blob: 90bc1f433e9dea46b7051a87f86af8503bba87f0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkCanvas_DEFINED
11#define SkCanvas_DEFINED
12
13#include "SkTypes.h"
14#include "SkBitmap.h"
15#include "SkDeque.h"
reed@google.com5c3d1472011-02-22 19:12:23 +000016#include "SkClipStack.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkPaint.h"
18#include "SkRefCnt.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019#include "SkPath.h"
20#include "SkRegion.h"
21#include "SkScalarCompare.h"
reed@android.com845fdac2009-06-23 03:01:32 +000022#include "SkXfermode.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
24class SkBounder;
25class SkDevice;
26class SkDraw;
27class SkDrawFilter;
28class SkPicture;
29
30/** \class SkCanvas
31
32 A Canvas encapsulates all of the state about drawing into a device (bitmap).
33 This includes a reference to the device itself, and a stack of matrix/clip
34 values. For any given draw call (e.g. drawRect), the geometry of the object
35 being drawn is transformed by the concatenation of all the matrices in the
36 stack. The transformed geometry is clipped by the intersection of all of
37 the clips in the stack.
38
39 While the Canvas holds the state of the drawing device, the state (style)
40 of the object being drawn is held by the Paint, which is provided as a
41 parameter to each of the draw() methods. The Paint holds attributes such as
42 color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns),
43 etc.
44*/
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000045class SK_API SkCanvas : public SkRefCnt {
reed@android.com8a1c16f2008-12-17 15:59:43 +000046public:
reed@google.comcde92112011-07-06 20:00:52 +000047 SkCanvas();
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +000048
reed@google.com6dc74552011-07-21 18:00:46 +000049 /** Construct a canvas with the specified device to draw into.
bsalomon@google.come97f0852011-06-17 13:10:25 +000050
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +000051 @param device Specifies a device for the canvas to draw into.
52 */
53 explicit SkCanvas(SkDevice* device);
54
55 /** Deprecated - Construct a canvas with the specified bitmap to draw into.
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 @param bitmap Specifies a bitmap for the canvas to draw into. Its
57 structure are copied to the canvas.
58 */
59 explicit SkCanvas(const SkBitmap& bitmap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 virtual ~SkCanvas();
61
62 ///////////////////////////////////////////////////////////////////////////
63
reed@google.com210ce002011-11-01 14:24:23 +000064 /**
65 * Return the width/height of the underlying device. The current drawable
66 * area may be small (due to clipping or saveLayer). For a canvas with
67 * no device, 0,0 will be returned.
68 */
69 SkISize getDeviceSize() const;
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 /** Return the canvas' device object, which may be null. The device holds
72 the bitmap of the pixels that the canvas draws into. The reference count
73 of the returned device is not changed by this call.
74 */
75 SkDevice* getDevice() const;
76
77 /** Specify a device for this canvas to draw into. If it is not null, its
78 reference count is incremented. If the canvas was already holding a
79 device, its reference count is decremented. The new device is returned.
80 */
81 SkDevice* setDevice(SkDevice* device);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +000082
reed@google.com9266fed2011-03-30 00:18:03 +000083 /**
84 * saveLayer() can create another device (which is later drawn onto
85 * the previous device). getTopDevice() returns the top-most device current
86 * installed. Note that this can change on other calls like save/restore,
87 * so do not access this device after subsequent canvas calls.
88 * The reference count of the device is not changed.
89 */
90 SkDevice* getTopDevice() const;
91
reed@android.comf2b98d62010-12-20 18:26:13 +000092 /**
93 * Create a new raster device and make it current. This also returns
94 * the new device.
95 */
reed@google.comaf951c92011-06-16 19:10:39 +000096 SkDevice* setBitmapDevice(const SkBitmap& bitmap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
reed@google.com51df9e32010-12-23 19:29:18 +000098 /**
reed@google.comcde92112011-07-06 20:00:52 +000099 * Shortcut for getDevice()->createCompatibleDevice(...).
100 * If getDevice() == NULL, this method does nothing, and returns NULL.
bsalomon@google.come97f0852011-06-17 13:10:25 +0000101 */
102 SkDevice* createCompatibleDevice(SkBitmap::Config config,
103 int width, int height,
104 bool isOpaque);
105
reed@google.com4b226022011-01-11 18:32:13 +0000106 ///////////////////////////////////////////////////////////////////////////
107
bsalomon@google.comc6980972011-11-02 19:57:21 +0000108 /**
109 * On success (returns true), copy the canvas pixels into the bitmap.
110 * On failure, the bitmap parameter is left unchanged and false is
111 * returned.
112 *
113 * If the canvas is backed by a non-raster device (e.g. PDF) then
114 * readPixels will fail.
115 *
116 * If the bitmap has pixels already allocated, the canvas pixels will be
117 * written there. If not, bitmap->allocPixels() will be called
118 * automatically. If the bitmap is backed by a texture readPixels will
119 * fail.
120 *
121 * The canvas' pixels are converted to the bitmap's config. The only
122 * supported config is kARGB_8888_Config, though this may be relaxed in
123 * future.
124 *
125 * The actual pixels written is the intersection of the canvas' bounds, and
126 * the rectangle formed by the bitmap's width,height and the specified x,y.
127 * If bitmap pixels extend outside of that intersection, they will not be
128 * modified.
129 *
130 * Example that reads the entire canvas into a bitmap:
131 * SkISize size = canvas->getDeviceSize();
132 * bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
133 * size.fHeight);
134 * if (canvas->readPixels(bitmap, 0, 0)) {
135 * // use the pixels
136 * }
137 */
138 bool readPixels(SkBitmap* bitmap, int x, int y);
139
reed@google.com4b226022011-01-11 18:32:13 +0000140 /**
bsalomon@google.comc6980972011-11-02 19:57:21 +0000141 * DEPRECATED: This will be removed as soon as webkit is no longer relying
142 * on it. The bitmap is resized to the intersection of srcRect and the
143 * canvas bounds. New pixels are always allocated on success. Bitmap is
144 * unmodified on failure.
reed@google.com51df9e32010-12-23 19:29:18 +0000145 */
146 bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
reed@google.com51df9e32010-12-23 19:29:18 +0000147
148 /**
149 * Similar to draw sprite, this method will copy the pixels in bitmap onto
150 * the device, with the top/left corner specified by (x, y). The pixel
151 * values in the device are completely replaced: there is no blending.
epoger@google.com4f1151a2011-07-25 15:47:33 +0000152 *
153 * Note: If you are recording drawing commands on this canvas to
154 * SkPicture, writePixels() is ignored!
reed@google.com51df9e32010-12-23 19:29:18 +0000155 */
156 void writePixels(const SkBitmap& bitmap, int x, int y);
reed@google.com4b226022011-01-11 18:32:13 +0000157
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 ///////////////////////////////////////////////////////////////////////////
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000159
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 enum SaveFlags {
161 /** save the matrix state, restoring it on restore() */
162 kMatrix_SaveFlag = 0x01,
163 /** save the clip state, restoring it on restore() */
164 kClip_SaveFlag = 0x02,
165 /** the layer needs to support per-pixel alpha */
166 kHasAlphaLayer_SaveFlag = 0x04,
167 /** the layer needs to support 8-bits per color component */
168 kFullColorLayer_SaveFlag = 0x08,
169 /** the layer should clip against the bounds argument */
170 kClipToLayer_SaveFlag = 0x10,
171
172 // helper masks for common choices
173 kMatrixClip_SaveFlag = 0x03,
174 kARGB_NoClipLayer_SaveFlag = 0x0F,
175 kARGB_ClipLayer_SaveFlag = 0x1F
176 };
177
reed@android.comdc3381f2010-02-11 16:05:15 +0000178 /** This call saves the current matrix, clip, and drawFilter, and pushes a
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 copy onto a private stack. Subsequent calls to translate, scale,
reed@android.comdc3381f2010-02-11 16:05:15 +0000180 rotate, skew, concat or clipRect, clipPath, and setDrawFilter all
181 operate on this copy.
182 When the balancing call to restore() is made, the previous matrix, clip,
183 and drawFilter are restored.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 @return The value to pass to restoreToCount() to balance this save()
185 */
186 virtual int save(SaveFlags flags = kMatrixClip_SaveFlag);
187
188 /** This behaves the same as save(), but in addition it allocates an
189 offscreen bitmap. All drawing calls are directed there, and only when
190 the balancing call to restore() is made is that offscreen transfered to
reed@android.comdc3381f2010-02-11 16:05:15 +0000191 the canvas (or the previous layer).
reed@android.comad164b22010-07-02 17:20:51 +0000192 @param bounds (may be null) This rect, if non-null, is used as a hint to
193 limit the size of the offscreen, and thus drawing may be
194 clipped to it, though that clipping is not guaranteed to
195 happen. If exact clipping is desired, use clipRect().
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 @param paint (may be null) This is copied, and is applied to the
197 offscreen when restore() is called
198 @param flags LayerFlags
199 @return The value to pass to restoreToCount() to balance this save()
200 */
201 virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
202 SaveFlags flags = kARGB_ClipLayer_SaveFlag);
203
204 /** This behaves the same as save(), but in addition it allocates an
205 offscreen bitmap. All drawing calls are directed there, and only when
206 the balancing call to restore() is made is that offscreen transfered to
reed@android.comdc3381f2010-02-11 16:05:15 +0000207 the canvas (or the previous layer).
reed@android.com40408612010-07-02 17:24:23 +0000208 @param bounds (may be null) This rect, if non-null, is used as a hint to
209 limit the size of the offscreen, and thus drawing may be
210 clipped to it, though that clipping is not guaranteed to
211 happen. If exact clipping is desired, use clipRect().
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 @param alpha This is applied to the offscreen when restore() is called.
213 @param flags LayerFlags
214 @return The value to pass to restoreToCount() to balance this save()
215 */
216 int saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
217 SaveFlags flags = kARGB_ClipLayer_SaveFlag);
218
219 /** This call balances a previous call to save(), and is used to remove all
reed@android.comdc3381f2010-02-11 16:05:15 +0000220 modifications to the matrix/clip/drawFilter state since the last save
221 call.
222 It is an error to call restore() more times than save() was called.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 */
224 virtual void restore();
225
226 /** Returns the number of matrix/clip states on the SkCanvas' private stack.
227 This will equal # save() calls - # restore() calls.
228 */
229 int getSaveCount() const;
230
231 /** Efficient way to pop any calls to save() that happened after the save
232 count reached saveCount. It is an error for saveCount to be less than
233 getSaveCount()
234 @param saveCount The number of save() levels to restore from
235 */
236 void restoreToCount(int saveCount);
237
238 /** Preconcat the current matrix with the specified translation
239 @param dx The distance to translate in X
240 @param dy The distance to translate in Y
241 returns true if the operation succeeded (e.g. did not overflow)
242 */
243 virtual bool translate(SkScalar dx, SkScalar dy);
244
245 /** Preconcat the current matrix with the specified scale.
246 @param sx The amount to scale in X
247 @param sy The amount to scale in Y
248 returns true if the operation succeeded (e.g. did not overflow)
249 */
250 virtual bool scale(SkScalar sx, SkScalar sy);
251
252 /** Preconcat the current matrix with the specified rotation.
253 @param degrees The amount to rotate, in degrees
254 returns true if the operation succeeded (e.g. did not overflow)
255 */
256 virtual bool rotate(SkScalar degrees);
257
258 /** Preconcat the current matrix with the specified skew.
259 @param sx The amount to skew in X
260 @param sy The amount to skew in Y
261 returns true if the operation succeeded (e.g. did not overflow)
262 */
263 virtual bool skew(SkScalar sx, SkScalar sy);
264
265 /** Preconcat the current matrix with the specified matrix.
266 @param matrix The matrix to preconcatenate with the current matrix
267 @return true if the operation succeeded (e.g. did not overflow)
268 */
269 virtual bool concat(const SkMatrix& matrix);
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 /** Replace the current matrix with a copy of the specified matrix.
272 @param matrix The matrix that will be copied into the current matrix.
273 */
274 virtual void setMatrix(const SkMatrix& matrix);
reed@google.com4b226022011-01-11 18:32:13 +0000275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 /** Helper for setMatrix(identity). Sets the current matrix to identity.
277 */
278 void resetMatrix();
279
280 /** Modify the current clip with the specified rectangle.
281 @param rect The rect to intersect with the current clip
282 @param op The region op to apply to the current clip
283 @return true if the canvas' clip is non-empty
284 */
285 virtual bool clipRect(const SkRect& rect,
reed@google.com071eef92011-10-12 11:52:53 +0000286 SkRegion::Op op = SkRegion::kIntersect_Op,
287 bool doAntiAlias = false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288
289 /** Modify the current clip with the specified path.
290 @param path The path to apply to the current clip
291 @param op The region op to apply to the current clip
292 @return true if the canvas' new clip is non-empty
293 */
294 virtual bool clipPath(const SkPath& path,
reed@google.com071eef92011-10-12 11:52:53 +0000295 SkRegion::Op op = SkRegion::kIntersect_Op,
296 bool doAntiAlias = false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297
298 /** Modify the current clip with the specified region. Note that unlike
299 clipRect() and clipPath() which transform their arguments by the current
300 matrix, clipRegion() assumes its argument is already in device
301 coordinates, and so no transformation is performed.
302 @param deviceRgn The region to apply to the current clip
303 @param op The region op to apply to the current clip
304 @return true if the canvas' new clip is non-empty
305 */
306 virtual bool clipRegion(const SkRegion& deviceRgn,
307 SkRegion::Op op = SkRegion::kIntersect_Op);
308
309 /** Helper for clipRegion(rgn, kReplace_Op). Sets the current clip to the
310 specified region. This does not intersect or in any other way account
311 for the existing clip region.
312 @param deviceRgn The region to copy into the current clip.
313 @return true if the new clip region is non-empty
314 */
315 bool setClipRegion(const SkRegion& deviceRgn) {
316 return this->clipRegion(deviceRgn, SkRegion::kReplace_Op);
317 }
318
319 /** Enum describing how to treat edges when performing quick-reject tests
320 of a geometry against the current clip. Treating them as antialiased
321 (kAA_EdgeType) will take into account the extra pixels that may be drawn
322 if the edge does not lie exactly on a device pixel boundary (after being
323 transformed by the current matrix).
324 */
325 enum EdgeType {
326 /** Treat the edges as B&W (not antialiased) for the purposes of testing
327 against the current clip
328 */
329 kBW_EdgeType,
330 /** Treat the edges as antialiased for the purposes of testing
331 against the current clip
332 */
333 kAA_EdgeType
334 };
335
336 /** Return true if the specified rectangle, after being transformed by the
337 current matrix, would lie completely outside of the current clip. Call
338 this to check if an area you intend to draw into is clipped out (and
339 therefore you can skip making the draw calls).
340 @param rect the rect to compare with the current clip
341 @param et specifies how to treat the edges (see EdgeType)
342 @return true if the rect (transformed by the canvas' matrix) does not
343 intersect with the canvas' clip
344 */
345 bool quickReject(const SkRect& rect, EdgeType et) const;
346
347 /** Return true if the specified path, after being transformed by the
348 current matrix, would lie completely outside of the current clip. Call
349 this to check if an area you intend to draw into is clipped out (and
350 therefore you can skip making the draw calls). Note, for speed it may
351 return false even if the path itself might not intersect the clip
352 (i.e. the bounds of the path intersects, but the path does not).
353 @param path The path to compare with the current clip
354 @param et specifies how to treat the edges (see EdgeType)
355 @return true if the path (transformed by the canvas' matrix) does not
356 intersect with the canvas' clip
357 */
358 bool quickReject(const SkPath& path, EdgeType et) const;
359
360 /** Return true if the horizontal band specified by top and bottom is
361 completely clipped out. This is a conservative calculation, meaning
362 that it is possible that if the method returns false, the band may still
363 in fact be clipped out, but the converse is not true. If this method
364 returns true, then the band is guaranteed to be clipped out.
365 @param top The top of the horizontal band to compare with the clip
366 @param bottom The bottom of the horizontal and to compare with the clip
367 @return true if the horizontal band is completely clipped out (i.e. does
368 not intersect the current clip)
369 */
370 bool quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const;
371
372 /** Return the bounds of the current clip (in local coordinates) in the
373 bounds parameter, and return true if it is non-empty. This can be useful
374 in a way similar to quickReject, in that it tells you that drawing
375 outside of these bounds will be clipped out.
376 */
377 bool getClipBounds(SkRect* bounds, EdgeType et = kAA_EdgeType) const;
378
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000379 /** Return the bounds of the current clip, in device coordinates; returns
380 true if non-empty. Maybe faster than getting the clip explicitly and
381 then taking its bounds.
382 */
383 bool getClipDeviceBounds(SkIRect* bounds) const;
384
385
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 /** Fill the entire canvas' bitmap (restricted to the current clip) with the
reed@android.com845fdac2009-06-23 03:01:32 +0000387 specified ARGB color, using the specified mode.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 @param a the alpha component (0..255) of the color to fill the canvas
389 @param r the red component (0..255) of the color to fill the canvas
390 @param g the green component (0..255) of the color to fill the canvas
391 @param b the blue component (0..255) of the color to fill the canvas
392 @param mode the mode to apply the color in (defaults to SrcOver)
393 */
394 void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +0000395 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396
397 /** Fill the entire canvas' bitmap (restricted to the current clip) with the
reed@android.com845fdac2009-06-23 03:01:32 +0000398 specified color and mode.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 @param color the color to draw with
400 @param mode the mode to apply the color in (defaults to SrcOver)
401 */
402 void drawColor(SkColor color,
reed@android.com845fdac2009-06-23 03:01:32 +0000403 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404
reed@google.com2a981812011-04-14 18:59:28 +0000405 /**
406 * This erases the entire drawing surface to the specified color,
407 * irrespective of the clip. It does not blend with the previous pixels,
408 * but always overwrites them.
409 *
410 * It is roughly equivalent to the following:
411 * canvas.save();
412 * canvas.clipRect(hugeRect, kReplace_Op);
413 * paint.setColor(color);
414 * paint.setXfermodeMode(kSrc_Mode);
415 * canvas.drawPaint(paint);
416 * canvas.restore();
417 * though it is almost always much more efficient.
418 */
419 virtual void clear(SkColor);
420
421 /**
422 * Fill the entire canvas' bitmap (restricted to the current clip) with the
423 * specified paint.
424 * @param paint The paint used to fill the canvas
425 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 virtual void drawPaint(const SkPaint& paint);
427
428 enum PointMode {
429 /** drawPoints draws each point separately */
430 kPoints_PointMode,
431 /** drawPoints draws each pair of points as a line segment */
432 kLines_PointMode,
433 /** drawPoints draws the array of points as a polygon */
434 kPolygon_PointMode
435 };
436
437 /** Draw a series of points, interpreted based on the PointMode mode. For
438 all modes, the count parameter is interpreted as the total number of
439 points. For kLine mode, count/2 line segments are drawn.
440 For kPoint mode, each point is drawn centered at its coordinate, and its
441 size is specified by the paint's stroke-width. It draws as a square,
442 unless the paint's cap-type is round, in which the points are drawn as
443 circles.
444 For kLine mode, each pair of points is drawn as a line segment,
445 respecting the paint's settings for cap/join/width.
446 For kPolygon mode, the entire array is drawn as a series of connected
447 line segments.
448 Note that, while similar, kLine and kPolygon modes draw slightly
449 differently than the equivalent path built with a series of moveto,
450 lineto calls, in that the path will draw all of its contours at once,
451 with no interactions if contours intersect each other (think XOR
452 xfermode). drawPoints always draws each element one at a time.
453 @param mode PointMode specifying how to draw the array of points.
454 @param count The number of points in the array
455 @param pts Array of points to draw
456 @param paint The paint used to draw the points
457 */
458 virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
459 const SkPaint& paint);
460
461 /** Helper method for drawing a single point. See drawPoints() for a more
462 details.
463 */
464 void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint);
reed@google.com4b226022011-01-11 18:32:13 +0000465
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 /** Draws a single pixel in the specified color.
467 @param x The X coordinate of which pixel to draw
468 @param y The Y coordiante of which pixel to draw
469 @param color The color to draw
470 */
471 void drawPoint(SkScalar x, SkScalar y, SkColor color);
472
473 /** Draw a line segment with the specified start and stop x,y coordinates,
474 using the specified paint. NOTE: since a line is always "framed", the
475 paint's Style is ignored.
476 @param x0 The x-coordinate of the start point of the line
477 @param y0 The y-coordinate of the start point of the line
478 @param x1 The x-coordinate of the end point of the line
479 @param y1 The y-coordinate of the end point of the line
480 @param paint The paint used to draw the line
481 */
482 void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
483 const SkPaint& paint);
484
485 /** Draw the specified rectangle using the specified paint. The rectangle
486 will be filled or stroked based on the Style in the paint.
487 @param rect The rect to be drawn
488 @param paint The paint used to draw the rect
489 */
490 virtual void drawRect(const SkRect& rect, const SkPaint& paint);
491
492 /** Draw the specified rectangle using the specified paint. The rectangle
493 will be filled or framed based on the Style in the paint.
494 @param rect The rect to be drawn
495 @param paint The paint used to draw the rect
496 */
497 void drawIRect(const SkIRect& rect, const SkPaint& paint)
498 {
499 SkRect r;
500 r.set(rect); // promotes the ints to scalars
501 this->drawRect(r, paint);
502 }
reed@google.com4b226022011-01-11 18:32:13 +0000503
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 /** Draw the specified rectangle using the specified paint. The rectangle
505 will be filled or framed based on the Style in the paint.
506 @param left The left side of the rectangle to be drawn
507 @param top The top side of the rectangle to be drawn
508 @param right The right side of the rectangle to be drawn
509 @param bottom The bottom side of the rectangle to be drawn
510 @param paint The paint used to draw the rect
511 */
512 void drawRectCoords(SkScalar left, SkScalar top, SkScalar right,
513 SkScalar bottom, const SkPaint& paint);
514
515 /** Draw the specified oval using the specified paint. The oval will be
516 filled or framed based on the Style in the paint.
517 @param oval The rectangle bounds of the oval to be drawn
518 @param paint The paint used to draw the oval
519 */
520 void drawOval(const SkRect& oval, const SkPaint&);
521
522 /** Draw the specified circle using the specified paint. If radius is <= 0,
523 then nothing will be drawn. The circle will be filled
524 or framed based on the Style in the paint.
525 @param cx The x-coordinate of the center of the cirle to be drawn
526 @param cy The y-coordinate of the center of the cirle to be drawn
527 @param radius The radius of the cirle to be drawn
528 @param paint The paint used to draw the circle
529 */
530 void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
531 const SkPaint& paint);
532
533 /** Draw the specified arc, which will be scaled to fit inside the
534 specified oval. If the sweep angle is >= 360, then the oval is drawn
535 completely. Note that this differs slightly from SkPath::arcTo, which
536 treats the sweep angle mod 360.
537 @param oval The bounds of oval used to define the shape of the arc
538 @param startAngle Starting angle (in degrees) where the arc begins
539 @param sweepAngle Sweep angle (in degrees) measured clockwise
540 @param useCenter true means include the center of the oval. For filling
541 this will draw a wedge. False means just use the arc.
542 @param paint The paint used to draw the arc
543 */
544 void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
545 bool useCenter, const SkPaint& paint);
546
547 /** Draw the specified round-rect using the specified paint. The round-rect
548 will be filled or framed based on the Style in the paint.
549 @param rect The rectangular bounds of the roundRect to be drawn
550 @param rx The x-radius of the oval used to round the corners
551 @param ry The y-radius of the oval used to round the corners
552 @param paint The paint used to draw the roundRect
553 */
554 void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
555 const SkPaint& paint);
556
557 /** Draw the specified path using the specified paint. The path will be
558 filled or framed based on the Style in the paint.
559 @param path The path to be drawn
560 @param paint The paint used to draw the path
561 */
562 virtual void drawPath(const SkPath& path, const SkPaint& paint);
563
564 /** Draw the specified bitmap, with its top/left corner at (x,y), using the
565 specified paint, transformed by the current matrix. Note: if the paint
566 contains a maskfilter that generates a mask which extends beyond the
567 bitmap's original width/height, then the bitmap will be drawn as if it
568 were in a Shader with CLAMP mode. Thus the color outside of the original
569 width/height will be the edge color replicated.
570 @param bitmap The bitmap to be drawn
571 @param left The position of the left side of the bitmap being drawn
572 @param top The position of the top side of the bitmap being drawn
573 @param paint The paint used to draw the bitmap, or NULL
574 */
575 virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
576 const SkPaint* paint = NULL);
577
578 /** Draw the specified bitmap, with the specified matrix applied (before the
579 canvas' matrix is applied).
580 @param bitmap The bitmap to be drawn
581 @param src Optional: specify the subset of the bitmap to be drawn
582 @param dst The destination rectangle where the scaled/translated
583 image will be drawn
584 @param paint The paint used to draw the bitmap, or NULL
585 */
586 virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
587 const SkRect& dst, const SkPaint* paint = NULL);
588
589 virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
590 const SkPaint* paint = NULL);
reed@google.com4b226022011-01-11 18:32:13 +0000591
reed@google.comf0b5e112011-09-07 11:57:34 +0000592 /**
593 * Draw the bitmap stretched differentially to fit into dst.
594 * center is a rect within the bitmap, and logically divides the bitmap
595 * into 9 sections (3x3). For example, if the middle pixel of a [5x5]
596 * bitmap is the "center", then the center-rect should be [2, 2, 3, 3].
597 *
598 * If the dst is >= the bitmap size, then...
599 * - The 4 corners are not stretch at all.
600 * - The sides are stretch in only one axis.
601 * - The center is stretch in both axes.
602 * Else, for each axis where dst < bitmap,
603 * - The corners shrink proportionally
604 * - The sides (along the shrink axis) and center are not drawn
605 */
606 virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
607 const SkRect& dst, const SkPaint* paint = NULL);
608
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 /** Draw the specified bitmap, with its top/left corner at (x,y),
610 NOT transformed by the current matrix. Note: if the paint
611 contains a maskfilter that generates a mask which extends beyond the
612 bitmap's original width/height, then the bitmap will be drawn as if it
613 were in a Shader with CLAMP mode. Thus the color outside of the original
614 width/height will be the edge color replicated.
615 @param bitmap The bitmap to be drawn
616 @param left The position of the left side of the bitmap being drawn
617 @param top The position of the top side of the bitmap being drawn
618 @param paint The paint used to draw the bitmap, or NULL
619 */
620 virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
621 const SkPaint* paint = NULL);
622
623 /** Draw the text, with origin at (x,y), using the specified paint.
624 The origin is interpreted based on the Align setting in the paint.
625 @param text The text to be drawn
626 @param byteLength The number of bytes to read from the text parameter
627 @param x The x-coordinate of the origin of the text being drawn
628 @param y The y-coordinate of the origin of the text being drawn
629 @param paint The paint used for the text (e.g. color, size, style)
630 */
631 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
632 SkScalar y, const SkPaint& paint);
633
634 /** Draw the text, with each character/glyph origin specified by the pos[]
reed@google.com4b226022011-01-11 18:32:13 +0000635 array. The origin is interpreted by the Align setting in the paint.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636 @param text The text to be drawn
637 @param byteLength The number of bytes to read from the text parameter
638 @param pos Array of positions, used to position each character
639 @param paint The paint used for the text (e.g. color, size, style)
640 */
641 virtual void drawPosText(const void* text, size_t byteLength,
642 const SkPoint pos[], const SkPaint& paint);
reed@google.com4b226022011-01-11 18:32:13 +0000643
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644 /** Draw the text, with each character/glyph origin specified by the x
645 coordinate taken from the xpos[] array, and the y from the constY param.
reed@google.com4b226022011-01-11 18:32:13 +0000646 The origin is interpreted by the Align setting in the paint.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 @param text The text to be drawn
648 @param byteLength The number of bytes to read from the text parameter
649 @param xpos Array of x-positions, used to position each character
650 @param constY The shared Y coordinate for all of the positions
651 @param paint The paint used for the text (e.g. color, size, style)
652 */
653 virtual void drawPosTextH(const void* text, size_t byteLength,
654 const SkScalar xpos[], SkScalar constY,
655 const SkPaint& paint);
reed@google.com4b226022011-01-11 18:32:13 +0000656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657 /** Draw the text, with origin at (x,y), using the specified paint, along
658 the specified path. The paint's Align setting determins where along the
659 path to start the text.
660 @param text The text to be drawn
661 @param byteLength The number of bytes to read from the text parameter
662 @param path The path the text should follow for its baseline
663 @param hOffset The distance along the path to add to the text's
664 starting position
665 @param vOffset The distance above(-) or below(+) the path to
666 position the text
667 @param paint The paint used for the text
668 */
669 void drawTextOnPathHV(const void* text, size_t byteLength,
670 const SkPath& path, SkScalar hOffset,
671 SkScalar vOffset, const SkPaint& paint);
672
673 /** Draw the text, with origin at (x,y), using the specified paint, along
674 the specified path. The paint's Align setting determins where along the
675 path to start the text.
676 @param text The text to be drawn
677 @param byteLength The number of bytes to read from the text parameter
678 @param path The path the text should follow for its baseline
679 @param matrix (may be null) Applied to the text before it is
680 mapped onto the path
681 @param paint The paint used for the text
682 */
683 virtual void drawTextOnPath(const void* text, size_t byteLength,
684 const SkPath& path, const SkMatrix* matrix,
685 const SkPaint& paint);
686
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000687#ifdef ANDROID
688 /** Draw the text on path, with each character/glyph origin specified by the pos[]
689 array. The origin is interpreted by the Align setting in the paint.
690 @param text The text to be drawn
691 @param byteLength The number of bytes to read from the text parameter
692 @param pos Array of positions, used to position each character
693 @param paint The paint used for the text (e.g. color, size, style)
694 @param path The path to draw on
695 @param matrix The canvas matrix
696 */
697 void drawPosTextOnPath(const void* text, size_t byteLength,
698 const SkPoint pos[], const SkPaint& paint,
699 const SkPath& path, const SkMatrix* matrix);
700#endif
701
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 /** Draw the picture into this canvas. This method effective brackets the
703 playback of the picture's draw calls with save/restore, so the state
704 of this canvas will be unchanged after this call. This contrasts with
705 the more immediate method SkPicture::draw(), which does not bracket
706 the canvas with save/restore, thus the canvas may be left in a changed
707 state after the call.
708 @param picture The recorded drawing commands to playback into this
709 canvas.
710 */
711 virtual void drawPicture(SkPicture& picture);
reed@google.com4b226022011-01-11 18:32:13 +0000712
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 enum VertexMode {
714 kTriangles_VertexMode,
715 kTriangleStrip_VertexMode,
716 kTriangleFan_VertexMode
717 };
reed@google.com4b226022011-01-11 18:32:13 +0000718
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719 /** Draw the array of vertices, interpreted as triangles (based on mode).
720 @param vmode How to interpret the array of vertices
721 @param vertexCount The number of points in the vertices array (and
722 corresponding texs and colors arrays if non-null)
723 @param vertices Array of vertices for the mesh
724 @param texs May be null. If not null, specifies the coordinate
725 in texture space for each vertex.
726 @param colors May be null. If not null, specifies a color for each
727 vertex, to be interpolated across the triangle.
728 @param xmode Used if both texs and colors are present. In this
729 case the colors are combined with the texture using mode,
730 before being drawn using the paint. If mode is null, then
reed@android.com845fdac2009-06-23 03:01:32 +0000731 kMultiply_Mode is used.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 @param indices If not null, array of indices to reference into the
733 vertex (texs, colors) array.
734 @param indexCount number of entries in the indices array (if not null)
reed@google.com4b226022011-01-11 18:32:13 +0000735 @param paint Specifies the shader/texture if present.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 */
737 virtual void drawVertices(VertexMode vmode, int vertexCount,
738 const SkPoint vertices[], const SkPoint texs[],
739 const SkColor colors[], SkXfermode* xmode,
740 const uint16_t indices[], int indexCount,
741 const SkPaint& paint);
742
reed@android.comcb608442009-12-04 21:32:27 +0000743 /** Send a blob of data to the canvas.
744 For canvases that draw, this call is effectively a no-op, as the data
745 is not parsed, but just ignored. However, this call exists for
746 subclasses like SkPicture's recording canvas, that can store the data
747 and then play it back later (via another call to drawData).
748 */
749 virtual void drawData(const void* data, size_t length);
750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751 //////////////////////////////////////////////////////////////////////////
reed@google.com4b226022011-01-11 18:32:13 +0000752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 /** Get the current bounder object.
754 The bounder's reference count is unchaged.
755 @return the canva's bounder (or NULL).
756 */
757 SkBounder* getBounder() const { return fBounder; }
758
759 /** Set a new bounder (or NULL).
760 Pass NULL to clear any previous bounder.
761 As a convenience, the parameter passed is also returned.
762 If a previous bounder exists, its reference count is decremented.
763 If bounder is not NULL, its reference count is incremented.
764 @param bounder the new bounder (or NULL) to be installed in the canvas
765 @return the set bounder object
766 */
767 virtual SkBounder* setBounder(SkBounder* bounder);
reed@google.com4b226022011-01-11 18:32:13 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 /** Get the current filter object. The filter's reference count is not
reed@android.comdc3381f2010-02-11 16:05:15 +0000770 affected. The filter is saved/restored, just like the matrix and clip.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 @return the canvas' filter (or NULL).
772 */
773 SkDrawFilter* getDrawFilter() const;
reed@google.com4b226022011-01-11 18:32:13 +0000774
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775 /** Set the new filter (or NULL). Pass NULL to clear any existing filter.
776 As a convenience, the parameter is returned. If an existing filter
777 exists, its refcnt is decrement. If the new filter is not null, its
reed@android.comdc3381f2010-02-11 16:05:15 +0000778 refcnt is incremented. The filter is saved/restored, just like the
779 matrix and clip.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780 @param filter the new filter (or NULL)
781 @return the new filter
782 */
783 virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter);
784
785 //////////////////////////////////////////////////////////////////////////
786
787 /** Return the current matrix on the canvas.
788 This does not account for the translate in any of the devices.
789 @return The current matrix on the canvas.
790 */
791 const SkMatrix& getTotalMatrix() const;
792
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000793 enum ClipType {
794 kEmpty_ClipType = 0,
795 kRect_ClipType,
796 kComplex_ClipType
797 };
798
799 /** Returns a description of the total clip; may be cheaper than
800 getting the clip and querying it directly.
801 */
802 ClipType getClipType() const;
803
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 /** Return the current device clip (concatenation of all clip calls).
805 This does not account for the translate in any of the devices.
806 @return the current device clip (concatenation of all clip calls).
807 */
808 const SkRegion& getTotalClip() const;
809
reed@google.com7d7ca792011-02-23 22:39:18 +0000810 /**
reed@google.com5e2457e2011-10-10 21:24:37 +0000811 * Return true if the current clip is non-empty.
812 *
813 * If bounds is not NULL, set it to the bounds of the current clip
814 * in global coordinates.
815 */
816 bool getTotalClipBounds(SkIRect* bounds) const;
817
818 /**
reed@google.com7d7ca792011-02-23 22:39:18 +0000819 * Return the current clipstack. This mirrors the result in getTotalClip()
820 * but is represented as a stack of geometric clips + region-ops.
821 */
822 const SkClipStack& getTotalClipStack() const;
823
reed@android.comf2b98d62010-12-20 18:26:13 +0000824 void setExternalMatrix(const SkMatrix* = NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825
826 ///////////////////////////////////////////////////////////////////////////
827
828 /** After calling saveLayer(), there can be any number of devices that make
829 up the top-most drawing area. LayerIter can be used to iterate through
830 those devices. Note that the iterator is only valid until the next API
831 call made on the canvas. Ownership of all pointers in the iterator stays
832 with the canvas, so none of them should be modified or deleted.
833 */
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +0000834 class SK_API LayerIter /*: SkNoncopyable*/ {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835 public:
836 /** Initialize iterator with canvas, and set values for 1st device */
837 LayerIter(SkCanvas*, bool skipEmptyClips);
838 ~LayerIter();
reed@google.com4b226022011-01-11 18:32:13 +0000839
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 /** Return true if the iterator is done */
841 bool done() const { return fDone; }
842 /** Cycle to the next device */
843 void next();
reed@google.com4b226022011-01-11 18:32:13 +0000844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 // These reflect the current device in the iterator
846
847 SkDevice* device() const;
848 const SkMatrix& matrix() const;
849 const SkRegion& clip() const;
850 const SkPaint& paint() const;
851 int x() const;
852 int y() const;
reed@google.com4b226022011-01-11 18:32:13 +0000853
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854 private:
855 // used to embed the SkDrawIter object directly in our instance, w/o
856 // having to expose that class def to the public. There is an assert
857 // in our constructor to ensure that fStorage is large enough
858 // (though needs to be a compile-time-assert!). We use intptr_t to work
859 // safely with 32 and 64 bit machines (to ensure the storage is enough)
reed@android.comf2b98d62010-12-20 18:26:13 +0000860 intptr_t fStorage[32];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 class SkDrawIter* fImpl; // this points at fStorage
862 SkPaint fDefaultPaint;
863 bool fDone;
864 };
865
866protected:
867 // all of the drawBitmap variants call this guy
reed@android.comf2b98d62010-12-20 18:26:13 +0000868 virtual void commonDrawBitmap(const SkBitmap&, const SkIRect*,
869 const SkMatrix&, const SkPaint& paint);
reed@google.com4b226022011-01-11 18:32:13 +0000870
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871private:
872 class MCRec;
873
reed@google.com5c3d1472011-02-22 19:12:23 +0000874 SkClipStack fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 SkDeque fMCStack;
876 // points to top of stack
877 MCRec* fMCRec;
878 // the first N recs that can fit here mean we won't call malloc
879 uint32_t fMCRecStorage[32];
880
881 SkBounder* fBounder;
reed@android.com199f1082009-06-10 02:12:47 +0000882 SkDevice* fLastDeviceToGainFocus;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883
bsalomon@google.comd302f142011-03-03 13:54:13 +0000884 void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&,
885 const SkClipStack& clipStack);
reed@google.com4b226022011-01-11 18:32:13 +0000886
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887 bool fDeviceCMDirty; // cleared by updateDeviceCMCache()
888 void updateDeviceCMCache();
889
890 friend class SkDrawIter; // needs setupDrawForLayerDevice()
891
bsalomon@google.come97f0852011-06-17 13:10:25 +0000892 SkDevice* createLayerDevice(SkBitmap::Config, int width, int height,
893 bool isOpaque);
894
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 SkDevice* init(SkDevice*);
reed@google.comf0b5e112011-09-07 11:57:34 +0000896
897 // internal methods are not virtual, so they can safely be called by other
898 // canvas apis, without confusing subclasses (like SkPictureRecording)
reed@android.comf2b98d62010-12-20 18:26:13 +0000899 void internalDrawBitmap(const SkBitmap&, const SkIRect*, const SkMatrix& m,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900 const SkPaint* paint);
reed@google.comf0b5e112011-09-07 11:57:34 +0000901 void internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
902 const SkRect& dst, const SkPaint* paint);
903 void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
904 const SkRect& dst, const SkPaint* paint);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +0000905 void internalDrawPaint(const SkPaint& paint);
906
reed@google.comf0b5e112011-09-07 11:57:34 +0000907
reed@android.com8a1c16f2008-12-17 15:59:43 +0000908 void drawDevice(SkDevice*, int x, int y, const SkPaint*);
909 // shared by save() and saveLayer()
910 int internalSave(SaveFlags flags);
911 void internalRestore();
bungeman@google.com52c748b2011-08-22 21:30:43 +0000912 static void DrawRect(const SkDraw& draw, const SkPaint& paint,
913 const SkRect& r, SkScalar textSize);
914 static void DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
915 const char text[], size_t byteLength,
916 SkScalar x, SkScalar y);
reed@google.com4b226022011-01-11 18:32:13 +0000917
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918 /* These maintain a cache of the clip bounds in local coordinates,
919 (converted to 2s-compliment if floats are slow).
920 */
921 mutable SkRectCompareType fLocalBoundsCompareType;
922 mutable bool fLocalBoundsCompareTypeDirty;
923
reed@android.comba09de42010-02-05 20:46:05 +0000924 mutable SkRectCompareType fLocalBoundsCompareTypeBW;
925 mutable bool fLocalBoundsCompareTypeDirtyBW;
926
927 /* Get the local clip bounds with an anti-aliased edge.
928 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929 const SkRectCompareType& getLocalClipBoundsCompareType() const {
reed@android.comba09de42010-02-05 20:46:05 +0000930 return getLocalClipBoundsCompareType(kAA_EdgeType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931 }
reed@android.comba09de42010-02-05 20:46:05 +0000932
933 const SkRectCompareType& getLocalClipBoundsCompareType(EdgeType et) const {
934 if (et == kAA_EdgeType) {
935 if (fLocalBoundsCompareTypeDirty) {
936 this->computeLocalClipBoundsCompareType(et);
937 fLocalBoundsCompareTypeDirty = false;
938 }
939 return fLocalBoundsCompareType;
940 } else {
941 if (fLocalBoundsCompareTypeDirtyBW) {
942 this->computeLocalClipBoundsCompareType(et);
943 fLocalBoundsCompareTypeDirtyBW = false;
944 }
945 return fLocalBoundsCompareTypeBW;
946 }
947 }
948 void computeLocalClipBoundsCompareType(EdgeType et) const;
reed@android.comf2b98d62010-12-20 18:26:13 +0000949
950 SkMatrix fExternalMatrix, fExternalInverse;
951 bool fUseExternalMatrix;
reed@google.com5c3d1472011-02-22 19:12:23 +0000952
953 class AutoValidateClip : ::SkNoncopyable {
954 public:
955 explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) {
956 fCanvas->validateClip();
957 }
958 ~AutoValidateClip() { fCanvas->validateClip(); }
959
960 private:
961 const SkCanvas* fCanvas;
962 };
963
964#ifdef SK_DEBUG
965 void validateClip() const;
966#else
967 void validateClip() const {}
968#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969};
970
971/** Stack helper class to automatically call restoreToCount() on the canvas
972 when this object goes out of scope. Use this to guarantee that the canvas
973 is restored to a known state.
974*/
975class SkAutoCanvasRestore : SkNoncopyable {
976public:
977 SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas) {
978 SkASSERT(canvas);
979 fSaveCount = canvas->getSaveCount();
980 if (doSave) {
981 canvas->save();
982 }
983 }
984 ~SkAutoCanvasRestore() {
985 fCanvas->restoreToCount(fSaveCount);
986 }
987
988private:
989 SkCanvas* fCanvas;
990 int fSaveCount;
991};
992
993#endif