Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[iOS] Move WKPDFView's password view to WKWebView
https://bugs.webkit.org/show_bug.cgi?id=167401

Reviewed by Tim Horton.

r210943 moved the PDF password view into the new class WKPasswordView but left it as a
subview of the WKPDFView. To show the password view for Web content, my original plan was to
teach WKContentView to host its own password view, but this turned out not to work. Since
QuickLook needs to unlock a document before determining its preview's MIME type, we have to
ask for a password during provisional navigation, but if the still-committed document is a
PDF then the WKContentView will not be in the view hierarchy.

To ensure password view visibility, this patch moves the ownership of WKPasswordView to
WKWebView and creates an internal API for showing and hiding it. When
-_showPasswordViewWithDocumentName:passwordHandler: is called, WKWebView inserts a new
WKPasswordView as a subview of the scroll view and hides the current content view. The
password view is removed and the current content view is unhidden by -_hidePasswordView.

This also fixes a bug in WKPDFView where a PDF document is laid out incorrectly if the view
size changes while the password view is displayed.

* UIProcess/API/Cocoa/WKWebView.mm: Declared _passwordView.
(-[WKWebView _processDidExit]): Hid the password view.
(-[WKWebView _didCommitLayerTree:]): Ignored if not showing the standard content view.
(-[WKWebView _restorePageScrollPosition:scrollOrigin:previousObscuredInset:scale:]): Ditto.
(-[WKWebView _restorePageStateToUnobscuredCenter:scale:]): Ditto.
(-[WKWebView usesStandardContentView]): Changed to return false if _passwordView is non-nil.
(-[WKWebView _updateContentRectsWithState:]): Updated _passwordView's frame with the current
bounds size.
(-[WKWebView _showPasswordViewWithDocumentName:passwordHandler:]): Created a WKPasswordView,
called -showInScrollView:, and hid _currentContentView.
(-[WKWebView _hidePasswordView]): Removed _passwordView from its superview, set
_passwordView to nil, and unhid _currentContentView.
(-[WKWebView _passwordView]): Returned _passwordView.
(-[WKWebView _beginAnimatedResizeWithUpdates:]): Called -usesStandardContentView instead of
checking for a non-nil _customContentView when deciding whether to do a non-animated resize.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/ios/WKPDFView.mm: Removed _passwordView.
(-[WKPDFView web_setMinimumSize:]): Set m_minimumSize and updated the frame size even when a
password view is displayed.
(-[WKPDFView _computePageAndDocumentFrames]): Removed password view code.
(-[WKPDFView _showPasswordEntryField]): Ditto.
(-[WKPDFView _passwordViewFrame]): Deleted.
* UIProcess/ios/WKPasswordView.h:
* UIProcess/ios/WKPasswordView.mm:
(-[WKPasswordView initWithFrame:documentName:]): Stored a copy of documentName in
_documentName.
(-[WKPasswordView documentName]): Added. Returns _documentName.
(-[WKPasswordView showInScrollView:]): Renamed from displayInContentView:. Started saving
zoomScale and contentSize.
(-[WKPasswordView hide]): Started restoring zoomeScale and contentSize.
(-[WKPasswordView showPasswordFailureAlert]): Renamed from -displayPasswordFailureAlert.
(-[WKPasswordView displayInContentView:]): Renamed to -showInScrollView:
(-[WKPasswordView displayPasswordFailureAlert]): Renamed to -showPasswordFailureAlert.


Canonical link: https://commits.webkit.org/184456@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211160 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
aestes committed Jan 25, 2017
1 parent 94d32ab commit 4442b38
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 37 deletions.
57 changes: 57 additions & 0 deletions Source/WebKit2/ChangeLog
@@ -1,3 +1,60 @@
2017-01-25 Andy Estes <aestes@apple.com>

[iOS] Move WKPDFView's password view to WKWebView
https://bugs.webkit.org/show_bug.cgi?id=167401

Reviewed by Tim Horton.

