Diff
Modified: trunk/Source/WebCore/ChangeLog (195493 => 195494)
--- trunk/Source/WebCore/ChangeLog 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/ChangeLog 2016-01-23 00:24:02 UTC (rev 195494)
@@ -1,3 +1,33 @@
+2016-01-22 Enrica Casucci <[email protected]>
+
+ Add support for DataDetectors in WK (iOS).
+ https://bugs.webkit.org/show_bug.cgi?id=152989
+ rdar://problem/22855960
+
+ Reviewed by Tim Horton.
+
+ This patch adds the logic to perform data detection and modify
+ the DOM by adding data detector links as appropriate.
+ The data detector results returned by detectContentInRange are
+ stored in the Frame object.
+
+ * editing/cocoa/DataDetection.h:
+ * editing/cocoa/DataDetection.mm:
+ (WebCore::resultIsURL):
+ (WebCore::constructURLStringForResult):
+ (WebCore::removeResultLinksFromAnchor):
+ (WebCore::searchForLinkRemovingExistingDDLinks):
+ (WebCore::dataDetectorTypeForCategory):
+ (WebCore::buildQuery):
+ (WebCore::DataDetection::detectContentInRange):
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::checkLoadCompleteForThisFrame):
+ * page/Frame.h:
+ (WebCore::Frame::setDataDetectionResults):
+ (WebCore::Frame::dataDetectionResults):
+ * platform/spi/cocoa/DataDetectorsCoreSPI.h:
+ (DDQueryOffsetCompare):
+
2016-01-22 Daniel Bates <[email protected]>
LayoutTest http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html crashing
@@ -1724,7 +1754,6 @@
(WebCore::matchesFutureCuePseudoClass):
(WebCore::matchesPastCuePseudoClass):
->>>>>>> .r195316
2016-01-19 Chris Dumez <[email protected]>
Unreviewed, rolling out r195179.
Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.h (195493 => 195494)
--- trunk/Source/WebCore/editing/cocoa/DataDetection.h 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.h 2016-01-23 00:24:02 UTC (rev 195494)
@@ -30,6 +30,7 @@
#import <wtf/RetainPtr.h>
OBJC_CLASS DDActionContext;
+OBJC_CLASS NSArray;
namespace WebCore {
@@ -53,7 +54,7 @@
#if PLATFORM(MAC)
WEBCORE_EXPORT static RetainPtr<DDActionContext> detectItemAroundHitTestResult(const HitTestResult&, FloatRect& detectedDataBoundingBox, RefPtr<Range>& detectedDataRange);
#endif
- WEBCORE_EXPORT static void detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes);
+ WEBCORE_EXPORT static NSArray *detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes);
};
} // namespace WebCore
Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.mm (195493 => 195494)
--- trunk/Source/WebCore/editing/cocoa/DataDetection.mm 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.mm 2016-01-23 00:24:02 UTC (rev 195494)
@@ -44,6 +44,12 @@
#import "VisibleUnits.h"
#import "htmlediting.h"
+#if PLATFORM(IOS)
+const char *dataDetectorsURLScheme = "x-apple-data-detectors";
+const char *dataDetectorsAttributeTypeKey = "x-apple-data-detectors-type";
+const char *dataDetectorsAttributeResultKey = "x-apple-data-detectors-result";
+#endif
+
namespace WebCore {
#if PLATFORM(MAC)
@@ -138,9 +144,412 @@
return detectItemAtPositionWithRange(position, contextRange, detectedDataBoundingBox, detectedDataRange);
}
#endif // PLATFORM(MAC)
+
+#if PLATFORM(IOS)
+
+static BOOL resultIsURL(DDResultRef result)
+{
+ if (!result)
+ return NO;
+
+ static NSSet *urlTypes = [[NSSet setWithObjects: (NSString *)getDDBinderHttpURLKey(), (NSString *)getDDBinderWebURLKey(), (NSString *)getDDBinderMailURLKey(), (NSString *)getDDBinderGenericURLKey(), (NSString *)getDDBinderEmailKey(), nil] retain];
+ return [urlTypes containsObject:(NSString *)DDResultGetType(result)];
+}
-void DataDetection::detectContentInRange(RefPtr<Range>&, DataDetectorTypes)
+static NSString *constructURLStringForResult(DDResultRef currentResult, NSString *resultIdentifier, NSDate *referenceDate, NSTimeZone *referenceTimeZone, DataDetectorTypes detectionTypes)
{
+ if (!DDResultHasProperties(currentResult, DDResultPropertyPassiveDisplay))
+ return nil;
+
+ DDURLifierPhoneNumberDetectionTypes phoneTypes = (detectionTypes & DataDetectorTypePhoneNumber) ? DDURLifierPhoneNumberDetectionRegular : DDURLifierPhoneNumberDetectionNone;
+ DDResultCategory category = DDResultGetCategory(currentResult);
+ CFStringRef type = DDResultGetType(currentResult);
+
+ if (((detectionTypes & DataDetectorTypeAddress) && (DDResultCategoryAddress == category))
+ || ((detectionTypes & DataDetectorTypeTrackingNumber) && (CFStringCompare(getDDBinderTrackingNumberKey(), type, 0) == kCFCompareEqualTo))
+ || ((detectionTypes & DataDetectorTypeFlight) && (CFStringCompare(getDDBinderFlightInformationKey(), type, 0) == kCFCompareEqualTo))
+ || ((detectionTypes & DataDetectorTypePhoneNumber) && (DDResultCategoryPhoneNumber == category))
+ || ((detectionTypes & DataDetectorTypeLink) && resultIsURL(currentResult))) {
+
+ return DDURLStringForResult(currentResult, resultIdentifier, phoneTypes, referenceDate, referenceTimeZone);
+ }
+ if ((detectionTypes & DataDetectorTypeCalendarEvent) && (DDResultCategoryCalendarEvent == category)) {
+ if (!DDResultIsPastDate(currentResult, (CFDateRef)referenceDate, (CFTimeZoneRef)referenceTimeZone))
+ return DDURLStringForResult(currentResult, resultIdentifier, phoneTypes, referenceDate, referenceTimeZone);
+ }
+ return nil;
}
+static void removeResultLinksFromAnchor(Node* node, Node* nodeParent)
+{
+ // Perform a depth-first search for anchor nodes, which have the DDURLScheme attribute set to true,
+ // take their children and insert them before the anchor,
+ // and then remove the anchor.
+
+ if (!node)
+ return;
+
+ BOOL nodeIsDDAnchor = is<HTMLAnchorElement>(*node) && downcast<Element>(*node).getAttribute(getDDURLScheme()) == "true";
+
+ RefPtr<NodeList> children = node->childNodes();
+ unsigned childCount = children->length();
+ for (size_t i = 0; i < childCount; i++) {
+ Node *child = children->item(i);
+ if (is<Element>(*child))
+ removeResultLinksFromAnchor(child, node);
+ }
+
+ if (nodeIsDDAnchor && nodeParent) {
+ children = node->childNodes();
+ childCount = children->length();
+
+ // Iterate over the children and move them all onto the same level as this anchor.
+ // Remove the anchor afterwards.
+ for (size_t i = 0; i < childCount; i++) {
+ Node *child = children->item(0);
+ nodeParent->insertBefore(child, node, ASSERT_NO_EXCEPTION);
+ }
+ nodeParent->removeChild(node, ASSERT_NO_EXCEPTION);
+ }
+}
+
+static bool searchForLinkRemovingExistingDDLinks(Node* startNode, Node* endNode)
+{
+ Node *node = startNode;
+ while (node) {
+ if (is<HTMLAnchorElement>(*node)) {
+ if (downcast<Element>(*node).getAttribute(getDDURLScheme()) != "true")
+ return true;
+ removeResultLinksFromAnchor(node, node->parentElement());
+ }
+
+ if (node == endNode) {
+ // If we found the end node and no link, return false unless an ancestor node is a link.
+ // The only ancestors not tested at this point are in the direct line from self's parent to the top.
+ node = startNode->parentNode();
+ while (node) {
+ if (is<HTMLAnchorElement>(*node)) {
+ if (downcast<Element>(*node).getAttribute(getDDURLScheme()) != "true")
+ return true;
+ removeResultLinksFromAnchor(node, node->parentElement());
+ }
+ node = node->parentNode();
+ }
+ return false;
+ }
+
+ RefPtr<NodeList> childNodes = node->childNodes();
+ if (childNodes->length())
+ node = childNodes->item(0);
+ else {
+ Node *newNode = node->nextSibling();
+ Node *parentNode = node;
+ while (!newNode) {
+ parentNode = parentNode->parentNode();
+ if (!parentNode)
+ return false;
+ newNode = parentNode->nextSibling();
+ }
+ node = newNode;
+ }
+ }
+ return false;
+}
+
+static NSString *dataDetectorTypeForCategory(DDResultCategory category)
+{
+ switch (category) {
+ case DDResultCategoryPhoneNumber:
+ return @"telephone";
+ case DDResultCategoryLink:
+ return @"link";
+ case DDResultCategoryAddress:
+ return @"address";
+ case DDResultCategoryCalendarEvent:
+ return @"calendar-event";
+ case DDResultCategoryMisc:
+ return @"misc";
+ default:
+ return @"";
+ }
+}
+
+static String dataDetectorStringForPath(NSIndexPath* path)
+{
+ NSUInteger length = path.length;
+
+ switch (length) {
+ case 0:
+ return String();
+
+ case 1:
+ return String::format("%lu", (unsigned long)[path indexAtPosition:0]);
+
+ case 2:
+ return String::format("%lu/%lu", (unsigned long)[path indexAtPosition:0], (unsigned long)[path indexAtPosition:1]);
+
+ default:
+ {
+ String componentsString = String::format("%lu", (unsigned long)[path indexAtPosition:0]);
+ for (NSUInteger i = 1 ; i < length ; i++) {
+ componentsString.append("/");
+ componentsString.append(String::format("%lu", (unsigned long)[path indexAtPosition:i]));
+ }
+
+ return componentsString;
+ }
+ }
+}
+
+static void buildQuery(DDScanQueryRef scanQuery, Range* contextRange)
+{
+ // Once we're over this number of fragments, stop at the first hard break.
+ const CFIndex maxFragmentWithHardBreak = 1000;
+ // Once we're over this number of fragments, we stop at the line.
+ const CFIndex maxFragmentWithLinebreak = 5000;
+ // Once we're over this number of fragments, we stop at the space.
+ const CFIndex maxFragmentSpace = 10000;
+
+ CFCharacterSetRef whiteSpacesSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline);
+ CFCharacterSetRef newLinesSet = CFCharacterSetGetPredefined(kCFCharacterSetNewline);
+
+ RefPtr<Range> endRange;
+ CFIndex iteratorCount = 0;
+ CFIndex fragmentCount = 0;
+
+ // Build the scan query adding separators.
+ // For each fragment the iterator increment is stored as metadata.
+ for (TextIterator iterator(contextRange); !iterator.atEnd(); iterator.advance(), iteratorCount++) {
+ size_t currentTextLength = iterator.text().length();
+ if (!currentTextLength) {
+ DDScanQueryAddSeparator(scanQuery, DDTextCoalescingTypeHardBreak);
+ if (iteratorCount > maxFragmentWithHardBreak)
+ break;
+ continue;
+ }
+ // Test for white space nodes, we're coalescing them.
+ const UniChar *currentCharPtr = iterator.text().upconvertedCharacters();
+
+ bool containsOnlyWhiteSpace = true;
+ bool hasTab = false;
+ bool hasNewline = false;
+ int nbspCount = 0;
+ for (NSUInteger i = 0; i < currentTextLength; i++) {
+ if (!CFCharacterSetIsCharacterMember(whiteSpacesSet, *currentCharPtr)) {
+ containsOnlyWhiteSpace = false;
+ break;
+ }
+
+ if (CFCharacterSetIsCharacterMember(newLinesSet, *currentCharPtr))
+ hasNewline = true;
+ else if (*currentCharPtr == '\t')
+ hasTab = true;
+
+ // Multiple consecutive non breakable spaces are most likely simulated tabs.
+ if (*currentCharPtr == 0xa0) {
+ if (++nbspCount > 2)
+ hasTab = true;
+ } else
+ nbspCount = 0;
+
+ currentCharPtr++;
+ }
+ if (containsOnlyWhiteSpace) {
+ if (hasNewline) {
+ DDScanQueryAddLineBreak(scanQuery);
+ if (iteratorCount > maxFragmentWithLinebreak)
+ break;
+ } else {
+ DDScanQueryAddSeparator(scanQuery, hasTab ? DDTextCoalescingTypeTab : DDTextCoalescingTypeSpace);
+ if (iteratorCount > maxFragmentSpace)
+ break;
+ }
+ continue;
+ }
+
+ RetainPtr<CFStringRef> currentText = adoptCF(CFStringCreateWithCharacters(kCFAllocatorDefault, iterator.text().upconvertedCharacters(), iterator.text().length()));
+ DDScanQueryAddTextFragment(scanQuery, currentText.get(), CFRangeMake(0, currentTextLength), (void *)iteratorCount, (DDTextFragmentMode)0, DDTextCoalescingTypeNone);
+ fragmentCount++;
+ }
+}
+
+static inline CFComparisonResult queryOffsetCompare(DDQueryOffset o1, DDQueryOffset o2)
+{
+ if (o1.queryIndex < o2.queryIndex)
+ return kCFCompareLessThan;
+ if (o1.queryIndex > o2.queryIndex)
+ return kCFCompareGreaterThan;
+ if (o1.offset < o2.offset)
+ return kCFCompareLessThan;
+ if (o1.offset > o2.offset)
+ return kCFCompareGreaterThan;
+ return kCFCompareEqualTo;
+}
+
+NSArray *DataDetection::detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes types)
+{
+ RetainPtr<DDScannerRef> scanner = adoptCF(DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
+ RetainPtr<DDScanQueryRef> scanQuery = adoptCF(DDScanQueryCreate(NULL));
+ buildQuery(scanQuery.get(), contextRange.get());
+
+ // FIXME: we should add a timeout to this call to make sure it doesn't take too much time.
+ if (!DDScannerScanQuery(scanner.get(), scanQuery.get()))
+ return nil;
+
+ RetainPtr<CFArrayRef> scannerResults = adoptCF(DDScannerCopyResultsWithOptions(scanner.get(), getDDScannerCopyResultsOptionsForPassiveUse() | DDScannerCopyResultsOptionsCoalesceSignatures));
+ if (!scannerResults)
+ return nil;
+
+ CFIndex resultCount = CFArrayGetCount(scannerResults.get());
+ if (!resultCount)
+ return nil;
+
+ Vector<RetainPtr<DDResultRef>> allResults;
+ Vector<RetainPtr<NSIndexPath>> indexPaths;
+ NSInteger currentTopLevelIndex = 0;
+
+ // Iterate through the scanner results to find signatures and extract all the subresults while
+ // populating the array of index paths to use in the href of the anchors being created.
+ for (id resultObject in (NSArray *)scannerResults.get()) {
+ DDResultRef result = (DDResultRef)resultObject;
+ NSIndexPath *indexPath = [NSIndexPath indexPathWithIndex:currentTopLevelIndex];
+ if (CFStringCompare(DDResultGetType(result), getDDBinderSignatureBlockKey(), 0) == kCFCompareEqualTo) {
+ NSArray *subresults = (NSArray *)DDResultGetSubResults(result);
+
+ for (NSUInteger subResultIndex = 0 ; subResultIndex < [subresults count] ; subResultIndex++) {
+ indexPaths.append([indexPath indexPathByAddingIndex:subResultIndex]);
+ allResults.append((DDResultRef)[subresults objectAtIndex:subResultIndex]);
+ }
+ } else {
+ allResults.append(result);
+ indexPaths.append(indexPath);
+ }
+ currentTopLevelIndex++;
+ }
+
+ Vector<Vector<RefPtr<Range>>> allResultRanges;
+ TextIterator iterator(contextRange.get());
+ CFIndex iteratorCount = 0;
+
+ // Iterate through the array of the expanded results to create a vector of Range objects that indicate
+ // where the DOM needs to be modified.
+ // Each result can be contained all in one text node or can span multiple text nodes.
+ for (auto& result : allResults) {
+ DDQueryRange queryRange = DDResultGetQueryRangeForURLification(result.get());
+ CFIndex iteratorTargetAdvanceCount = (CFIndex)DDScanQueryGetFragmentMetaData(scanQuery.get(), queryRange.start.queryIndex);
+ while (iteratorCount < iteratorTargetAdvanceCount) {
+ iterator.advance();
+ iteratorCount++;
+ }
+
+ Vector<RefPtr<Range>> fragmentRanges;
+ RefPtr<Range> currentRange = iterator.range();
+ CFIndex fragmentIndex = queryRange.start.queryIndex;
+ if (fragmentIndex == queryRange.end.queryIndex)
+ fragmentRanges.append(TextIterator::subrange(currentRange.get(), queryRange.start.offset, queryRange.end.offset - queryRange.start.offset));
+ else
+ fragmentRanges.append(currentRange);
+
+ while (fragmentIndex < queryRange.end.queryIndex) {
+ fragmentIndex++;
+ iteratorTargetAdvanceCount = (CFIndex)DDScanQueryGetFragmentMetaData(scanQuery.get(), fragmentIndex);
+ while (iteratorCount < iteratorTargetAdvanceCount) {
+ iterator.advance();
+ iteratorCount++;
+ }
+ currentRange = iterator.range();
+ fragmentRanges.append(currentRange);
+ }
+ allResultRanges.append(fragmentRanges);
+ }
+
+ CFTimeZoneRef tz = CFTimeZoneCopyDefault();
+ NSDate *referenceDate = [NSDate date];
+ Text* lastTextNodeToUpdate = nullptr;
+ String lastNodeContent;
+ size_t contentOffset = 0;
+ DDQueryOffset lastModifiedQueryOffset = {-1, 0};
+
+ // For each result add the link.
+ // Since there could be multiple results in the same text node, the node is only modified when
+ // we are about to process a different text node.
+ resultCount = allResults.size();
+
+ for (CFIndex resultIndex = 0; resultIndex < resultCount; resultIndex++) {
+ DDResultRef coreResult = allResults[resultIndex].get();
+ DDQueryRange queryRange = DDResultGetQueryRangeForURLification(coreResult);
+ Vector<RefPtr<Range>> resultRanges = allResultRanges[resultIndex];
+
+ // Compare the query offsets to make sure we don't go backwards
+ if (queryOffsetCompare(lastModifiedQueryOffset, queryRange.start) >= 0)
+ continue;
+
+ if (!resultRanges.size())
+ continue;
+
+ NSString *identifier = dataDetectorStringForPath(indexPaths[resultIndex].get());
+ NSString *correspondingURL = constructURLStringForResult(coreResult, identifier, referenceDate, (NSTimeZone *)tz, types);
+
+ if (!correspondingURL || searchForLinkRemovingExistingDDLinks(&resultRanges.first()->startContainer(), &resultRanges.last()->endContainer()))
+ continue;
+
+ lastModifiedQueryOffset = queryRange.end;
+
+ for (auto& range : resultRanges) {
+ Node* parentNode = range->startContainer().parentNode();
+ Text& currentTextNode = downcast<Text>(range->startContainer());
+ Document& document = currentTextNode.document();
+ String textNodeData;
+
+ if (lastTextNodeToUpdate != ¤tTextNode) {
+ if (lastTextNodeToUpdate)
+ lastTextNodeToUpdate->setData(lastNodeContent);
+ contentOffset = 0;
+ if (range->startOffset() > 0)
+ textNodeData = currentTextNode.substringData(0, range->startOffset(), ASSERT_NO_EXCEPTION);
+ } else
+ textNodeData = currentTextNode.substringData(contentOffset, range->startOffset() - contentOffset, ASSERT_NO_EXCEPTION);
+
+ if (!textNodeData.isEmpty()) {
+ RefPtr<Node> newNode = Text::create(document, textNodeData);
+ parentNode->insertBefore(newNode, ¤tTextNode, ASSERT_NO_EXCEPTION);
+ contentOffset = range->startOffset();
+ }
+
+ // Create the actual anchor node and insert it before the current node.
+ textNodeData = currentTextNode.substringData(range->startOffset(), range->endOffset() - range->startOffset(), ASSERT_NO_EXCEPTION);
+ RefPtr<Node> newNode = Text::create(document, textNodeData);
+ parentNode->insertBefore(newNode, ¤tTextNode, ASSERT_NO_EXCEPTION);
+
+ RefPtr<HTMLAnchorElement> anchorElement = HTMLAnchorElement::create(document);
+ anchorElement->setHref(correspondingURL);
+ anchorElement->setDir("ltr");
+ RefPtr<Attr> color = downcast<Element>(parentNode)->getAttributeNode("color");
+ if (color)
+ anchorElement->setAttribute(HTMLNames::styleAttr, color->style()->cssText());
+
+ anchorElement->Node::appendChild(newNode, ASSERT_NO_EXCEPTION);
+ parentNode->insertBefore(anchorElement, ¤tTextNode, ASSERT_NO_EXCEPTION);
+ // Add a special attribute to mark this URLification as the result of data detectors.
+ anchorElement->setAttribute(QualifiedName(nullAtom, dataDetectorsURLScheme, nullAtom), "true");
+ anchorElement->setAttribute(QualifiedName(nullAtom, dataDetectorsAttributeTypeKey, nullAtom), dataDetectorTypeForCategory(DDResultGetCategory(coreResult)));
+ anchorElement->setAttribute(QualifiedName(nullAtom, dataDetectorsAttributeResultKey, nullAtom), identifier);
+ contentOffset = range->endOffset();
+
+ lastNodeContent = currentTextNode.substringData(range->endOffset(), currentTextNode.length() - range->endOffset(), ASSERT_NO_EXCEPTION);
+ lastTextNodeToUpdate = ¤tTextNode;
+ }
+ }
+ if (lastTextNodeToUpdate)
+ lastTextNodeToUpdate->setData(lastNodeContent);
+
+ return [getDDScannerResultClass() resultsFromCoreResults:scannerResults.get()];
+}
+
+#else
+NSArray *DataDetection::detectContentInRange(RefPtr<Range>&, DataDetectorTypes)
+{
+ return nil;
+}
+#endif
} // namespace WebCore
Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (195493 => 195494)
--- trunk/Source/WebCore/loader/FrameLoader.cpp 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp 2016-01-23 00:24:02 UTC (rev 195494)
@@ -2279,14 +2279,14 @@
m_client.dispatchDidFailLoad(error);
loadingEvent = AXObjectCache::AXLoadingFailed;
} else {
- m_client.dispatchDidFinishLoad();
- loadingEvent = AXObjectCache::AXLoadingFinished;
#if ENABLE(DATA_DETECTION)
if (m_frame.settings().dataDetectorTypes() != DataDetectorTypeNone) {
RefPtr<Range> documentRange = makeRange(firstPositionInNode(m_frame.document()->documentElement()), lastPositionInNode(m_frame.document()->documentElement()));
- DataDetection::detectContentInRange(documentRange, m_frame.settings().dataDetectorTypes());
+ m_frame.setDataDetectionResults(DataDetection::detectContentInRange(documentRange, m_frame.settings().dataDetectorTypes()));
}
#endif
+ m_client.dispatchDidFinishLoad();
+ loadingEvent = AXObjectCache::AXLoadingFinished;
}
// Notify accessibility.
Modified: trunk/Source/WebCore/page/Frame.h (195493 => 195494)
--- trunk/Source/WebCore/page/Frame.h 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/page/Frame.h 2016-01-23 00:24:02 UTC (rev 195494)
@@ -47,10 +47,13 @@
#include "FrameWin.h"
#endif
+#if PLATFORM(COCOA)
+OBJC_CLASS NSArray;
+#endif
+
#if PLATFORM(IOS)
OBJC_CLASS DOMCSSStyleDeclaration;
OBJC_CLASS DOMNode;
-OBJC_CLASS NSArray;
OBJC_CLASS NSString;
#endif
@@ -185,6 +188,11 @@
WEBCORE_EXPORT float frameScaleFactor() const;
void deviceOrPageScaleFactorChanged();
+
+#if ENABLE(DATA_DETECTION)
+ void setDataDetectionResults(NSArray *results) { m_dataDetectionResults = results; }
+ NSArray *dataDetectionResults() const { return m_dataDetectionResults.get(); }
+#endif
#if PLATFORM(IOS)
const ViewportArguments& viewportArguments() const;
@@ -292,6 +300,9 @@
const std::unique_ptr<EventHandler> m_eventHandler;
const std::unique_ptr<AnimationController> m_animationController;
+#if ENABLE(DATA_DETECTION)
+ RetainPtr<NSArray> m_dataDetectionResults;
+#endif
#if PLATFORM(IOS)
void betterApproximateNode(const IntPoint& testPoint, NodeQualifier, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect);
bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center);
Modified: trunk/Source/WebCore/platform/spi/cocoa/DataDetectorsCoreSPI.h (195493 => 195494)
--- trunk/Source/WebCore/platform/spi/cocoa/DataDetectorsCoreSPI.h 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebCore/platform/spi/cocoa/DataDetectorsCoreSPI.h 2016-01-23 00:24:02 UTC (rev 195494)
@@ -23,10 +23,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#import "SoftLinking.h"
+
#if USE(APPLE_INTERNAL_SDK)
+#import <DataDetectorsCore/DDBinderKeys_Private.h>
+#import <DataDetectorsCore/DDScannerResult.h>
#import <DataDetectorsCore/DataDetectorsCore.h>
-
+#if PLATFORM(IOS)
+#import <DataDetectorsCore/DDURLifier.h>
+#endif
#else // !USE(APPLE_INTERNAL_SDK)
typedef enum {
@@ -38,8 +44,65 @@
enum {
DDScannerCopyResultsOptionsNone = 0,
DDScannerCopyResultsOptionsNoOverlap = 1 << 0,
+ DDScannerCopyResultsOptionsCoalesceSignatures = 1 << 1,
};
+enum {
+ DDURLifierPhoneNumberDetectionNone = 0,
+ DDURLifierPhoneNumberDetectionRegular = 1 << 1,
+ DDURLifierPhoneNumberDetectionQuotedShorts = 1 << 2,
+ DDURLifierPhoneNumberDetectionUnquotedShorts = 1 << 3
+};
+typedef NSUInteger DDURLifierPhoneNumberDetectionTypes;
+
+typedef enum __DDTextCoalescingType {
+ DDTextCoalescingTypeNone = 0,
+ DDTextCoalescingTypeSpace = 1,
+ DDTextCoalescingTypeTab = 2,
+ DDTextCoalescingTypeLineBreak = 3,
+ DDTextCoalescingTypeHardBreak = 4,
+} DDTextCoalescingType;
+
+typedef enum {
+ DDResultCategoryUnknown = 0,
+ DDResultCategoryLink = 1,
+ DDResultCategoryPhoneNumber = 2,
+ DDResultCategoryAddress = 3,
+ DDResultCategoryCalendarEvent = 4,
+ DDResultCategoryMisc = 5,
+} DDResultCategory;
+
+typedef enum __DDTextFragmentType {
+ DDTextFragmentTypeTrimWhiteSpace = 0x1,
+ DDTextFragmentTypeIgnoreCRLF = 0x2,
+} DDTextFragmentMode;
+
+extern CFStringRef const DDBinderHttpURLKey;
+extern CFStringRef const DDBinderWebURLKey;
+extern CFStringRef const DDBinderMailURLKey;
+extern CFStringRef const DDBinderGenericURLKey;
+extern CFStringRef const DDBinderEmailKey;
+extern CFStringRef const DDBinderTrackingNumberKey;
+extern CFStringRef const DDBinderFlightInformationKey;
+extern CFStringRef const DDBinderSignatureBlockKey;
+extern NSString * const DDURLScheme;
+
+@interface DDScannerResult : NSObject <NSCoding, NSSecureCoding>
++ (NSArray *)resultsFromCoreResults:(CFArrayRef)coreResults;
+@end
+
+#define DDResultPropertyPassiveDisplay (1 << 0)
+
+typedef struct __DDQueryOffset {
+ CFIndex queryIndex;
+ CFIndex offset;
+} DDQueryOffset;
+
+typedef struct __DDQueryRange {
+ DDQueryOffset start;
+ DDQueryOffset end;
+} DDQueryRange;
+
#endif // !USE(APPLE_INTERNAL_SDK)
typedef struct __DDResult *DDResultRef;
@@ -48,13 +111,56 @@
typedef CFIndex DDScannerCopyResultsOptions;
typedef CFIndex DDScannerOptions;
+extern const DDScannerCopyResultsOptions DDScannerCopyResultsOptionsForPassiveUse;
extern "C" {
DDScannerRef DDScannerCreate(DDScannerType, DDScannerOptions, CFErrorRef*);
+DDScanQueryRef DDScanQueryCreate(CFAllocatorRef);
DDScanQueryRef DDScanQueryCreateFromString(CFAllocatorRef, CFStringRef, CFRange);
Boolean DDScannerScanQuery(DDScannerRef, DDScanQueryRef);
CFArrayRef DDScannerCopyResultsWithOptions(DDScannerRef, DDScannerCopyResultsOptions);
CFRange DDResultGetRange(DDResultRef);
+CFStringRef DDResultGetType(DDResultRef);
+DDResultCategory DDResultGetCategory(DDResultRef);
+Boolean DDResultIsPastDate(DDResultRef, CFDateRef referenceDate, CFTimeZoneRef referenceTimeZone);
+void DDScanQueryAddTextFragment(DDScanQueryRef, CFStringRef, CFRange, void *identifier, DDTextFragmentMode, DDTextCoalescingType);
+void DDScanQueryAddSeparator(DDScanQueryRef, DDTextCoalescingType);
+void DDScanQueryAddLineBreak(DDScanQueryRef);
+void *DDScanQueryGetFragmentMetaData(DDScanQueryRef, CFIndex queryIndex);
+bool DDResultHasProperties(DDResultRef, CFIndex propertySet);
+CFArrayRef DDResultGetSubResults(DDResultRef);
+DDQueryRange DDResultGetQueryRangeForURLification(DDResultRef);
+#if PLATFORM(IOS)
+SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore)
+SOFT_LINK_CLASS(DataDetectorsCore, DDScannerResult)
+SOFT_LINK(DataDetectorsCore, DDScannerCreate, DDScannerRef, (DDScannerType type, DDScannerOptions options, CFErrorRef * errorRef), (type, options, errorRef))
+SOFT_LINK(DataDetectorsCore, DDScannerScanQuery, Boolean, (DDScannerRef scanner, DDScanQueryRef query), (scanner, query))
+SOFT_LINK(DataDetectorsCore, DDScanQueryCreate, DDScanQueryRef, (CFAllocatorRef allocator), (allocator))
+SOFT_LINK(DataDetectorsCore, DDScannerCopyResultsWithOptions, CFArrayRef, (DDScannerRef scanner, DDScannerCopyResultsOptions options), (scanner, options))
+SOFT_LINK(DataDetectorsCore, DDResultGetRange, CFRange, (DDResultRef result), (result))
+SOFT_LINK(DataDetectorsCore, DDResultGetType, CFStringRef, (DDResultRef result), (result))
+SOFT_LINK(DataDetectorsCore, DDResultGetCategory, DDResultCategory, (DDResultRef result), (result))
+SOFT_LINK(DataDetectorsCore, DDResultIsPastDate, Boolean, (DDResultRef result, CFDateRef referenceDate, CFTimeZoneRef referenceTimeZone), (result, referenceDate, referenceTimeZone))
+SOFT_LINK(DataDetectorsCore, DDScanQueryAddTextFragment, void, (DDScanQueryRef query, CFStringRef fragment, CFRange range, void *identifier, DDTextFragmentMode mode, DDTextCoalescingType type), (query, fragment, range, identifier, mode, type))
+SOFT_LINK(DataDetectorsCore, DDScanQueryAddSeparator, void, (DDScanQueryRef query, DDTextCoalescingType type), (query, type))
+SOFT_LINK(DataDetectorsCore, DDScanQueryAddLineBreak, void, (DDScanQueryRef query), (query))
+SOFT_LINK(DataDetectorsCore, DDScanQueryGetFragmentMetaData, void *, (DDScanQueryRef query, CFIndex queryIndex), (query, queryIndex))
+SOFT_LINK(DataDetectorsCore, DDResultHasProperties, bool, (DDResultRef result, CFIndex propertySet), (result, propertySet))
+SOFT_LINK(DataDetectorsCore, DDResultGetSubResults, CFArrayRef, (DDResultRef result), (result))
+SOFT_LINK(DataDetectorsCore, DDResultGetQueryRangeForURLification, DDQueryRange, (DDResultRef result), (result))
+SOFT_LINK(DataDetectorsCore, DDURLStringForResult, NSString *, (DDResultRef currentResult, NSString * resultIdentifier, DDURLifierPhoneNumberDetectionTypes includingTelGroups, NSDate * referenceDate, NSTimeZone * referenceTimeZone), (currentResult, resultIdentifier, includingTelGroups, referenceDate, referenceTimeZone))
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderHttpURLKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderWebURLKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderMailURLKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderGenericURLKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderEmailKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderTrackingNumberKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderFlightInformationKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDBinderSignatureBlockKey, CFStringRef)
+SOFT_LINK_POINTER(DataDetectorsCore, DDURLScheme, NSString *)
+SOFT_LINK_CONSTANT(DataDetectorsCore, DDScannerCopyResultsOptionsForPassiveUse, DDScannerCopyResultsOptions)
+#endif
+
}
Modified: trunk/Source/WebKit2/ChangeLog (195493 => 195494)
--- trunk/Source/WebKit2/ChangeLog 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebKit2/ChangeLog 2016-01-23 00:24:02 UTC (rev 195494)
@@ -1,3 +1,15 @@
+2016-01-22 Enrica Casucci <[email protected]>
+
+ Add support for DataDetectors in WK (iOS).
+ https://bugs.webkit.org/show_bug.cgi?id=152989
+ rdar://problem/22855960
+
+ Reviewed by Tim Horton.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (fromWKDataDetectorTypes): Changed parameter to uint64_t to
+ successfully compare against WKDataDetectorTypeAll.
+
2016-01-17 Ada Chan <[email protected]>
Add a mode parameter to MediaControllerInterface::supportsFullscreen() and ChromeClient::supportsVideoFullscreen().
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (195493 => 195494)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2016-01-23 00:19:02 UTC (rev 195493)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2016-01-23 00:24:02 UTC (rev 195494)
@@ -315,7 +315,7 @@
#endif
#if ENABLE(DATA_DETECTION)
-static WebCore::DataDetectorTypes fromWKDataDetectorTypes(uint32_t types)
+static WebCore::DataDetectorTypes fromWKDataDetectorTypes(uint64_t types)
{
if (static_cast<WKDataDetectorTypes>(types) == WKDataDetectorTypeNone)
return WebCore::DataDetectorTypeNone;