From a2a4fab1693d6985dda4de9e91825fd667f07598 Mon Sep 17 00:00:00 2001 From: varkha Date: Fri, 11 Mar 2016 13:12:24 -0800 Subject: [PATCH] Adjusts content bubble animation with respect to icon size This CL corrects several issues with the icon bubble animation: 1. The bubble is not clipping its children, so the image draws outside the bubble bounds. This is MD-specific. 2. The image is being centered at the bubble center when the size is too low, instead of always being positioned based on the leading edge of the bubble, so it doesn't "slide in" correctly shifting during the initial portion of the animation. 3. The animation "closes" down to zero width (MD) or smaller than necessary width (non-MD) and then snaps the image back into place; it should animate down to become just large enough to show the image. 4. Removes the clamp in non-MD size that prevents animation from starting at zero. 5. Avoids clipping icon at the end of the animation (MD) by hiding the border even before the animation ends. 6. Reduces padding at the end of the MD version of the text label. 7. Corrects RTL layout by showing trailing edge of the icon first. BUG=591411 Review URL: https://codereview.chromium.org/1763713004 Cr-Commit-Position: refs/heads/master@{#380729} --- chrome/browser/ui/layout_constants.cc | 2 +- .../content_setting_image_view.cc | 47 ++-- .../location_bar/content_setting_image_view.h | 1 + .../location_bar/icon_label_bubble_view.cc | 109 ++++++--- .../location_bar/icon_label_bubble_view.h | 16 +- .../icon_label_bubble_view_unittest.cc | 217 ++++++++++++++++++ chrome/chrome_tests_unit.gypi | 1 + 7 files changed, 342 insertions(+), 51 deletions(-) create mode 100644 chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc index 7fefe4e213e256..229a1eb91dfed6 100644 --- a/chrome/browser/ui/layout_constants.cc +++ b/chrome/browser/ui/layout_constants.cc @@ -11,7 +11,7 @@ int GetLayoutConstant(LayoutConstant constant) { const int kFindBarVerticalOffset[] = {1, 6, 6}; const int kIconLabelViewInternalPadding[] = {3, 2, 2}; - const int kIconLabelViewTrailingPadding[] = {2, 8, 8}; + const int kIconLabelViewTrailingPadding[] = {2, 3, 3}; const int kLocationBarBorderThickness[] = {2, 1, 1}; const int kLocationBarBubbleFontVerticalPadding[] = {1, 2, 4}; const int kLocationBarBubbleHorizontalPadding[] = {1, 4, 4}; diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc index a3b7640cee9233..234c753ad1b193 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc @@ -56,7 +56,9 @@ ContentSettingImageView::ContentSettingImageView( SetBackgroundImageGrid(kBackgroundImages); } - image()->SetHorizontalAlignment(views::ImageView::LEADING); + image()->SetHorizontalAlignment(base::i18n::IsRTL() + ? views::ImageView::TRAILING + : views::ImageView::LEADING); image()->set_interactive(true); image()->EnableCanvasFlippingForRTLUI(true); image()->SetAccessibilityFocusable(true); @@ -94,7 +96,8 @@ void ContentSettingImageView::Update(content::WebContents* web_contents) { // the user. If this becomes a problem, we could design some sort of queueing // mechanism to show one after the other, but it doesn't seem important now. int string_id = content_setting_image_model_->explanatory_string_id(); - if (string_id && !ShouldShowBackground()) { + if (string_id && !label()->visible()) { + ink_drop_delegate_->OnAction(views::InkDropState::HIDDEN); SetLabel(l10n_util::GetStringUTF16(string_id)); label()->SetVisible(true); slide_animator_.Show(); @@ -113,7 +116,8 @@ SkColor ContentSettingImageView::GetBorderColor() const { } bool ContentSettingImageView::ShouldShowBackground() const { - return slide_animator_.is_animating() || pause_animation_; + return (!IsShrinking() || label()->width() > 0) && + (slide_animator_.is_animating() || pause_animation_); } double ContentSettingImageView::WidthMultiplier() const { @@ -132,6 +136,13 @@ double ContentSettingImageView::WidthMultiplier() const { return size_fraction; } +bool ContentSettingImageView::IsShrinking() const { + const double kOpenFraction = + static_cast(kOpenTimeMS) / kAnimationDurationMS; + return (!pause_animation_ && slide_animator_.is_animating() && + slide_animator_.GetCurrentValue() > (1.0 - kOpenFraction)); +} + void ContentSettingImageView::AnimationEnded(const gfx::Animation* animation) { slide_animator_.Reset(); if (!pause_animation_) { @@ -184,10 +195,8 @@ void ContentSettingImageView::OnMouseReleased(const ui::MouseEvent& event) { return; } const bool activated = HitTestPoint(event.location()); - if (!label()->visible()) { - ink_drop_delegate_->OnAction(activated ? views::InkDropState::ACTIVATED - : views::InkDropState::HIDDEN); - } + if (!label()->visible() && !activated) + ink_drop_delegate_->OnAction(views::InkDropState::HIDDEN); if (activated) OnClick(); } @@ -196,17 +205,13 @@ bool ContentSettingImageView::OnKeyPressed(const ui::KeyEvent& event) { if (event.key_code() != ui::VKEY_SPACE && event.key_code() != ui::VKEY_RETURN) return false; - ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); OnClick(); return true; } void ContentSettingImageView::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP) { - if (!label()->visible()) - ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); + if (event->type() == ui::ET_GESTURE_TAP) OnClick(); - } if ((event->type() == ui::ET_GESTURE_TAP) || (event->type() == ui::ET_GESTURE_TAP_DOWN)) event->SetHandled(); @@ -242,7 +247,19 @@ void ContentSettingImageView::OnWidgetVisibilityChanged(views::Widget* widget, void ContentSettingImageView::OnClick() { if (slide_animator_.is_animating()) { - if (!pause_animation_) { + // If the user clicks while we're animating, the bubble arrow will be + // pointing to the image, and if we allow the animation to keep running, the + // image will move away from the arrow (or we'll have to move the bubble, + // which is even worse). So we want to stop the animation. We have two + // choices: jump to the final post-animation state (no label visible), or + // pause the animation where we are and continue running after the bubble + // closes. The former looks more jerky, so we avoid it unless the animation + // hasn't even fully exposed the image yet, in which case pausing with half + // an image visible will look broken. + const int final_width = image()->GetPreferredSize().width() + + GetBubbleOuterPadding(true) + + GetBubbleOuterPadding(false); + if (!pause_animation_ && ShouldShowBackground() && width() > final_width) { pause_animation_ = true; pause_animation_state_ = slide_animator_.GetCurrentValue(); } @@ -264,8 +281,10 @@ void ContentSettingImageView::OnClick() { // bubble doesn't need an arrow. If the user clicks during an animation, // the animation simply pauses and no other visible state change occurs, so // show the arrow in this case. - if (ui::MaterialDesignController::IsModeMaterial() && !pause_animation_) + if (ui::MaterialDesignController::IsModeMaterial() && !pause_animation_) { + ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); bubble_view_->SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); + } bubble_widget->Show(); } } diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h index a6beed464000b9..814c3035e1abbd 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h @@ -65,6 +65,7 @@ class ContentSettingImageView : public IconLabelBubbleView, SkColor GetBorderColor() const override; bool ShouldShowBackground() const override; double WidthMultiplier() const override; + bool IsShrinking() const override; // gfx::AnimationDelegate: void AnimationEnded(const gfx::Animation* animation) override; diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index f51e30a49c0ff2..480e856968adfc 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc @@ -105,6 +105,10 @@ double IconLabelBubbleView::WidthMultiplier() const { return 1.0; } +bool IconLabelBubbleView::IsShrinking() const { + return false; +} + int IconLabelBubbleView::GetImageAndPaddingWidth() const { const int image_width = image_->GetPreferredSize().width(); return image_width @@ -118,20 +122,53 @@ gfx::Size IconLabelBubbleView::GetPreferredSize() const { } void IconLabelBubbleView::Layout() { - // In MD mode, both extension icons and Chrome-provided icons are 16px, - // so it's not necessary to handle them differently. TODO(estade): clean - // this up when MD is on by default. - bool icon_has_enough_padding = + // Compute the label bounds. The label gets whatever size is left over after + // accounting for the preferred image width and padding amounts. Note that if + // the label has zero size it doesn't actually matter what we compute its X + // value to be, since it won't be visible, so the X value can be "wrong" + // compared to where the right edge of the image is computed to be below. + // This means doing this layout doesn't doesn't depend on any of the layout + // below. That layout, however, may need for this layout to have already + // happened, since the value of ShouldShowBackground() we read below may + // depend on whether the label has nonzero size. Therefore, we do this first. + const int label_x = GetBubbleOuterPadding(true) + GetImageAndPaddingWidth(); + const int label_width = + std::max(0, width() - label_x - GetBubbleOuterPadding(false)); + label_->SetBounds(label_x, 0, label_width, height()); + + // Now compute the image bounds. In non-MD, the leading padding depends on + // whether this is an extension icon, since extension icons and + // Chrome-provided icons are different sizes. In MD, these sizes are the + // same, so it's not necessary to handle the two types differently. + const bool icon_has_enough_padding = !is_extension_icon_ || ui::MaterialDesignController::IsModeMaterial(); - const int image_width = image_->GetPreferredSize().width(); - image_->SetBounds(std::min((width() - image_width) / 2, - GetBubbleOuterPadding(icon_has_enough_padding)), - 0, image_->GetPreferredSize().width(), height()); + int image_x = GetBubbleOuterPadding(icon_has_enough_padding); + const int image_preferred_width = image_->GetPreferredSize().width(); + int bubble_trailing_padding = GetBubbleOuterPadding(false); + + // If ShouldShowBackground() is true, then either we show a background in the + // steady state, or we're not yet in the last portion of the animation. In + // these cases, we leave the leading and trailing padding alone; we don't want + // to let the image overlap the edge of the background, as this looks glitchy. + // If this is false, however, then we're only showing the image, and either + // the view width is the image width, or it's animating downwards and getting + // close to it. In these cases, we want to shrink the trailing padding first, + // so the image slides all the way to the trailing edge before slowing or + // stopping; then we want to shrink the leading padding down to zero. + if (!ShouldShowBackground()) { + image_x = std::min(image_x, width() - image_preferred_width); + bubble_trailing_padding = std::min( + bubble_trailing_padding, width() - image_preferred_width - image_x); + } - int pre_label_width = GetBubbleOuterPadding(true) + GetImageAndPaddingWidth(); - label_->SetBounds(pre_label_width, 0, - width() - pre_label_width - GetBubbleOuterPadding(false), - height()); + // Now that we've computed the padding values, give the image all the + // remaining width. This will be less than the image's preferred width during + // the first portion of the animation; during the very beginning there may not + // be enough room to show the image at all. + const int image_width = + std::min(image_preferred_width, + std::max(0, width() - image_x - bubble_trailing_padding)); + image_->SetBounds(image_x, 0, image_width, height()); } void IconLabelBubbleView::OnNativeThemeChanged( @@ -177,20 +214,41 @@ SkColor IconLabelBubbleView::GetParentBackgroundColor() const { : parent_background_color_; } -gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int width) const { +gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int label_width) const { gfx::Size size(image_->GetPreferredSize()); - if (ShouldShowBackground()) { - const int non_label_width = GetBubbleOuterPadding(true) + - GetImageAndPaddingWidth() + - GetBubbleOuterPadding(false); - size = gfx::Size(WidthMultiplier() * (width + non_label_width), 0); - if (!ui::MaterialDesignController::IsModeMaterial()) - size.SetToMax(background_painter_->GetMinimumSize()); + bool shrinking = IsShrinking(); + // Animation continues for the last few pixels even after the label is not + // visible in order to slide the icon into its final position. Therefore it + // is necessary to animate |total_width| even when the background is hidden + // as long as the animation is still shrinking. + if (ShouldShowBackground() || shrinking) { + const int image_width = size.width(); + const int padding = GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING) + + GetBubbleOuterPadding(true) + + GetBubbleOuterPadding(false); + // |multiplier| grows from zero to one, stays equal to one and then shrinks + // to zero again. The view width should correspondingly grow from zero to + // fully showing both label and icon, stay there, then shrink to just large + // enough to show the icon. We don't want to shrink all the way back to + // zero, since this would mean the view would completely disappear and then + // pop back to an icon after the animation finishes. + int total_width = WidthMultiplier() * (label_width + image_width + padding); + if (shrinking) + total_width = std::max(total_width, image_width); + size.set_width(total_width); } - return size; } +int IconLabelBubbleView::GetBubbleOuterPadding(bool leading) const { + if (ui::MaterialDesignController::IsModeMaterial()) + return GetBubbleOuterPaddingMd(leading); + + return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - + GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + + (leading ? 0 : GetLayoutConstant(ICON_LABEL_VIEW_TRAILING_PADDING)); +} + void IconLabelBubbleView::SetLabelBackgroundColor( SkColor chip_background_color) { // The background images are painted atop |parent_background_color_|. @@ -205,15 +263,6 @@ void IconLabelBubbleView::SetLabelBackgroundColor( SkColorGetA(chip_background_color))); } -int IconLabelBubbleView::GetBubbleOuterPadding(bool leading) const { - if (ui::MaterialDesignController::IsModeMaterial()) - return GetBubbleOuterPaddingMd(leading); - - return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - - GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + - (leading ? 0 : GetLayoutConstant(ICON_LABEL_VIEW_TRAILING_PADDING)); -} - int IconLabelBubbleView::GetBubbleOuterPaddingMd(bool leading) const { // When the image is empty, leading and trailing padding are equal. if (image_->GetPreferredSize().IsEmpty() || !leading) diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h index f1a58d69658e70..9cefe0feae97a9 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h @@ -54,6 +54,7 @@ class IconLabelBubbleView : public views::InkDropHostView { protected: views::ImageView* image() { return image_; } views::Label* label() { return label_; } + const views::Label* label() const { return label_; } // Gets the color for displaying text. virtual SkColor GetTextColor() const = 0; @@ -70,6 +71,9 @@ class IconLabelBubbleView : public views::InkDropHostView { // full-width view and can be used to animate the width of the view. virtual double WidthMultiplier() const; + // Returns true when animation is in progress and is shrinking. + virtual bool IsShrinking() const; + // Returns the amount of horizontal space needed to draw the image and its // padding before the label. virtual int GetImageAndPaddingWidth() const; @@ -87,18 +91,18 @@ class IconLabelBubbleView : public views::InkDropHostView { SkColor GetParentBackgroundColor() const; - gfx::Size GetSizeForLabelWidth(int width) const; + gfx::Size GetSizeForLabelWidth(int label_width) const; + + // Amount of padding from the edge of the icon / label to the outer edge of + // the bubble view. If |leading| is true, this is the padding at the + // beginning of the bubble (left in LTR), otherwise it's the trailing padding. + int GetBubbleOuterPadding(bool leading) const; private: // Sets a background color on |label_| based on |chip_background_color| and // the parent's bg color. void SetLabelBackgroundColor(SkColor chip_background_color); - // Amount of padding at the edges of the bubble. If |leading| is true, this - // is the padding at the beginning of the bubble (left in LTR), otherwise it's - // the end padding. - int GetBubbleOuterPadding(bool leading) const; - // As above, but for Material Design. TODO(estade): remove/replace the above. int GetBubbleOuterPaddingMd(bool leading) const; diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc new file mode 100644 index 00000000000000..36e1a4ad4d2ce7 --- /dev/null +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc @@ -0,0 +1,217 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h" + +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/test/views_test_base.h" + +namespace { + +const int kStayOpenTimeMS = 100; +const int kOpenTimeMS = 100; +const int kAnimationDurationMS = (kOpenTimeMS * 2) + kStayOpenTimeMS; +const int kImageSize = 15; +const SkColor kTestColor = SkColorSetRGB(64, 64, 64); +const int kNumberOfSteps = 300; + +class TestIconLabelBubbleView : public IconLabelBubbleView { + public: + enum State { + GROWING, + STEADY, + SHRINKING, + }; + + TestIconLabelBubbleView(const gfx::FontList& font_list, SkColor color) + : IconLabelBubbleView(0, font_list, color, false), value_(0) { + GetImageView()->SetImageSize(gfx::Size(kImageSize, kImageSize)); + SetLabel(base::ASCIIToUTF16("Label")); + } + + void SetCurrentAnimationValue(int value) { + value_ = value; + SizeToPreferredSize(); + } + + int width() { return bounds().width(); } + bool IsLabelVisible() const { return label()->visible(); } + void SetLabelVisible(bool visible) { label()->SetVisible(visible); } + const gfx::Rect& GetLabelBounds() const { return label()->bounds(); } + + State state() const { + const double kOpenFraction = + static_cast(kOpenTimeMS) / kAnimationDurationMS; + double state = value_ / (double)kNumberOfSteps; + if (state < kOpenFraction) + return GROWING; + if (state > (1.0 - kOpenFraction)) + return SHRINKING; + return STEADY; + } + + protected: + // IconLabelBubbleView: + SkColor GetTextColor() const override { return kTestColor; } + SkColor GetBorderColor() const override { return kTestColor; } + + bool ShouldShowBackground() const override { + return !IsShrinking() || label()->width() > 0; + } + + double WidthMultiplier() const override { + const double kOpenFraction = + static_cast(kOpenTimeMS) / kAnimationDurationMS; + double fraction = value_ / (double)kNumberOfSteps; + switch (state()) { + case GROWING: + return fraction / kOpenFraction; + case STEADY: + return 1.0; + case SHRINKING: + return (1.0 - fraction) / kOpenFraction; + } + NOTREACHED(); + return 1.0; + } + + bool IsShrinking() const override { return state() == SHRINKING; } + + private: + int value_; + DISALLOW_COPY_AND_ASSIGN(TestIconLabelBubbleView); +}; + +} // namespace + +class IconLabelBubbleViewTest : public views::ViewsTestBase { + public: + IconLabelBubbleViewTest() + : views::ViewsTestBase(), + steady_reached_(false), + shrinking_reached_(false), + minimum_size_reached_(false), + previous_width_(0), + initial_image_x_(0) {} + ~IconLabelBubbleViewTest() override {} + + protected: + // views::ViewsTestBase: + void SetUp() override { + views::ViewsTestBase::SetUp(); + gfx::FontList font_list; + view_.reset(new TestIconLabelBubbleView(font_list, kTestColor)); + } + + void VerifyWithAnimationStep(int step) { + Reset(); + for (int value = 0; value < kNumberOfSteps; value += step) { + SetValue(value); + VerifyAnimationStep(); + } + view_->SetLabelVisible(false); + } + + private: + void Reset() { + view_->SetLabelVisible(true); + SetValue(0); + steady_reached_ = false; + shrinking_reached_ = false; + minimum_size_reached_ = false; + previous_width_ = 0; + initial_image_x_ = GetImageBounds().x(); + EXPECT_NE(0, initial_image_x_); + } + + void VerifyAnimationStep() { + switch (state()) { + case TestIconLabelBubbleView::State::GROWING: { + EXPECT_GE(width(), previous_width_); + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_GE(GetImageBounds().x(), 0); + if (GetImageBounds().width() > 0) + EXPECT_LE(GetImageBounds().right(), width()); + EXPECT_TRUE(IsLabelVisible()); + if (GetLabelBounds().width() > 0) { + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + } + break; + } + case TestIconLabelBubbleView::State::STEADY: { + if (steady_reached_) + EXPECT_EQ(previous_width_, width()); + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_GT(GetImageBounds().x(), 0); + EXPECT_LT(GetImageBounds().right(), width()); + EXPECT_TRUE(IsLabelVisible()); + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + steady_reached_ = true; + break; + } + case TestIconLabelBubbleView::State::SHRINKING: { + if (shrinking_reached_) + EXPECT_LE(width(), previous_width_); + if (minimum_size_reached_) + EXPECT_EQ(previous_width_, width()); + + EXPECT_GE(GetImageBounds().x(), 0); + if (width() <= initial_image_x_ + kImageSize) { + EXPECT_EQ(width(), GetImageBounds().right()); + EXPECT_EQ(0, GetLabelBounds().width()); + } else { + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_LE(GetImageBounds().right(), width()); + } + if (GetLabelBounds().width() > 0) { + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + } + shrinking_reached_ = true; + if (width() == kImageSize) + minimum_size_reached_ = true; + break; + } + } + previous_width_ = width(); + } + + void SetValue(int value) { view_->SetCurrentAnimationValue(value); } + + TestIconLabelBubbleView::State state() const { return view_->state(); } + + int width() { return view_->width(); } + + bool IsLabelVisible() { return view_->IsLabelVisible(); } + + const gfx::Rect& GetLabelBounds() const { return view_->GetLabelBounds(); } + + const gfx::Rect& GetImageBounds() const { + return view_->GetImageView()->bounds(); + } + + scoped_ptr view_; + + bool steady_reached_; + bool shrinking_reached_; + bool minimum_size_reached_; + int previous_width_; + int initial_image_x_; +}; + +// Tests layout rules for IconLabelBubbleView while simulating animation. +// The animation is first growing the bubble from zero, then keeping its size +// constant and finally shrinking it down to its minimum size which is the image +// size. +// Various step sizes during animation simulate different possible timing. +TEST_F(IconLabelBubbleViewTest, AnimateLayout) { + VerifyWithAnimationStep(1); + VerifyWithAnimationStep(5); + VerifyWithAnimationStep(10); + VerifyWithAnimationStep(25); +} diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index cc4e59290405e5..17a87411d0d2cb 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1371,6 +1371,7 @@ 'browser/ui/views/frame/test_with_browser_view.cc', 'browser/ui/views/frame/test_with_browser_view.h', 'browser/ui/views/frame/web_contents_close_handler_unittest.cc', + 'browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc', 'browser/ui/views/omnibox/omnibox_view_views_unittest.cc', 'browser/ui/views/status_icons/status_tray_win_unittest.cc', 'browser/ui/views/sync/bubble_sync_promo_view_unittest.cc',