Title: [238471] trunk
Revision
238471
Author
wenson_hs...@apple.com
Date
2018-11-24 13:06:09 -0800 (Sat, 24 Nov 2018)

Log Message

[Cocoa] Add WKWebView SPI to trigger and remove data detection
https://bugs.webkit.org/show_bug.cgi?id=191918
<rdar://problem/36185051>

Reviewed by Tim Horton.

Source/WebCore:

Add a helper method on DataDetection to remove all data detected links in the given document. See WebKit changes
for more detail.

* editing/cocoa/DataDetection.h:
* editing/cocoa/DataDetection.mm:
(WebCore::DataDetection::removeDataDetectedLinksInDocument):

Source/WebKit:

Adds support for two new WKWebView SPI methods, `-_detectDataWithTypes:completionHandler:` and
`-_removeAllDataDetectedLinks:`, to allow internal WebKit clients to run data detection and add links to data
detected content, or remove all data detected links from the document.

Test: WebKit.AddAndRemoveDataDetectors

* Shared/Cocoa/DataDetectionResult.h:
* Shared/Cocoa/DataDetectionResult.mm:
(WebKit::DataDetectionResult::decode):

Modernize DataDetectionResult's IPC decoding, so that it can be used with reply-based async IPC.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _removeDataDetectedLinks:]):
(-[WKWebView _detectDataWithTypes:completionHandler:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::detectDataInAllFrames):
(WebKit::WebPageProxy::removeDataDetectedLinks):

Add or remove data detected links from each frame in the page, and then propagate the new data detector
results of the main frame to the UI process (this matches current behavior, where the results of -[WKWebView
_dataDetectionResults] only reflects data detection results in the main frame of the page).

* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::removeDataDetectedLinks):
(WebKit::WebPage::detectDataInAllFrames):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Add an API test to exercise the new WebKit SPI.

* TestWebKitAPI/DataDetectorsCoreSPI.h: Added.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/DataDetection.mm:
(-[WKWebView synchronouslyDetectDataWithTypes:]):
(-[WKWebView synchronouslyRemoveDataDetectedLinks]):
(TEST):
* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(TestWebKitAPI::TEST):
(-[TestWKWebView tagsInBody]): Deleted.
(-[TestWKWebView expectElementTagsInOrder:]): Deleted.
(-[TestWKWebView expectElementCount:tagName:]): Deleted.
(-[TestWKWebView expectElementTag:toComeBefore:]): Deleted.

Rename this from `-expectElementCount:tagName:` to `-expectElementCount:querySelector:`.

* TestWebKitAPI/Tests/WebKitCocoa/data-detectors.html: Added.

Add a new test page containing some content that can be data detected.

* TestWebKitAPI/cocoa/TestWKWebView.h:
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[WKWebView tagsInBody]):
(-[WKWebView expectElementTagsInOrder:]):
(-[WKWebView expectElementCount:querySelector:]):
(-[WKWebView expectElementTag:toComeBefore:]):

Move some testing helper functions from WKAttachmentTests to a testing category on WKWebView. This allows us to
use `-expectElementCount:querySelector:` in tests outside of WKAttachmentTests.

(-[WKWebView objectByEvaluatingJavaScript:]):
(-[WKWebView objectByEvaluatingJavaScriptWithUserGesture:]):
(-[WKWebView stringByEvaluatingJavaScript:]):

Move some common helper functions from TestWKWebView to a testing category on WKWebView.

(-[TestWKWebView objectByEvaluatingJavaScript:]): Deleted.
(-[TestWKWebView objectByEvaluatingJavaScriptWithUserGesture:]): Deleted.
(-[TestWKWebView stringByEvaluatingJavaScript:]): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (238470 => 238471)


--- trunk/Source/WebCore/ChangeLog	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebCore/ChangeLog	2018-11-24 21:06:09 UTC (rev 238471)
@@ -1,3 +1,18 @@
+2018-11-24  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Cocoa] Add WKWebView SPI to trigger and remove data detection
+        https://bugs.webkit.org/show_bug.cgi?id=191918
+        <rdar://problem/36185051>
+
+        Reviewed by Tim Horton.
+
+        Add a helper method on DataDetection to remove all data detected links in the given document. See WebKit changes
+        for more detail.
+
+        * editing/cocoa/DataDetection.h:
+        * editing/cocoa/DataDetection.mm:
+        (WebCore::DataDetection::removeDataDetectedLinksInDocument):
+
 2018-11-24  Andy Estes  <aes...@apple.com>
 
         [Cocoa] SOFT_LINK_CLASS_FOR_{HEADER,SOURCE} should generate a more concise getter function

Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.h (238470 => 238471)


--- trunk/Source/WebCore/editing/cocoa/DataDetection.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -37,6 +37,7 @@
 
 namespace WebCore {
 
+class Document;
 class Element;
 class FloatRect;
 class HitTestResult;
@@ -61,6 +62,7 @@
     WEBCORE_EXPORT static RetainPtr<DDActionContext> detectItemAroundHitTestResult(const HitTestResult&, FloatRect& detectedDataBoundingBox, RefPtr<Range>& detectedDataRange);
 #endif
     WEBCORE_EXPORT static NSArray *detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes, NSDictionary *context);
+    WEBCORE_EXPORT static void removeDataDetectedLinksInDocument(Document&);
 #if PLATFORM(IOS_FAMILY)
     WEBCORE_EXPORT static bool canBePresentedByDataDetectors(const URL&);
     WEBCORE_EXPORT static bool isDataDetectorLink(Element&);

Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.mm (238470 => 238471)


--- trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -429,6 +429,16 @@
     return kCFCompareEqualTo;
 }
 
+void DataDetection::removeDataDetectedLinksInDocument(Document& document)
+{
+    Vector<Ref<HTMLAnchorElement>> allAnchorElements;
+    for (auto& anchor : descendantsOfType<HTMLAnchorElement>(document))
+        allAnchorElements.append(anchor);
+
+    for (auto& anchor : allAnchorElements)
+        removeResultLinksFromAnchor(anchor.get());
+}
+
 NSArray *DataDetection::detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes types, NSDictionary *context)
 {
     RetainPtr<DDScannerRef> scanner = adoptCF(softLink_DataDetectorsCore_DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
@@ -647,10 +657,16 @@
 }
 
 #else
+
 NSArray *DataDetection::detectContentInRange(RefPtr<Range>&, DataDetectorTypes, NSDictionary *)
 {
     return nil;
 }
+
+void DataDetection::removeDataDetectedLinksInDocument(Document&)
+{
+}
+
 #endif
 
 const String& DataDetection::dataDetectorURLProtocol()

Modified: trunk/Source/WebKit/ChangeLog (238470 => 238471)


--- trunk/Source/WebKit/ChangeLog	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/ChangeLog	2018-11-24 21:06:09 UTC (rev 238471)
@@ -1,3 +1,42 @@
+2018-11-24  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Cocoa] Add WKWebView SPI to trigger and remove data detection
+        https://bugs.webkit.org/show_bug.cgi?id=191918
+        <rdar://problem/36185051>
+
+        Reviewed by Tim Horton.
+
+        Adds support for two new WKWebView SPI methods, `-_detectDataWithTypes:completionHandler:` and
+        `-_removeAllDataDetectedLinks:`, to allow internal WebKit clients to run data detection and add links to data
+        detected content, or remove all data detected links from the document.
+
+        Test: WebKit.AddAndRemoveDataDetectors
+
+        * Shared/Cocoa/DataDetectionResult.h:
+        * Shared/Cocoa/DataDetectionResult.mm:
+        (WebKit::DataDetectionResult::decode):
+
+        Modernize DataDetectionResult's IPC decoding, so that it can be used with reply-based async IPC.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _removeDataDetectedLinks:]):
+        (-[WKWebView _detectDataWithTypes:completionHandler:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::detectDataInAllFrames):
+        (WebKit::WebPageProxy::removeDataDetectedLinks):
+
+        Add or remove data detected links from each frame in the page, and then propagate the new data detector
+        results of the main frame to the UI process (this matches current behavior, where the results of -[WKWebView
+        _dataDetectionResults] only reflects data detection results in the main frame of the page).
+
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::removeDataDetectedLinks):
+        (WebKit::WebPage::detectDataInAllFrames):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2018-11-24  Andy Estes  <aes...@apple.com>
 
         [Cocoa] SOFT_LINK_CLASS_FOR_{HEADER,SOURCE} should generate a more concise getter function

Modified: trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.h (238470 => 238471)


--- trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -38,7 +38,7 @@
     RetainPtr<NSArray> results;
 
     void encode(IPC::Encoder&) const;
-    static bool decode(IPC::Decoder&, DataDetectionResult&);
+    static std::optional<DataDetectionResult> decode(IPC::Decoder&);
 };
 
 }

Modified: trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.mm (238470 => 238471)


--- trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -46,22 +46,23 @@
     IPC::encode(encoder, (__bridge CFDataRef)archiver.get().encodedData);
 }
 
-bool DataDetectionResult::decode(IPC::Decoder& decoder, DataDetectionResult& result)
+std::optional<DataDetectionResult> DataDetectionResult::decode(IPC::Decoder& decoder)
 {
     RetainPtr<CFDataRef> data;
     if (!IPC::decode(decoder, data))
-        return false;
+        return std::nullopt;
 
+    DataDetectionResult result;
     auto unarchiver = secureUnarchiverFromData((__bridge NSData *)data.get());
     @try {
         result.results = [unarchiver decodeObjectOfClasses:[NSSet setWithArray:@[ [NSArray class], getDDScannerResultClass()] ] forKey:@"dataDetectorResults"];
     } @catch (NSException *exception) {
         LOG_ERROR("Failed to decode NSArray of DDScanResult: %@", exception);
-        return false;
+        return std::nullopt;
     }
     
     [unarchiver finishDecoding];
-    return true;
+    return { WTFMove(result) };
 }
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (238470 => 238471)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -5423,10 +5423,39 @@
     _page->setMuted(coreState);
 }
 
+- (void)_removeDataDetectedLinks:(dispatch_block_t)completion
+{
+#if ENABLE(DATA_DETECTION)
+    _page->removeDataDetectedLinks([completion = makeBlockPtr(completion), page = makeWeakPtr(_page.get())] (auto& result) {
+        if (page)
+            page->setDataDetectionResult(result);
+        if (completion)
+            completion();
+    });
+#else
+    UNUSED_PARAM(completion);
+#endif
+}
+
 #pragma mark iOS-specific methods
 
 #if PLATFORM(IOS_FAMILY)
 
