Changeset 181770 in webkit
- Timestamp:
- Mar 19, 2015, 5:20:52 PM (10 years ago)
- Location:
- trunk/Source
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r181766 r181770 1 2015-03-19 Jer Noble <jer.noble@apple.com> 2 3 [WK2][Mac] Fullscreen animations with mismatched aspect ratios are "squished". 4 https://bugs.webkit.org/show_bug.cgi?id=142132 5 6 Reviewed by Tim Horton. 7 8 Add a new utility method to calculate a rect with a specific aspect ratio wrapping a smaller one. 9 10 * platform/graphics/GeometryUtilities.cpp: 11 (WebCore::smallestRectWithAspectRatioAroundRect): 12 * platform/graphics/GeometryUtilities.h: 13 1 14 2015-03-19 Chris Dumez <cdumez@apple.com> 2 15 -
trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp
r181515 r181770 133 133 } 134 134 135 FloatRect smallestRectWithAspectRatioAroundRect(float aspectRatio, const FloatRect& srcRect) 136 { 137 FloatRect destRect = srcRect; 138 139 if (aspectRatio < srcRect.size().aspectRatio()) { 140 float dy = destRect.width() / aspectRatio - destRect.height(); 141 destRect.inflateY(dy / 2); 142 } else { 143 float dx = destRect.height() * aspectRatio - destRect.width(); 144 destRect.inflateX(dx / 2); 145 } 146 return destRect; 135 147 } 148 149 } -
trunk/Source/WebCore/platform/graphics/GeometryUtilities.h
r181515 r181770 47 47 48 48 WEBCORE_EXPORT FloatRect largestRectWithAspectRatioInsideRect(float aspectRatio, const FloatRect&); 49 WEBCORE_EXPORT FloatRect smallestRectWithAspectRatioAroundRect(float aspectRatio, const FloatRect&); 49 50 50 51 // Compute a rect that encloses all points covered by the given rect if it were rotated a full turn around (0,0). -
trunk/Source/WebKit2/ChangeLog
r181760 r181770 1 2015-03-19 Jer Noble <jer.noble@apple.com> 2 3 [WK2][Mac] Fullscreen animations with mismatched aspect ratios are "squished". 4 https://bugs.webkit.org/show_bug.cgi?id=142132 5 6 Reviewed by Tim Horton. 7 8 Use CALayer animations for the transition into and out of fullscreen. 9 10 The fullscreen transition consists of three separate animations: 11 1. An opacity animation for the black backdrop behind the fullscreen content 12 2. A scale/translation animation from fullscreen element's initial screen to its final one. 13 3. A clip animation from the fullscreen element's initial aspect ratio to its final one. 14 15 The opacity animation will apply to the fullscreen window's content view's layer's 16 background color. To separately animate the transform and mask of the web view's content, a 17 layer-backed subview is added to the content view, and the scale/translation & clip 18 animations are applied to its transform property and mask layer respectively. 19 20 Utility methods to create each animation have been added, and each includes a parameter for 21 the direction of the animation, so that the same methods can be used for entering and 22 exiting fullscreen transitions. 23 24 The user-visible changes to this new transition are when the aspect ratios of the initial 25 and final screen locations are different: previously the transition would use a scale 26 transform to "squish" the fullscreen content into the initial aspect ratio. The new 27 transition instead "clips" the fullscreen content to the initial aspect ratio. For common 28 operations such a <video> element with a different aspect ratio than the screen, this makes 29 the black letterbox "grow" during the transition, and makes the transition overall much 30 smoother. 31 32 * UIProcess/mac/WKFullScreenWindowController.h: 33 * UIProcess/mac/WKFullScreenWindowController.mm: 34 (-[WKFullScreenWindowController initWithWindow:webView:]): Create and initialze the clipping view. 35 (-[WKFullScreenWindowController applicationDidChangeScreenParameters:]): _backgroundWindow was removed. 36 (-[WKFullScreenWindowController enterFullScreen:]): Add the webView to the _clipView, not the contentView. 37 (-[WKFullScreenWindowController beganEnterFullScreenWithInitialFrame:finalFrame:]): _backgroundWindow, 38 _fadeAnimation, and _scaleAnimation are all removed. 39 (-[WKFullScreenWindowController finishedEnterFullScreenAnimation:]): Ditto. 40 (-[WKFullScreenWindowController finishedExitFullScreenAnimation:]): Ditto. Hide the contentView's 41 layer. Pause visibility updates. 42 (-[WKFullScreenWindowController completeFinishExitFullScreenAnimationAfterRepaint]): Resume visibility updates. 43 (-[WKFullScreenWindowController close]): _fadeAnimation and _scaleAnimation are removed. 44 (-[WKFullScreenWindowController customWindowsToEnterFullScreenForWindow:]): Return only the fullscreen 45 window. 46 (-[WKFullScreenWindowController customWindowsToExitFullScreenForWindow:]): Ditto. 47 (zoomAnimation): Added. 48 (maskAnimation): Added. 49 (fadeAnimation): Added. 50 (-[WKFullScreenWindowController _startEnterFullScreenAnimationWithDuration:]): Use the utility 51 methods above to set up the animation. 52 (-[WKFullScreenWindowController _startExitFullScreenAnimationWithDuration:]): Ditto. 53 (createBackgroundFullscreenWindow): Deleted. 54 (windowFrameFromApparentFrames): Deleted. 55 1 56 2015-03-19 Enrica Casucci <enrica@apple.com> 2 57 -
trunk/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.h
r180885 r181770 40 40 @class WKView; 41 41 @class WebCoreFullScreenPlaceholderView; 42 @class WebWindowScaleAnimation;43 @class WebWindowFadeAnimation;44 42 45 43 typedef enum FullScreenState : NSInteger FullScreenState; … … 49 47 WKView *_webView; // Cannot be retained, see <rdar://problem/14884666>. 50 48 RetainPtr<WebCoreFullScreenPlaceholderView> _webViewPlaceholder; 51 RetainPtr<WebWindowScaleAnimation> _scaleAnimation; 52 RetainPtr<WebWindowFadeAnimation> _fadeAnimation; 53 RetainPtr<NSWindow> _backgroundWindow; 49 RetainPtr<NSView> _clipView; 54 50 NSRect _initialFrame; 55 51 NSRect _finalFrame; -
trunk/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.mm
r181607 r181770 39 39 #import <WebCore/DisplaySleepDisabler.h> 40 40 #import <WebCore/FloatRect.h> 41 #import <WebCore/GeometryUtilities.h> 41 42 #import <WebCore/IntRect.h> 42 43 #import <WebCore/LocalizedStrings.h> 43 44 #import <WebCore/WebCoreFullScreenPlaceholderView.h> 44 45 #import <WebCore/WebCoreFullScreenWindow.h> 45 #import <WebCore/WebWindowAnimation.h>46 #import <WebKitSystemInterface.h>47 46 48 47 using namespace WebKit; 49 48 using namespace WebCore; 50 51 static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame);52 49 53 50 static const NSTimeInterval DefaultWatchdogTimerInterval = 1; … … 97 94 [window setDelegate:self]; 98 95 [window setCollectionBehavior:([window collectionBehavior] | NSWindowCollectionBehaviorFullScreenPrimary)]; 96 97 NSView *contentView = [window contentView]; 98 contentView.wantsLayer = YES; 99 contentView.layer.hidden = YES; 100 contentView.autoresizesSubviews = YES; 101 102 _clipView = adoptNS([[NSView alloc] initWithFrame:contentView.bounds]); 103 [_clipView setWantsLayer:YES]; 104 [_clipView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 105 CALayer *maskLayer = [CALayer layer]; 106 maskLayer.anchorPoint = CGPointZero; 107 maskLayer.frame = contentView.bounds; 108 maskLayer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); 109 [_clipView layer].mask = maskLayer; 110 [contentView addSubview:_clipView.get()]; 111 99 112 [self windowDidLoad]; 100 113 _webView = webView; … … 172 185 NSRect screenFrame = [[window screen] frame]; 173 186 [window setFrame:screenFrame display:YES]; 174 [_backgroundWindow setFrame:screenFrame display:YES];175 187 } 176 188 … … 248 260 // Then insert the WebView into the full screen window 249 261 NSView* contentView = [[self window] contentView]; 250 [ contentView addSubview:_webView positioned:NSWindowBelow relativeTo:nil];262 [_clipView addSubview:_webView positioned:NSWindowBelow relativeTo:nil]; 251 263 [_webView setFrame:[contentView bounds]]; 252 264 … … 267 279 _initialFrame = initialFrame; 268 280 _finalFrame = finalFrame; 269 270 if (!_backgroundWindow)271 _backgroundWindow = createBackgroundFullscreenWindow(NSZeroRect);272 273 // The -orderBack: call below can cause the full screen window's contents to draw on top of274 // all other visible windows on the screen, despite NSDisableScreenUpdates having been set, and275 // despite being explicitly ordered behind all other windows. Set the initial scaled frame here276 // before ordering the window on-screen to avoid this flash. <rdar://problem/18325063>277 WKWindowSetScaledFrame(self.window, initialFrame, finalFrame);278 281 279 282 [self.window orderBack: self]; // Make sure the full screen window is part of the correct Space. … … 294 297 [self _manager]->setAnimatingFullScreen(false); 295 298 296 NSRect windowBounds = [[self window] frame];297 windowBounds.origin = NSZeroPoint;298 WKWindowSetClipRect([self window], windowBounds);299 300 [_fadeAnimation stopAnimation];301 [_fadeAnimation setWindow:nil];302 _fadeAnimation = nullptr;303 304 [_backgroundWindow orderOut:self];305 [_backgroundWindow setFrame:NSZeroRect display:YES];306 307 299 [_webViewPlaceholder setExitWarningVisible:YES]; 308 300 [_webViewPlaceholder setTarget:self]; … … 311 303 _fullScreenState = NotInFullScreen; 312 304 313 [_scaleAnimation stopAnimation];314 315 [_backgroundWindow orderOut:self];316 [_backgroundWindow setFrame:NSZeroRect display:YES];317 318 305 [[self window] setAutodisplay:YES]; 319 306 [_webView _setSuppressVisibilityUpdates:NO]; … … 387 374 // Screen updates to be re-enabled in completeFinishExitFullScreenAnimationAfterRepaint. 388 375 NSDisableScreenUpdates(); 376 [_webView _setSuppressVisibilityUpdates:YES]; 377 [[self window] orderOut:self]; 378 NSView *contentView = [[self window] contentView]; 379 contentView.layer.hidden = YES; 389 380 [[_webViewPlaceholder window] setAutodisplay:NO]; 390 381 … … 392 383 [self _replaceView:_webViewPlaceholder.get() with:_webView]; 393 384 makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView); 394 395 [[self window] orderOut:self];396 397 NSRect windowBounds = [[self window] frame];398 windowBounds.origin = NSZeroPoint;399 WKWindowSetClipRect([self window], windowBounds);400 [[self window] setFrame:NSZeroRect display:YES];401 402 [_scaleAnimation stopAnimation];403 [_scaleAnimation setWindow:nil];404 _scaleAnimation = nullptr;405 406 [_fadeAnimation stopAnimation];407 [_fadeAnimation setWindow:nil];408 _fadeAnimation = nullptr;409 410 [_backgroundWindow orderOut:self];411 [_backgroundWindow setFrame:NSZeroRect display:YES];412 385 413 386 [[_webView window] makeKeyAndOrderFront:self]; … … 436 409 [[_webView window] setAutodisplay:YES]; 437 410 [[_webView window] displayIfNeeded]; 411 [_webView _setSuppressVisibilityUpdates:NO]; 438 412 NSEnableScreenUpdates(); 439 413 } … … 457 431 [self finishedExitFullScreenAnimation:YES]; 458 432 459 [_scaleAnimation stopAnimation];460 [_scaleAnimation setWindow:nil];461 [_fadeAnimation stopAnimation];462 [_fadeAnimation setWindow:nil];463 464 433 _webView = nil; 465 434 … … 472 441 - (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window 473 442 { 474 return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil];443 return @[self.window]; 475 444 } 476 445 477 446 - (NSArray *)customWindowsToExitFullScreenForWindow:(NSWindow *)window 478 447 { 479 return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil];448 return @[self.window]; 480 449 } 481 450 … … 538 507 } 539 508 540 static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame) 541 { 542 NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 543 [window setOpaque:YES]; 544 [window setBackgroundColor:[NSColor blackColor]]; 545 [window setReleasedWhenClosed:NO]; 546 return adoptNS(window); 547 } 548 549 static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFrame, NSRect finalFrame) 550 { 551 NSRect initialWindowFrame; 552 if (!NSWidth(initialFrame) || !NSWidth(finalFrame) || !NSHeight(initialFrame) || !NSHeight(finalFrame)) 553 return screenFrame; 554 555 CGFloat xScale = NSWidth(screenFrame) / NSWidth(finalFrame); 556 CGFloat yScale = NSHeight(screenFrame) / NSHeight(finalFrame); 557 CGFloat xTrans = NSMinX(screenFrame) - NSMinX(finalFrame); 558 CGFloat yTrans = NSMinY(screenFrame) - NSMinY(finalFrame); 559 initialWindowFrame.size = NSMakeSize(NSWidth(initialFrame) * xScale, NSHeight(initialFrame) * yScale); 560 initialWindowFrame.origin = NSMakePoint 561 ( NSMinX(initialFrame) + xTrans / (NSWidth(finalFrame) / NSWidth(initialFrame)) 562 , NSMinY(initialFrame) + yTrans / (NSHeight(finalFrame) / NSHeight(initialFrame))); 563 return initialWindowFrame; 509 enum AnimationDirection { AnimateIn, AnimateOut }; 510 static CAAnimation *zoomAnimation(const FloatRect& initialFrame, const FloatRect& finalFrame, CFTimeInterval duration, AnimationDirection direction) 511 { 512 CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; 513 FloatRect scaleRect = smallestRectWithAspectRatioAroundRect(finalFrame.size().aspectRatio(), initialFrame); 514 CGAffineTransform resetOriginTransform = CGAffineTransformMakeTranslation(-finalFrame.x(), -finalFrame.y()); 515 CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleRect.width() / finalFrame.width(), scaleRect.height() / finalFrame.height()); 516 CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(scaleRect.x(), scaleRect.y()); 517 518 CGAffineTransform finalTransform = CGAffineTransformConcat(CGAffineTransformConcat(resetOriginTransform, scaleTransform), translateTransform); 519 NSValue *scaleValue = [NSValue valueWithCATransform3D:CATransform3DMakeAffineTransform(finalTransform)]; 520 if (direction == AnimateIn) 521 scaleAnimation.fromValue = scaleValue; 522 else 523 scaleAnimation.toValue = scaleValue; 524 525 scaleAnimation.duration = duration; 526 scaleAnimation.removedOnCompletion = NO; 527 scaleAnimation.fillMode = kCAFillModeBoth; 528 scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 529 return scaleAnimation; 530 } 531 532 static CAAnimation *maskAnimation(const FloatRect& initialFrame, const FloatRect& finalFrame, CFTimeInterval duration, AnimationDirection direction) 533 { 534 CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"]; 535 FloatRect boundsRect = largestRectWithAspectRatioInsideRect(initialFrame.size().aspectRatio(), finalFrame); 536 NSValue *boundsValue = [NSValue valueWithRect:FloatRect(FloatPoint(), boundsRect.size())]; 537 if (direction == AnimateIn) 538 boundsAnimation.fromValue = boundsValue; 539 else 540 boundsAnimation.toValue = boundsValue; 541 542 CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position"]; 543 NSValue *positionValue = [NSValue valueWithPoint:boundsRect.location()]; 544 if (direction == AnimateIn) 545 positionAnimation.fromValue = positionValue; 546 else 547 positionAnimation.toValue = positionValue; 548 549 CAAnimationGroup *animation = [CAAnimationGroup animation]; 550 animation.animations = @[boundsAnimation, positionAnimation]; 551 animation.duration = duration; 552 animation.removedOnCompletion = NO; 553 animation.fillMode = kCAFillModeBoth; 554 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 555 return animation; 556 } 557 558 static CAAnimation *fadeAnimation(CFTimeInterval duration, AnimationDirection direction) 559 { 560 CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 561 if (direction == AnimateIn) 562 fadeAnimation.toValue = (id)CGColorGetConstantColor(kCGColorBlack); 563 else 564 fadeAnimation.fromValue = (id)CGColorGetConstantColor(kCGColorBlack); 565 fadeAnimation.duration = duration; 566 fadeAnimation.removedOnCompletion = NO; 567 fadeAnimation.fillMode = kCAFillModeBoth; 568 fadeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 569 return fadeAnimation; 564 570 } 565 571 566 572 - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration 567 573 { 568 NSRect screenFrame = [[[self window] screen] frame]; 569 NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); 570 571 _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:initialWindowFrame finalFrame:screenFrame]); 572 573 [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 574 [_scaleAnimation setCurrentProgress:0]; 575 [_scaleAnimation startAnimation]; 576 577 // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: 578 NSRect finalBounds = _finalFrame; 579 #pragma clang diagnostic push 580 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 581 finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; 582 #pragma clang diagnostic pop 583 WKWindowSetClipRect([self window], finalBounds); 574 [[_clipView layer] addAnimation:zoomAnimation(_initialFrame, _finalFrame, duration, AnimateIn) forKey:@"fullscreen"]; 575 [[_clipView layer].mask addAnimation:maskAnimation(_initialFrame, _finalFrame, duration, AnimateIn) forKey:@"fullscreen"]; 576 577 NSView* contentView = [[self window] contentView]; 578 contentView.layer.hidden = NO; 579 [contentView.layer addAnimation:fadeAnimation(duration, AnimateIn) forKey:@"fullscreen"]; 584 580 585 581 NSWindow* window = [self window]; … … 588 584 [window makeKeyAndOrderFront:self]; 589 585 [window setCollectionBehavior:behavior]; 590 591 592 if (!_backgroundWindow)593 _backgroundWindow = createBackgroundFullscreenWindow(screenFrame);594 else595 [_backgroundWindow setFrame:screenFrame display:NO];596 597 CGFloat currentAlpha = 0;598 if (_fadeAnimation) {599 currentAlpha = [_fadeAnimation currentAlpha];600 [_fadeAnimation stopAnimation];601 [_fadeAnimation setWindow:nil];602 }603 604 _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration605 window:_backgroundWindow.get()606 initialAlpha:currentAlpha607 finalAlpha:1]);608 [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking];609 [_fadeAnimation setCurrentProgress:0];610 [_fadeAnimation startAnimation];611 612 [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];613 586 614 587 [_webView _setSuppressVisibilityUpdates:NO]; … … 628 601 } 629 602 630 NSRect screenFrame = [[[self window] screen] frame]; 631 NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); 632 633 NSRect currentFrame = _scaleAnimation ? [_scaleAnimation currentFrame] : [[self window] frame]; 634 _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:currentFrame finalFrame:initialWindowFrame]); 635 636 [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 637 [_scaleAnimation setCurrentProgress:0]; 638 [_scaleAnimation startAnimation]; 639 640 if (!_backgroundWindow) 641 _backgroundWindow = createBackgroundFullscreenWindow(screenFrame); 642 else 643 [_backgroundWindow setFrame:screenFrame display:NO]; 644 645 CGFloat currentAlpha = 1; 646 if (_fadeAnimation) { 647 currentAlpha = [_fadeAnimation currentAlpha]; 648 [_fadeAnimation stopAnimation]; 649 [_fadeAnimation setWindow:nil]; 650 } 651 _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration 652 window:_backgroundWindow.get() 653 initialAlpha:currentAlpha 654 finalAlpha:0]); 655 [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 656 [_fadeAnimation setCurrentProgress:0]; 657 [_fadeAnimation startAnimation]; 658 659 [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; 660 661 // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: 662 NSRect finalBounds = _finalFrame; 663 #pragma clang diagnostic push 664 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 665 finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; 666 #pragma clang diagnostic pop 667 WKWindowSetClipRect([self window], finalBounds); 603 [[_clipView layer] addAnimation:zoomAnimation(_initialFrame, _finalFrame, duration, AnimateOut) forKey:@"fullscreen"]; 604 [[_clipView layer].mask addAnimation:maskAnimation(_initialFrame, _finalFrame, duration, AnimateOut) forKey:@"fullscreen"]; 605 606 NSView* contentView = [[self window] contentView]; 607 contentView.layer.hidden = NO; 608 [contentView.layer addAnimation:fadeAnimation(duration, AnimateOut) forKey:@"fullscreen"]; 668 609 669 610 [_webView _setSuppressVisibilityUpdates:NO];
Note:
See TracChangeset
for help on using the changeset viewer.