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

Unified Diff: chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.mm

Issue 2152823004: [Material][Mac] Animation for Omnibox Verbose State Chips (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleaning up Created 4 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.mm
diff --git a/chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.mm
new file mode 100644
index 0000000000000000000000000000000000000000..f4e7b4657b608d1ff8a7c2609b3e96b12b2fced4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.mm
@@ -0,0 +1,347 @@
+// Copyright (c) 2011 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.
+
+#import "chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.h"
+
+#import "base/logging.h"
+#import "base/mac/mac_util.h"
+#include "base/strings/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "ui/base/cocoa/nsview_additions.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/cubic_bezier.h"
+#include "ui/gfx/image/image_skia_util_mac.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+#include "ui/gfx/text_elider.h"
+
+namespace {
+
+// Duration of animation.
+const NSTimeInterval kShowInterval = 0.33;
+const NSTimeInterval kRetainInterval = 5;
+const NSTimeInterval kHideInterval = 0.25;
+const NSTimeInterval kAnimationDuration =
+ kShowInterval + kRetainInterval + kHideInterval;
+
+// Interval of the animation timer, 60Hz.
+const NSTimeInterval kAnimationInterval = 1.0 / 60.0;
+
+// Transformation values at the beginning of the animation.
+const CGFloat kStartScale = 0.25;
+const CGFloat kStartXOffset = -15.0;
+
+// Padding between the icon and label.
+CGFloat kIconLabelPadding = 4.0;
+
+// Inset for the background.
+const CGFloat kBackgroundYInset = 4.0;
+
+// The offset of the text's baseline on a retina screen.
+const CGFloat kRetinaBaselineOffset = 0.5;
+
+// Different states in which the animation can be.
+// - kAnimatingIn: The text fades in and expands out.
+// - kAnimationDelay: The text should be displayed in full size.
+// - kAnimatingOut: The text fades out and shrinks.
+// - kAnimationFinished: The text is hidden.
+enum AnimationState {
+ kAnimatingIn,
+ kAnimationDelay,
+ kAnimatingOut,
+ kAnimationFinished,
+};
+
+} // namespace
+
+@interface SecureVerboseAnimation : NSObject {
+ @private
+ SecureVerboseBubbleDecoration* owner_; // Weak, owns this.
+ double progress_; // Counter, [0..1], with aninmation progress.
+ double duration_;
+ NSTimer* timer_; // Animation timer. Owns this, owned by the run loop.
+ AnimationState state_;
+}
+
+// Designated initializer. |owner| must not be nil. Animation timer will start
+// as soon as the object is created.
+- (id)initWithOwner:(SecureVerboseBubbleDecoration*)owner;
+
+// Call when |owner| is going away or the animation needs to be stopped.
+// Ensures that any dangling references are cleared. Can be called multiple
+// times.
+- (void)stopAnimation;
+
+// Returns the current progress of the animation with the curve applied to it.
+// A value in the range of [0, 1].
+- (double)animationProgress;
+
+// Returns the animation interval based on the current state.
+- (double)animationInterval;
+
+// Returns true if the animation is running.
+- (BOOL)isRunning;
+
+// Returns the current state of the animation.
+- (AnimationState)animationState;
+
+@end
+
+@implementation SecureVerboseAnimation
+
+- (id)initWithOwner:(SecureVerboseBubbleDecoration*)owner {
+ self = [super init];
+ if (self) {
+ owner_ = owner;
+ timer_ = [NSTimer scheduledTimerWithTimeInterval:kAnimationInterval
+ target:self
+ selector:@selector(timerFired:)
+ userInfo:nil
+ repeats:YES];
+ state_ = kAnimatingIn;
+ duration_ = 0;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!timer_);
+ [super dealloc];
+}
+
+// Clear weak references and stop the timer.
+- (void)stopAnimation {
+ state_ = kAnimationFinished;
+ [timer_ invalidate];
+ timer_ = nil;
+}
+
+- (double)animationInterval {
+ switch (state_) {
+ case kAnimatingIn:
+ return kShowInterval;
+ case kAnimatingOut:
+ return kHideInterval;
+ case kAnimationDelay:
+ return kRetainInterval;
+ case kAnimationFinished:
+ return 0;
+ }
+}
+
+- (BOOL)isRunning {
+ return timer_ != nil;
+}
+
+- (AnimationState)animationState {
+ return state_;
+}
+
+- (void)timerFired:(NSTimer*)timer {
+ duration_ += kAnimationInterval;
+
+ // Increment animation progress, normalized to [0..1].
+ progress_ += kAnimationInterval / [self animationInterval];
+ progress_ = std::min(progress_, 1.0);
+
+ // Check if the animation state has changed. If it has changed, then
+ // reset the progress back to 0.
+ AnimationState currentState = state_;
+ if (duration_ <= kShowInterval)
+ currentState = kAnimatingIn;
+ else if (duration_ >= kAnimationDuration - kHideInterval)
+ currentState = kAnimatingOut;
+ else
+ currentState = kAnimationDelay;
+
+ if (state_ != currentState) {
+ state_ = currentState;
+ progress_ = 0;
+ }
+
+ // Stop timer if it has reached the end of its life.
+ if (duration_ >= kAnimationDuration)
+ [self stopAnimation];
+
+ owner_->OnAnimationProgressed();
+}
+
+- (double)animationProgress {
+ switch (state_) {
+ case kAnimatingIn:
+ return gfx::Tween::CalculateValue(gfx::Tween::FAST_OUT_SLOW_IN,
+ progress_);
+ case kAnimatingOut:
+ return 1 - gfx::Tween::CalculateValue(gfx::Tween::FAST_OUT_SLOW_IN_EXPO,
+ progress_);
+ case kAnimationDelay:
+ return 1.0;
+ case kAnimationFinished:
+ return 0;
+ }
+}
+
+@end
+
+//////////////////////////////////////////////////////////////////
+// SecureVerboseBubbleDecoration, public:
+
+SecureVerboseBubbleDecoration::SecureVerboseBubbleDecoration(
+ LocationIconDecoration* location_icon,
+ LocationBarViewMac* owner)
+ : EVBubbleDecoration(location_icon),
+ label_color_(gfx::kGoogleGreen700),
+ owner_(owner) {}
+
+SecureVerboseBubbleDecoration::~SecureVerboseBubbleDecoration() {
+ // Just in case the timer is still holding onto the animation object, force
+ // cleanup so it can't get back to |this|.
+ [animation_ stopAnimation];
+}
+
+void SecureVerboseBubbleDecoration::SetLabelColor(SkColor color) {
+ label_color_ = color;
+}
+
+void SecureVerboseBubbleDecoration::OnAnimationProgressed() {
+ owner_->Layout();
+}
+
+void SecureVerboseBubbleDecoration::StartAnimation() {
+ // For testing only
+ if (animation_.get() && [animation_ isRunning])
+ return;
+
+ animation_.reset([[SecureVerboseAnimation alloc] initWithOwner:this]);
+}
+
+//////////////////////////////////////////////////////////////////
+// SecureVerboseBubbleDecoration::LocationBarDecoration:
+
+CGFloat SecureVerboseBubbleDecoration::GetWidthForSpace(CGFloat width) {
+ CGFloat locationIconWidth = location_icon_->GetWidthForSpace(width);
+ CGFloat textWidth =
+ EVBubbleDecoration::GetWidthForSpace(width) - locationIconWidth;
+
+ return (textWidth * GetAnimationProgress()) + locationIconWidth;
+}
+
+void SecureVerboseBubbleDecoration::DrawInFrame(NSRect frame,
+ NSView* control_view) {
+ const NSRect decoration_frame = NSInsetRect(frame, 0.0, kBackgroundYInset);
+ CGFloat textOffset = NSMinX(decoration_frame);
+ if (image_) {
+ CGFloat imageAlpha =
+ animation_.get() && [animation_ animationState] == kAnimatingIn
+ ? GetAnimationProgress()
+ : 1.0;
+
+ // Center the image vertically.
+ const NSSize imageSize = [image_ size];
+ NSRect imageRect = decoration_frame;
+ imageRect.origin.y +=
+ std::floor((NSHeight(decoration_frame) - imageSize.height) / 2.0);
+ imageRect.size = imageSize;
+ [image_ drawInRect:imageRect
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:imageAlpha
+ respectFlipped:YES
+ hints:nil];
+ textOffset = NSMaxX(imageRect) + kIconLabelPadding;
+ }
+
+ // Set the text color and draw the text.
+ if (label_) {
+ bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
+ NSColor* text_color =
+ in_dark_mode ? skia::SkColorToSRGBNSColor(kMaterialDarkModeTextColor)
+ : GetBackgroundBorderColor();
+ SetTextColor(text_color);
+
+ // Transform the coordinate system to adjust the baseline on Retina.
+ // This is the only way to get fractional adjustments.
+ gfx::ScopedNSGraphicsContextSaveGState saveGraphicsState;
+ CGFloat lineWidth = [control_view cr_lineWidth];
+ if (lineWidth < 1) {
+ NSAffineTransform* transform = [NSAffineTransform transform];
+ [transform translateXBy:0 yBy:kRetinaBaselineOffset];
+ [transform concat];
+ }
+
+ base::scoped_nsobject<NSAttributedString> str([[NSAttributedString alloc]
+ initWithString:label_
+ attributes:attributes_]);
+
+ // Calculate the text frame based on the text height and offsets.
+ NSRect textRect = frame;
+ CGFloat textHeight = [str size].height;
+
+ textRect.origin.x = textOffset;
+ textRect.origin.y = roundf(NSMidY(textRect) - textHeight / 2.0) - 1;
+ textRect.size.width = NSMaxX(decoration_frame) - NSMinX(textRect);
+ textRect.size.height = textHeight;
+
+ NSAffineTransform* transform = [NSAffineTransform transform];
+ CGFloat progress = GetAnimationProgress();
+
+ // Apply transformations so that the text animation:
+ // - Scales from 0.75 to 1.
+ // - Translates the X position to its origin after it got scaled, and
+ // before moving in a position from from -15 to 0
+ // - Translates the Y position so that the text is centered vertically.
+ double scale = gfx::Tween::DoubleValueBetween(progress, kStartScale, 1.0);
+
+ double xOriginOffset = NSMinX(textRect) * (1 - scale);
+ double yOriginOffset = NSMinY(textRect) * (1 - scale);
+ double xOffset = gfx::Tween::DoubleValueBetween(progress, kStartXOffset, 0);
+ double yOffset = NSHeight(textRect) * (1 - scale) / 2.0;
+
+ [transform translateXBy:xOffset + xOriginOffset
+ yBy:yOffset + yOriginOffset];
+ [transform scaleBy:scale];
+ [transform concat];
+
+ // Draw the label.
+ [str drawInRect:textRect];
+
+ // Draw the divider.
+ NSBezierPath* line = [NSBezierPath bezierPath];
+ [line setLineWidth:1];
+ [line moveToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
+ NSMinY(decoration_frame))];
+ [line lineToPoint:NSMakePoint(NSMaxX(decoration_frame) - DividerPadding(),
+ NSMaxY(decoration_frame))];
+
+ NSColor* divider_color = GetDividerColor(in_dark_mode);
+ CGFloat divider_alpha =
+ [divider_color alphaComponent] * GetAnimationProgress();
+ divider_color = [divider_color colorWithAlphaComponent:divider_alpha];
+ [divider_color set];
+ [line stroke];
+ }
+}
+
+//////////////////////////////////////////////////////////////////
+// SecureVerboseBubbleDecoration::BubbleDecoration:
+
+NSColor* SecureVerboseBubbleDecoration::GetBackgroundBorderColor() {
+ return skia::SkColorToSRGBNSColor(
+ SkColorSetA(label_color_, 255.0 * GetAnimationProgress()));
+}
+
+//////////////////////////////////////////////////////////////////
+// SecureVerboseBubbleDecoration, private:
+
+CGFloat SecureVerboseBubbleDecoration::GetAnimationProgress() const {
+ return !animation_.get() || ![animation_ isRunning]
+ ? 0.0
+ : [animation_ animationProgress];
+}
« no previous file with comments | « chrome/browser/ui/cocoa/location_bar/secure_verbose_bubble_decoration.h ('k') | chrome/chrome_browser_ui.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698