[iOS WK2] Fixed elements can go outside the document on pinching
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 10 May 2014 00:11:26 +0000 (00:11 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 10 May 2014 00:11:26 +0000 (00:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=132759
<rdar://problem/16870835>

Reviewed by Benjamin Poulain.

Constrain the rect used to position fixed position objects when pinching (when
the scale goes below the minimumScale). Do so in such a way that there's a smooth
transition between rubber-banding and pinching.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _updateScrollViewBackground]): Use a nicer form for std::max<>.
(-[WKWebView _updateVisibleContentRects]): Pass the minimum scale.
* UIProcess/API/ios/WKViewIOS.mm:
(-[WKView _updateVisibleContentRects]): Ditto.
* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(adjustedUnexposedEdge): Helper to adjust the left/top.
(adjustedUnexposedMaxEdge): Helper to adjust the right/bottom.
(fixedPositionRectFromExposedRect):
(-[WKContentView didUpdateVisibleRect:unobscuredRect:scale:minimumScale:inStableState:]):
(-[WKContentView didUpdateVisibleRect:unobscuredRect:scale:inStableState:]): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@168560 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/ios/WKViewIOS.mm
Source/WebKit2/UIProcess/ios/WKContentView.h
Source/WebKit2/UIProcess/ios/WKContentView.mm

index 452a2da..a284fe7 100644 (file)
@@ -1,3 +1,28 @@
+2014-05-09  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] Fixed elements can go outside the document on pinching
+        https://bugs.webkit.org/show_bug.cgi?id=132759
+        <rdar://problem/16870835>
+
+        Reviewed by Benjamin Poulain.
+        
+        Constrain the rect used to position fixed position objects when pinching (when
+        the scale goes below the minimumScale). Do so in such a way that there's a smooth
+        transition between rubber-banding and pinching.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _updateScrollViewBackground]): Use a nicer form for std::max<>.
+        (-[WKWebView _updateVisibleContentRects]): Pass the minimum scale.
+        * UIProcess/API/ios/WKViewIOS.mm:
+        (-[WKView _updateVisibleContentRects]): Ditto.
+        * UIProcess/ios/WKContentView.h:
+        * UIProcess/ios/WKContentView.mm:
+        (adjustedUnexposedEdge): Helper to adjust the left/top.
+        (adjustedUnexposedMaxEdge): Helper to adjust the right/bottom.
+        (fixedPositionRectFromExposedRect):
+        (-[WKContentView didUpdateVisibleRect:unobscuredRect:scale:minimumScale:inStableState:]):
+        (-[WKContentView didUpdateVisibleRect:unobscuredRect:scale:inStableState:]): Deleted.
+
 2014-05-09  Zalan Bujtas  <zalan@apple.com>
 
         Subpixel rendering[iOS]: Top bar on apple.com/support jiggles when the swoosh animates.
index 0aeae92..0bc8423 100644 (file)
@@ -447,7 +447,7 @@ static CGFloat contentZoomScale(WKWebView* webView)
     CGFloat minimumZoomScale = [_scrollView minimumZoomScale];
     if (zoomScale < minimumZoomScale) {
         CGFloat slope = 12;
-        CGFloat opacity = std::max(1 - slope * (minimumZoomScale - zoomScale), static_cast<CGFloat>(0));
+        CGFloat opacity = std::max<CGFloat>(1 - slope * (minimumZoomScale - zoomScale), 0);
         cgColor = adoptCF(CGColorCreateCopyWithAlpha(cgColor.get(), opacity));
     }
     RetainPtr<UIColor*> uiBackgroundColor = adoptNS([[UIColor alloc] initWithCGColor:cgColor.get()]);
@@ -779,7 +779,11 @@ static inline void setViewportConfigurationMinimumLayoutSize(WebKit::WebPageProx
     CGFloat scaleFactor = contentZoomScale(self);
 
     BOOL isStableState = !(_isChangingObscuredInsetsInteractively || [_scrollView isDragging] || [_scrollView isDecelerating] || [_scrollView isZooming] || [_scrollView isZoomBouncing] || [_scrollView _isAnimatingZoom]);
-    [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates unobscuredRect:unobscuredRectInContentCoordinates unobscuredRectInScrollViewCoordinates:unobscuredRect scale:scaleFactor inStableState:isStableState isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively];
+    [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates
+        unobscuredRect:unobscuredRectInContentCoordinates
+        unobscuredRectInScrollViewCoordinates:unobscuredRect
+        scale:scaleFactor minimumScale:[_scrollView minimumZoomScale]
+        inStableState:isStableState isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively];
 }
 
 - (void)_keyboardChangedWithInfo:(NSDictionary *)keyboardInfo adjustScrollView:(BOOL)adjustScrollView
index 2770621..fd986bf 100644 (file)
@@ -261,9 +261,11 @@ using namespace WebKit;
     CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, _obscuredInsets);
     CGRect unobscuredRectInContentCoordinates = [self convertRect:unobscuredRect toView:_contentView.get()];
 
