| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/tab_contents_controller.h" | 5 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/command_line.h" |
| 10 #include "base/mac/scoped_cftyperef.h" |
| 9 #include "base/mac/scoped_nsobject.h" | 11 #include "base/mac/scoped_nsobject.h" |
| 10 #include "chrome/browser/devtools/devtools_window.h" | 12 #include "chrome/browser/devtools/devtools_window.h" |
| 11 #import "chrome/browser/themes/theme_properties.h" | 13 #import "chrome/browser/themes/theme_properties.h" |
| 12 #import "chrome/browser/themes/theme_service.h" | 14 #import "chrome/browser/themes/theme_service.h" |
| 13 #import "chrome/browser/ui/cocoa/themed_window.h" | 15 #import "chrome/browser/ui/cocoa/themed_window.h" |
| 14 #include "content/public/browser/render_view_host.h" | 16 #include "content/public/browser/render_view_host.h" |
| 15 #include "content/public/browser/render_widget_host_view.h" | 17 #include "content/public/browser/render_widget_host_view.h" |
| 16 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" |
| 17 #include "content/public/browser/web_contents_observer.h" | 19 #include "content/public/browser/web_contents_observer.h" |
| 18 #include "content/public/browser/web_contents_view.h" | 20 #include "content/public/browser/web_contents_view.h" |
| 21 #include "ui/base/cocoa/animation_utils.h" |
| 22 #include "ui/base/ui_base_switches.h" |
| 19 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
| 20 | 24 |
| 21 using content::WebContents; | 25 using content::WebContents; |
| 22 using content::WebContentsObserver; | 26 using content::WebContentsObserver; |
| 23 | 27 |
| 24 // FullscreenObserver is used by TabContentsController to monitor for the | 28 // FullscreenObserver is used by TabContentsController to monitor for the |
| 25 // showing/destruction of fullscreen render widgets. When notified, | 29 // showing/destruction of fullscreen render widgets. When notified, |
| 26 // TabContentsController will alter its child view hierarchy to either embed a | 30 // TabContentsController will alter its child view hierarchy to either embed a |
| 27 // fullscreen render widget view or restore the normal WebContentsView render | 31 // fullscreen render widget view or restore the normal WebContentsView render |
| 28 // view. The embedded fullscreen render widget will fill the user's screen in | 32 // view. The embedded fullscreen render widget will fill the user's screen in |
| (...skipping 25 matching lines...) Expand all Loading... |
| 54 [controller_ toggleFullscreenWidget:YES]; | 58 [controller_ toggleFullscreenWidget:YES]; |
| 55 } | 59 } |
| 56 | 60 |
| 57 private: | 61 private: |
| 58 TabContentsController* const controller_; | 62 TabContentsController* const controller_; |
| 59 | 63 |
| 60 DISALLOW_COPY_AND_ASSIGN(FullscreenObserver); | 64 DISALLOW_COPY_AND_ASSIGN(FullscreenObserver); |
| 61 }; | 65 }; |
| 62 | 66 |
| 63 @interface TabContentsController (TabContentsContainerViewDelegate) | 67 @interface TabContentsController (TabContentsContainerViewDelegate) |
| 68 - (BOOL)contentsInFullscreenCaptureMode; |
| 64 // Computes and returns the frame to use for the contents view within the | 69 // Computes and returns the frame to use for the contents view within the |
| 65 // container view. | 70 // container view. |
| 66 - (NSRect)frameForContentsView; | 71 - (NSRect)frameForContentsView; |
| 67 @end | 72 @end |
| 68 | 73 |
| 69 // An NSView with special-case handling for when the contents view does not | 74 // An NSView with special-case handling for when the contents view does not |
| 70 // expand to fill the entire tab contents area. See 'AutoEmbedFullscreen mode' | 75 // expand to fill the entire tab contents area. See 'AutoEmbedFullscreen mode' |
| 71 // in header file comments. | 76 // in header file comments. |
| 72 @interface TabContentsContainerView : NSView { | 77 @interface TabContentsContainerView : NSView { |
| 73 @private | 78 @private |
| 74 TabContentsController* delegate_; // weak | 79 TabContentsController* delegate_; // weak |
| 75 } | 80 } |
| 81 |
| 82 - (NSColor*)computeBackgroundColor; |
| 76 @end | 83 @end |
| 77 | 84 |
| 78 @implementation TabContentsContainerView | 85 @implementation TabContentsContainerView |
| 79 | 86 |
| 80 - (id)initWithDelegate:(TabContentsController*)delegate { | 87 - (id)initWithDelegate:(TabContentsController*)delegate { |
| 81 if ((self = [super initWithFrame:NSZeroRect])) { | 88 if ((self = [super initWithFrame:NSZeroRect])) { |
| 82 delegate_ = delegate; | 89 delegate_ = delegate; |
| 90 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 91 switches::kDisableCoreAnimation)) { |
| 92 ScopedCAActionDisabler disabler; |
| 93 base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]); |
| 94 [layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; |
| 95 [self setLayer:layer]; |
| 96 [self setWantsLayer:YES]; |
| 97 } |
| 83 } | 98 } |
| 84 return self; | 99 return self; |
| 85 } | 100 } |
| 86 | 101 |
| 87 // Called by the delegate during dealloc to invalidate the pointer held by this | 102 // Called by the delegate during dealloc to invalidate the pointer held by this |
| 88 // view. | 103 // view. |
| 89 - (void)delegateDestroyed { | 104 - (void)delegateDestroyed { |
| 90 delegate_ = nil; | 105 delegate_ = nil; |
| 91 } | 106 } |
| 92 | 107 |
| 108 - (NSColor*)computeBackgroundColor { |
| 109 // This view is sometimes flashed into visibility (e.g, when closing |
| 110 // windows), so ensure that the flash be white in those cases. |
| 111 if (![delegate_ contentsInFullscreenCaptureMode]) |
| 112 return [NSColor whiteColor]; |
| 113 |
| 114 // Fill with a dark tint of the new tab page's background color. This is |
| 115 // only seen when the subview is sized specially for fullscreen tab capture. |
| 116 NSColor* bgColor = nil; |
| 117 ThemeService* const theme = |
| 118 static_cast<ThemeService*>([[self window] themeProvider]); |
| 119 if (theme) |
| 120 bgColor = theme->GetNSColor(ThemeProperties::COLOR_NTP_BACKGROUND); |
| 121 if (!bgColor) |
| 122 bgColor = [[self window] backgroundColor]; |
| 123 const float kDarknessFraction = 0.80f; |
| 124 return [bgColor blendedColorWithFraction:kDarknessFraction |
| 125 ofColor:[NSColor blackColor]]; |
| 126 } |
| 127 |
| 93 // Override -drawRect to fill the view with a solid color outside of the | 128 // Override -drawRect to fill the view with a solid color outside of the |
| 94 // subview's frame. | 129 // subview's frame. |
| 95 - (void)drawRect:(NSRect)dirtyRect { | 130 - (void)drawRect:(NSRect)dirtyRect { |
| 96 NSView* const contentsView = | 131 NSView* const contentsView = |
| 97 [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil; | 132 [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil; |
| 98 if (!contentsView || !NSContainsRect([contentsView frame], dirtyRect)) { | 133 if (!contentsView || !NSContainsRect([contentsView frame], dirtyRect)) { |
| 99 // Fill with a dark tint of the new tab page's background color. This is | 134 [[self computeBackgroundColor] setFill]; |
| 100 // only seen when the subview is sized specially for fullscreen tab capture. | |
| 101 NSColor* bgColor = nil; | |
| 102 ThemeService* const theme = | |
| 103 static_cast<ThemeService*>([[self window] themeProvider]); | |
| 104 if (theme) | |
| 105 bgColor = theme->GetNSColor(ThemeProperties::COLOR_NTP_BACKGROUND); | |
| 106 if (!bgColor) | |
| 107 bgColor = [[self window] backgroundColor]; | |
| 108 const float kDarknessFraction = 0.80f; | |
| 109 [[bgColor blendedColorWithFraction:kDarknessFraction | |
| 110 ofColor:[NSColor blackColor]] setFill]; | |
| 111 NSRectFill(dirtyRect); | 135 NSRectFill(dirtyRect); |
| 112 } | 136 } |
| 113 [super drawRect:dirtyRect]; | 137 [super drawRect:dirtyRect]; |
| 114 } | 138 } |
| 115 | 139 |
| 116 // Override auto-resizing logic to query the delegate for the exact frame to | 140 // Override auto-resizing logic to query the delegate for the exact frame to |
| 117 // use for the contents view. | 141 // use for the contents view. |
| 118 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { | 142 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { |
| 119 NSView* const contentsView = | 143 NSView* const contentsView = |
| 120 [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil; | 144 [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil; |
| 121 if (!contentsView || [contentsView autoresizingMask] == NSViewNotSizable || | 145 if (!contentsView || [contentsView autoresizingMask] == NSViewNotSizable || |
| 122 !delegate_) { | 146 !delegate_) { |
| 123 return; | 147 return; |
| 124 } | 148 } |
| 125 [contentsView setFrame:[delegate_ frameForContentsView]]; | 149 [contentsView setFrame:[delegate_ frameForContentsView]]; |
| 126 } | 150 } |
| 127 | 151 |
| 152 // Update the background layer's color whenever the view needs to repaint. |
| 153 - (void)setNeedsDisplayInRect:(NSRect)rect { |
| 154 [super setNeedsDisplayInRect:rect]; |
| 155 |
| 156 // Convert from an NSColor to a CGColorRef. |
| 157 NSColor* nsBackgroundColor = [self computeBackgroundColor]; |
| 158 NSColorSpace* nsColorSpace = [nsBackgroundColor colorSpace]; |
| 159 CGColorSpaceRef cgColorSpace = [nsColorSpace CGColorSpace]; |
| 160 const NSInteger numberOfComponents = [nsBackgroundColor numberOfComponents]; |
| 161 CGFloat components[numberOfComponents]; |
| 162 [nsBackgroundColor getComponents:components]; |
| 163 base::ScopedCFTypeRef<CGColorRef> cgBackgroundColor( |
| 164 CGColorCreate(cgColorSpace, components)); |
| 165 |
| 166 ScopedCAActionDisabler disabler; |
| 167 [[self layer] setBackgroundColor:cgBackgroundColor]; |
| 168 } |
| 169 |
| 128 @end // @implementation TabContentsContainerView | 170 @end // @implementation TabContentsContainerView |
| 129 | 171 |
| 130 @implementation TabContentsController | 172 @implementation TabContentsController |
| 131 @synthesize webContents = contents_; | 173 @synthesize webContents = contents_; |
| 132 | 174 |
| 133 - (id)initWithContents:(WebContents*)contents | 175 - (id)initWithContents:(WebContents*)contents |
| 134 andAutoEmbedFullscreen:(BOOL)enableEmbeddedFullscreen { | 176 andAutoEmbedFullscreen:(BOOL)enableEmbeddedFullscreen { |
| 135 if ((self = [super initWithNibName:nil bundle:nil])) { | 177 if ((self = [super initWithNibName:nil bundle:nil])) { |
| 136 if (enableEmbeddedFullscreen) | 178 if (enableEmbeddedFullscreen) |
| 137 fullscreenObserver_.reset(new FullscreenObserver(self)); | 179 fullscreenObserver_.reset(new FullscreenObserver(self)); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 [self ensureContentsVisible]; | 298 [self ensureContentsVisible]; |
| 257 } | 299 } |
| 258 } | 300 } |
| 259 | 301 |
| 260 - (void)toggleFullscreenWidget:(BOOL)enterFullscreen { | 302 - (void)toggleFullscreenWidget:(BOOL)enterFullscreen { |
| 261 isEmbeddingFullscreenWidget_ = enterFullscreen && | 303 isEmbeddingFullscreenWidget_ = enterFullscreen && |
| 262 contents_ && contents_->GetFullscreenRenderWidgetHostView(); | 304 contents_ && contents_->GetFullscreenRenderWidgetHostView(); |
| 263 [self ensureContentsVisible]; | 305 [self ensureContentsVisible]; |
| 264 } | 306 } |
| 265 | 307 |
| 266 - (NSRect)frameForContentsView { | 308 - (BOOL)contentsInFullscreenCaptureMode { |
| 267 const NSSize containerSize = [[self view] frame].size; | |
| 268 gfx::Rect rect; | |
| 269 rect.set_width(containerSize.width); | |
| 270 rect.set_height(containerSize.height); | |
| 271 | |
| 272 // In most cases, the contents view is simply sized to fill the container | |
| 273 // view's bounds. Only WebContentses that are in fullscreen mode and being | |
| 274 // screen-captured will engage the special layout/sizing behavior. | |
| 275 if (!fullscreenObserver_) | 309 if (!fullscreenObserver_) |
| 276 return NSRectFromCGRect(rect.ToCGRect()); | 310 return NO; |
| 277 // Note: Grab a known-valid WebContents pointer from |fullscreenObserver_|. | 311 // Note: Grab a known-valid WebContents pointer from |fullscreenObserver_|. |
| 278 content::WebContents* const wc = fullscreenObserver_->web_contents(); | 312 content::WebContents* const wc = fullscreenObserver_->web_contents(); |
| 279 if (!wc || | 313 if (!wc || |
| 280 wc->GetCapturerCount() == 0 || | 314 wc->GetCapturerCount() == 0 || |
| 281 wc->GetPreferredSize().IsEmpty() || | 315 wc->GetPreferredSize().IsEmpty() || |
| 282 !(isEmbeddingFullscreenWidget_ || | 316 !(isEmbeddingFullscreenWidget_ || |
| 283 (wc->GetDelegate() && | 317 (wc->GetDelegate() && |
| 284 wc->GetDelegate()->IsFullscreenForTabOrPending(wc)))) { | 318 wc->GetDelegate()->IsFullscreenForTabOrPending(wc)))) { |
| 319 return NO; |
| 320 } |
| 321 return YES; |
| 322 } |
| 323 |
| 324 - (NSRect)frameForContentsView { |
| 325 const NSSize containerSize = [[self view] frame].size; |
| 326 gfx::Rect rect; |
| 327 rect.set_width(containerSize.width); |
| 328 rect.set_height(containerSize.height); |
| 329 |
| 330 // In most cases, the contents view is simply sized to fill the container |
| 331 // view's bounds. Only WebContentses that are in fullscreen mode and being |
| 332 // screen-captured will engage the special layout/sizing behavior. |
| 333 if (![self contentsInFullscreenCaptureMode]) |
| 285 return NSRectFromCGRect(rect.ToCGRect()); | 334 return NSRectFromCGRect(rect.ToCGRect()); |
| 286 } | |
| 287 | 335 |
| 288 // Size the contents view to the capture video resolution and center it. If | 336 // Size the contents view to the capture video resolution and center it. If |
| 289 // the container view is not large enough to fit it at the preferred size, | 337 // the container view is not large enough to fit it at the preferred size, |
| 290 // scale down to fit (preserving aspect ratio). | 338 // scale down to fit (preserving aspect ratio). |
| 339 content::WebContents* const wc = fullscreenObserver_->web_contents(); |
| 291 const gfx::Size captureSize = wc->GetPreferredSize(); | 340 const gfx::Size captureSize = wc->GetPreferredSize(); |
| 292 if (captureSize.width() <= rect.width() && | 341 if (captureSize.width() <= rect.width() && |
| 293 captureSize.height() <= rect.height()) { | 342 captureSize.height() <= rect.height()) { |
| 294 // No scaling, just centering. | 343 // No scaling, just centering. |
| 295 rect.ClampToCenteredSize(captureSize); | 344 rect.ClampToCenteredSize(captureSize); |
| 296 } else { | 345 } else { |
| 297 // Scale down, preserving aspect ratio, and center. | 346 // Scale down, preserving aspect ratio, and center. |
| 298 // TODO(miu): This is basically media::ComputeLetterboxRegion(), and it | 347 // TODO(miu): This is basically media::ComputeLetterboxRegion(), and it |
| 299 // looks like others have written this code elsewhere. Let's consolidate | 348 // looks like others have written this code elsewhere. Let's consolidate |
| 300 // into a shared function ui/gfx/geometry or around there. | 349 // into a shared function ui/gfx/geometry or around there. |
| 301 const int64 x = static_cast<int64>(captureSize.width()) * rect.height(); | 350 const int64 x = static_cast<int64>(captureSize.width()) * rect.height(); |
| 302 const int64 y = static_cast<int64>(captureSize.height()) * rect.width(); | 351 const int64 y = static_cast<int64>(captureSize.height()) * rect.width(); |
| 303 if (y < x) { | 352 if (y < x) { |
| 304 rect.ClampToCenteredSize(gfx::Size( | 353 rect.ClampToCenteredSize(gfx::Size( |
| 305 rect.width(), static_cast<int>(y / captureSize.width()))); | 354 rect.width(), static_cast<int>(y / captureSize.width()))); |
| 306 } else { | 355 } else { |
| 307 rect.ClampToCenteredSize(gfx::Size( | 356 rect.ClampToCenteredSize(gfx::Size( |
| 308 static_cast<int>(x / captureSize.height()), rect.height())); | 357 static_cast<int>(x / captureSize.height()), rect.height())); |
| 309 } | 358 } |
| 310 } | 359 } |
| 311 | 360 |
| 312 return NSRectFromCGRect(rect.ToCGRect()); | 361 return NSRectFromCGRect(rect.ToCGRect()); |
| 313 } | 362 } |
| 314 | 363 |
| 315 @end | 364 @end |
| OLD | NEW |