[iOS] Implement safe browsing in WebKit
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2018 01:08:07 +0000 (01:08 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2018 01:08:07 +0000 (01:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191441

Reviewed by Tim Horton.

Source/WebKit:

In r237863 I implemented this for Mac.  This refines the UI and implements it for iOS.

* Shared/WebPreferences.yaml:
* Shared/WebPreferencesDefaultValues.h:
* UIProcess/API/C/mac/WKContextPrivateMac.mm:
(WKContextHandlesSafeBrowsing):
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _showSafeBrowsingWarning:completionHandler:]):
(-[WKWebView _clearSafeBrowsingWarning]):
(-[WKWebView layoutSubviews]):
(-[WKWebView setFrameSize:]):
(+[WKWebView _handlesSafeBrowsing]):
(-[WKWebView _safeBrowsingWarningForTesting]):
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/Cocoa/PageClientImplCocoa.h:
* UIProcess/Cocoa/PageClientImplCocoa.mm:
(WebKit::PageClientImplCocoa::allocFileWrapperInstance const):
(WebKit::PageClientImplCocoa::serializableFileWrapperClasses const):
* UIProcess/Cocoa/WKSafeBrowsingWarning.h:
* UIProcess/Cocoa/WKSafeBrowsingWarning.mm:
(confirmMalwareSentinel):
(visitUnsafeWebsiteSentinel):
(colorForItem):
(addLinkAndReplace):
(-[WKSafeBrowsingExclamationPoint drawRect:]):
(makeButton):
(makeTitleLabel):
(setBackground):
(-[WKSafeBrowsingWarning initWithFrame:safeBrowsingResult:completionHandler:]):
(-[WKSafeBrowsingWarning addContent]):
(-[WKSafeBrowsingWarning showDetailsClicked]):
(-[WKSafeBrowsingWarning layoutText]):
(-[WKSafeBrowsingWarning textView:clickedOnLink:atIndex:]):
(-[WKSafeBrowsingWarning layout]):
(-[WKSafeBrowsingWarning layoutSubviews]):
(-[WKSafeBrowsingWarning textView:shouldInteractWithURL:inRange:interaction:]):
(-[WKSafeBrowsingWarning didMoveToWindow]):
(-[WKSafeBrowsingWarning clickedOnLink:]):
(-[WKSafeBrowsingTextView initWithAttributedString:forWarning:]):
(-[WKSafeBrowsingTextView intrinsicContentSize]):
(colorNamed): Deleted.
(+[WKSafeBrowsingTextView viewWithAttributedString:linkTarget:]): Deleted.
(+[WKSafeBrowsingTextView viewWithString:]): Deleted.
(-[WKSafeBrowsingTextView clickedOnLink:atIndex:]): Deleted.
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::isViewWindowActive):
(WebKit::PageClientImpl::isViewFocused):
(WebKit::PageClientImpl::isViewVisible):
(WebKit::PageClientImpl::isViewInWindow):
(WebKit::PageClientImpl::decidePolicyForGeolocationPermissionRequest):
(WebKit::PageClientImpl::enterAcceleratedCompositingMode):
(WebKit::PageClientImpl::showSafeBrowsingWarning):
(WebKit::PageClientImpl::clearSafeBrowsingWarning):
(WebKit::PageClientImpl::mimeTypesWithCustomContentProviders):
(WebKit::PageClientImpl::navigationGestureDidBegin):
(WebKit::PageClientImpl::navigationGestureWillEnd):
(WebKit::PageClientImpl::navigationGestureDidEnd):
(WebKit::PageClientImpl::willRecordNavigationSnapshot):
(WebKit::PageClientImpl::didRemoveNavigationGestureSnapshot):
(WebKit::PageClientImpl::requestPasswordForQuickLookDocument):
* UIProcess/mac/PageClientImplMac.mm:
(WebKit::PageClientImpl::showShareSheet):
(WebKit::PageClientImpl::navigationGestureDidBegin):
(WebKit::PageClientImpl::navigationGestureWillEnd):
(WebKit::PageClientImpl::navigationGestureDidEnd):
(WebKit::PageClientImpl::willRecordNavigationSnapshot):
(WebKit::PageClientImpl::didRemoveNavigationGestureSnapshot):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/SafeBrowsing.mm:
(checkTitleAndClick):
(TEST):

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

14 files changed:
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebPreferences.yaml
Source/WebKit/Shared/WebPreferencesDefaultValues.h
Source/WebKit/UIProcess/API/C/mac/WKContextPrivateMac.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.h
Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm
Source/WebKit/UIProcess/Cocoa/WKSafeBrowsingWarning.h
Source/WebKit/UIProcess/Cocoa/WKSafeBrowsingWarning.mm
Source/WebKit/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit/UIProcess/mac/PageClientImplMac.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/SafeBrowsing.mm

index 8f3770c..bb28d41 100644 (file)
@@ -1,3 +1,78 @@
+2018-11-12  Alex Christensen  <achristensen@webkit.org>
+
+        [iOS] Implement safe browsing in WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=191441
+
+        Reviewed by Tim Horton.
+
+        In r237863 I implemented this for Mac.  This refines the UI and implements it for iOS.
+
+        * Shared/WebPreferences.yaml:
+        * Shared/WebPreferencesDefaultValues.h:
+        * UIProcess/API/C/mac/WKContextPrivateMac.mm:
+        (WKContextHandlesSafeBrowsing):
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _showSafeBrowsingWarning:completionHandler:]):
+        (-[WKWebView _clearSafeBrowsingWarning]):
+        (-[WKWebView layoutSubviews]):
+        (-[WKWebView setFrameSize:]):
+        (+[WKWebView _handlesSafeBrowsing]):
+        (-[WKWebView _safeBrowsingWarningForTesting]):
+        * UIProcess/API/Cocoa/WKWebViewInternal.h:
+        * UIProcess/Cocoa/PageClientImplCocoa.h:
+        * UIProcess/Cocoa/PageClientImplCocoa.mm:
+        (WebKit::PageClientImplCocoa::allocFileWrapperInstance const):
+        (WebKit::PageClientImplCocoa::serializableFileWrapperClasses const):
+        * UIProcess/Cocoa/WKSafeBrowsingWarning.h:
+        * UIProcess/Cocoa/WKSafeBrowsingWarning.mm:
+        (confirmMalwareSentinel):
+        (visitUnsafeWebsiteSentinel):
+        (colorForItem):
+        (addLinkAndReplace):
+        (-[WKSafeBrowsingExclamationPoint drawRect:]):
+        (makeButton):
+        (makeTitleLabel):
+        (setBackground):
+        (-[WKSafeBrowsingWarning initWithFrame:safeBrowsingResult:completionHandler:]):
+        (-[WKSafeBrowsingWarning addContent]):
+        (-[WKSafeBrowsingWarning showDetailsClicked]):
+        (-[WKSafeBrowsingWarning layoutText]):
+        (-[WKSafeBrowsingWarning textView:clickedOnLink:atIndex:]):
+        (-[WKSafeBrowsingWarning layout]):
+        (-[WKSafeBrowsingWarning layoutSubviews]):
+        (-[WKSafeBrowsingWarning textView:shouldInteractWithURL:inRange:interaction:]):
+        (-[WKSafeBrowsingWarning didMoveToWindow]):
+        (-[WKSafeBrowsingWarning clickedOnLink:]):
+        (-[WKSafeBrowsingTextView initWithAttributedString:forWarning:]):
+        (-[WKSafeBrowsingTextView intrinsicContentSize]):
+        (colorNamed): Deleted.
+        (+[WKSafeBrowsingTextView viewWithAttributedString:linkTarget:]): Deleted.
+        (+[WKSafeBrowsingTextView viewWithString:]): Deleted.
+        (-[WKSafeBrowsingTextView clickedOnLink:atIndex:]): Deleted.
+        * UIProcess/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::isViewWindowActive):
+        (WebKit::PageClientImpl::isViewFocused):
+        (WebKit::PageClientImpl::isViewVisible):
+        (WebKit::PageClientImpl::isViewInWindow):
+        (WebKit::PageClientImpl::decidePolicyForGeolocationPermissionRequest):
+        (WebKit::PageClientImpl::enterAcceleratedCompositingMode):
+        (WebKit::PageClientImpl::showSafeBrowsingWarning):
+        (WebKit::PageClientImpl::clearSafeBrowsingWarning):
+        (WebKit::PageClientImpl::mimeTypesWithCustomContentProviders):
+        (WebKit::PageClientImpl::navigationGestureDidBegin):
+        (WebKit::PageClientImpl::navigationGestureWillEnd):
+        (WebKit::PageClientImpl::navigationGestureDidEnd):
+        (WebKit::PageClientImpl::willRecordNavigationSnapshot):
+        (WebKit::PageClientImpl::didRemoveNavigationGestureSnapshot):
+        (WebKit::PageClientImpl::requestPasswordForQuickLookDocument):
+        * UIProcess/mac/PageClientImplMac.mm:
+        (WebKit::PageClientImpl::showShareSheet):
+        (WebKit::PageClientImpl::navigationGestureDidBegin):
+        (WebKit::PageClientImpl::navigationGestureWillEnd):
+        (WebKit::PageClientImpl::navigationGestureDidEnd):
+        (WebKit::PageClientImpl::willRecordNavigationSnapshot):
+        (WebKit::PageClientImpl::didRemoveNavigationGestureSnapshot):
+
 2018-11-12  Tim Horton  <timothy_horton@apple.com>
 
         Make it possible to edit images inline
