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

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

Issue 2870643003: Add support for animations in vector icons. (Closed)
Patch Set: deps, casting 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 | « ui/gfx/paint_vector_icon.h ('k') | 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"
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 "base/trace_event/trace_event.h"
16 #include "cc/paint/paint_canvas.h" 17 #include "cc/paint/paint_canvas.h"
17 #include "cc/paint/paint_flags.h" 18 #include "cc/paint/paint_flags.h"
18 #include "third_party/skia/include/core/SkPath.h" 19 #include "third_party/skia/include/core/SkPath.h"
20 #include "ui/gfx/animation/tween.h"
19 #include "ui/gfx/canvas.h" 21 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/image/canvas_image_source.h" 22 #include "ui/gfx/image/canvas_image_source.h"
21 #include "ui/gfx/scoped_canvas.h" 23 #include "ui/gfx/scoped_canvas.h"
22 #include "ui/gfx/vector_icon_types.h" 24 #include "ui/gfx/vector_icon_types.h"
23 25
24 namespace gfx { 26 namespace gfx {
25 27
26 namespace { 28 namespace {
27 29
28 // Helper that simplifies iterating over a sequence of PathElements. 30 // Helper that simplifies iterating over a sequence of PathElements.
(...skipping 25 matching lines...) Expand all
54 case CANVAS_DIMENSIONS: 56 case CANVAS_DIMENSIONS:
55 return 1; 57 return 1;
56 58
57 case MOVE_TO: 59 case MOVE_TO:
58 case R_MOVE_TO: 60 case R_MOVE_TO:
59 case LINE_TO: 61 case LINE_TO:
60 case R_LINE_TO: 62 case R_LINE_TO:
61 return 2; 63 return 2;
62 64
63 case CIRCLE: 65 case CIRCLE:
66 case TRANSITION_END:
64 return 3; 67 return 3;
65 68
66 case PATH_COLOR_ARGB: 69 case PATH_COLOR_ARGB:
67 case CUBIC_TO_SHORTHAND: 70 case CUBIC_TO_SHORTHAND:
68 case CLIP: 71 case CLIP:
69 return 4; 72 return 4;
70 73
71 case ROUND_RECT: 74 case ROUND_RECT:
72 return 5; 75 return 5;
73 76
74 case CUBIC_TO: 77 case CUBIC_TO:
75 case R_CUBIC_TO: 78 case R_CUBIC_TO:
76 return 6; 79 return 6;
77 80
78 case ARC_TO: 81 case ARC_TO:
79 case R_ARC_TO: 82 case R_ARC_TO:
80 return 7; 83 return 7;
81 84
82 case NEW_PATH: 85 case NEW_PATH:
83 case PATH_MODE_CLEAR: 86 case PATH_MODE_CLEAR:
84 case CAP_SQUARE: 87 case CAP_SQUARE:
85 case CLOSE: 88 case CLOSE:
86 case DISABLE_AA: 89 case DISABLE_AA:
87 case FLIPS_IN_RTL: 90 case FLIPS_IN_RTL:
91 case TRANSITION_FROM:
92 case TRANSITION_TO:
88 case END: 93 case END:
89 return 0; 94 return 0;
90 } 95 }
91 96
92 NOTREACHED(); 97 NOTREACHED();
93 return 0; 98 return 0;
94 } 99 }
95 100
96 const PathElement* path_elements_; 101 const PathElement* path_elements_;
97 int command_index_ = 0; 102 int command_index_ = 0;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 path.push_back(PathElement(SkIntToScalar(hex_value))); 155 path.push_back(PathElement(SkIntToScalar(hex_value)));
151 else 156 else
152 path.push_back(PathElement(CommandFromString(piece))); 157 path.push_back(PathElement(CommandFromString(piece)));
153 } 158 }
154 return path; 159 return path;
155 } 160 }
156 161
157 void PaintPath(Canvas* canvas, 162 void PaintPath(Canvas* canvas,
158 const PathElement* path_elements, 163 const PathElement* path_elements,
159 int dip_size, 164 int dip_size,
160 SkColor color) { 165 SkColor color,
166 const base::TimeDelta& elapsed_time) {
161 SkPath path; 167 SkPath path;
162 path.setFillType(SkPath::kEvenOdd_FillType); 168 path.setFillType(SkPath::kEvenOdd_FillType);
163 169
164 int canvas_size = kReferenceSizeDip; 170 int canvas_size = kReferenceSizeDip;
165 std::vector<SkPath> paths; 171 std::vector<SkPath> paths;
166 std::vector<cc::PaintFlags> flags_array; 172 std::vector<cc::PaintFlags> flags_array;
167 SkRect clip_rect = SkRect::MakeEmpty(); 173 SkRect clip_rect = SkRect::MakeEmpty();
168 bool flips_in_rtl = false; 174 bool flips_in_rtl = false;
169 CommandType previous_command_type = NEW_PATH; 175 CommandType previous_command_type = NEW_PATH;
170 176
171 for (PathParser parser(path_elements); parser.CurrentCommand() != END; 177 for (PathParser parser(path_elements); parser.CurrentCommand() != END;
172 parser.Advance()) { 178 parser.Advance()) {
173 auto arg = [&parser](int i) { return parser.GetArgument(i); }; 179 auto arg = [&parser](int i) { return parser.GetArgument(i); };
174 const CommandType command_type = parser.CurrentCommand(); 180 const CommandType command_type = parser.CurrentCommand();
175 if (paths.empty() || command_type == NEW_PATH) { 181 auto start_new_path = [&paths]() {
176 paths.push_back(SkPath()); 182 paths.push_back(SkPath());
177 paths.back().setFillType(SkPath::kEvenOdd_FillType); 183 paths.back().setFillType(SkPath::kEvenOdd_FillType);
178 184 };
185 auto start_new_flags = [&flags_array, &color]() {
179 flags_array.push_back(cc::PaintFlags()); 186 flags_array.push_back(cc::PaintFlags());
180 flags_array.back().setColor(color); 187 flags_array.back().setColor(color);
181 flags_array.back().setAntiAlias(true); 188 flags_array.back().setAntiAlias(true);
182 flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap); 189 flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap);
190 };
191
192 if (paths.empty() || command_type == NEW_PATH) {
193 start_new_path();
194 start_new_flags();
183 } 195 }
184 196
185 SkPath& path = paths.back(); 197 SkPath& path = paths.back();
186 cc::PaintFlags& flags = flags_array.back(); 198 cc::PaintFlags& flags = flags_array.back();
187 switch (command_type) { 199 switch (command_type) {
188 // Handled above. 200 // Handled above.
189 case NEW_PATH: 201 case NEW_PATH:
190 break; 202 break;
191 203
192 case PATH_COLOR_ARGB: 204 case PATH_COLOR_ARGB:
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 break; 344 break;
333 345
334 case DISABLE_AA: 346 case DISABLE_AA:
335 flags.setAntiAlias(false); 347 flags.setAntiAlias(false);
336 break; 348 break;
337 349
338 case FLIPS_IN_RTL: 350 case FLIPS_IN_RTL:
339 flips_in_rtl = true; 351 flips_in_rtl = true;
340 break; 352 break;
341 353
354 // Transitions work by pushing new paths and a new set of flags onto the
355 // stack. When TRANSITION_END is seen, the paths and flags are
356 // interpolated based on |elapsed_time| and the tween type.
357 case TRANSITION_FROM: {
358 start_new_path();
359 break;
360 }
361
362 case TRANSITION_TO: {
363 start_new_path();
364 start_new_flags();
365 break;
366 }
367
368 case TRANSITION_END: {
369 DCHECK_GT(paths.size(), 2U);
370 // TODO(estade): check whether this operation (interpolation) is costly,
371 // and remove this TRACE log if not.
372 TRACE_EVENT0("ui", "PaintVectorIcon TRANSITION_END");
373
374 const base::TimeDelta delay =
375 base::TimeDelta::FromMillisecondsD(SkScalarToDouble(arg(0)));
376 const base::TimeDelta duration =
377 base::TimeDelta::FromMillisecondsD(SkScalarToDouble(arg(1)));
378
379 double state = 0;
380 if (elapsed_time >= delay + duration) {
381 state = 1;
382 } else if (elapsed_time > delay) {
383 state = (elapsed_time - delay).ToInternalValue() /
384 static_cast<double>(duration.ToInternalValue());
385 }
386
387 auto weight = Tween::CalculateValue(
388 static_cast<Tween::Type>(SkScalarTruncToInt(arg(2))), state);
389
390 SkPath path1, path2;
391 path1.swap(paths.back());
392 paths.pop_back();
393 path2.swap(paths.back());
394 paths.pop_back();
395
396 SkPath interpolated_path;
397 bool could_interpolate =
398 path1.interpolate(path2, weight, &interpolated_path);
399 DCHECK(could_interpolate);
400 paths.back().addPath(interpolated_path);
401
402 // Perform manual interpolation of flags properties. TODO(estade): fill
403 // more of these in as necessary.
404 DCHECK_GT(flags_array.size(), 1U);
405 cc::PaintFlags& end_flags = flags_array.back();
406 cc::PaintFlags& start_flags = flags_array[flags_array.size() - 2];
407
408 start_flags.setColor(Tween::ColorValueBetween(
409 weight, start_flags.getColor(), end_flags.getColor()));
410
411 flags_array.pop_back();
412 break;
413 }
414
342 case END: 415 case END:
343 NOTREACHED(); 416 NOTREACHED();
344 break; 417 break;
345 } 418 }
346 419
347 previous_command_type = command_type; 420 previous_command_type = command_type;
348 } 421 }
349 422
350 gfx::ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size, 423 ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size, flips_in_rtl);
351 flips_in_rtl);
352 424
353 if (dip_size != canvas_size) { 425 if (dip_size != canvas_size) {
354 SkScalar scale = SkIntToScalar(dip_size) / SkIntToScalar(canvas_size); 426 SkScalar scale = SkIntToScalar(dip_size) / SkIntToScalar(canvas_size);
355 canvas->sk_canvas()->scale(scale, scale); 427 canvas->sk_canvas()->scale(scale, scale);
356 } 428 }
357 429
358 if (!clip_rect.isEmpty()) 430 if (!clip_rect.isEmpty())
359 canvas->sk_canvas()->clipRect(clip_rect); 431 canvas->sk_canvas()->clipRect(clip_rect);
360 432
361 DCHECK_EQ(flags_array.size(), paths.size()); 433 DCHECK_EQ(flags_array.size(), paths.size());
362 for (size_t i = 0; i < paths.size(); ++i) 434 for (size_t i = 0; i < paths.size(); ++i)
363 canvas->DrawPath(paths[i], flags_array[i]); 435 canvas->DrawPath(paths[i], flags_array[i]);
364 } 436 }
365 437
366 class VectorIconSource : public CanvasImageSource { 438 class VectorIconSource : public CanvasImageSource {
367 public: 439 public:
368 VectorIconSource(const VectorIcon& icon, 440 VectorIconSource(const VectorIcon& icon,
369 int dip_size, 441 int dip_size,
370 SkColor color, 442 SkColor color,
371 const VectorIcon& badge_icon) 443 const VectorIcon& badge_icon)
372 : CanvasImageSource(gfx::Size(dip_size, dip_size), false), 444 : CanvasImageSource(Size(dip_size, dip_size), false),
373 color_(color), 445 color_(color),
374 icon_(icon), 446 icon_(icon),
375 badge_(badge_icon) {} 447 badge_(badge_icon) {}
376 448
377 VectorIconSource(const std::string& definition, int dip_size, SkColor color) 449 VectorIconSource(const std::string& definition, int dip_size, SkColor color)
378 : CanvasImageSource(gfx::Size(dip_size, dip_size), false), 450 : CanvasImageSource(Size(dip_size, dip_size), false),
379 color_(color), 451 color_(color),
380 icon_(kNoneIcon), 452 icon_(kNoneIcon),
381 badge_(kNoneIcon), 453 badge_(kNoneIcon),
382 path_(PathFromSource(definition)) {} 454 path_(PathFromSource(definition)) {}
383 455
384 ~VectorIconSource() override {} 456 ~VectorIconSource() override {}
385 457
386 // CanvasImageSource: 458 // CanvasImageSource:
387 bool HasRepresentationAtAllScales() const override { 459 bool HasRepresentationAtAllScales() const override {
388 return !icon_.is_empty(); 460 return !icon_.is_empty();
389 } 461 }
390 462
391 void Draw(gfx::Canvas* canvas) override { 463 void Draw(Canvas* canvas) override {
392 if (path_.empty()) { 464 if (path_.empty()) {
393 PaintVectorIcon(canvas, icon_, size_.width(), color_); 465 PaintVectorIcon(canvas, icon_, size_.width(), color_);
394 if (!badge_.is_empty()) 466 if (!badge_.is_empty())
395 PaintVectorIcon(canvas, badge_, size_.width(), color_); 467 PaintVectorIcon(canvas, badge_, size_.width(), color_);
396 } else { 468 } else {
397 PaintPath(canvas, path_.data(), size_.width(), color_); 469 PaintPath(canvas, path_.data(), size_.width(), color_, base::TimeDelta());
398 } 470 }
399 } 471 }
400 472
401 private: 473 private:
402 const SkColor color_; 474 const SkColor color_;
403 const VectorIcon& icon_; 475 const VectorIcon& icon_;
404 const VectorIcon& badge_; 476 const VectorIcon& badge_;
405 const std::vector<PathElement> path_; 477 const std::vector<PathElement> path_;
406 478
407 DISALLOW_COPY_AND_ASSIGN(VectorIconSource); 479 DISALLOW_COPY_AND_ASSIGN(VectorIconSource);
(...skipping 11 matching lines...) Expand all
419 int dip_size, 491 int dip_size,
420 SkColor color, 492 SkColor color,
421 const VectorIcon& badge_icon) { 493 const VectorIcon& badge_icon) {
422 IconDescription description(&icon, dip_size, color, &badge_icon); 494 IconDescription description(&icon, dip_size, color, &badge_icon);
423 auto iter = images_.find(description); 495 auto iter = images_.find(description);
424 if (iter != images_.end()) 496 if (iter != images_.end())
425 return iter->second; 497 return iter->second;
426 498
427 ImageSkia icon_image( 499 ImageSkia icon_image(
428 new VectorIconSource(icon, dip_size, color, badge_icon), 500 new VectorIconSource(icon, dip_size, color, badge_icon),
429 gfx::Size(dip_size, dip_size)); 501 Size(dip_size, dip_size));
430 images_.insert(std::make_pair(description, icon_image)); 502 images_.insert(std::make_pair(description, icon_image));
431 return icon_image; 503 return icon_image;
432 } 504 }
433 505
434 private: 506 private:
435 struct IconDescription { 507 struct IconDescription {
436 IconDescription(const VectorIcon* icon, 508 IconDescription(const VectorIcon* icon,
437 int dip_size, 509 int dip_size,
438 SkColor color, 510 SkColor color,
439 const VectorIcon* badge_icon) 511 const VectorIcon* badge_icon)
440 : icon(icon), 512 : icon(icon),
441 dip_size(dip_size), 513 dip_size(dip_size),
442 color(color), 514 color(color),
443 badge_icon(badge_icon) {} 515 badge_icon(badge_icon) {}
444 516
445 bool operator<(const IconDescription& other) const { 517 bool operator<(const IconDescription& other) const {
446 return std::tie(icon, dip_size, color, badge_icon) < 518 return std::tie(icon, dip_size, color, badge_icon) <
447 std::tie(other.icon, other.dip_size, other.color, 519 std::tie(other.icon, other.dip_size, other.color,
448 other.badge_icon); 520 other.badge_icon);
449 } 521 }
450 522
451 const gfx::VectorIcon* icon; 523 const VectorIcon* icon;
452 int dip_size; 524 int dip_size;
453 SkColor color; 525 SkColor color;
454 const gfx::VectorIcon* badge_icon; 526 const VectorIcon* badge_icon;
455 }; 527 };
456 528
457 std::map<IconDescription, ImageSkia> images_; 529 std::map<IconDescription, ImageSkia> images_;
458 530
459 DISALLOW_COPY_AND_ASSIGN(VectorIconCache); 531 DISALLOW_COPY_AND_ASSIGN(VectorIconCache);
460 }; 532 };
461 533
462 static base::LazyInstance<VectorIconCache>::DestructorAtExit g_icon_cache = 534 static base::LazyInstance<VectorIconCache>::DestructorAtExit g_icon_cache =
463 LAZY_INSTANCE_INITIALIZER; 535 LAZY_INSTANCE_INITIALIZER;
464 536
465 } // namespace 537 } // namespace
466 538
467 const VectorIcon kNoneIcon = {}; 539 const VectorIcon kNoneIcon = {};
468 540
469 void PaintVectorIcon(Canvas* canvas, const VectorIcon& icon, SkColor color) { 541 void PaintVectorIcon(Canvas* canvas,
470 PaintVectorIcon(canvas, icon, GetDefaultSizeOfVectorIcon(icon), color); 542 const VectorIcon& icon,
543 SkColor color,
544 const base::TimeDelta& elapsed_time) {
545 PaintVectorIcon(canvas, icon, GetDefaultSizeOfVectorIcon(icon), color,
546 elapsed_time);
471 } 547 }
472 548
473 void PaintVectorIcon(Canvas* canvas, 549 void PaintVectorIcon(Canvas* canvas,
474 const VectorIcon& icon, 550 const VectorIcon& icon,
475 int dip_size, 551 int dip_size,
476 SkColor color) { 552 SkColor color,
553 const base::TimeDelta& elapsed_time) {
477 DCHECK(!icon.is_empty()); 554 DCHECK(!icon.is_empty());
478 const PathElement* path = (canvas->image_scale() == 1.f && icon.path_1x_) 555 const PathElement* path =
479 ? icon.path_1x_ 556 (canvas->image_scale() == 1.f && icon.path_1x) ? icon.path_1x : icon.path;
480 : icon.path_; 557 PaintPath(canvas, path, dip_size, color, elapsed_time);
481 PaintPath(canvas, path, dip_size, color);
482 } 558 }
483 559
484 ImageSkia CreateVectorIcon(const VectorIcon& icon, SkColor color) { 560 ImageSkia CreateVectorIcon(const VectorIcon& icon, SkColor color) {
485 return CreateVectorIcon(icon, GetDefaultSizeOfVectorIcon(icon), color); 561 return CreateVectorIcon(icon, GetDefaultSizeOfVectorIcon(icon), color);
486 } 562 }
487 563
488 ImageSkia CreateVectorIcon(const VectorIcon& icon, 564 ImageSkia CreateVectorIcon(const VectorIcon& icon,
489 int dip_size, 565 int dip_size,
490 SkColor color) { 566 SkColor color) {
491 return CreateVectorIconWithBadge(icon, dip_size, color, kNoneIcon); 567 return CreateVectorIconWithBadge(icon, dip_size, color, kNoneIcon);
492 } 568 }
493 569
494 ImageSkia CreateVectorIconWithBadge(const VectorIcon& icon, 570 ImageSkia CreateVectorIconWithBadge(const VectorIcon& icon,
495 int dip_size, 571 int dip_size,
496 SkColor color, 572 SkColor color,
497 const VectorIcon& badge_icon) { 573 const VectorIcon& badge_icon) {
498 return icon.is_empty() ? gfx::ImageSkia() 574 return icon.is_empty() ? ImageSkia()
499 : g_icon_cache.Get().GetOrCreateIcon( 575 : g_icon_cache.Get().GetOrCreateIcon(
500 icon, dip_size, color, badge_icon); 576 icon, dip_size, color, badge_icon);
501 } 577 }
502 578
503 ImageSkia CreateVectorIconFromSource(const std::string& source, 579 ImageSkia CreateVectorIconFromSource(const std::string& source,
504 int dip_size, 580 int dip_size,
505 SkColor color) { 581 SkColor color) {
506 return CanvasImageSource::MakeImageSkia<VectorIconSource>(source, dip_size, 582 return CanvasImageSource::MakeImageSkia<VectorIconSource>(source, dip_size,
507 color); 583 color);
508 } 584 }
509 585
510 int GetDefaultSizeOfVectorIcon(const gfx::VectorIcon& icon) { 586 int GetDefaultSizeOfVectorIcon(const VectorIcon& icon) {
511 const PathElement* one_x_path = icon.path_1x_ ? icon.path_1x_ : icon.path_; 587 const PathElement* one_x_path = icon.path_1x ? icon.path_1x : icon.path;
512 return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg 588 return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg
513 : kReferenceSizeDip; 589 : kReferenceSizeDip;
514 } 590 }
515 591
592 base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon) {
593 base::TimeDelta last_motion;
594 for (PathParser parser(icon.path); parser.CurrentCommand() != END;
595 parser.Advance()) {
596 if (parser.CurrentCommand() != TRANSITION_END)
597 continue;
598
599 auto end_time = base::TimeDelta::FromMillisecondsD(parser.GetArgument(0)) +
600 base::TimeDelta::FromMillisecondsD(parser.GetArgument(1));
601 if (end_time > last_motion)
602 last_motion = end_time;
603 }
604 return last_motion;
605 }
606
516 } // namespace gfx 607 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/paint_vector_icon.h ('k') | ui/gfx/vector_icon_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698