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

Side by Side 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, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_animation .h"
6
7 #include "base/file_path.h"
8 #include "base/location.h"
9 #import "base/mac/foundation_util.h"
10 #include "base/native_library.h"
11 #include "ui/base/animation/tween.h"
12
13 // The window animations in this file use private APIs as described here:
14 // http://goo.gl/CK43l
15 // There are two important things to keep in mind when modifying this file:
16 // - For most operations the origin of the coordinate system is top left.
17 // - Perspective and shear transformations get clipped if they are bigger
18 // then the window size. This does not seem to apply to scale transformations.
19
20 // Length of the animation in seconds.
21 const NSTimeInterval kSAnimationDuraiton = 0.18;
22
23 // The number of pixels above the final destination to animate from.
24 const CGFloat kShowHideVerticalOffset = 20;
25
26 // Scale the window by this percent when animating.
27 const CGFloat kShowHideScalePercent = 0.99;
28
29 // Size of the perspective effect as a percent of the window width.
30 const CGFloat kShowHidePerspectivePercent = 0.04;
31
32 namespace {
33
34 typedef int CGSWindow;
35 typedef int CGSConnection;
36 typedef struct {
37 float x;
38 float y;
39 } MeshPoint;
40 typedef struct {
41 MeshPoint local;
42 MeshPoint global;
43 } CGPointWarp;
44
45 // These are private APIs that we look up at runtime.
46 typedef CGSConnection (*CGSDefaultConnectionFunc)();
47 typedef CGError (*CGSSetWindowTransformFunc)(
48 const CGSConnection cid,
49 const CGSWindow wid,
50 CGAffineTransform transform);
51 typedef CGError (*CGSSetWindowWarpFunc)(
52 const CGSConnection cid,
53 const CGSWindow wid,
54 int w,
55 int h,
56 CGPointWarp* mesh);
57 typedef CGError (*CGSSetWindowAlphaFunc)(
58 const CGSConnection cid,
59 const CGSWindow wid,
60 float alpha);
61
62 CGSDefaultConnectionFunc g_CGSDefaultConnection;
63 CGSSetWindowTransformFunc g_CGSSetWindowTransform;
64 CGSSetWindowWarpFunc g_CGSSetWindowWarp;
65 CGSSetWindowAlphaFunc g_CGSSetWindowAlpha;
66
67 // Look up private Window APIs. Returns true on success.
68 bool InitializeWindowAPIs() {
69 bool should_initialize = true;
70 if (should_initialize) {
71 should_initialize = false;
72 CFBundleRef bundle =
73 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreGraphics"));
74 if (!bundle)
75 return false;
76
77 NSArray* names = [NSArray arrayWithObjects:
78 @"_CGSDefaultConnection",
79 @"CGSSetWindowTransform",
80 @"CGSSetWindowWarp",
81 @"CGSSetWindowAlpha",
82 nil];
83 void* functions[[names count]];
84 CFBundleGetFunctionPointersForNames(
85 bundle, base::mac::NSToCFCast(names), functions);
86
87 g_CGSDefaultConnection =
88 reinterpret_cast<CGSDefaultConnectionFunc>(functions[0]);
89 g_CGSSetWindowTransform =
90 reinterpret_cast<CGSSetWindowTransformFunc>(functions[1]);
91 g_CGSSetWindowWarp = reinterpret_cast<CGSSetWindowWarpFunc>(functions[2]);
92 g_CGSSetWindowAlpha = reinterpret_cast<CGSSetWindowAlphaFunc>(functions[3]);
93 }
94 return g_CGSDefaultConnection && g_CGSSetWindowTransform &&
95 g_CGSSetWindowWarp && g_CGSSetWindowAlpha;
96 }
97
98 // Get the window location relative to the top left of the main screen.
99 // Most Cocoa APIs use a coordinate system where the screen origin is the
100 // bottom left. The various CGSSetWindow* APIs use a coordinate system where
101 // the screen origin is the top left.
102 NSPoint GetCGSWindowScreenOrigin(NSWindow* window) {
103 NSArray *screens = [NSScreen screens];
104 if ([screens count] == 0)
105 return NSZeroPoint;
106 NSScreen* main_screen = [screens objectAtIndex:0];
107
108 NSRect window_frame = [window frame];
109 NSRect screen_frame = [main_screen frame];
110 return NSMakePoint(NSMinX(window_frame),
111 NSHeight(screen_frame) - NSMaxY(window_frame));
112 }
113
114 // Set the transparency of the window.
115 void SetWindowAlpha(NSWindow* window, float alpha) {
116 CGSConnection cid = g_CGSDefaultConnection();
117 g_CGSSetWindowAlpha(cid, [window windowNumber], alpha);
118 }
119
120 // Scales the window and translates it so that it stays centered relative
121 // to its original position.
122 void SetWindowScale(NSWindow* window, float scale) {
123 CGFloat scale_delta = 1.0 - scale;
124 CGFloat cur_scale = 1.0 + scale_delta;
125 CGAffineTransform transform =
126 CGAffineTransformMakeScale(cur_scale, cur_scale);
127
128 // Translate the window to keep it centered at the original location.
129 NSSize window_size = [window frame].size;
130 CGFloat scale_offset_x = window_size.width * (1 - cur_scale) / 2.0;
131 CGFloat scale_offset_y = window_size.height * (1 - cur_scale) / 2.0;
132
133 NSPoint origin = GetCGSWindowScreenOrigin(window);
134 CGFloat new_x = -origin.x + scale_offset_x;
135 CGFloat new_y = -origin.y + scale_offset_y;
136 transform = CGAffineTransformTranslate(transform, new_x, new_y);
137
138 CGSConnection cid = g_CGSDefaultConnection();
139 g_CGSSetWindowTransform(cid, [window windowNumber], transform);
140 }
141
142 // Unsets any window warp that may have been previously applied.
143 // Window warp prevents other effects such as CGSSetWindowTransform from
144 // being applied.
145 void ClearWindowWarp(NSWindow* window) {
146 CGSConnection cid = g_CGSDefaultConnection();
147 g_CGSSetWindowWarp(cid, [window windowNumber], 0, 0, NULL);
148 }
149
150 // Applies various transformations using a warp effect. The window is
151 // translated vertically by |y_offset|. The window is scaled |by |scale| and
152 // translated so that the it remains centered relative to its original position.
153 // Finally, perspective is effect is applied by shrinking the top of the window.
154 void SetWindowWarp(NSWindow* window,
155 float y_offset,
156 float scale,
157 float perspective_offset) {
158 NSRect win_rect = [window frame];
159 win_rect.origin = NSZeroPoint;
160 NSRect screen_rect = win_rect;
161 screen_rect.origin = GetCGSWindowScreenOrigin(window);
162
163 // Apply a vertical translate.
164 screen_rect.origin.y -= y_offset;
165
166 // Apply a scale and translate to keep the window centered.
167 screen_rect.origin.x += (NSWidth(win_rect) - NSWidth(screen_rect)) / 2.0;
168 screen_rect.origin.y += (NSHeight(win_rect) - NSHeight(screen_rect)) / 2.0;
169
170 // A 2 x 2 mesh that maps each corner of the window to a location in screen
171 // coordinates. Note that the origin of the coordinate system is top, left.
172 CGPointWarp mesh[2][2] = {
173 {
174 { // Top left.
175 {NSMinX(win_rect), NSMinY(win_rect)},
176 {NSMinX(screen_rect) + perspective_offset, NSMinY(screen_rect)},
177 },
178 { // Top right.
179 {NSMaxX(win_rect), NSMinY(win_rect)},
180 {NSMaxX(screen_rect) - perspective_offset, NSMinY(screen_rect)},
181 }
182 },
183 {
184 { // Bottom left.
185 {NSMinX(win_rect), NSMaxY(win_rect)},
186 {NSMinX(screen_rect), NSMaxY(screen_rect)},
187 },
188 { // Bottom right.
189 {NSMaxX(win_rect), NSMaxY(win_rect)},
190 {NSMaxX(screen_rect), NSMaxY(screen_rect)},
191 }
192 },
193 };
194
195 CGSConnection cid = g_CGSDefaultConnection();
196 g_CGSSetWindowWarp(cid, [window windowNumber], 2, 2, &(mesh[0][0]));
197 }
198
199 // Sets the varoius effects that are a part of the Show/Hide animation.
200 // Value is a number between 0 and 1 where 0 means the window is completely
201 // hidden and 1 means the window is fully visible.
202 void UpdateWindowShowHideAnimationState(NSWindow* window, CGFloat value) {
203 CGFloat inverse_value = 1.0 - value;
204
205 SetWindowAlpha(window, value);
206 CGFloat y_offset = kShowHideVerticalOffset * inverse_value;
207 CGFloat scale = 1.0 - (1.0 - kShowHideScalePercent) * inverse_value;
208 CGFloat perspective_offset =
209 ([window frame].size.width * kShowHidePerspectivePercent) * inverse_value;
210
211 SetWindowWarp(window, y_offset, scale, perspective_offset);
212 }
213
214 }
215
216 @interface ConstrainedWindowAnimationBase ()
217 // Subclasses should override these to update the window state for the current
218 // animation value.
219 - (void)setWindowStateForStart;
220 - (void)setWindowStateForValue:(float)value;
221 - (void)setWindowStateForEnd;
222 @end
223
224 @implementation ConstrainedWindowAnimationBase
225
226 - (id)initWithWindow:(NSWindow*)window {
227 if (!InitializeWindowAPIs()) {
228 [self release];
229 return nil;
230 }
231
232 if ((self = [self initWithDuration:kSAnimationDuraiton
233 animationCurve:NSAnimationEaseInOut])) {
234 window_.reset([window retain]);
235 [self setAnimationBlockingMode:NSAnimationNonblocking];
236 [self setWindowStateForStart];
237 }
238 return self;
239 }
240
241 - (void)stopAnimation {
242 [super stopAnimation];
243 [self setWindowStateForEnd];
244 if ([[self delegate] respondsToSelector:@selector(animationDidEnd:)])
245 [[self delegate] animationDidEnd:self];
246 }
247
248 - (void)setCurrentProgress:(NSAnimationProgress)progress {
249 [super setCurrentProgress:progress];
250
251 if (progress >= 1.0) {
252 [self setWindowStateForEnd];
253 return;
254 }
255 [self setWindowStateForValue:[self currentValue]];
256 }
257
258 - (void)setWindowStateForStart {
259 // Subclasses can optionally override this method.
260 }
261
262 - (void)setWindowStateForValue:(float)value {
263 // Subclasses must override this method.
264 NOTREACHED();
265 }
266
267 - (void)setWindowStateForEnd {
268 // Subclasses can optionally override this method.
269 }
270
271 @end
272
273
274 @implementation ConstrainedWindowAnimationShow
275
276 - (void)setWindowStateForStart {
277 SetWindowAlpha(window_, 0.0);
278 }
279
280 - (void)setWindowStateForValue:(float)value {
281 UpdateWindowShowHideAnimationState(window_, value);
282 }
283
284 - (void)setWindowStateForEnd {
285 SetWindowAlpha(window_, 1.0);
286 ClearWindowWarp(window_);
287 }
288
289 @end
290
291 @implementation ConstrainedWindowAnimationHide
292
293 - (void)setWindowStateForValue:(float)value {
294 UpdateWindowShowHideAnimationState(window_, 1.0 - value);
295 }
296
297 - (void)setWindowStateForEnd {
298 SetWindowAlpha(window_, 0.0);
299 ClearWindowWarp(window_);
300 }
301
302 @end
303
304 @implementation ConstrainedWindowAnimationPulse
305
306 // Sets the window scale based on the animation progress.
307 - (void)setWindowStateForValue:(float)value {
308 struct KeyFrame {
309 float value;
310 float scale;
311 };
312 KeyFrame frames[] = {
313 {0.00, 1.0},
314 {0.40, 1.02},
315 {0.60, 1.02},
316 {1.00, 1.0},
317 };
318
319 CGFloat scale = 1;
320 int count = sizeof(frames) / sizeof(*frames);
321 for (int i = count - 1; i >= 0; --i) {
322 if (value >= frames[i].value) {
323 CGFloat delta = frames[i + 1].value - frames[i].value;
324 CGFloat percent = (value - frames[i].value) / delta;
325 scale = ui::Tween::ValueBetween(percent,
326 frames[i].scale,
327 frames[i + 1].scale);
328 break;
329 }
330 }
331
332 SetWindowScale(window_, scale);
333 }
334
335 - (void)setWindowStateForEnd {
336 SetWindowScale(window_, 1.0);
337 }
338
339 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698