- Revision
- 174232
- Author
- [email protected]
- Date
- 2014-10-02 14:51:14 -0700 (Thu, 02 Oct 2014)
Log Message
[iOS] Teach WKPDFView to navigate to pageNumber links
https://bugs.webkit.org/show_bug.cgi?id=137358
Reviewed by Tim Horton.
Treat PDF pageNumber annotations as if they were fragment navigations in an HTML document. For a given page
number N, create a fragment called "#pageN" and tell WebKit to navigate to it. By doing this we create history
entries for each pageNumber navigation and allow for proper back/forward. When navigating to a page, reset to
the initial scale factor and scroll to the beginning of the Nth page.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _zoomToPoint:atScale:animated:]): Added an animated parameter. If animated is NO, use a duration of 0.
(-[WKWebView _zoomToRect:atScale:origin:animated:]): Added an animated parameter and passed it to _zoomToPoint:atScale:animated:.
(-[WKWebView _zoomOutWithOrigin:animated:]): Ditto.
(-[WKWebView _zoomToRect:withOrigin:fitEntireRect:minimumScale:maximumScale:minimumScrollDistance:]): Called _zoomToRect:atScale:origin:animated:,
setting animated to YES.
(-[WKWebView _didSameDocumentNavigationForMainFrame:]): Called web_didSameDocumentNavigation: on _customContentView.
(-[WKWebView _zoomToPoint:atScale:]): Deleted.
(-[WKWebView _zoomToRect:atScale:origin:]): Deleted.
(-[WKWebView _zoomOutWithOrigin:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/Cocoa/WKWebViewContentProvider.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::didSameDocumentNavigationForMainFrame): Called _didSameDocumentNavigationForMainFrame on m_webView.
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _zoomOutWithOrigin:]): Called _zoomOutWithOrigin:animated: on m_webView, setting animated to YES.
* UIProcess/ios/WKPDFPageNumberIndicator.h:
* UIProcess/ios/WKPDFPageNumberIndicator.mm:
(-[WKPDFPageNumberIndicator hide]): Added a method to hide the page number indicator.
* UIProcess/ios/WKPDFView.mm:
(-[WKPDFView web_setContentProviderData:suggestedFilename:]): Added a FIXME for restoring scroll position and page scale when loading from the back/forward list.
(-[WKPDFView scrollViewDidScroll:]): Stopped showing the page number indicator if a same-document navigation is occurring (to match UIWebPDFView).
(-[WKPDFView _updatePageNumberIndicator]): Ditto.
(-[WKPDFView web_didSameDocumentNavigation:]):
(-[WKPDFView _resetZoomAnimated:]): For same-document navigations of type kWKSameDocumentNavigationSessionStatePop, extracted the page index from the URL fragment
identifier, hid the page number indicator, reset the zoom (without an animation to match UIWebPDFView), and scrolled to the beginning of the given page.
(-[WKPDFView resetZoom:]): Called _resetZoomAnimated:, setting animated to YES.
(-[WKPDFView annotation:wasTouchedAtPoint:controller:]): If there is a non-zero pageNumber in the link annotation, construct a "#pageN" fragment and navigate to it.
Modified Paths
Diff
Modified: trunk/Source/WebKit2/ChangeLog (174231 => 174232)
--- trunk/Source/WebKit2/ChangeLog 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/ChangeLog 2014-10-02 21:51:14 UTC (rev 174232)
@@ -1,3 +1,44 @@
+2014-10-02 Andy Estes <[email protected]>
+
+ [iOS] Teach WKPDFView to navigate to pageNumber links
+ https://bugs.webkit.org/show_bug.cgi?id=137358
+
+ Reviewed by Tim Horton.
+
+ Treat PDF pageNumber annotations as if they were fragment navigations in an HTML document. For a given page
+ number N, create a fragment called "#pageN" and tell WebKit to navigate to it. By doing this we create history
+ entries for each pageNumber navigation and allow for proper back/forward. When navigating to a page, reset to
+ the initial scale factor and scroll to the beginning of the Nth page.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _zoomToPoint:atScale:animated:]): Added an animated parameter. If animated is NO, use a duration of 0.
+ (-[WKWebView _zoomToRect:atScale:origin:animated:]): Added an animated parameter and passed it to _zoomToPoint:atScale:animated:.
+ (-[WKWebView _zoomOutWithOrigin:animated:]): Ditto.
+ (-[WKWebView _zoomToRect:withOrigin:fitEntireRect:minimumScale:maximumScale:minimumScrollDistance:]): Called _zoomToRect:atScale:origin:animated:,
+ setting animated to YES.
+ (-[WKWebView _didSameDocumentNavigationForMainFrame:]): Called web_didSameDocumentNavigation: on _customContentView.
+ (-[WKWebView _zoomToPoint:atScale:]): Deleted.
+ (-[WKWebView _zoomToRect:atScale:origin:]): Deleted.
+ (-[WKWebView _zoomOutWithOrigin:]): Deleted.
+ * UIProcess/API/Cocoa/WKWebViewInternal.h:
+ * UIProcess/Cocoa/WKWebViewContentProvider.h:
+ * UIProcess/ios/PageClientImplIOS.mm:
+ (WebKit::PageClientImpl::didSameDocumentNavigationForMainFrame): Called _didSameDocumentNavigationForMainFrame on m_webView.
+ * UIProcess/ios/WKContentView.mm:
+ (-[WKContentView _zoomOutWithOrigin:]): Called _zoomOutWithOrigin:animated: on m_webView, setting animated to YES.
+ * UIProcess/ios/WKPDFPageNumberIndicator.h:
+ * UIProcess/ios/WKPDFPageNumberIndicator.mm:
+ (-[WKPDFPageNumberIndicator hide]): Added a method to hide the page number indicator.
+ * UIProcess/ios/WKPDFView.mm:
+ (-[WKPDFView web_setContentProviderData:suggestedFilename:]): Added a FIXME for restoring scroll position and page scale when loading from the back/forward list.
+ (-[WKPDFView scrollViewDidScroll:]): Stopped showing the page number indicator if a same-document navigation is occurring (to match UIWebPDFView).
+ (-[WKPDFView _updatePageNumberIndicator]): Ditto.
+ (-[WKPDFView web_didSameDocumentNavigation:]):
+ (-[WKPDFView _resetZoomAnimated:]): For same-document navigations of type kWKSameDocumentNavigationSessionStatePop, extracted the page index from the URL fragment
+ identifier, hid the page number indicator, reset the zoom (without an animation to match UIWebPDFView), and scrolled to the beginning of the given page.
+ (-[WKPDFView resetZoom:]): Called _resetZoomAnimated:, setting animated to YES.
+ (-[WKPDFView annotation:wasTouchedAtPoint:controller:]): If there is a non-zero pageNumber in the link annotation, construct a "#pageN" fragment and navigate to it.
+
2014-10-02 Tim Horton <[email protected]>
Move PageOverlay[Controller] to WebCore
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2014-10-02 21:51:14 UTC (rev 174232)
@@ -50,6 +50,7 @@
#import "WKNavigationInternal.h"
#import "WKPreferencesInternal.h"
#import "WKProcessPoolInternal.h"
+#import "WKSharedAPICast.h"
#import "WKUIDelegate.h"
#import "WKUIDelegatePrivate.h"
#import "WKUserContentControllerInternal.h"
@@ -973,22 +974,26 @@
return WebKit::ViewSnapshot::create(slotID, imageSize, imageSize.width() * imageSize.height() * 4);
}
-- (void)_zoomToPoint:(WebCore::FloatPoint)point atScale:(double)scale
+- (void)_zoomToPoint:(WebCore::FloatPoint)point atScale:(double)scale animated:(BOOL)animated
{
- double maximumZoomDuration = 0.4;
- double minimumZoomDuration = 0.1;
- double zoomDurationFactor = 0.3;
-
+ CFTimeInterval duration = 0;
CGFloat zoomScale = contentZoomScale(self);
- CFTimeInterval duration = std::min(fabs(log(zoomScale) - log(scale)) * zoomDurationFactor + minimumZoomDuration, maximumZoomDuration);
+ if (animated) {
+ const double maximumZoomDuration = 0.4;
+ const double minimumZoomDuration = 0.1;
+ const double zoomDurationFactor = 0.3;
+
+ duration = std::min(fabs(log(zoomScale) - log(scale)) * zoomDurationFactor + minimumZoomDuration, maximumZoomDuration);
+ }
+
if (scale != zoomScale)
_page->willStartUserTriggeredZooming();
[_scrollView _zoomToCenter:point scale:scale duration:duration];
}
-- (void)_zoomToRect:(WebCore::FloatRect)targetRect atScale:(double)scale origin:(WebCore::FloatPoint)origin
+- (void)_zoomToRect:(WebCore::FloatRect)targetRect atScale:(double)scale origin:(WebCore::FloatPoint)origin animated:(BOOL)animated
{
// FIMXE: Some of this could be shared with _scrollToRect.
const double visibleRectScaleChange = contentZoomScale(self) / scale;
@@ -1014,7 +1019,7 @@
visibleRectAfterZoom.move(-topLeftObscuredInsetAfterZoom);
visibleRectAfterZoom.expand(topLeftObscuredInsetAfterZoom + bottomRightObscuredInsetAfterZoom);
- [self _zoomToPoint:visibleRectAfterZoom.center() atScale:scale];
+ [self _zoomToPoint:visibleRectAfterZoom.center() atScale:scale animated:animated];
}
static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOffset, WebCore::FloatSize contentSize, WebCore::FloatSize unobscuredContentSize)
@@ -1087,9 +1092,9 @@
return true;
}
-- (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin
+- (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated
{
- [self _zoomToPoint:origin atScale:[_scrollView minimumZoomScale]];
+ [self _zoomToPoint:origin atScale:[_scrollView minimumZoomScale] animated:animated];
}
// focusedElementRect and selectionRect are both in document coordinates.
@@ -1229,7 +1234,7 @@
if ([self _scrollToRect:targetRect origin:origin minimumScrollDistance:minimumScrollDistance])
return true;
} else if (targetScale != currentScale) {
- [self _zoomToRect:targetRect atScale:targetScale origin:origin];
+ [self _zoomToRect:targetRect atScale:targetScale origin:origin animated:YES];
return true;
}
@@ -1436,6 +1441,11 @@
inStableState:isStableState isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively];
}
+- (void)_didSameDocumentNavigationForMainFrame:(WebKit::SameDocumentNavigationType)navigationType
+{
+ [_customContentView web_didSameDocumentNavigation:toAPI(navigationType)];
+}
+
- (void)_keyboardChangedWithInfo:(NSDictionary *)keyboardInfo adjustScrollView:(BOOL)adjustScrollView
{
NSValue *endFrameValue = [keyboardInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h 2014-10-02 21:51:14 UTC (rev 174232)
@@ -27,6 +27,7 @@
#if WK_API_ENABLED
+#import "SameDocumentNavigationType.h"
#import <wtf/RefPtr.h>
#import <wtf/RetainPtr.h>
@@ -84,7 +85,7 @@
- (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance;
- (void)_zoomToFocusRect:(WebCore::FloatRect)focusedElementRect selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll;
- (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance;
-- (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin;
+- (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated;
- (void)_setHasCustomContentView:(BOOL)hasCustomContentView loadedMIMEType:(const WTF::String&)mimeType;
- (void)_didFinishLoadingDataForCustomContentProviderWithSuggestedFilename:(const WTF::String&)suggestedFilename data:(NSData *)data;
@@ -95,6 +96,8 @@
- (void)_updateVisibleContentRects;
+- (void)_didSameDocumentNavigationForMainFrame:(WebKit::SameDocumentNavigationType)navigationType;
+
@property (nonatomic, readonly) UIEdgeInsets _computedContentInset;
#endif
@end
Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WKWebViewContentProvider.h (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/Cocoa/WKWebViewContentProvider.h 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WKWebViewContentProvider.h 2014-10-02 21:51:14 UTC (rev 174232)
@@ -29,6 +29,8 @@
#if PLATFORM(IOS)
+#import <WebKit/WKPageLoadTypes.h>
+
@class NSData;
@class UIScrollView;
@class UIView;
@@ -47,6 +49,7 @@
- (void)web_setOverlaidAccessoryViewsInset:(CGSize)inset;
- (void)web_computedContentInsetDidChange;
- (void)web_setFixedOverlayView:(UIView *)fixedOverlayView;
+- (void)web_didSameDocumentNavigation:(WKSameDocumentNavigationType)navigationType;
@end
Modified: trunk/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm 2014-10-02 21:51:14 UTC (rev 174232)
@@ -692,8 +692,9 @@
{
}
-void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType)
+void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType navigationType)
{
+ [m_webView _didSameDocumentNavigationForMainFrame:navigationType];
}
} // namespace WebKit
Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm 2014-10-02 21:51:14 UTC (rev 174232)
@@ -494,7 +494,7 @@
- (void)_zoomOutWithOrigin:(CGPoint)origin
{
- return [_webView _zoomOutWithOrigin:origin];
+ return [_webView _zoomOutWithOrigin:origin animated:YES];
}
- (void)_applicationWillResignActive:(NSNotification*)notification
Modified: trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.h (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.h 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.h 2014-10-02 21:51:14 UTC (rev 174232)
@@ -34,6 +34,7 @@
- (void)moveToPoint:(CGPoint)point animated:(BOOL)animated;
- (void)show;
+- (void)hide;
@end
Modified: trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.mm (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.mm 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/ios/WKPDFPageNumberIndicator.mm 2014-10-02 21:51:14 UTC (rev 174232)
@@ -122,6 +122,11 @@
_timer = [NSTimer scheduledTimerWithTimeInterval:indicatorTimeout target:self selector:@selector(hide:) userInfo:nil repeats:NO];
}
+- (void)hide
+{
+ [self hide:nil];
+}
+
- (void)hide:(NSTimer *)timer
{
[UIView animateWithDuration:indicatorFadeDuration animations:^{
Modified: trunk/Source/WebKit2/UIProcess/ios/WKPDFView.mm (174231 => 174232)
--- trunk/Source/WebKit2/UIProcess/ios/WKPDFView.mm 2014-10-02 21:06:14 UTC (rev 174231)
+++ trunk/Source/WebKit2/UIProcess/ios/WKPDFView.mm 2014-10-02 21:51:14 UTC (rev 174232)
@@ -28,6 +28,7 @@
#if PLATFORM(IOS)
+#import "SessionState.h"
#import "WKPDFPageNumberIndicator.h"
#import "WKWebViewInternal.h"
#import "WebPageProxy.h"
@@ -57,6 +58,10 @@
RetainPtr<UIPDFPage> page;
} PDFPageInfo;
+@interface WKPDFView ()
+- (void)_resetZoomAnimated:(BOOL)animated;
+@end
+
@implementation WKPDFView {
RetainPtr<UIPDFDocument> _pdfDocument;
RetainPtr<NSString> _suggestedFilename;
@@ -72,6 +77,7 @@
UIView *_fixedOverlayView;
BOOL _isStartingZoom;
+ BOOL _isPerformingSameDocumentNavigation;
}
- (instancetype)web_initWithFrame:(CGRect)frame webView:(WKWebView *)webView
@@ -129,6 +135,8 @@
RetainPtr<CGPDFDocumentRef> cgPDFDocument = adoptCF(CGPDFDocumentCreateWithProvider(dataProvider.get()));
_pdfDocument = adoptNS([[UIPDFDocument alloc] initWithCGPDFDocument:cgPDFDocument.get()]);
+ // FIXME: restore the scroll position and page scale if navigating from the back/forward list.
+
[self _computePageAndDocumentFrames];
[self _revalidateViews];
}
@@ -147,7 +155,9 @@
return;
[self _revalidateViews];
- [_pageNumberIndicator show];
+
+ if (!_isPerformingSameDocumentNavigation)
+ [_pageNumberIndicator show];
}
- (void)_revalidateViews
@@ -201,6 +211,9 @@
- (void)_updatePageNumberIndicator
{
+ if (_isPerformingSameDocumentNavigation)
+ return;
+
if (!_pageNumberIndicator)
_pageNumberIndicator = adoptNS([[WKPDFPageNumberIndicator alloc] initWithFrame:CGRectZero]);
@@ -229,6 +242,36 @@
[_fixedOverlayView addSubview:_pageNumberIndicator.get()];
}
+- (void)web_didSameDocumentNavigation:(WKSameDocumentNavigationType)navigationType
+{
+ // Check for kWKSameDocumentNavigationSessionStatePop instead of kWKSameDocumentNavigationAnchorNavigation since the
+ // latter is only called once when navigating to the same anchor in succession. If the user navigates to a page
+ // then scrolls back and clicks on the same link a second time, we want to scroll again.
+ if (navigationType != kWKSameDocumentNavigationSessionStatePop)
+ return;
+
+ // FIXME: restore the scroll position and page scale if navigating back from a fragment.
+
+ NSString *fragment = _webView.URL.fragment;
+ if (![fragment hasPrefix:@"page"])
+ return;
+
+ NSInteger pageIndex = [[fragment substringFromIndex:4] integerValue] - 1;
+ if (pageIndex < 0 || static_cast<std::size_t>(pageIndex) >= _pages.size())
+ return;
+
+ _isPerformingSameDocumentNavigation = YES;
+
+ [_pageNumberIndicator hide];
+ [self _resetZoomAnimated:NO];
+
+ // Ensure that the page margin is visible below the content inset.
+ const CGFloat verticalOffset = _pages[pageIndex].frame.origin.y - _webView._computedContentInset.top - pdfPageMargin;
+ [_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x, verticalOffset) animated:NO];
+
+ _isPerformingSameDocumentNavigation = NO;
+}
+
- (void)_computePageAndDocumentFrames
{
NSUInteger pageCount = [_pdfDocument numberOfPages];
@@ -264,6 +307,17 @@
[_scrollView setContentSize:newFrame.size];
}
+- (void)_resetZoomAnimated:(BOOL)animated
+{
+ _isStartingZoom = YES;
+
+ CGRect scrollViewBounds = _scrollView.bounds;
+ CGPoint centerOfPageInDocumentCoordinates = [_scrollView convertPoint:CGPointMake(CGRectGetMidX(scrollViewBounds), CGRectGetMidY(scrollViewBounds)) toView:self];
+ [_webView _zoomOutWithOrigin:centerOfPageInDocumentCoordinates animated:animated];
+
+ _isStartingZoom = NO;
+}
+
#pragma mark UIPDFPageViewDelegate
- (void)zoom:(UIPDFPageView *)pageView to:(CGRect)targetRect atPoint:(CGPoint)origin kind:(UIPDFObjectKind)kind
@@ -285,13 +339,7 @@
- (void)resetZoom:(UIPDFPageView *)pageView
{
- _isStartingZoom = YES;
-
- CGRect scrollViewBounds = _scrollView.bounds;
- CGPoint centerOfPageInDocumentCoordinates = [_scrollView convertPoint:CGPointMake(CGRectGetMidX(scrollViewBounds), CGRectGetMidY(scrollViewBounds)) toView:self];
- [_webView _zoomOutWithOrigin:centerOfPageInDocumentCoordinates];
-
- _isStartingZoom = NO;
+ [self _resetZoomAnimated:YES];
}
#pragma mark UIPDFAnnotationControllerDelegate
@@ -304,12 +352,17 @@
return;
UIPDFLinkAnnotation *linkAnnotation = (UIPDFLinkAnnotation *)annotation;
- String urlString = linkAnnotation.url.absoluteString;
+ String urlString;
+ if (NSURL *url = ""
+ urlString = url.absoluteString;
+ else if (NSUInteger pageNumber = linkAnnotation.pageNumber) {
+ urlString = ASCIILiteral("#page");
+ urlString.append(String::number(pageNumber));
+ }
+
if (urlString.isEmpty())
return;
- // FIXME: Support pageNumber navigations
-
CGPoint documentPoint = [controller.pageView convertPoint:point toView:self];
CGPoint screenPoint = [self.window convertPoint:[self convertPoint:documentPoint toView:nil] toWindow:nil];
static const int64_t dispatchOffset = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(200)).count();