-    CGFloat scaleFactor = [_scrollView zoomScale];
-
-    [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates unobscuredRect:unobscuredRectInContentCoordinates unobscuredRectInScrollViewCoordinates:unobscuredRect scale:scaleFactor inStableState:YES isChangingObscuredInsetsInteractively:NO];
+    [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates
+        unobscuredRect:unobscuredRectInContentCoordinates
+        unobscuredRectInScrollViewCoordinates:unobscuredRect
+        scale:[_scrollView zoomScale] minimumScale:[_scrollView minimumZoomScale]
+        inStableState:YES isChangingObscuredInsetsInteractively:NO];
 }
 
 - (void)_keyboardChangedWithInfo:(NSDictionary *)keyboardInfo adjustScrollView:(BOOL)adjustScrollView
index 5eecfe0..5bd99b3 100644 (file)
@@ -60,7 +60,10 @@ struct WebPageConfiguration;
 - (instancetype)initWithFrame:(CGRect)frame context:(WebKit::WebContext&)context configuration:(WebKit::WebPageConfiguration)webPageConfiguration webView:(WKWebView *)webView;
 
 - (void)setMinimumSize:(CGSize)size;
-- (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates scale:(CGFloat)scale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively;
+- (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect
+    unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
+    scale:(CGFloat)scale minimumScale:(CGFloat)minimumScale
+    inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively;
 
 - (void)didFinishScrolling;
 - (void)didZoomToScale:(CGFloat)scale;
index 7bb0c61..f284c3b 100644 (file)
@@ -292,12 +292,42 @@ private:
     }
 }
 
-static inline FloatRect fixedPositionRectFromExposedRect(CGRect unobscuredRect, CGSize documentSize, CGFloat scale)
+static inline float adjustedUnexposedEdge(float documentEdge, float exposedRectEdge, float factor)
 {
-    return FrameView::rectForViewportConstrainedObjects(enclosingLayoutRect(unobscuredRect), roundedLayoutSize(FloatSize(documentSize)), scale, false, StickToViewportBounds);
+    if (exposedRectEdge < documentEdge)
+        return documentEdge - factor * (documentEdge - exposedRectEdge);
+    
+    return exposedRectEdge;
+}
+
+static inline float adjustedUnexposedMaxEdge(float documentEdge, float exposedRectEdge, float factor)
+{
+    if (exposedRectEdge > documentEdge)
+        return documentEdge + factor * (exposedRectEdge - documentEdge);
+    
+    return exposedRectEdge;
+}
+
+static inline FloatRect fixedPositionRectFromExposedRect(CGRect unobscuredRect, CGSize documentSize, CGFloat scale, CGFloat minimumScale)
+{
+    FloatRect constrainedUnobscuredRect = unobscuredRect;
+    FloatRect documentRect = FloatRect(FloatPoint(), FloatSize(documentSize));
+    
+    if (scale < minimumScale) {
+        const CGFloat slope = 12;
+        CGFloat factor = std::max<CGFloat>(1 - slope * (minimumScale - scale), 0);
+            
+        constrainedUnobscuredRect.setX(adjustedUnexposedEdge(documentRect.x(), constrainedUnobscuredRect.x(), factor));
+        constrainedUnobscuredRect.setY(adjustedUnexposedEdge(documentRect.y(), constrainedUnobscuredRect.y(), factor));
+        constrainedUnobscuredRect.setWidth(adjustedUnexposedMaxEdge(documentRect.maxX(), constrainedUnobscuredRect.maxX(), factor) - constrainedUnobscuredRect.x());
+        constrainedUnobscuredRect.setHeight(adjustedUnexposedMaxEdge(documentRect.maxY(), constrainedUnobscuredRect.maxY(), factor) - constrainedUnobscuredRect.y());
+    }
+    
+    return FrameView::rectForViewportConstrainedObjects(enclosingLayoutRect(constrainedUnobscuredRect), roundedLayoutSize(FloatSize(documentSize)), scale, false, StickToViewportBounds);
 }
 
-- (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates scale:(CGFloat)zoomScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively
+- (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
+    scale:(CGFloat)zoomScale minimumScale:(CGFloat)minimumScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively
 {
     double timestamp = monotonicallyIncreasingTime();
     HistoricalVelocityData::VelocityData velocityData;
@@ -314,11 +344,11 @@ static inline FloatRect fixedPositionRectFromExposedRect(CGRect unobscuredRect,
         filteredScale = _page->displayedContentScale();
     }
 
-    FloatRect customFixedPositionRect = fixedPositionRectFromExposedRect(unobscuredRect, [self bounds].size, zoomScale);
+    FloatRect customFixedPositionRect = fixedPositionRectFromExposedRect(unobscuredRect, [self bounds].size, zoomScale, minimumScale);
     _page->updateVisibleContentRects(VisibleContentRectUpdateInfo(_page->nextVisibleContentRectUpdateID(), visibleRect, unobscuredRect, unobscuredRectInScrollViewCoordinates, customFixedPositionRect, filteredScale, isStableState, isChangingObscuredInsetsInteractively, timestamp, velocityData.horizontalVelocity, velocityData.verticalVelocity, velocityData.scaleChangeRate));
     
     RemoteScrollingCoordinatorProxy* scrollingCoordinator = _page->scrollingCoordinatorProxy();
-    scrollingCoordinator->viewportChangedViaDelegatedScrolling(scrollingCoordinator->rootScrollingNodeID(), unobscuredRect, zoomScale);
+    scrollingCoordinator->viewportChangedViaDelegatedScrolling(scrollingCoordinator->rootScrollingNodeID(), customFixedPositionRect, zoomScale);
 
     if (auto drawingArea = _page->drawingArea())
         drawingArea->updateDebugIndicator();