index 5679fe6..50e946e 100644 (file)
@@ -56,7 +56,7 @@ XSSAuditorEnabled:
 
 SafeBrowsingEnabled:
   type: bool
-  defaultValue: DEFAULT_SAFE_BROWSING_ENABLED
+  defaultValue: true
   webcoreBinding: none
 
 PrivateBrowsingEnabled:
index 1acfd29..4da6c10 100644 (file)
@@ -58,7 +58,6 @@
 #endif
 
 #if PLATFORM(IOS_FAMILY)
-#define DEFAULT_SAFE_BROWSING_ENABLED false
 #define DEFAULT_ALLOWS_PICTURE_IN_PICTURE_MEDIA_PLAYBACK true
 #define DEFAULT_BACKSPACE_KEY_NAVIGATION_ENABLED false
 #define DEFAULT_FRAME_FLATTENING true
@@ -78,7 +77,6 @@
 #define DEFAULT_INTERACTIVE_MEDIA_CAPTURE_STREAM_REPROMPT_INTERVAL_IN_MINUTES 1
 #define EXPERIMENTAL_FULLSCREEN_API_HIDDEN false
 #else
-#define DEFAULT_SAFE_BROWSING_ENABLED true
 #define DEFAULT_ALLOWS_PICTURE_IN_PICTURE_MEDIA_PLAYBACK false
 #define DEFAULT_BACKSPACE_KEY_NAVIGATION_ENABLED true
 #define DEFAULT_FRAME_FLATTENING false
index c5fdb0c..be7fcf2 100644 (file)
@@ -173,5 +173,5 @@ bool WKContextShouldSuggestBlockWebGL()
 
 bool WKContextHandlesSafeBrowsing()
 {
-    return DEFAULT_SAFE_BROWSING_ENABLED;
+    return true;
 }
index 7b6c49a..b864c52 100644 (file)
@@ -274,6 +274,7 @@ static std::optional<WebCore::ScrollbarOverlayStyle> toCoreScrollbarStyle(_WKOve
     WeakObjCPtr<id <_WKInputDelegate>> _inputDelegate;
 
     std::optional<BOOL> _resolutionForShareSheetImmediateCompletionForTesting;
+    RetainPtr<WKSafeBrowsingWarning> _safeBrowsingWarning;
 
 #if PLATFORM(IOS_FAMILY)
     RetainPtr<_WKRemoteObjectRegistry> _remoteObjectRegistry;
@@ -1276,6 +1277,21 @@ static NSDictionary *dictionaryRepresentationForEditorState(const WebKit::Editor
         [uiDelegate _webView:self editorStateDidChange:dictionaryRepresentationForEditorState(_page->editorState())];
 }
 
+- (void)_showSafeBrowsingWarning:(const WebKit::SafeBrowsingResult&)result completionHandler:(CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)>&&)completionHandler
+{
+    _safeBrowsingWarning = adoptNS([[WKSafeBrowsingWarning alloc] initWithFrame:self.bounds safeBrowsingResult:result completionHandler:[weakSelf = WeakObjCPtr<WKWebView>(self), completionHandler = WTFMove(completionHandler)] (auto&& result) mutable {
+        if (auto strongSelf = weakSelf.get())
+            [std::exchange(strongSelf->_safeBrowsingWarning, nullptr) removeFromSuperview];
+        completionHandler(WTFMove(result));
+    }]);
+    [self addSubview:_safeBrowsingWarning.get()];
+}
+
+- (void)_clearSafeBrowsingWarning
+{
+    [std::exchange(_safeBrowsingWarning, nullptr) removeFromSuperview];
+}
+
 #if ENABLE(ATTACHMENT_ELEMENT)
 
 - (void)_didInsertAttachment:(API::Attachment&)attachment withSource:(NSString *)source
@@ -1352,6 +1368,7 @@ static NSDictionary *dictionaryRepresentationForEditorState(const WebKit::Editor
 
 - (void)layoutSubviews
 {
+    [_safeBrowsingWarning setFrame:self.bounds];
     [super layoutSubviews];
     [self _frameOrBoundsChanged];
 }
@@ -3312,6 +3329,7 @@ static void accessibilityEventsEnabledChangedCallback(CFNotificationCenterRef, v
 - (void)setFrameSize:(NSSize)size
 {
     [super setFrameSize:size];
+    [_safeBrowsingWarning setFrame:self.bounds];
     _impl->setFrameSize(NSSizeToCGSize(size));
 }
 
@@ -4711,7 +4729,7 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
 
 + (BOOL)_handlesSafeBrowsing
 {
-    return DEFAULT_SAFE_BROWSING_ENABLED;
+    return true;
 }
 
 - (void)_evaluateJavaScriptWithoutUserGesture:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
@@ -6749,7 +6767,7 @@ static WebCore::UserInterfaceLayoutDirection toUserInterfaceLayoutDirection(UISe
 #else
 - (UIView *)_safeBrowsingWarningForTesting
 {
-    return nil;
+    return _safeBrowsingWarning.get();
 }
 #endif
 
index 3b3e806..ff45a52 100644 (file)
 #import "WKWebViewConfiguration.h"
 #import "_WKAttachmentInternal.h"
 #import "_WKWebViewPrintFormatterInternal.h"
+#import <wtf/CompletionHandler.h>
 #import <wtf/RefPtr.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/Variant.h>
 
 #if PLATFORM(IOS_FAMILY)
 #import "UIKitSPI.h"
@@ -63,11 +65,17 @@ class Attachment;
 }
 
 namespace WebKit {
+enum class ContinueUnsafeLoad : bool;
+class SafeBrowsingResult;
 class ViewSnapshot;
 class WebPageProxy;
 struct PrintInfo;
 }
 
+namespace WebCore {
+class URL;
+}
+
 @class WKWebViewContentProviderRegistry;
 @class WKPasswordView;
 @class _WKFrameHandle;
@@ -171,6 +179,9 @@ struct PrintInfo;
 - (void)_didInsertAttachment:(API::Attachment&)attachment withSource:(NSString *)source;
 #endif
 
+- (void)_showSafeBrowsingWarning:(const WebKit::SafeBrowsingResult&)result completionHandler:(CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)>&&)completionHandler;
+- (void)_clearSafeBrowsingWarning;
+
 - (std::optional<BOOL>)_resolutionForShareSheetImmediateCompletionForTesting;
 
 - (WKPageRef)_pageForTesting;
index d727372..83948d8 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "PageClient.h"
+#include <wtf/WeakObjCPtr.h>
 
 @class WKWebView;
 
@@ -50,7 +51,7 @@ public:
 #endif
 
 protected:
-    WKWebView *m_webView;
+    WeakObjCPtr<WKWebView> m_webView;
 };
 
 }
