| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/mac/scoped_cftyperef.h" | 11 #include "base/mac/scoped_cftyperef.h" |
| 12 #include "base/mac/scoped_nsobject.h" | 12 #include "base/mac/scoped_nsobject.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "chrome/browser/devtools/devtools_window.h" | 14 #include "chrome/browser/devtools/devtools_window.h" |
| 15 #import "chrome/browser/themes/theme_properties.h" | 15 #import "chrome/browser/themes/theme_properties.h" |
| 16 #import "chrome/browser/themes/theme_service.h" | 16 #import "chrome/browser/themes/theme_service.h" |
| 17 #import "chrome/browser/ui/cocoa/themed_window.h" | 17 #import "chrome/browser/ui/cocoa/themed_window.h" |
| 18 #include "chrome/browser/ui/view_ids.h" | 18 #include "chrome/browser/ui/view_ids.h" |
| 19 #include "content/public/browser/render_view_host.h" | 19 #include "content/public/browser/render_view_host.h" |
| 20 #include "content/public/browser/render_widget_host.h" | 20 #include "content/public/browser/render_widget_host.h" |
| 21 #include "content/public/browser/render_widget_host_view.h" | 21 #include "content/public/browser/render_widget_host_view.h" |
| 22 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
| 23 #include "content/public/browser/web_contents_observer.h" | 23 #include "content/public/browser/web_contents_observer.h" |
| 24 #include "skia/ext/skia_utils_mac.h" | 24 #include "skia/ext/skia_utils_mac.h" |
| 25 #include "ui/base/cocoa/animation_utils.h" | 25 #include "ui/base/cocoa/animation_utils.h" |
| 26 #include "ui/gfx/geometry/rect.h" | 26 #include "ui/gfx/geometry/rect_conversions.h" |
| 27 #include "ui/gfx/geometry/rect_f.h" |
| 28 #include "ui/gfx/geometry/size.h" |
| 29 #include "ui/gfx/geometry/size_f.h" |
| 27 | 30 |
| 28 using content::WebContents; | 31 using content::WebContents; |
| 29 using content::WebContentsObserver; | 32 using content::WebContentsObserver; |
| 30 | 33 |
| 31 // FullscreenObserver is used by TabContentsController to monitor for the | 34 // FullscreenObserver is used by TabContentsController to monitor for the |
| 32 // showing/destruction of fullscreen render widgets. When notified, | 35 // showing/destruction of fullscreen render widgets. When notified, |
| 33 // TabContentsController will alter its child view hierarchy to either embed a | 36 // TabContentsController will alter its child view hierarchy to either embed a |
| 34 // fullscreen render widget view or restore the normal WebContentsView render | 37 // fullscreen render widget view or restore the normal WebContentsView render |
| 35 // view. The embedded fullscreen render widget will fill the user's screen in | 38 // view. The embedded fullscreen render widget will fill the user's screen in |
| 36 // the case where TabContentsController's NSView is a subview of a browser | 39 // the case where TabContentsController's NSView is a subview of a browser |
| (...skipping 26 matching lines...) Expand all Loading... |
| 63 } | 66 } |
| 64 | 67 |
| 65 private: | 68 private: |
| 66 TabContentsController* const controller_; | 69 TabContentsController* const controller_; |
| 67 | 70 |
| 68 DISALLOW_COPY_AND_ASSIGN(FullscreenObserver); | 71 DISALLOW_COPY_AND_ASSIGN(FullscreenObserver); |
| 69 }; | 72 }; |
| 70 | 73 |
| 71 @interface TabContentsController (TabContentsContainerViewDelegate) | 74 @interface TabContentsController (TabContentsContainerViewDelegate) |
| 72 - (BOOL)contentsInFullscreenCaptureMode; | 75 - (BOOL)contentsInFullscreenCaptureMode; |
| 73 // Computes and returns the frame to use for the contents view using the size of | 76 |
| 74 // |container| as the target size. | 77 // Computes and returns the frame to use for the scaling view within the |
| 75 - (NSRect)frameForContentsViewIn:(NSView*)container; | 78 // TabContentsContainerView. |
| 79 - (NSRect)frameForScalingViewIn:(NSView*)container; |
| 80 |
| 81 // Computes and returns the bounds to use for the scaling view within the |
| 82 // TabContentsContainerView. In the normal case, the bounds size will be |
| 83 // equivalent to frame size. In 'AutoEmbedFullscreen mode', the bounds size is |
| 84 // set to the video capture resolution, which is almost always different from |
| 85 // the frame size. See 'AutoEmbedFullscreen mode' in header file comments. |
| 86 - (NSRect)boundsForScalingViewIn:(NSView*)container; |
| 76 | 87 |
| 77 // Returns YES if the content view should be resized. | 88 // Returns YES if the content view should be resized. |
| 78 - (BOOL)shouldResizeContentView; | 89 - (BOOL)shouldResizeContentView; |
| 79 | 90 |
| 80 // Returns YES if the content view is inside a popup. | 91 // Returns YES if the content view is inside a popup. |
| 81 - (BOOL)isPopup; | 92 - (BOOL)isPopup; |
| 82 | 93 |
| 83 @end | 94 @end |
| 84 | 95 |
| 85 // An NSView with special-case handling for when the contents view does not | 96 // An NSView with special-case handling for when the contents view does not |
| 86 // expand to fill the entire tab contents area. See 'AutoEmbedFullscreen mode' | 97 // expand to fill the entire tab contents area. See 'AutoEmbedFullscreen mode' |
| 87 // in header file comments. | 98 // in header file comments. |
| 99 // |
| 100 // This view creates and manages its own subview, a "scaling" view, which acts |
| 101 // as a container for the contents view. It allows the rendering size of the |
| 102 // contents view to be something different than its normal on-screen display |
| 103 // size. |
| 88 @interface TabContentsContainerView : NSView { | 104 @interface TabContentsContainerView : NSView { |
| 89 @private | 105 @private |
| 90 TabContentsController* delegate_; // weak | 106 TabContentsController* delegate_; // weak |
| 91 } | 107 } |
| 92 | 108 |
| 109 - (void)ensureContentsVisible:(NSView*)contentsView; |
| 93 - (void)updateBackgroundColor; | 110 - (void)updateBackgroundColor; |
| 94 @end | 111 @end |
| 95 | 112 |
| 96 @implementation TabContentsContainerView | 113 @implementation TabContentsContainerView |
| 97 | 114 |
| 98 - (id)initWithDelegate:(TabContentsController*)delegate { | 115 - (id)initWithDelegate:(TabContentsController*)delegate { |
| 99 if ((self = [super initWithFrame:NSZeroRect])) { | 116 if ((self = [super initWithFrame:NSZeroRect])) { |
| 100 delegate_ = delegate; | 117 delegate_ = delegate; |
| 118 |
| 101 ScopedCAActionDisabler disabler; | 119 ScopedCAActionDisabler disabler; |
| 102 base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]); | 120 base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]); |
| 103 [self setLayer:layer]; | 121 [self setLayer:layer]; |
| 104 [self setWantsLayer:YES]; | 122 [self setWantsLayer:YES]; |
| 105 [self updateBackgroundColor]; | 123 [self updateBackgroundColor]; |
| 124 |
| 125 // Create and add the scaling view. |
| 126 [self addSubview:[[NSView alloc] initWithFrame:NSZeroRect]]; |
| 106 } | 127 } |
| 107 return self; | 128 return self; |
| 108 } | 129 } |
| 109 | 130 |
| 110 // Called by the delegate during dealloc to invalidate the pointer held by this | 131 // Called by the delegate during dealloc to invalidate the pointer held by this |
| 111 // view. | 132 // view. |
| 112 - (void)delegateDestroyed { | 133 - (void)delegateDestroyed { |
| 113 delegate_ = nil; | 134 delegate_ = nil; |
| 114 } | 135 } |
| 115 | 136 |
| 116 // Override auto-resizing logic to query the delegate for the exact frame to | 137 // Returns the scaling view, which is the child of TabContentsContainerView. |
| 117 // use for the contents view. | 138 - (NSView*)scalingView { |
| 118 // TODO(spqchan): The popup check is a temporary solution to fix the regression | 139 return [[self subviews] objectAtIndex:0]; |
| 119 // issue described in crbug.com/604288. This method doesn't really affect | 140 } |
| 120 // fullscreen if the content is inside a normal browser window, but would | 141 |
| 121 // cause a flash fullscreen widget to blow up if it's inside a popup. | 142 // Return the contents view, which is the child of the scaling view; or nil if |
| 143 // there isn't one attached. |
| 144 - (NSView*)contentsView { |
| 145 NSArray* const scalingViewSubviews = [[self scalingView] subviews]; |
| 146 if ([scalingViewSubviews count] == 0) |
| 147 return nil; // No contents view attached. |
| 148 return [scalingViewSubviews objectAtIndex:0]; |
| 149 } |
| 150 |
| 151 // Override auto-resizing logic to query the delegate for the exact frame and |
| 152 // bounds to use for the contents view, and then perform manual layout of the |
| 153 // scaling view (child view) and contents view (grandchild view). |
| 122 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { | 154 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { |
| 123 NSView* const contentsView = | 155 ScopedCAActionDisabler disabler; |
| 124 [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil; | 156 |
| 125 if (!contentsView || [contentsView autoresizingMask] == NSViewNotSizable || | 157 NSView* const contentsView = [self contentsView]; |
| 126 !delegate_ || | 158 if (!contentsView) |
| 159 return; // No contents view attached yet. |
| 160 |
| 161 // TODO(spqchan): The popup check is a temporary solution to fix the |
| 162 // regression described in crbug.com/604288. This method doesn't really affect |
| 163 // fullscreen if the content is inside a normal browser window, but would |
| 164 // cause a flash fullscreen widget to blow up if it's inside a popup. |
| 165 if (!delegate_ || |
| 127 (![delegate_ shouldResizeContentView] && [delegate_ isPopup])) { | 166 (![delegate_ shouldResizeContentView] && [delegate_ isPopup])) { |
| 128 return; | 167 return; |
| 129 } | 168 } |
| 130 | 169 |
| 131 ScopedCAActionDisabler disabler; | 170 // Set the position and size of the scaling view within this container view. |
| 132 [contentsView setFrame:[delegate_ frameForContentsViewIn:self]]; | 171 NSView* const scalingView = [self scalingView]; |
| 172 [scalingView setFrame:[delegate_ frameForScalingViewIn:self]]; |
| 173 const NSRect scalingViewBounds = [delegate_ boundsForScalingViewIn:self]; |
| 174 [scalingView setBounds:scalingViewBounds]; |
| 175 |
| 176 // Update the position and size of the contents view, if it has changed. |
| 177 if (!NSEqualRects(scalingViewBounds, [contentsView frame])) |
| 178 [contentsView setFrame:scalingViewBounds]; |
| 133 } | 179 } |
| 134 | 180 |
| 135 // Update the background layer's color whenever the view needs to repaint. | 181 // Update the background layer's color whenever the view needs to repaint. |
| 136 - (void)setNeedsDisplayInRect:(NSRect)rect { | 182 - (void)setNeedsDisplayInRect:(NSRect)rect { |
| 137 [super setNeedsDisplayInRect:rect]; | 183 [super setNeedsDisplayInRect:rect]; |
| 138 [self updateBackgroundColor]; | 184 [self updateBackgroundColor]; |
| 139 } | 185 } |
| 140 | 186 |
| 187 - (void)ensureContentsVisible:(NSView*)contentsView { |
| 188 DCHECK(contentsView); |
| 189 |
| 190 // TabContentsContainerView performs manual layout. |
| 191 [contentsView setAutoresizingMask:NSViewNotSizable]; |
| 192 |
| 193 NSView* const scalingView = [self scalingView]; |
| 194 if ([[scalingView subviews] count] == 0) { |
| 195 [scalingView addSubview:contentsView]; |
| 196 } else if ([[scalingView subviews] objectAtIndex:0] != contentsView) { |
| 197 [scalingView replaceSubview:[[scalingView subviews] objectAtIndex:0] |
| 198 with:contentsView]; |
| 199 } |
| 200 |
| 201 [self resizeSubviewsWithOldSize:[self bounds].size]; |
| 202 } |
| 203 |
| 141 - (void)updateBackgroundColor { | 204 - (void)updateBackgroundColor { |
| 142 // This view is sometimes flashed into visibility (e.g, when closing | 205 // This view is sometimes flashed into visibility (e.g, when closing |
| 143 // windows or opening new tabs), so ensure that the flash be the theme | 206 // windows or opening new tabs), so ensure that the flash be the theme |
| 144 // background color in those cases. | 207 // background color in those cases. |
| 145 SkColor skBackgroundColor = SK_ColorWHITE; | 208 SkColor skBackgroundColor = SK_ColorWHITE; |
| 146 const ThemeProvider* theme = [[self window] themeProvider]; | 209 const ThemeProvider* theme = [[self window] themeProvider]; |
| 147 if (theme) | 210 if (theme) |
| 148 skBackgroundColor = theme->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); | 211 skBackgroundColor = theme->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); |
| 149 | 212 |
| 150 // If the page is in fullscreen tab capture mode, change the background color | 213 // If the page is in fullscreen tab capture mode, change the background color |
| (...skipping 11 matching lines...) Expand all Loading... |
| 162 base::ScopedCFTypeRef<CGColorRef> cgBackgroundColor( | 225 base::ScopedCFTypeRef<CGColorRef> cgBackgroundColor( |
| 163 skia::CGColorCreateFromSkColor(skBackgroundColor)); | 226 skia::CGColorCreateFromSkColor(skBackgroundColor)); |
| 164 [[self layer] setBackgroundColor:cgBackgroundColor]; | 227 [[self layer] setBackgroundColor:cgBackgroundColor]; |
| 165 } | 228 } |
| 166 | 229 |
| 167 - (ViewID)viewID { | 230 - (ViewID)viewID { |
| 168 return VIEW_ID_TAB_CONTAINER; | 231 return VIEW_ID_TAB_CONTAINER; |
| 169 } | 232 } |
| 170 | 233 |
| 171 - (BOOL)acceptsFirstResponder { | 234 - (BOOL)acceptsFirstResponder { |
| 172 return [[self subviews] count] > 0 && | 235 NSView* const contentsView = [self contentsView]; |
| 173 [[[self subviews] objectAtIndex:0] acceptsFirstResponder]; | 236 return contentsView && [contentsView acceptsFirstResponder]; |
| 174 } | 237 } |
| 175 | 238 |
| 176 // When receiving a click-to-focus in the solid color area surrounding the | 239 // When receiving a click-to-focus in the solid color area surrounding the |
| 177 // WebContents' native view, immediately transfer focus to WebContents' native | 240 // WebContents' native view, immediately transfer focus to WebContents' native |
| 178 // view. | 241 // view. |
| 179 - (BOOL)becomeFirstResponder { | 242 - (BOOL)becomeFirstResponder { |
| 180 if (![self acceptsFirstResponder]) | 243 if (![self acceptsFirstResponder]) |
| 181 return NO; | 244 return NO; |
| 182 return [[self window] makeFirstResponder:[[self subviews] objectAtIndex:0]]; | 245 return [[self window] makeFirstResponder:[self contentsView]]; |
| 183 } | 246 } |
| 184 | 247 |
| 185 - (BOOL)canBecomeKeyView { | 248 - (BOOL)canBecomeKeyView { |
| 186 return NO; // Tab/Shift-Tab should focus the subview, not this view. | 249 return NO; // Tab/Shift-Tab should focus the subview, not this view. |
| 187 } | 250 } |
| 188 | 251 |
| 189 @end // @implementation TabContentsContainerView | 252 @end // @implementation TabContentsContainerView |
| 190 | 253 |
| 191 @implementation TabContentsController | 254 @implementation TabContentsController |
| 192 @synthesize webContents = contents_; | 255 @synthesize webContents = contents_; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 214 [[TabContentsContainerView alloc] initWithDelegate:self]); | 277 [[TabContentsContainerView alloc] initWithDelegate:self]); |
| 215 [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable]; | 278 [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable]; |
| 216 [self setView:view]; | 279 [self setView:view]; |
| 217 } | 280 } |
| 218 | 281 |
| 219 - (void)ensureContentsVisibleInSuperview:(NSView*)superview { | 282 - (void)ensureContentsVisibleInSuperview:(NSView*)superview { |
| 220 if (!contents_) | 283 if (!contents_) |
| 221 return; | 284 return; |
| 222 | 285 |
| 223 ScopedCAActionDisabler disabler; | 286 ScopedCAActionDisabler disabler; |
| 224 NSView* contentsContainer = [self view]; | 287 |
| 225 NSArray* subviews = [contentsContainer subviews]; | |
| 226 NSView* contentsNativeView; | 288 NSView* contentsNativeView; |
| 227 content::RenderWidgetHostView* const fullscreenView = | 289 content::RenderWidgetHostView* const fullscreenView = |
| 228 isEmbeddingFullscreenWidget_ ? | 290 isEmbeddingFullscreenWidget_ ? |
| 229 contents_->GetFullscreenRenderWidgetHostView() : NULL; | 291 contents_->GetFullscreenRenderWidgetHostView() : NULL; |
| 230 if (fullscreenView) { | 292 if (fullscreenView) { |
| 231 contentsNativeView = fullscreenView->GetNativeView(); | 293 contentsNativeView = fullscreenView->GetNativeView(); |
| 232 } else { | 294 } else { |
| 233 isEmbeddingFullscreenWidget_ = NO; | 295 isEmbeddingFullscreenWidget_ = NO; |
| 234 contentsNativeView = contents_->GetNativeView(); | 296 contentsNativeView = contents_->GetNativeView(); |
| 235 } | 297 } |
| 236 | 298 |
| 237 if ([self shouldResizeContentView]) | 299 TabContentsContainerView* const contentsContainer = |
| 238 [contentsNativeView setFrame:[self frameForContentsViewIn:superview]]; | 300 static_cast<TabContentsContainerView*>([self view]); |
| 239 | 301 [contentsContainer ensureContentsVisible:contentsNativeView]; |
| 240 if ([subviews count] == 0) { | |
| 241 [contentsContainer addSubview:contentsNativeView]; | |
| 242 } else if ([subviews objectAtIndex:0] != contentsNativeView) { | |
| 243 [contentsContainer replaceSubview:[subviews objectAtIndex:0] | |
| 244 with:contentsNativeView]; | |
| 245 } | |
| 246 | |
| 247 [contentsNativeView setAutoresizingMask:NSViewNotSizable]; | |
| 248 [contentsContainer setFrame:[superview bounds]]; | 302 [contentsContainer setFrame:[superview bounds]]; |
| 249 [superview addSubview:contentsContainer]; | 303 [superview addSubview:contentsContainer]; |
| 250 [contentsNativeView setAutoresizingMask:NSViewWidthSizable| | |
| 251 NSViewHeightSizable]; | |
| 252 | |
| 253 [contentsContainer setNeedsDisplay:YES]; | 304 [contentsContainer setNeedsDisplay:YES]; |
| 254 | 305 |
| 255 // Push the background color down to the RenderWidgetHostView, so that if | 306 // Push the background color down to the RenderWidgetHostView, so that if |
| 256 // there is a flash between contents appearing, it will be the theme's color, | 307 // there is a flash between contents appearing, it will be the theme's color, |
| 257 // not white. | 308 // not white. |
| 258 SkColor skBackgroundColor = SK_ColorWHITE; | 309 SkColor skBackgroundColor = SK_ColorWHITE; |
| 259 const ThemeProvider* theme = [[[self view] window] themeProvider]; | 310 const ThemeProvider* theme = [[[self view] window] themeProvider]; |
| 260 if (theme) | 311 if (theme) |
| 261 skBackgroundColor = theme->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); | 312 skBackgroundColor = theme->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); |
| 262 content::RenderWidgetHostView* rwhv = contents_->GetRenderWidgetHostView(); | 313 content::RenderWidgetHostView* rwhv = contents_->GetRenderWidgetHostView(); |
| 263 if (rwhv) | 314 if (rwhv) |
| 264 rwhv->SetBackgroundColor(skBackgroundColor); | 315 rwhv->SetBackgroundColor(skBackgroundColor); |
| 265 } | 316 } |
| 266 | 317 |
| 267 - (void)updateFullscreenWidgetFrame { | 318 - (void)updateFullscreenWidgetFrame { |
| 268 // This should only apply if a fullscreen widget is embedded. | 319 // This should only apply if a fullscreen widget is embedded. |
| 269 if (!isEmbeddingFullscreenWidget_ || blockFullscreenResize_) | 320 if (!isEmbeddingFullscreenWidget_ || blockFullscreenResize_) |
| 270 return; | 321 return; |
| 271 | 322 |
| 272 content::RenderWidgetHostView* const fullscreenView = | 323 content::RenderWidgetHostView* const fullscreenView = |
| 273 contents_->GetFullscreenRenderWidgetHostView(); | 324 contents_->GetFullscreenRenderWidgetHostView(); |
| 274 if (fullscreenView) { | 325 if (fullscreenView) { |
| 275 [fullscreenView->GetNativeView() | 326 [static_cast<TabContentsContainerView*>([self view]) |
| 276 setFrame:[self frameForContentsViewIn:[self view]]]; | 327 ensureContentsVisible:fullscreenView->GetNativeView()]; |
| 277 } | 328 } |
| 278 } | 329 } |
| 279 | 330 |
| 280 - (void)changeWebContents:(WebContents*)newContents { | 331 - (void)changeWebContents:(WebContents*)newContents { |
| 281 contents_ = newContents; | 332 contents_ = newContents; |
| 282 fullscreenObserver_->Observe(contents_); | 333 fullscreenObserver_->Observe(contents_); |
| 283 isEmbeddingFullscreenWidget_ = | 334 isEmbeddingFullscreenWidget_ = |
| 284 contents_ && contents_->GetFullscreenRenderWidgetHostView(); | 335 contents_ && contents_->GetFullscreenRenderWidgetHostView(); |
| 285 } | 336 } |
| 286 | 337 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 wc->GetCapturerCount() == 0 || | 394 wc->GetCapturerCount() == 0 || |
| 344 wc->GetPreferredSize().IsEmpty() || | 395 wc->GetPreferredSize().IsEmpty() || |
| 345 !(isEmbeddingFullscreenWidget_ || | 396 !(isEmbeddingFullscreenWidget_ || |
| 346 (wc->GetDelegate() && | 397 (wc->GetDelegate() && |
| 347 wc->GetDelegate()->IsFullscreenForTabOrPending(wc)))) { | 398 wc->GetDelegate()->IsFullscreenForTabOrPending(wc)))) { |
| 348 return NO; | 399 return NO; |
| 349 } | 400 } |
| 350 return YES; | 401 return YES; |
| 351 } | 402 } |
| 352 | 403 |
| 353 - (NSRect)frameForContentsViewIn:(NSView*)container { | 404 - (NSRect)frameForScalingViewIn:(NSView*)container { |
| 354 gfx::Rect rect([container bounds]); | 405 NSRect bounds = [container bounds]; |
| 406 bounds.origin = NSZeroPoint; |
| 355 | 407 |
| 356 // In most cases, the contents view is simply sized to fill the container | 408 // In most cases, the contents view is simply sized to fill the container |
| 357 // view's bounds. Only WebContentses that are in fullscreen mode and being | 409 // view's bounds. Only WebContentses that are in fullscreen mode and being |
| 358 // screen-captured will engage the special layout/sizing behavior. | 410 // screen-captured will engage the special layout/sizing behavior. |
| 359 if (![self contentsInFullscreenCaptureMode]) | 411 if (![self contentsInFullscreenCaptureMode]) |
| 360 return NSRectFromCGRect(rect.ToCGRect()); | 412 return bounds; |
| 361 | 413 |
| 362 // Size the contents view to the capture video resolution and center it. If | 414 // For 'AutoEmbedFullscreen mode', scale the view to fit within the container, |
| 363 // the container view is not large enough to fit it at the preferred size, | 415 // and center it. |
| 364 // scale down to fit (preserving aspect ratio). | 416 gfx::RectF rect(bounds); |
| 365 content::WebContents* const wc = fullscreenObserver_->web_contents(); | 417 gfx::Size captureSize = |
| 366 const gfx::Size captureSize = wc->GetPreferredSize(); | 418 fullscreenObserver_->web_contents()->GetPreferredSize(); |
| 367 if (captureSize.width() <= rect.width() && | 419 DCHECK(!captureSize.IsEmpty()); |
| 368 captureSize.height() <= rect.height()) { | 420 const float x = captureSize.width() * rect.height(); |
| 369 // No scaling, just centering. | 421 const float y = captureSize.height() * rect.width(); |
| 370 rect.ClampToCenteredSize(captureSize); | 422 if (y < x) { |
| 423 rect.ClampToCenteredSize(gfx::SizeF(rect.width(), y / captureSize.width())); |
| 371 } else { | 424 } else { |
| 372 // Scale down, preserving aspect ratio, and center. | 425 rect.ClampToCenteredSize( |
| 373 // TODO(miu): This is basically media::ComputeLetterboxRegion(), and it | 426 gfx::SizeF(x / captureSize.height(), rect.height())); |
| 374 // looks like others have written this code elsewhere. Let's consolidate | |
| 375 // into a shared function ui/gfx/geometry or around there. | |
| 376 const int64_t x = static_cast<int64_t>(captureSize.width()) * rect.height(); | |
| 377 const int64_t y = static_cast<int64_t>(captureSize.height()) * rect.width(); | |
| 378 if (y < x) { | |
| 379 rect.ClampToCenteredSize(gfx::Size( | |
| 380 rect.width(), static_cast<int>(y / captureSize.width()))); | |
| 381 } else { | |
| 382 rect.ClampToCenteredSize(gfx::Size( | |
| 383 static_cast<int>(x / captureSize.height()), rect.height())); | |
| 384 } | |
| 385 } | 427 } |
| 428 // Ensure the bounds align with pixel boundaries. |
| 429 return gfx::ToEnclosedRect(rect).ToCGRect(); |
| 430 } |
| 386 | 431 |
| 387 return NSRectFromCGRect(rect.ToCGRect()); | 432 - (NSRect)boundsForScalingViewIn:(NSView*)container { |
| 433 NSRect bounds; |
| 434 bounds.origin = NSZeroPoint; |
| 435 |
| 436 // When in 'AutoEmbedFullscreen mode' mode, the bounds size is set to the |
| 437 // video capture resolution. See header file for more details. |
| 438 if ([self contentsInFullscreenCaptureMode]) { |
| 439 content::WebContents* const wc = fullscreenObserver_->web_contents(); |
| 440 gfx::Size captureSize = wc->GetPreferredSize(); |
| 441 DCHECK(!captureSize.IsEmpty()); |
| 442 bounds.size = captureSize.ToCGSize(); |
| 443 } else { |
| 444 bounds.size = [container bounds].size; |
| 445 } |
| 446 return bounds; |
| 388 } | 447 } |
| 389 | 448 |
| 390 - (BOOL)shouldResizeContentView { | 449 - (BOOL)shouldResizeContentView { |
| 391 return !isEmbeddingFullscreenWidget_ || !blockFullscreenResize_; | 450 return !isEmbeddingFullscreenWidget_ || !blockFullscreenResize_; |
| 392 } | 451 } |
| 393 | 452 |
| 394 - (BOOL)isPopup { | 453 - (BOOL)isPopup { |
| 395 return isPopup_; | 454 return isPopup_; |
| 396 } | 455 } |
| 397 | 456 |
| 398 @end | 457 @end |
| OLD | NEW |