+- (void)_detectDataWithTypes:(WKDataDetectorTypes)types completionHandler:(dispatch_block_t)completion
+{
+#if ENABLE(DATA_DETECTION)
+    _page->detectDataInAllFrames(fromWKDataDetectorTypes(types), [completion = makeBlockPtr(completion), page = makeWeakPtr(_page.get())] (auto& result) {
+        if (page)
+            page->setDataDetectionResult(result);
+        if (completion)
+            completion();
+    });
+#else
+    UNUSED_PARAM(types);
+    UNUSED_PARAM(completion);
+#endif
+}
+
 #if ENABLE(FULLSCREEN_API)
 - (void)removeFromSuperview
 {

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (238470 => 238471)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -27,6 +27,7 @@
 
 #if WK_API_ENABLED
 
+#import <WebKit/WKDataDetectorTypes.h>
 #import <WebKit/_WKActivatedElementInfo.h>
 #import <WebKit/_WKAttachment.h>
 #import <WebKit/_WKFindOptions.h>
@@ -193,6 +194,8 @@
 - (void)_showSafeBrowsingWarningWithTitle:(NSString *)title warning:(NSString *)warning details:(NSAttributedString *)details completionHandler:(void(^)(BOOL))completionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 - (void)_isJITEnabled:(void(^)(BOOL))completionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_removeDataDetectedLinks:(dispatch_block_t)completion WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 - (IBAction)_alignCenter:(id)sender WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (IBAction)_alignJustified:(id)sender WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (IBAction)_alignLeft:(id)sender WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@@ -216,6 +219,8 @@
 - (void)_setFontSize:(CGFloat)fontSize sender:(id)sender WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (void)_setTextColor:(UIColor *)color sender:(id)sender WK_API_AVAILABLE(ios(WK_IOS_TBA));
 
+- (void)_detectDataWithTypes:(WKDataDetectorTypes)types completionHandler:(dispatch_block_t)completion WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
 // DERECATED: The setters of the three following function are deprecated, please use overrideLayoutParameters.
 // Define the smallest size a page take with a regular viewport.
 @property (nonatomic, readonly) CGSize _minimumLayoutSizeOverride;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (238470 => 238471)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-11-24 21:06:09 UTC (rev 238471)
@@ -8243,6 +8243,20 @@
 #endif
 }
 
+#if ENABLE(DATA_DETECTION)
+
+void WebPageProxy::detectDataInAllFrames(WebCore::DataDetectorTypes types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
+{
+    m_process->connection()->sendWithAsyncReply(Messages::WebPage::DetectDataInAllFrames(static_cast<uint64_t>(types)), WTFMove(completionHandler), m_pageID);
+}
+
+void WebPageProxy::removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
+{
+    m_process->connection()->sendWithAsyncReply(Messages::WebPage::RemoveDataDetectedLinks(), WTFMove(completionHandler), m_pageID);
+}
+
+#endif
+
 } // namespace WebKit
 
 #undef MERGE_WHEEL_EVENTS

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (238470 => 238471)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -362,6 +362,8 @@
 
 #if ENABLE(DATA_DETECTION)
     NSArray *dataDetectionResults() { return m_dataDetectionResults.get(); }
+    void detectDataInAllFrames(WebCore::DataDetectorTypes, CompletionHandler<void(const DataDetectionResult&)>&&);
+    void removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&&);
 #endif
         
 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (238470 => 238471)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-11-24 21:06:09 UTC (rev 238471)
@@ -3385,6 +3385,7 @@
 }
 
 #if ENABLE(DATA_DETECTION)
+
 void WebPage::setDataDetectionResults(NSArray *detectionResults)
 {
     DataDetectionResult dataDetectionResult;
@@ -3391,8 +3392,36 @@
     dataDetectionResult.results = detectionResults;
     send(Messages::WebPageProxy::SetDataDetectionResult(dataDetectionResult));
 }
-#endif
 