index 75ace9a..efe4e81 100644 (file)
@@ -69,7 +69,7 @@ void PageClientImplCocoa::didRemoveAttachment(API::Attachment& attachment)
 NSFileWrapper *PageClientImplCocoa::allocFileWrapperInstance() const
 {
 #if WK_API_ENABLED
-    Class cls = m_webView.configuration._attachmentFileWrapperClass ?: [NSFileWrapper self];
+    Class cls = [m_webView configuration]._attachmentFileWrapperClass ?: [NSFileWrapper self];
     return [cls alloc];
 #else
     return nil;
@@ -80,7 +80,7 @@ NSSet *PageClientImplCocoa::serializableFileWrapperClasses() const
 {
     Class defaultFileWrapperClass = NSFileWrapper.self;
 #if WK_API_ENABLED
-    Class configuredFileWrapperClass = m_webView.configuration._attachmentFileWrapperClass;
+    Class configuredFileWrapperClass = [m_webView configuration]._attachmentFileWrapperClass;
     if (configuredFileWrapperClass && configuredFileWrapperClass != defaultFileWrapperClass)
         return [NSSet setWithObjects:configuredFileWrapperClass, defaultFileWrapperClass, nil];
 #endif
index 1479bde..fb4b915 100644 (file)
@@ -44,18 +44,20 @@ class SafeBrowsingResult;
 enum class ContinueUnsafeLoad : bool;
 }
 
+OBJC_CLASS WKSafeBrowsingTextView;
+
 #if PLATFORM(MAC)
 using RectType = NSRect;
-using StackViewType = NSStackView;
+@interface WKSafeBrowsingWarning : NSView<NSTextViewDelegate>
 #else
 using RectType = CGRect;
-using StackViewType = UIStackView;
+@interface WKSafeBrowsingWarning : UIScrollView<UITextViewDelegate>
 #endif
-
-@interface WKSafeBrowsingWarning : StackViewType {
+{
 @package
     CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)> _completionHandler;
     RefPtr<const WebKit::SafeBrowsingResult> _result;
+    RetainPtr<NSMutableArray<WKSafeBrowsingTextView *>> _textViews;
 }
 
 - (instancetype)initWithFrame:(RectType)frame safeBrowsingResult:(const WebKit::SafeBrowsingResult&)result completionHandler:(CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)>&&)completionHandler;
index 6bdf5a7..38a25b6 100644 (file)
 #import <wtf/BlockPtr.h>
 #import <wtf/Language.h>
 
-const CGFloat exclamationPointSize = 30;
-const CGFloat textSize = 13;
+constexpr CGFloat exclamationPointSize = 30;
+constexpr CGFloat titleSize = 26;
+constexpr CGFloat boxCornerRadius = 6;
+#if HAVE(SAFE_BROWSING)
+constexpr CGFloat marginSize = 20;
+constexpr CGFloat maxWidth = 675;
+#endif
+
 #if PLATFORM(MAC)
-const CGFloat marginSize = 20;
-const size_t maxWidth = 600;
+constexpr CGFloat textSize = 14;
 using ColorType = NSColor;
 using FontType = NSFont;
-using ViewType = NSView;
-using BezierPathType = NSBezierPath;
 using TextViewType = NSTextView;
+using ButtonType = NSButton;
+using AlignmentType = NSLayoutAttribute;
+using ViewType = NSView;
+using SizeType = NSSize;
 #else
+constexpr CGFloat textSize = 20;
 using ColorType = UIColor;
 using FontType = UIFont;
-using ViewType = UIView;
-using BezierPathType = UIBezierPath;
 using TextViewType = UITextView;
+using ButtonType = UIButton;
+using AlignmentType = UIStackViewAlignment;
+using ViewType = UIView;
+using SizeType = CGSize;
 #endif
 
-static id confirmMalwareSentinel()
+enum class WarningItem : uint8_t {
+    Background,
+    BoxBackground,
+    ExclamationPoint,
+    TitleText,
+    MessageText,
+    ShowDetailsButton,
+    GoBackButton
+};
+
+static NSURL *confirmMalwareSentinel()
 {
-    return @"WKConfirmMalwareSentinel";
+    return [NSURL URLWithString:@"WKConfirmMalwareSentinel"];
 }
 
-static id visitUnsafeWebsiteSentinel()
+static NSURL *visitUnsafeWebsiteSentinel()
 {
-    return @"WKVisitUnsafeWebsiteSentinel";
+    return [NSURL URLWithString:@"WKVisitUnsafeWebsiteSentinel"];
 }
 
-static ColorType *colorNamed(NSString *name)
+static ColorType *colorForItem(WarningItem item, ViewType *warning)
 {
+    ASSERT([warning isKindOfClass:[WKSafeBrowsingWarning class]]);
 #if PLATFORM(MAC)
+
+    auto colorNamed = [] (NSString *name) -> ColorType* {
 #if HAVE(SAFE_BROWSING)
-    return [NSColor colorNamed:name bundle:[NSBundle bundleWithIdentifier:@"com.apple.WebKit"]];
+        return [NSColor colorNamed:name bundle:[NSBundle bundleWithIdentifier:@"com.apple.WebKit"]];
 #else
-    ASSERT_NOT_REACHED();
-    return nil;
+        ASSERT_NOT_REACHED();
+        return nil;
 #endif
+    };
+
+    switch (item) {
+    case WarningItem::Background:
+        return colorNamed(@"WKSafeBrowsingWarningBackground");
+    case WarningItem::BoxBackground:
+        return [NSColor windowBackgroundColor];
+    case WarningItem::TitleText:
+    case WarningItem::ExclamationPoint:
+        return colorNamed(@"WKSafeBrowsingWarningTitle");
+    case WarningItem::MessageText:
+        return colorNamed(@"WKSafeBrowsingWarningText");
+    case WarningItem::ShowDetailsButton:
+    case WarningItem::GoBackButton:
+        ASSERT_NOT_REACHED();
+        return nil;
+    }
 #else
-    return [UIColor colorNamed:name inBundle:[NSBundle bundleWithIdentifier:@"com.apple.WebKit"] compatibleWithTraitCollection:nil];
+    UIColor *red = [UIColor colorWithRed:0.998 green:0.239 blue:0.233 alpha:1.0];
+    UIColor *white = [UIColor whiteColor];
+    bool narrow = warning.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact;
+
+    switch (item) {
+    case WarningItem::Background:
+        return red;
+    case WarningItem::BoxBackground:
+        return narrow ? red : white;
+    case WarningItem::TitleText:
+    case WarningItem::ExclamationPoint:
+        return narrow ? white : red;
+    case WarningItem::MessageText:
+    case WarningItem::ShowDetailsButton:
+        return narrow ? white : [UIColor darkTextColor];
+    case WarningItem::GoBackButton:
+        return narrow ? white : warning.tintColor;
+    }
 #endif
+    ASSERT_NOT_REACHED();
+    return nil;
 }
 
