Skip to content
Permalink
Browse files
[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 4442b38c4499261a474a6696a12562c790ea5b94
@@ -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
@@ -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"
@@ -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;
@@ -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];
@@ -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) {
@@ -1406,7 +1410,7 @@ - (void)_restorePageScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOri
if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
return;

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

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

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

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

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

- (CGSize)scrollView:(UIScrollView*)scrollView contentSizeForZoomScale:(CGFloat)scale withProposedSize:(CGSize)proposedSize
@@ -2111,6 +2115,7 @@ static bool scrollViewCanScroll(UIScrollView *scrollView)
- (void)_updateContentRectsWithState:(BOOL)inStableState
{
if (![self usesStandardContentView]) {
[_passwordView setFrame:self.bounds];
[_customContentView web_computedContentInsetDidChange];
return;
}
@@ -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
@@ -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;
}
@@ -56,6 +56,7 @@ struct PrintInfo;
}

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

@@ -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;
@@ -76,8 +76,6 @@ @implementation WKPDFView {
RetainPtr<NSString> _suggestedFilename;
RetainPtr<WKPDFPageNumberIndicator> _pageNumberIndicator;

RetainPtr<WKPasswordView> _passwordView;

Vector<PDFPageInfo> _pages;
unsigned _centerPageNumber;

@@ -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;
@@ -361,9 +359,6 @@ - (void)web_didSameDocumentNavigation:(WKSameDocumentNavigationType)navigationTy

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

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

@@ -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
@@ -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
@@ -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;
}

@@ -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];
@@ -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;
@@ -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];

0 comments on commit 4442b38

Please sign in to comment.