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

Side by Side Diff: chrome/browser/cocoa/tabpose_window.mm

Issue 2976008: Bar (Closed)
Patch Set: rebase Created 10 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2010 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/cocoa/tabpose_window.h"
6
7 #import <QuartzCore/QuartzCore.h>
8
9 #include "base/mac_util.h"
10 #include "base/scoped_cftyperef.h"
11 #include "base/task.h"
12 #include "chrome/browser/browser_process.h"
13 #import "chrome/browser/cocoa/browser_window_controller.h"
14 #import "chrome/browser/cocoa/fast_resize_view.h"
15 #import "chrome/browser/cocoa/tab_strip_controller.h"
16 #include "chrome/browser/renderer_host/backing_store_mac.h"
17 #include "chrome/browser/renderer_host/render_widget_host_view.h"
18 #include "chrome/browser/renderer_host/render_view_host.h"
19 #include "chrome/browser/tab_contents/tab_contents.h"
20 #include "chrome/browser/tab_contents/thumbnail_generator.h"
21 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
22
23 // FIXME: Need to listen for tab creation / destruction and react to that
24 // FIXME: would be nice if at least the selected tab would be "live" (i.e.
25 // videos play etc)
26
27 // FIXME (related?): crashes if invoked while stuff is still loading
28
29 const float S = 1.03;
30
31 // CAGradientLayer is 10.6-only -- roll our own
32 @interface GradientLayer : CALayer
33 - (void)drawInContext:(CGContextRef)context;
34 @end
35
36 @implementation GradientLayer
37 - (void)drawInContext:(CGContextRef)context {
38 scoped_cftyperef<CGColorSpaceRef> grayColorspace(
39 CGColorSpaceCreateWithName(kCGColorSpaceGenericGray));
40 NSLog(@"count: %d", CGColorSpaceGetNumberOfComponents(grayColorspace));
41 CGFloat grays[] = { 0.1, 0.39 };
42 CGFloat locations[] = { 0, 1 };
43 scoped_cftyperef<CGGradientRef> gradient(CGGradientCreateWithColorComponents(
44 grayColorspace, grays, locations, arraysize(grays)));
45
46 CGPoint midY = CGPointMake(0.0, 15);
47 CGContextDrawLinearGradient(context, gradient, midY, CGPointZero, 0);
48 }
49 @end
50
51
52 // A CALayer that draws a CGLayerRef (or a CGBitmap).
53 @interface BackingStoreLayer : CALayer {
54 BackingStoreMac* backing_store_;
55 }
56 - (id)initWithBackingStore:(BackingStoreMac*)store;
57 - (void)drawInContext:(CGContextRef)context;
58 @end
59
60 @implementation BackingStoreLayer
61 - (id)initWithBackingStore:(BackingStoreMac*)store {
62 CHECK(store);
63 if ((self = [super init])) {
64 backing_store_ = store;
65 }
66 return self;
67 }
68
69 - (void)drawInContext:(CGContextRef)context {
70 // Hrm, looks like I need to use the drawing delegate functionality of
71 // a layer here
72 if (backing_store_->cg_layer()) {
73 // TODO: add clipping to dirtyRect if it improves drawing performance.
74 CGContextDrawLayerInRect(context, [self bounds],
75 backing_store_->cg_layer());
76 } else {
77 NSLog(@"no layer!");
78 // if we haven't created a layer yet, draw the cached bitmap into
79 // the window. The CGLayer will be created the next time the renderer
80 // paints.
81 scoped_cftyperef<CGImageRef> image(
82 CGBitmapContextCreateImage(backing_store_->cg_bitmap()));
83 CGContextDrawImage(context, [self bounds], image);
84 }
85 }
86 @end
87
88 // FIXME comment
89 class TabposeCallback {
90 public:
91 TabposeCallback(CALayer* layer)
92 : layer_(layer) {}
93
94 void DidReceiveBitmap(const SkBitmap& bitmap) {
95 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
96 NSLog(@"receiving bitmap %d %d", bitmap.width(), bitmap.height());
97 // FIXME: too many conversions
98 scoped_cftyperef<CGImageRef> cgimage(SkCreateCGImageRef(bitmap));
99 layer_.contents = (id)cgimage.get();
100 layer_.backgroundColor = nil; // clear out bg color to default value
101 }
102 private:
103 CALayer* layer_;
104 };
105
106 // FIXME: look at DISABLE_RUNNABLE_METHOD_REFCOUNT
107 // FIXME: look at URLFetcher's inner class for thread switching
108
109 // FIMXE comment is wrong
110 // A helper class used to interface with chrome's c++ code. Used to dispatch
111 // stuff to threads; to listen for things; etc.
112 class TabposeHelper : public base::RefCountedThreadSafe<TabposeHelper> {
113 public:
114 TabposeHelper(TabposeWindow* window)
115 : window_(window)/*, factory_(this)*/ {}
116
117 void LoadThumbnail(RenderWidgetHost* rwh, CALayer* layer2, const gfx::Size& s) ;
118 private:
119 friend class base::RefCountedThreadSafe<TabposeHelper>;
120 ~TabposeHelper() {}
121 void LoadThumbnailIO(RenderWidgetHost* rwh, CALayer* layer2, const gfx::Size& s, const gfx::Size& fullSize);
122
123 TabposeWindow* window_;
124 // ScopedRunnableMethodFactory<TabposeHelper> factory_;
125 };
126
127 void TabposeHelper::LoadThumbnail(RenderWidgetHost* rwh, CALayer* layer2, const gfx::Size& s) {
128 // rwh->set_painting_observer(NULL); // FIXME
129
130 NSSize nsFullSize = [[window_->browser_ tabContentArea] frame].size;
131 gfx::Size fullSize(NSSizeToCGSize(nsFullSize));
132
133 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
134 // FIXME: is the hop to the IO thread really necessary?
135 ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
136 NewRunnableMethod(this, &TabposeHelper::LoadThumbnailIO, rwh, layer2, s, f ullSize));
137 }
138
139 void TabposeHelper::LoadThumbnailIO(RenderWidgetHost* rwh, CALayer* layer2, cons t gfx::Size& s, const gfx::Size& fullSize) {
140 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
141 ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
142
143 // FIXME: Internally, this allocs memory for both transport dib and then
144 // an SkBitmap (which _then_ needs to be converted to a CGImageRef).
145 // Reduce the amount of copying; possibly by sidestepping
146 // ThumbnailGenerator.
147 TabposeCallback* callback = new TabposeCallback(layer2);
148 window_->callbacks_.push_back(callback); // takes ownership
149
150 // |fullSize| is slightly larger (view bounds doesn't include scroll bars?)
151 // gfx::Size page_size(rwh->view()->GetViewBounds().size()); // Logical size t he renderer renders at
152 gfx::Size page_size(fullSize); // Logical size the renderer renders at
153
154 // This is a bit tricky: We really only need a bitmap at size |s|, but when
155 // the user clicks a thumbnail and it zooms large, this single thumbnail
156 // should have a pixel size close to the view bounds, so that the image doesnt
157 // get blurry. One possible idea would be to get all thumbs at size |s| and
158 // request the one currently below the mouse at full size, but then it might
159 // not be ready when the click happens. For now, KISS, and request everything
160 // at the full resolution.
161 // gfx::Size desired_size(s); // physical pixel size the image is rendered at
162 gfx::Size desired_size(page_size); // physical pixel size the image is render ed at
163 NSLog(@"scheduling snapshot request");
164
165 // FIXME: check that observer is currently NULL
166 // FIXME: this lets us receive straggling requests from an old tabpose window. leads to crashes.
167 rwh->set_painting_observer(generator);
168 generator->AskForSnapshot(rwh, /*prefer_backing_store=*/false,
169 NewCallback(callback, &TabposeCallback::DidReceiveBi tmap),
170 page_size, desired_size);
171 // FIXME: needs to be cancelled somehow if we die before renderer returns
172 }
173
174 @interface TabposeWindow (Private)
175 - (void)fadeAway:(BOOL)slomo;
176 @end
177
178 TabposeWindow* g_tabposeWindow = nil; // FIXME: not global, but on window (?)
179
180 @implementation TabposeWindow
181
182 - (id)initFor:(BrowserWindowController*)browserController slomo:(BOOL)slomo {
183 NSWindow* parent = [browserController window];
184 NSRect frame = [parent frame];
185 if ((self = [super initWithContentRect:frame
186 styleMask:NSBorderlessWindowMask
187 backing:NSBackingStoreBuffered
188 defer:NO])) {
189 // NSImage* img = [NSImage imageNamed:@"contents1"];
190
191 helper_ = new TabposeHelper(self);
192
193 state_ = kFadingIn;
194
195 browser_ = browserController;
196 [self setReleasedWhenClosed:YES];
197 [self setOpaque:NO];
198 [self setBackgroundColor:[NSColor clearColor]];
199 [parent addChildWindow:self ordered:NSWindowAbove];
200 [self makeKeyAndOrderFront:self];
201
202 CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
203 // CGFloat valuesG[4] = {0.15, 0.15, 0.15, 1}; // pdf bg
204 CGFloat valuesG[4] = {0.39, 0.39, 0.39, 1}; // cole mock
205 CGColorRef gray = CGColorCreate(rgbColorspace, valuesG);
206
207 // CGFloat valuesB[4] = {0.0, 0.0, 1.0, 0.7};
208 // CGColorRef blue = CGColorCreate(rgbColorspace, valuesB);
209 CGColorSpaceRelease(rgbColorspace);
210
211 NSView* contentArea = [browser_ tabContentArea] ; // FIXME
212 NSRect areaFrame = [contentArea frame];
213
214 rootLayer_ = [CALayer layer];
215 [[self contentView] setLayer:rootLayer_];
216 [[self contentView] setWantsLayer:YES];
217
218 bgLayer_ = [CALayer layer];
219 bgLayer_.backgroundColor = gray;
220 #if 0
221 bgLayer_.frame = CGRectMake(0, 0, NSWidth(frame), NSHeight(frame));
222 #else
223 bgLayer_.frame = NSRectToCGRect([contentArea frame]);
224 #endif
225 bgLayer_.masksToBounds = YES;
226 [rootLayer_ addSublayer:bgLayer_];
227
228 // Add top gradient
229 CALayer* gradientLayer = [GradientLayer layer];
230 gradientLayer.frame = CGRectMake(0, bgLayer_.frame.size.height - 15, bgLayer _.frame.size.width, 15);
231 [gradientLayer setNeedsDisplay]; // draw once
232 [bgLayer_ addSublayer:gradientLayer];
233
234
235 // Configure hand cursor
236 NSTrackingArea* trackingArea = [[NSTrackingArea alloc]
237 initWithRect:[[self contentView] frame]
238 options:NSTrackingCursorUpdate|NSTrackingActiveInKeyWindow
239 owner:self
240 userInfo:nil];
241 [[self contentView] addTrackingArea:[trackingArea autorelease]];
242
243 [self disableCursorRects];
244 if (NSPointInRect([NSEvent mouseLocation], [self frame]))
245 [[NSCursor pointingHandCursor] set];
246
247 // Needs to be called after -disableCursorRects.
248 [self setAcceptsMouseMovedEvents:YES];
249
250
251 // set up perspective
252 CATransform3D t = CATransform3DIdentity;
253 t.m34 = 1.0 / 1850;
254 bgLayer_.sublayerTransform = t;
255
256 #if 0
257 // Animate in.
258 // FIXME: probably want to use a CABasicAnimation instead
259 CATransition* animation = [CATransition animation];
260 //animation.type = kCATransitionPush;
261 //animation.type = kCATransitionMoveIn;
262 //animation.type = kCATransitionFade;
263 animation.type = kCATransitionReveal;
264 //animation.subtype = kCATransitionFromTop;
265 //animation.delegate = self;
266 animation.duration = 1.f * (slomo ? 4 : 1); // half for in, half for out
267 //[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMe diaTimingFunctionEaseInEaseOut]];
268 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMedi aTimingFunctionEaseOut]];
269 [bgLayer_ addAnimation:animation forKey:nil];
270 #endif
271
272 // Count tabs.
273 // Browser* browser = browserController->browser_.get();
274 TabStripController* tabStripController = browserController->tabStripControll er_.get();
275 TabStripModel* tabStripModel = tabStripController->tabStripModel_;
276 NSArray* arrays = tabStripController->tabArray_.get();
277 NSSet* closing = tabStripController->closingControllers_.get();
278
279 selectedLayer_ = nil;
280 initiallySelectedIndex_ = selectedIndex_ = tabStripModel->selected_index();
281
282
283 int n = [arrays count] - [closing count];
284
285 // We want to have the small rects have the same aspect ratio a as a full
286 // tab. Let w, h be the size of a small rect, and w_c, h_c the size of the
287 // container. dx, dy are the distances between small rects in x, y direction .
288
289 // Geometry yields:
290 // w_c = nx * (w + dx) - dx <=> w = (w_c + d_x) / nx - d_x
291 // h_c = ny * (h + dy) - dy <=> h = (h_c + d_y) / ny - d_t
292 // Plugging this into
293 // a := tab_width / tab_height = w / h
294 // yields
295 // a = ((w_c - (nx - 1)*d_x)*ny) / (nx*(h_c - (ny - 1)*d_y))
296 // Plugging in nx = n/ny and pen and paper (or wolfram alpha:
297 // http://www.wolframalpha.com/input/?i=(-sqrt((d+n-a+f+n)^2-4+(a+f%2Ba+h)+( -d+n-n+w))%2Ba+f+n-d+n)/(2+a+(f%2Bh)) , (solution for nx)
298 // http://www.wolframalpha.com/input/?i=+(-sqrt((a+f+n-d+n)^2-4+(d%2Bw)+(-a+ f+n-a+h+n))-a+f+n%2Bd+n)/(2+(d%2Bw)) , (solution for ny)
299 // ) gives us nx and ny (but the wrong root -- s/-sqrt(FOO)/sqrt(FOO)/.
300
301 int row = 0, col = 0, i = 0;
302
303 CGFloat a = NSWidth([contentArea frame]) / NSHeight([contentArea frame]);
304
305 // FIXME: need to audit everything to check where i want rects with and with out bookmarks bar
306 // (right now, detached bookmark bar screws this up a bit)
307 int kOffsetTop = 30 + NSHeight([[browser_ window] frame]) - NSHeight([[brows er_ tabContentArea] frame]);
308 // if (browser_->bookmarkBarController_.get()->visualState_ == bookmarks::kDe tachedState) // FIXME: check for NULL?
309 // kOffsetTop -= NSHeight([[browser_->bookmarkBarController_ view] frame]);
310 int kOffsetLeft = 30;
311 int kOffsetRight = 30;
312 int kOffsetBottom = 30;
313 int kPaddingX = 15;
314 int kPaddingY = 10;
315
316 int extraOffsetX = 0;
317 int extraOffsetY = 0;
318 double w_c = NSWidth(frame) - kOffsetLeft - kOffsetRight;
319 double h_c = NSHeight(frame) - kOffsetTop - kOffsetBottom;
320 dx = kPaddingX;
321 dy = kPaddingY;
322 double fny = (sqrt(pow(n*(a*dy - dx), 2) + 4*n*a*(dx + w_c)*(dy + h_c)) - n* (a*dy - dx)) / (2*(dx + w_c));
323 ny = int(roundf(fny));
324 nx = int(ceilf(n / float(ny)));
325 last_nx = n - nx * (ny - 1);
326 w = floor((w_c + dx)/float(nx) - dx);
327 h = floor((h_c + dy)/float(ny) - dy);
328 if (a > w/float(h)) {
329 h = w / a;
330 extraOffsetY = (h_c - ((h + dy)*ny - dy))/2;
331 } else {
332 w = h * a;
333 extraOffsetX = (w_c - ((w + dx)*nx - dx))/2;
334 }
335
336 NSMutableArray* allLayers = [[NSMutableArray alloc] initWithCapacity:n];
337 allLayers_.reset(allLayers);
338 // for (TabController* tab in arrays) {
339 for (int ci = 0; ci < n; ++ci) {
340 #if 0
341 if ([closing containsObject:tab])
342 continue;
343
344 NSView* tabView = [tab view];
345
346 CALayer* layer = [CALayer layer];
347 layer.backgroundColor = blue;
348 layer.frame = NSRectToCGRect([[self contentView] convertRect:[tabView boun ds] fromView:tabView]);
349 #endif
350 #if 0
351 // Get tab image. FIXME: on bg thread?
352 #if 0
353 // XXX: Doesn't work?!
354 NSBitmapImageRep* imageRep =
355 [tabView bitmapImageRepForCachingDisplayInRect:[tabView bounds]];
356 if ([imageRep bitmapData])
357 bzero([imageRep bitmapData],
358 [imageRep bytesPerRow] * [imageRep pixelsHigh]);
359 [tabView cacheDisplayInRect:[tabView bounds] toBitmapImageRep:imageRep];
360 CGImageRef image = CGImageCreateCopy([imageRep CGImage]);
361 layer.contents = (id)image;
362 #elif 0
363 [tabView lockFocus];
364 NSBitmapImageRep* imageRep =
365 [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[tabView bounds]] a utorelease];
366 [tabView unlockFocus];
367 CGImageRef image = CGImageCreateCopy([imageRep CGImage]);
368 layer.contents = (id)image;
369 #else
370 NSImage* nsi = [NSImage imageNamed:@"NSUserGroup"];
371 layer.contents = nsi;
372 #endif
373 // CFRelease(image);
374 // layer.contents = imageRep;
375
376 // NSImage *image = [[[NSImage alloc] initWithSize:[imageRep size]] autorel ease];
377 // [image addRepresentation:imageRep];
378 // layer.contents = image;
379 #endif
380
381 // [rootLayer addSublayer:layer];
382
383 CALayer* layer2;
384 // FIXME: on bg thread; also call the other method; ; also do
385 // CGLayer->CGImage conversion directly without going through skia, etc.
386 TabContents* contents = tabStripModel->GetTabContentsAt(i);
387 DCHECK(contents);
388 RenderViewHost* rvh = contents->render_view_host();
389 RenderWidgetHost* rwh = rvh;
390 DCHECK(rwh);
391
392 BackingStoreMac* backing_store = (BackingStoreMac*)rwh->GetBackingStore(fa lse);
393 if (backing_store) {
394 layer2 = [[[BackingStoreLayer alloc] initWithBackingStore:backing_store] autorelease];
395 [layer2 setNeedsDisplay];
396 } else {
397 layer2 = [CALayer layer];
398 // Set placeholder
399 #if 0
400 // Icon as placeholder (FIXME: load only once)
401 int m = MIN(w, h);
402 // Can't use nsimage_cache::ImageNamed(), because that uses
403 // initWithContentsOfFile, which creates a cached representation at
404 // 16x16 and then throws away the vector data.
405 NSString* path = [mac_util::MainAppBundle() pathForImageResource:@"nav.p df"];
406 NSPDFImageRep* pdfRep = [NSPDFImageRep imageRepWithContentsOfFile:path];
407 NSImage* pdfImage = [[[NSImage alloc] initWithSize:NSMakeSize(m, m)] aut orelease];
408 [pdfImage addRepresentation:pdfRep];
409 // FIXME: if we don't leak this, the image rep frees its cgimage soon
410 // and the CALayer crashes when it wants to draw.
411 NSBitmapImageRep* bitmap = [[NSBitmapImageRep imageRepWithData:[pdfImage TIFFRepresentation]] retain]; // XXX
412 layer2.contents = (id)[bitmap CGImage];
413 #else
414 // background color as placeholder
415 layer2.backgroundColor = CGColorGetConstantColor(kCGColorWhite);
416 #endif
417 helper_->LoadThumbnail(rwh, layer2, gfx::Size(w, h));
418 }
419 layer2.contentsGravity = kCAGravityResizeAspect; // for placeholder
420
421 // layer2.backgroundColor = blue;
422 int x = kOffsetLeft + col*(w + kPaddingX) + extraOffsetX;
423 if (row == ny - 1) {
424 // last row
425 x += (nx - last_nx) * (w + kPaddingX) / 2;
426 }
427 int y = kOffsetTop + row*(h + kPaddingY) + extraOffsetY;
428 layer2.anchorPoint = CGPointMake(0.5, 0.5);
429
430 // NSBitmapImageRep* rep = (NSBitmapImageRep*)[img bestRepresentationForDev ice:nil];
431 // layer2.contents = (id)[rep CGImage];
432 // layer2.contentsGravity = kCAGravityResizeAspect;
433
434 // layer2.shadowOpacity = 0.5; // FIXME: Slows things down, even if disabl ed before animation runs
435 layer2.shadowRadius = 10;
436 layer2.shadowOffset = CGSizeMake(0, -10);
437 // layer2.borderColor = blue;
438
439
440 if (i == selectedIndex_) {
441 // http://developer.apple.com/mac/library/qa/qa2008/qa1620.html
442 // Prepare the animation from the old size to the new size
443 CGRect oldBounds = NSRectToCGRect([contentArea frame]);
444 CGRect newBounds = oldBounds;
445 newBounds.size = CGSizeMake(w, h);
446 CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"b ounds"];
447 animation.fromValue = [NSValue valueWithRect:NSRectFromCGRect(oldBounds) ];
448 animation.toValue = [NSValue valueWithRect:NSRectFromCGRect(newBounds)];
449 animation.duration = .25f * (slomo ? 4 : 1);
450 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMe diaTimingFunctionEaseOut];
451
452 // Update the layer's bounds so the layer doesn't snap back when the ani mation completes.
453 layer2.bounds = newBounds;
454
455 // Add the animation, overriding the implicit animation.
456 [layer2 addAnimation:animation forKey:@"bounds"];
457
458 // Prepare the animation from the current position to the new position
459 NSPoint t = areaFrame.origin;
460
461 CGPoint opoint = CGPointMake(t.x + NSWidth(areaFrame)/2, t.y + NSHeight( areaFrame)/2);
462 CGPoint point = CGPointMake(x + w/2, NSHeight(frame) - y - h + h/2);
463 animation = [CABasicAnimation animationWithKeyPath:@"position"];
464 animation.fromValue = [NSValue valueWithPoint:NSPointFromCGPoint(opoint) ];
465 animation.toValue = [NSValue valueWithPoint:NSPointFromCGPoint(point)];
466 animation.duration = .25f * (slomo ? 4 : 1);
467 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMe diaTimingFunctionEaseOut];
468
469 // Update the layer's position so that the layer doesn't snap back when the animation completes.
470 layer2.position = point;
471
472 // Add the animation, overriding the implicit animation.
473 [layer2 addAnimation:animation forKey:@"position"];
474
475 [rootLayer_ insertSublayer:layer2 above:bgLayer_];
476 selectedLayer_ = layer2;
477
478 // selectedLayer_.borderWidth = 5;
479 // [selectedLayer_ setValue:[NSNumber numberWithFloat:S] forKey:@"transfo rm.scale"];
480 [CATransaction begin];
481 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActio ns];
482 selectedLayer_.transform = CATransform3DMakeScale(S, S, 1);
483 [CATransaction commit];
484 } else {
485 #if 0
486 CABasicAnimation* zoom = [CABasicAnimation animationWithKeyPath:@"transfo rm.translation.z"];
487 [layer2 setValue:[NSNumber numberWithFloat:0] forKey:@"transform.translat ion.z"];
488 zoom.fromValue = [NSNumber numberWithFloat:1000];
489 zoom.toValue = [NSNumber numberWithFloat:0];
490 zoom.duration = .25f * (slomo ? 4 : 1);
491 zoom.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTim ingFunctionLinear];
492 [layer2 addAnimation:zoom forKey:@"transform"];
493 #else
494 int sel_col = selectedIndex_ % nx;
495 int sel_row = selectedIndex_ / nx;
496 CGFloat r = NSWidth([contentArea frame]) / float(w);
497 int ox = (NSWidth([contentArea frame]) + dx*r) * (col - sel_col);
498 if (row == ny - 1) {
499 // last row
500 ox += (nx - last_nx) * (NSWidth([contentArea frame]) + dx*r) / 2;
501 }
502 if (sel_row == ny - 1) {
503 // last row
504 ox -= (nx - last_nx) * (NSWidth([contentArea frame]) + dx*r) / 2;
505 }
506 int oy = (NSHeight([contentArea frame]) + dy*r) * (row - sel_row);
507
508 CGRect oldBounds = NSRectToCGRect([contentArea frame]);
509 CGRect newBounds = oldBounds;
510 newBounds.size = CGSizeMake(w, h);
511 CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"bo unds"];
512 animation.fromValue = [NSValue valueWithRect:NSRectFromCGRect(oldBounds)] ;
513 animation.toValue = [NSValue valueWithRect:NSRectFromCGRect(newBounds)];
514 animation.duration = .25f * (slomo ? 4 : 1);
515 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMed iaTimingFunctionEaseOut];
516
517 // Update the layer's bounds so the layer doesn't snap back when the anim ation completes.
518 layer2.bounds = newBounds;
519
520 // Add the animation, overriding the implicit animation.
521 [layer2 addAnimation:animation forKey:@"bounds"];
522
523 // Prepare the animation from the current position to the new position
524 NSPoint t = [contentArea frame].origin;
525 CGPoint opoint = CGPointMake(ox + t.x + NSWidth(areaFrame)/2, /*NSHeight( frame) - h*/- oy + t.y + NSHeight(areaFrame)/2);
526
527 CGPoint point = CGPointMake(x + w/2, NSHeight(frame) - y - h + h/2);
528 animation = [CABasicAnimation animationWithKeyPath:@"position"];
529 animation.fromValue = [NSValue valueWithPoint:NSPointFromCGPoint(opoint)] ;
530 animation.toValue = [NSValue valueWithPoint:NSPointFromCGPoint(point)];
531 animation.duration = .25f * (slomo ? 4 : 1);
532 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMed iaTimingFunctionEaseOut];
533
534 // Update the layer's position so that the layer doesn't snap back when t he animation completes.
535 layer2.position = point;
536
537 // Add the animation, overriding the implicit animation.
538 [layer2 addAnimation:animation forKey:@"position"];
539 #endif
540
541 [bgLayer_ addSublayer:layer2];
542 }
543 [allLayers addObject:layer2];
544
545
546 ++col;
547 if (col == nx) {
548 col = 0;
549 ++row;
550 }
551 ++i;
552 }
553 }
554 return self;
555 }
556
557 - (BOOL)canBecomeKeyWindow {
558 return YES;
559 }
560
561 - (void)mouseMoved:(NSEvent*)event {
562 int i = 0;
563 CALayer* newSelectedLayer = nil;
564 int newIndex = -1;
565 CGPoint p = NSPointToCGPoint([event locationInWindow]);
566 for (CALayer* layer in allLayers_.get()) {
567 CGPoint lp = [layer convertPoint:p fromLayer:rootLayer_];
568 if ([layer containsPoint:lp]) {
569 newSelectedLayer = layer;
570 newIndex = i;
571 }
572 ++i;
573 }
574
575 if (newSelectedLayer && newSelectedLayer != selectedLayer_) {
576 CALayer* oldSelectedLayer = selectedLayer_;
577
578 [CATransaction begin];
579 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActio ns];
580 if (selectedLayer_)
581 [bgLayer_ addSublayer:selectedLayer_];
582 selectedLayer_ = newSelectedLayer;
583 [selectedLayer_ removeFromSuperlayer];
584 [rootLayer_ insertSublayer:selectedLayer_ above:bgLayer_];
585 selectedIndex_ = newIndex;
586 [CATransaction commit];
587
588 if (oldSelectedLayer)
589 oldSelectedLayer.transform = CATransform3DIdentity;
590 if (newSelectedLayer)
591 newSelectedLayer.transform = CATransform3DMakeScale(S, S, 1);
592 }
593 }
594
595 // FIXME: do this on long hover, too
596 - (void)mouseDown:(NSEvent*)event {
597 [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
598 }
599
600 - (void)keyDown:(NSEvent*)event {
601 }
602
603 - (void)keyUp:(NSEvent*)event {
604 if (state_ == kFadingOut)
605 return;
606
607 NSString* characters = [event characters];
608 unichar character = [characters characterAtIndex:0]; // FIXME: check len
609 switch (character) {
610 case NSEnterCharacter:
611 case NSNewlineCharacter:
612 case NSCarriageReturnCharacter:
613 case ' ':
614 [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
615 break;
616 case '\e': // Escape
617 selectedIndex_ = initiallySelectedIndex_;
618 selectedLayer_ = [allLayers_ objectAtIndex:selectedIndex_];
619 [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
620 break;
621 }
622 }
623
624 - (void)cursorUpdate:(NSEvent*)event {
625 [[NSCursor pointingHandCursor] set];
626 }
627
628 - (void)fadeAway:(BOOL)slomo {
629 if (state_ == kFadingOut)
630 return;
631
632 [[NSCursor arrowCursor] set];
633
634 state_ = kFadingOut;
635 [self setAcceptsMouseMovedEvents:NO];
636
637 // Clean out observers, so that eventual pending thumbnail requests don't
638 // resolve against dead objects.
639 TabStripController* tabStripController = browser_->tabStripController_.get();
640 TabStripModel* tabStripModel = tabStripController->tabStripModel_;
641 for (int i = 0; i < tabStripModel->count(); ++i) {
642 TabContents* contents = tabStripModel->GetTabContentsAt(i);
643 contents->render_view_host()->set_painting_observer(NULL);
644 }
645
646 // Select chosen tab (FIXME: don't on ESC)
647 if (selectedIndex_ >= 0)
648 tabStripModel->SelectTabContentsAt(selectedIndex_, /*user_gesture=*/true);
649
650 #if 1
651 // FIXME: this is only here so that we get a notification after 4 / 1 seconds.
652 // Do that in a simpler way.
653 CABasicAnimation* fade = [CABasicAnimation animationWithKeyPath:@"opacity"];
654 bgLayer_.opacity = 0.99; // make it stick, change model value
655 fade.fromValue = [NSNumber numberWithFloat:1];
656 fade.toValue = [NSNumber numberWithFloat:0.99];
657 fade.duration = .5f * (slomo ? 4 : 1);
658 fade.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFu nctionEaseOut];
659 fade.delegate = self;
660 #endif
661
662 if (selectedIndex_ >= 0) {
663 CALayer* layer = selectedLayer_; //[[bgLayer_ sublayers] objectAtIndex:selec tedIndex_];
664
665 [CATransaction begin];
666 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActio ns];
667 // layer.contentsGravity = kCAGravityResize;
668 // layer.opaque = YES;
669 // layer.compositingFilter = [CIFilter filterWithName:@"CISourceInCompositing "];
670 selectedLayer_.borderWidth = 0;
671
672 // Animating large shadows is slow -- don't.
673 layer.shadowOpacity = 0;
674 layer.transform = CATransform3DIdentity;
675
676 [layer removeFromSuperlayer];
677 // [rootLayer_ insertSublayer:layer above:bgLayer_];
678 [bgLayer_ addSublayer:layer]; // move on top of all other layers
679
680 [CATransaction commit];
681
682
683
684 [CATransaction begin];
685 if (slomo) {
686 CGFloat f = [[CATransaction valueForKey:kCATransactionAnimationDuration] f loatValue];
687 f = 0.5; // the above returns 0 :-P
688 [CATransaction setValue:[NSNumber numberWithFloat:4*f] forKey:kCATransacti onAnimationDuration];
689 }
690 layer.frame = NSRectToCGRect([[browser_ tabContentArea] frame]);
691 if ([layer isKindOfClass:[BackingStoreLayer class]])
692 [layer setNeedsDisplay]; // Redraw layer at big resolution, so that zoom- in isn't blocky.
693 // layer.opacity = 0;
694 [CATransaction commit];
695 }
696
697 int i = 0, col = 0, row = 0;
698 for (CALayer* layer in allLayers_.get()) {
699 // DCHECK_NE(layer, selectedLayer_);
700 // if (layer == selectedLayer_) continue;
701 if (i == selectedIndex_) {
702 ++i;
703 ++col;
704 if (col == nx) {
705 col = 0;
706 ++row;
707 }
708 continue;
709 }
710
711 // Animating large shadows is slow -- don't.
712 [CATransaction begin];
713 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActio ns];
714 layer.shadowOpacity = 0;
715 [CATransaction commit];
716
717 #if 0
718 CABasicAnimation* zoom = [CABasicAnimation animationWithKeyPath:@"transform. translation.z"];
719 // [layer setValue:[NSNumber numberWithFloat:1000] forKey:@"transform.transla tion.z"];
720 zoom.fromValue = [NSNumber numberWithFloat:0];
721 zoom.toValue = [NSNumber numberWithFloat:-1000]; // negative Z to keep them behind the selected layer
722 zoom.duration = .5f * (slomo ? 4 : 1);
723 zoom.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTiming FunctionLinear];
724 [layer addAnimation:zoom forKey:@"transform"];
725 #else
726 int sel_col = selectedIndex_ % nx;
727 int sel_row = selectedIndex_ / nx;
728 NSLog(@"%d %d %d %d %d", col, row, sel_col, sel_row, selectedIndex_);
729 CGFloat r = NSWidth([[browser_ tabContentArea] frame]) / float(w);
730 int ox = (NSWidth([[browser_ tabContentArea] frame]) + dx*r) * (col - sel_c ol);
731 if (row == ny - 1) {
732 // last row
733 ox += (nx - last_nx) * (NSWidth([[browser_ tabContentArea] frame]) + dx*r ) / 2;
734 }
735 if (sel_row == ny - 1) {
736 // last row
737 ox -= (nx - last_nx) * (NSWidth([[browser_ tabContentArea] frame]) + dx*r ) / 2;
738 }
739 int oy = (NSHeight([[browser_ tabContentArea] frame]) + dy*r) * (row - sel_ row);
740
741 CGRect newFrame = NSRectToCGRect([[browser_ tabContentArea] frame]);
742 newFrame.origin.x += ox;
743 newFrame.origin.y -= oy;
744
745 [CATransaction begin];
746 if (slomo) {
747 CGFloat f = 0.5;
748 [CATransaction setValue:[NSNumber numberWithFloat:4*f] forKey:kCATransact ionAnimationDuration];
749 }
750 layer.frame = newFrame;
751 [CATransaction commit];
752
753 ++col;
754 if (col == nx) {
755 col = 0;
756 ++row;
757 }
758 #endif
759 ++i;
760 }
761
762 [bgLayer_ addAnimation:fade forKey:@"opacity"]; // override any implicit anim ation
763 }
764
765 - (void)swipeWithEvent:(NSEvent*)event {
766 if ([event deltaY] > 0.5)
767 [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
768 }
769
770 - (BOOL)windowShouldClose:(id)window {
771 [self fadeAway:NO];
772 return NO;
773 }
774
775 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag {
776 [self close];
777 }
778
779 - (void)close {
780 [[self parentWindow] removeChildWindow:g_tabposeWindow];
781 g_tabposeWindow = nil;
782 [super close];
783 }
784
785 + (void)openTabposeFor:(BrowserWindowController*)browser slomo:(BOOL)slomo{
786 if (g_tabposeWindow)
787 return;
788
789 g_tabposeWindow = [[TabposeWindow alloc] initFor:browser slomo:slomo];
790 }
791
792 + (void)closeTabpose {
793 [g_tabposeWindow close];
794 }
795
796 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/tabpose_window.h ('k') | chrome/browser/renderer_host/render_widget_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698