1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef UI_GFX_CANVAS_H_
6#define UI_GFX_CANVAS_H_
7
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/strings/string16.h"
13#include "skia/ext/platform_canvas.h"
14#include "skia/ext/refptr.h"
15#include "ui/gfx/image/image_skia.h"
16#include "ui/gfx/native_widget_types.h"
17#include "ui/gfx/shadow_value.h"
18#include "ui/gfx/text_constants.h"
19
20namespace gfx {
21
22class Rect;
23class FontList;
24class Point;
25class Size;
26class Transform;
27
28// Canvas is a SkCanvas wrapper that provides a number of methods for
29// common operations used throughout an application built using ui/gfx.
30//
31// All methods that take integer arguments (as is used throughout views)
32// end with Int. If you need to use methods provided by SkCanvas, you'll
33// need to do a conversion. In particular you'll need to use |SkIntToScalar()|,
34// or if converting from a scalar to an integer |SkScalarRound()|.
35//
36// A handful of methods in this class are overloaded providing an additional
37// argument of type SkXfermode::Mode. SkXfermode::Mode specifies how the
38// source and destination colors are combined. Unless otherwise specified,
39// the variant that does not take a SkXfermode::Mode uses a transfer mode
40// of kSrcOver_Mode.
41class GFX_EXPORT Canvas {
42 public:
43  // Specifies the alignment for text rendered with the DrawStringRect method.
44  enum {
45    TEXT_ALIGN_LEFT = 1 << 0,
46    TEXT_ALIGN_CENTER = 1 << 1,
47    TEXT_ALIGN_RIGHT = 1 << 2,
48
49    // Specifies the text consists of multiple lines.
50    MULTI_LINE = 1 << 3,
51
52    // By default DrawStringRect does not process the prefix ('&') character
53    // specially. That is, the string "&foo" is rendered as "&foo". When
54    // rendering text from a resource that uses the prefix character for
55    // mnemonics, the prefix should be processed and can be rendered as an
56    // underline (SHOW_PREFIX), or not rendered at all (HIDE_PREFIX).
57    SHOW_PREFIX = 1 << 4,
58    HIDE_PREFIX = 1 << 5,
59
60    // Prevent ellipsizing
61    NO_ELLIPSIS = 1 << 6,
62
63    // Specifies if words can be split by new lines.
64    // This only works with MULTI_LINE.
65    CHARACTER_BREAK = 1 << 7,
66
67    // Instructs DrawStringRect() to render the text using RTL directionality.
68    // In most cases, passing this flag is not necessary because information
69    // about the text directionality is going to be embedded within the string
70    // in the form of special Unicode characters. However, we don't insert
71    // directionality characters into strings if the locale is LTR because some
72    // platforms (for example, an English Windows XP with no RTL fonts
73    // installed) don't support these characters. Thus, this flag should be
74    // used to render text using RTL directionality when the locale is LTR.
75    FORCE_RTL_DIRECTIONALITY = 1 << 8,
76
77    // Similar to FORCE_RTL_DIRECTIONALITY, but left-to-right.
78    // See FORCE_RTL_DIRECTIONALITY for details.
79    FORCE_LTR_DIRECTIONALITY = 1 << 9,
80
81    // Instructs DrawStringRect() to not use subpixel rendering.  This is useful
82    // when rendering text onto a fully- or partially-transparent background
83    // that will later be blended with another image.
84    NO_SUBPIXEL_RENDERING = 1 << 10,
85  };
86
87  // Creates an empty canvas with image_scale of 1x.
88  Canvas();
89
90  // Creates canvas with provided DIP |size| and |image_scale|.
91  // If this canvas is not opaque, it's explicitly cleared to transparent before
92  // being returned.
93  Canvas(const Size& size, float image_scale, bool is_opaque);
94
95  // Constructs a canvas with the size and the image_scale of the provided
96  // |image_rep|, and draws the |image_rep| into it.
97  Canvas(const ImageSkiaRep& image_rep, bool is_opaque);
98
99  virtual ~Canvas();
100
101  // Creates a Canvas backed by an |sk_canvas| with |image_scale_|.
102  // |sk_canvas| is assumed to be already scaled based on |image_scale|
103  // so no additional scaling is applied.
104  static Canvas* CreateCanvasWithoutScaling(SkCanvas* sk_canvas,
105                                            float image_scale);
106
107  // Recreates the backing platform canvas with DIP |size| and |image_scale_|.
108  // If the canvas is not opaque, it is explicitly cleared.
109  // This method is public so that canvas_skia_paint can recreate the platform
110  // canvas after having initialized the canvas.
111  // TODO(pkotwicz): Push the image_scale into skia::PlatformCanvas such that
112  // this method can be private.
113  void RecreateBackingCanvas(const Size& size,
114                             float image_scale,
115                             bool is_opaque);
116
117  // Compute the size required to draw some text with the provided fonts.
118  // Attempts to fit the text with the provided width and height. Increases
119  // height and then width as needed to make the text fit. This method
120  // supports multiple lines. On Skia only a line_height can be specified and
121  // specifying a 0 value for it will cause the default height to be used.
122  static void SizeStringInt(const base::string16& text,
123                            const FontList& font_list,
124                            int* width,
125                            int* height,
126                            int line_height,
127                            int flags);
128
129  // This is same as SizeStringInt except that fractional size is returned.
130  // See comment in GetStringWidthF for its usage.
131  static void SizeStringFloat(const base::string16& text,
132                              const FontList& font_list,
133                              float* width,
134                              float* height,
135                              int line_height,
136                              int flags);
137
138  // Returns the number of horizontal pixels needed to display the specified
139  // |text| with |font_list|.
140  static int GetStringWidth(const base::string16& text,
141                            const FontList& font_list);
142
143  // This is same as GetStringWidth except that fractional width is returned.
144  // Use this method for the scenario that multiple string widths need to be
145  // summed up. This is because GetStringWidth returns the ceiled width and
146  // adding multiple ceiled widths could cause more precision loss for certain
147  // platform like Mac where the fractioal width is used.
148  static float GetStringWidthF(const base::string16& text,
149                               const FontList& font_list);
150
151  // Returns the default text alignment to be used when drawing text on a
152  // Canvas based on the directionality of the system locale language.
153  // This function is used by Canvas::DrawStringRect when the text alignment
154  // is not specified.
155  //
156  // This function returns either Canvas::TEXT_ALIGN_LEFT or
157  // Canvas::TEXT_ALIGN_RIGHT.
158  static int DefaultCanvasTextAlignment();
159
160  // Draws text with a 1-pixel halo around it of the given color.
161  // On Windows, it allows ClearType to be drawn to an otherwise transparent
162  //   bitmap for drag images. Drag images have only 1-bit of transparency, so
163  //   we don't do any fancy blurring.
164  // On Linux, text with halo is created by stroking it with 2px |halo_color|
165  //   then filling it with |text_color|.
166  // On Mac, NOTIMPLEMENTED.
167  //   TODO(dhollowa): Skia-native implementation is underway.  Cut over to
168  //   that when ready.  http::/crbug.com/109946
169  void DrawStringRectWithHalo(const base::string16& text,
170                              const FontList& font_list,
171                              SkColor text_color,
172                              SkColor halo_color,
173                              const Rect& display_rect,
174                              int flags);
175
176  // Extracts an ImageSkiaRep from the contents of this canvas.
177  ImageSkiaRep ExtractImageRep() const;
178
179  // Draws a dashed rectangle of the specified color.
180  void DrawDashedRect(const Rect& rect, SkColor color);
181
182  // Saves a copy of the drawing state onto a stack, operating on this copy
183  // until a balanced call to Restore() is made.
184  void Save();
185
186  // As with Save(), except draws to a layer that is blended with the canvas
187  // at the specified alpha once Restore() is called.
188  // |layer_bounds| are the bounds of the layer relative to the current
189  // transform.
190  void SaveLayerAlpha(uint8 alpha);
191  void SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds);
192
193  // Restores the drawing state after a call to Save*(). It is an error to
194  // call Restore() more times than Save*().
195  void Restore();
196
197  // Adds |rect| to the current clip.
198  void ClipRect(const Rect& rect);
199
200  // Adds |path| to the current clip. |do_anti_alias| is true if the clip
201  // should be antialiased.
202  void ClipPath(const SkPath& path, bool do_anti_alias);
203
204  // Returns true if the current clip is empty.
205  bool IsClipEmpty() const;
206
207  // Returns the bounds of the current clip (in local coordinates) in the
208  // |bounds| parameter, and returns true if it is non empty.
209  bool GetClipBounds(Rect* bounds);
210
211  void Translate(const Vector2d& offset);
212
213  void Scale(int x_scale, int y_scale);
214
215  // Fills the entire canvas' bitmap (restricted to current clip) with
216  // specified |color| using a transfer mode of SkXfermode::kSrcOver_Mode.
217  void DrawColor(SkColor color);
218
219  // Fills the entire canvas' bitmap (restricted to current clip) with
220  // specified |color| and |mode|.
221  void DrawColor(SkColor color, SkXfermode::Mode mode);
222
223  // Fills |rect| with |color| using a transfer mode of
224  // SkXfermode::kSrcOver_Mode.
225  void FillRect(const Rect& rect, SkColor color);
226
227  // Fills |rect| with the specified |color| and |mode|.
228  void FillRect(const Rect& rect, SkColor color, SkXfermode::Mode mode);
229
230  // Draws a single pixel rect in the specified region with the specified
231  // color, using a transfer mode of SkXfermode::kSrcOver_Mode.
232  //
233  // NOTE: if you need a single pixel line, use DrawLine.
234  void DrawRect(const Rect& rect, SkColor color);
235
236  // Draws a single pixel rect in the specified region with the specified
237  // color and transfer mode.
238  //
239  // NOTE: if you need a single pixel line, use DrawLine.
240  void DrawRect(const Rect& rect, SkColor color, SkXfermode::Mode mode);
241
242  // Draws the given rectangle with the given |paint| parameters.
243  void DrawRect(const Rect& rect, const SkPaint& paint);
244
245  // Draw the given point with the given |paint| parameters.
246  void DrawPoint(const Point& p, const SkPaint& paint);
247
248  // Draws a single pixel line with the specified color.
249  void DrawLine(const Point& p1, const Point& p2, SkColor color);
250
251  // Draws a line with the given |paint| parameters.
252  void DrawLine(const Point& p1, const Point& p2, const SkPaint& paint);
253
254  // Draws a circle with the given |paint| parameters.
255  void DrawCircle(const Point& center_point,
256                  int radius,
257                  const SkPaint& paint);
258
259  // Draws the given rectangle with rounded corners of |radius| using the
260  // given |paint| parameters.
261  void DrawRoundRect(const Rect& rect, int radius, const SkPaint& paint);
262
263  // Draws the given path using the given |paint| parameters.
264  void DrawPath(const SkPath& path, const SkPaint& paint);
265
266  // Draws an image with the origin at the specified location. The upper left
267  // corner of the bitmap is rendered at the specified location.
268  // Parameters are specified relative to current canvas scale not in pixels.
269  // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1.
270  void DrawImageInt(const ImageSkia&, int x, int y);
271
272  // Helper for DrawImageInt(..., paint) that constructs a temporary paint and
273  // calls paint.setAlpha(alpha).
274  void DrawImageInt(const ImageSkia&, int x, int y, uint8 alpha);
275
276  // Draws an image with the origin at the specified location, using the
277  // specified paint. The upper left corner of the bitmap is rendered at the
278  // specified location.
279  // Parameters are specified relative to current canvas scale not in pixels.
280  // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
281  void DrawImageInt(const ImageSkia& image,
282                    int x,
283                    int y,
284                    const SkPaint& paint);
285
286  // Draws a portion of an image in the specified location. The src parameters
287  // correspond to the region of the bitmap to draw in the region defined
288  // by the dest coordinates.
289  //
290  // If the width or height of the source differs from that of the destination,
291  // the image will be scaled. When scaling down, a mipmap will be generated.
292  // Set |filter| to use filtering for images, otherwise the nearest-neighbor
293  // algorithm is used for resampling.
294  //
295  // An optional custom SkPaint can be provided.
296  // Parameters are specified relative to current canvas scale not in pixels.
297  // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
298  void DrawImageInt(const ImageSkia& image,
299                    int src_x,
300                    int src_y,
301                    int src_w,
302                    int src_h,
303                    int dest_x,
304                    int dest_y,
305                    int dest_w,
306                    int dest_h,
307                    bool filter);
308  void DrawImageInt(const ImageSkia& image,
309                    int src_x,
310                    int src_y,
311                    int src_w,
312                    int src_h,
313                    int dest_x,
314                    int dest_y,
315                    int dest_w,
316                    int dest_h,
317                    bool filter,
318                    const SkPaint& paint);
319
320  // Same as the DrawImageInt functions above. Difference being this does not
321  // do any scaling, i.e. it assumes that the source/destination/image, etc are
322  // in pixels. It does translate the destination rectangle to ensure that the
323  // image is displayed at the correct pixel coordinates.
324  void DrawImageIntInPixel(const ImageSkia& image,
325                           int src_x,
326                           int src_y,
327                           int src_w,
328                           int src_h,
329                           int dest_x,
330                           int dest_y,
331                           int dest_w,
332                           int dest_h,
333                           bool filter,
334                           const SkPaint& paint);
335
336  // Draws an |image| with the top left corner at |x| and |y|, clipped to
337  // |path|.
338  // Parameters are specified relative to current canvas scale not in pixels.
339  // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1.
340  void DrawImageInPath(const ImageSkia& image,
341                       int x,
342                       int y,
343                       const SkPath& path,
344                       const SkPaint& paint);
345
346  // Draws text with the specified color, fonts and location. The text is
347  // aligned to the left, vertically centered, clipped to the region. If the
348  // text is too big, it is truncated and '...' is added to the end.
349  void DrawStringRect(const base::string16& text,
350                      const FontList& font_list,
351                      SkColor color,
352                      const Rect& display_rect);
353
354  // Draws text with the specified color, fonts and location. The last argument
355  // specifies flags for how the text should be rendered. It can be one of
356  // TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT or TEXT_ALIGN_LEFT.
357  void DrawStringRectWithFlags(const base::string16& text,
358                               const FontList& font_list,
359                               SkColor color,
360                               const Rect& display_rect,
361                               int flags);
362
363  // Similar to above DrawStringRect method but with text shadows support.
364  // Currently it's only implemented for canvas skia. Specifying a 0 line_height
365  // will cause the default height to be used.
366  void DrawStringRectWithShadows(const base::string16& text,
367                                 const FontList& font_list,
368                                 SkColor color,
369                                 const Rect& text_bounds,
370                                 int line_height,
371                                 int flags,
372                                 const ShadowValues& shadows);
373
374  // Draws a dotted gray rectangle used for focus purposes.
375  void DrawFocusRect(const Rect& rect);
376
377  // Draws a |rect| in the specified region with the specified |color| with a
378  // with of one logical pixel which might be more device pixels.
379  void DrawSolidFocusRect(const Rect& rect, SkColor color);
380
381  // Tiles the image in the specified region.
382  // Parameters are specified relative to current canvas scale not in pixels.
383  // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
384  void TileImageInt(const ImageSkia& image,
385                    int x,
386                    int y,
387                    int w,
388                    int h);
389  void TileImageInt(const ImageSkia& image,
390                    int src_x,
391                    int src_y,
392                    int dest_x,
393                    int dest_y,
394                    int w,
395                    int h);
396  void TileImageInt(const ImageSkia& image,
397                    int src_x,
398                    int src_y,
399                    float tile_scale_x,
400                    float tile_scale_y,
401                    int dest_x,
402                    int dest_y,
403                    int w,
404                    int h);
405
406  // Returns a native drawing context for platform specific drawing routines to
407  // use. Must be balanced by a call to EndPlatformPaint().
408  NativeDrawingContext BeginPlatformPaint();
409
410  // Signifies the end of platform drawing using the native drawing context
411  // returned by BeginPlatformPaint().
412  void EndPlatformPaint();
413
414  // Apply transformation on the canvas.
415  void Transform(const Transform& transform);
416
417  // Draws the given string with a fade gradient at the end.
418  void DrawFadedString(const base::string16& text,
419                       const FontList& font_list,
420                       SkColor color,
421                       const Rect& display_rect,
422                       int flags);
423
424  skia::PlatformCanvas* platform_canvas() { return owned_canvas_.get(); }
425  SkCanvas* sk_canvas() { return canvas_; }
426  float image_scale() const { return image_scale_; }
427
428 private:
429  Canvas(SkCanvas* canvas, float image_scale);
430
431  // Test whether the provided rectangle intersects the current clip rect.
432  bool IntersectsClipRectInt(int x, int y, int w, int h);
433  bool IntersectsClipRect(const Rect& rect);
434
435  // Helper for the DrawImageInt functions declared above. The |pixel|
436  // parameter if true indicates that the bounds and the image are to
437  // be assumed to be in pixels, i.e. no scaling needs to be performed.
438  void DrawImageIntHelper(const ImageSkia& image,
439                          int src_x,
440                          int src_y,
441                          int src_w,
442                          int src_h,
443                          int dest_x,
444                          int dest_y,
445                          int dest_w,
446                          int dest_h,
447                          bool filter,
448                          const SkPaint& paint,
449                          float image_scale,
450                          bool pixel);
451
452  // The device scale factor at which drawing on this canvas occurs.
453  // An additional scale can be applied via Canvas::Scale(). However,
454  // Canvas::Scale() does not affect |image_scale_|.
455  float image_scale_;
456
457  skia::RefPtr<skia::PlatformCanvas> owned_canvas_;
458  SkCanvas* canvas_;
459
460  DISALLOW_COPY_AND_ASSIGN(Canvas);
461};
462
463}  // namespace gfx
464
465#endif  // UI_GFX_CANVAS_H_
466