-#if PLATFORM(MAC)
 static void replace(NSMutableAttributedString *string, NSString *toReplace, NSString *replaceWith)
 {
     [string replaceCharactersInRange:[string.string rangeOfString:toReplace] withString:replaceWith];
@@ -90,7 +148,6 @@ static void addLinkAndReplace(NSMutableAttributedString *string, NSString *toRep
     } range:NSMakeRange(0, replaceWith.length)];
     [string replaceCharactersInRange:[string.string rangeOfString:toReplace] withAttributedString:stringWithLink];
 }
-#endif
 
 @interface WKSafeBrowsingExclamationPoint : ViewType
 @end
@@ -99,22 +156,39 @@ static void addLinkAndReplace(NSMutableAttributedString *string, NSString *toRep
 
 - (void)drawRect:(RectType)rect
 {
-    [colorNamed(@"WKSafeBrowsingWarningTitle") set];
+    constexpr CGFloat centerX = exclamationPointSize / 2;
+    constexpr CGFloat pointCenterY = exclamationPointSize * 7 / 30;
+    constexpr CGFloat pointRadius = 2.25 * exclamationPointSize / 30;
+    constexpr CGFloat lineBottomCenterY = exclamationPointSize * 13 / 30;
+    constexpr CGFloat lineTopCenterY = exclamationPointSize * 23 / 30;
+    constexpr CGFloat lineRadius = 1.75 * exclamationPointSize / 30;
+    ViewType *warning = self.superview.superview;
 #if PLATFORM(MAC)
-#define addArcWithCenter appendBezierPathWithArcWithCenter
-    NSRect square = NSMakeRect(0, 0, exclamationPointSize, exclamationPointSize);
+    [colorForItem(WarningItem::ExclamationPoint, warning) set];
+    NSBezierPath *exclamationPoint = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(0, 0, exclamationPointSize, exclamationPointSize)];
+    [exclamationPoint appendBezierPathWithArcWithCenter: { centerX, lineBottomCenterY } radius:lineRadius startAngle:0 endAngle:180 clockwise:YES];
+    [exclamationPoint appendBezierPathWithArcWithCenter: { centerX, lineTopCenterY } radius:lineRadius startAngle:180 endAngle:360 clockwise:YES];
+    [exclamationPoint lineToPoint: { centerX + lineRadius, lineBottomCenterY }];
+    [exclamationPoint appendBezierPathWithArcWithCenter: { centerX, pointCenterY } radius:pointRadius startAngle:0 endAngle:180 clockwise:YES];
+    [exclamationPoint appendBezierPathWithArcWithCenter: { centerX, pointCenterY } radius:pointRadius startAngle:180 endAngle:360 clockwise:YES];
 #else
-    CGRect square = CGRectMake(0, 0, exclamationPointSize, exclamationPointSize);
+    auto flip = [] (auto y) {
+        return exclamationPointSize - y;
+    };
+    [colorForItem(WarningItem::BoxBackground, warning) set];
+    auto square = CGRectMake(0, 0, exclamationPointSize, exclamationPointSize);
+    [[UIBezierPath bezierPathWithRect:square] fill];
+    
+    [colorForItem(WarningItem::ExclamationPoint, warning) set];
+    UIBezierPath *exclamationPoint = [UIBezierPath bezierPathWithOvalInRect:square];
+    [exclamationPoint addArcWithCenter: { centerX, flip(lineTopCenterY) } radius:lineRadius startAngle:2 * piDouble endAngle:piDouble clockwise:NO];
+    [exclamationPoint addArcWithCenter: { centerX, flip(lineBottomCenterY) } radius:lineRadius startAngle:piDouble endAngle:0 clockwise:NO];
+    [exclamationPoint addArcWithCenter: { centerX, flip(pointCenterY) } radius:pointRadius startAngle:0 endAngle:piDouble clockwise:NO];
+    [exclamationPoint addArcWithCenter: { centerX, flip(pointCenterY) } radius:pointRadius startAngle:piDouble endAngle:piDouble * 2 clockwise:NO];
+    [exclamationPoint addLineToPoint: { centerX + lineRadius, flip(lineBottomCenterY) }];
+    [exclamationPoint addLineToPoint: { centerX + lineRadius, flip(lineTopCenterY) }];
 #endif
-    BezierPathType *exclamationPoint = [BezierPathType bezierPathWithOvalInRect:square];
-    [exclamationPoint addArcWithCenter: { exclamationPointSize / 2, exclamationPointSize * 13 / 30 } radius:1.75 startAngle:0 endAngle:180 clockwise:YES];
-    [exclamationPoint addArcWithCenter: { exclamationPointSize / 2, exclamationPointSize * 23 / 30 } radius:1.75 startAngle:180 endAngle:360 clockwise:YES];
-    [exclamationPoint addArcWithCenter: { exclamationPointSize / 2, exclamationPointSize * 7 / 30 } radius:2.25 startAngle:0 endAngle:180 clockwise:YES];
-    [exclamationPoint addArcWithCenter: { exclamationPointSize / 2, exclamationPointSize * 7 / 30 } radius:2.25 startAngle:180 endAngle:360 clockwise:YES];
     [exclamationPoint fill];
-#if PLATFORM(MAC)
-#undef addArcWithCenter
-#endif
 }
 
 - (NSSize)intrinsicContentSize
