Chromium Code Reviews| Index: ui/gfx/paint_vector_icon.cc |
| diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc |
| index 060fd3e81959c326026c27cc81abe324c0c3df4a..e63e85572e9a735239cd3bd3fc2afe8068e3b72f 100644 |
| --- a/ui/gfx/paint_vector_icon.cc |
| +++ b/ui/gfx/paint_vector_icon.cc |
| @@ -7,6 +7,8 @@ |
| #include <map> |
| #include "base/lazy_instance.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/gfx/vector_icon_types.h" |
| @@ -16,84 +18,48 @@ namespace gfx { |
| namespace { |
| -class VectorIconSource : public CanvasImageSource { |
| - public: |
| - VectorIconSource(VectorIconId id, size_t dip_size, SkColor color) |
| - : CanvasImageSource( |
| - gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)), |
| - false), |
| - id_(id), |
| - color_(color) {} |
| - |
| - ~VectorIconSource() override {} |
| - |
| - // CanvasImageSource: |
| - void Draw(gfx::Canvas* canvas) override { |
| - PaintVectorIcon(canvas, id_, size_.width(), color_); |
| - } |
| - |
| - private: |
| - const VectorIconId id_; |
| - const SkColor color_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(VectorIconSource); |
| -}; |
| - |
| -// This class caches vector icons (as ImageSkia) so they don't have to be drawn |
| -// more than once. This also guarantees the backing data for the images returned |
| -// by CreateVectorIcon will persist in memory until program termination. |
| -class VectorIconCache { |
| - public: |
| - VectorIconCache() {} |
| - ~VectorIconCache() {} |
| - |
| - ImageSkia GetOrCreateIcon(VectorIconId id, size_t dip_size, SkColor color) { |
| - IconDescription description(id, dip_size, color); |
| - auto iter = images_.find(description); |
| - if (iter != images_.end()) |
| - return iter->second; |
| +// Translates a string such as "MOVE_TO" into a command such as MOVE_TO. |
| +CommandType CommandFromString(const std::string& source) { |
| +#define RETURN_IF_IS(command) \ |
| + if (source == #command) \ |
| + return command; |
| + |
| + RETURN_IF_IS(MOVE_TO); |
| + RETURN_IF_IS(R_MOVE_TO); |
| + RETURN_IF_IS(R_LINE_TO); |
| + RETURN_IF_IS(H_LINE_TO); |
| + RETURN_IF_IS(R_H_LINE_TO); |
| + RETURN_IF_IS(V_LINE_TO); |
| + RETURN_IF_IS(R_V_LINE_TO); |
| + RETURN_IF_IS(CUBIC_TO); |
| + RETURN_IF_IS(R_CUBIC_TO); |
| + RETURN_IF_IS(CIRCLE); |
| + RETURN_IF_IS(CLOSE); |
| + RETURN_IF_IS(END); |
| +#undef RETURN_IF_IS |
|
sky
2015/08/03 15:27:49
It would be nice if this generated a compile error
Evan Stade
2015/08/03 17:19:37
I agree, but the only way I can think to do that i
|
| + |
| + NOTREACHED(); |
| + return CLOSE; |
| +} |
| - ImageSkia icon( |
| - new VectorIconSource(id, dip_size, color), |
| - gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size))); |
| - images_.insert(std::make_pair(description, icon)); |
| - return icon; |
| +std::vector<PathElement> PathFromSource(const std::string& source) { |
| + std::vector<PathElement> path; |
| + std::vector<std::string> pieces = base::SplitString( |
| + source, "\n ,f", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + for (const auto& piece : pieces) { |
| + double value; |
| + if (base::StringToDouble(piece, &value)) |
| + path.push_back(PathElement(SkDoubleToScalar(value))); |
| + else |
| + path.push_back(PathElement(CommandFromString(piece))); |
| } |
| + return path; |
| +} |
| - private: |
| - struct IconDescription { |
| - IconDescription(VectorIconId id, size_t dip_size, SkColor color) |
| - : id(id), dip_size(dip_size), color(color) {} |
| - |
| - bool operator<(const IconDescription& other) const { |
| - if (id != other.id) |
| - return id < other.id; |
| - if (dip_size != other.dip_size) |
| - return dip_size < other.dip_size; |
| - return color < other.color; |
| - } |
| - |
| - VectorIconId id; |
| - size_t dip_size; |
| - SkColor color; |
| - }; |
| - |
| - std::map<IconDescription, ImageSkia> images_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(VectorIconCache); |
| -}; |
| - |
| -static base::LazyInstance<VectorIconCache> g_icon_cache = |
| - LAZY_INSTANCE_INITIALIZER; |
| - |
| -} // namespace |
| - |
| -void PaintVectorIcon(Canvas* canvas, |
| - VectorIconId id, |
| - size_t dip_size, |
| - SkColor color) { |
| - DCHECK(VectorIconId::VECTOR_ICON_NONE != id); |
| - const PathElement* path_elements = GetPathForVectorIcon(id); |
| +void PaintPath(Canvas* canvas, |
| + const PathElement* path_elements, |
| + size_t dip_size, |
| + SkColor color) { |
| SkPath path; |
| path.setFillType(SkPath::kEvenOdd_FillType); |
| if (dip_size != kReferenceSizeDip) { |
| @@ -207,8 +173,110 @@ void PaintVectorIcon(Canvas* canvas, |
| canvas->DrawPath(path, paint); |
| } |
| +class VectorIconSource : public CanvasImageSource { |
| + public: |
| + VectorIconSource(VectorIconId id, size_t dip_size, SkColor color) |
| + : CanvasImageSource( |
| + gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)), |
| + false), |
| + id_(id), |
| + color_(color) {} |
| + |
| + VectorIconSource(const std::string& definition, |
| + size_t dip_size, |
| + SkColor color) |
| + : CanvasImageSource( |
| + gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)), |
| + false), |
| + id_(VectorIconId::VECTOR_ICON_NONE), |
| + path_(PathFromSource(definition)), |
| + color_(color) {} |
| + |
| + ~VectorIconSource() override {} |
| + |
| + // CanvasImageSource: |
| + void Draw(gfx::Canvas* canvas) override { |
| + if (path_.empty()) |
| + PaintVectorIcon(canvas, id_, size_.width(), color_); |
| + else |
| + PaintPath(canvas, path_.data(), size_.width(), color_); |
| + } |
| + |
| + private: |
| + const VectorIconId id_; |
| + const std::vector<PathElement> path_; |
| + const SkColor color_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(VectorIconSource); |
| +}; |
| + |
| +// This class caches vector icons (as ImageSkia) so they don't have to be drawn |
| +// more than once. This also guarantees the backing data for the images returned |
| +// by CreateVectorIcon will persist in memory until program termination. |
| +class VectorIconCache { |
| + public: |
| + VectorIconCache() {} |
| + ~VectorIconCache() {} |
| + |
| + ImageSkia GetOrCreateIcon(VectorIconId id, size_t dip_size, SkColor color) { |
| + IconDescription description(id, dip_size, color); |
| + auto iter = images_.find(description); |
| + if (iter != images_.end()) |
| + return iter->second; |
| + |
| + ImageSkia icon( |
| + new VectorIconSource(id, dip_size, color), |
| + gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size))); |
| + images_.insert(std::make_pair(description, icon)); |
| + return icon; |
| + } |
| + |
| + private: |
| + struct IconDescription { |
| + IconDescription(VectorIconId id, size_t dip_size, SkColor color) |
| + : id(id), dip_size(dip_size), color(color) {} |
| + |
| + bool operator<(const IconDescription& other) const { |
| + if (id != other.id) |
| + return id < other.id; |
| + if (dip_size != other.dip_size) |
| + return dip_size < other.dip_size; |
| + return color < other.color; |
| + } |
| + |
| + VectorIconId id; |
| + size_t dip_size; |
| + SkColor color; |
| + }; |
| + |
| + std::map<IconDescription, ImageSkia> images_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(VectorIconCache); |
| +}; |
| + |
| +static base::LazyInstance<VectorIconCache> g_icon_cache = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +} // namespace |
| + |
| +void PaintVectorIcon(Canvas* canvas, |
| + VectorIconId id, |
| + size_t dip_size, |
| + SkColor color) { |
| + DCHECK(VectorIconId::VECTOR_ICON_NONE != id); |
| + PaintPath(canvas, GetPathForVectorIcon(id), dip_size, color); |
| +} |
| + |
| ImageSkia CreateVectorIcon(VectorIconId id, size_t dip_size, SkColor color) { |
| return g_icon_cache.Get().GetOrCreateIcon(id, dip_size, color); |
| } |
| +ImageSkia CreateVectorIconFromSource(const std::string& source, |
| + size_t dip_size, |
| + SkColor color) { |
| + return ImageSkia( |
| + new VectorIconSource(source, dip_size, color), |
| + gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size))); |
| +} |
| + |
| } // namespace gfx |