+void WebPage::removeDataDetectedLinks(Messages::WebPage::RemoveDataDetectedLinks::AsyncReply&& reply)
+{
+    for (auto frame = makeRefPtr(&m_page->mainFrame()); frame; frame = frame->tree().traverseNext()) {
+        auto document = makeRefPtr(frame->document());
+        if (!document)
+            continue;
+
+        DataDetection::removeDataDetectedLinksInDocument(*document);
+        frame->setDataDetectionResults(nullptr);
+    }
+    reply({ m_page->mainFrame().dataDetectionResults() });
+}
+
+void WebPage::detectDataInAllFrames(uint64_t types, Messages::WebPage::DetectDataInAllFrames::AsyncReply&& reply)
+{
+    auto dataDetectorTypes = static_cast<WebCore::DataDetectorTypes>(types);
+    for (auto frame = makeRefPtr(&m_page->mainFrame()); frame; frame = frame->tree().traverseNext()) {
+        auto document = makeRefPtr(frame->document());
+        if (!document)
+            continue;
+
+        RefPtr<Range> range = Range::create(*document, Position { document.get(), Position::PositionIsBeforeChildren }, Position { document.get(), Position::PositionIsAfterChildren });
+        frame->setDataDetectionResults(DataDetection::detectContentInRange(range, dataDetectorTypes, m_dataDetectionContext.get()));
+    }
+    reply({ m_page->mainFrame().dataDetectionResults() });
+}
+
+#endif // ENABLE(DATA_DETECTION)
+
 #if PLATFORM(COCOA)
 void WebPage::willCommitLayerTree(RemoteLayerTreeTransaction& layerTransaction)
 {

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (238470 => 238471)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -48,6 +48,7 @@
 #include "SharedMemory.h"
 #include "UserData.h"
 #include "WebBackForwardListProxy.h"
+#include "WebPageMessages.h"
 #include "WebURLSchemeHandler.h"
 #include "WebUserContentController.h"
 #include <_javascript_Core/InspectorFrontendChannel.h>
@@ -92,7 +93,6 @@
 
 #if PLATFORM(IOS_FAMILY)
 #include "GestureTypes.h"
-#include "WebPageMessages.h"
 #include <WebCore/IntPointHash.h>
 #include <WebCore/ViewportConfiguration.h>
 #endif
@@ -107,6 +107,10 @@
 #include <WebCore/PlatformTouchEvent.h>
 #endif
 
+#if ENABLE(DATA_DETECTION)
+#include <WebCore/DataDetection.h>
+#endif
+
 #if ENABLE(MAC_GESTURE_EVENTS)
 #include <WebKitAdditions/PlatformGestureEventMac.h>
 #endif
@@ -992,6 +996,8 @@
 
 #if ENABLE(DATA_DETECTION)
     void setDataDetectionResults(NSArray *);
+    void detectDataInAllFrames(uint64_t, Messages::WebPage::DetectDataInAllFrames::AsyncReply&&);
+    void removeDataDetectedLinks(Messages::WebPage::RemoveDataDetectedLinks::AsyncReply&&);
 #endif
 
     unsigned extendIncrementalRenderingSuppression();

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (238470 => 238471)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2018-11-24 21:06:09 UTC (rev 238471)
@@ -193,6 +193,11 @@
     PerformDictionaryLookupAtLocation(WebCore::FloatPoint point)
 #endif
 
+#if ENABLE(DATA_DETECTION)
+    DetectDataInAllFrames(uint64_t types) -> (struct WebKit::DataDetectionResult result) Async
+    RemoveDataDetectedLinks() -> (struct WebKit::DataDetectionResult result) Async
+#endif
+
 #if PLATFORM(MAC)
     PerformDictionaryLookupOfCurrentSelection()
 #endif

Modified: trunk/Tools/ChangeLog (238470 => 238471)


--- trunk/Tools/ChangeLog	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/ChangeLog	2018-11-24 21:06:09 UTC (rev 238471)
@@ -1,3 +1,52 @@
+2018-11-24  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Cocoa] Add WKWebView SPI to trigger and remove data detection
+        https://bugs.webkit.org/show_bug.cgi?id=191918
+        <rdar://problem/36185051>
+
+        Reviewed by Tim Horton.
+
+        Add an API test to exercise the new WebKit SPI.
+
+        * TestWebKitAPI/DataDetectorsCoreSPI.h: Added.
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/DataDetection.mm:
+        (-[WKWebView synchronouslyDetectDataWithTypes:]):
+        (-[WKWebView synchronouslyRemoveDataDetectedLinks]):
+        (TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+        (TestWebKitAPI::TEST):
+        (-[TestWKWebView tagsInBody]): Deleted.
+        (-[TestWKWebView expectElementTagsInOrder:]): Deleted.
+        (-[TestWKWebView expectElementCount:tagName:]): Deleted.
+        (-[TestWKWebView expectElementTag:toComeBefore:]): Deleted.
+
+        Rename this from `-expectElementCount:tagName:` to `-expectElementCount:querySelector:`.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/data-detectors.html: Added.
+
+        Add a new test page containing some content that can be data detected.
+
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[WKWebView tagsInBody]):
+        (-[WKWebView expectElementTagsInOrder:]):
+        (-[WKWebView expectElementCount:querySelector:]):
+        (-[WKWebView expectElementTag:toComeBefore:]):
+
+        Move some testing helper functions from WKAttachmentTests to a testing category on WKWebView. This allows us to
+        use `-expectElementCount:querySelector:` in tests outside of WKAttachmentTests.
+
+        (-[WKWebView objectByEvaluatingJavaScript:]):
+        (-[WKWebView objectByEvaluatingJavaScriptWithUserGesture:]):
+        (-[WKWebView stringByEvaluatingJavaScript:]):
+
+        Move some common helper functions from TestWKWebView to a testing category on WKWebView.
+
+        (-[TestWKWebView objectByEvaluatingJavaScript:]): Deleted.
+        (-[TestWKWebView objectByEvaluatingJavaScriptWithUserGesture:]): Deleted.
+        (-[TestWKWebView stringByEvaluatingJavaScript:]): Deleted.
+
 2018-11-23  Sam Weinig  <s...@webkit.org>
 
         Add raw pointer overloads to ListHashSet via SmartPtr specialized functions

Copied: trunk/Tools/TestWebKitAPI/DataDetectorsCoreSPI.h (from rev 238470, trunk/Source/WebKit/Shared/Cocoa/DataDetectionResult.h) (0 => 238471)


--- trunk/Tools/TestWebKitAPI/DataDetectorsCoreSPI.h	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/DataDetectorsCoreSPI.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(DATA_DETECTION)
+
+#import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
+
+#if !USE(APPLE_INTERNAL_SDK)
+
+@interface DDScannerResult (Private)
+@property (readonly, nonatomic) NSString *value;
+@property (readonly, nonatomic) NSString *type;
+@property (readonly, nonatomic) DDResultCategory category;
+@end
+
+#endif // !USE(APPLE_INTERNAL_SDK)
+
+#endif // ENABLE(DATA_DETECTION)

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (238470 => 238471)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-11-24 21:06:09 UTC (rev 238471)
@@ -852,6 +852,7 @@
 		F46A095A1ED8A6E600D4AA55 /* apple.gif in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30EB1ED28619000482E1 /* apple.gif */; };
 		F46A095B1ED8A6E600D4AA55 /* gif-and-file-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */; };
 		F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; };
