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 |