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 848bb2b4b59ae3d5a4c93b22623e8552fea46aea..f332c08d31329f54f6519f9dd335b817abc138c4 100644 |
| --- a/ui/gfx/paint_vector_icon.cc |
| +++ b/ui/gfx/paint_vector_icon.cc |
| @@ -16,6 +16,7 @@ |
| #include "cc/paint/paint_canvas.h" |
| #include "cc/paint/paint_flags.h" |
| #include "third_party/skia/include/core/SkPath.h" |
| +#include "ui/gfx/animation/tween.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/gfx/scoped_canvas.h" |
| @@ -67,6 +68,7 @@ class PathParser { |
| return 2; |
| case CIRCLE: |
| + case TRANSITION_END: |
| return 3; |
| case PATH_COLOR_ARGB: |
| @@ -91,6 +93,8 @@ class PathParser { |
| case CLOSE: |
| case DISABLE_AA: |
| case FLIPS_IN_RTL: |
| + case TRANSITION_FROM: |
| + case TRANSITION_TO: |
| case END: |
| return 0; |
| } |
| @@ -163,7 +167,8 @@ std::vector<PathElement> PathFromSource(const std::string& source) { |
| void PaintPath(Canvas* canvas, |
| const PathElement* path_elements, |
| int dip_size, |
| - SkColor color) { |
| + SkColor color, |
| + const base::TimeDelta* elapsed_time = nullptr) { |
| SkPath path; |
| path.setFillType(SkPath::kEvenOdd_FillType); |
| @@ -179,14 +184,21 @@ void PaintPath(Canvas* canvas, |
| while (parser.Advance()) { |
| const CommandType command_type = parser.CurrentCommand(); |
| - if (paths.empty() || command_type == NEW_PATH) { |
| + |
| + auto start_new_path = [&paths]() { |
| paths.push_back(SkPath()); |
| paths.back().setFillType(SkPath::kEvenOdd_FillType); |
| - |
| + }; |
| + auto start_new_flags = [&flags_array, &color]() { |
| flags_array.push_back(cc::PaintFlags()); |
| flags_array.back().setColor(color); |
| flags_array.back().setAntiAlias(true); |
| flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap); |
| + }; |
| + |
| + if (paths.empty() || command_type == NEW_PATH) { |
| + start_new_path(); |
| + start_new_flags(); |
| } |
| SkPath& path = paths.back(); |
| @@ -346,6 +358,68 @@ void PaintPath(Canvas* canvas, |
| flips_in_rtl = true; |
| break; |
| + // Transitions work by pushing new paths and a new set of flags onto the |
| + // stack. When TRANSITION_END is seen, the paths and flags are |
| + // interpolated based on |elapsed_time| and the tween type. |
| + case TRANSITION_FROM: { |
| + start_new_path(); |
| + break; |
| + } |
| + |
| + case TRANSITION_TO: { |
| + start_new_path(); |
| + start_new_flags(); |
| + break; |
| + } |
| + |
| + case TRANSITION_END: { |
| + DCHECK_GT(paths.size(), 2U); |
| + |
| + const base::TimeDelta delay = |
| + base::TimeDelta::FromMillisecondsD(SkScalarToDouble(arg(0))); |
| + const base::TimeDelta duration = |
| + base::TimeDelta::FromMillisecondsD(SkScalarToDouble(arg(1))); |
| + const base::TimeDelta current_time = |
| + elapsed_time ? *elapsed_time : base::TimeDelta(); |
| + |
| + double state = 0; |
| + if (current_time >= delay + duration) { |
| + state = 1; |
| + } else if (current_time > delay) { |
| + state = (current_time - delay).ToInternalValue() / |
| + static_cast<double>(duration.ToInternalValue()); |
| + } |
| + |
| + auto weight = |
| + Tween::CalculateValue(static_cast<Tween::Type>(arg(2)), state); |
|
tdanderson
2017/05/08 21:22:54
I recognize that allowing non-numeric arguments wo
Evan Stade
2017/05/08 22:27:41
I don't think that's necessary. I haven't actually
tdanderson
2017/05/09 20:31:40
Acknowledged.
|
| + |
| + SkPath path1, path2; |
| + path1.swap(paths.back()); |
| + paths.pop_back(); |
| + path2.swap(paths.back()); |
| + paths.pop_back(); |
| + |
| + SkPath interpolated_path; |
| + bool could_interpolate = |
| + path1.interpolate(path2, weight, &interpolated_path); |
| + DCHECK(could_interpolate); |
| + paths.back().addPath(interpolated_path); |
| + |
| + // Perform manual interpolation of flags properties. TODO(estade): fill |
| + // more of these in as necessary. |
| + DCHECK_GT(flags_array.size(), 1U); |
| + cc::PaintFlags& end_flags = flags_array.back(); |
| + cc::PaintFlags& start_flags = flags_array[flags_array.size() - 2]; |
| + |
| + start_flags.setColor(Tween::ColorValueBetween( |
| + weight, start_flags.getColor(), end_flags.getColor())); |
| + start_flags.setStrokeWidth(Tween::FloatValueBetween( |
| + weight, start_flags.getStrokeWidth(), end_flags.getStrokeWidth())); |
| + |
| + flags_array.pop_back(); |
| + break; |
| + } |
| + |
| case END: |
| NOTREACHED(); |
| break; |
| @@ -354,8 +428,7 @@ void PaintPath(Canvas* canvas, |
| previous_command_type = command_type; |
| } |
| - gfx::ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size, |
| - flips_in_rtl); |
| + ScopedRTLFlipCanvas scoped_rtl_flip_canvas(canvas, canvas_size, flips_in_rtl); |
| if (dip_size != canvas_size) { |
| SkScalar scale = SkIntToScalar(dip_size) / SkIntToScalar(canvas_size); |
| @@ -376,13 +449,13 @@ class VectorIconSource : public CanvasImageSource { |
| int dip_size, |
| SkColor color, |
| const VectorIcon& badge_icon) |
| - : CanvasImageSource(gfx::Size(dip_size, dip_size), false), |
| + : CanvasImageSource(Size(dip_size, dip_size), false), |
| color_(color), |
| icon_(icon), |
| badge_(badge_icon) {} |
| VectorIconSource(const std::string& definition, int dip_size, SkColor color) |
| - : CanvasImageSource(gfx::Size(dip_size, dip_size), false), |
| + : CanvasImageSource(Size(dip_size, dip_size), false), |
| color_(color), |
| icon_(kNoneIcon), |
| badge_(kNoneIcon), |
| @@ -395,7 +468,7 @@ class VectorIconSource : public CanvasImageSource { |
| return !icon_.is_empty(); |
| } |
| - void Draw(gfx::Canvas* canvas) override { |
| + void Draw(Canvas* canvas) override { |
| if (path_.empty()) { |
| PaintVectorIcon(canvas, icon_, size_.width(), color_); |
| if (!badge_.is_empty()) |
| @@ -433,7 +506,7 @@ class VectorIconCache { |
| ImageSkia icon_image( |
| new VectorIconSource(icon, dip_size, color, badge_icon), |
| - gfx::Size(dip_size, dip_size)); |
| + Size(dip_size, dip_size)); |
| images_.insert(std::make_pair(description, icon_image)); |
| return icon_image; |
| } |
| @@ -455,10 +528,10 @@ class VectorIconCache { |
| other.badge_icon); |
| } |
| - const gfx::VectorIcon* icon; |
| + const VectorIcon* icon; |
| int dip_size; |
| SkColor color; |
| - const gfx::VectorIcon* badge_icon; |
| + const VectorIcon* badge_icon; |
| }; |
| std::map<IconDescription, ImageSkia> images_; |
| @@ -473,19 +546,24 @@ static base::LazyInstance<VectorIconCache>::DestructorAtExit g_icon_cache = |
| const VectorIcon kNoneIcon = {}; |
| -void PaintVectorIcon(Canvas* canvas, const VectorIcon& icon, SkColor color) { |
| - PaintVectorIcon(canvas, icon, GetDefaultSizeOfVectorIcon(icon), color); |
| +void PaintVectorIcon(Canvas* canvas, |
| + const VectorIcon& icon, |
| + SkColor color, |
| + const base::TimeDelta* elapsed_time) { |
| + PaintVectorIcon(canvas, icon, GetDefaultSizeOfVectorIcon(icon), color, |
| + elapsed_time); |
| } |
| void PaintVectorIcon(Canvas* canvas, |
| const VectorIcon& icon, |
| int dip_size, |
| - SkColor color) { |
| + SkColor color, |
| + const base::TimeDelta* elapsed_time) { |
| DCHECK(!icon.is_empty()); |
| const PathElement* path = (canvas->image_scale() == 1.f && icon.path_1x_) |
| ? icon.path_1x_ |
| : icon.path_; |
| - PaintPath(canvas, path, dip_size, color); |
| + PaintPath(canvas, path, dip_size, color, elapsed_time); |
| } |
| ImageSkia CreateVectorIcon(const VectorIcon& icon, SkColor color) { |
| @@ -502,7 +580,7 @@ ImageSkia CreateVectorIconWithBadge(const VectorIcon& icon, |
| int dip_size, |
| SkColor color, |
| const VectorIcon& badge_icon) { |
| - return icon.is_empty() ? gfx::ImageSkia() |
| + return icon.is_empty() ? ImageSkia() |
| : g_icon_cache.Get().GetOrCreateIcon( |
| icon, dip_size, color, badge_icon); |
| } |
| @@ -514,10 +592,25 @@ ImageSkia CreateVectorIconFromSource(const std::string& source, |
| color); |
| } |
| -int GetDefaultSizeOfVectorIcon(const gfx::VectorIcon& icon) { |
| +int GetDefaultSizeOfVectorIcon(const VectorIcon& icon) { |
| const PathElement* one_x_path = icon.path_1x_ ? icon.path_1x_ : icon.path_; |
| return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg |
| : kReferenceSizeDip; |
| } |
| +base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon) { |
|
tdanderson
2017/05/08 21:22:54
I don't see any place in this CL where you are usi
Evan Stade
2017/05/08 22:27:41
You could make the same argument for the transitio
tdanderson
2017/05/09 20:31:40
Acknowledged.
|
| + base::TimeDelta last_motion; |
| + PathParser parser(icon.path_); |
| + while (parser.Advance()) { |
| + if (parser.CurrentCommand() != TRANSITION_END) |
| + continue; |
| + |
| + auto end_time = base::TimeDelta::FromMillisecondsD(parser.GetArgument(0)) + |
| + base::TimeDelta::FromMillisecondsD(parser.GetArgument(1)); |
| + if (end_time > last_motion) |
| + last_motion = end_time; |
| + } |
| + return last_motion; |
| +} |
| + |
| } // namespace gfx |