@@ -124,7 +198,6 @@ static void addLinkAndReplace(NSMutableAttributedString *string, NSString *toRep
 
 @end
 
-#if PLATFORM(MAC)
 static NSURL *reportAnErrorURL(const WebKit::SafeBrowsingResult& result)
 {
     return WebCore::URL({ }, makeString(result.reportAnErrorURLBase(), "&url=", encodeWithURLEscapeSequences(result.url()), "&hl=", defaultLanguage()));
@@ -191,14 +264,63 @@ static NSMutableAttributedString *detailsText(const WebKit::SafeBrowsingResult&
     ASSERT(result.isUnwantedSoftware());
     return malwareOrUnwantedSoftwareDetails(result, WEB_UI_NSSTRING(@"Warnings are shown for websites where harmful software has been detected. You can check %the-status-of-site% on the %safeBrowsingProvider% diagnostic page.", "Unwanted software warning description"), @"%the-status-of-site%", false);
 }
+
+static ButtonType *makeButton(WarningItem item, WKSafeBrowsingWarning *warning, SEL action)
+{
+    NSString *title = nil;
+    if (item == WarningItem::ShowDetailsButton)
+        title = WEB_UI_NSSTRING(@"Show details", "Action from safe browsing warning");
+    else
+        title = WEB_UI_NSSTRING(@"Go back", "Action from safe browsing warning");
+    title = [title capitalizedString];
+#if PLATFORM(MAC)
+    return [NSButton buttonWithTitle:title target:warning action:action];
+#else
+    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
+    NSAttributedString *attributedTitle = [[[NSAttributedString alloc] initWithString:title attributes:@{
+        NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),
+        NSUnderlineColorAttributeName:[UIColor whiteColor],
+        NSForegroundColorAttributeName:colorForItem(item, warning),
+        NSFontAttributeName:[FontType systemFontOfSize:textSize]
+    }] autorelease];
+    [button setAttributedTitle:attributedTitle forState:UIControlStateNormal];
+    [button addTarget:warning action:action forControlEvents:UIControlEventTouchUpInside];
+    return button;
+#endif
+}
+
+static ViewType *makeTitleLabel(NSString *title, ViewType *warning)
+{
+    auto attributedString = [[[NSAttributedString alloc] initWithString:title attributes:@{
+        NSFontAttributeName:[FontType boldSystemFontOfSize:titleSize],
+        NSForegroundColorAttributeName:colorForItem(WarningItem::TitleText, warning)
+    }] autorelease];
+#if PLATFORM(MAC)
+    return [NSTextField labelWithAttributedString:attributedString];
+#else
+    auto label = [[UILabel new] autorelease];
+    label.attributedText = attributedString;
+    label.lineBreakMode = NSLineBreakByWordWrapping;
+    label.numberOfLines = 0;
+    return label;
 #endif
+}
+
+static void setBackground(ViewType *view, ColorType *color)
+{
+#if PLATFORM(MAC)
+    view.wantsLayer = YES;
+    view.layer.backgroundColor = color.CGColor;
+#else
+    view.backgroundColor = color;
+#endif
+}
 
 @interface WKSafeBrowsingTextView : TextViewType {
 @package
-    WeakObjCPtr<WKSafeBrowsingWarning> _target;
+    WeakObjCPtr<WKSafeBrowsingWarning> _warning;
 }
-+ (instancetype)viewWithAttributedString:(NSAttributedString *)attributedString linkTarget:(WKSafeBrowsingWarning *)target;
-+ (instancetype)viewWithString:(NSString *)string;
+- (instancetype)initWithAttributedString:(NSAttributedString *)attributedString forWarning:(WKSafeBrowsingWarning *)warning;
 @end
 
 @implementation WKSafeBrowsingWarning
@@ -209,54 +331,157 @@ static NSMutableAttributedString *detailsText(const WebKit::SafeBrowsingResult&
         completionHandler(WebKit::ContinueUnsafeLoad::Yes);
         return nil;
     }
-
     _completionHandler = WTFMove(completionHandler);
     _result = makeRef(result);
-
+    setBackground(self, colorForItem(WarningItem::Background, self));
 #if PLATFORM(MAC)
-    self.wantsLayer = YES;
-    self.layer.backgroundColor = [colorNamed(@"WKSafeBrowsingWarningBackground") CGColor];
-
-    NSStackView *top = [NSStackView stackViewWithViews:@[
-        [[WKSafeBrowsingExclamationPoint new] autorelease],
-        [NSTextField labelWithAttributedString:[[[NSAttributedString alloc] initWithString:titleText(result) attributes:@{
-            NSFontAttributeName:[NSFont systemFontOfSize:exclamationPointSize],
-            NSForegroundColorAttributeName:colorNamed(@"WKSafeBrowsingWarningText")
-        }] autorelease]]
-    ]];
+    [self addContent];
+#endif
+    return self;
+}
+
+- (void)addContent
+{
+    auto exclamationPoint = [[WKSafeBrowsingExclamationPoint new] autorelease];
+    auto title = makeTitleLabel(titleText(*_result), self);
+    auto warning = [[[WKSafeBrowsingTextView alloc] initWithAttributedString:[[[NSAttributedString alloc] initWithString:warningText(*_result) attributes:@{ NSFontAttributeName:[FontType systemFontOfSize:textSize] }] autorelease] forWarning:self] autorelease];
+    auto showDetails = makeButton(WarningItem::ShowDetailsButton, self, @selector(showDetailsClicked));
+    auto goBack = makeButton(WarningItem::GoBackButton, self, @selector(goBackClicked));
+    auto box = [[ViewType new] autorelease];
+    setBackground(box, colorForItem(WarningItem::BoxBackground, self));
+    box.layer.cornerRadius = boxCornerRadius;
+    _textViews = adoptNS([NSMutableArray new]);
+    [_textViews addObject:warning];
+
+    for (ViewType *view in @[exclamationPoint, title, warning, goBack, showDetails]) {
+        view.translatesAutoresizingMaskIntoConstraints = NO;
+        [box addSubview:view];
+    }
+    box.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:box];
+
+#if HAVE(SAFE_BROWSING)
+    [NSLayoutConstraint activateConstraints:@[
+        [[self.topAnchor anchorWithOffsetToAnchor:box.topAnchor] constraintEqualToAnchor:[box.bottomAnchor anchorWithOffsetToAnchor:self.bottomAnchor] multiplier:0.5],
+        [[self.leftAnchor anchorWithOffsetToAnchor:box.leftAnchor] constraintEqualToAnchor:[box.rightAnchor anchorWithOffsetToAnchor:self.rightAnchor]],
+
+        [box.widthAnchor constraintLessThanOrEqualToConstant:maxWidth],
+        [box.widthAnchor constraintLessThanOrEqualToAnchor:self.widthAnchor],
 
-    WKSafeBrowsingTextView *middle = [WKSafeBrowsingTextView viewWithString:warningText(result)];
+        [[box.leadingAnchor anchorWithOffsetToAnchor:exclamationPoint.leadingAnchor] constraintEqualToConstant:marginSize],
+        [[box.leadingAnchor anchorWithOffsetToAnchor:title.leadingAnchor] constraintEqualToConstant:marginSize * 1.5 + exclamationPointSize],
+        [[box.leadingAnchor anchorWithOffsetToAnchor:warning.leadingAnchor] constraintEqualToConstant:marginSize],
 
-    NSStackView *bottom = [NSStackView stackViewWithViews:@[
-        [NSButton buttonWithTitle:WEB_UI_NSSTRING(@"Show details", "Action from safe browsing warning") target:self action:@selector(showDetailsClicked)],
-        [NSButton buttonWithTitle:WEB_UI_NSSTRING(@"Go back", "Action from safe browsing warning") target:self action:@selector(goBackClicked)]
+        [[title.trailingAnchor anchorWithOffsetToAnchor:box.trailingAnchor] constraintGreaterThanOrEqualToConstant:marginSize],
+        [[warning.trailingAnchor anchorWithOffsetToAnchor:box.trailingAnchor] constraintGreaterThanOrEqualToConstant:marginSize],
+        [[goBack.trailingAnchor anchorWithOffsetToAnchor:box.trailingAnchor] constraintEqualToConstant:marginSize],
+
+        [[title.topAnchor anchorWithOffsetToAnchor:exclamationPoint.topAnchor] constraintEqualToAnchor:[exclamationPoint.bottomAnchor anchorWithOffsetToAnchor:title.bottomAnchor]],
+
+        [goBack.topAnchor constraintEqualToAnchor:showDetails.topAnchor],
+        [[showDetails.trailingAnchor anchorWithOffsetToAnchor:goBack.leadingAnchor] constraintEqualToConstant:marginSize],
+
+        [[box.topAnchor anchorWithOffsetToAnchor:title.topAnchor] constraintEqualToConstant:marginSize],
+        [[title.bottomAnchor anchorWithOffsetToAnchor:warning.topAnchor] constraintEqualToConstant:marginSize],
+        [[warning.bottomAnchor anchorWithOffsetToAnchor:goBack.topAnchor] constraintEqualToConstant:marginSize],
+        [[goBack.bottomAnchor anchorWithOffsetToAnchor:box.bottomAnchor] constraintEqualToConstant:marginSize]
     ]];
+#endif
+}
+
+- (void)showDetailsClicked
+{
+    ViewType *box = self.subviews.lastObject;
+    ButtonType *showDetails = box.subviews.lastObject;
+    [showDetails removeFromSuperview];
+
+    NSMutableAttributedString *text = detailsText(*_result);
+    [text addAttributes:@{ NSFontAttributeName:[FontType systemFontOfSize:textSize] } range:NSMakeRange(0, text.length)];
+    WKSafeBrowsingTextView *details = [[[WKSafeBrowsingTextView alloc] initWithAttributedString:text forWarning:self] autorelease];
+    [_textViews addObject:details];
+    ViewType *bottom = [[ViewType new] autorelease];
+    setBackground(bottom, colorForItem(WarningItem::BoxBackground, self));
+    bottom.layer.cornerRadius = boxCornerRadius;
 
-    for (NSStackView *view in @[top, bottom])
-        [view setHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical];
-
-    StackViewType *box = [NSStackView stackViewWithViews:@[top, middle, bottom]];
-    box.wantsLayer = YES;
-    box.layer.backgroundColor = [[NSColor windowBackgroundColor] CGColor];
-    box.layer.cornerRadius = 6;
-    box.alignment = NSLayoutAttributeCenterX;
-    [box.widthAnchor constraintEqualToConstant:maxWidth].active = true;
-    box.edgeInsets = { marginSize, marginSize, marginSize, marginSize };
-    [box setHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical];
-    [self addView:box inGravity:NSStackViewGravityCenter];
+#if HAVE(SAFE_BROWSING)
+    constexpr auto maxY = kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
+    constexpr auto minY = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
+#if PLATFORM(MAC)
+    box.layer.maskedCorners = maxY;
+    bottom.layer.maskedCorners = minY;
 #else
-    // FIXME: Get this working on iOS.
-    completionHandler(WebKit::ContinueUnsafeLoad::Yes);
+    box.layer.maskedCorners = minY;
+    bottom.layer.maskedCorners = maxY;
+#endif
+#endif
+
+    ViewType *line = [[ViewType new] autorelease];
+    setBackground(line, [ColorType lightGrayColor]);
+    for (ViewType *view in @[details, bottom, line])
+        view.translatesAutoresizingMaskIntoConstraints = NO;
+
+    [self addSubview:bottom];
+    [bottom addSubview:line];
+    [bottom addSubview:details];
+#if HAVE(SAFE_BROWSING)
+    [NSLayoutConstraint activateConstraints:@[
+        [box.widthAnchor constraintEqualToAnchor:bottom.widthAnchor],
+        [box.bottomAnchor constraintEqualToAnchor:bottom.topAnchor],
+        [box.leadingAnchor constraintEqualToAnchor:bottom.leadingAnchor],
+        [line.widthAnchor constraintEqualToAnchor:bottom.widthAnchor],
+        [line.leadingAnchor constraintEqualToAnchor:bottom.leadingAnchor],
+        [line.topAnchor constraintEqualToAnchor:bottom.topAnchor],
+        [line.heightAnchor constraintEqualToConstant:1],
+        [[bottom.topAnchor anchorWithOffsetToAnchor:details.topAnchor] constraintEqualToConstant:marginSize],
+        [[details.bottomAnchor anchorWithOffsetToAnchor:bottom.bottomAnchor] constraintEqualToConstant:marginSize],
+        [[bottom.leadingAnchor anchorWithOffsetToAnchor:details.leadingAnchor] constraintEqualToConstant:marginSize],
+        [[details.trailingAnchor anchorWithOffsetToAnchor:bottom.trailingAnchor] constraintEqualToConstant:marginSize],
+    ]];
+#endif
+    [self layoutText];
+#if !PLATFORM(MAC)
+    [self layoutIfNeeded];
+    CGFloat height = 0;
+    for (ViewType *subview in self.subviews)
+        height += subview.frame.size.height;
+    [self setContentSize: { self.frame.size.width, self.frame.size.height / 2 + height }];
 #endif
-    return self;
+}
+
+- (void)layoutText
+{
+    for (WKSafeBrowsingTextView *view in _textViews.get())
+        [view invalidateIntrinsicContentSize];
 }
 
 #if PLATFORM(MAC)
+- (BOOL)textView:(NSTextView *)textView clickedOnLink:(id)link atIndex:(NSUInteger)charIndex
+{
+    [self clickedOnLink:link];
+    return YES;
+}
+
 - (void)layout
 {
-    for (NSView *view in self.subviews.firstObject.subviews)
-        [view invalidateIntrinsicContentSize];
     [super layout];
+    [self layoutText];
+}
+#else
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self layoutText];
+}
+
+- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction
+{
+    [self clickedOnLink:URL];
+    return NO;
+}
+
+- (void)didMoveToWindow
+{
+    [self addContent];
 }
 #endif
 
