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

Unified Diff: chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.mm

Issue 10870094: Constrained window sheet controller (test patch) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rename Created 8 years, 4 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/constrained_window/constrained_window_animation.mm
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.mm
new file mode 100644
index 0000000000000000000000000000000000000000..94efee914a04f70cf4085bcd035347411aea074c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.mm
@@ -0,0 +1,339 @@
+// Copyright (c) 2012 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/constrained_window/constrained_window_animation.h"
+
+#include "base/file_path.h"
+#include "base/location.h"
+#import "base/mac/foundation_util.h"
+#include "base/native_library.h"
+#include "ui/base/animation/tween.h"
+
+// The window animations in this file use private APIs as described here:
+// http://goo.gl/CK43l
+// There are two important things to keep in mind when modifying this file:
+// - For most operations the origin of the coordinate system is top left.
+// - Perspective and shear transformations get clipped if they are bigger
+// then the window size. This does not seem to apply to scale transformations.
+
+// Length of the animation in seconds.
+const NSTimeInterval kSAnimationDuraiton = 0.18;
+
+// The number of pixels above the final destination to animate from.
+const CGFloat kShowHideVerticalOffset = 20;
+
+// Scale the window by this percent when animating.
+const CGFloat kShowHideScalePercent = 0.99;
+
+// Size of the perspective effect as a percent of the window width.
+const CGFloat kShowHidePerspectivePercent = 0.04;
+
+namespace {
+
+typedef int CGSWindow;
+typedef int CGSConnection;
+typedef struct {
+ float x;
+ float y;
+} MeshPoint;
+typedef struct {
+ MeshPoint local;
+ MeshPoint global;
+} CGPointWarp;
+
+// These are private APIs that we look up at runtime.
+typedef CGSConnection (*CGSDefaultConnectionFunc)();
+typedef CGError (*CGSSetWindowTransformFunc)(
+ const CGSConnection cid,
+ const CGSWindow wid,
+ CGAffineTransform transform);
+typedef CGError (*CGSSetWindowWarpFunc)(
+ const CGSConnection cid,
+ const CGSWindow wid,
+ int w,
+ int h,
+ CGPointWarp* mesh);
+typedef CGError (*CGSSetWindowAlphaFunc)(
+ const CGSConnection cid,
+ const CGSWindow wid,
+ float alpha);
+
+CGSDefaultConnectionFunc g_CGSDefaultConnection;
+CGSSetWindowTransformFunc g_CGSSetWindowTransform;
+CGSSetWindowWarpFunc g_CGSSetWindowWarp;
+CGSSetWindowAlphaFunc g_CGSSetWindowAlpha;
+
+// Look up private Window APIs. Returns true on success.
+bool InitializeWindowAPIs() {
+ bool should_initialize = true;
+ if (should_initialize) {
+ should_initialize = false;
+ CFBundleRef bundle =
+ CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreGraphics"));
+ if (!bundle)
+ return false;
+
+ NSArray* names = [NSArray arrayWithObjects:
+ @"_CGSDefaultConnection",
+ @"CGSSetWindowTransform",
+ @"CGSSetWindowWarp",
+ @"CGSSetWindowAlpha",
+ nil];
+ void* functions[[names count]];
+ CFBundleGetFunctionPointersForNames(
+ bundle, base::mac::NSToCFCast(names), functions);
+
+ g_CGSDefaultConnection =
+ reinterpret_cast<CGSDefaultConnectionFunc>(functions[0]);
+ g_CGSSetWindowTransform =
+ reinterpret_cast<CGSSetWindowTransformFunc>(functions[1]);
+ g_CGSSetWindowWarp = reinterpret_cast<CGSSetWindowWarpFunc>(functions[2]);
+ g_CGSSetWindowAlpha = reinterpret_cast<CGSSetWindowAlphaFunc>(functions[3]);
+ }
+ return g_CGSDefaultConnection && g_CGSSetWindowTransform &&
+ g_CGSSetWindowWarp && g_CGSSetWindowAlpha;
+}
+
+// Get the window location relative to the top left of the main screen.
+// Most Cocoa APIs use a coordinate system where the screen origin is the
+// bottom left. The various CGSSetWindow* APIs use a coordinate system where
+// the screen origin is the top left.
+NSPoint GetCGSWindowScreenOrigin(NSWindow* window) {
+ NSArray *screens = [NSScreen screens];
+ if ([screens count] == 0)
+ return NSZeroPoint;
+ NSScreen* main_screen = [screens objectAtIndex:0];
+
+ NSRect window_frame = [window frame];
+ NSRect screen_frame = [main_screen frame];
+ return NSMakePoint(NSMinX(window_frame),
+ NSHeight(screen_frame) - NSMaxY(window_frame));
+}
+
+// Set the transparency of the window.
+void SetWindowAlpha(NSWindow* window, float alpha) {
+ CGSConnection cid = g_CGSDefaultConnection();
+ g_CGSSetWindowAlpha(cid, [window windowNumber], alpha);
+}
+
+// Scales the window and translates it so that it stays centered relative
+// to its original position.
+void SetWindowScale(NSWindow* window, float scale) {
+ CGFloat scale_delta = 1.0 - scale;
+ CGFloat cur_scale = 1.0 + scale_delta;
+ CGAffineTransform transform =
+ CGAffineTransformMakeScale(cur_scale, cur_scale);
+
+ // Translate the window to keep it centered at the original location.
+ NSSize window_size = [window frame].size;
+ CGFloat scale_offset_x = window_size.width * (1 - cur_scale) / 2.0;
+ CGFloat scale_offset_y = window_size.height * (1 - cur_scale) / 2.0;
+
+ NSPoint origin = GetCGSWindowScreenOrigin(window);
+ CGFloat new_x = -origin.x + scale_offset_x;
+ CGFloat new_y = -origin.y + scale_offset_y;
+ transform = CGAffineTransformTranslate(transform, new_x, new_y);
+
+ CGSConnection cid = g_CGSDefaultConnection();
+ g_CGSSetWindowTransform(cid, [window windowNumber], transform);
+}
+
+// Unsets any window warp that may have been previously applied.
+// Window warp prevents other effects such as CGSSetWindowTransform from
+// being applied.
+void ClearWindowWarp(NSWindow* window) {
+ CGSConnection cid = g_CGSDefaultConnection();
+ g_CGSSetWindowWarp(cid, [window windowNumber], 0, 0, NULL);
+}
+
+// Applies various transformations using a warp effect. The window is
+// translated vertically by |y_offset|. The window is scaled |by |scale| and
+// translated so that the it remains centered relative to its original position.
+// Finally, perspective is effect is applied by shrinking the top of the window.
+void SetWindowWarp(NSWindow* window,
+ float y_offset,
+ float scale,
+ float perspective_offset) {
+ NSRect win_rect = [window frame];
+ win_rect.origin = NSZeroPoint;
+ NSRect screen_rect = win_rect;
+ screen_rect.origin = GetCGSWindowScreenOrigin(window);
+
+ // Apply a vertical translate.
+ screen_rect.origin.y -= y_offset;
+
+ // Apply a scale and translate to keep the window centered.
+ screen_rect.origin.x += (NSWidth(win_rect) - NSWidth(screen_rect)) / 2.0;
+ screen_rect.origin.y += (NSHeight(win_rect) - NSHeight(screen_rect)) / 2.0;
+
+ // A 2 x 2 mesh that maps each corner of the window to a location in screen
+ // coordinates. Note that the origin of the coordinate system is top, left.
+ CGPointWarp mesh[2][2] = {
+ {
+ { // Top left.
+ {NSMinX(win_rect), NSMinY(win_rect)},
+ {NSMinX(screen_rect) + perspective_offset, NSMinY(screen_rect)},
+ },
+ { // Top right.
+ {NSMaxX(win_rect), NSMinY(win_rect)},
+ {NSMaxX(screen_rect) - perspective_offset, NSMinY(screen_rect)},
+ }
+ },
+ {
+ { // Bottom left.
+ {NSMinX(win_rect), NSMaxY(win_rect)},
+ {NSMinX(screen_rect), NSMaxY(screen_rect)},
+ },
+ { // Bottom right.
+ {NSMaxX(win_rect), NSMaxY(win_rect)},
+ {NSMaxX(screen_rect), NSMaxY(screen_rect)},
+ }
+ },
+ };
+
+ CGSConnection cid = g_CGSDefaultConnection();
+ g_CGSSetWindowWarp(cid, [window windowNumber], 2, 2, &(mesh[0][0]));
+}
+
+// Sets the varoius effects that are a part of the Show/Hide animation.
+// Value is a number between 0 and 1 where 0 means the window is completely
+// hidden and 1 means the window is fully visible.
+void UpdateWindowShowHideAnimationState(NSWindow* window, CGFloat value) {
+ CGFloat inverse_value = 1.0 - value;
+
+ SetWindowAlpha(window, value);
+ CGFloat y_offset = kShowHideVerticalOffset * inverse_value;
+ CGFloat scale = 1.0 - (1.0 - kShowHideScalePercent) * inverse_value;
+ CGFloat perspective_offset =
+ ([window frame].size.width * kShowHidePerspectivePercent) * inverse_value;
+
+ SetWindowWarp(window, y_offset, scale, perspective_offset);
+}
+
+}
+
+@interface ConstrainedWindowAnimationBase ()
+// Subclasses should override these to update the window state for the current
+// animation value.
+- (void)setWindowStateForStart;
+- (void)setWindowStateForValue:(float)value;
+- (void)setWindowStateForEnd;
+@end
+
+@implementation ConstrainedWindowAnimationBase
+
+- (id)initWithWindow:(NSWindow*)window {
+ if (!InitializeWindowAPIs()) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [self initWithDuration:kSAnimationDuraiton
+ animationCurve:NSAnimationEaseInOut])) {
+ window_.reset([window retain]);
+ [self setAnimationBlockingMode:NSAnimationNonblocking];
+ [self setWindowStateForStart];
+ }
+ return self;
+}
+
+- (void)stopAnimation {
+ [super stopAnimation];
+ [self setWindowStateForEnd];
+ if ([[self delegate] respondsToSelector:@selector(animationDidEnd:)])
+ [[self delegate] animationDidEnd:self];
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ [super setCurrentProgress:progress];
+
+ if (progress >= 1.0) {
+ [self setWindowStateForEnd];
+ return;
+ }
+ [self setWindowStateForValue:[self currentValue]];
+}
+
+- (void)setWindowStateForStart {
+ // Subclasses can optionally override this method.
+}
+
+- (void)setWindowStateForValue:(float)value {
+ // Subclasses must override this method.
+ NOTREACHED();
+}
+
+- (void)setWindowStateForEnd {
+ // Subclasses can optionally override this method.
+}
+
+@end
+
+
+@implementation ConstrainedWindowAnimationShow
+
+- (void)setWindowStateForStart {
+ SetWindowAlpha(window_, 0.0);
+}
+
+- (void)setWindowStateForValue:(float)value {
+ UpdateWindowShowHideAnimationState(window_, value);
+}
+
+- (void)setWindowStateForEnd {
+ SetWindowAlpha(window_, 1.0);
+ ClearWindowWarp(window_);
+}
+
+@end
+
+@implementation ConstrainedWindowAnimationHide
+
+- (void)setWindowStateForValue:(float)value {
+ UpdateWindowShowHideAnimationState(window_, 1.0 - value);
+}
+
+- (void)setWindowStateForEnd {
+ SetWindowAlpha(window_, 0.0);
+ ClearWindowWarp(window_);
+}
+
+@end
+
+@implementation ConstrainedWindowAnimationPulse
+
+// Sets the window scale based on the animation progress.
+- (void)setWindowStateForValue:(float)value {
+ struct KeyFrame {
+ float value;
+ float scale;
+ };
+ KeyFrame frames[] = {
+ {0.00, 1.0},
+ {0.40, 1.02},
+ {0.60, 1.02},
+ {1.00, 1.0},
+ };
+
+ CGFloat scale = 1;
+ int count = sizeof(frames) / sizeof(*frames);
+ for (int i = count - 1; i >= 0; --i) {
+ if (value >= frames[i].value) {
+ CGFloat delta = frames[i + 1].value - frames[i].value;
+ CGFloat percent = (value - frames[i].value) / delta;
+ scale = ui::Tween::ValueBetween(percent,
+ frames[i].scale,
+ frames[i + 1].scale);
+ break;
+ }
+ }
+
+ SetWindowScale(window_, scale);
+}
+
+- (void)setWindowStateForEnd {
+ SetWindowScale(window_, 1.0);
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698