Durable Storage: Refactor browser test and test the basic "deny" flow.
[chromium-blink-merge.git] / ui / gfx / paint_vector_icon.cc
blob304ed4c08fc10c203d97027e1ae1e5f805abf97e
1 // Copyright 2015 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.
5 #include "ui/gfx/paint_vector_icon.h"
7 #include <map>
9 #include "base/lazy_instance.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "third_party/skia/include/core/SkPath.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/image/canvas_image_source.h"
15 #include "ui/gfx/vector_icon_types.h"
16 #include "ui/gfx/vector_icons2.h"
18 namespace gfx {
20 namespace {
22 // Translates a string such as "MOVE_TO" into a command such as MOVE_TO.
23 CommandType CommandFromString(const std::string& source) {
24 #define RETURN_IF_IS(command) \
25 if (source == #command) \
26 return command;
28 RETURN_IF_IS(NEW_PATH);
29 RETURN_IF_IS(PATH_COLOR_ARGB);
30 RETURN_IF_IS(STROKE);
31 RETURN_IF_IS(MOVE_TO);
32 RETURN_IF_IS(R_MOVE_TO);
33 RETURN_IF_IS(LINE_TO);
34 RETURN_IF_IS(R_LINE_TO);
35 RETURN_IF_IS(H_LINE_TO);
36 RETURN_IF_IS(R_H_LINE_TO);
37 RETURN_IF_IS(V_LINE_TO);
38 RETURN_IF_IS(R_V_LINE_TO);
39 RETURN_IF_IS(CUBIC_TO);
40 RETURN_IF_IS(R_CUBIC_TO);
41 RETURN_IF_IS(CIRCLE);
42 RETURN_IF_IS(CLOSE);
43 RETURN_IF_IS(CANVAS_DIMENSIONS);
44 RETURN_IF_IS(CLIP);
45 RETURN_IF_IS(DISABLE_AA);
46 RETURN_IF_IS(END);
47 #undef RETURN_IF_IS
49 NOTREACHED();
50 return CLOSE;
53 std::vector<PathElement> PathFromSource(const std::string& source) {
54 std::vector<PathElement> path;
55 std::vector<std::string> pieces = base::SplitString(
56 source, "\n ,f", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
57 for (const auto& piece : pieces) {
58 double value;
59 if (base::StringToDouble(piece, &value))
60 path.push_back(PathElement(SkDoubleToScalar(value)));
61 else
62 path.push_back(PathElement(CommandFromString(piece)));
64 return path;
67 void PaintPath(Canvas* canvas,
68 const PathElement* path_elements,
69 size_t dip_size,
70 SkColor color) {
71 SkPath path;
72 path.setFillType(SkPath::kEvenOdd_FillType);
74 size_t canvas_size = kReferenceSizeDip;
75 std::vector<SkPath> paths;
76 std::vector<SkPaint> paints;
77 SkRect clip_rect = SkRect::MakeEmpty();
79 for (size_t i = 0; path_elements[i].type != END; i++) {
80 if (paths.empty() || path_elements[i].type == NEW_PATH) {
81 paths.push_back(SkPath());
82 paths.back().setFillType(SkPath::kEvenOdd_FillType);
84 paints.push_back(SkPaint());
85 paints.back().setColor(color);
86 paints.back().setAntiAlias(true);
87 paints.back().setStrokeCap(SkPaint::kRound_Cap);
90 SkPath& path = paths.back();
91 SkPaint& paint = paints.back();
92 switch (path_elements[i].type) {
93 // Handled above.
94 case NEW_PATH:
95 continue;
97 case PATH_COLOR_ARGB: {
98 int a = SkScalarFloorToInt(path_elements[++i].arg);
99 int r = SkScalarFloorToInt(path_elements[++i].arg);
100 int g = SkScalarFloorToInt(path_elements[++i].arg);
101 int b = SkScalarFloorToInt(path_elements[++i].arg);
102 paint.setColor(SkColorSetARGB(a, r, g, b));
103 break;
106 case STROKE: {
107 paint.setStyle(SkPaint::kStroke_Style);
108 SkScalar width = path_elements[++i].arg;
109 paint.setStrokeWidth(width);
110 break;
113 case MOVE_TO: {
114 SkScalar x = path_elements[++i].arg;
115 SkScalar y = path_elements[++i].arg;
116 path.moveTo(x, y);
117 break;
120 case R_MOVE_TO: {
121 SkScalar x = path_elements[++i].arg;
122 SkScalar y = path_elements[++i].arg;
123 path.rMoveTo(x, y);
124 break;
127 case LINE_TO: {
128 SkScalar x = path_elements[++i].arg;
129 SkScalar y = path_elements[++i].arg;
130 path.lineTo(x, y);
131 break;
134 case R_LINE_TO: {
135 SkScalar x = path_elements[++i].arg;
136 SkScalar y = path_elements[++i].arg;
137 path.rLineTo(x, y);
138 break;
141 case H_LINE_TO: {
142 SkPoint last_point;
143 path.getLastPt(&last_point);
144 SkScalar x = path_elements[++i].arg;
145 path.lineTo(x, last_point.fY);
146 break;
149 case R_H_LINE_TO: {
150 SkScalar x = path_elements[++i].arg;
151 path.rLineTo(x, 0);
152 break;
155 case V_LINE_TO: {
156 SkPoint last_point;
157 path.getLastPt(&last_point);
158 SkScalar y = path_elements[++i].arg;
159 path.lineTo(last_point.fX, y);
160 break;
163 case R_V_LINE_TO: {
164 SkScalar y = path_elements[++i].arg;
165 path.rLineTo(0, y);
166 break;
169 case CUBIC_TO: {
170 SkScalar x1 = path_elements[++i].arg;
171 SkScalar y1 = path_elements[++i].arg;
172 SkScalar x2 = path_elements[++i].arg;
173 SkScalar y2 = path_elements[++i].arg;
174 SkScalar x3 = path_elements[++i].arg;
175 SkScalar y3 = path_elements[++i].arg;
176 path.cubicTo(x1, y1, x2, y2, x3, y3);
177 break;
180 case R_CUBIC_TO: {
181 SkScalar x1 = path_elements[++i].arg;
182 SkScalar y1 = path_elements[++i].arg;
183 SkScalar x2 = path_elements[++i].arg;
184 SkScalar y2 = path_elements[++i].arg;
185 SkScalar x3 = path_elements[++i].arg;
186 SkScalar y3 = path_elements[++i].arg;
187 path.rCubicTo(x1, y1, x2, y2, x3, y3);
188 break;
191 case CIRCLE: {
192 SkScalar x = path_elements[++i].arg;
193 SkScalar y = path_elements[++i].arg;
194 SkScalar r = path_elements[++i].arg;
195 path.addCircle(x, y, r);
196 break;
199 case CLOSE: {
200 path.close();
201 break;
204 case CANVAS_DIMENSIONS: {
205 SkScalar width = path_elements[++i].arg;
206 canvas_size = SkScalarTruncToInt(width);
207 break;
210 case CLIP: {
211 SkScalar x = path_elements[++i].arg;
212 SkScalar y = path_elements[++i].arg;
213 SkScalar w = path_elements[++i].arg;
214 SkScalar h = path_elements[++i].arg;
215 clip_rect = SkRect::MakeXYWH(x, y, w, h);
216 break;
219 case DISABLE_AA: {
220 paint.setAntiAlias(false);
221 break;
224 case END:
225 NOTREACHED();
226 break;
230 if (dip_size != canvas_size) {
231 SkScalar scale = SkIntToScalar(dip_size) / SkIntToScalar(canvas_size);
232 canvas->sk_canvas()->scale(scale, scale);
235 if (!clip_rect.isEmpty())
236 canvas->sk_canvas()->clipRect(clip_rect);
238 DCHECK_EQ(paints.size(), paths.size());
239 for (size_t i = 0; i < paths.size(); ++i)
240 canvas->DrawPath(paths[i], paints[i]);
243 class VectorIconSource : public CanvasImageSource {
244 public:
245 VectorIconSource(VectorIconId id, size_t dip_size, SkColor color)
246 : CanvasImageSource(
247 gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)),
248 false),
249 id_(id),
250 color_(color) {}
252 VectorIconSource(const std::string& definition,
253 size_t dip_size,
254 SkColor color)
255 : CanvasImageSource(
256 gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)),
257 false),
258 id_(VectorIconId::VECTOR_ICON_NONE),
259 path_(PathFromSource(definition)),
260 color_(color) {}
262 ~VectorIconSource() override {}
264 // CanvasImageSource:
265 void Draw(gfx::Canvas* canvas) override {
266 if (path_.empty())
267 PaintVectorIcon(canvas, id_, size_.width(), color_);
268 else
269 PaintPath(canvas, path_.data(), size_.width(), color_);
272 private:
273 const VectorIconId id_;
274 const std::vector<PathElement> path_;
275 const SkColor color_;
277 DISALLOW_COPY_AND_ASSIGN(VectorIconSource);
280 // This class caches vector icons (as ImageSkia) so they don't have to be drawn
281 // more than once. This also guarantees the backing data for the images returned
282 // by CreateVectorIcon will persist in memory until program termination.
283 class VectorIconCache {
284 public:
285 VectorIconCache() {}
286 ~VectorIconCache() {}
288 ImageSkia GetOrCreateIcon(VectorIconId id, size_t dip_size, SkColor color) {
289 IconDescription description(id, dip_size, color);
290 auto iter = images_.find(description);
291 if (iter != images_.end())
292 return iter->second;
294 ImageSkia icon(
295 new VectorIconSource(id, dip_size, color),
296 gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)));
297 images_.insert(std::make_pair(description, icon));
298 return icon;
301 private:
302 struct IconDescription {
303 IconDescription(VectorIconId id, size_t dip_size, SkColor color)
304 : id(id), dip_size(dip_size), color(color) {}
306 bool operator<(const IconDescription& other) const {
307 if (id != other.id)
308 return id < other.id;
309 if (dip_size != other.dip_size)
310 return dip_size < other.dip_size;
311 return color < other.color;
314 VectorIconId id;
315 size_t dip_size;
316 SkColor color;
319 std::map<IconDescription, ImageSkia> images_;
321 DISALLOW_COPY_AND_ASSIGN(VectorIconCache);
324 static base::LazyInstance<VectorIconCache> g_icon_cache =
325 LAZY_INSTANCE_INITIALIZER;
327 } // namespace
329 void PaintVectorIcon(Canvas* canvas,
330 VectorIconId id,
331 size_t dip_size,
332 SkColor color) {
333 DCHECK(VectorIconId::VECTOR_ICON_NONE != id);
334 const PathElement* path = canvas->image_scale() == 1.f
335 ? GetPathForVectorIconAt1xScale(id)
336 : GetPathForVectorIcon(id);
337 PaintPath(canvas, path, dip_size, color);
340 ImageSkia CreateVectorIcon(VectorIconId id, size_t dip_size, SkColor color) {
341 return g_icon_cache.Get().GetOrCreateIcon(id, dip_size, color);
344 ImageSkia CreateVectorIconFromSource(const std::string& source,
345 size_t dip_size,
346 SkColor color) {
347 return ImageSkia(
348 new VectorIconSource(source, dip_size, color),
349 gfx::Size(static_cast<int>(dip_size), static_cast<int>(dip_size)));
352 } // namespace gfx