@@ -273,7 +498,7 @@ static NSMutableAttributedString *detailsText(const WebKit::SafeBrowsingResult&
         _completionHandler(WebKit::ContinueUnsafeLoad::No);
 }
 
-- (void)clickedOnLink:(id)link
+- (void)clickedOnLink:(NSURL *)link
 {
     if (!_completionHandler)
         return;
@@ -304,68 +529,41 @@ static NSMutableAttributedString *detailsText(const WebKit::SafeBrowsingResult&
     _completionHandler((NSURL *)link);
 }
 
-- (void)showDetailsClicked
-{
-#if PLATFORM(MAC)
-    NSStackView *box = self.views.firstObject;
-    NSStackView *bottom = box.views.lastObject;
-    NSButton *showDetailsButton = bottom.views.firstObject;
-    [bottom removeView:showDetailsButton];
-    WKSafeBrowsingTextView *details = [WKSafeBrowsingTextView viewWithAttributedString:detailsText(*_result) linkTarget:self];
-    [box addView:details inGravity:NSStackViewGravityCenter];
-#else
-    // FIXME: Get this working on iOS.
-#endif
-}
-
 @end
 
 @implementation WKSafeBrowsingTextView
 
-+ (instancetype)viewWithAttributedString:(NSAttributedString *)attributedString linkTarget:(WKSafeBrowsingWarning *)target
+- (instancetype)initWithAttributedString:(NSAttributedString *)attributedString forWarning:(WKSafeBrowsingWarning *)warning
 {
-    WKSafeBrowsingTextView *instance = [[self new] autorelease];
-    if (!instance)
+    if (!(self = [super init]))
         return nil;
-    instance->_target = target;
+    self->_warning = warning;
+    self.delegate = warning;
 
-    ColorType *foregroundColor = colorNamed(@"WKSafeBrowsingWarningText");
+    ColorType *foregroundColor = colorForItem(WarningItem::MessageText, warning);
     NSMutableAttributedString *string = [attributedString mutableCopy];
-    [string addAttributes:@{
-        NSForegroundColorAttributeName : foregroundColor,
-        NSFontAttributeName:[FontType systemFontOfSize:textSize]
-    } range:NSMakeRange(0, string.length)];
-
-#if PLATFORM(MAC)
-    [instance setLinkTextAttributes:@{ NSForegroundColorAttributeName : foregroundColor }];
-    [instance setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical];
-    [instance setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical];
-    [instance.widthAnchor constraintLessThanOrEqualToConstant:maxWidth - 2 * marginSize].active = true;
-    [instance setBackgroundColor:[NSColor windowBackgroundColor]];
-    [instance.textStorage appendAttributedString:string];
+    [string addAttributes:@{ NSForegroundColorAttributeName : foregroundColor } range:NSMakeRange(0, string.length)];
+    [self setBackgroundColor:colorForItem(WarningItem::BoxBackground, warning)];
+    [self setLinkTextAttributes:@{ NSForegroundColorAttributeName : foregroundColor }];
+    [self.textStorage appendAttributedString:string];
+    self.editable = NO;
+#if !PLATFORM(MAC)
+    self.scrollEnabled = NO;
 #endif
-    return instance;
-}
 
-+ (instancetype)viewWithString:(NSString *)string
-{
-    return [WKSafeBrowsingTextView viewWithAttributedString:[[[NSMutableAttributedString alloc] initWithString:string] autorelease] linkTarget:nil];
+    return self;
 }
 
-- (NSSize)intrinsicContentSize
+- (SizeType)intrinsicContentSize
 {
-    [self.layoutManager ensureLayoutForTextContainer:self.textContainer];
-    auto size = [self.layoutManager usedRectForTextContainer:self.textContainer].size;
 #if PLATFORM(MAC)
-    return { NSViewNoIntrinsicMetric, size.height };
+    [self.layoutManager ensureLayoutForTextContainer:self.textContainer];
+    return { NSViewNoIntrinsicMetric, [self.layoutManager usedRectForTextContainer:self.textContainer].size.height };
 #else
-    return { UIViewNoIntrinsicMetric, size.height };
+    auto width = std::min<CGFloat>(maxWidth, [_warning frame].size.width) - 2 * marginSize;
+    constexpr auto noHeightConstraint = CGFLOAT_MAX;
+    return { width, [self sizeThatFits: { width, noHeightConstraint }].height };
 #endif
 }
 
-- (void)clickedOnLink:(id)link atIndex:(NSUInteger)charIndex
-{
-    [_target clickedOnLink:link];
-}
-
 @end
index e0f3c0a..4ab814a 100644 (file)
@@ -62,7 +62,7 @@
 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
 #import <wtf/BlockPtr.h>
 
-#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_webView->_page->process().connection())
+#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_webView.get()->_page->process().connection())
 
 @interface WKEditCommandObjC : NSObject
 {
@@ -161,18 +161,18 @@ IntSize PageClientImpl::viewSize()
 bool PageClientImpl::isViewWindowActive()
 {
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098
-    return isViewVisible() || (m_webView && [m_webView _isRetainingActiveFocusedState]);
+    return isViewVisible() || [m_webView _isRetainingActiveFocusedState];
 }
 
 bool PageClientImpl::isViewFocused()
 {
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098
-    return isViewWindowActive() || (m_webView && [m_webView _isRetainingActiveFocusedState]);
+    return isViewWindowActive() || [m_webView _isRetainingActiveFocusedState];
 }
 
 bool PageClientImpl::isViewVisible()
 {
-    if (isViewInWindow() && !m_webView._isBackground)
+    if (isViewInWindow() && ![m_webView _isBackground])
         return true;
     
     if ([m_webView _isShowingVideoPictureInPicture])
@@ -187,8 +187,8 @@ bool PageClientImpl::isViewVisible()
 bool PageClientImpl::isViewInWindow()
 {
     // FIXME: in WebKitTestRunner, m_webView is nil, so check the content view instead.
-    if (m_webView)
-        return [m_webView window];
+    if (auto webView = m_webView.get())
+        return [webView window];
 
     return [m_contentView window];
 }
@@ -248,7 +248,7 @@ void PageClientImpl::didCompleteSyntheticClick()
 
 void PageClientImpl::decidePolicyForGeolocationPermissionRequest(WebFrameProxy& frame, API::SecurityOrigin& origin, Function<void(bool)>& completionHandler)
 {
-    [[wrapper(m_webView->_page->process().processPool()) _geolocationProvider] decidePolicyForGeolocationRequestFromOrigin:origin.securityOrigin() frame:frame completionHandler:std::exchange(completionHandler, nullptr) view:m_webView];
+    [[wrapper(m_webView.get()->_page->process().processPool()) _geolocationProvider] decidePolicyForGeolocationRequestFromOrigin:origin.securityOrigin() frame:frame completionHandler:std::exchange(completionHandler, nullptr) view:m_webView.get().get()];
 }
 
 void PageClientImpl::didStartProvisionalLoadForMainFrame()
@@ -469,18 +469,21 @@ void PageClientImpl::setTextIndicatorAnimationProgress(float)
 {
 }
 
-void PageClientImpl::showSafeBrowsingWarning(const SafeBrowsingResult&, CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)>&& completionHandler)
+void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
 {
-    completionHandler(WebKit::ContinueUnsafeLoad::Yes); // FIXME: Implement.
 }
 
-void PageClientImpl::clearSafeBrowsingWarning()
+void PageClientImpl::showSafeBrowsingWarning(const SafeBrowsingResult& result, CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, WebCore::URL>&&)>&& completionHandler)
 {
-    // FIXME: Implement.
+    if (auto webView = m_webView.get())
+        [webView _showSafeBrowsingWarning:result completionHandler:WTFMove(completionHandler)];
+    else
+        completionHandler(ContinueUnsafeLoad::No);
 }
 
-void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
+void PageClientImpl::clearSafeBrowsingWarning()
 {
+    [m_webView _clearSafeBrowsingWarning];
 }
 
 void PageClientImpl::exitAcceleratedCompositingMode()
@@ -695,23 +698,23 @@ void PageClientImpl::scrollingNodeScrollDidEndScroll()
 
 Vector<String> PageClientImpl::mimeTypesWithCustomContentProviders()
 {
-    return m_webView._contentProviderRegistry._mimeTypesWithCustomContentProviders;
+    return [m_webView _contentProviderRegistry]._mimeTypesWithCustomContentProviders;
 }
 
 void PageClientImpl::navigationGestureDidBegin()
 {
     [m_webView _navigationGestureDidBegin];
-    NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidBegin();
+    NavigationState::fromWebPage(*m_webView.get()->_page).navigationGestureDidBegin();
 }
 
 void PageClientImpl::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
 {
-    NavigationState::fromWebPage(*m_webView->_page).navigationGestureWillEnd(willNavigate, item);
+    NavigationState::fromWebPage(*m_webView.get()->_page).navigationGestureWillEnd(willNavigate, item);
 }
 
 void PageClientImpl::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
 {
-    NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidEnd(willNavigate, item);
+    NavigationState::fromWebPage(*m_webView.get()->_page).navigationGestureDidEnd(willNavigate, item);
     [m_webView _navigationGestureDidEnd];
 }
 
@@ -722,12 +725,12 @@ void PageClientImpl::navigationGestureDidEnd()
 
 void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem& item)
 {
-    NavigationState::fromWebPage(*m_webView->_page).willRecordNavigationSnapshot(item);
+    NavigationState::fromWebPage(*m_webView.get()->_page).willRecordNavigationSnapshot(item);
 }
 
 void PageClientImpl::didRemoveNavigationGestureSnapshot()
 {
-    NavigationState::fromWebPage(*m_webView->_page).navigationGestureSnapshotWasRemoved();
+    NavigationState::fromWebPage(*m_webView.get()->_page).navigationGestureSnapshotWasRemoved();
 }
 
 void PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame()