r210943 moved the PDF password view into the new class WKPasswordView but left it as a
subview of the WKPDFView. To show the password view for Web content, my original plan was to
teach WKContentView to host its own password view, but this turned out not to work. Since
QuickLook needs to unlock a document before determining its preview's MIME type, we have to
ask for a password during provisional navigation, but if the still-committed document is a
PDF then the WKContentView will not be in the view hierarchy.

To ensure password view visibility, this patch moves the ownership of WKPasswordView to
WKWebView and creates an internal API for showing and hiding it. When
-_showPasswordViewWithDocumentName:passwordHandler: is called, WKWebView inserts a new
WKPasswordView as a subview of the scroll view and hides the current content view. The
password view is removed and the current content view is unhidden by -_hidePasswordView.

This also fixes a bug in WKPDFView where a PDF document is laid out incorrectly if the view
size changes while the password view is displayed.

* UIProcess/API/Cocoa/WKWebView.mm: Declared _passwordView.
(-[WKWebView _processDidExit]): Hid the password view.
(-[WKWebView _didCommitLayerTree:]): Ignored if not showing the standard content view.
(-[WKWebView _restorePageScrollPosition:scrollOrigin:previousObscuredInset:scale:]): Ditto.
(-[WKWebView _restorePageStateToUnobscuredCenter:scale:]): Ditto.
(-[WKWebView usesStandardContentView]): Changed to return false if _passwordView is non-nil.
(-[WKWebView _updateContentRectsWithState:]): Updated _passwordView's frame with the current
bounds size.
(-[WKWebView _showPasswordViewWithDocumentName:passwordHandler:]): Created a WKPasswordView,
called -showInScrollView:, and hid _currentContentView.
(-[WKWebView _hidePasswordView]): Removed _passwordView from its superview, set
_passwordView to nil, and unhid _currentContentView.
(-[WKWebView _passwordView]): Returned _passwordView.
(-[WKWebView _beginAnimatedResizeWithUpdates:]): Called -usesStandardContentView instead of
checking for a non-nil _customContentView when deciding whether to do a non-animated resize.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/ios/WKPDFView.mm: Removed _passwordView.
(-[WKPDFView web_setMinimumSize:]): Set m_minimumSize and updated the frame size even when a
password view is displayed.
(-[WKPDFView _computePageAndDocumentFrames]): Removed password view code.
(-[WKPDFView _showPasswordEntryField]): Ditto.
(-[WKPDFView _passwordViewFrame]): Deleted.
* UIProcess/ios/WKPasswordView.h:
* UIProcess/ios/WKPasswordView.mm:
(-[WKPasswordView initWithFrame:documentName:]): Stored a copy of documentName in
_documentName.
(-[WKPasswordView documentName]): Added. Returns _documentName.
(-[WKPasswordView showInScrollView:]): Renamed from displayInContentView:. Started saving
zoomScale and contentSize.
(-[WKPasswordView hide]): Started restoring zoomeScale and contentSize.
(-[WKPasswordView showPasswordFailureAlert]): Renamed from -displayPasswordFailureAlert.
(-[WKPasswordView displayInContentView:]): Renamed to -showInScrollView:
(-[WKPasswordView displayPasswordFailureAlert]): Renamed to -showPasswordFailureAlert.

2017-01-25 Wenson Hsieh <wenson_hsieh@apple.com>

