| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 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/ui/cocoa/tab_contents/overlayable_contents_controller.h" | 5 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" |
| 6 | 6 |
| 7 #include "base/mac/bundle_locations.h" | |
| 8 #include "chrome/browser/ui/cocoa/browser_window_controller.h" | |
| 9 #include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h" | 7 #include "chrome/browser/ui/cocoa/tab_contents/instant_overlay_controller_mac.h" |
| 10 #include "chrome/browser/ui/cocoa/tab_contents/overlay_separator_view.h" | |
| 11 #include "content/public/browser/web_contents.h" | 8 #include "content/public/browser/web_contents.h" |
| 12 #include "content/public/browser/web_contents_view.h" | 9 #include "content/public/browser/web_contents_view.h" |
| 13 | 10 |
| 14 @interface OverlayableContentsController() | 11 @interface OverlayableContentsController() |
| 15 - (void)viewDidResize:(NSNotification*)note; | 12 - (void)viewDidResize:(NSNotification*)note; |
| 16 - (void)layoutViews; | 13 - (void)layoutViews; |
| 17 - (CGFloat)overlayHeightInPixels; | 14 - (CGFloat)overlayHeightInPixels; |
| 18 - (BOOL)shouldShowTopSeparator; | |
| 19 @end | 15 @end |
| 20 | 16 |
| 21 @implementation OverlayableContentsController | 17 @implementation OverlayableContentsController |
| 22 | 18 |
| 23 @synthesize drawDropShadow = drawDropShadow_; | |
| 24 @synthesize activeContainerOffset = activeContainerOffset_; | |
| 25 @synthesize overlayContentsOffset = overlayContentsOffset_; | |
| 26 | |
| 27 - (id)initWithBrowser:(Browser*)browser | 19 - (id)initWithBrowser:(Browser*)browser |
| 28 windowController:(BrowserWindowController*)windowController { | 20 windowController:(BrowserWindowController*)windowController { |
| 29 if ((self = [super init])) { | 21 if ((self = [super init])) { |
| 30 windowController_ = windowController; | |
| 31 base::scoped_nsobject<NSView> view( | 22 base::scoped_nsobject<NSView> view( |
| 32 [[NSView alloc] initWithFrame:NSZeroRect]); | 23 [[NSView alloc] initWithFrame:NSZeroRect]); |
| 33 [view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable]; | 24 [view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable]; |
| 34 [view setAutoresizesSubviews:NO]; | |
| 35 [[NSNotificationCenter defaultCenter] | 25 [[NSNotificationCenter defaultCenter] |
| 36 addObserver:self | 26 addObserver:self |
| 37 selector:@selector(viewDidResize:) | 27 selector:@selector(viewDidResize:) |
| 38 name:NSViewFrameDidChangeNotification | 28 name:NSViewFrameDidChangeNotification |
| 39 object:view]; | 29 object:view]; |
| 40 [self setView:view]; | 30 [self setView:view]; |
| 41 | 31 |
| 42 activeContainer_.reset([[NSView alloc] initWithFrame:NSZeroRect]); | 32 activeContainer_.reset([[NSView alloc] initWithFrame:NSZeroRect]); |
| 33 [activeContainer_ setAutoresizingMask:NSViewHeightSizable | |
| 34 NSViewWidthSizable]; |
| 43 [view addSubview:activeContainer_]; | 35 [view addSubview:activeContainer_]; |
| 44 | 36 |
| 45 instantOverlayController_.reset( | 37 instantOverlayController_.reset( |
| 46 new InstantOverlayControllerMac(browser, windowController, self)); | 38 new InstantOverlayControllerMac(browser, windowController, self)); |
| 47 topSeparatorView_.reset( | |
| 48 [[OverlayTopSeparatorView alloc] initWithFrame:NSZeroRect]); | |
| 49 [[self view] addSubview:topSeparatorView_]; | |
| 50 } | 39 } |
| 51 return self; | 40 return self; |
| 52 } | 41 } |
| 53 | 42 |
| 54 - (void)dealloc { | 43 - (void)dealloc { |
| 55 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 44 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 56 [super dealloc]; | 45 [super dealloc]; |
| 57 } | 46 } |
| 58 | 47 |
| 59 - (void)setOverlay:(content::WebContents*)overlay | 48 - (void)setOverlay:(content::WebContents*)overlay |
| 60 height:(CGFloat)height | 49 height:(CGFloat)height |
| 61 heightUnits:(InstantSizeUnits)heightUnits | 50 heightUnits:(InstantSizeUnits)heightUnits |
| 62 drawDropShadow:(BOOL)drawDropShadow { | 51 drawDropShadow:(BOOL)drawDropShadow { |
| 63 // If drawing drop shadow, clip the bottom 1-px-thick separator out of | |
| 64 // overlay. | |
| 65 // TODO(sail): remove this when GWS gives chrome the height without the | |
| 66 // separator. | |
| 67 if (drawDropShadow && heightUnits != INSTANT_SIZE_PERCENT) | |
| 68 --height; | |
| 69 | |
| 70 if (overlayContents_ == overlay && | 52 if (overlayContents_ == overlay && |
| 71 overlayHeight_ == height && | 53 overlayHeight_ == height && |
| 72 overlayHeightUnits_ == heightUnits && | 54 overlayHeightUnits_ == heightUnits) { |
| 73 drawDropShadow_ == drawDropShadow) { | |
| 74 return; | 55 return; |
| 75 } | 56 } |
| 76 | 57 |
| 77 // Remove any old overlay contents before showing the new one. | 58 // Remove any old overlay contents before showing the new one. |
| 78 if (overlayContents_) { | 59 if (overlayContents_) { |
| 79 if (overlayContents_ != overlay) | 60 if (overlayContents_ != overlay) |
| 80 overlayContents_->WasHidden(); | 61 overlayContents_->WasHidden(); |
| 81 [overlayContents_->GetView()->GetNativeView() removeFromSuperview]; | 62 [overlayContents_->GetView()->GetNativeView() removeFromSuperview]; |
| 82 } | 63 } |
| 83 | 64 |
| 84 overlayContents_ = overlay; | 65 overlayContents_ = overlay; |
| 85 overlayHeight_ = height; | 66 overlayHeight_ = height; |
| 86 overlayHeightUnits_ = heightUnits; | 67 overlayHeightUnits_ = heightUnits; |
| 87 drawDropShadow_ = drawDropShadow; | |
| 88 | 68 |
| 89 // Add the overlay contents. | 69 // Add the overlay contents. |
| 90 if (overlayContents_) { | 70 if (overlayContents_) { |
| 91 [[[self view] window] disableScreenUpdatesUntilFlush]; | 71 [[[self view] window] disableScreenUpdatesUntilFlush]; |
| 92 [[self view] addSubview:overlayContents_->GetView()->GetNativeView()]; | 72 [[self view] addSubview:overlayContents_->GetView()->GetNativeView()]; |
| 93 } | 73 } |
| 94 | 74 |
| 95 if (drawDropShadow_) { | |
| 96 if (!dropShadowView_) { | |
| 97 dropShadowView_.reset( | |
| 98 [[OverlayBottomSeparatorView alloc] initWithFrame:NSZeroRect]); | |
| 99 [[self view] addSubview:dropShadowView_]; | |
| 100 } | |
| 101 } else { | |
| 102 [dropShadowView_ removeFromSuperview]; | |
| 103 dropShadowView_.reset(); | |
| 104 } | |
| 105 | |
| 106 [self layoutViews]; | 75 [self layoutViews]; |
| 107 | 76 |
| 108 if (overlayContents_) | 77 if (overlayContents_) |
| 109 overlayContents_->WasShown(); | 78 overlayContents_->WasShown(); |
| 110 } | 79 } |
| 111 | 80 |
| 112 - (void)onActivateTabWithContents:(content::WebContents*)contents { | 81 - (void)onActivateTabWithContents:(content::WebContents*)contents { |
| 113 if (overlayContents_ == contents) { | 82 if (overlayContents_ == contents) { |
| 114 if (overlayContents_) { | 83 if (overlayContents_) { |
| 115 [overlayContents_->GetView()->GetNativeView() removeFromSuperview]; | 84 [overlayContents_->GetView()->GetNativeView() removeFromSuperview]; |
| 116 overlayContents_ = NULL; | 85 overlayContents_ = NULL; |
| 117 } | 86 } |
| 118 [self setOverlay:NULL | 87 [self setOverlay:NULL |
| 119 height:0 | 88 height:0 |
| 120 heightUnits:INSTANT_SIZE_PIXELS | 89 heightUnits:INSTANT_SIZE_PIXELS |
| 121 drawDropShadow:NO]; | 90 drawDropShadow:NO]; |
| 122 } | 91 } |
| 123 } | 92 } |
| 124 | 93 |
| 94 - (InstantOverlayControllerMac*)instantOverlayController { |
| 95 return instantOverlayController_.get(); |
| 96 } |
| 97 |
| 125 - (BOOL)isShowingOverlay { | 98 - (BOOL)isShowingOverlay { |
| 126 return overlayContents_ != nil; | 99 return overlayContents_ != nil; |
| 127 } | 100 } |
| 128 | 101 |
| 129 - (InstantOverlayControllerMac*)instantOverlayController { | |
| 130 return instantOverlayController_.get(); | |
| 131 } | |
| 132 | |
| 133 - (void)activeContentsCompositingIOSurfaceCreated { | |
| 134 if (!overlayContents_) | |
| 135 return; | |
| 136 | |
| 137 // If the active tab becomes composited the the overlay will no longer be | |
| 138 // visible. Workaround this by re-adding the overlay to the view hierarchy. | |
| 139 // See http://crbug.com/222122 | |
| 140 [overlayContents_->GetView()->GetNativeView() removeFromSuperview]; | |
| 141 [[self view] addSubview:overlayContents_->GetView()->GetNativeView()]; | |
| 142 } | |
| 143 | |
| 144 - (NSView*)activeContainer { | 102 - (NSView*)activeContainer { |
| 145 return activeContainer_.get(); | 103 return activeContainer_.get(); |
| 146 } | 104 } |
| 147 | 105 |
| 148 - (NSView*)dropShadowView { | |
| 149 return dropShadowView_.get(); | |
| 150 } | |
| 151 | |
| 152 - (void)setActiveContainerOffset:(CGFloat)activeContainerOffset { | |
| 153 if (activeContainerOffset_ == activeContainerOffset) | |
| 154 return; | |
| 155 | |
| 156 activeContainerOffset_ = activeContainerOffset; | |
| 157 [self layoutViews]; | |
| 158 } | |
| 159 | |
| 160 - (void)setOverlayContentsOffset:(CGFloat)overlayContentsOffset { | |
| 161 if (overlayContentsOffset_ == overlayContentsOffset) | |
| 162 return; | |
| 163 | |
| 164 overlayContentsOffset_ = overlayContentsOffset; | |
| 165 [self layoutViews]; | |
| 166 } | |
| 167 | |
| 168 - (void)viewDidResize:(NSNotification*)note { | 106 - (void)viewDidResize:(NSNotification*)note { |
| 169 [self layoutViews]; | 107 [self layoutViews]; |
| 170 } | 108 } |
| 171 | 109 |
| 172 - (void)layoutViews { | 110 - (void)layoutViews { |
| 173 NSRect bounds = [[self view] bounds]; | 111 if (!overlayContents_) |
| 174 | 112 return; |
| 175 // Layout the separator at the top of the view. | |
| 176 NSRect separatorRect = bounds; | |
| 177 if ([self shouldShowTopSeparator]) | |
| 178 separatorRect.size.height = [OverlayTopSeparatorView preferredHeight]; | |
| 179 else | |
| 180 separatorRect.size.height = 0; | |
| 181 separatorRect.origin.y = NSMaxY(bounds) - NSHeight(separatorRect); | |
| 182 [topSeparatorView_ setFrame:separatorRect]; | |
| 183 | 113 |
| 184 // Layout the overlay. | 114 // Layout the overlay. |
| 185 if (overlayContents_) { | 115 NSRect bounds = [[self view] bounds]; |
| 186 NSRect overlayFrame = bounds; | 116 NSRect overlayFrame = bounds; |
| 187 overlayFrame.size.height = [self overlayHeightInPixels]; | 117 overlayFrame.size.height = [self overlayHeightInPixels]; |
| 188 overlayFrame.origin.y = NSMinY([topSeparatorView_ frame]) - | 118 overlayFrame.origin.y = NSMaxY(bounds) - NSHeight(overlayFrame); |
| 189 NSHeight(overlayFrame) - overlayContentsOffset_; | 119 [overlayContents_->GetView()->GetNativeView() setFrame:overlayFrame]; |
| 190 [overlayContents_->GetView()->GetNativeView() setFrame:overlayFrame]; | |
| 191 | |
| 192 if (dropShadowView_) { | |
| 193 NSRect dropShadowFrame = bounds; | |
| 194 dropShadowFrame.size.height = | |
| 195 [OverlayBottomSeparatorView preferredHeight]; | |
| 196 dropShadowFrame.origin.y = | |
| 197 NSMinY(overlayFrame) - NSHeight(dropShadowFrame); | |
| 198 [dropShadowView_ setFrame:dropShadowFrame]; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 // Layout the active tab contents. | |
| 203 NSRect activeFrame = bounds; | |
| 204 if (activeContainerOffset_) | |
| 205 activeFrame.size.height -= activeContainerOffset_; | |
| 206 else | |
| 207 activeFrame.size.height -= NSHeight([topSeparatorView_ frame]); | |
| 208 if (!NSEqualRects(activeFrame, [activeContainer_ frame])) { | |
| 209 [[activeContainer_ window] disableScreenUpdatesUntilFlush]; | |
| 210 [activeContainer_ setFrame:activeFrame]; | |
| 211 } | |
| 212 } | 120 } |
| 213 | 121 |
| 214 - (CGFloat)overlayHeightInPixels { | 122 - (CGFloat)overlayHeightInPixels { |
| 215 CGFloat height = NSHeight([[self view] bounds]) - | 123 CGFloat height = NSHeight([[self view] bounds]); |
| 216 NSHeight([topSeparatorView_ frame]) - overlayContentsOffset_; | |
| 217 switch (overlayHeightUnits_) { | 124 switch (overlayHeightUnits_) { |
| 218 case INSTANT_SIZE_PERCENT: | 125 case INSTANT_SIZE_PERCENT: |
| 219 return std::min(height, (height * overlayHeight_) / 100); | 126 return std::min(height, (height * overlayHeight_) / 100); |
| 220 case INSTANT_SIZE_PIXELS: | 127 case INSTANT_SIZE_PIXELS: |
| 221 return std::min(height, overlayHeight_); | 128 return std::min(height, overlayHeight_); |
| 222 } | 129 } |
| 223 } | 130 } |
| 224 | 131 |
| 225 - (BOOL)shouldShowTopSeparator { | |
| 226 // In presentation mode tab contents are flush with the top of the screen | |
| 227 // so there's no need for a separator. | |
| 228 if ([windowController_ inPresentationMode]) | |
| 229 return NO; | |
| 230 | |
| 231 if (![windowController_ hasToolbar]) | |
| 232 return NO; | |
| 233 | |
| 234 // Show a separator is the overlay or the tab contents will be shown right | |
| 235 // next to the omnibox. | |
| 236 return activeContainerOffset_ == 0 || overlayContents_; | |
| 237 } | |
| 238 | |
| 239 @end | 132 @end |
| OLD | NEW |