+		F47DFB2621A878DF00021FB6 /* data-detectors.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47DFB2421A8704A00021FB6 /* data-detectors.html */; };
 		F4811E5921940BDE00A5E0FD /* WKWebViewEditActions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4811E5821940B4400A5E0FD /* WKWebViewEditActions.mm */; };
 		F4856CA31E649EA8009D7EE7 /* attachment-element.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4856CA21E6498A8009D7EE7 /* attachment-element.html */; };
 		F486B1D01F67952300F34BDD /* DataTransfer-setDragImage.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */; };
@@ -1019,6 +1020,7 @@
 				7AEAD4811E20122700416EFE /* CrossPartitionFileSchemeAccess.html in Copy Resources */,
 				F4AB578A1F65165400DB0DA1 /* custom-draggable-div.html in Copy Resources */,
 				290F4275172A221C00939FF0 /* custom-protocol-sync-xhr.html in Copy Resources */,
+				F47DFB2621A878DF00021FB6 /* data-detectors.html in Copy Resources */,
 				F486B1D01F67952300F34BDD /* DataTransfer-setDragImage.html in Copy Resources */,
 				F457A9D6202D68AF00F7E9D5 /* DataTransfer.html in Copy Resources */,
 				F4512E131F60C44600BB369E /* DataTransferItem-getAsEntry.html in Copy Resources */,
@@ -2147,6 +2149,8 @@
 		F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; };
 		F47D30EB1ED28619000482E1 /* apple.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = apple.gif; sourceTree = "<group>"; };
 		F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
+		F47DFB2421A8704A00021FB6 /* data-detectors.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "data-detectors.html"; sourceTree = "<group>"; };
+		F47DFB2721A885E700021FB6 /* DataDetectorsCoreSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataDetectorsCoreSPI.h; sourceTree = "<group>"; };
 		F4811E5821940B4400A5E0FD /* WKWebViewEditActions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewEditActions.mm; sourceTree = "<group>"; };
 		F4856CA21E6498A8009D7EE7 /* attachment-element.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "attachment-element.html"; sourceTree = "<group>"; };
 		F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "DataTransfer-setDragImage.html"; sourceTree = "<group>"; };
@@ -2311,6 +2315,7 @@
 				A13EBB441B87332B00097110 /* WebProcessPlugIn */,
 				F4517B682054E0AC00C26721 /* ClassMethodSwizzler.h */,
 				F4517B692054E0AC00C26721 /* ClassMethodSwizzler.mm */,
+				F47DFB2721A885E700021FB6 /* DataDetectorsCoreSPI.h */,
 				F46128B4211C861A00D9FADB /* DragAndDropSimulator.h */,
 				F44D06481F3962E3001A0E29 /* EditingTestHarness.h */,
 				F44D06491F3962E3001A0E29 /* EditingTestHarness.mm */,
@@ -2740,6 +2745,7 @@
 				9B1056421F9047CC00D5583F /* copy-html.html */,
 				9B62630B1F8C2510007EE29B /* copy-url.html */,
 				F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */,
+				F47DFB2421A8704A00021FB6 /* data-detectors.html */,
 				F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */,
 				F457A9B3202D535300F7E9D5 /* DataTransfer.html */,
 				F4512E121F60C43400BB369E /* DataTransferItem-getAsEntry.html */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataDetection.mm (238470 => 238471)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataDetection.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataDetection.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -25,14 +25,43 @@
 
 #include "config.h"
 
+#import "DataDetectorsCoreSPI.h"
 #import "PlatformUtilities.h"
 #import "Test.h"
 #import "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
 #import <WebKit/WebKit.h>
 #import <wtf/RetainPtr.h>
 
 #if WK_API_ENABLED && PLATFORM(IOS_FAMILY)
 