@@ -840,7 +843,7 @@ void PageClientImpl::requestPasswordForQuickLookDocument(const String& fileName,
         completionHandler(password);
     });
 
-    if (WKPasswordView *passwordView = m_webView._passwordView) {
+    if (WKPasswordView *passwordView = [m_webView _passwordView]) {
         ASSERT(fileName == String { passwordView.documentName });
         [passwordView showPasswordFailureAlert];
         passwordView.userDidEnterPassword = passwordHandler.get();
@@ -848,7 +851,7 @@ void PageClientImpl::requestPasswordForQuickLookDocument(const String& fileName,
     }
 
     [m_webView _showPasswordViewWithDocumentName:fileName passwordHandler:passwordHandler.get()];
-    NavigationState::fromWebPage(*m_webView->_page).didRequestPasswordForQuickLookDocument();
+    NavigationState::fromWebPage(*m_webView.get()->_page).didRequestPasswordForQuickLookDocument();
 }
 #endif
 
index 0d67201..c98a547 100644 (file)
@@ -564,7 +564,7 @@ void PageClientImpl::selectionDidChange()
 #if WK_API_ENABLED
 bool PageClientImpl::showShareSheet(const ShareDataWithParsedURL& shareData, WTF::CompletionHandler<void(bool)>&& completionHandler)
 {
-    m_impl->showShareSheet(shareData, WTFMove(completionHandler), m_webView);
+    m_impl->showShareSheet(shareData, WTFMove(completionHandler), m_webView.get().get());
     return true;
 }
 #endif
@@ -753,16 +753,16 @@ void PageClientImpl::navigationGestureDidBegin()
     m_impl->dismissContentRelativeChildWindowsWithAnimation(true);
 
 #if WK_API_ENABLED
-    if (m_webView)
-        NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidBegin();
+    if (auto webView = m_webView.get())
+        NavigationState::fromWebPage(*webView->_page).navigationGestureDidBegin();
 #endif
 }
 
 void PageClientImpl::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
 {
 #if WK_API_ENABLED
-    if (m_webView)
-        NavigationState::fromWebPage(*m_webView->_page).navigationGestureWillEnd(willNavigate, item);
+    if (auto webView = m_webView.get())
+        NavigationState::fromWebPage(*webView->_page).navigationGestureWillEnd(willNavigate, item);
 #else
     UNUSED_PARAM(willNavigate);
     UNUSED_PARAM(item);
@@ -772,8 +772,8 @@ void PageClientImpl::navigationGestureWillEnd(bool willNavigate, WebBackForwardL
 void PageClientImpl::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
 {
 #if WK_API_ENABLED
-    if (m_webView)
-        NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidEnd(willNavigate, item);
+    if (auto webView = m_webView.get())
+        NavigationState::fromWebPage(*webView->_page).navigationGestureDidEnd(willNavigate, item);
 #else
     UNUSED_PARAM(willNavigate);
     UNUSED_PARAM(item);
@@ -787,8 +787,8 @@ void PageClientImpl::navigationGestureDidEnd()
 void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem& item)
 {
 #if WK_API_ENABLED
-    if (m_webView)
-        NavigationState::fromWebPage(*m_webView->_page).willRecordNavigationSnapshot(item);
+    if (auto webView = m_webView.get())
+        NavigationState::fromWebPage(*webView->_page).willRecordNavigationSnapshot(item);
 #else
     UNUSED_PARAM(item);
 #endif
@@ -797,8 +797,8 @@ void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem& item)
 void PageClientImpl::didRemoveNavigationGestureSnapshot()
 {
 #if WK_API_ENABLED
-    if (m_webView)
-        NavigationState::fromWebPage(*m_webView->_page).navigationGestureSnapshotWasRemoved();
+    if (auto webView = m_webView.get())
+        NavigationState::fromWebPage(*webView->_page).navigationGestureSnapshotWasRemoved();
 #endif
 }
 
index b252842..3a89a27 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-12  Alex Christensen  <achristensen@webkit.org>
+
+        [iOS] Implement safe browsing in WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=191441
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/SafeBrowsing.mm:
+        (checkTitleAndClick):
+        (TEST):
+
 2018-11-12  Basuke Suzuki  <basuke.suzuki@sony.com>
 
         [Curl] Add API Test for Curl cookie backend.
index 7dea6dd..48b99ef 100644 (file)
@@ -137,8 +137,6 @@ static bool committedNavigation;
 
 @end
 
-#if PLATFORM(MAC) // FIXME: Test on iOS once implemented.
-
 static NSURL *simpleURL()
 {
     return [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
@@ -154,31 +152,46 @@ static RetainPtr<WKWebView> safeBrowsingView()
     [webView loadRequest:[NSURLRequest requestWithURL:simpleURL()]];
     while (![webView _safeBrowsingWarningForTesting])
         TestWebKitAPI::Util::spinRunLoop();
+#if !PLATFORM(MAC)
+    [[webView _safeBrowsingWarningForTesting] didMoveToWindow];
+#endif
     return webView;
 }
 
+#if PLATFORM(MAC)
+static void checkTitleAndClick(NSButton *button, const char* expectedTitle)
+{
+    EXPECT_STREQ(button.title.UTF8String, expectedTitle);
+    [button performClick:nil];
+}
+#else
+static void checkTitleAndClick(UIButton *button, const char* expectedTitle)
+{
+    EXPECT_STREQ([button attributedTitleForState:UIControlStateNormal].string.UTF8String, expectedTitle);
+    UIView *target = button.superview.superview;
+    SEL selector = NSSelectorFromString(strcmp(expectedTitle, "Go Back") ? @"showDetailsClicked" : @"goBackClicked");
+    [target performSelector:selector];
+}
+#endif
+
 TEST(SafeBrowsing, GoBack)
 {
     auto webView = safeBrowsingView();
-    NSView *bottom = [webView _safeBrowsingWarningForTesting].subviews.firstObject.subviews.lastObject;
-    NSButton *goBack = (NSButton *)bottom.subviews.lastObject;
-    EXPECT_STREQ(goBack.title.UTF8String, "Go back");
-    [goBack performClick:nil];
+    auto warning = [webView _safeBrowsingWarningForTesting];
+    auto box = warning.subviews.firstObject;
+    checkTitleAndClick(box.subviews[3], "Go Back");
     EXPECT_EQ([webView _safeBrowsingWarningForTesting], nil);
 }
 
 TEST(SafeBrowsing, VisitUnsafeWebsite)
 {
     auto webView = safeBrowsingView();
-    NSView *warning = [webView _safeBrowsingWarningForTesting];
-    NSView *box = warning.subviews.firstObject;
-    NSButton *showDetails = (NSButton *)box.subviews.lastObject.subviews.firstObject;
-    EXPECT_STREQ(showDetails.title.UTF8String, "Show details");
-    EXPECT_EQ(box.subviews.count, 3ull);
-    [showDetails performClick:nil];
-    EXPECT_EQ(box.subviews.count, 4ull);
+    auto warning = [webView _safeBrowsingWarningForTesting];
+    EXPECT_EQ(warning.subviews.count, 1ull);
+    checkTitleAndClick(warning.subviews.firstObject.subviews[4], "Show Details");
+    EXPECT_EQ(warning.subviews.count, 2ull);
     EXPECT_FALSE(committedNavigation);
-    [warning performSelector:NSSelectorFromString(@"clickedOnLink:") withObject:@"WKVisitUnsafeWebsiteSentinel"];
+    [warning performSelector:NSSelectorFromString(@"clickedOnLink:") withObject:[NSURL URLWithString:@"WKVisitUnsafeWebsiteSentinel"]];
     TestWebKitAPI::Util::run(&committedNavigation);
 }
 
@@ -191,8 +204,6 @@ TEST(SafeBrowsing, NavigationClearsWarning)
         TestWebKitAPI::Util::spinRunLoop();
 }
 
-#endif // PLATFORM(MAC)
-
 @interface NullLookupContext : NSObject
 @end
 @implementation NullLookupContext