Add support for named pasteboards, pasteboard strategies and platform pasteboards
Expand Down
36 changes: 31 additions & 5 deletions Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Expand Up @@ -57,6 +57,7 @@
#import "WKNSURLExtras.h"
#import "WKNavigationDelegate.h"
#import "WKNavigationInternal.h"
#import "WKPasswordView.h"
#import "WKPreferencesInternal.h"
#import "WKProcessPoolInternal.h"
#import "WKSharedAPICast.h"
Expand Down Expand Up @@ -273,6 +274,8 @@ @implementation WKWebView {

Vector<std::function<void ()>> _snapshotsDeferredDuringResize;
RetainPtr<NSMutableArray> _stableStatePresentationUpdateCallbacks;

RetainPtr<WKPasswordView> _passwordView;
#endif
#if PLATFORM(MAC)
std::unique_ptr<WebKit::WebViewImpl> _impl;
Expand Down Expand Up @@ -1192,6 +1195,7 @@ - (UIEdgeInsets)_computedContentInset

- (void)_processDidExit
{
[self _hidePasswordView];
if (!_customContentView && _dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
NSUInteger indexOfResizeAnimationView = [[_scrollView subviews] indexOfObject:_resizeAnimationView.get()];
[_scrollView insertSubview:_contentView.get() atIndex:indexOfResizeAnimationView];
Expand Down Expand Up @@ -1268,7 +1272,7 @@ static inline bool areEssentiallyEqualAsFloat(float a, float b)

- (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction
{
if (_customContentView)
if (![self usesStandardContentView])
return;

if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
Expand Down Expand Up @@ -1406,7 +1410,7 @@ - (void)_restorePageScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOri
if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
return;

if (_customContentView)
if (![self usesStandardContentView])
return;

_needsToRestoreUnobscuredCenter = NO;
Expand All @@ -1423,7 +1427,7 @@ - (void)_restorePageStateToUnobscuredCenter:(WebCore::FloatPoint)center scale:(d
if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
return;

if (_customContentView)
if (![self usesStandardContentView])
return;

_needsToRestoreScrollPosition = NO;
Expand Down Expand Up @@ -1834,7 +1838,7 @@ - (BOOL)_allowsDoubleTapGestures

- (BOOL)usesStandardContentView
{
return !_customContentView;
return !_customContentView && !_passwordView;
}

- (CGSize)scrollView:(UIScrollView*)scrollView contentSizeForZoomScale:(CGFloat)scale withProposedSize:(CGSize)proposedSize
Expand Down Expand Up @@ -2111,6 +2115,7 @@ static bool scrollViewCanScroll(UIScrollView *scrollView)
- (void)_updateContentRectsWithState:(BOOL)inStableState
{
if (![self usesStandardContentView]) {
[_passwordView setFrame:self.bounds];
[_customContentView web_computedContentInsetDidChange];
return;
}
Expand Down Expand Up @@ -2331,6 +2336,27 @@ - (void)_navigationGestureDidEnd
_frozenUnobscuredContentRect = std::nullopt;
}

- (void)_showPasswordViewWithDocumentName:(NSString *)documentName passwordHandler:(void (^)(NSString *))passwordHandler
{
ASSERT(!_passwordView);
_passwordView = adoptNS([[WKPasswordView alloc] initWithFrame:self.bounds documentName:documentName]);
[_passwordView setUserDidEnterPassword:passwordHandler];
[_passwordView showInScrollView:_scrollView.get()];
self._currentContentView.hidden = YES;
}

- (void)_hidePasswordView
{
self._currentContentView.hidden = NO;
[_passwordView removeFromSuperview];
_passwordView = nil;
}

- (WKPasswordView *)_passwordView
{
return _passwordView.get();
}

#endif // PLATFORM(IOS)

#pragma mark OS X-specific methods
Expand Down Expand Up @@ -4212,7 +4238,7 @@ - (void)_beginAnimatedResizeWithUpdates:(void (^)(void))updateBlock
CGRect oldBounds = self.bounds;
WebCore::FloatRect oldUnobscuredContentRect = _page->unobscuredContentRect();

if (_customContentView || !_hasCommittedLoadForMainFrame || CGRectIsEmpty(oldBounds) || oldUnobscuredContentRect.isEmpty()) {
if (![self usesStandardContentView] || !_hasCommittedLoadForMainFrame || CGRectIsEmpty(oldBounds) || oldUnobscuredContentRect.isEmpty()) {
updateBlock();
return;
}
Expand Down
6 changes: 6 additions & 0 deletions Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
Expand Up @@ -56,6 +56,7 @@ struct PrintInfo;
}

@class WKWebViewContentProviderRegistry;
@class WKPasswordView;
@class _WKFrameHandle;
@protocol _WKWebViewPrintProvider;

Expand Down Expand Up @@ -116,6 +117,11 @@ struct PrintInfo;
- (void)_navigationGestureDidEnd;
- (BOOL)_isNavigationSwipeGestureRecognizer:(UIGestureRecognizer *)recognizer;

- (void)_showPasswordViewWithDocumentName:(NSString *)documentName passwordHandler:(void (^)(NSString *))passwordHandler;
- (void)_hidePasswordView;

@property (nonatomic, readonly) WKPasswordView *_passwordView;

@property (nonatomic, readonly) BOOL _isBackground;

@property (nonatomic, readonly) WKWebViewContentProviderRegistry *_contentProviderRegistry;
Expand Down
30 changes: 7 additions & 23 deletions Source/WebKit2/UIProcess/ios/WKPDFView.mm
Expand Up @@ -76,8 +76,6 @@ @implementation WKPDFView {
RetainPtr<NSString> _suggestedFilename;
RetainPtr<WKPDFPageNumberIndicator> _pageNumberIndicator;

RetainPtr<WKPasswordView> _passwordView;

Vector<PDFPageInfo> _pages;
unsigned _centerPageNumber;

Expand Down Expand Up @@ -205,13 +203,13 @@ - (void)web_setContentProviderData:(NSData *)data suggestedFilename:(NSString *)

- (void)web_setMinimumSize:(CGSize)size
{
if (_passwordView) {
[_passwordView setFrame:[self _passwordViewFrame]];
_minimumSize = size;

if (_webView._passwordView) {
self.frame = { self.frame.origin, size };
return;
}

_minimumSize = size;

CGFloat oldDocumentLeftFraction = 0;
CGFloat oldDocumentTopFraction = 0;
CGSize contentSize = _scrollView.contentSize;
Expand Down Expand Up @@ -361,9 +359,6 @@ - (void)web_didSameDocumentNavigation:(WKSameDocumentNavigationType)navigationTy

- (void)_computePageAndDocumentFrames
{
if (_passwordView)
return;

NSUInteger pageCount = [_pdfDocument numberOfPages];
[_pageNumberIndicator setPageCount:pageCount];

Expand Down Expand Up @@ -746,28 +741,17 @@ - (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant shouldIncludeAp

#pragma mark Password protection UI

- (CGRect)_passwordViewFrame
{
CGRect webViewBounds = _webView.bounds;
return CGRectMake(0, 0, webViewBounds.size.width, webViewBounds.size.height);
}

- (void)_showPasswordEntryField
{
_passwordView = adoptNS([[WKPasswordView alloc] initWithFrame:[self _passwordViewFrame] documentName:_suggestedFilename.get()]);

[_passwordView setUserDidEnterPassword:[retainedSelf = retainPtr(self)](NSString *password) {
[_webView _showPasswordViewWithDocumentName:_suggestedFilename.get() passwordHandler:[retainedSelf = retainPtr(self), webView = retainPtr(_webView)](NSString *password) {
if (!CGPDFDocumentUnlockWithPassword(retainedSelf->_cgPDFDocument.get(), password.UTF8String)) {
[retainedSelf->_passwordView displayPasswordFailureAlert];
[[webView _passwordView] showPasswordFailureAlert];
return;
}

[retainedSelf->_passwordView hide];
retainedSelf->_passwordView = nil;
[webView _hidePasswordView];
[retainedSelf _didLoadPDFDocument];
}];

[_passwordView displayInContentView:self];
}

- (void)willMoveToWindow:(UIWindow *)newWindow
Expand Down
5 changes: 3 additions & 2 deletions Source/WebKit2/UIProcess/ios/WKPasswordView.h
Expand Up @@ -30,10 +30,11 @@
@interface WKPasswordView : UIView

- (instancetype)initWithFrame:(CGRect)frame documentName:(NSString *)documentName;
- (void)displayInContentView:(UIView *)contentView;
- (void)showInScrollView:(UIScrollView *)scrollView;
- (void)hide;
- (void)displayPasswordFailureAlert;
- (void)showPasswordFailureAlert;

@property (nonatomic, readonly) NSString *documentName;
@property (nonatomic, copy) void (^userDidEnterPassword)(NSString *);

@end
Expand Down
26 changes: 19 additions & 7 deletions Source/WebKit2/UIProcess/ios/WKPasswordView.mm
Expand Up @@ -41,10 +41,13 @@ @interface WKPasswordView () <UIDocumentPasswordViewDelegate>
@end

@implementation WKPasswordView {
RetainPtr<NSString> _documentName;
RetainPtr<UIScrollView> _scrollView;
RetainPtr<UIDocumentPasswordView> _passwordView;
CGFloat _savedMinimumZoomScale;
CGFloat _savedMaximumZoomScale;
CGFloat _savedZoomScale;
CGSize _savedContentSize;
RetainPtr<UIColor> _savedBackgroundColor;
}

Expand All @@ -54,7 +57,8 @@ - (instancetype)initWithFrame:(CGRect)frame documentName:(NSString *)documentNam
if (!self)
return nil;

_passwordView = adoptNS([[UIDocumentPasswordView alloc] initWithDocumentName:documentName]);
_documentName = adoptNS([documentName copy]);
_passwordView = adoptNS([[UIDocumentPasswordView alloc] initWithDocumentName:_documentName.get()]);
[_passwordView setFrame:self.bounds];
[_passwordView setPasswordDelegate:self];
[_passwordView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
Expand All @@ -65,34 +69,42 @@ - (instancetype)initWithFrame:(CGRect)frame documentName:(NSString *)documentNam
return self;
}

- (NSString *)documentName
{
return _documentName.get();
}

- (void)layoutSubviews
{
if (_scrollView)
[_scrollView setContentSize:self.frame.size];
}

- (void)displayInContentView:(UIView *)contentView
- (void)showInScrollView:(UIScrollView *)scrollView
{
ASSERT([contentView isKindOfClass:[WKContentView class]] || [contentView conformsToProtocol:@protocol(WKWebViewContentProvider)]);
ASSERT([contentView.superview isKindOfClass:[UIScrollView class]]);
_scrollView = (UIScrollView *)contentView.superview;
_scrollView = scrollView;

_savedMinimumZoomScale = [_scrollView minimumZoomScale];
_savedMaximumZoomScale = [_scrollView maximumZoomScale];
_savedZoomScale = [_scrollView zoomScale];
_savedContentSize = [_scrollView contentSize];
_savedBackgroundColor = [_scrollView backgroundColor];

[_scrollView setMinimumZoomScale:1];
[_scrollView setMaximumZoomScale:1];
[_scrollView setZoomScale:1];
[_scrollView setContentSize:self.frame.size];
[_scrollView setBackgroundColor:[UIColor groupTableViewBackgroundColor]];

[contentView addSubview:self];
[scrollView addSubview:self];
}

- (void)hide
{
[_scrollView setMinimumZoomScale:_savedMinimumZoomScale];
[_scrollView setMaximumZoomScale:_savedMaximumZoomScale];
[_scrollView setZoomScale:_savedZoomScale];
[_scrollView setContentSize:_savedContentSize];
[_scrollView setBackgroundColor:_savedBackgroundColor.get()];

_scrollView = nil;
Expand All @@ -101,7 +113,7 @@ - (void)hide
[self removeFromSuperview];
}

- (void)displayPasswordFailureAlert
- (void)showPasswordFailureAlert
{
[[_passwordView passwordField] setText:@""];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:WEB_UI_STRING("The document could not be opened with that password.", "document password failure alert message") message:@"" preferredStyle:UIAlertControllerStyleAlert];
Expand Down

0 comments on commit 4442b38

Please sign in to comment.