+@interface WKWebView (DataDetection)
+- (void)synchronouslyDetectDataWithTypes:(WKDataDetectorTypes)types;
+- (void)synchronouslyRemoveDataDetectedLinks;
+@end
+
+@implementation WKWebView (DataDetection)
+
+- (void)synchronouslyDetectDataWithTypes:(WKDataDetectorTypes)types
+{
+    __block bool done = false;
+    [self _detectDataWithTypes:types completionHandler:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
+- (void)synchronouslyRemoveDataDetectedLinks
+{
+    __block bool done = false;
+    [self _removeDataDetectedLinks:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
+@end
+
 static bool ranScript;
 
 @interface DataDetectionUIDelegate : NSObject <WKUIDelegate>
@@ -97,4 +126,39 @@
     expectLinkCount(webView.get(), @"yesterday at 6PM", 1);
 }
 
+TEST(WebKit, AddAndRemoveDataDetectors)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"data-detectors"];
+    [webView expectElementCount:0 querySelector:@"a[x-apple-data-detectors=true]"];
+    EXPECT_EQ(0U, [webView _dataDetectionResults].count);
+
+    auto checkDataDetectionResults = [] (NSArray<DDScannerResult *> *results) {
+        EXPECT_EQ(3U, results.count);
+        EXPECT_EQ(DDResultCategoryUnknown, results[0].category);
+        EXPECT_TRUE([results[0].value containsString:@"+1-234-567-8900"]);
+        EXPECT_TRUE([results[0].value containsString:@"https://www.apple.com"]);
+        EXPECT_TRUE([results[0].value containsString:@"2 Apple Park Way, Cupertino 95014"]);
+        EXPECT_WK_STREQ("SignatureBlock", results[0].type);
+        EXPECT_EQ(DDResultCategoryCalendarEvent, results[1].category);
+        EXPECT_WK_STREQ("Date", results[1].type);
+        EXPECT_WK_STREQ("December 21, 2021", results[1].value);
+        EXPECT_EQ(DDResultCategoryMisc, results[2].category);
+        EXPECT_WK_STREQ("FlightInformation", results[2].type);
+        EXPECT_WK_STREQ("AC780", results[2].value);
+    };
+
+    [webView synchronouslyDetectDataWithTypes:WKDataDetectorTypeAll];
+    [webView expectElementCount:5 querySelector:@"a[x-apple-data-detectors=true]"];
+    checkDataDetectionResults([webView _dataDetectionResults]);
+
+    [webView synchronouslyRemoveDataDetectedLinks];
+    [webView expectElementCount:0 querySelector:@"a[x-apple-data-detectors=true]"];
+    EXPECT_EQ(0U, [webView _dataDetectionResults].count);
+
+    [webView synchronouslyDetectDataWithTypes:WKDataDetectorTypeAddress | WKDataDetectorTypePhoneNumber];
+    [webView expectElementCount:2 querySelector:@"a[x-apple-data-detectors=true]"];
+    checkDataDetectionResults([webView _dataDetectionResults]);
+}
+
 #endif

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm (238470 => 238471)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -215,37 +215,6 @@
 
 @implementation TestWKWebView (AttachmentTesting)
 
-- (NSArray<NSString *> *)tagsInBody
-{
-    return [self objectByEvaluatingJavaScript:@"Array.from(document.body.getElementsByTagName('*')).map(e => e.tagName)"];
-}
-
-- (void)expectElementTagsInOrder:(NSArray<NSString *> *)tagNames
-{
-    auto remainingTags = adoptNS([tagNames mutableCopy]);
-    NSArray<NSString *> *tagsInBody = self.tagsInBody;
-    for (NSString *tag in tagsInBody.reverseObjectEnumerator) {
-        if ([tag isEqualToString:[remainingTags lastObject]])
-            [remainingTags removeLastObject];
-        if (![remainingTags count])
-            break;
-    }
-    EXPECT_EQ([remainingTags count], 0U);
-    if ([remainingTags count])
-        NSLog(@"Expected to find ordered tags: %@ in: %@", tagNames, tagsInBody);
-}
-
-- (void)expectElementCount:(NSInteger)count tagName:(NSString *)tagName
-{
-    NSString *script = [NSString stringWithFormat:@"document.querySelectorAll('%@').length", tagName];
-    EXPECT_EQ(count, [self stringByEvaluatingJavaScript:script].integerValue);
-}
-
-- (void)expectElementTag:(NSString *)tagName toComeBefore:(NSString *)otherTagName
-{
-    [self expectElementTagsInOrder:@[tagName, otherTagName]];
-}
-
 - (_WKAttachment *)synchronouslyInsertAttachmentWithFileWrapper:(NSFileWrapper *)fileWrapper contentType:(NSString *)contentType
 {
     __block bool done = false;
@@ -831,7 +800,7 @@
     }
 
     auto checkAttachmentConsistency = [webView, file, folder] (_WKAttachment *expectedFileAttachment, _WKAttachment *expectedFolderAttachment) {
-        [webView expectElementCount:2 tagName:@"ATTACHMENT"];
+        [webView expectElementCount:2 querySelector:@"ATTACHMENT"];
         EXPECT_TRUE(UTTypeConformsTo((__bridge CFStringRef)[webView valueOfAttribute:@"type" forQuerySelector:@"attachment[title=folder]"], kUTTypeDirectory));
         EXPECT_TRUE(UTTypeConformsTo((__bridge CFStringRef)[webView valueOfAttribute:@"type" forQuerySelector:@"attachment[title^=test]"], kUTTypeData));
         EXPECT_WK_STREQ(expectedFileAttachment.uniqueIdentifier, [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment[title^=test]').uniqueIdentifier"]);
@@ -928,7 +897,7 @@
         [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil];
         [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil];
         observer.expectAttachmentUpdates(@[ ], @[ ]);
-        [webView expectElementCount:0 tagName:@"BR"];
+        [webView expectElementCount:0 querySelector:@"BR"];
     }
 }
 
@@ -971,13 +940,13 @@
     [webView _executeEditCommand:@"InsertHTML" argument:@"<strong>text</strong>" completion:nil];
     [webView _synchronouslyExecuteEditCommand:@"InsertParagraph" argument:nil];
     [webView expectElementTag:@"IMG" toComeBefore:@"STRONG"];
-    [webView expectElementCount:1 tagName:@"IMG"];
+    [webView expectElementCount:1 querySelector:@"IMG"];
 
     // Drag the attachment element to somewhere below the strong text.
     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 350)];
 
     [webView expectElementTag:@"STRONG" toComeBefore:@"IMG"];
