From e0480417e2113a881182583a8d205ebe0738e4ce Mon Sep 17 00:00:00 2001 From: kkhorimoto Date: Mon, 8 Jun 2015 14:47:52 -0700 Subject: Fixed zoom scale rotation bugs. The percentage into the available zoom scale ranges for the scroll views must be maintained after orientation changes. These bugs occur when pages specify hardcoded values for their viewport widths. In UIWebView, rotation that occurs after zooming has occurred will not trigger a relayout of the scroll view's zoom scales. Similarly, WKWebView will not be zoomed properly after a rotation that occurs after a pinch gesture. BUG=462393, 488766 TEST= WKWebView: load en.wikipedia.org, pinch in and release so that the zoom bounces back to 1.0, then rotate the device. The scale should remain at 1.0. UIWebView: load www.reddit.com, pinch in, and release so the zoom bounces back, then rotate the device. The page should be zoomed in to fit with landscape width. Review URL: https://codereview.chromium.org/1154163011 Cr-Commit-Position: refs/heads/master@{#333351} --- ios/web/public/web_state/page_scroll_state.h | 5 +++ ios/web/web_state/ui/crw_web_controller.mm | 57 +++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 6 deletions(-) (limited to 'ios/web') diff --git a/ios/web/public/web_state/page_scroll_state.h b/ios/web/public/web_state/page_scroll_state.h index 9984019..b68598a 100644 --- a/ios/web/public/web_state/page_scroll_state.h +++ b/ios/web/public/web_state/page_scroll_state.h @@ -39,6 +39,11 @@ class PageScrollState { // can only be applied to CRWUIWebViewWebControllers. bool IsZoomScaleLegacyFormat() const; + // Returns the allowed zoom scale range for this scroll state. + double GetMinMaxZoomDifference() const { + return maximum_zoom_scale_ - minimum_zoom_scale_; + } + // Accessors for scroll offsets and zoom scale. double scroll_offset_x() const { return scroll_offset_x_; } void set_scroll_offset_x(double scroll_offset_x) { diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index c566bf0..1be4d7c 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm @@ -298,6 +298,11 @@ void CancelAllTouches(UIScrollView* web_scroll_view) { - (NSString*)javascriptToReplaceWebViewURL:(const GURL&)url stateObjectJSON:(NSString*)stateObject; - (BOOL)isLoaded; +// Called by NSNotificationCenter upon orientation changes. +- (void)orientationDidChange; +// Queries the web view for the user-scalable meta tag and calls +// |-applyPageScrollState:userScalable:| with the result. +- (void)applyPageScrollState:(const web::PageScrollState&)scrollState; // Restores state of the web view's scroll view from |scrollState|. // |isUserScalable| represents the value of user-scalable meta tag. - (void)applyPageScrollState:(const web::PageScrollState&)scrollState @@ -580,6 +585,11 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5; _gestureRecognizers.reset([[NSMutableArray alloc] init]); _webViewToolbars.reset([[NSMutableArray alloc] init]); _pendingLoadCompleteActions.reset([[NSMutableArray alloc] init]); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(orientationDidChange) + name:UIApplicationDidChangeStatusBarOrientationNotification + object:nil]; } return self; } @@ -678,6 +688,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5; DCHECK(_isBeingDestroyed); // 'close' must have been called already. DCHECK(!self.webView); _touchTrackingRecognizer.get().touchTrackingDelegate = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } @@ -3301,16 +3312,50 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5; _scrollStateOnStartLoading.scroll_offset_y() && [self absoluteZoomScaleForScrollState:currentScrollState] == [self absoluteZoomScaleForScrollState:_scrollStateOnStartLoading]) { - base::WeakNSObject weakSelf(self); - [self queryUserScalableProperty:^(BOOL isUserScalable) { - base::scoped_nsobject strongSelf([weakSelf retain]); - [strongSelf applyPageScrollState:pageScrollState - userScalable:isUserScalable]; - }]; + [self applyPageScrollState:pageScrollState]; } } } +- (void)orientationDidChange { + // When rotating, the available zoom scale range may change, zoomScale's + // percentage into this range should remain constant. However, there are + // two known bugs with respect to adjusting the zoomScale on rotation: + // - WKWebView sometimes erroneously resets the scroll view's zoom scale to + // an incorrect value ( rdar://20100815 ). + // - After zooming occurs in a UIWebView that's displaying a page with a hard- + // coded viewport width, the zoom will not be updated upon rotation + // ( crbug.com/485055 ). + if (!self.webView) + return; + web::NavigationItem* currentItem = self.currentNavItem; + if (!currentItem) + return; + web::PageScrollState scrollState = currentItem->GetPageScrollState(); + if (!scrollState.IsValid()) + return; + CGFloat zoomPercentage = + (scrollState.zoom_scale() - scrollState.minimum_zoom_scale()) / + scrollState.GetMinMaxZoomDifference(); + scrollState.set_minimum_zoom_scale(self.webScrollView.minimumZoomScale); + scrollState.set_maximum_zoom_scale(self.webScrollView.maximumZoomScale); + scrollState.set_zoom_scale(scrollState.minimum_zoom_scale() + + zoomPercentage * + scrollState.GetMinMaxZoomDifference()); + currentItem->SetPageScrollState(scrollState); + [self applyPageScrollState:currentItem->GetPageScrollState()]; +} + +- (void)applyPageScrollState:(const web::PageScrollState&)scrollState { + if (!scrollState.IsValid()) + return; + base::WeakNSObject weakSelf(self); + [self queryUserScalableProperty:^(BOOL isUserScalable) { + base::scoped_nsobject strongSelf([weakSelf retain]); + [strongSelf applyPageScrollState:scrollState userScalable:isUserScalable]; + }]; +} + - (void)applyPageScrollState:(const web::PageScrollState&)scrollState userScalable:(BOOL)isUserScalable { DCHECK(scrollState.IsValid()); -- cgit v1.1