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