-    [webView expectElementCount:1 tagName:@"IMG"];
+    [webView expectElementCount:1 querySelector:@"IMG"];
     EXPECT_EQ([simulator insertedAttachments].count, [simulator removedAttachments].count);
 
     [simulator endDataTransfer];
@@ -1034,8 +1003,8 @@
     }
 
     EXPECT_TRUE(zipAttachment && imageAttachment && pdfAttachment);
-    [webView expectElementCount:2 tagName:@"ATTACHMENT"];
-    [webView expectElementCount:1 tagName:@"IMG"];
+    [webView expectElementCount:2 querySelector:@"ATTACHMENT"];
+    [webView expectElementCount:1 querySelector:@"IMG"];
     EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
 
     NSString *zipAttachmentType = [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"];
@@ -1338,7 +1307,7 @@
 
     ObserveAttachmentUpdatesForScope observer(webView.get());
     [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
-    [webView expectElementCount:2 tagName:@"IMG"];
+    [webView expectElementCount:2 querySelector:@"IMG"];
 
     for (_WKAttachment *attachment in observer.observer().inserted) {
         if ([attachment.info.contentType isEqualToString:@"image/png"])
@@ -1473,7 +1442,7 @@
     auto secondWebView = webViewForTestingAttachments();
     ObserveAttachmentUpdatesForScope observer(secondWebView.get());
     [secondWebView paste:nil];
-    [secondWebView expectElementCount:3 tagName:@"attachment"];
+    [secondWebView expectElementCount:3 querySelector:@"attachment"];
     EXPECT_EQ(3U, observer.observer().inserted.count);
 
     NSString *plainFileIdentifier = [secondWebView stringByEvaluatingJavaScript:@"document.querySelector('attachment[title^=test]').uniqueIdentifier"];
@@ -1516,8 +1485,8 @@
         EXPECT_EQ(2U, [insertedAttachments count]);
     }
 
-    [webView expectElementCount:1 tagName:@"ATTACHMENT"];
-    [webView expectElementCount:1 tagName:@"IMG"];
+    [webView expectElementCount:1 querySelector:@"ATTACHMENT"];
+    [webView expectElementCount:1 querySelector:@"IMG"];
     EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').getAttribute('type')"]);
     EXPECT_WK_STREQ("test.pdf", [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').getAttribute('title')"]);
 
@@ -1552,8 +1521,8 @@
 
     [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(50, 50)];
 
-    [webView expectElementCount:1 tagName:@"ATTACHMENT"];
-    [webView expectElementCount:1 tagName:@"IMG"];
+    [webView expectElementCount:1 querySelector:@"ATTACHMENT"];
+    [webView expectElementCount:1 querySelector:@"IMG"];
     EXPECT_EQ(2U, [simulator insertedAttachments].count);
 
     auto insertedAttachments = retainPtr([simulator insertedAttachments]);
@@ -1573,8 +1542,8 @@
     [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil];
     auto removedAttachments = retainPtr([simulator removedAttachments]);
     EXPECT_EQ(2U, [removedAttachments count]);
-    [webView expectElementCount:0 tagName:@"ATTACHMENT"];
-    [webView expectElementCount:0 tagName:@"IMG"];
+    [webView expectElementCount:0 querySelector:@"ATTACHMENT"];
+    [webView expectElementCount:0 querySelector:@"IMG"];
     EXPECT_TRUE([removedAttachments containsObject:[insertedAttachments firstObject]]);
     EXPECT_TRUE([removedAttachments containsObject:[insertedAttachments lastObject]]);
 }
@@ -1681,7 +1650,7 @@
     for (_WKAttachment *attachment in [dragAndDropSimulator insertedAttachments])
         EXPECT_GT([attachment info].data.length, 0U);
 
-    [webView expectElementCount:2 tagName:@"ATTACHMENT"];
+    [webView expectElementCount:2 querySelector:@"ATTACHMENT"];
     EXPECT_WK_STREQ("hello.rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]);
     EXPECT_WK_STREQ("text/rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     EXPECT_WK_STREQ("world.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]);
@@ -1706,7 +1675,7 @@
     EXPECT_EQ(1U, [dragAndDropSimulator insertedAttachments].count);
     EXPECT_EQ(0U, [dragAndDropSimulator removedAttachments].count);
     [[dragAndDropSimulator insertedAttachments].firstObject expectRequestedDataToBe:data];
-    [webView expectElementCount:1 tagName:@"ATTACHMENT"];
+    [webView expectElementCount:1 querySelector:@"ATTACHMENT"];
     EXPECT_WK_STREQ("archive.zip", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]);
     EXPECT_WK_STREQ("application/zip", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
 }

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/data-detectors.html (0 => 238471)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/data-detectors.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/data-detectors.html	2018-11-24 21:06:09 UTC (rev 238471)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<body>
+<table>
+<tbody>
+<tr>
+    <td>Telephone number</td>
+    <td>+1-234-567-8900</td>
+</tr>
+<tr>
+    <td>Link</td>
+    <td>https://www.apple.com</td>
+</tr>
+<tr>
+    <td>Address</td>
+    <td>2 Apple Park Way, Cupertino 95014</td>
+</tr>
+<tr>
+    <td>Calendar event</td>
+    <td>December 21, 2021</td>
+</tr>
+<tr>
+    <td>Flight number</td>
+    <td>AC780</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (238470 => 238471)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2018-11-24 21:06:09 UTC (rev 238471)
@@ -48,7 +48,14 @@
 @end
 
 @interface WKWebView (TestWebKitAPI)
+@property (nonatomic, readonly) NSArray<NSString *> *tagsInBody;
 - (BOOL)_synchronouslyExecuteEditCommand:(NSString *)command argument:(NSString *)argument;
+- (void)expectElementTagsInOrder:(NSArray<NSString *> *)tagNames;
+- (void)expectElementCount:(NSInteger)count querySelector:(NSString *)querySelector;
+- (void)expectElementTag:(NSString *)tagName toComeBefore:(NSString *)otherTagName;
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
+- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script;
+- (id)objectByEvaluatingJavaScript:(NSString *)script;
 @end
 
 @interface TestMessageHandler : NSObject <WKScriptMessageHandler>
@@ -64,9 +71,6 @@
 - (void)synchronouslyLoadHTMLString:(NSString *)html;
 - (void)synchronouslyLoadHTMLString:(NSString *)html baseURL:(NSURL *)url;
 - (void)synchronouslyLoadTestPageNamed:(NSString *)pageName;
-- (id)objectByEvaluatingJavaScript:(NSString *)script;
-- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script;
-- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
 - (void)waitForMessage:(NSString *)message;
 - (void)performAfterLoading:(dispatch_block_t)actions;
 - (void)waitForNextPresentationUpdate;

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (238470 => 238471)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2018-11-24 18:37:14 UTC (rev 238470)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2018-11-24 21:06:09 UTC (rev 238471)
@@ -78,6 +78,72 @@
     return success;
 }
 
+- (NSArray<NSString *> *)tagsInBody
+{
+    return [self objectByEvaluatingJavaScript:@"Array.from(document.body.getElementsByTagName('*')).map(e => e.tagName)"];
+}
+
+- (void)expectElementTagsInOrder:(NSArray<NSString *> *)tagNames
+{
+    auto remainingTags = adoptNS([tagNames mutableCopy]);
+    NSArray<NSString *> *tagsInBody = self.tagsInBody;
+    for (NSString *tag in tagsInBody.reverseObjectEnumerator) {
+        if ([tag isEqualToString:[remainingTags lastObject]])
+            [remainingTags removeLastObject];
+        if (![remainingTags count])
+            break;
+    }
+    EXPECT_EQ([remainingTags count], 0U);
+    if ([remainingTags count])
+        NSLog(@"Expected to find ordered tags: %@ in: %@", tagNames, tagsInBody);
+}
+
+- (void)expectElementCount:(NSInteger)count querySelector:(NSString *)querySelector
+{
+    NSString *script = [NSString stringWithFormat:@"document.querySelectorAll('%@').length", querySelector];
+    EXPECT_EQ(count, [self stringByEvaluatingJavaScript:script].integerValue);
+}
+
+- (void)expectElementTag:(NSString *)tagName toComeBefore:(NSString *)otherTagName
+{
+    [self expectElementTagsInOrder:@[tagName, otherTagName]];
+}
+
+- (id)objectByEvaluatingJavaScript:(NSString *)script
+{
+    bool isWaitingForJavaScript = false;
+    RetainPtr<id> evalResult;
+    [self _evaluateJavaScriptWithoutUserGesture:script completionHandler:[&] (id result, NSError *error) {
+        evalResult = result;
+        isWaitingForJavaScript = true;
+        EXPECT_TRUE(!error);
+        if (error)
+            NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
+    }];
+    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+    return evalResult.autorelease();
+}
+
+- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script
+{
+    bool isWaitingForJavaScript = false;
+    RetainPtr<id> evalResult;
+    [self evaluateJavaScript:script completionHandler:[&] (id result, NSError *error) {
+        evalResult = result;
+        isWaitingForJavaScript = true;
+        EXPECT_TRUE(!error);
+        if (error)
+            NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
+    }];
+    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+    return evalResult.autorelease();
+}
+
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
+{
+    return [NSString stringWithFormat:@"%@", [self objectByEvaluatingJavaScript:script]];
+}
+
 @end
 
 @implementation TestMessageHandler {
@@ -289,41 +355,6 @@
     [self _test_waitForDidFinishNavigation];
 }
 
-- (id)objectByEvaluatingJavaScript:(NSString *)script
-{
-    bool isWaitingForJavaScript = false;
-    RetainPtr<id> evalResult;
-    [self _evaluateJavaScriptWithoutUserGesture:script completionHandler:[&] (id result, NSError *error) {
-        evalResult = result;
-        isWaitingForJavaScript = true;
-        EXPECT_TRUE(!error);
-        if (error)
-            NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
-    }];
-    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
-    return evalResult.autorelease();
-}
-
-- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script
-{
-    bool isWaitingForJavaScript = false;
-    RetainPtr<id> evalResult;
-    [self evaluateJavaScript:script completionHandler:[&] (id result, NSError *error) {
-        evalResult = result;
-        isWaitingForJavaScript = true;
-        EXPECT_TRUE(!error);
-        if (error)
-            NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
-    }];
-    TestWebKitAPI::Util::run(&isWaitingForJavaScript);
-    return evalResult.autorelease();
-}
-
-- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
-{
-    return [NSString stringWithFormat:@"%@", [self objectByEvaluatingJavaScript:script]];
-}
-
 - (void)waitForMessage:(NSString *)message
 {
     __block bool isDoneWaiting = false;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to