|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef UI_GFX_CANVAS_H_ | 
|  | #define UI_GFX_CANVAS_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <compare> | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <string_view> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/component_export.h" | 
|  | #include "base/containers/lru_cache.h" | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "cc/paint/paint_canvas.h" | 
|  | #include "cc/paint/paint_flags.h" | 
|  | #include "cc/paint/skia_paint_canvas.h" | 
|  | #include "cc/paint/skottie_color_map.h" | 
|  | #include "cc/paint/skottie_frame_data.h" | 
|  | #include "cc/paint/skottie_text_property_value.h" | 
|  | #include "ui/gfx/native_ui_types.h" | 
|  | #include "ui/gfx/platform_font.h" | 
|  | #include "ui/gfx/text_constants.h" | 
|  |  | 
|  | namespace cc { | 
|  | class SkottieWrapper; | 
|  | }  // namespace cc | 
|  |  | 
|  | namespace gfx { | 
|  |  | 
|  | class Rect; | 
|  | class RectF; | 
|  | class FontList; | 
|  | class ImageSkia; | 
|  | class ImageSkiaRep; | 
|  | class Point; | 
|  | class PointF; | 
|  | class Size; | 
|  | class Transform; | 
|  | class Vector2d; | 
|  |  | 
|  | // Canvas is a PaintCanvas wrapper that provides a number of methods for | 
|  | // common operations used throughout an application built using ui/gfx. | 
|  | // | 
|  | // All methods that take integer arguments (as is used throughout views) | 
|  | // end with Int. If you need to use methods provided by PaintCanvas, you'll | 
|  | // need to do a conversion. In particular you'll need to use |SkIntToScalar()|, | 
|  | // or if converting from a scalar to an integer |SkScalarRound()|. | 
|  | // | 
|  | // A handful of methods in this class are overloaded providing an additional | 
|  | // argument of type SkBlendMode. SkBlendMode specifies how the | 
|  | // source and destination colors are combined. Unless otherwise specified, | 
|  | // the variant that does not take a SkBlendMode uses a transfer mode | 
|  | // of kSrcOver_Mode. | 
|  | class COMPONENT_EXPORT(GFX) Canvas { | 
|  | public: | 
|  | enum { | 
|  | // Specifies the alignment for text rendered with the DrawStringRect method. | 
|  | TEXT_ALIGN_LEFT = 1 << 0, | 
|  | TEXT_ALIGN_CENTER = 1 << 1, | 
|  | TEXT_ALIGN_RIGHT = 1 << 2, | 
|  | TEXT_ALIGN_TO_HEAD = 1 << 3, | 
|  |  | 
|  | // Specifies the text consists of multiple lines. | 
|  | MULTI_LINE = 1 << 4, | 
|  |  | 
|  | // By default DrawStringRect does not process the prefix ('&') character | 
|  | // specially. That is, the string "&foo" is rendered as "&foo". When | 
|  | // rendering text from a resource that uses the prefix character for | 
|  | // mnemonics, the prefix should be processed and can be rendered as an | 
|  | // underline (SHOW_PREFIX), or not rendered at all (HIDE_PREFIX). | 
|  | SHOW_PREFIX = 1 << 5, | 
|  | HIDE_PREFIX = 1 << 6, | 
|  |  | 
|  | // Prevent ellipsizing | 
|  | NO_ELLIPSIS = 1 << 7, | 
|  |  | 
|  | // Specifies if words can be split by new lines. | 
|  | // This only works with MULTI_LINE. | 
|  | CHARACTER_BREAKABLE = 1 << 8, | 
|  |  | 
|  | // Instructs DrawStringRect() to not use subpixel rendering.  This is useful | 
|  | // when rendering text onto a fully- or partially-transparent background | 
|  | // that will later be blended with another image. | 
|  | NO_SUBPIXEL_RENDERING = 1 << 9, | 
|  | }; | 
|  |  | 
|  | // Creates an empty canvas with image_scale of 1x. | 
|  | Canvas(); | 
|  |  | 
|  | // Creates canvas with provided DIP |size| and |image_scale|. | 
|  | // If this canvas is not opaque, it's explicitly cleared to transparent before | 
|  | // being returned. | 
|  | Canvas(const Size& size, float image_scale, bool is_opaque); | 
|  |  | 
|  | // Creates a Canvas backed by an |sk_canvas| with |image_scale_|. | 
|  | // |sk_canvas| is assumed to be already scaled based on |image_scale| | 
|  | // so no additional scaling is applied. | 
|  | // Note: the caller must ensure that sk_canvas outlives this object, or until | 
|  | // RecreateBackingCanvas is called. | 
|  | Canvas(cc::PaintCanvas* sk_canvas, float image_scale); | 
|  |  | 
|  | Canvas(const Canvas&) = delete; | 
|  | Canvas& operator=(const Canvas&) = delete; | 
|  |  | 
|  | virtual ~Canvas(); | 
|  |  | 
|  | // Recreates the backing platform canvas with DIP |size| and |image_scale_|. | 
|  | // If the canvas is not opaque, it is explicitly cleared. | 
|  | // TODO(pkotwicz): Push the image_scale into skia::PlatformCanvas such that | 
|  | // this method can be private. | 
|  | void RecreateBackingCanvas(const Size& size, | 
|  | float image_scale, | 
|  | bool is_opaque); | 
|  |  | 
|  | // Compute the size required to draw some text with the provided fonts. | 
|  | // Attempts to fit the text with the provided width and height. Increases | 
|  | // height and then width as needed to make the text fit. This method | 
|  | // supports multiple lines. On Skia only a line_height can be specified and | 
|  | // specifying a 0 value for it will cause the default height to be used. | 
|  | static void SizeStringInt(std::u16string_view text, | 
|  | const FontList& font_list, | 
|  | int* width, | 
|  | int* height, | 
|  | int line_height, | 
|  | int flags); | 
|  |  | 
|  | // This is same as SizeStringInt except that fractional size is returned. | 
|  | // See comment in GetStringWidthF for its usage. | 
|  | static void SizeStringFloat(std::u16string_view text, | 
|  | const FontList& font_list, | 
|  | float* width, | 
|  | float* height, | 
|  | int line_height, | 
|  | int flags); | 
|  |  | 
|  | // Returns the number of horizontal pixels needed to display the specified | 
|  | // |text| with |font_list|. | 
|  | static int GetStringWidth(std::u16string_view text, | 
|  | const FontList& font_list); | 
|  |  | 
|  | // This is same as GetStringWidth except that fractional width is returned. | 
|  | // Use this method for the scenario that multiple string widths need to be | 
|  | // summed up. This is because GetStringWidth returns the ceiled width and | 
|  | // adding multiple ceiled widths could cause more precision loss for certain | 
|  | // platform like Mac where the fractional width is used. | 
|  | static float GetStringWidthF(std::u16string_view text, | 
|  | const FontList& font_list); | 
|  |  | 
|  | // Returns the default text alignment to be used when drawing text on a | 
|  | // Canvas based on the directionality of the system locale language. | 
|  | // This function is used by Canvas::DrawStringRect when the text alignment | 
|  | // is not specified. | 
|  | // | 
|  | // This function returns either Canvas::TEXT_ALIGN_LEFT or | 
|  | // Canvas::TEXT_ALIGN_RIGHT. | 
|  | static int DefaultCanvasTextAlignment(); | 
|  |  | 
|  | // Key for the string width cache. | 
|  | using StringWidthCacheKey = | 
|  | std::pair<std::u16string, scoped_refptr<const gfx::PlatformFont>>; | 
|  |  | 
|  | struct StringWidthCacheKeyCompare { | 
|  | bool operator()(const StringWidthCacheKey& lhs, | 
|  | const StringWidthCacheKey& rhs) const { | 
|  | if (lhs.first != rhs.first) { | 
|  | return lhs.first < rhs.first; | 
|  | } | 
|  | if (!lhs.second || !rhs.second) { | 
|  | return lhs.second < rhs.second; | 
|  | } | 
|  | return *lhs.second < *rhs.second; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Cache for string widths. | 
|  | using StringWidthCache = | 
|  | base::LRUCache<StringWidthCacheKey, float, StringWidthCacheKeyCompare>; | 
|  |  | 
|  | static StringWidthCache& GetStringWidthCacheForTesting(); | 
|  |  | 
|  | // Unscales by the image scale factor (aka device scale factor), and returns | 
|  | // that factor.  This is useful when callers want to draw directly in the | 
|  | // native scale. | 
|  | float UndoDeviceScaleFactor(); | 
|  |  | 
|  | // Saves a copy of the drawing state onto a stack, operating on this copy | 
|  | // until a balanced call to Restore() is made. | 
|  | void Save(); | 
|  |  | 
|  | // As with Save(), except draws to a layer that is blended with the canvas | 
|  | // at the specified alpha once Restore() is called. | 
|  | // |layer_bounds| are the bounds of the layer relative to the current | 
|  | // transform. | 
|  | void SaveLayerAlpha(uint8_t alpha); | 
|  | void SaveLayerAlpha(uint8_t alpha, const Rect& layer_bounds); | 
|  |  | 
|  | // Like SaveLayerAlpha but draws the layer with an arbitrary set of | 
|  | // PaintFlags once Restore() is called. | 
|  | void SaveLayerWithFlags(const cc::PaintFlags& flags); | 
|  |  | 
|  | // Restores the drawing state after a call to Save*(). It is an error to | 
|  | // call Restore() more times than Save*(). | 
|  | void Restore(); | 
|  |  | 
|  | // Applies |rect| to the current clip using the specified region |op|. | 
|  | void ClipRect(const Rect& rect, SkClipOp op = SkClipOp::kIntersect); | 
|  | void ClipRect(const RectF& rect, SkClipOp op = SkClipOp::kIntersect); | 
|  |  | 
|  | // Adds |path| to the current clip. |do_anti_alias| is true if the clip | 
|  | // should be antialiased. | 
|  | void ClipPath(const SkPath& path, bool do_anti_alias); | 
|  |  | 
|  | // Returns the bounds of the current clip (in local coordinates) in the | 
|  | // |bounds| parameter, and returns true if it is non empty. | 
|  | bool GetClipBounds(Rect* bounds); | 
|  |  | 
|  | void Translate(const Vector2d& offset); | 
|  |  | 
|  | void Scale(float x_scale, float y_scale); | 
|  |  | 
|  | // Fills the entire canvas' bitmap (restricted to current clip) with | 
|  | // specified |color| using a transfer mode of SkBlendMode::kSrcOver. | 
|  | void DrawColor(SkColor color); | 
|  |  | 
|  | // Fills the entire canvas' bitmap (restricted to current clip) with | 
|  | // specified |color| and |mode|. | 
|  | void DrawColor(SkColor color, SkBlendMode mode); | 
|  |  | 
|  | // Fills |rect| with |color| using a transfer mode of | 
|  | // SkBlendMode::kSrcOver. | 
|  | void FillRect(const Rect& rect, SkColor color); | 
|  |  | 
|  | // Fills |rect| with the specified |color| and |mode|. | 
|  | void FillRect(const Rect& rect, SkColor color, SkBlendMode mode); | 
|  |  | 
|  | // Draws a single pixel rect in the specified region with the specified | 
|  | // color, using a transfer mode of SkBlendMode::kSrcOver. | 
|  | // | 
|  | // NOTE: if you need a single pixel line, use DrawLine. | 
|  | void DrawRect(const RectF& rect, SkColor color); | 
|  |  | 
|  | // Draws a single pixel rect in the specified region with the specified | 
|  | // color and transfer mode. | 
|  | // | 
|  | // NOTE: if you need a single pixel line, use DrawLine. | 
|  | void DrawRect(const RectF& rect, SkColor color, SkBlendMode mode); | 
|  |  | 
|  | // Draws the given rectangle with the given |flags| parameters. | 
|  | // DEPRECATED in favor of the RectF version below. | 
|  | // TODO(funkysidd): Remove this (http://crbug.com/553726) | 
|  | void DrawRect(const Rect& rect, const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws the given rectangle with the given |flags| parameters. | 
|  | void DrawRect(const RectF& rect, const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws a single pixel line with the specified color. | 
|  | // DEPRECATED in favor of the RectF version below. | 
|  | // TODO(funkysidd): Remove this (http://crbug.com/553726) | 
|  | void DrawLine(const Point& p1, const Point& p2, SkColor color); | 
|  |  | 
|  | // Draws a single dip line with the specified color. | 
|  | void DrawLine(const PointF& p1, const PointF& p2, SkColor color); | 
|  |  | 
|  | // Draws a line with the given |flags| parameters. | 
|  | // DEPRECATED in favor of the RectF version below. | 
|  | // TODO(funkysidd): Remove this (http://crbug.com/553726) | 
|  | void DrawLine(const Point& p1, const Point& p2, const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws a line with the given |flags| parameters. | 
|  | void DrawLine(const PointF& p1, | 
|  | const PointF& p2, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws a line that's a single DIP. At fractional scale factors, this is | 
|  | // floored to the nearest integral number of pixels. | 
|  | void DrawSharpLine(PointF p1, PointF p2, SkColor color); | 
|  |  | 
|  | // As above, but draws a single pixel at all scale factors. | 
|  | void Draw1pxLine(PointF p1, PointF p2, SkColor color); | 
|  |  | 
|  | // Draws a circle with the given |flags| parameters. | 
|  | // DEPRECATED in favor of the RectF version below. | 
|  | // TODO(funkysidd): Remove this (http://crbug.com/553726) | 
|  | void DrawCircle(const Point& center_point, | 
|  | int radius, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws a circle with the given |flags| parameters. | 
|  | void DrawCircle(const PointF& center_point, | 
|  | float radius, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws the given rectangle with rounded corners of |radius| using the | 
|  | // given |flags| parameters. DEPRECATED in favor of the RectF version below. | 
|  | // TODO(mgiuca): Remove this (http://crbug.com/553726). | 
|  | void DrawRoundRect(const Rect& rect, int radius, const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws the given rectangle with rounded corners of |radius| using the | 
|  | // given |flags| parameters. | 
|  | void DrawRoundRect(const RectF& rect, | 
|  | float radius, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws the given path using the given |flags| parameters. | 
|  | void DrawPath(const SkPath& path, const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws an image with the origin at the specified location. The upper left | 
|  | // corner of the bitmap is rendered at the specified location. | 
|  | // Parameters are specified relative to current canvas scale not in pixels. | 
|  | // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1. | 
|  | void DrawImageInt(const ImageSkia&, int x, int y); | 
|  |  | 
|  | // Helper for DrawImageInt(..., flags) that constructs a temporary flags and | 
|  | // calls flags.setAlpha(alpha). | 
|  | void DrawImageInt(const ImageSkia&, int x, int y, uint8_t alpha); | 
|  |  | 
|  | // Draws an image with the origin at the specified location, using the | 
|  | // specified flags. The upper left corner of the bitmap is rendered at the | 
|  | // specified location. | 
|  | // Parameters are specified relative to current canvas scale not in pixels. | 
|  | // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. | 
|  | void DrawImageInt(const ImageSkia& image, | 
|  | int x, | 
|  | int y, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws a portion of an image in the specified location. The src parameters | 
|  | // correspond to the region of the bitmap to draw in the region defined | 
|  | // by the dest coordinates. | 
|  | // | 
|  | // If the width or height of the source differs from that of the destination, | 
|  | // the image will be scaled. When scaling down, a mipmap will be generated. | 
|  | // Set |filter| to use filtering for images, otherwise the nearest-neighbor | 
|  | // algorithm is used for resampling. | 
|  | // | 
|  | // An optional custom cc::PaintFlags can be provided. | 
|  | // Parameters are specified relative to current canvas scale not in pixels. | 
|  | // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. | 
|  | void DrawImageInt(const ImageSkia& image, | 
|  | int src_x, | 
|  | int src_y, | 
|  | int src_w, | 
|  | int src_h, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | int dest_w, | 
|  | int dest_h, | 
|  | bool filter); | 
|  | void DrawImageInt(const ImageSkia& image, | 
|  | int src_x, | 
|  | int src_y, | 
|  | int src_w, | 
|  | int src_h, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | int dest_w, | 
|  | int dest_h, | 
|  | bool filter, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Same as the DrawImageInt functions above. Difference being this does not | 
|  | // do any scaling, i.e. it does not scale the output by the device scale | 
|  | // factor (the internal image_scale_). It takes an ImageSkiaRep instead of | 
|  | // an ImageSkia as the caller chooses the exact scale/pixel representation to | 
|  | // use, which will not be scaled while drawing it into the canvas. | 
|  | void DrawImageIntInPixel(const ImageSkiaRep& image_rep, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | int dest_w, | 
|  | int dest_h, | 
|  | bool filter, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws an |image| with the top left corner at |x| and |y|, clipped to | 
|  | // |path|. | 
|  | // Parameters are specified relative to current canvas scale not in pixels. | 
|  | // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1. | 
|  | void DrawImageInPath(const ImageSkia& image, | 
|  | int x, | 
|  | int y, | 
|  | const SkPath& path, | 
|  | const cc::PaintFlags& flags); | 
|  |  | 
|  | // Draws the frame of the |skottie| animation specified by the normalized time | 
|  | // instant t [0->first frame .. 1->last frame] onto the region corresponded by | 
|  | // |dst| in the canvas. |images| is a map from asset id to the corresponding | 
|  | // image to use when rendering this frame; it may be empty if this animation | 
|  | // frame does not contain any images in it. | 
|  | void DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie, | 
|  | const Rect& dst, | 
|  | float t, | 
|  | cc::SkottieFrameDataMap images, | 
|  | const cc::SkottieColorMap& color_map, | 
|  | cc::SkottieTextPropertyValueMap text_map); | 
|  |  | 
|  | // Draws text with the specified color, fonts and location. The text is | 
|  | // aligned to the left, vertically centered, clipped to the region. If the | 
|  | // text is too big, it is truncated and '...' is added to the end. | 
|  | void DrawStringRect(std::u16string_view text, | 
|  | const FontList& font_list, | 
|  | SkColor color, | 
|  | const Rect& display_rect); | 
|  |  | 
|  | // Draws text with the specified color, fonts and location. The last argument | 
|  | // specifies flags for how the text should be rendered. It can be one of | 
|  | // TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT or TEXT_ALIGN_LEFT. | 
|  | void DrawStringRectWithFlags(std::u16string_view text, | 
|  | const FontList& font_list, | 
|  | SkColor color, | 
|  | const Rect& display_rect, | 
|  | int flags); | 
|  |  | 
|  | // Draws a |rect| in the specified region with the specified |color|. The | 
|  | // width of the stroke is |thickness| dip, but the actual pixel width will be | 
|  | // floored to ensure an integral value. | 
|  | void DrawSolidFocusRect(RectF rect, SkColor color, int thickness); | 
|  |  | 
|  | // Tiles the image in the specified region. | 
|  | // Parameters are specified relative to current canvas scale not in pixels. | 
|  | // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. | 
|  | void TileImageInt(const ImageSkia& image, | 
|  | int x, | 
|  | int y, | 
|  | int w, | 
|  | int h); | 
|  | void TileImageInt(const ImageSkia& image, | 
|  | int src_x, | 
|  | int src_y, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | int w, | 
|  | int h, | 
|  | float tile_scale = 1.0f, | 
|  | SkTileMode tile_mode_x = SkTileMode::kRepeat, | 
|  | SkTileMode tile_mode_y = SkTileMode::kRepeat, | 
|  | cc::PaintFlags* flags = nullptr); | 
|  |  | 
|  | // Helper for TileImageInt().  Initializes |flags| for tiling |image| with the | 
|  | // given parameters.  Returns false if the provided image does not have a | 
|  | // representation for the current scale. | 
|  | bool InitPaintFlagsForTiling(const ImageSkia& image, | 
|  | int src_x, | 
|  | int src_y, | 
|  | float tile_scale_x, | 
|  | float tile_scale_y, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | SkTileMode tile_mode_x, | 
|  | SkTileMode tile_mode_y, | 
|  | cc::PaintFlags* flags); | 
|  |  | 
|  | // Apply transformation on the canvas. | 
|  | void Transform(const Transform& transform); | 
|  |  | 
|  | // Text will be clipped when the canvas is scaled. See crbug.com/1469229. | 
|  | // This method prevents clipping by increasing the clip rect size by 0.5f. | 
|  | void AdjustClipRectForTextBounds(const Rect& text_bounds); | 
|  |  | 
|  | // Note that writing to this bitmap will modify pixels stored in this canvas. | 
|  | SkBitmap GetBitmap() const; | 
|  |  | 
|  | // Tests whether the provided rectangle intersects the current clip rect. | 
|  | bool IntersectsClipRect(const SkRect& rect) const; | 
|  |  | 
|  | // TODO(enne): rename sk_canvas members and interface. | 
|  | cc::PaintCanvas* sk_canvas() { return canvas_; } | 
|  | float image_scale() const { return image_scale_; } | 
|  |  | 
|  | private: | 
|  | // Helper for the DrawImageInt functions declared above. The | 
|  | // |remove_image_scale| parameter indicates if the scale of the |image_rep| | 
|  | // should be removed when drawing the image, to avoid double-scaling it. | 
|  | void DrawImageIntHelper(const ImageSkiaRep& image_rep, | 
|  | int src_x, | 
|  | int src_y, | 
|  | int src_w, | 
|  | int src_h, | 
|  | int dest_x, | 
|  | int dest_y, | 
|  | int dest_w, | 
|  | int dest_h, | 
|  | bool filter, | 
|  | const cc::PaintFlags& flags, | 
|  | bool remove_image_scale); | 
|  | cc::PaintCanvas* CreateOwnedCanvas(const Size& size, bool is_opaque); | 
|  |  | 
|  | // The device scale factor at which drawing on this canvas occurs. | 
|  | // An additional scale can be applied via Canvas::Scale(). However, | 
|  | // Canvas::Scale() does not affect |image_scale_|. | 
|  | float image_scale_; | 
|  |  | 
|  | // canvas_ is our active canvas object. Sometimes we are also the owner, | 
|  | // in which case bitmap_ and owned_canvas_ will be set. Other times we are | 
|  | // just borrowing someone else's canvas, in which case canvas_ will point | 
|  | // there but bitmap_ and owned_canvas_ will not exist. | 
|  | std::optional<SkBitmap> bitmap_; | 
|  | std::optional<cc::SkiaPaintCanvas> owned_canvas_; | 
|  | raw_ptr<cc::PaintCanvas> canvas_; | 
|  | }; | 
|  |  | 
|  | }  // namespace gfx | 
|  |  | 
|  | #endif  // UI_GFX_CANVAS_H_ |