blob: 80e913d9f9913e0b3973c2214a356ca0527c4630 [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"
reeddbc3cef2015-04-29 12:18:57 -070011#include "SkColorFilter.h"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000012#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000019#include "SkMetaData.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000020#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070021#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000022#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000023#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080024#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000025#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000026#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000027#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070029#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000030#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000031#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080032#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000033#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000035#if SK_SUPPORT_GPU
36#include "GrRenderTarget.h"
37#endif
38
reedd990e2f2014-12-22 11:58:30 -080039static bool gIgnoreSaveLayerBounds;
40void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
41 gIgnoreSaveLayerBounds = ignore;
42}
43bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
44 return gIgnoreSaveLayerBounds;
45}
46
reed0acf1b42014-12-22 16:12:38 -080047static bool gTreatSpriteAsBitmap;
48void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
49 gTreatSpriteAsBitmap = spriteAsBitmap;
50}
51bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
52 return gTreatSpriteAsBitmap;
53}
54
reed@google.comda17f752012-08-16 18:27:05 +000055// experimental for faster tiled drawing...
56//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000057
reed@android.com8a1c16f2008-12-17 15:59:43 +000058//#define SK_TRACE_SAVERESTORE
59
60#ifdef SK_TRACE_SAVERESTORE
61 static int gLayerCounter;
62 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
63 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
64
65 static int gRecCounter;
66 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
67 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
68
69 static int gCanvasCounter;
70 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
71 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
72#else
73 #define inc_layer()
74 #define dec_layer()
75 #define inc_rec()
76 #define dec_rec()
77 #define inc_canvas()
78 #define dec_canvas()
79#endif
80
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000081typedef SkTLazy<SkPaint> SkLazyPaint;
82
reed@google.com97af1a62012-08-28 12:19:02 +000083void SkCanvas::predrawNotify() {
84 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000085 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000086 }
87}
88
reed@android.com8a1c16f2008-12-17 15:59:43 +000089///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000090
reed4a8126e2014-09-22 07:29:03 -070091static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
92 const uint32_t propFlags = props.flags();
93 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
94 flags &= ~SkPaint::kDither_Flag;
95 }
96 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
97 flags &= ~SkPaint::kAntiAlias_Flag;
98 }
99 return flags;
100}
101
102///////////////////////////////////////////////////////////////////////////////
103
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000104/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 The clip/matrix/proc are fields that reflect the top of the save/restore
106 stack. Whenever the canvas changes, it marks a dirty flag, and then before
107 these are used (assuming we're not on a layer) we rebuild these cache
108 values: they reflect the top of the save stack, but translated and clipped
109 by the device's XY offset and bitmap-bounds.
110*/
111struct DeviceCM {
112 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000113 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000114 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000115 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700116 const SkMatrix* fMatrix;
117 SkMatrix fMatrixStorage;
118 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
reed96e657d2015-03-10 17:30:07 -0700120 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed61f501f2015-04-29 08:34:00 -0700121 bool conservativeRasterClip, bool deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700122 : fNext(NULL)
123 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700124 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700125 {
126 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000128 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 }
reed@google.com4b226022011-01-11 18:32:13 +0000130 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000134 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700135 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000136 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 fDevice->unref();
138 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000139 SkDELETE(fPaint);
140 }
reed@google.com4b226022011-01-11 18:32:13 +0000141
mtkleinfeaadee2015-04-08 11:25:48 -0700142 void reset(const SkIRect& bounds) {
143 SkASSERT(!fPaint);
144 SkASSERT(!fNext);
145 SkASSERT(fDevice);
146 fClip.setRect(bounds);
147 }
148
reed@google.com045e62d2011-10-24 12:19:46 +0000149 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
150 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000151 int x = fDevice->getOrigin().x();
152 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 int width = fDevice->width();
154 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 if ((x | y) == 0) {
157 fMatrix = &totalMatrix;
158 fClip = totalClip;
159 } else {
160 fMatrixStorage = totalMatrix;
161 fMatrixStorage.postTranslate(SkIntToScalar(-x),
162 SkIntToScalar(-y));
163 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 totalClip.translate(-x, -y, &fClip);
166 }
167
reed@google.com045e62d2011-10-24 12:19:46 +0000168 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
170 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000173 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 SkRegion::kDifference_Op);
175 }
reed@google.com4b226022011-01-11 18:32:13 +0000176
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000177 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
178
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179#ifdef SK_DEBUG
180 if (!fClip.isEmpty()) {
181 SkIRect deviceR;
182 deviceR.set(0, 0, width, height);
183 SkASSERT(deviceR.contains(fClip.getBounds()));
184 }
185#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000186 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187};
188
189/* This is the record we keep for each save/restore level in the stack.
190 Since a level optionally copies the matrix and/or stack, we have pointers
191 for these fields. If the value is copied for this level, the copy is
192 stored in the ...Storage field, and the pointer points to that. If the
193 value is not copied for this level, we ignore ...Storage, and just point
194 at the corresponding value in the previous level in the stack.
195*/
196class SkCanvas::MCRec {
197public:
reed1f836ee2014-07-07 07:49:34 -0700198 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700199 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 /* If there are any layers in the stack, this points to the top-most
201 one that is at or below this level in the stack (so we know what
202 bitmap/device to draw into from this level. This value is NOT
203 reference counted, since the real owner is either our fLayer field,
204 or a previous one in a lower level.)
205 */
reed2ff1fce2014-12-11 07:07:37 -0800206 DeviceCM* fTopLayer;
207 SkRasterClip fRasterClip;
208 SkMatrix fMatrix;
209 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
reedd9544982014-09-09 18:46:22 -0700211 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700212 fFilter = NULL;
213 fLayer = NULL;
214 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800215 fMatrix.reset();
216 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700217
reedd9544982014-09-09 18:46:22 -0700218 // don't bother initializing fNext
219 inc_rec();
220 }
reed2ff1fce2014-12-11 07:07:37 -0800221 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700222 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700224 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800225 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700226
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 // don't bother initializing fNext
228 inc_rec();
229 }
230 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000231 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkDELETE(fLayer);
233 dec_rec();
234 }
mtkleinfeaadee2015-04-08 11:25:48 -0700235
236 void reset(const SkIRect& bounds) {
237 SkASSERT(fLayer);
238 SkASSERT(fDeferredSaveCount == 0);
239
240 fMatrix.reset();
241 fRasterClip.setRect(bounds);
242 fLayer->reset(bounds);
243 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244};
245
246class SkDrawIter : public SkDraw {
247public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000248 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000249 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000250 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 canvas->updateDeviceCMCache();
252
reed687fa1c2015-04-07 08:00:56 -0700253 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000255 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 }
reed@google.com4b226022011-01-11 18:32:13 +0000257
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 bool next() {
259 // skip over recs with empty clips
260 if (fSkipEmptyClips) {
261 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
262 fCurrLayer = fCurrLayer->fNext;
263 }
264 }
265
reed@google.comf68c5e22012-02-24 16:38:58 +0000266 const DeviceCM* rec = fCurrLayer;
267 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
269 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000270 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
271 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 fDevice = rec->fDevice;
273 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000275 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
277 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000279
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 return true;
281 }
282 return false;
283 }
reed@google.com4b226022011-01-11 18:32:13 +0000284
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000285 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286 int getX() const { return fDevice->getOrigin().x(); }
287 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 const SkMatrix& getMatrix() const { return *fMatrix; }
289 const SkRegion& getClip() const { return *fClip; }
290 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292private:
293 SkCanvas* fCanvas;
294 const DeviceCM* fCurrLayer;
295 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 SkBool8 fSkipEmptyClips;
297
298 typedef SkDraw INHERITED;
299};
300
301/////////////////////////////////////////////////////////////////////////////
302
reeddbc3cef2015-04-29 12:18:57 -0700303static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
304 return lazy->isValid() ? lazy->get() : lazy->set(orig);
305}
306
307/**
308 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
309 * colorfilter, else return NULL.
310 */
311static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
312#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_TO_COLORFILTER
313 return NULL;
314#else
315 SkImageFilter* imgf = paint.getImageFilter();
316 if (!imgf) {
317 return NULL;
318 }
319
320 SkColorFilter* imgCF;
321 if (!imgf->asAColorFilter(&imgCF)) {
322 return NULL;
323 }
324
325 SkColorFilter* paintCF = paint.getColorFilter();
326 if (NULL == paintCF) {
327 // there is no existing paint colorfilter, so we can just return the imagefilter's
328 return imgCF;
329 }
330
331 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
332 // and we need to combine them into a single colorfilter.
333 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
334 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
335#endif
336}
337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338class AutoDrawLooper {
339public:
reed4a8126e2014-09-22 07:29:03 -0700340 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000341 bool skipLayerForImageFilter = false,
342 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000343 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700345 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000346 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700347 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000348 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349
reeddbc3cef2015-04-29 12:18:57 -0700350 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
351 if (simplifiedCF) {
352 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
353 paint->setColorFilter(simplifiedCF)->unref();
354 paint->setImageFilter(NULL);
355 fPaint = paint;
356 }
357
358 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700359 /**
360 * We implement ImageFilters for a given draw by creating a layer, then applying the
361 * imagefilter to the pixels of that layer (its backing surface/image), and then
362 * we call restore() to xfer that layer to the main canvas.
363 *
364 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
365 * 2. Generate the src pixels:
366 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
367 * return (fPaint). We then draw the primitive (using srcover) into a cleared
368 * buffer/surface.
369 * 3. Restore the layer created in #1
370 * The imagefilter is passed the buffer/surface from the layer (now filled with the
371 * src pixels of the primitive). It returns a new "filtered" buffer, which we
372 * draw onto the previous layer using the xfermode from the original paint.
373 */
reed@google.com8926b162012-03-23 15:36:36 +0000374 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700375 tmp.setImageFilter(fPaint->getImageFilter());
376 tmp.setXfermode(fPaint->getXfermode());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000377 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700378 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700379 fTempLayerForImageFilter = true;
380 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000381 }
382
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000383 if (SkDrawLooper* looper = paint.getLooper()) {
384 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
385 looper->contextSize());
386 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000387 fIsSimple = false;
388 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000389 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000390 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700391 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000392 }
piotaixrb5fae932014-09-24 13:03:30 -0700393
reed4a8126e2014-09-22 07:29:03 -0700394 uint32_t oldFlags = paint.getFlags();
395 fNewPaintFlags = filter_paint_flags(props, oldFlags);
396 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700397 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700398 paint->setFlags(fNewPaintFlags);
399 fPaint = paint;
400 // if we're not simple, doNext() will take care of calling setFlags()
401 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000402 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000403
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700405 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000406 fCanvas->internalRestore();
407 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000408 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000410
reed@google.com4e2b3d32011-04-07 14:18:59 +0000411 const SkPaint& paint() const {
412 SkASSERT(fPaint);
413 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000415
reed@google.com129ec222012-05-15 13:24:09 +0000416 bool next(SkDrawFilter::Type drawType) {
417 if (fDone) {
418 return false;
419 } else if (fIsSimple) {
420 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000421 return !fPaint->nothingToDraw();
422 } else {
423 return this->doNext(drawType);
424 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000425 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427private:
reeddbc3cef2015-04-29 12:18:57 -0700428 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
429 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000430 SkCanvas* fCanvas;
431 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000432 SkDrawFilter* fFilter;
433 const SkPaint* fPaint;
434 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700435 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700436 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000437 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000438 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000439 SkDrawLooper::Context* fLooperContext;
440 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000441
442 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443};
444
reed@google.com129ec222012-05-15 13:24:09 +0000445bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000446 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000447 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700448 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000449
reeddbc3cef2015-04-29 12:18:57 -0700450 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
451 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700452 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000453
reed5c476fb2015-04-20 08:04:21 -0700454 if (fTempLayerForImageFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000455 paint->setImageFilter(NULL);
reed5c476fb2015-04-20 08:04:21 -0700456 paint->setXfermode(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000459 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000460 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000461 return false;
462 }
463 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000464 if (!fFilter->filter(paint, drawType)) {
465 fDone = true;
466 return false;
467 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000468 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000469 // no looper means we only draw once
470 fDone = true;
471 }
472 }
473 fPaint = paint;
474
475 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000476 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000477 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000478 }
479
480 // call this after any possible paint modifiers
481 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 fPaint = NULL;
483 return false;
484 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485 return true;
486}
487
reed@android.com8a1c16f2008-12-17 15:59:43 +0000488////////// macros to place around the internal draw calls //////////////////
489
reed@google.com8926b162012-03-23 15:36:36 +0000490#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000491 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700492 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000493 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000494 SkDrawIter iter(this);
495
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000496#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000497 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700498 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000501
reed@google.com4e2b3d32011-04-07 14:18:59 +0000502#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503
504////////////////////////////////////////////////////////////////////////////
505
mtkleinfeaadee2015-04-08 11:25:48 -0700506void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
507 this->restoreToCount(1);
508 fCachedLocalClipBounds.setEmpty();
509 fCachedLocalClipBoundsDirty = true;
510 fClipStack->reset();
511 fMCRec->reset(bounds);
512
513 // We're peering through a lot of structs here. Only at this scope do we
514 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
515 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
516}
517
reedd9544982014-09-09 18:46:22 -0700518SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
519 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000520 fCachedLocalClipBounds.setEmpty();
521 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000522 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000523 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700524 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800525 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000526 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527
reed687fa1c2015-04-07 08:00:56 -0700528 fClipStack.reset(SkNEW(SkClipStack));
529
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700531 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532
reeda499f902015-05-01 09:34:31 -0700533 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
534 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
535 new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700536
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538
reed@google.com97af1a62012-08-28 12:19:02 +0000539 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000540
reedf92c8662014-08-18 08:02:43 -0700541 if (device) {
reedb2db8982014-11-13 12:41:02 -0800542 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700543 if (device->forceConservativeRasterClip()) {
544 fConservativeRasterClip = true;
545 }
reedf92c8662014-08-18 08:02:43 -0700546 device->onAttachToCanvas(this);
547 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800548 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700549 }
550 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551}
552
reed@google.comcde92112011-07-06 20:00:52 +0000553SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000554 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700555 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000556{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000557 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000558
reedd9544982014-09-09 18:46:22 -0700559 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000560}
561
reedd9544982014-09-09 18:46:22 -0700562static SkBitmap make_nopixels(int width, int height) {
563 SkBitmap bitmap;
564 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
565 return bitmap;
566}
567
568class SkNoPixelsBitmapDevice : public SkBitmapDevice {
569public:
reed78e27682014-11-19 08:04:34 -0800570 SkNoPixelsBitmapDevice(const SkIRect& bounds)
571 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
572 {
573 this->setOrigin(bounds.x(), bounds.y());
574 }
reedd9544982014-09-09 18:46:22 -0700575
576private:
piotaixrb5fae932014-09-24 13:03:30 -0700577
reedd9544982014-09-09 18:46:22 -0700578 typedef SkBitmapDevice INHERITED;
579};
580
reed96a857e2015-01-25 10:33:58 -0800581SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000582 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800583 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000584{
585 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700586
reed78e27682014-11-19 08:04:34 -0800587 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
588 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700589}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000590
reed78e27682014-11-19 08:04:34 -0800591SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700592 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700593 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700594{
595 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700596
reed78e27682014-11-19 08:04:34 -0800597 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700598}
599
reed4a8126e2014-09-22 07:29:03 -0700600SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700601 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700602 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700603{
604 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700605
reedd9544982014-09-09 18:46:22 -0700606 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607}
608
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000609SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000610 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700611 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000612{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700614
reedd9544982014-09-09 18:46:22 -0700615 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616}
617
reed4a8126e2014-09-22 07:29:03 -0700618SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700619 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700620 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700621{
622 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700623
reed4a8126e2014-09-22 07:29:03 -0700624 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
625 this->init(device, kDefault_InitFlags);
626}
reed29c857d2014-09-21 10:25:07 -0700627
reed4a8126e2014-09-22 07:29:03 -0700628SkCanvas::SkCanvas(const SkBitmap& bitmap)
629 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
630 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
631{
632 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700633
reed4a8126e2014-09-22 07:29:03 -0700634 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
635 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636}
637
638SkCanvas::~SkCanvas() {
639 // free up the contents of our deque
640 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000641
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 this->internalRestore(); // restore the last, since we're going away
643
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000644 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000645
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646 dec_canvas();
647}
648
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649SkDrawFilter* SkCanvas::getDrawFilter() const {
650 return fMCRec->fFilter;
651}
652
653SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700654 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
656 return filter;
657}
658
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000659SkMetaData& SkCanvas::getMetaData() {
660 // metadata users are rare, so we lazily allocate it. If that changes we
661 // can decide to just make it a field in the device (rather than a ptr)
662 if (NULL == fMetaData) {
663 fMetaData = new SkMetaData;
664 }
665 return *fMetaData;
666}
667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668///////////////////////////////////////////////////////////////////////////////
669
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000670void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000671 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000672 if (device) {
673 device->flush();
674 }
675}
676
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000677SkISize SkCanvas::getTopLayerSize() const {
678 SkBaseDevice* d = this->getTopDevice();
679 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
680}
681
682SkIPoint SkCanvas::getTopLayerOrigin() const {
683 SkBaseDevice* d = this->getTopDevice();
684 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
685}
686
687SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000688 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000689 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
690}
691
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000694 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 SkASSERT(rec && rec->fLayer);
696 return rec->fLayer->fDevice;
697}
698
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000699SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000700 if (updateMatrixClip) {
701 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
702 }
reed@google.com9266fed2011-03-30 00:18:03 +0000703 return fMCRec->fTopLayer->fDevice;
704}
705
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000706bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
707 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
708 return false;
709 }
710
711 bool weAllocated = false;
712 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700713 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000714 return false;
715 }
716 weAllocated = true;
717 }
718
719 SkBitmap bm(*bitmap);
720 bm.lockPixels();
721 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
722 return true;
723 }
724
725 if (weAllocated) {
726 bitmap->setPixelRef(NULL);
727 }
728 return false;
729}
reed@google.com51df9e32010-12-23 19:29:18 +0000730
bsalomon@google.comc6980972011-11-02 19:57:21 +0000731bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000732 SkIRect r = srcRect;
733 const SkISize size = this->getBaseLayerSize();
734 if (!r.intersect(0, 0, size.width(), size.height())) {
735 bitmap->reset();
736 return false;
737 }
738
reed84825042014-09-02 12:50:45 -0700739 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000740 // bitmap will already be reset.
741 return false;
742 }
743 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
744 bitmap->reset();
745 return false;
746 }
747 return true;
748}
749
reed96472de2014-12-10 09:53:42 -0800750bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000751 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000752 if (!device) {
753 return false;
754 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000755 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800756
reed96472de2014-12-10 09:53:42 -0800757 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
758 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000759 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000760 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000761
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000762 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800763 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000764}
765
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
767 if (bitmap.getTexture()) {
768 return false;
769 }
770 SkBitmap bm(bitmap);
771 bm.lockPixels();
772 if (bm.getPixels()) {
773 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
774 }
775 return false;
776}
777
778bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
779 int x, int y) {
780 switch (origInfo.colorType()) {
781 case kUnknown_SkColorType:
782 case kIndex_8_SkColorType:
783 return false;
784 default:
785 break;
786 }
787 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
788 return false;
789 }
790
791 const SkISize size = this->getBaseLayerSize();
792 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
793 if (!target.intersect(0, 0, size.width(), size.height())) {
794 return false;
795 }
796
797 SkBaseDevice* device = this->getDevice();
798 if (!device) {
799 return false;
800 }
801
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000802 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700803 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000804
805 // if x or y are negative, then we have to adjust pixels
806 if (x > 0) {
807 x = 0;
808 }
809 if (y > 0) {
810 y = 0;
811 }
812 // here x,y are either 0 or negative
813 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
814
reed4af35f32014-06-27 17:47:49 -0700815 // Tell our owning surface to bump its generation ID
816 this->predrawNotify();
817
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000818 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000819 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000820}
reed@google.com51df9e32010-12-23 19:29:18 +0000821
junov@google.com4370aed2012-01-18 16:21:08 +0000822SkCanvas* SkCanvas::canvasForDrawIter() {
823 return this;
824}
825
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826//////////////////////////////////////////////////////////////////////////////
827
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828void SkCanvas::updateDeviceCMCache() {
829 if (fDeviceCMDirty) {
830 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700831 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000833
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700835 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000837 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 do {
reed687fa1c2015-04-07 08:00:56 -0700839 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 } while ((layer = layer->fNext) != NULL);
841 }
842 fDeviceCMDirty = false;
843 }
844}
845
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846///////////////////////////////////////////////////////////////////////////////
847
reed2ff1fce2014-12-11 07:07:37 -0800848void SkCanvas::checkForDeferredSave() {
849 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800850 this->doSave();
851 }
852}
853
reedf0090cb2014-11-26 08:55:51 -0800854int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800855#ifdef SK_DEBUG
856 int count = 0;
857 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
858 for (;;) {
859 const MCRec* rec = (const MCRec*)iter.next();
860 if (!rec) {
861 break;
862 }
863 count += 1 + rec->fDeferredSaveCount;
864 }
865 SkASSERT(count == fSaveCount);
866#endif
867 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800868}
869
870int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800871 fSaveCount += 1;
872 fMCRec->fDeferredSaveCount += 1;
873 return this->getSaveCount() - 1; // return our prev value
874}
875
876void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800877 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700878
879 SkASSERT(fMCRec->fDeferredSaveCount > 0);
880 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800881 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800882}
883
884void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800885 if (fMCRec->fDeferredSaveCount > 0) {
886 SkASSERT(fSaveCount > 1);
887 fSaveCount -= 1;
888 fMCRec->fDeferredSaveCount -= 1;
889 } else {
890 // check for underflow
891 if (fMCStack.count() > 1) {
892 this->willRestore();
893 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700894 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800895 this->internalRestore();
896 this->didRestore();
897 }
reedf0090cb2014-11-26 08:55:51 -0800898 }
899}
900
901void SkCanvas::restoreToCount(int count) {
902 // sanity check
903 if (count < 1) {
904 count = 1;
905 }
mtkleinf0f14112014-12-12 08:46:25 -0800906
reedf0090cb2014-11-26 08:55:51 -0800907 int n = this->getSaveCount() - count;
908 for (int i = 0; i < n; ++i) {
909 this->restore();
910 }
911}
912
reed2ff1fce2014-12-11 07:07:37 -0800913void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700915 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000916 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000917
reed687fa1c2015-04-07 08:00:56 -0700918 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919}
920
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000922#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000924#else
925 return true;
926#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927}
928
junov@chromium.orga907ac32012-02-24 21:54:07 +0000929bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700930 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000931 SkIRect clipBounds;
932 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000933 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000934 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000935
reed96e657d2015-03-10 17:30:07 -0700936 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
937
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000938 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700939 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000940 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000941 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700942 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000944
reed96e657d2015-03-10 17:30:07 -0700945 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946 r.roundOut(&ir);
947 // early exit if the layer's bounds are clipped out
948 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000949 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700950 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700951 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000952 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000953 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954 }
955 } else { // no user bounds, so just use the clip
956 ir = clipBounds;
957 }
reed180aec42015-03-11 10:39:04 -0700958 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000960 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700961 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700962 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700963 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700964 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000965 }
966
967 if (intersection) {
968 *intersection = ir;
969 }
970 return true;
971}
972
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000973int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800974 if (gIgnoreSaveLayerBounds) {
975 bounds = NULL;
976 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000977 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700978 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700979 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800980 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000981}
982
reed2ff1fce2014-12-11 07:07:37 -0800983int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800984 if (gIgnoreSaveLayerBounds) {
985 bounds = NULL;
986 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000987 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700988 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700989 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800990 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000991}
992
reed2ff1fce2014-12-11 07:07:37 -0800993void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700994 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000995#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000996 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000997#endif
998
junov@chromium.orga907ac32012-02-24 21:54:07 +0000999 // do this before we create the layer. We don't call the public save() since
1000 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001001 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001002
1003 fDeviceCMDirty = true;
1004
1005 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001006 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001007 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 }
1009
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001010 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1011 // the clipRectBounds() call above?
1012 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001013 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001014 }
1015
reed76033be2015-03-14 10:54:31 -07001016 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001017 SkPixelGeometry geo = fProps.pixelGeometry();
1018 if (paint) {
reed76033be2015-03-14 10:54:31 -07001019 // TODO: perhaps add a query to filters so we might preserve opaqueness...
1020 if (paint->getImageFilter() || paint->getColorFilter()) {
1021 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001022 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001023 }
1024 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001025 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1026 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027
reedb2db8982014-11-13 12:41:02 -08001028 SkBaseDevice* device = this->getTopDevice();
1029 if (NULL == device) {
1030 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001031 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001032 }
reedb2db8982014-11-13 12:41:02 -08001033
reed61f501f2015-04-29 08:34:00 -07001034 bool forceSpriteOnRestore = false;
1035 {
1036 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
1037 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1038 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1039 if (NULL == newDev) {
1040 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
1041 newDev = SkBitmapDevice::Create(createInfo.fInfo);
1042 if (NULL == newDev) {
1043 SkErrorInternals::SetError(kInternalError_SkError,
1044 "Unable to create device for layer.");
1045 return;
1046 }
1047 forceSpriteOnRestore = true;
1048 }
1049 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001050 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001051
reed@google.com6f8f2922011-03-04 22:27:10 +00001052 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001053 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
1054 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 device->unref();
1056
1057 layer->fNext = fMCRec->fTopLayer;
1058 fMCRec->fLayer = layer;
1059 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060}
1061
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001062int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1063 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1064}
1065
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1067 SaveFlags flags) {
1068 if (0xFF == alpha) {
1069 return this->saveLayer(bounds, NULL, flags);
1070 } else {
1071 SkPaint tmpPaint;
1072 tmpPaint.setAlpha(alpha);
1073 return this->saveLayer(bounds, &tmpPaint, flags);
1074 }
1075}
1076
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077void SkCanvas::internalRestore() {
1078 SkASSERT(fMCStack.count() != 0);
1079
1080 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001081 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082
reed687fa1c2015-04-07 08:00:56 -07001083 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001084
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001085 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 DeviceCM* layer = fMCRec->fLayer; // may be null
1087 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1088 fMCRec->fLayer = NULL;
1089
1090 // now do the normal restore()
1091 fMCRec->~MCRec(); // balanced in save()
1092 fMCStack.pop_back();
1093 fMCRec = (MCRec*)fMCStack.back();
1094
1095 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1096 since if we're being recorded, we don't want to record this (the
1097 recorder will have already recorded the restore).
1098 */
bsalomon49f085d2014-09-05 13:34:00 -07001099 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001101 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001102 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001103 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001104 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001106 SkDELETE(layer);
1107 } else {
1108 // we're at the root
reeda499f902015-05-01 09:34:31 -07001109 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001110 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001112 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113}
1114
reed4a8126e2014-09-22 07:29:03 -07001115SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1116 if (NULL == props) {
1117 props = &fProps;
1118 }
1119 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001120}
1121
reed4a8126e2014-09-22 07:29:03 -07001122SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001123 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001124 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001125}
1126
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001127SkImageInfo SkCanvas::imageInfo() const {
1128 SkBaseDevice* dev = this->getDevice();
1129 if (dev) {
1130 return dev->imageInfo();
1131 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001132 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001133 }
1134}
1135
1136const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1137 return this->onPeekPixels(info, rowBytes);
1138}
1139
1140const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1141 SkBaseDevice* dev = this->getDevice();
1142 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1143}
1144
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001145void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1146 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1147 if (pixels && origin) {
1148 *origin = this->getTopDevice(false)->getOrigin();
1149 }
1150 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001151}
1152
1153void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1154 SkBaseDevice* dev = this->getTopDevice();
1155 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1156}
1157
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001158SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1159 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1160 if (NULL == fAddr) {
1161 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001162 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001163 return; // failure, fAddr is NULL
1164 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001165 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1166 return; // failure, fAddr is NULL
1167 }
1168 fAddr = fBitmap.getPixels();
1169 fRowBytes = fBitmap.rowBytes();
1170 }
1171 SkASSERT(fAddr); // success
1172}
1173
1174bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1175 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001176 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001177 } else {
1178 bitmap->reset();
1179 return false;
1180 }
1181}
1182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001184void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001186 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 return;
1188 }
1189
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001190 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001192 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001194
1195 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001196
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001197 SkRect storage;
1198 const SkRect* bounds = NULL;
1199 if (paint && paint->canComputeFastBounds()) {
1200 bitmap.getBounds(&storage);
1201 matrix.mapRect(&storage);
1202 bounds = &paint->computeFastBounds(storage, &storage);
1203 }
1204
1205 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001206
1207 while (iter.next()) {
1208 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1209 }
1210
1211 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212}
1213
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001214void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001215 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 SkPaint tmp;
1217 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 paint = &tmp;
1219 }
reed@google.com4b226022011-01-11 18:32:13 +00001220
reed@google.com8926b162012-03-23 15:36:36 +00001221 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001223 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001224 paint = &looper.paint();
1225 SkImageFilter* filter = paint->getImageFilter();
1226 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001227 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001228 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001229 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001230 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001231 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001232 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001233 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001234 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001235 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001236 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001237 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001238 SkPaint tmpUnfiltered(*paint);
1239 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001240 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1241 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001242 }
reed61f501f2015-04-29 08:34:00 -07001243 } else if (deviceIsBitmapDevice) {
1244 const SkBitmap& src = srcDev->accessBitmap(false);
1245 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001246 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001247 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001248 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001250 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251}
1252
reed41af9662015-01-05 07:49:08 -08001253void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001254 if (gTreatSpriteAsBitmap) {
1255 this->save();
1256 this->resetMatrix();
1257 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1258 this->restore();
1259 return;
1260 }
1261
danakj9881d632014-11-26 12:41:06 -08001262 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001263 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001264 return;
1265 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001266 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001267
reed@google.com8926b162012-03-23 15:36:36 +00001268 SkPaint tmp;
1269 if (NULL == paint) {
1270 paint = &tmp;
1271 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001272
reed@google.com8926b162012-03-23 15:36:36 +00001273 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001274
reed@google.com8926b162012-03-23 15:36:36 +00001275 while (iter.next()) {
1276 paint = &looper.paint();
1277 SkImageFilter* filter = paint->getImageFilter();
1278 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1279 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001280 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001281 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001282 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001283 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001284 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001285 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001286 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001287 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001288 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001289 SkPaint tmpUnfiltered(*paint);
1290 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001291 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001292 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001293 }
1294 } else {
1295 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1296 }
1297 }
1298 LOOPER_END
1299}
1300
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001302void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001303 SkMatrix m;
1304 m.setTranslate(dx, dy);
1305 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306}
1307
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001308void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001309 SkMatrix m;
1310 m.setScale(sx, sy);
1311 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312}
1313
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001314void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001315 SkMatrix m;
1316 m.setRotate(degrees);
1317 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318}
1319
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001320void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001321 SkMatrix m;
1322 m.setSkew(sx, sy);
1323 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001324}
1325
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001326void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001327 if (matrix.isIdentity()) {
1328 return;
1329 }
1330
reed2ff1fce2014-12-11 07:07:37 -08001331 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001333 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001334 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001335
1336 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001337}
1338
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001340 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001342 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001343 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001344 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347void SkCanvas::resetMatrix() {
1348 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001349
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 matrix.reset();
1351 this->setMatrix(matrix);
1352}
1353
1354//////////////////////////////////////////////////////////////////////////////
1355
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001356void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001357 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1359 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001360}
1361
1362void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001363#ifdef SK_ENABLE_CLIP_QUICKREJECT
1364 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001365 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001366 return false;
1367 }
1368
reed@google.com3b3e8952012-08-16 20:53:31 +00001369 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001370 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001371 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001372
reed687fa1c2015-04-07 08:00:56 -07001373 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001374 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001375 }
1376 }
1377#endif
1378
reed@google.com5c3d1472011-02-22 19:12:23 +00001379 AutoValidateClip avc(this);
1380
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001382 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001383 if (!fAllowSoftClip) {
1384 edgeStyle = kHard_ClipEdgeStyle;
1385 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386
reed1f836ee2014-07-07 07:49:34 -07001387 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001388 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001389 // the matrix. This means we don't have to a) make a path, and b) tell
1390 // the region code to scan-convert the path, only to discover that it
1391 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393
reed1f836ee2014-07-07 07:49:34 -07001394 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001395 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001396 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001398 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001399 // and clip against that, since it can handle any matrix. However, to
1400 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1401 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 SkPath path;
1403
1404 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406 }
1407}
1408
reed73e714e2014-09-04 09:02:23 -07001409static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1410 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001411 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001412}
1413
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001414void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001415 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001416 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001417 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001418 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1419 } else {
1420 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001421 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001422}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001423
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001425 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001426 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001427 AutoValidateClip avc(this);
1428
1429 fDeviceCMDirty = true;
1430 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431 if (!fAllowSoftClip) {
1432 edgeStyle = kHard_ClipEdgeStyle;
1433 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001434
reed687fa1c2015-04-07 08:00:56 -07001435 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001436
1437 SkPath devPath;
1438 devPath.addRRect(transformedRRect);
1439
reed73e714e2014-09-04 09:02:23 -07001440 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001441 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001442 }
1443
1444 SkPath path;
1445 path.addRRect(rrect);
1446 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001447 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001448}
1449
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001450void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001451 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1453 SkRect r;
1454 if (!path.isInverseFillType() && path.isRect(&r)) {
1455 this->onClipRect(r, op, edgeStyle);
1456 } else {
1457 this->onClipPath(path, op, edgeStyle);
1458 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459}
1460
1461void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001462#ifdef SK_ENABLE_CLIP_QUICKREJECT
1463 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001464 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001465 return false;
1466 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001467
reed@google.com3b3e8952012-08-16 20:53:31 +00001468 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001469 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001470 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001471
reed687fa1c2015-04-07 08:00:56 -07001472 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001473 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001474 }
1475 }
1476#endif
1477
reed@google.com5c3d1472011-02-22 19:12:23 +00001478 AutoValidateClip avc(this);
1479
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001481 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001482 if (!fAllowSoftClip) {
1483 edgeStyle = kHard_ClipEdgeStyle;
1484 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485
1486 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001487 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488
reed@google.comfe701122011-11-08 19:41:23 +00001489 // Check if the transfomation, or the original path itself
1490 // made us empty. Note this can also happen if we contained NaN
1491 // values. computing the bounds detects this, and will set our
1492 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1493 if (devPath.getBounds().isEmpty()) {
1494 // resetting the path will remove any NaN or other wanky values
1495 // that might upset our scan converter.
1496 devPath.reset();
1497 }
1498
reed@google.com5c3d1472011-02-22 19:12:23 +00001499 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001500 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001501
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001502 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001503 bool clipIsAA = getClipStack()->asPath(&devPath);
1504 if (clipIsAA) {
1505 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001506 }
fmalita1a481fe2015-02-04 07:39:34 -08001507
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001508 op = SkRegion::kReplace_Op;
1509 }
1510
reed73e714e2014-09-04 09:02:23 -07001511 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512}
1513
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001514void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001515 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001517}
1518
1519void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001520 AutoValidateClip avc(this);
1521
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001523 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524
reed@google.com5c3d1472011-02-22 19:12:23 +00001525 // todo: signal fClipStack that we have a region, and therefore (I guess)
1526 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001527 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001528
reed1f836ee2014-07-07 07:49:34 -07001529 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530}
1531
reed@google.com819c9212011-02-23 18:56:55 +00001532#ifdef SK_DEBUG
1533void SkCanvas::validateClip() const {
1534 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001535 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001536 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001537 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001538 return;
1539 }
1540
reed@google.com819c9212011-02-23 18:56:55 +00001541 SkIRect ir;
1542 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001543 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001544
reed687fa1c2015-04-07 08:00:56 -07001545 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001546 const SkClipStack::Element* element;
1547 while ((element = iter.next()) != NULL) {
1548 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001549 case SkClipStack::Element::kRect_Type:
1550 element->getRect().round(&ir);
1551 tmpClip.op(ir, element->getOp());
1552 break;
1553 case SkClipStack::Element::kEmpty_Type:
1554 tmpClip.setEmpty();
1555 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001556 default: {
1557 SkPath path;
1558 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001559 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001560 break;
1561 }
reed@google.com819c9212011-02-23 18:56:55 +00001562 }
1563 }
reed@google.com819c9212011-02-23 18:56:55 +00001564}
1565#endif
1566
reed@google.com90c07ea2012-04-13 13:50:27 +00001567void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001568 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001569 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001570
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001571 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001572 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001573 }
1574}
1575
reed@google.com5c3d1472011-02-22 19:12:23 +00001576///////////////////////////////////////////////////////////////////////////////
1577
reed@google.com754de5f2014-02-24 19:38:20 +00001578bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001579 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001580}
1581
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001582bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001583 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001584}
1585
reed@google.com3b3e8952012-08-16 20:53:31 +00001586bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001587 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001588 return true;
1589
reed1f836ee2014-07-07 07:49:34 -07001590 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 return true;
1592 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593
reed1f836ee2014-07-07 07:49:34 -07001594 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001595 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001596 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001597 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001598 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001599 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001600
reed@android.coma380ae42009-07-21 01:17:02 +00001601 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001602 // TODO: should we use | instead, or compare all 4 at once?
1603 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001604 return true;
1605 }
reed@google.comc0784db2013-12-13 21:16:12 +00001606 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001607 return true;
1608 }
1609 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611}
1612
reed@google.com3b3e8952012-08-16 20:53:31 +00001613bool SkCanvas::quickReject(const SkPath& path) const {
1614 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
reed@google.com3b3e8952012-08-16 20:53:31 +00001617bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001618 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001619 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620 return false;
1621 }
1622
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001623 SkMatrix inverse;
1624 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001625 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001626 if (bounds) {
1627 bounds->setEmpty();
1628 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001629 return false;
1630 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631
bsalomon49f085d2014-09-05 13:34:00 -07001632 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001633 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001634 // adjust it outwards in case we are antialiasing
1635 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001636
reed@google.com8f4d2302013-12-17 16:44:46 +00001637 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1638 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639 inverse.mapRect(bounds, r);
1640 }
1641 return true;
1642}
1643
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001644bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001645 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001646 if (clip.isEmpty()) {
1647 if (bounds) {
1648 bounds->setEmpty();
1649 }
1650 return false;
1651 }
1652
bsalomon49f085d2014-09-05 13:34:00 -07001653 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001654 *bounds = clip.getBounds();
1655 }
1656 return true;
1657}
1658
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001660 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661}
1662
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001663const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001664 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001665}
1666
reed@google.com9c135db2014-03-12 18:28:35 +00001667GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1668 SkBaseDevice* dev = this->getTopDevice();
1669 return dev ? dev->accessRenderTarget() : NULL;
1670}
1671
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001672GrContext* SkCanvas::getGrContext() {
1673#if SK_SUPPORT_GPU
1674 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001675 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001677 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001678 return renderTarget->getContext();
1679 }
1680 }
1681#endif
1682
1683 return NULL;
1684
1685}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001686
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001687void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1688 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001689 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001690 if (outer.isEmpty()) {
1691 return;
1692 }
1693 if (inner.isEmpty()) {
1694 this->drawRRect(outer, paint);
1695 return;
1696 }
1697
1698 // We don't have this method (yet), but technically this is what we should
1699 // be able to assert...
1700 // SkASSERT(outer.contains(inner));
1701 //
1702 // For now at least check for containment of bounds
1703 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1704
1705 this->onDrawDRRect(outer, inner, paint);
1706}
1707
reed41af9662015-01-05 07:49:08 -08001708// These need to stop being virtual -- clients need to override the onDraw... versions
1709
1710void SkCanvas::drawPaint(const SkPaint& paint) {
1711 this->onDrawPaint(paint);
1712}
1713
1714void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1715 this->onDrawRect(r, paint);
1716}
1717
1718void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1719 this->onDrawOval(r, paint);
1720}
1721
1722void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1723 this->onDrawRRect(rrect, paint);
1724}
1725
1726void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1727 this->onDrawPoints(mode, count, pts, paint);
1728}
1729
1730void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1731 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1732 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1733 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1734 indices, indexCount, paint);
1735}
1736
1737void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1738 this->onDrawPath(path, paint);
1739}
1740
1741void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1742 this->onDrawImage(image, dx, dy, paint);
1743}
1744
1745void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1746 const SkPaint* paint) {
1747 this->onDrawImageRect(image, src, dst, paint);
1748}
1749
1750void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001751 if (bitmap.empty()) {
1752 return;
1753 }
reed41af9662015-01-05 07:49:08 -08001754 this->onDrawBitmap(bitmap, dx, dy, paint);
1755}
1756
1757void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1758 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001759 if (bitmap.empty()) {
1760 return;
1761 }
reed41af9662015-01-05 07:49:08 -08001762 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1763}
1764
1765void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1766 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001767 if (bitmap.empty()) {
1768 return;
1769 }
reed41af9662015-01-05 07:49:08 -08001770 this->onDrawBitmapNine(bitmap, center, dst, paint);
1771}
1772
1773void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001774 if (bitmap.empty()) {
1775 return;
1776 }
reed41af9662015-01-05 07:49:08 -08001777 this->onDrawSprite(bitmap, left, top, paint);
1778}
1779
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780//////////////////////////////////////////////////////////////////////////////
1781// These are the virtual drawing methods
1782//////////////////////////////////////////////////////////////////////////////
1783
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001784void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001785 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001786 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1787 }
1788}
1789
reed41af9662015-01-05 07:49:08 -08001790void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001792 this->internalDrawPaint(paint);
1793}
1794
1795void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001796 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001797
1798 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001799 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800 }
1801
reed@google.com4e2b3d32011-04-07 14:18:59 +00001802 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803}
1804
reed41af9662015-01-05 07:49:08 -08001805void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1806 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001807 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808 if ((long)count <= 0) {
1809 return;
1810 }
1811
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001812 SkRect r, storage;
1813 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001814 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001815 // special-case 2 points (common for drawing a single line)
1816 if (2 == count) {
1817 r.set(pts[0], pts[1]);
1818 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001819 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001820 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001821 bounds = &paint.computeFastStrokeBounds(r, &storage);
1822 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001823 return;
1824 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001825 }
reed@google.coma584aed2012-05-16 14:06:02 +00001826
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827 SkASSERT(pts != NULL);
1828
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001829 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001830
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001832 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833 }
reed@google.com4b226022011-01-11 18:32:13 +00001834
reed@google.com4e2b3d32011-04-07 14:18:59 +00001835 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001836}
1837
reed41af9662015-01-05 07:49:08 -08001838void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001840 SkRect storage;
1841 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001843 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1844 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1845 SkRect tmp(r);
1846 tmp.sort();
1847
1848 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001849 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001850 return;
1851 }
1852 }
reed@google.com4b226022011-01-11 18:32:13 +00001853
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001854 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855
1856 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001857 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001858 }
1859
reed@google.com4e2b3d32011-04-07 14:18:59 +00001860 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001861}
1862
reed41af9662015-01-05 07:49:08 -08001863void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001864 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001865 SkRect storage;
1866 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001867 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001868 bounds = &paint.computeFastBounds(oval, &storage);
1869 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001870 return;
1871 }
1872 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001873
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001874 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001875
1876 while (iter.next()) {
1877 iter.fDevice->drawOval(iter, oval, looper.paint());
1878 }
1879
1880 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001881}
1882
reed41af9662015-01-05 07:49:08 -08001883void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001885 SkRect storage;
1886 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001887 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001888 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1889 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001890 return;
1891 }
1892 }
1893
1894 if (rrect.isRect()) {
1895 // call the non-virtual version
1896 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001897 return;
1898 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001899 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001900 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1901 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001902 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001903
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001904 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001905
1906 while (iter.next()) {
1907 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1908 }
1909
1910 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001911}
1912
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001913void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1914 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001915 SkRect storage;
1916 const SkRect* bounds = NULL;
1917 if (paint.canComputeFastBounds()) {
1918 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1919 if (this->quickReject(*bounds)) {
1920 return;
1921 }
1922 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001923
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001924 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001925
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001926 while (iter.next()) {
1927 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1928 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001929
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001930 LOOPER_END
1931}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001932
reed41af9662015-01-05 07:49:08 -08001933void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001934 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001935 if (!path.isFinite()) {
1936 return;
1937 }
1938
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001939 SkRect storage;
1940 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001941 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001942 const SkRect& pathBounds = path.getBounds();
1943 bounds = &paint.computeFastBounds(pathBounds, &storage);
1944 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945 return;
1946 }
1947 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001948
1949 const SkRect& r = path.getBounds();
1950 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001951 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001952 this->internalDrawPaint(paint);
1953 }
1954 return;
1955 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001957 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001958
1959 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001960 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961 }
1962
reed@google.com4e2b3d32011-04-07 14:18:59 +00001963 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001964}
1965
kkinnunena9baa652015-03-05 06:33:54 -08001966void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001967 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001968 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001969}
1970
reed41af9662015-01-05 07:49:08 -08001971void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1972 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001973 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001974 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001975}
1976
reed41af9662015-01-05 07:49:08 -08001977void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001978 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979 SkDEBUGCODE(bitmap.validate();)
1980
reed@google.com3d608122011-11-21 15:16:16 +00001981 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001982 SkRect bounds = {
1983 x, y,
1984 x + SkIntToScalar(bitmap.width()),
1985 y + SkIntToScalar(bitmap.height())
1986 };
1987 if (paint) {
1988 (void)paint->computeFastBounds(bounds, &bounds);
1989 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001990 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001991 return;
1992 }
1993 }
reed@google.com4b226022011-01-11 18:32:13 +00001994
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 SkMatrix matrix;
1996 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001997 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998}
1999
reed@google.com9987ec32011-09-07 11:57:52 +00002000// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002001void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002002 const SkRect& dst, const SkPaint* paint,
2003 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002004 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002005 return;
2006 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002007
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002008 SkRect storage;
2009 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002010 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002011 if (paint) {
2012 bounds = &paint->computeFastBounds(dst, &storage);
2013 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002014 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002015 return;
2016 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017 }
reed@google.com3d608122011-11-21 15:16:16 +00002018
reed@google.com33535f32012-09-25 15:37:50 +00002019 SkLazyPaint lazy;
2020 if (NULL == paint) {
2021 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002023
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002024 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002025
reed@google.com33535f32012-09-25 15:37:50 +00002026 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002027 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002028 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002029
reed@google.com33535f32012-09-25 15:37:50 +00002030 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031}
2032
reed41af9662015-01-05 07:49:08 -08002033void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2034 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002035 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002036 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002037 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002038}
2039
reed@google.com9987ec32011-09-07 11:57:52 +00002040void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2041 const SkIRect& center, const SkRect& dst,
2042 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002043 if (bitmap.drawsNothing()) {
2044 return;
2045 }
reed@google.com3d608122011-11-21 15:16:16 +00002046 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002047 SkRect storage;
2048 const SkRect* bounds = &dst;
2049 if (paint) {
2050 bounds = &paint->computeFastBounds(dst, &storage);
2051 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002052 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002053 return;
2054 }
2055 }
2056
reed@google.com9987ec32011-09-07 11:57:52 +00002057 const int32_t w = bitmap.width();
2058 const int32_t h = bitmap.height();
2059
2060 SkIRect c = center;
2061 // pin center to the bounds of the bitmap
2062 c.fLeft = SkMax32(0, center.fLeft);
2063 c.fTop = SkMax32(0, center.fTop);
2064 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2065 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2066
reed@google.com71121732012-09-18 15:14:33 +00002067 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002068 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002069 };
2070 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002071 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002072 };
reed@google.com9987ec32011-09-07 11:57:52 +00002073 SkScalar dstX[4] = {
2074 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2075 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2076 };
2077 SkScalar dstY[4] = {
2078 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2079 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2080 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002081
reed@google.com9987ec32011-09-07 11:57:52 +00002082 if (dstX[1] > dstX[2]) {
2083 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2084 dstX[2] = dstX[1];
2085 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002086
reed@google.com9987ec32011-09-07 11:57:52 +00002087 if (dstY[1] > dstY[2]) {
2088 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2089 dstY[2] = dstY[1];
2090 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002091
reed@google.com9987ec32011-09-07 11:57:52 +00002092 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002093 SkRect s, d;
2094
reed@google.com9987ec32011-09-07 11:57:52 +00002095 s.fTop = srcY[y];
2096 s.fBottom = srcY[y+1];
2097 d.fTop = dstY[y];
2098 d.fBottom = dstY[y+1];
2099 for (int x = 0; x < 3; x++) {
2100 s.fLeft = srcX[x];
2101 s.fRight = srcX[x+1];
2102 d.fLeft = dstX[x];
2103 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002104 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002105 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002106 }
2107 }
2108}
2109
reed41af9662015-01-05 07:49:08 -08002110void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2111 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002112 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002113 SkDEBUGCODE(bitmap.validate();)
2114
2115 // Need a device entry-point, so gpu can use a mesh
2116 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2117}
2118
reed@google.comf67e4cf2011-03-15 20:56:58 +00002119class SkDeviceFilteredPaint {
2120public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002121 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002122 uint32_t filteredFlags = device->filterTextFlags(paint);
2123 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002124 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002125 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002126 fPaint = newPaint;
2127 } else {
2128 fPaint = &paint;
2129 }
2130 }
2131
reed@google.comf67e4cf2011-03-15 20:56:58 +00002132 const SkPaint& paint() const { return *fPaint; }
2133
2134private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002135 const SkPaint* fPaint;
2136 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002137};
2138
bungeman@google.com52c748b2011-08-22 21:30:43 +00002139void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2140 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002141 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002142 draw.fDevice->drawRect(draw, r, paint);
2143 } else {
2144 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002145 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002146 draw.fDevice->drawRect(draw, r, p);
2147 }
2148}
2149
2150void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2151 const char text[], size_t byteLength,
2152 SkScalar x, SkScalar y) {
2153 SkASSERT(byteLength == 0 || text != NULL);
2154
2155 // nothing to draw
2156 if (text == NULL || byteLength == 0 ||
2157 draw.fClip->isEmpty() ||
2158 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2159 return;
2160 }
2161
2162 SkScalar width = 0;
2163 SkPoint start;
2164
2165 start.set(0, 0); // to avoid warning
2166 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2167 SkPaint::kStrikeThruText_Flag)) {
2168 width = paint.measureText(text, byteLength);
2169
2170 SkScalar offsetX = 0;
2171 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2172 offsetX = SkScalarHalf(width);
2173 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2174 offsetX = width;
2175 }
2176 start.set(x - offsetX, y);
2177 }
2178
2179 if (0 == width) {
2180 return;
2181 }
2182
2183 uint32_t flags = paint.getFlags();
2184
2185 if (flags & (SkPaint::kUnderlineText_Flag |
2186 SkPaint::kStrikeThruText_Flag)) {
2187 SkScalar textSize = paint.getTextSize();
2188 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2189 SkRect r;
2190
2191 r.fLeft = start.fX;
2192 r.fRight = start.fX + width;
2193
2194 if (flags & SkPaint::kUnderlineText_Flag) {
2195 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2196 start.fY);
2197 r.fTop = offset;
2198 r.fBottom = offset + height;
2199 DrawRect(draw, paint, r, textSize);
2200 }
2201 if (flags & SkPaint::kStrikeThruText_Flag) {
2202 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2203 start.fY);
2204 r.fTop = offset;
2205 r.fBottom = offset + height;
2206 DrawRect(draw, paint, r, textSize);
2207 }
2208 }
2209}
2210
reed@google.come0d9ce82014-04-23 04:00:17 +00002211void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2212 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002213 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002214
2215 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002216 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002217 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002218 DrawTextDecorations(iter, dfp.paint(),
2219 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220 }
2221
reed@google.com4e2b3d32011-04-07 14:18:59 +00002222 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002223}
2224
reed@google.come0d9ce82014-04-23 04:00:17 +00002225void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2226 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002227 SkPoint textOffset = SkPoint::Make(0, 0);
2228
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002229 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002230
reed@android.com8a1c16f2008-12-17 15:59:43 +00002231 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002232 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002233 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002234 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002235 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002236
reed@google.com4e2b3d32011-04-07 14:18:59 +00002237 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002238}
2239
reed@google.come0d9ce82014-04-23 04:00:17 +00002240void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2241 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002242
2243 SkPoint textOffset = SkPoint::Make(0, constY);
2244
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002245 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002246
reed@android.com8a1c16f2008-12-17 15:59:43 +00002247 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002248 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002249 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002250 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002251 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002252
reed@google.com4e2b3d32011-04-07 14:18:59 +00002253 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002254}
2255
reed@google.come0d9ce82014-04-23 04:00:17 +00002256void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2257 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002258 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002259
reed@android.com8a1c16f2008-12-17 15:59:43 +00002260 while (iter.next()) {
2261 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002262 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002263 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002264
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002265 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002266}
2267
fmalita00d5c2c2014-08-21 08:53:26 -07002268void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2269 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002270
fmalita85d5eb92015-03-04 11:20:12 -08002271 SkRect storage;
2272 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002273 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002274 storage = blob->bounds().makeOffset(x, y);
2275 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002276
fmalita85d5eb92015-03-04 11:20:12 -08002277 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002278 return;
2279 }
2280 }
2281
fmalita024f9962015-03-03 19:08:17 -08002282 // We cannot filter in the looper as we normally do, because the paint is
2283 // incomplete at this point (text-related attributes are embedded within blob run paints).
2284 SkDrawFilter* drawFilter = fMCRec->fFilter;
2285 fMCRec->fFilter = NULL;
2286
fmalita85d5eb92015-03-04 11:20:12 -08002287 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002288
fmalitaaa1b9122014-08-28 14:32:24 -07002289 while (iter.next()) {
2290 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002291 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002292 }
2293
fmalitaaa1b9122014-08-28 14:32:24 -07002294 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002295
2296 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002297}
2298
reed@google.come0d9ce82014-04-23 04:00:17 +00002299// These will become non-virtual, so they always call the (virtual) onDraw... method
2300void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2301 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002302 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002303 this->onDrawText(text, byteLength, x, y, paint);
2304}
2305void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2306 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002307 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002308 this->onDrawPosText(text, byteLength, pos, paint);
2309}
2310void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2311 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002312 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002313 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2314}
2315void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2316 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002317 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002318 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2319}
fmalita00d5c2c2014-08-21 08:53:26 -07002320void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2321 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002322 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002323 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002324 this->onDrawTextBlob(blob, x, y, paint);
2325 }
2326}
reed@google.come0d9ce82014-04-23 04:00:17 +00002327
reed41af9662015-01-05 07:49:08 -08002328void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2329 const SkPoint verts[], const SkPoint texs[],
2330 const SkColor colors[], SkXfermode* xmode,
2331 const uint16_t indices[], int indexCount,
2332 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002333 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002334 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002335
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 while (iter.next()) {
2337 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002338 colors, xmode, indices, indexCount,
2339 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002340 }
reed@google.com4b226022011-01-11 18:32:13 +00002341
reed@google.com4e2b3d32011-04-07 14:18:59 +00002342 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002343}
2344
dandovb3c9d1c2014-08-12 08:34:29 -07002345void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2346 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002348 if (NULL == cubics) {
2349 return;
2350 }
mtklein6cfa73a2014-08-13 13:33:49 -07002351
dandovecfff212014-08-04 10:02:00 -07002352 // Since a patch is always within the convex hull of the control points, we discard it when its
2353 // bounding rectangle is completely outside the current clip.
2354 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002355 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002356 if (this->quickReject(bounds)) {
2357 return;
2358 }
mtklein6cfa73a2014-08-13 13:33:49 -07002359
dandovb3c9d1c2014-08-12 08:34:29 -07002360 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2361}
2362
2363void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2364 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2365
dandovecfff212014-08-04 10:02:00 -07002366 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002367
dandovecfff212014-08-04 10:02:00 -07002368 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002369 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002370 }
mtklein6cfa73a2014-08-13 13:33:49 -07002371
dandovecfff212014-08-04 10:02:00 -07002372 LOOPER_END
2373}
2374
reed3cb38402015-02-06 08:36:15 -08002375void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002376 if (dr && !this->quickReject(dr->getBounds())) {
2377 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002378 }
2379}
2380
reed3cb38402015-02-06 08:36:15 -08002381void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002382 dr->draw(this);
2383}
2384
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385//////////////////////////////////////////////////////////////////////////////
2386// These methods are NOT virtual, and therefore must call back into virtual
2387// methods, rather than actually drawing themselves.
2388//////////////////////////////////////////////////////////////////////////////
2389
2390void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002391 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002393 SkPaint paint;
2394
2395 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002396 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002397 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002398 }
2399 this->drawPaint(paint);
2400}
2401
reed@android.com845fdac2009-06-23 03:01:32 +00002402void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002403 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 SkPaint paint;
2405
2406 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002407 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002408 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409 }
2410 this->drawPaint(paint);
2411}
2412
2413void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002414 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002416
reed@android.com8a1c16f2008-12-17 15:59:43 +00002417 pt.set(x, y);
2418 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2419}
2420
2421void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002422 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 SkPoint pt;
2424 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002425
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426 pt.set(x, y);
2427 paint.setColor(color);
2428 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2429}
2430
2431void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2432 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002433 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002434 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002435
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436 pts[0].set(x0, y0);
2437 pts[1].set(x1, y1);
2438 this->drawPoints(kLines_PointMode, 2, pts, paint);
2439}
2440
2441void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2442 SkScalar right, SkScalar bottom,
2443 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002444 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445 SkRect r;
2446
2447 r.set(left, top, right, bottom);
2448 this->drawRect(r, paint);
2449}
2450
2451void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2452 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002453 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002454 if (radius < 0) {
2455 radius = 0;
2456 }
2457
2458 SkRect r;
2459 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002460 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002461}
2462
2463void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2464 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002465 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466 if (rx > 0 && ry > 0) {
2467 if (paint.canComputeFastBounds()) {
2468 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002469 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470 return;
2471 }
2472 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002473 SkRRect rrect;
2474 rrect.setRectXY(r, rx, ry);
2475 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 } else {
2477 this->drawRect(r, paint);
2478 }
2479}
2480
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2482 SkScalar sweepAngle, bool useCenter,
2483 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002484 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2486 this->drawOval(oval, paint);
2487 } else {
2488 SkPath path;
2489 if (useCenter) {
2490 path.moveTo(oval.centerX(), oval.centerY());
2491 }
2492 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2493 if (useCenter) {
2494 path.close();
2495 }
2496 this->drawPath(path, paint);
2497 }
2498}
2499
2500void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2501 const SkPath& path, SkScalar hOffset,
2502 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002503 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002505
reed@android.com8a1c16f2008-12-17 15:59:43 +00002506 matrix.setTranslate(hOffset, vOffset);
2507 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2508}
2509
reed@android.comf76bacf2009-05-13 14:00:33 +00002510///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002511
2512/**
2513 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2514 * against the playback cost of recursing into the subpicture to get at its actual ops.
2515 *
2516 * For now we pick a conservatively small value, though measurement (and other heuristics like
2517 * the type of ops contained) may justify changing this value.
2518 */
2519#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002520
reedd5fa1a42014-08-09 11:08:05 -07002521void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002522 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002523 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002524 if (matrix && matrix->isIdentity()) {
2525 matrix = NULL;
2526 }
reed1c2c4412015-04-30 13:09:24 -07002527 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2528 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2529 picture->playback(this);
2530 } else {
2531 this->onDrawPicture(picture, matrix, paint);
2532 }
reedd5fa1a42014-08-09 11:08:05 -07002533 }
2534}
robertphillips9b14f262014-06-04 05:40:44 -07002535
reedd5fa1a42014-08-09 11:08:05 -07002536void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2537 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002538 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002539 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002540 // Canvas has to first give the device the opportunity to render
2541 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002542 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002543 return; // the device has rendered the entire picture
2544 }
2545 }
2546
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002547 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002548 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549}
2550
reed@android.com8a1c16f2008-12-17 15:59:43 +00002551///////////////////////////////////////////////////////////////////////////////
2552///////////////////////////////////////////////////////////////////////////////
2553
2554SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002555 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002556
2557 SkASSERT(canvas);
2558
2559 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2560 fDone = !fImpl->next();
2561}
2562
2563SkCanvas::LayerIter::~LayerIter() {
2564 fImpl->~SkDrawIter();
2565}
2566
2567void SkCanvas::LayerIter::next() {
2568 fDone = !fImpl->next();
2569}
2570
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002571SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 return fImpl->getDevice();
2573}
2574
2575const SkMatrix& SkCanvas::LayerIter::matrix() const {
2576 return fImpl->getMatrix();
2577}
2578
2579const SkPaint& SkCanvas::LayerIter::paint() const {
2580 const SkPaint* paint = fImpl->getPaint();
2581 if (NULL == paint) {
2582 paint = &fDefaultPaint;
2583 }
2584 return *paint;
2585}
2586
2587const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2588int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2589int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002590
2591///////////////////////////////////////////////////////////////////////////////
2592
fmalitac3b589a2014-06-05 12:40:07 -07002593SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002594
2595///////////////////////////////////////////////////////////////////////////////
2596
2597static bool supported_for_raster_canvas(const SkImageInfo& info) {
2598 switch (info.alphaType()) {
2599 case kPremul_SkAlphaType:
2600 case kOpaque_SkAlphaType:
2601 break;
2602 default:
2603 return false;
2604 }
2605
2606 switch (info.colorType()) {
2607 case kAlpha_8_SkColorType:
2608 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002609 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002610 break;
2611 default:
2612 return false;
2613 }
2614
2615 return true;
2616}
2617
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002618SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2619 if (!supported_for_raster_canvas(info)) {
2620 return NULL;
2621 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002622
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002623 SkBitmap bitmap;
2624 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2625 return NULL;
2626 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002627 return SkNEW_ARGS(SkCanvas, (bitmap));
2628}
reedd5fa1a42014-08-09 11:08:05 -07002629
2630///////////////////////////////////////////////////////////////////////////////
2631
2632SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002633 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002634 : fCanvas(canvas)
2635 , fSaveCount(canvas->getSaveCount())
2636{
bsalomon49f085d2014-09-05 13:34:00 -07002637 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002638 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002639 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002640 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002641 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002642 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002643 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002644 canvas->save();
2645 }
mtklein6cfa73a2014-08-13 13:33:49 -07002646
bsalomon49f085d2014-09-05 13:34:00 -07002647 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002648 canvas->concat(*matrix);
2649 }
2650}
2651
2652SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2653 fCanvas->restoreToCount(fSaveCount);
2654}