[go: up one dir, main page]

[Toolbar UI Mac] Fix location bar animation

Pinning the location bar currently uses [[locationBar_ animator] frame], but
this unfortunately relies on inconsistent (and undocumented) behavior of the
animator proxy to return the proper value after animation. Remove the uses of
this, and ensure that the location bar stops animating if it's at the proper
position.

BUG=457162

Review URL: https://codereview.chromium.org/916993004

Cr-Commit-Position: refs/heads/master@{#316713}
(cherry picked from commit 787f5b8906bd97c79dc935b4aec61c4d3017bd14)

TBR=avi@chromium.org

Review URL: https://codereview.chromium.org/938783002

Cr-Commit-Position: refs/branch-heads/2272@{#327}
Cr-Branched-From: 827a380cfdb31aa54c8d56e63ce2c3fd8c3ba4d4-refs/heads/master@{#310958}
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index 94f25768..57525e9 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -220,10 +220,16 @@
 }
 
 bool ToolbarActionsBarBridge::IsAnimating() const {
-  return false;
+  return [[controller_ containerView] isAnimating];
 }
 
 void ToolbarActionsBarBridge::StopAnimating() {
+  // Unfortunately, animating the browser actions container affects neighboring
+  // views (like the omnibox), which could also be animating. Because of this,
+  // instead of just ending the animation, the cleanest way to terminate is to
+  // "animate" to the current frame.
+  [controller_ resizeContainerToWidth:
+      NSWidth([[controller_ containerView] frame])];
 }
 
 int ToolbarActionsBarBridge::GetChevronWidth() const {
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
index 521ec5e..1786be9 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
@@ -125,6 +125,9 @@
   // Holds current tooltip strings, to keep them from being dealloced.
   base::scoped_nsobject<NSMutableArray> currentToolTips_;
 
+  // Animation object used for resizing the autocomplete field.
+  base::scoped_nsobject<NSViewAnimation> resizeAnimation_;
+
   base::scoped_nsobject<NSString> suggestText_;
   base::scoped_nsobject<NSColor> suggestColor_;
 }
@@ -142,6 +145,13 @@
 // Clears the undo chain for this text field.
 - (void)clearUndoChain;
 
+// Animates the text field to the given |frame|.
+- (void)animateToFrame:(NSRect)frame;
+
+// Stops the current animation, if any. The frame will be set to the current
+// (mid-animation) frame.
+- (void)stopAnimation;
+
 // Updates cursor and tooltip rects depending on the contents of the text field
 // e.g. the security icon should have a default pointer shown on hover instead
 // of an I-beam.
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index bb920d56..6c25cc8 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -14,6 +14,10 @@
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
+namespace {
+const CGFloat kAnimationDuration = 0.2;
+}
+
 @implementation AutocompleteTextField
 
 @synthesize observer = observer_;
@@ -32,6 +36,9 @@
   [[self cell] setTruncatesLastVisibleLine:YES];
   [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
   currentToolTips_.reset([[NSMutableArray alloc] init]);
+  resizeAnimation_.reset([[NSViewAnimation alloc] init]);
+  [resizeAnimation_ setDuration:kAnimationDuration];
+  [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
 }
 
 - (void)flagsChanged:(NSEvent*)theEvent {
@@ -221,6 +228,28 @@
   return undoManager_.get();
 }
 
+- (void)animateToFrame:(NSRect)frame {
+  [self stopAnimation];
+  NSDictionary* animationDictionary = @{
+    NSViewAnimationTargetKey : self,
+    NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]],
+    NSViewAnimationEndFrameKey : [NSValue valueWithRect:frame]
+  };
+  [resizeAnimation_ setViewAnimations:@[ animationDictionary ]];
+  [resizeAnimation_ startAnimation];
+}
+
+- (void)stopAnimation {
+  if ([resizeAnimation_ isAnimating]) {
+    // [NSViewAnimation stopAnimation] results in advancing the animation to
+    // the end. Since this is almost certainly not the behavior we want, reset
+    // the frame to the current frame.
+    NSRect frame = [self frame];
+    [resizeAnimation_ stopAnimation];
+    [self setFrame:frame];
+  }
+}
+
 - (void)clearUndoChain {
   [undoManager_ removeAllActions];
 }
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 0b1b39a..e02a464 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -73,9 +73,6 @@
 // The minimum width of the location bar in pixels.
 const CGFloat kMinimumLocationBarWidth = 100.0;
 
-// The duration of any animation that occurs within the toolbar in seconds.
-const CGFloat kAnimationDuration = 0.2;
-
 // The amount of left padding that the wrench menu should have.
 const CGFloat kWrenchMenuLeftPadding = 3.0;
 
@@ -669,7 +666,7 @@
 }
 
 - (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate {
-  CGFloat locationBarXPos = NSMaxX([[locationBar_ animator] frame]);
+  CGFloat locationBarXPos = NSMaxX([locationBar_ frame]);
   CGFloat leftDistance;
 
   if ([browserActionsContainerView_ isHidden]) {
@@ -681,6 +678,8 @@
   }
   if (leftDistance != 0.0)
     [self adjustLocationSizeBy:leftDistance animate:animate];
+  else
+    [locationBar_ stopAnimation];
 }
 
 - (void)maintainMinimumLocationBarWidth {
@@ -749,18 +748,15 @@
 
 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
   // Ensure that the location bar is in its proper place.
-  NSRect locationFrame = [[locationBar_ animator] frame];
+  NSRect locationFrame = [locationBar_ frame];
   locationFrame.size.width += dX;
 
-  if (!animate) {
-    [locationBar_ setFrame:locationFrame];
-    return;
-  }
+  [locationBar_ stopAnimation];
 
-  [NSAnimationContext beginGrouping];
-  [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
-  [[locationBar_ animator] setFrame:locationFrame];
-  [NSAnimationContext endGrouping];
+  if (animate)
+    [locationBar_ animateToFrame:locationFrame];
+  else
+    [locationBar_ setFrame:locationFrame];
 }
 
 - (NSPoint)bookmarkBubblePoint {