Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(609)

Side by Side Diff: ui/gfx/paint_vector_icon.cc

Issue 2861203002: Refactor some vector icon parsing code for reuse (Closed)
Patch Set: compile more Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | ui/gfx/vector_icon_types.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/paint_vector_icon.h" 5 #include "ui/gfx/paint_vector_icon.h"
tdanderson 2017/05/08 20:13:20 general comment for follow-up CL(s): I think the a
Evan Stade 2017/05/08 22:13:37 Did you have something in mind that you think is i
tdanderson 2017/05/09 16:42:49 Thank you for sharing this philosophy. I will take
6 6
7 #include <map> 7 #include <map>
8 #include <tuple> 8 #include <tuple>
9 9
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
11 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_split.h" 15 #include "base/strings/string_split.h"
16 #include "cc/paint/paint_canvas.h" 16 #include "cc/paint/paint_canvas.h"
17 #include "cc/paint/paint_flags.h" 17 #include "cc/paint/paint_flags.h"
18 #include "third_party/skia/include/core/SkPath.h" 18 #include "third_party/skia/include/core/SkPath.h"
19 #include "ui/gfx/canvas.h" 19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/image/canvas_image_source.h" 20 #include "ui/gfx/image/canvas_image_source.h"
21 #include "ui/gfx/scoped_canvas.h" 21 #include "ui/gfx/scoped_canvas.h"
22 #include "ui/gfx/vector_icon_types.h" 22 #include "ui/gfx/vector_icon_types.h"
23 23
24 namespace gfx { 24 namespace gfx {
25 25
26 namespace { 26 namespace {
27 27
28 // Helper that simplifies iterating over a sequence of PathElements.
tdanderson 2017/05/08 20:13:20 optional: "...of the form 'command, (argument,)*'"
Evan Stade 2017/05/08 22:13:37 shrug, I can't think of any extra wording that add
tdanderson 2017/05/09 16:42:49 Acknowledged.
29 class PathParser {
30 public:
31 PathParser(const PathElement* path_elements)
32 : path_elements_(path_elements) {}
33 ~PathParser() {}
34
35 bool Advance() {
36 if (command_index_ < 0)
tdanderson 2017/05/08 20:13:20 From a usage point of view I would expect that:
Evan Stade 2017/05/08 22:13:37 simplified this and the loop below. Once again pro
37 command_index_ = 0;
38 else if (CurrentCommand() != END)
39 command_index_ += GetArgumentCount() + 1;
40 return CurrentCommand() != END;
41 }
42
43 CommandType CurrentCommand() const {
44 return path_elements_[command_index_].command;
45 }
46
47 SkScalar GetArgument(int index) const {
tdanderson 2017/05/08 20:13:20 Consider GetArgumentOfCurrentCommand() for increas
Evan Stade 2017/05/08 22:13:37 Acknowledged.
48 DCHECK_LT(index, GetArgumentCount());
49 return path_elements_[command_index_ + 1 + index].arg;
50 }
51
52 private:
53 int GetArgumentCount() const {
54 switch (CurrentCommand()) {
55 case STROKE:
56 case H_LINE_TO:
57 case R_H_LINE_TO:
58 case V_LINE_TO:
59 case R_V_LINE_TO:
60 case CANVAS_DIMENSIONS:
61 return 1;
62
63 case MOVE_TO:
64 case R_MOVE_TO:
65 case LINE_TO:
66 case R_LINE_TO:
67 return 2;
68
69 case CIRCLE:
70 return 3;
71
72 case PATH_COLOR_ARGB:
73 case CUBIC_TO_SHORTHAND:
74 case CLIP:
75 return 4;
76
77 case ROUND_RECT:
78 return 5;
79
80 case CUBIC_TO:
81 case R_CUBIC_TO:
82 return 6;
83
84 case ARC_TO:
85 case R_ARC_TO:
86 return 7;
87
88 case NEW_PATH:
tdanderson 2017/05/08 20:13:20 nit: move the 0-argument block above the 1-argumen
Evan Stade 2017/05/08 22:13:37 I like this here because it's what I consider a de
tdanderson 2017/05/09 16:42:49 I am not sure how that is related. If I had a swit
89 case PATH_MODE_CLEAR:
90 case CAP_SQUARE:
91 case CLOSE:
92 case DISABLE_AA:
93 case FLIPS_IN_RTL:
94 case END:
95 return 0;
96 }
97
98 NOTREACHED();
99 return 0;
100 }
101
102 const PathElement* path_elements_;
103 int command_index_ = -1;
104
105 DISALLOW_COPY_AND_ASSIGN(PathParser);
106 };
107
28 // Translates a string such as "MOVE_TO" into a command such as MOVE_TO. 108 // Translates a string such as "MOVE_TO" into a command such as MOVE_TO.
29 CommandType CommandFromString(const std::string& source) { 109 CommandType CommandFromString(const std::string& source) {
30 #define RETURN_IF_IS(command) \ 110 #define RETURN_IF_IS(command) \
31 if (source == #command) \ 111 if (source == #command) \
32 return command; 112 return command;
33 113
34 RETURN_IF_IS(NEW_PATH); 114 RETURN_IF_IS(NEW_PATH);
35 RETURN_IF_IS(PATH_COLOR_ARGB); 115 RETURN_IF_IS(PATH_COLOR_ARGB);
36 RETURN_IF_IS(PATH_MODE_CLEAR); 116 RETURN_IF_IS(PATH_MODE_CLEAR);
37 RETURN_IF_IS(STROKE); 117 RETURN_IF_IS(STROKE);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 SkPath path; 167 SkPath path;
88 path.setFillType(SkPath::kEvenOdd_FillType); 168 path.setFillType(SkPath::kEvenOdd_FillType);
89 169
90 int canvas_size = kReferenceSizeDip; 170 int canvas_size = kReferenceSizeDip;
91 std::vector<SkPath> paths; 171 std::vector<SkPath> paths;
92 std::vector<cc::PaintFlags> flags_array; 172 std::vector<cc::PaintFlags> flags_array;
93 SkRect clip_rect = SkRect::MakeEmpty(); 173 SkRect clip_rect = SkRect::MakeEmpty();
94 bool flips_in_rtl = false; 174 bool flips_in_rtl = false;
95 CommandType previous_command_type = NEW_PATH; 175 CommandType previous_command_type = NEW_PATH;
96 176
97 for (size_t i = 0; path_elements[i].type != END; i++) { 177 PathParser parser(path_elements);
98 if (paths.empty() || path_elements[i].type == NEW_PATH) { 178 auto arg = [&parser](int i) { return parser.GetArgument(i); };
179
180 while (parser.Advance()) {
181 const CommandType command_type = parser.CurrentCommand();
182 if (paths.empty() || command_type == NEW_PATH) {
99 paths.push_back(SkPath()); 183 paths.push_back(SkPath());
100 paths.back().setFillType(SkPath::kEvenOdd_FillType); 184 paths.back().setFillType(SkPath::kEvenOdd_FillType);
101 185
102 flags_array.push_back(cc::PaintFlags()); 186 flags_array.push_back(cc::PaintFlags());
103 flags_array.back().setColor(color); 187 flags_array.back().setColor(color);
104 flags_array.back().setAntiAlias(true); 188 flags_array.back().setAntiAlias(true);
105 flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap); 189 flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap);
106 } 190 }
107 191
108 SkPath& path = paths.back(); 192 SkPath& path = paths.back();
109 cc::PaintFlags& flags = flags_array.back(); 193 cc::PaintFlags& flags = flags_array.back();
110 CommandType command_type = path_elements[i].type;
111 switch (command_type) { 194 switch (command_type) {
112 // Handled above. 195 // Handled above.
113 case NEW_PATH: 196 case NEW_PATH:
114 continue; 197 break;
115 198
116 case PATH_COLOR_ARGB: { 199 case PATH_COLOR_ARGB:
117 int a = SkScalarFloorToInt(path_elements[++i].arg); 200 flags.setColor(SkColorSetARGB(
118 int r = SkScalarFloorToInt(path_elements[++i].arg); 201 SkScalarFloorToInt(arg(0)), SkScalarFloorToInt(arg(1)),
119 int g = SkScalarFloorToInt(path_elements[++i].arg); 202 SkScalarFloorToInt(arg(2)), SkScalarFloorToInt(arg(3))));
120 int b = SkScalarFloorToInt(path_elements[++i].arg);
121 flags.setColor(SkColorSetARGB(a, r, g, b));
122 break; 203 break;
123 }
124 204
125 case PATH_MODE_CLEAR: { 205 case PATH_MODE_CLEAR:
126 flags.setBlendMode(SkBlendMode::kClear); 206 flags.setBlendMode(SkBlendMode::kClear);
127 break; 207 break;
128 };
129 208
130 case STROKE: { 209 case STROKE:
131 flags.setStyle(cc::PaintFlags::kStroke_Style); 210 flags.setStyle(cc::PaintFlags::kStroke_Style);
132 SkScalar width = path_elements[++i].arg; 211 flags.setStrokeWidth(arg(0));
133 flags.setStrokeWidth(width);
134 break; 212 break;
135 }
136 213
137 case CAP_SQUARE: { 214 case CAP_SQUARE:
138 flags.setStrokeCap(cc::PaintFlags::kSquare_Cap); 215 flags.setStrokeCap(cc::PaintFlags::kSquare_Cap);
139 break; 216 break;
140 }
141 217
142 case MOVE_TO: { 218 case MOVE_TO:
143 SkScalar x = path_elements[++i].arg; 219 path.moveTo(arg(0), arg(1));
144 SkScalar y = path_elements[++i].arg;
145 path.moveTo(x, y);
146 break; 220 break;
147 }
148 221
149 case R_MOVE_TO: { 222 case R_MOVE_TO:
150 if (previous_command_type == CLOSE) { 223 if (previous_command_type == CLOSE) {
151 // This triggers injectMoveToIfNeeded() so that the next subpath 224 // This triggers injectMoveToIfNeeded() so that the next subpath
152 // will start at the correct place. See [ 225 // will start at the correct place. See [
153 // https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand ]. 226 // https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand ].
154 path.rLineTo(0, 0); 227 path.rLineTo(0, 0);
155 } 228 }
156 229
157 SkScalar x = path_elements[++i].arg; 230 path.rMoveTo(arg(0), arg(1));
158 SkScalar y = path_elements[++i].arg;
159 path.rMoveTo(x, y);
160 break; 231 break;
161 }
162 232
163 case ARC_TO: 233 case ARC_TO:
164 case R_ARC_TO: { 234 case R_ARC_TO: {
165 SkScalar rx = path_elements[++i].arg; 235 SkScalar rx = arg(0);
166 SkScalar ry = path_elements[++i].arg; 236 SkScalar ry = arg(1);
167 SkScalar angle = path_elements[++i].arg; 237 SkScalar angle = arg(2);
168 SkScalar large_arc_flag = path_elements[++i].arg; 238 SkScalar large_arc_flag = arg(3);
169 SkScalar arc_sweep_flag = path_elements[++i].arg; 239 SkScalar arc_sweep_flag = arg(4);
170 SkScalar x = path_elements[++i].arg; 240 SkScalar x = arg(5);
171 SkScalar y = path_elements[++i].arg; 241 SkScalar y = arg(6);
172 242
173 auto path_fn = 243 auto path_fn =
174 command_type == ARC_TO 244 command_type == ARC_TO
175 ? static_cast<void (SkPath::*)( 245 ? static_cast<void (SkPath::*)(
176 SkScalar, SkScalar, SkScalar, SkPath::ArcSize, 246 SkScalar, SkScalar, SkScalar, SkPath::ArcSize,
177 SkPath::Direction, SkScalar, SkScalar)>(&SkPath::arcTo) 247 SkPath::Direction, SkScalar, SkScalar)>(&SkPath::arcTo)
178 : &SkPath::rArcTo; 248 : &SkPath::rArcTo;
179 (path.*path_fn)( 249 (path.*path_fn)(
180 rx, ry, angle, 250 rx, ry, angle,
181 large_arc_flag ? SkPath::kLarge_ArcSize : SkPath::kSmall_ArcSize, 251 large_arc_flag ? SkPath::kLarge_ArcSize : SkPath::kSmall_ArcSize,
182 arc_sweep_flag ? SkPath::kCW_Direction : SkPath::kCCW_Direction, x, 252 arc_sweep_flag ? SkPath::kCW_Direction : SkPath::kCCW_Direction, x,
183 y); 253 y);
184 break; 254 break;
185 } 255 }
186 256
187 case LINE_TO: { 257 case LINE_TO:
188 SkScalar x = path_elements[++i].arg; 258 path.lineTo(arg(0), arg(1));
189 SkScalar y = path_elements[++i].arg;
190 path.lineTo(x, y);
191 break; 259 break;
192 }
193 260
194 case R_LINE_TO: { 261 case R_LINE_TO:
195 SkScalar x = path_elements[++i].arg; 262 path.rLineTo(arg(0), arg(1));
196 SkScalar y = path_elements[++i].arg;
197 path.rLineTo(x, y);
198 break; 263 break;
199 }
200 264
201 case H_LINE_TO: { 265 case H_LINE_TO: {
202 SkPoint last_point; 266 SkPoint last_point;
203 path.getLastPt(&last_point); 267 path.getLastPt(&last_point);
204 SkScalar x = path_elements[++i].arg; 268 path.lineTo(arg(0), last_point.fY);
205 path.lineTo(x, last_point.fY);
206 break; 269 break;
207 } 270 }
208 271
209 case R_H_LINE_TO: { 272 case R_H_LINE_TO:
210 SkScalar x = path_elements[++i].arg; 273 path.rLineTo(arg(0), 0);
211 path.rLineTo(x, 0);
212 break; 274 break;
213 }
214 275
215 case V_LINE_TO: { 276 case V_LINE_TO: {
216 SkPoint last_point; 277 SkPoint last_point;
217 path.getLastPt(&last_point); 278 path.getLastPt(&last_point);
218 SkScalar y = path_elements[++i].arg; 279 path.lineTo(last_point.fX, arg(0));
219 path.lineTo(last_point.fX, y);
220 break; 280 break;
221 } 281 }
222 282
223 case R_V_LINE_TO: { 283 case R_V_LINE_TO:
224 SkScalar y = path_elements[++i].arg; 284 path.rLineTo(0, arg(0));
225 path.rLineTo(0, y);
226 break; 285 break;
227 }
228 286
229 case CUBIC_TO: { 287 case CUBIC_TO:
230 SkScalar x1 = path_elements[++i].arg; 288 path.cubicTo(arg(0), arg(1), arg(2), arg(3), arg(4), arg(5));
231 SkScalar y1 = path_elements[++i].arg;
232 SkScalar x2 = path_elements[++i].arg;
233 SkScalar y2 = path_elements[++i].arg;
234 SkScalar x3 = path_elements[++i].arg;
235 SkScalar y3 = path_elements[++i].arg;
236 path.cubicTo(x1, y1, x2, y2, x3, y3);
237 break; 289 break;
238 }
239 290
240 case R_CUBIC_TO: { 291 case R_CUBIC_TO:
241 SkScalar x1 = path_elements[++i].arg; 292 path.rCubicTo(arg(0), arg(1), arg(2), arg(3), arg(4), arg(5));
242 SkScalar y1 = path_elements[++i].arg;
243 SkScalar x2 = path_elements[++i].arg;
244 SkScalar y2 = path_elements[++i].arg;
245 SkScalar x3 = path_elements[++i].arg;
246 SkScalar y3 = path_elements[++i].arg;
247 path.rCubicTo(x1, y1, x2, y2, x3, y3);
248 break; 293 break;
249 }
250 294
251 case CUBIC_TO_SHORTHAND: { 295 case CUBIC_TO_SHORTHAND: {
252 // Compute the first control point (|x1| and |y1|) as the reflection 296 // Compute the first control point (|x1| and |y1|) as the reflection
253 // of the second control point on the previous command relative to 297 // of the second control point on the previous command relative to
254 // the current point. If there is no previous command or if the 298 // the current point. If there is no previous command or if the
255 // previous command is not a cubic Bezier curve, the first control 299 // previous command is not a cubic Bezier curve, the first control
256 // point is coincident with the current point. Refer to the SVG 300 // point is coincident with the current point. Refer to the SVG
257 // path specs for further details. 301 // path specs for further details.
258 SkPoint last_point; 302 SkPoint last_point;
259 path.getLastPt(&last_point); 303 path.getLastPt(&last_point);
260 SkScalar delta_x = 0; 304 SkScalar delta_x = 0;
261 SkScalar delta_y = 0; 305 SkScalar delta_y = 0;
262 if (previous_command_type == CUBIC_TO || 306 if (previous_command_type == CUBIC_TO ||
263 previous_command_type == R_CUBIC_TO || 307 previous_command_type == R_CUBIC_TO ||
264 previous_command_type == CUBIC_TO_SHORTHAND) { 308 previous_command_type == CUBIC_TO_SHORTHAND) {
265 SkPoint last_control_point = path.getPoint(path.countPoints() - 2); 309 SkPoint last_control_point = path.getPoint(path.countPoints() - 2);
266 delta_x = last_point.fX - last_control_point.fX; 310 delta_x = last_point.fX - last_control_point.fX;
267 delta_y = last_point.fY - last_control_point.fY; 311 delta_y = last_point.fY - last_control_point.fY;
268 } 312 }
269 313
270 SkScalar x1 = last_point.fX + delta_x; 314 SkScalar x1 = last_point.fX + delta_x;
271 SkScalar y1 = last_point.fY + delta_y; 315 SkScalar y1 = last_point.fY + delta_y;
272 SkScalar x2 = path_elements[++i].arg; 316 path.cubicTo(x1, y1, arg(0), arg(1), arg(2), arg(3));
273 SkScalar y2 = path_elements[++i].arg;
274 SkScalar x3 = path_elements[++i].arg;
275 SkScalar y3 = path_elements[++i].arg;
276 path.cubicTo(x1, y1, x2, y2, x3, y3);
277 break; 317 break;
278 } 318 }
279 319
280 case CIRCLE: { 320 case CIRCLE:
281 SkScalar x = path_elements[++i].arg; 321 path.addCircle(arg(0), arg(1), arg(2));
282 SkScalar y = path_elements[++i].arg;
283 SkScalar r = path_elements[++i].arg;
284 path.addCircle(x, y, r);
285 break; 322 break;
286 }
287 323
288 case ROUND_RECT: { 324 case ROUND_RECT:
289 SkScalar x = path_elements[++i].arg; 325 path.addRoundRect(SkRect::MakeXYWH(arg(0), arg(1), arg(2), arg(3)),
290 SkScalar y = path_elements[++i].arg; 326 arg(4), arg(4));
291 SkScalar w = path_elements[++i].arg;
292 SkScalar h = path_elements[++i].arg;
293 SkScalar radius = path_elements[++i].arg;
294 path.addRoundRect(SkRect::MakeXYWH(x, y, w, h), radius, radius);
295 break; 327 break;
296 }
297 328
298 case CLOSE: { 329 case CLOSE:
299 path.close(); 330 path.close();
300 break; 331 break;
301 }
302 332
303 case CANVAS_DIMENSIONS: { 333 case CANVAS_DIMENSIONS:
304 SkScalar width = path_elements[++i].arg; 334 canvas_size = SkScalarTruncToInt(arg(0));
305 canvas_size = SkScalarTruncToInt(width);
306 break; 335 break;
307 }
308 336
309 case CLIP: { 337 case CLIP:
310 SkScalar x = path_elements[++i].arg; 338 clip_rect = SkRect::MakeXYWH(arg(0), arg(1), arg(2), arg(3));
311 SkScalar y = path_elements[++i].arg;
312 SkScalar w = path_elements[++i].arg;
313 SkScalar h = path_elements[++i].arg;
314 clip_rect = SkRect::MakeXYWH(x, y, w, h);
315 break; 339 break;
316 }
317 340
318 case DISABLE_AA: { 341 case DISABLE_AA:
319 flags.setAntiAlias(false); 342 flags.setAntiAlias(false);
320 break; 343 break;
321 }
322 344
323 case FLIPS_IN_RTL: { 345 case FLIPS_IN_RTL:
324 flips_in_rtl = true; 346 flips_in_rtl = true;
325 break; 347 break;
326 }
327 348
328 case END: 349 case END:
329 NOTREACHED(); 350 NOTREACHED();
330 break; 351 break;
331 } 352 }
332 353
333 previous_command_type = command_type; 354 previous_command_type = command_type;
334 } 355 }
335 356
336 gfx::ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size, 357 gfx::ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size,
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 509
489 ImageSkia CreateVectorIconFromSource(const std::string& source, 510 ImageSkia CreateVectorIconFromSource(const std::string& source,
490 int dip_size, 511 int dip_size,
491 SkColor color) { 512 SkColor color) {
492 return CanvasImageSource::MakeImageSkia<VectorIconSource>(source, dip_size, 513 return CanvasImageSource::MakeImageSkia<VectorIconSource>(source, dip_size,
493 color); 514 color);
494 } 515 }
495 516
496 int GetDefaultSizeOfVectorIcon(const gfx::VectorIcon& icon) { 517 int GetDefaultSizeOfVectorIcon(const gfx::VectorIcon& icon) {
497 const PathElement* one_x_path = icon.path_1x_ ? icon.path_1x_ : icon.path_; 518 const PathElement* one_x_path = icon.path_1x_ ? icon.path_1x_ : icon.path_;
498 return one_x_path[0].type == CANVAS_DIMENSIONS ? one_x_path[1].arg 519 return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg
499 : kReferenceSizeDip; 520 : kReferenceSizeDip;
500 } 521 }
501 522
502 } // namespace gfx 523 } // namespace gfx
OLDNEW
« no previous file with comments | « no previous file | ui/gfx/vector_icon_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698