| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/tabpose_window.h" | 5 #import "chrome/browser/cocoa/tabpose_window.h" |
| 6 | 6 |
| 7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
| 8 | 8 |
| 9 #include "app/resource_bundle.h" | 9 #include "app/resource_bundle.h" |
| 10 #include "base/mac_util.h" | 10 #include "base/mac_util.h" |
| 11 #include "base/scoped_callback_factory.h" |
| 11 #include "base/sys_string_conversions.h" | 12 #include "base/sys_string_conversions.h" |
| 13 #include "chrome/browser/browser_process.h" |
| 12 #import "chrome/browser/cocoa/browser_window_controller.h" | 14 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 13 #import "chrome/browser/cocoa/tab_strip_controller.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_view_host.h" |
| 14 #include "chrome/browser/tab_contents/tab_contents.h" | 18 #include "chrome/browser/tab_contents/tab_contents.h" |
| 19 #include "chrome/browser/tab_contents/thumbnail_generator.h" |
| 15 #include "grit/app_resources.h" | 20 #include "grit/app_resources.h" |
| 16 #include "skia/ext/skia_utils_mac.h" | 21 #include "skia/ext/skia_utils_mac.h" |
| 22 #include "third_party/skia/include/utils/mac/SkCGUtils.h" |
| 17 | 23 |
| 18 const int kTopGradientHeight = 15; | 24 const int kTopGradientHeight = 15; |
| 19 | 25 |
| 20 NSString* const kAnimationIdKey = @"AnimationId"; | 26 NSString* const kAnimationIdKey = @"AnimationId"; |
| 21 NSString* const kAnimationIdFadeIn = @"FadeIn"; | 27 NSString* const kAnimationIdFadeIn = @"FadeIn"; |
| 22 NSString* const kAnimationIdFadeOut = @"FadeOut"; | 28 NSString* const kAnimationIdFadeOut = @"FadeOut"; |
| 23 | 29 |
| 24 const CGFloat kDefaultAnimationDuration = 0.25; // In seconds. | 30 const CGFloat kDefaultAnimationDuration = 0.25; // In seconds. |
| 25 const CGFloat kSlomoFactor = 4; | 31 const CGFloat kSlomoFactor = 4; |
| 26 | 32 |
| 27 // CAGradientLayer is 10.6-only -- roll our own. | 33 // CAGradientLayer is 10.6-only -- roll our own. |
| 28 @interface DarkGradientLayer : CALayer | 34 @interface DarkGradientLayer : CALayer |
| 29 - (void)drawInContext:(CGContextRef)context; | 35 - (void)drawInContext:(CGContextRef)context; |
| 30 @end | 36 @end |
| 31 | 37 |
| 32 @implementation DarkGradientLayer | 38 @implementation DarkGradientLayer |
| 33 - (void)drawInContext:(CGContextRef)context { | 39 - (void)drawInContext:(CGContextRef)context { |
| 34 scoped_cftyperef<CGColorSpaceRef> grayColorSpace( | 40 scoped_cftyperef<CGColorSpaceRef> grayColorSpace( |
| 35 CGColorSpaceCreateWithName(kCGColorSpaceGenericGray)); | 41 CGColorSpaceCreateWithName(kCGColorSpaceGenericGray)); |
| 36 CGFloat grays[] = { 0.277, 1.0, 0.39, 1.0 }; | 42 CGFloat grays[] = { 0.277, 1.0, 0.39, 1.0 }; |
| 37 CGFloat locations[] = { 0, 1 }; | 43 CGFloat locations[] = { 0, 1 }; |
| 38 scoped_cftyperef<CGGradientRef> gradient(CGGradientCreateWithColorComponents( | 44 scoped_cftyperef<CGGradientRef> gradient(CGGradientCreateWithColorComponents( |
| 39 grayColorSpace.get(), grays, locations, arraysize(locations))); | 45 grayColorSpace.get(), grays, locations, arraysize(locations))); |
| 40 CGPoint topLeft = CGPointMake(0.0, kTopGradientHeight); | 46 CGPoint topLeft = CGPointMake(0.0, kTopGradientHeight); |
| 41 CGContextDrawLinearGradient(context, gradient.get(), topLeft, CGPointZero, 0); | 47 CGContextDrawLinearGradient(context, gradient.get(), topLeft, CGPointZero, 0); |
| 42 } | 48 } |
| 43 @end | 49 @end |
| 44 | 50 |
| 51 // FIXME: this needs to be cleaned up a lot |
| 52 |
| 53 // FIXME: look at URLFetcher's inner class for thread switching |
| 54 |
| 55 // FIMXE comment is wrong |
| 56 // A helper class used to interface with chrome's c++ code. Used to dispatch |
| 57 // stuff to threads; to listen for things; etc. |
| 58 class TabposeHelper : public base::RefCountedThreadSafe<TabposeHelper> { |
| 59 public: |
| 60 TabposeHelper(/*TabposeWindow* window*/NSSize fullS) |
| 61 : nsFullSize(fullS) /*window_(window)*//*, factory_(this)*/ , layer_(nil),
factory_(this) {} |
| 62 |
| 63 void LoadThumbnail(RenderWidgetHost* rwh, CALayer* layer2, const gfx::Size& s)
; |
| 64 private: |
| 65 friend class base::RefCountedThreadSafe<TabposeHelper>; |
| 66 ~TabposeHelper() {} |
| 67 |
| 68 void DidReceiveBitmap(const SkBitmap& bitmap) { |
| 69 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 70 NSLog(@"receiving bitmap %d %d", bitmap.width(), bitmap.height()); |
| 71 // FIXME: too many conversions (SkCreateCGImageRef() actually shares memory, |
| 72 // so it's not too bad) |
| 73 cgimage.reset(SkCreateCGImageRef(bitmap)); |
| 74 layer_.contents = (id)cgimage.get(); |
| 75 } |
| 76 |
| 77 scoped_cftyperef<CGImageRef> cgimage; |
| 78 NSSize nsFullSize; |
| 79 CALayer* layer_; |
| 80 base::ScopedCallbackFactory<TabposeHelper> factory_; |
| 81 }; |
| 82 |
| 83 void TabposeHelper::LoadThumbnail(RenderWidgetHost* rwh, CALayer* layer2, const |
| 84 gfx::Size& s) { |
| 85 gfx::Size fullSize(NSSizeToCGSize(nsFullSize)); |
| 86 |
| 87 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 88 |
| 89 // Don't need to go on IO thread, as this just sends an IPC anyway |
| 90 // (and ScopedCallbackFactory isn't threadsafe :-P) |
| 91 ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator(); |
| 92 |
| 93 // FIXME: Internally, this allocs memory for both transport dib and then |
| 94 // an SkBitmap (which _then_ needs to be converted to a CGImageRef). |
| 95 // Reduce the amount of copying; possibly by sidestepping |
| 96 // ThumbnailGenerator. |
| 97 CHECK(!layer_); |
| 98 layer_ = layer2; |
| 99 |
| 100 // |fullSize| is slightly larger (view bounds doesn't include scroll bars?) |
| 101 gfx::Size page_size(fullSize); // Logical size the renderer renders at |
| 102 |
| 103 // This is a bit tricky: We really only need a bitmap at size |s|, but when |
| 104 // the user clicks a thumbnail and it zooms large, this single thumbnail |
| 105 // should have a pixel size close to the view bounds, so that the image doesnt |
| 106 // get blurry. One possible idea would be to get all thumbs at size |s| and |
| 107 // request the one currently below the mouse at full size, but then it might |
| 108 // not be ready when the click happens. For now, KISS, and request everything |
| 109 // at the full resolution. |
| 110 // FIXME: even better plan: call model->selectTab before starting the bg anima
tion. |
| 111 // that makes sure the target tab has a backing store. then call setNeedsDispl
ay on the |
| 112 // layer, and it'll be redrawn from the backing store -- and all bg thumbs can
stay small. |
| 113 // yay! (is this true?) => no :-/, it takes too long for the backing store to
load. |
| 114 //gfx::Size desired_size(s); // physical pixel size the image is rendered at |
| 115 gfx::Size desired_size(fullSize); // physical pixel size the image is rendere
d at |
| 116 NSLog(@"scheduling snapshot request"); |
| 117 |
| 118 // FIXME: check that observer is currently NULL |
| 119 // FIXME: set observer back to NULL at some point |
| 120 rwh->set_painting_observer(generator); |
| 121 generator->AskForSnapshot(rwh, /*prefer_backing_store=*/false, |
| 122 factory_.NewCallback(&TabposeHelper::DidReceiveBitma
p), |
| 123 page_size, desired_size); |
| 124 } |
| 125 |
| 126 |
| 127 |
| 128 // A CALayer that draws a CGLayerRef (or a CGBitmap). |
| 129 @interface BackingStoreLayer : CALayer { |
| 130 TabContents* contents_; // should really have a tabpose::Tile*? |
| 131 NSSize smallSize; |
| 132 NSSize fullSize; |
| 133 scoped_refptr<TabposeHelper> helper_; |
| 134 BOOL didSendLoad_; |
| 135 } |
| 136 - (id)initWithTabContents:(TabContents*)contents smallSize:(NSSize)s fullSize:(N
SSize)s2; |
| 137 - (void)drawInContext:(CGContextRef)context; |
| 138 @end |
| 139 |
| 140 @implementation BackingStoreLayer |
| 141 - (id)initWithTabContents:(TabContents*)contents smallSize:(NSSize)s fullSize:(N
SSize)s2 { |
| 142 CHECK(contents); |
| 143 if ((self = [super init])) { |
| 144 contents_ = contents; |
| 145 smallSize = s; |
| 146 fullSize = s2; |
| 147 } |
| 148 return self; |
| 149 } |
| 150 |
| 151 - (void)drawInContext:(CGContextRef)context { |
| 152 RenderWidgetHost* rwh = contents_->render_view_host(); |
| 153 BackingStoreMac* backing_store_ = (BackingStoreMac*)rwh->GetBackingStore(false
); |
| 154 if (!backing_store_) { |
| 155 // Either the tab was never visible, or its backing store got evicted. |
| 156 |
| 157 NSLog(@"drawing layer without backingstore %d %@", didSendLoad_, self.contents); |
| 158 // do this only if we haven't already sent a thumbnail request before |
| 159 // else this is done on hide and way too much in general |
| 160 if (!didSendLoad_) { |
| 161 helper_ = new TabposeHelper(NSSizeFromCGSize(NSSizeToCGSize(fullSize))); |
| 162 helper_->LoadThumbnail(rwh, self, gfx::Size(NSSizeToCGSize(smallSize))); |
| 163 didSendLoad_ = YES; |
| 164 |
| 165 // Overwrites |contents|, so do this only once, to fill with bg color. |
| 166 [super drawInContext:context]; |
| 167 } |
| 168 |
| 169 if ([self contents]) { |
| 170 CGContextDrawImage(context, [self bounds], (CGImageRef)[self contents]); |
| 171 } |
| 172 |
| 173 return; |
| 174 } |
| 175 |
| 176 // TODO(thakis): re-send PaintAt ipc when tabstripmodelobserver informs us |
| 177 // that a tab has changed (reload favicon & title, too) |
| 178 |
| 179 // TODO(thakis): backing store might have wrong size (?) |
| 180 |
| 181 // TODO(thakis): composited tabs might not be rendered correctly by this |
| 182 // (once this is in BWC, let it add a sublayer for all IOSurfaces) |
| 183 |
| 184 // TODO(thakis): Draw only into rect not occupied by info bars, detached |
| 185 // bookmarks bar, devtool |
| 186 if (backing_store_->cg_layer()) { |
| 187 CGContextDrawLayerInRect(context, [self bounds], |
| 188 backing_store_->cg_layer()); |
| 189 } else { |
| 190 NSLog(@"no layer!"); |
| 191 scoped_cftyperef<CGImageRef> image( |
| 192 CGBitmapContextCreateImage(backing_store_->cg_bitmap())); |
| 193 CGContextDrawImage(context, [self bounds], image); |
| 194 } |
| 195 } |
| 196 @end |
| 197 |
| 198 |
| 199 |
| 45 namespace { | 200 namespace { |
| 46 | 201 |
| 47 class ScopedCAActionDisabler { | 202 class ScopedCAActionDisabler { |
| 48 public: | 203 public: |
| 49 ScopedCAActionDisabler() { | 204 ScopedCAActionDisabler() { |
| 50 [CATransaction begin]; | 205 [CATransaction begin]; |
| 51 [CATransaction setValue:[NSNumber numberWithBool:YES] | 206 [CATransaction setValue:[NSNumber numberWithBool:YES] |
| 52 forKey:kCATransactionDisableActions]; | 207 forKey:kCATransactionDisableActions]; |
| 53 } | 208 } |
| 54 | 209 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 // 2. loads that font | 281 // 2. loads that font |
| 127 // 3. calls |set_font_metrics()| which updates the title rect | 282 // 3. calls |set_font_metrics()| which updates the title rect |
| 128 // 4. receives the title rect and puts the title on it with the font from 2. | 283 // 4. receives the title rect and puts the title on it with the font from 2. |
| 129 void set_font_metrics(CGFloat ascender, CGFloat descender); | 284 void set_font_metrics(CGFloat ascender, CGFloat descender); |
| 130 CGFloat title_font_size() const { return title_font_size_; } | 285 CGFloat title_font_size() const { return title_font_size_; } |
| 131 | 286 |
| 132 NSRect title_rect() const { return title_rect_; } | 287 NSRect title_rect() const { return title_rect_; } |
| 133 | 288 |
| 134 // Returns an unelided title. The view logic is responsible for eliding. | 289 // Returns an unelided title. The view logic is responsible for eliding. |
| 135 const string16& title() const { return contents_->GetTitle(); } | 290 const string16& title() const { return contents_->GetTitle(); } |
| 291 |
| 292 TabContents* tab_contents() const { return contents_; } |
| 136 private: | 293 private: |
| 137 friend class TileSet; | 294 friend class TileSet; |
| 138 | 295 |
| 139 // The thumb rect includes infobars, detached thumbnail bar, web contents, | 296 // The thumb rect includes infobars, detached thumbnail bar, web contents, |
| 140 // and devtools. | 297 // and devtools. |
| 141 NSRect thumb_rect_; | 298 NSRect thumb_rect_; |
| 142 NSRect start_thumb_rect_; | 299 NSRect start_thumb_rect_; |
| 143 | 300 |
| 144 NSRect favicon_rect_; | 301 NSRect favicon_rect_; |
| 145 | 302 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 176 // Move favicon down. | 333 // Move favicon down. |
| 177 favicon_rect_.origin.y = title_rect_.origin.y + descender; | 334 favicon_rect_.origin.y = title_rect_.origin.y + descender; |
| 178 } else { | 335 } else { |
| 179 // Move title down. | 336 // Move title down. |
| 180 title_rect_.origin.y = favicon_rect_.origin.y - descender; | 337 title_rect_.origin.y = favicon_rect_.origin.y - descender; |
| 181 } | 338 } |
| 182 } | 339 } |
| 183 | 340 |
| 184 // A tileset is responsible for owning and laying out all |Tile|s shown in a | 341 // A tileset is responsible for owning and laying out all |Tile|s shown in a |
| 185 // tabpose window. | 342 // tabpose window. |
| 186 class TileSet { | 343 class TileSet : public TabStripModelObserver { |
| 187 public: | 344 public: |
| 345 virtual ~TileSet() { source_model_->RemoveObserver(this); } // FIXME: crashes
if Build() wasn't called. |
| 188 // Fills in |tiles_|. | 346 // Fills in |tiles_|. |
| 189 void Build(TabStripModel* source_model); | 347 void Build(TabStripModel* source_model); |
| 190 | 348 |
| 191 // Computes coordinates for |tiles_|. | 349 // Computes coordinates for |tiles_|. |
| 192 void Layout(NSRect containing_rect); | 350 void Layout(NSRect containing_rect); |
| 193 | 351 |
| 194 int selected_index() const { return selected_index_; } | 352 int selected_index() const { return selected_index_; } |
| 195 void set_selected_index(int index); | 353 void set_selected_index(int index); |
| 196 void ResetSelectedIndex() { selected_index_ = initial_index_; } | 354 void ResetSelectedIndex() { selected_index_ = initial_index_; } |
| 197 | 355 |
| 198 const Tile& selected_tile() const { return *tiles_[selected_index()]; } | 356 const Tile& selected_tile() const { return *tiles_[selected_index()]; } |
| 199 Tile& tile_at(int index) { return *tiles_[index]; } | 357 Tile& tile_at(int index) { return *tiles_[index]; } |
| 200 const Tile& tile_at(int index) const { return *tiles_[index]; } | 358 const Tile& tile_at(int index) const { return *tiles_[index]; } |
| 201 | 359 |
| 360 // TabStripModelObserver |
| 361 virtual void TabInsertedAt(TabContents* contents, |
| 362 int index, |
| 363 bool foreground) { CHECK(false); } |
| 364 virtual void TabClosingAt(TabContents* contents, int index) { CHECK(false); } |
| 365 virtual void TabDetachedAt(TabContents* contents, int index) { CHECK(false); } |
| 366 virtual void TabMoved(TabContents* contents, |
| 367 int from_index, |
| 368 int to_index) { CHECK(false); } |
| 369 virtual void TabStripModelDeleted() { CHECK(false); } |
| 370 virtual void TabChangedAt(TabContents* contents, int index, |
| 371 TabChangeType change_type) { |
| 372 // FIXME: update tile with |contents|, reload title, favicon, thumb |
| 373 // depending on |change_type|. |
| 374 } |
| 375 |
| 202 private: | 376 private: |
| 203 ScopedVector<Tile> tiles_; | 377 ScopedVector<Tile> tiles_; |
| 204 | 378 |
| 205 int selected_index_; | 379 int selected_index_; |
| 206 int initial_index_; | 380 int initial_index_; |
| 381 |
| 382 TabStripModel* source_model_; |
| 207 }; | 383 }; |
| 208 | 384 |
| 209 void TileSet::Build(TabStripModel* source_model) { | 385 void TileSet::Build(TabStripModel* source_model) { |
| 210 selected_index_ = initial_index_ = source_model->selected_index(); | 386 selected_index_ = initial_index_ = source_model->selected_index(); |
| 211 tiles_.resize(source_model->count()); | 387 tiles_.resize(source_model->count()); |
| 212 for (size_t i = 0; i < tiles_.size(); ++i) { | 388 for (size_t i = 0; i < tiles_.size(); ++i) { |
| 213 tiles_[i] = new Tile; | 389 tiles_[i] = new Tile; |
| 214 tiles_[i]->contents_ = source_model->GetTabContentsAt(i); | 390 tiles_[i]->contents_ = source_model->GetTabContentsAt(i); |
| 215 } | 391 } |
| 392 |
| 393 source_model->AddObserver(this); |
| 394 source_model_ = source_model; |
| 216 } | 395 } |
| 217 | 396 |
| 218 void TileSet::Layout(NSRect containing_rect) { | 397 void TileSet::Layout(NSRect containing_rect) { |
| 219 int tile_count = tiles_.size(); | 398 int tile_count = tiles_.size(); |
| 220 | 399 |
| 221 // Room around the tiles insde of |containing_rect|. | 400 // Room around the tiles insde of |containing_rect|. |
| 222 const int kSmallPaddingTop = 30; | 401 const int kSmallPaddingTop = 30; |
| 223 const int kSmallPaddingLeft = 30; | 402 const int kSmallPaddingLeft = 30; |
| 224 const int kSmallPaddingRight = 30; | 403 const int kSmallPaddingRight = 30; |
| 225 const int kSmallPaddingBottom = 30; | 404 const int kSmallPaddingBottom = 30; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 const tabpose::Tile& tile = tileSet_->tile_at(newIndex); | 651 const tabpose::Tile& tile = tileSet_->tile_at(newIndex); |
| 473 selectionHighlight_.frame = | 652 selectionHighlight_.frame = |
| 474 NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -5, -5)); | 653 NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -5, -5)); |
| 475 | 654 |
| 476 tileSet_->set_selected_index(newIndex); | 655 tileSet_->set_selected_index(newIndex); |
| 477 } | 656 } |
| 478 | 657 |
| 479 - (void)setUpLayers:(NSRect)bgLayerRect slomo:(BOOL)slomo { | 658 - (void)setUpLayers:(NSRect)bgLayerRect slomo:(BOOL)slomo { |
| 480 // Root layer -- covers whole window. | 659 // Root layer -- covers whole window. |
| 481 rootLayer_ = [CALayer layer]; | 660 rootLayer_ = [CALayer layer]; |
| 482 [[self contentView] setLayer:rootLayer_]; | |
| 483 [[self contentView] setWantsLayer:YES]; | |
| 484 | 661 |
| 485 // Background layer -- the visible part of the window. | 662 // In a block so that the layers don't fade in. |
| 486 gray_.reset(CGColorCreateGenericGray(0.39, 1.0)); | 663 { |
| 487 bgLayer_ = [CALayer layer]; | 664 ScopedCAActionDisabler disabler; |
| 488 bgLayer_.backgroundColor = gray_; | 665 // Background layer -- the visible part of the window. |
| 489 bgLayer_.frame = NSRectToCGRect(bgLayerRect); | 666 gray_.reset(CGColorCreateGenericGray(0.39, 1.0)); |
| 490 bgLayer_.masksToBounds = YES; | 667 bgLayer_ = [CALayer layer]; |
| 491 [rootLayer_ addSublayer:bgLayer_]; | 668 bgLayer_.backgroundColor = gray_; |
| 669 bgLayer_.frame = NSRectToCGRect(bgLayerRect); |
| 670 bgLayer_.masksToBounds = YES; |
| 671 [rootLayer_ addSublayer:bgLayer_]; |
| 492 | 672 |
| 493 // Selection highlight layer. | 673 // Selection highlight layer. |
| 494 darkBlue_.reset(CGColorCreateGenericRGB(0.25, 0.34, 0.86, 1.0)); | 674 darkBlue_.reset(CGColorCreateGenericRGB(0.25, 0.34, 0.86, 1.0)); |
| 495 selectionHighlight_ = [CALayer layer]; | 675 selectionHighlight_ = [CALayer layer]; |
| 496 selectionHighlight_.backgroundColor = darkBlue_; | 676 selectionHighlight_.backgroundColor = darkBlue_; |
| 497 selectionHighlight_.cornerRadius = 5.0; | 677 selectionHighlight_.cornerRadius = 5.0; |
| 498 selectionHighlight_.zPosition = -1; // Behind other layers. | 678 selectionHighlight_.zPosition = -1; // Behind other layers. |
| 499 selectionHighlight_.hidden = YES; | 679 selectionHighlight_.hidden = YES; |
| 500 [bgLayer_ addSublayer:selectionHighlight_]; | 680 [bgLayer_ addSublayer:selectionHighlight_]; |
| 501 | 681 |
| 502 // Top gradient. | 682 // Top gradient. |
| 503 CALayer* gradientLayer = [DarkGradientLayer layer]; | 683 CALayer* gradientLayer = [DarkGradientLayer layer]; |
| 504 gradientLayer.frame = CGRectMake( | 684 gradientLayer.frame = CGRectMake( |
| 505 0, | 685 0, |
| 506 NSHeight(bgLayerRect) - kTopGradientHeight, | 686 NSHeight(bgLayerRect) - kTopGradientHeight, |
| 507 NSWidth(bgLayerRect), | 687 NSWidth(bgLayerRect), |
| 508 kTopGradientHeight); | 688 kTopGradientHeight); |
| 509 [gradientLayer setNeedsDisplay]; // Draw once. | 689 [gradientLayer setNeedsDisplay]; // Draw once. |
| 510 [bgLayer_ addSublayer:gradientLayer]; | 690 [bgLayer_ addSublayer:gradientLayer]; |
| 511 | 691 } |
| 512 // Layers for the tab thumbnails. | 692 // Layers for the tab thumbnails. |
| 513 tileSet_->Build(tabStripModel_); | 693 tileSet_->Build(tabStripModel_); |
| 514 tileSet_->Layout(bgLayerRect); | 694 tileSet_->Layout(bgLayerRect); |
| 515 | 695 |
| 516 NSImage* defaultFavIcon = ResourceBundle::GetSharedInstance().GetNSImageNamed( | 696 NSImage* defaultFavIcon = ResourceBundle::GetSharedInstance().GetNSImageNamed( |
| 517 IDR_DEFAULT_FAVICON); | 697 IDR_DEFAULT_FAVICON); |
| 518 | 698 |
| 519 allThumbnailLayers_.reset( | 699 allThumbnailLayers_.reset( |
| 520 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); | 700 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 521 allFaviconLayers_.reset( | 701 allFaviconLayers_.reset( |
| 522 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); | 702 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 523 allTitleLayers_.reset( | 703 allTitleLayers_.reset( |
| 524 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); | 704 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 525 for (int i = 0; i < tabStripModel_->count(); ++i) { | 705 for (int i = 0; i < tabStripModel_->count(); ++i) { |
| 526 const tabpose::Tile& tile = tileSet_->tile_at(i); | 706 const tabpose::Tile& tile = tileSet_->tile_at(i); |
| 527 CALayer* layer = [CALayer layer]; | 707 |
| 708 |
| 709 // FIXME: BrowserWindowController should create this layer |
| 710 CALayer* layer = [[[BackingStoreLayer alloc] initWithTabContents:tile.tab_co
ntents() smallSize:tile.thumb_rect().size fullSize:tile.GetStartRectRelativeTo(t
ileSet_->selected_tile()).size] autorelease]; |
| 711 [layer setNeedsDisplay]; |
| 528 | 712 |
| 529 // Background color as placeholder for now. | 713 // Background color as placeholder for now. |
| 530 layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite); | 714 layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite); |
| 531 | 715 |
| 532 AnimateCALayerFrameFromTo( | 716 AnimateCALayerFrameFromTo( |
| 533 layer, | 717 layer, |
| 534 tile.GetStartRectRelativeTo(tileSet_->selected_tile()), | 718 tile.GetStartRectRelativeTo(tileSet_->selected_tile()), |
| 535 tile.thumb_rect(), | 719 tile.thumb_rect(), |
| 536 kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1), | 720 kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1), |
| 537 i == tileSet_->selected_index() ? self : nil); | 721 i == tileSet_->selected_index() ? self : nil); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 titleLayer.string = base::SysUTF16ToNSString(tile.title()); | 759 titleLayer.string = base::SysUTF16ToNSString(tile.title()); |
| 576 titleLayer.fontSize = [font pointSize]; | 760 titleLayer.fontSize = [font pointSize]; |
| 577 titleLayer.truncationMode = kCATruncationEnd; | 761 titleLayer.truncationMode = kCATruncationEnd; |
| 578 titleLayer.font = font; | 762 titleLayer.font = font; |
| 579 titleLayer.zPosition = 1; // On top of the thumb shadow. | 763 titleLayer.zPosition = 1; // On top of the thumb shadow. |
| 580 titleLayer.hidden = YES; | 764 titleLayer.hidden = YES; |
| 581 [bgLayer_ addSublayer:titleLayer]; | 765 [bgLayer_ addSublayer:titleLayer]; |
| 582 [allTitleLayers_ addObject:titleLayer]; | 766 [allTitleLayers_ addObject:titleLayer]; |
| 583 } | 767 } |
| 584 [self selectTileAtIndex:tileSet_->selected_index()]; | 768 [self selectTileAtIndex:tileSet_->selected_index()]; |
| 769 |
| 770 // Needs to happen after all layers have been added to |rootLayer_|, else |
| 771 // there's a one frame flash of grey at the beginning of the animation |
| 772 // (|bgLayer_| showing through with none of its children visible yet). |
| 773 [[self contentView] setLayer:rootLayer_]; |
| 774 [[self contentView] setWantsLayer:YES]; |
| 585 } | 775 } |
| 586 | 776 |
| 587 - (BOOL)canBecomeKeyWindow { | 777 - (BOOL)canBecomeKeyWindow { |
| 588 return YES; | 778 return YES; |
| 589 } | 779 } |
| 590 | 780 |
| 591 - (void)keyDown:(NSEvent*)event { | 781 - (void)keyDown:(NSEvent*)event { |
| 592 // Overridden to prevent beeps. | 782 // Overridden to prevent beeps. |
| 593 } | 783 } |
| 594 | 784 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 for (CALayer* layer in allTitleLayers_.get()) | 866 for (CALayer* layer in allTitleLayers_.get()) |
| 677 layer.hidden = YES; | 867 layer.hidden = YES; |
| 678 | 868 |
| 679 // Running animations with shadows is slow, so turn shadows off before | 869 // Running animations with shadows is slow, so turn shadows off before |
| 680 // running the exit animation. | 870 // running the exit animation. |
| 681 for (CALayer* layer in allThumbnailLayers_.get()) | 871 for (CALayer* layer in allThumbnailLayers_.get()) |
| 682 layer.shadowOpacity = 0.0; | 872 layer.shadowOpacity = 0.0; |
| 683 } | 873 } |
| 684 | 874 |
| 685 // Animate layers out, all in one transaction. | 875 // Animate layers out, all in one transaction. |
| 686 CGFloat duration = kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1); | 876 CGFloat duration = 2 * kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1); |
| 687 ScopedCAActionSetDuration durationSetter(duration); | 877 ScopedCAActionSetDuration durationSetter(duration); |
| 688 for (NSUInteger i = 0; i < [allThumbnailLayers_ count]; ++i) { | 878 for (NSUInteger i = 0; i < [allThumbnailLayers_ count]; ++i) { |
| 689 CALayer* layer = [allThumbnailLayers_ objectAtIndex:i]; | 879 CALayer* layer = [allThumbnailLayers_ objectAtIndex:i]; |
| 690 // |start_thumb_rect_| was relative to |initial_index_|, now this needs to | 880 // |start_thumb_rect_| was relative to |initial_index_|, now this needs to |
| 691 // be relative to |selectedIndex_| (whose start rect was relative to | 881 // be relative to |selectedIndex_| (whose start rect was relative to |
| 692 // |initial_index_| too) | 882 // |initial_index_| too) |
| 693 CGRect newFrame = NSRectToCGRect( | 883 CGRect newFrame = NSRectToCGRect( |
| 694 tileSet_->tile_at(i).GetStartRectRelativeTo(tileSet_->selected_tile())); | 884 tileSet_->tile_at(i).GetStartRectRelativeTo(tileSet_->selected_tile())); |
| 695 | 885 |
| 696 // Add a delegate to one of the implicit animations to get a notification | 886 // Add a delegate to one of the implicit animations to get a notification |
| 697 // once the animations are done. | 887 // once the animations are done. |
| 698 if (static_cast<int>(i) == tileSet_->selected_index()) { | 888 if (static_cast<int>(i) == tileSet_->selected_index()) { |
| 699 CAAnimation* animation = [CAAnimation animation]; | 889 CAAnimation* animation = [CAAnimation animation]; |
| 700 animation.delegate = self; | 890 animation.delegate = self; |
| 701 [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey]; | 891 [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey]; |
| 702 [layer addAnimation:animation forKey:@"frame"]; | 892 [layer addAnimation:animation forKey:@"frame"]; |
| 703 } | 893 } |
| 704 | 894 |
| 705 layer.frame = newFrame; | 895 layer.frame = newFrame; |
| 896 |
| 897 if (static_cast<int>(i) == tileSet_->selected_index()) { |
| 898 // FIXME: only do this if the layer has a backing store (?) |
| 899 [layer setNeedsDisplay]; // Redraw layer at big resolution, so that zoom-
in isn't blocky. |
| 900 } |
| 706 } | 901 } |
| 707 } | 902 } |
| 708 | 903 |
| 709 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished { | 904 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished { |
| 710 NSString* animationId = [animation valueForKey:kAnimationIdKey]; | 905 NSString* animationId = [animation valueForKey:kAnimationIdKey]; |
| 711 if ([animationId isEqualToString:kAnimationIdFadeIn]) { | 906 if ([animationId isEqualToString:kAnimationIdFadeIn]) { |
| 712 if (finished) { | 907 if (finished) { |
| 713 // If the user clicks while the fade in animation is still running, | 908 // If the user clicks while the fade in animation is still running, |
| 714 // |state_| is already kFadingOut. In that case, don't do anything. | 909 // |state_| is already kFadingOut. In that case, don't do anything. |
| 715 DCHECK_EQ(tabpose::kFadingIn, state_); | 910 DCHECK_EQ(tabpose::kFadingIn, state_); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 727 for (CALayer* layer in allThumbnailLayers_.get()) | 922 for (CALayer* layer in allThumbnailLayers_.get()) |
| 728 layer.shadowOpacity = 0.5; | 923 layer.shadowOpacity = 0.5; |
| 729 } | 924 } |
| 730 } else if ([animationId isEqualToString:kAnimationIdFadeOut]) { | 925 } else if ([animationId isEqualToString:kAnimationIdFadeOut]) { |
| 731 DCHECK_EQ(tabpose::kFadingOut, state_); | 926 DCHECK_EQ(tabpose::kFadingOut, state_); |
| 732 [self close]; | 927 [self close]; |
| 733 } | 928 } |
| 734 } | 929 } |
| 735 | 930 |
| 736 @end | 931 @end |
| OLD | NEW |