Implement action menus for data detected items
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Oct 2014 18:48:23 +0000 (18:48 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Oct 2014 18:48:23 +0000 (18:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138178
<rdar://problem/18709436>

Reviewed by Anders Carlsson.

* WebCore.exp.in:
Export a symbol from Position that we need.

* WebCore.xcodeproj/project.pbxproj:
* platform/spi/mac/DataDetectorsSPI.h:
Add a combined SPI header for all of the random bits of DataDetectors that we use.

* Shared/API/c/WKActionMenuTypes.h:
Add a new type.

* Shared/WebHitTestResult.cpp:
(WebKit::WebHitTestResult::Data::Data):
(WebKit::WebHitTestResult::Data::encode):
(WebKit::WebHitTestResult::Data::decode):
* Shared/WebHitTestResult.h:
(WebKit::WebHitTestResult::isTextNode):
Determine, store, encode, and decode whether or not the hit node is a text node.

* Shared/mac/ActionMenuHitTestResult.h:
* Shared/mac/ActionMenuHitTestResult.mm: Renamed from Source/WebKit2/Shared/mac/ActionMenuHitTestResult.cpp.
(WebKit::ActionMenuHitTestResult::encode):
(WebKit::ActionMenuHitTestResult::decode):
Make ActionMenuHitTestResult an Obj-C++ file.
Store, encode, and decode (securely!) a DDActionContext and FloatRect
representing the bounding box of the data detected item, if any.

* UIProcess/API/mac/WKView.mm:
(-[WKView initWithFrame:context:configuration:webView:]):
(-[WKView willOpenMenu:withEvent:]): Deleted.
Stop using willOpenMenu; we'll use NSMenuDelegate's menuNeedsUpdate: instead.
Hook up WKActionMenuController as our action menu's delegate.

* UIProcess/mac/WKActionMenuController.mm:
(-[WKActionMenuController prepareForMenu:withEvent:]):
Call _updateActionMenuItems *after* we've adjusted _state, so that it
can depend on the value being correct.

(-[WKActionMenuController willOpenMenu:withEvent:]):
(-[WKActionMenuController didPerformActionMenuHitTest:]):
Move menu updating to menuNeedsUpdate for more accurate timing.

(_updateActionMenuItems):
When building the menu, if we have a text node that is not a link,
and hit a data detected item, retrieve the menu from the DDActionContext.
If we have nothing, make sure to reset _type, and if the final hit-test
is still pending, build a menu with a dummy item.

* WebKit2.xcodeproj/project.pbxproj:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::performActionMenuHitTestAtLocation): Moved to WebPageMac.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::rangeExpandedAroundPosition):
Factor this out of performDictionaryLookupAtLocation.

(WebKit::WebPage::performDictionaryLookupAtLocation):
Make use of rangeExpandedAroundPosition.

(WebKit::scanForDataDetectedItems):
Expand to four lines of context around the hit point.
Convert that range to plain text, and feed it to DataDetectors.
Find the result that intersects the hit point, and make a DDActionContext
for it. Also, store the bounding box of the first quad of the detected
text, to provide to Data Detectors as a hint for UI placement.

(WebKit::WebPage::performActionMenuHitTestAtLocation):
If the hit node is a text node, call scanForDataDetectedItems and
store the resultant DDActionContext and bounding rect on our
ActionMenuHitTestResult for transfer to the UI process.

* WebKitSystemInterface.h:
* libWebKitSystemInterfaceMavericks.a:
* libWebKitSystemInterfaceMountainLion.a:
* libWebKitSystemInterfaceYosemite.a:
Update WebKitSystemInterface.

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

21 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/spi/mac/DataDetectorsSPI.h [new file with mode: 0644]
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/API/c/WKActionMenuTypes.h
Source/WebKit2/Shared/WebHitTestResult.cpp
Source/WebKit2/Shared/WebHitTestResult.h
Source/WebKit2/Shared/mac/ActionMenuHitTestResult.h
Source/WebKit2/Shared/mac/ActionMenuHitTestResult.mm [moved from Source/WebKit2/Shared/mac/ActionMenuHitTestResult.cpp with 55% similarity]
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/mac/WKActionMenuController.h
Source/WebKit2/UIProcess/mac/WKActionMenuController.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
WebKitLibraries/ChangeLog
WebKitLibraries/WebKitSystemInterface.h
WebKitLibraries/libWebKitSystemInterfaceMavericks.a
WebKitLibraries/libWebKitSystemInterfaceMountainLion.a
WebKitLibraries/libWebKitSystemInterfaceYosemite.a

index 322d86008861cd80f69c50c0a33d6e9fb121515a..ac69c3ffcbbe797ac65bfc15418523ed048cd8e4 100644 (file)
@@ -1,3 +1,18 @@
+2014-10-29  Tim Horton  <timothy_horton@apple.com>
+
+        Implement action menus for data detected items
+        https://bugs.webkit.org/show_bug.cgi?id=138178
+        <rdar://problem/18709436>
+
+        Reviewed by Anders Carlsson.
+
+        * WebCore.exp.in:
+        Export a symbol from Position that we need.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/spi/mac/DataDetectorsSPI.h:
+        Add a combined SPI header for all of the random bits of DataDetectors that we use.
+
 2014-10-29  Jer Noble  <jer.noble@apple.com>
 
         [EME] NULL-dereference crash in MediaKeys::setMediaElement().
index e2d852856f16a79e30dfd9abc06a5c8d6e9b4478..e05eed10785b05e9b895b2d8a630f620f7f15cef 100644 (file)
@@ -1342,6 +1342,7 @@ __ZN7WebCore8Gradient12addColorStopEfRKNS_5ColorE
 __ZN7WebCore8GradientC1ERKNS_10FloatPointES3_
 __ZN7WebCore8GradientD1Ev
 __ZN7WebCore8PositionC1EN3WTF10PassRefPtrINS_4NodeEEENS0_10AnchorTypeE
+__ZN7WebCore8PositionC1EN3WTF10PassRefPtrINS_4NodeEEENS0_19LegacyEditingOffsetE
 __ZN7WebCore8PositionC1EN3WTF10PassRefPtrINS_4NodeEEEiNS0_10AnchorTypeE
 __ZN7WebCore8Settings13gQTKitEnabledE
 __ZN7WebCore8Settings14setJavaEnabledEb
index c91c166f1dad9ba6f6de63ad04145e26919218c0..936423a259fa076874d230c80ee914a9e47559ec 100644 (file)
                2D481F02146B5C5500AA7834 /* CrossfadeGeneratedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D2FC0551460CD6F00263633 /* CrossfadeGeneratedImage.h */; };
                2D481F03146B5C6500AA7834 /* GradientImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D2FC0561460CD6F00263633 /* GradientImage.cpp */; };
                2D481F04146B5C6B00AA7834 /* GradientImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D2FC0571460CD6F00263633 /* GradientImage.h */; };
+               2D59F1BF1A0044C6001F3D29 /* DataDetectorsSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D59F1BE1A0044C6001F3D29 /* DataDetectorsSPI.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D5A592F152525230036EE51 /* ImageOrientation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8748D7412CC3F89001FBA41 /* ImageOrientation.cpp */; };
                2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */ = {isa = PBXBuildFile; fileRef = A8748D6612CC3763001FBA41 /* ImageOrientation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                2D5BC42716F882EE007048D0 /* SecurityPolicyViolationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D5BC42516F882BE007048D0 /* SecurityPolicyViolationEvent.h */; };
                2D3EF4471917915C00034184 /* WebCoreCALayerExtras.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreCALayerExtras.mm; sourceTree = "<group>"; };
                2D46F04D17B96FBD005647F0 /* IntPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntPoint.cpp; sourceTree = "<group>"; };
                2D46F04F17B96FD2005647F0 /* IntSize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntSize.cpp; sourceTree = "<group>"; };
+               2D59F1BE1A0044C6001F3D29 /* DataDetectorsSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataDetectorsSPI.h; sourceTree = "<group>"; };
                2D5BC42516F882BE007048D0 /* SecurityPolicyViolationEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecurityPolicyViolationEvent.h; sourceTree = "<group>"; };
                2D5BC42616F882BE007048D0 /* SecurityPolicyViolationEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SecurityPolicyViolationEvent.idl; sourceTree = "<group>"; };
                2D5C9CFB19C7B52E00B3C5C1 /* PageOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageOverlay.cpp; sourceTree = "<group>"; };
                9348428019F1A9190009D5AE /* mac */ = {
                        isa = PBXGroup;
                        children = (
+                               2D59F1BE1A0044C6001F3D29 /* DataDetectorsSPI.h */,
                                2DCB837719F99BBA00A7FBE4 /* NSSharingServicePickerSPI.h */,
                                2DCB837819F99BBA00A7FBE4 /* NSSharingServiceSPI.h */,
                                9348428119F1A9190009D5AE /* NSViewSPI.h */,
                                8538F05B0AD722F1006A81D1 /* DOMRange.h in Headers */,
                                851EE8210ABCA58100A6AA33 /* DOMRangeException.h in Headers */,
                                8538F05D0AD722F1006A81D1 /* DOMRangeInternal.h in Headers */,
+                               2D59F1BF1A0044C6001F3D29 /* DataDetectorsSPI.h in Headers */,
                                8538F0850AD72CB6006A81D1 /* DOMRanges.h in Headers */,
                                858C38A70AA8F20400B187A4 /* DOMRect.h in Headers */,
                                85E711D60AC5D5350053270F /* DOMRectInternal.h in Headers */,
diff --git a/Source/WebCore/platform/spi/mac/DataDetectorsSPI.h b/Source/WebCore/platform/spi/mac/DataDetectorsSPI.h
new file mode 100644 (file)
index 0000000..f528250
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#import "SoftLinking.h"
+#import <objc/runtime.h>
+
+typedef struct __DDScanner DDScanner, *DDScannerRef;
+typedef struct __DDScanQuery *DDScanQueryRef;
+typedef struct __DDResult *DDResultRef;
+
+typedef enum {
+    DDScannerTypeStandard = 0,
+} DDScannerType;
+
+enum {
+    DDScannerOptionStopAtFirstMatch = 1,
+};
+typedef CFIndex DDScannerOptions;
+
+enum {
+    DDScannerCopyResultsOptionsNone = 0,
+    DDScannerCopyResultsOptionsNoOverlap = 1 << 0,
+};
+typedef CFIndex DDScannerCopyResultsOptions;
+
+SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
+SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore)
+
+extern "C" {
+
+SOFT_LINK(DataDetectorsCore, DDScannerCreate, DDScannerRef, (DDScannerType type, DDScannerOptions options, CFErrorRef* errorRef), (type, options, errorRef))
+SOFT_LINK(DataDetectorsCore, DDScanQueryCreateFromString, DDScanQueryRef, (CFAllocatorRef allocator, CFStringRef string, CFRange range), (allocator, string, range))
+SOFT_LINK(DataDetectorsCore, DDScannerScanQuery, DDScanQueryRef, (DDScannerRef scanner, DDScanQueryRef query), (scanner, query))
+SOFT_LINK(DataDetectorsCore, DDScannerCopyResultsWithOptions, CFArrayRef, (DDScannerRef scanner, DDScannerCopyResultsOptions options), (scanner, options))
+SOFT_LINK(DataDetectorsCore, DDResultGetRange, CFRange, (DDResultRef result), (result))
+
+}
+
+SOFT_LINK_CLASS(DataDetectors, DDActionContext)
+SOFT_LINK_CLASS(DataDetectors, DDActionsManager)
+
+@interface DDActionContext : NSObject <NSCopying, NSSecureCoding>
+
+@property NSRect highlightFrame;
+@property (retain) NSArray *allResults;
+@property (retain) __attribute__((NSObject)) DDResultRef mainResult;
+
+@end
+
+@interface DDActionsManager : NSObject
+
++ (DDActionsManager *)sharedManager;
+- (NSArray *)menuItemsForResult:(DDResultRef)result actionContext:(DDActionContext *)context;
+
+@end
index 1061071e156218a769273fd4c9736d6bdec2fee3..1ec81c281359607a8c374de1782965057822efb3 100644 (file)
@@ -1,3 +1,73 @@
+2014-10-29  Tim Horton  <timothy_horton@apple.com>
+
+        Implement action menus for data detected items
+        https://bugs.webkit.org/show_bug.cgi?id=138178
+        <rdar://problem/18709436>
+
+        Reviewed by Anders Carlsson.
+
+        * Shared/API/c/WKActionMenuTypes.h:
+        Add a new type.
+
+        * Shared/WebHitTestResult.cpp:
+        (WebKit::WebHitTestResult::Data::Data):
+        (WebKit::WebHitTestResult::Data::encode):
+        (WebKit::WebHitTestResult::Data::decode):
+        * Shared/WebHitTestResult.h:
+        (WebKit::WebHitTestResult::isTextNode):
+        Determine, store, encode, and decode whether or not the hit node is a text node.
+
+        * Shared/mac/ActionMenuHitTestResult.h:
+        * Shared/mac/ActionMenuHitTestResult.mm: Renamed from Source/WebKit2/Shared/mac/ActionMenuHitTestResult.cpp.
+        (WebKit::ActionMenuHitTestResult::encode):
+        (WebKit::ActionMenuHitTestResult::decode):
+        Make ActionMenuHitTestResult an Obj-C++ file.
+        Store, encode, and decode (securely!) a DDActionContext and FloatRect
+        representing the bounding box of the data detected item, if any.
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView initWithFrame:context:configuration:webView:]):
+        (-[WKView willOpenMenu:withEvent:]): Deleted.
+        Stop using willOpenMenu; we'll use NSMenuDelegate's menuNeedsUpdate: instead.
+        Hook up WKActionMenuController as our action menu's delegate.
+
+        * UIProcess/mac/WKActionMenuController.mm:
+        (-[WKActionMenuController prepareForMenu:withEvent:]):
+        Call _updateActionMenuItems *after* we've adjusted _state, so that it
+        can depend on the value being correct.
+
+        (-[WKActionMenuController willOpenMenu:withEvent:]):
+        (-[WKActionMenuController didPerformActionMenuHitTest:]):
+        Move menu updating to menuNeedsUpdate for more accurate timing.
+
+        (_updateActionMenuItems):
+        When building the menu, if we have a text node that is not a link,
+        and hit a data detected item, retrieve the menu from the DDActionContext.
+        If we have nothing, make sure to reset _type, and if the final hit-test
+        is still pending, build a menu with a dummy item.
+
+        * WebKit2.xcodeproj/project.pbxproj:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::performActionMenuHitTestAtLocation): Moved to WebPageMac.
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::rangeExpandedAroundPosition):
+        Factor this out of performDictionaryLookupAtLocation.
+
+        (WebKit::WebPage::performDictionaryLookupAtLocation):
+        Make use of rangeExpandedAroundPosition.
+
+        (WebKit::scanForDataDetectedItems):
+        Expand to four lines of context around the hit point.
+        Convert that range to plain text, and feed it to DataDetectors.
+        Find the result that intersects the hit point, and make a DDActionContext
+        for it. Also, store the bounding box of the first quad of the detected
+        text, to provide to Data Detectors as a hint for UI placement.
+
+        (WebKit::WebPage::performActionMenuHitTestAtLocation):
+        If the hit node is a text node, call scanForDataDetectedItems and
+        store the resultant DDActionContext and bounding rect on our
+        ActionMenuHitTestResult for transfer to the UI process.
+
 2014-10-29  Joseph Pecoraro  <pecoraro@apple.com>
 
         [iOS] iPad: Occasional <select> crashes attempting to scroll to non-existing row 0 in viewWillAppear
index 6a129a7d38a8fe621d3fa94447745304c7c751b4..242790225be32999764a16320b828b919b1a8418 100644 (file)
@@ -35,7 +35,8 @@ extern "C" {
 enum {
     kWKActionMenuNone = 0,
     kWKActionMenuLink,
-    kWKActionMenuImage
+    kWKActionMenuImage,
+    kWKActionMenuDataDetectedItem
 };
 typedef uint32_t _WKActionMenuType;
 
index 0974e4342c8c2276d8eb21b70932cfc871785640..49ae714b0befbe988cc7a253add536b501910215 100644 (file)
@@ -53,6 +53,7 @@ WebHitTestResult::Data::Data(const HitTestResult& hitTestResult)
     , elementBoundingBox(elementBoundingBoxInWindowCoordinates(hitTestResult))
     , isScrollbar(hitTestResult.scrollbar())
     , isSelected(hitTestResult.isSelected())
+    , isTextNode(hitTestResult.innerNode() && hitTestResult.innerNode()->isTextNode())
 {
 }
 
@@ -72,6 +73,7 @@ void WebHitTestResult::Data::encode(IPC::ArgumentEncoder& encoder) const
     encoder << elementBoundingBox;
     encoder << isScrollbar;
     encoder << isSelected;
+    encoder << isTextNode;
 }
 
 bool WebHitTestResult::Data::decode(IPC::ArgumentDecoder& decoder, WebHitTestResult::Data& hitTestResultData)
@@ -85,7 +87,8 @@ bool WebHitTestResult::Data::decode(IPC::ArgumentDecoder& decoder, WebHitTestRes
         || !decoder.decode(hitTestResultData.isContentEditable)
         || !decoder.decode(hitTestResultData.elementBoundingBox)
         || !decoder.decode(hitTestResultData.isScrollbar)
-        || !decoder.decode(hitTestResultData.isSelected))
+        || !decoder.decode(hitTestResultData.isSelected)
+        || !decoder.decode(hitTestResultData.isTextNode))
         return false;
 
     return true;
index b942cdd5fec2512a0c9f7f119f88111c84cc37f5..39a05eb6c634b4fa0cd0ca99eaedc62bfd96bc10 100644 (file)
@@ -53,6 +53,7 @@ public:
         WebCore::IntRect elementBoundingBox;
         bool isScrollbar;
         bool isSelected;
+        bool isTextNode;
 
         Data();
         explicit Data(const WebCore::HitTestResult&);
@@ -82,6 +83,8 @@ public:
 
     bool isSelected() const { return m_data.isSelected; }
 
+    bool isTextNode() const { return m_data.isTextNode; }
+
 private:
     explicit WebHitTestResult(const WebHitTestResult::Data& hitTestResultData)
         : m_data(hitTestResultData)
index 2dca549509ee1ddc9cf0790e9444a109c8153caa..c352f03f2e33c90c7810539c035283885357201a 100644 (file)
@@ -27,6 +27,9 @@
 #define ActionMenuHitTestResult_h
 
 #include "ShareableBitmap.h"
+#include <WebCore/FloatRect.h>
+
+OBJC_CLASS DDActionContext;
 
 namespace IPC {
 class ArgumentDecoder;
@@ -40,6 +43,9 @@ struct ActionMenuHitTestResult {
     static bool decode(IPC::ArgumentDecoder&, ActionMenuHitTestResult&);
 
     RefPtr<ShareableBitmap> image;
+
+    RetainPtr<DDActionContext> actionContext;
+    WebCore::FloatRect actionBoundingBox;
 };
 
 } // namespace WebKit
similarity index 55%
rename from Source/WebKit2/Shared/mac/ActionMenuHitTestResult.cpp
rename to Source/WebKit2/Shared/mac/ActionMenuHitTestResult.mm
index 081a1d59a4be838b0c05c9fa1e9f58c3de5ce249..a9683040ccecd6245344b66d113f2b25527ae081 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
-#include "ActionMenuHitTestResult.h"
+#import "config.h"
+#import "ActionMenuHitTestResult.h"
 
-#include "ArgumentDecoder.h"
-#include "ArgumentEncoder.h"
+#import "ArgumentCodersCF.h"
+#import "ArgumentDecoder.h"
+#import "ArgumentEncoder.h"
+#import "WebCoreArgumentCoders.h"
+#import <WebCore/DataDetectorsSPI.h>
 
 namespace WebKit {
 
@@ -40,6 +43,20 @@ void ActionMenuHitTestResult::encode(IPC::ArgumentEncoder& encoder) const
         image->createHandle(handle, SharedMemory::ReadOnly);
 
     encoder << handle;
+
+    bool hasActionContext = actionContext;
+    encoder << hasActionContext;
+    if (hasActionContext) {
+        RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]);
+        RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
+        [archiver setRequiresSecureCoding:YES];
+        [archiver encodeObject:actionContext.get() forKey:@"actionContext"];
+        [archiver finishEncoding];
+
+        IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get()));
+    }
+
+    encoder << actionBoundingBox;
 }
 
 bool ActionMenuHitTestResult::decode(IPC::ArgumentDecoder& decoder, ActionMenuHitTestResult& actionMenuHitTestResult)
@@ -51,6 +68,30 @@ bool ActionMenuHitTestResult::decode(IPC::ArgumentDecoder& decoder, ActionMenuHi
     if (!handle.isNull())
         actionMenuHitTestResult.image = ShareableBitmap::create(handle, SharedMemory::ReadOnly);
 
+    bool hasActionContext;
+    if (!decoder.decode(hasActionContext))
+        return false;
+
+    if (hasActionContext) {
+        RetainPtr<CFDataRef> data;
+        if (!IPC::decode(decoder, data))
+            return false;
+
+        RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]);
+        [unarchiver setRequiresSecureCoding:YES];
+        @try {
+            actionMenuHitTestResult.actionContext = [unarchiver decodeObjectOfClass:getDDActionContextClass() forKey:@"actionContext"];
+        } @catch (NSException *exception) {
+            LOG_ERROR("Failed to decode DDActionContext: %@", exception);
+            return false;
+        }
+        
+        [unarchiver finishDecoding];
+    }
+
+    if (!decoder.decode(actionMenuHitTestResult.actionBoundingBox))
+        return false;
+
     return true;
 }
     
index bd8ae21d207f071b0c9d9e90c23bb14ab7be5b22..4fac357b19c4852db9b68ba240bcd830aa99f1cf 100644 (file)
@@ -3538,6 +3538,7 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
         RetainPtr<NSMenu> menu = adoptNS([[NSMenu alloc] init]);
         self.actionMenu = menu.get();
         _data->_actionMenuController = adoptNS([[WKActionMenuController alloc] initWithPage:*_data->_page view:self]);
+        self.actionMenu.delegate = _data->_actionMenuController.get();
     }
 
     return self;
@@ -3642,11 +3643,6 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
     [_data->_actionMenuController prepareForMenu:menu withEvent:event];
 }
 
-- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event
-{
-    [_data->_actionMenuController willOpenMenu:menu withEvent:event];
-}
-
 - (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
 {
     [_data->_actionMenuController didCloseMenu:menu withEvent:event];
index 143dd12d8bb5980a55181f68a37a1e0e4098cd6b..443c2ccc1b772a0ad91633ec7686247ec8363456 100644 (file)
@@ -44,7 +44,7 @@ enum class ActionMenuState {
 
 @class WKView;
 
-@interface WKActionMenuController : NSObject {
+@interface WKActionMenuController : NSObject <NSMenuDelegate> {
 @private
     WebKit::WebPageProxy *_page;
     WKView *_wkView;
@@ -59,7 +59,6 @@ enum class ActionMenuState {
 - (void)willDestroyView:(WKView *)view;
 
 - (void)prepareForMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
-- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
 - (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
 
 - (void)didPerformActionMenuHitTest:(const WebKit::ActionMenuHitTestResult&)hitTestResult;
index 46d234887331211d86c5e76a3dbfce03fad25f82..5586a15cd23df7be17ddff8dcaf1ce51b08513e9 100644 (file)
 #import "WKNSURLExtras.h"
 #import "WKViewInternal.h"
 #import "WebContext.h"
+#import "WebKitSystemInterface.h"
 #import "WebPageMessages.h"
 #import "WebPageProxy.h"
 #import "WebPageProxyMessages.h"
 #import "WebProcessProxy.h"
+#import <Foundation/Foundation.h>
 #import <ImageIO/ImageIO.h>
 #import <ImageKit/ImageKit.h>
+#import <WebCore/DataDetectorsSPI.h>
 #import <WebCore/NSSharingServicePickerSPI.h>
 #import <WebCore/NSViewSPI.h>
 #import <WebCore/SoftLinking.h>
@@ -94,29 +97,10 @@ using namespace WebKit;
     if (menu != _wkView.actionMenu)
         return;
 
-    [self _updateActionMenuItems];
-
     _page->performActionMenuHitTestAtLocation([_wkView convertPoint:event.locationInWindow fromView:nil]);
 
     _state = ActionMenuState::Pending;
-}
-
-- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event
-{
-    if (menu != _wkView.actionMenu)
-        return;
-
-    ASSERT(_state != ActionMenuState::None);
-
-    // FIXME: We need to be able to cancel this if the menu goes away.
-    // FIXME: Connection can be null if the process is closed; we should clean up better in that case.
-    if (_state == ActionMenuState::Pending) {
-        if (auto* connection = _page->process().connection())
-            connection->waitForAndDispatchImmediately<Messages::WebPageProxy::DidPerformActionMenuHitTest>(_page->pageID(), std::chrono::milliseconds(500));
-    }
-
-    if (_state == ActionMenuState::Ready)
-        [self _updateActionMenuItems];
+    [self _updateActionMenuItems];
 }
 
 - (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
@@ -297,6 +281,25 @@ static NSString *pathToPhotoOnDisk(NSString *suggestedFilename)
     });
 }
 
+#pragma mark NSMenuDelegate implementation
+
+- (void)menuNeedsUpdate:(NSMenu *)menu
+{
+    if (menu != _wkView.actionMenu)
+        return;
+
+    ASSERT(_state != ActionMenuState::None);
+
+    // FIXME: We need to be able to cancel this if the menu goes away.
+    // FIXME: Connection can be null if the process is closed; we should clean up better in that case.
+    if (_state == ActionMenuState::Pending) {
+        if (auto* connection = _page->process().connection())
+            connection->waitForAndDispatchImmediately<Messages::WebPageProxy::DidPerformActionMenuHitTest>(_page->pageID(), std::chrono::milliseconds(500));
+    }
+
+    [self _updateActionMenuItems];
+}
+
 #pragma mark NSSharingServicePickerDelegate implementation
 
 - (id <NSSharingServiceDelegate>)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker delegateForSharingService:(NSSharingService *)sharingService
@@ -385,13 +388,28 @@ static NSImage *webKitBundleImageNamed(NSString *name)
         if (!hitTestResult->absoluteImageURL().isEmpty() && _hitTestResult.image) {
             _type = kWKActionMenuImage;
             return [self _defaultMenuItemsForImage];
-        } if (!hitTestResult->absoluteLinkURL().isEmpty()) {
+        }
+
+        if (!hitTestResult->absoluteLinkURL().isEmpty()) {
             _type = kWKActionMenuLink;
             return [self _defaultMenuItemsForLink];
         }
+
+        if (hitTestResult->isTextNode()) {
+            if (DDActionContext *actionContext = _hitTestResult.actionContext.get()) {
+                WKSetDDActionContextIsForActionMenu(actionContext);
+                actionContext.highlightFrame = [_wkView.window convertRectToScreen:[_wkView convertRect:_hitTestResult.actionBoundingBox toView:nil]];
+                NSArray *dataDetectorMenuItems = [[getDDActionsManagerClass() sharedManager] menuItemsForResult:[_hitTestResult.actionContext mainResult] actionContext:actionContext];
+                if (dataDetectorMenuItems.count) {
+                    _type = kWKActionMenuDataDetectedItem;
+                    return dataDetectorMenuItems;
+                }
+            }
+        }
     }
 
-    return @[ ];
+    _type = kWKActionMenuNone;
+    return _state != ActionMenuState::Ready ? @[ [NSMenuItem separatorItem] ] : @[ ];
 }
 
 - (void)_updateActionMenuItems
index a86243d14d8dc62ce11566cbbc4fd3b00336c2fe..d8a4ebcc5529745eebef5ac0a2f896c1d2ccc4e1 100644 (file)
                2D2ADF0916362DD500197E47 /* PDFPluginTextAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF0616362DC700197E47 /* PDFPluginTextAnnotation.mm */; };
                2D2ADF0B16362DDB00197E47 /* PDFPluginAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF031636243500197E47 /* PDFPluginAnnotation.mm */; };
                2D2ADF1016364D8200197E47 /* PDFPluginChoiceAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF0E16364D8200197E47 /* PDFPluginChoiceAnnotation.mm */; };
-               2D353B1219F8305D000EEACD /* ActionMenuHitTestResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.cpp */; };
+               2D353B1219F8305D000EEACD /* ActionMenuHitTestResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.mm */; };
                2D353B1319F8305D000EEACD /* ActionMenuHitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D353B1119F8305D000EEACD /* ActionMenuHitTestResult.h */; };
                2D3EF4421917646300034184 /* WebMemoryPressureHandlerIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D3EF4401917646300034184 /* WebMemoryPressureHandlerIOS.mm */; };
                2D3EF4431917646300034184 /* WebMemoryPressureHandlerIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D3EF4411917646300034184 /* WebMemoryPressureHandlerIOS.h */; };
                2D2ADF0C16363DEC00197E47 /* PDFLayerControllerDetails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PDFLayerControllerDetails.h; path = PDF/PDFLayerControllerDetails.h; sourceTree = "<group>"; };
                2D2ADF0D16364D8200197E47 /* PDFPluginChoiceAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDFPluginChoiceAnnotation.h; path = PDF/PDFPluginChoiceAnnotation.h; sourceTree = "<group>"; };
                2D2ADF0E16364D8200197E47 /* PDFPluginChoiceAnnotation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PDFPluginChoiceAnnotation.mm; path = PDF/PDFPluginChoiceAnnotation.mm; sourceTree = "<group>"; };
-               2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActionMenuHitTestResult.cpp; sourceTree = "<group>"; };
+               2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActionMenuHitTestResult.mm; sourceTree = "<group>"; };
                2D353B1119F8305D000EEACD /* ActionMenuHitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionMenuHitTestResult.h; sourceTree = "<group>"; };
                2D3EF4401917646300034184 /* WebMemoryPressureHandlerIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WebMemoryPressureHandlerIOS.mm; path = ios/WebMemoryPressureHandlerIOS.mm; sourceTree = "<group>"; };
                2D3EF4411917646300034184 /* WebMemoryPressureHandlerIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebMemoryPressureHandlerIOS.h; path = ios/WebMemoryPressureHandlerIOS.h; sourceTree = "<group>"; };
                BC111B5A112F628200337BAB /* mac */ = {
                        isa = PBXGroup;
                        children = (
-                               2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.cpp */,
+                               2D353B1019F8305D000EEACD /* ActionMenuHitTestResult.mm */,
                                2D353B1119F8305D000EEACD /* ActionMenuHitTestResult.h */,
                                E179FD9B134D38060015B883 /* ArgumentCodersMac.h */,
                                E179FD9E134D38250015B883 /* ArgumentCodersMac.mm */,
                                1AE00D5C182DADE100087DD7 /* KeyedEncoder.cpp in Sources */,
                                1AC8702E130B49A2002C1257 /* WebPluginSiteDataManager.cpp in Sources */,
                                BC5744EF12638FB3006F0F12 /* WebPopupItem.cpp in Sources */,
-                               2D353B1219F8305D000EEACD /* ActionMenuHitTestResult.cpp in Sources */,
+                               2D353B1219F8305D000EEACD /* ActionMenuHitTestResult.mm in Sources */,
                                0F931C1D18C5711900DBA7C3 /* ScrollingTreeOverflowScrollingNodeIOS.mm in Sources */,
                                D3B9484611FF4B6500032B39 /* WebPopupMenu.cpp in Sources */,
                                1AAF08A1192681D100B6390C /* WebUserContentControllerProxy.cpp in Sources */,
index 156c4a98f8b989d4c9b440503bd503ee48a7f822..21be10599241bf2a8dff8471372a71a0fa2a808d 100644 (file)
 #include <WebCore/Icon.h>
 #endif
 
-#if PLATFORM(MAC)
-#include "ActionMenuHitTestResult.h"
-#endif
-
 #ifndef NDEBUG
 #include <wtf/RefCountedLeakCounter.h>
 #endif
@@ -4799,34 +4795,4 @@ void WebPage::willChangeCurrentHistoryItemForMainFrame()
     send(Messages::WebPageProxy::WillChangeCurrentHistoryItemForMainFrame());
 }
 
-#if PLATFORM(MAC)
-void WebPage::performActionMenuHitTestAtLocation(WebCore::FloatPoint locationInViewCooordinates)
-{
-    layoutIfNeeded();
-
-    MainFrame& mainFrame = corePage()->mainFrame();
-    if (!mainFrame.view() || !mainFrame.view()->renderView()) {
-        send(Messages::WebPageProxy::DidPerformActionMenuHitTest(ActionMenuHitTestResult()));
-        return;
-    }
-
-    RenderView& mainRenderView = *mainFrame.view()->renderView();
-
-    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
-
-    HitTestResult hitTestResult(mainFrame.view()->rootViewToContents(roundedIntPoint(locationInViewCooordinates)));
-    mainRenderView.hitTest(request, hitTestResult);
-
-    ActionMenuHitTestResult actionMenuResult;
-
-    if (Image* image = hitTestResult.image()) {
-        actionMenuResult.image = ShareableBitmap::createShareable(IntSize(image->size()), ShareableBitmap::SupportsAlpha);
-        if (actionMenuResult.image)
-            actionMenuResult.image->createGraphicsContext()->drawImage(image, ColorSpaceDeviceRGB, IntPoint());
-    }
-
-    send(Messages::WebPageProxy::DidPerformActionMenuHitTest(actionMenuResult));
-}
-#endif
-
 } // namespace WebKit
index e0b5581d22f4492313176c22043591d59b6d8b9d..f9e6f756523b44fd1d6bd22da666726ccf6a06e4 100644 (file)
@@ -28,6 +28,7 @@
 
 #if PLATFORM(MAC)
 
+#import "ActionMenuHitTestResult.h"
 #import "AttributedString.h"
 #import "DataReference.h"
 #import "DictionaryPopupInfo.h"
 #import <QuartzCore/QuartzCore.h>
 #import <WebCore/AXObjectCache.h>
 #import <WebCore/BackForwardController.h>
+#import <WebCore/DataDetectorsSPI.h>
 #import <WebCore/EventHandler.h>
 #import <WebCore/FocusController.h>
 #import <WebCore/FrameLoader.h>
 #import <WebCore/FrameView.h>
+#import <WebCore/GraphicsContext.h>
 #import <WebCore/HTMLConverter.h>
 #import <WebCore/HitTestResult.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/RenderElement.h>
 #import <WebCore/RenderObject.h>
 #import <WebCore/RenderStyle.h>
+#import <WebCore/RenderView.h>
 #import <WebCore/ResourceHandle.h>
 #import <WebCore/ScrollView.h>
 #import <WebCore/StyleInheritedData.h>
 #import <WebCore/TextIterator.h>
 #import <WebCore/VisibleUnits.h>
 #import <WebCore/WindowsKeyboardCodes.h>
+#import <WebCore/htmlediting.h>
 #import <WebKitSystemInterface.h>
 
 using namespace WebCore;
@@ -496,6 +501,34 @@ static bool shouldUseSelection(const VisiblePosition& position, const VisibleSel
     return isPositionInRange(position, selectedRange.get());
 }
 
+static PassRefPtr<Range> rangeExpandedAroundPosition(const VisiblePosition& position, int numberOfLinesToExpand)
+{
+    VisiblePosition contextStart = position;
+    VisiblePosition contextEnd = position;
+    for (int i = 0; i < numberOfLinesToExpand; i++) {
+        VisiblePosition n = previousLinePosition(contextStart, contextStart.lineDirectionPointForBlockDirectionNavigation());
+        if (n.isNull() || n == contextStart)
+            break;
+        contextStart = n;
+    }
+    for (int i = 0; i < numberOfLinesToExpand; i++) {
+        VisiblePosition n = nextLinePosition(contextEnd, contextEnd.lineDirectionPointForBlockDirectionNavigation());
+        if (n.isNull() || n == contextEnd)
+            break;
+        contextEnd = n;
+    }
+
+    VisiblePosition lineStart = startOfLine(contextStart);
+    if (!lineStart.isNull())
+        contextStart = lineStart;
+
+    VisiblePosition lineEnd = endOfLine(contextEnd);
+    if (!lineEnd.isNull())
+        contextEnd = lineEnd;
+    
+    return makeRange(contextStart, contextEnd);
+}
+
 void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
 {
     if (PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame())) {
@@ -524,33 +557,9 @@ void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
     NSDictionary *options = nil;
 
     // As context, we are going to use four lines of text before and after the point. (Dictionary can sometimes look up things that are four lines long)
-    const int numberOfLinesOfContext = 4;
-    VisiblePosition contextStart = position;
-    VisiblePosition contextEnd = position;
-    for (int i = 0; i < numberOfLinesOfContext; i++) {
-        VisiblePosition n = previousLinePosition(contextStart, contextStart.lineDirectionPointForBlockDirectionNavigation());
-        if (n.isNull() || n == contextStart)
-            break;
-        contextStart = n;
-    }
-    for (int i = 0; i < numberOfLinesOfContext; i++) {
-        VisiblePosition n = nextLinePosition(contextEnd, contextEnd.lineDirectionPointForBlockDirectionNavigation());
-        if (n.isNull() || n == contextEnd)
-            break;
-        contextEnd = n;
-    }
+    RefPtr<Range> fullCharacterRange = rangeExpandedAroundPosition(position, 4);
+    NSRange rangeToPass = NSMakeRange(TextIterator::rangeLength(makeRange(fullCharacterRange->startPosition(), position).get()), 0);
 
-    VisiblePosition lineStart = startOfLine(contextStart);
-    if (!lineStart.isNull())
-        contextStart = lineStart;
-
-    VisiblePosition lineEnd = endOfLine(contextEnd);
-    if (!lineEnd.isNull())
-        contextEnd = lineEnd;
-
-    NSRange rangeToPass = NSMakeRange(TextIterator::rangeLength(makeRange(contextStart, position).get()), 0);
-
-    RefPtr<Range> fullCharacterRange = makeRange(contextStart, contextEnd);
     String fullPlainTextString = plainText(fullCharacterRange.get());
 
     NSRange extractedRange = WKExtractWordDefinitionTokenRangeFromContextualString(fullPlainTextString, rangeToPass, &options);
@@ -1050,6 +1059,95 @@ String WebPage::platformUserAgent(const URL&) const
     return String();
 }
 
+static RetainPtr<DDActionContext> scanForDataDetectedItems(const HitTestResult& hitTestResult, FloatRect& actionBoundingBox)
+{
+    Node* node = hitTestResult.innerNonSharedNode();
+    if (!node)
+        return nullptr;
+    auto renderer = node->renderer();
+    if (!renderer)
+        return nullptr;
+    VisiblePosition position = renderer->positionForPoint(hitTestResult.localPoint(), nullptr);
+    if (position.isNull())
+        position = firstPositionInOrBeforeNode(node);
+
+    RefPtr<Range> contextRange = rangeExpandedAroundPosition(position, 4);
+    String fullPlainTextString = plainText(contextRange.get());
+    int hitLocation = TextIterator::rangeLength(makeRange(contextRange->startPosition(), position).get());
+
+    RetainPtr<DDScannerRef> scanner = adoptCF(DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
+    RetainPtr<DDScanQueryRef> scanQuery = adoptCF(DDScanQueryCreateFromString(kCFAllocatorDefault, fullPlainTextString.createCFString().get(), CFRangeMake(0, fullPlainTextString.length())));
+
+    if (!DDScannerScanQuery(scanner.get(), scanQuery.get()))
+        return nullptr;
+
+    RetainPtr<CFArrayRef> results = adoptCF(DDScannerCopyResultsWithOptions(scanner.get(), DDScannerCopyResultsOptionsNoOverlap));
+
+    // Find the DDResultRef that intersects the hitTestResult's VisiblePosition.
+    DDResultRef mainResult = nullptr;
+    RefPtr<Range> mainResultRange;
+    CFIndex resultCount = CFArrayGetCount(results.get());
+    for (CFIndex i = 0; i < resultCount; i++) {
+        DDResultRef result = (DDResultRef)CFArrayGetValueAtIndex(results.get(), i);
+        CFRange resultRangeInContext = DDResultGetRange(result);
+        if (hitLocation >= resultRangeInContext.location && (hitLocation - resultRangeInContext.location) < resultRangeInContext.length) {
+            mainResult = result;
+            mainResultRange = TextIterator::subrange(contextRange.get(), resultRangeInContext.location, resultRangeInContext.length);
+            break;
+        }
+    }
+
+    if (!mainResult)
+        return nullptr;
+
+    RetainPtr<DDActionContext> actionContext = adoptNS([[getDDActionContextClass() alloc] init]);
+    [actionContext setAllResults:(NSArray *)results.get()];
+    [actionContext setMainResult:mainResult];
+
+    Vector<FloatQuad> quads;
+    mainResultRange->textQuads(quads);
+    if (!quads.isEmpty())
+        actionBoundingBox = mainResultRange->ownerDocument().view()->contentsToWindow(quads[0].enclosingBoundingBox());
+
+    return actionContext;
+}
+
+void WebPage::performActionMenuHitTestAtLocation(WebCore::FloatPoint locationInViewCooordinates)
+{
+    layoutIfNeeded();
+
+    MainFrame& mainFrame = corePage()->mainFrame();
+    if (!mainFrame.view() || !mainFrame.view()->renderView()) {
+        send(Messages::WebPageProxy::DidPerformActionMenuHitTest(ActionMenuHitTestResult()));
+        return;
+    }
+
+    RenderView& mainRenderView = *mainFrame.view()->renderView();
+
+    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
+
+    IntPoint locationInContentCoordinates = mainFrame.view()->rootViewToContents(roundedIntPoint(locationInViewCooordinates));
+    HitTestResult hitTestResult(locationInContentCoordinates);
+    mainRenderView.hitTest(request, hitTestResult);
+
+    ActionMenuHitTestResult actionMenuResult;
+
+    if (Image* image = hitTestResult.image()) {
+        actionMenuResult.image = ShareableBitmap::createShareable(IntSize(image->size()), ShareableBitmap::SupportsAlpha);
+        if (actionMenuResult.image)
+            actionMenuResult.image->createGraphicsContext()->drawImage(image, ColorSpaceDeviceRGB, IntPoint());
+    }
+
+    // FIXME: Avoid scanning if we will just throw away the result (e.g. we're over a link).
+    if (hitTestResult.innerNode() && hitTestResult.innerNode()->isTextNode()) {
+        FloatRect actionBoundingBox;
+        actionMenuResult.actionContext = scanForDataDetectedItems(hitTestResult, actionBoundingBox);
+        actionMenuResult.actionBoundingBox = actionBoundingBox;
+    }
+    
+    send(Messages::WebPageProxy::DidPerformActionMenuHitTest(actionMenuResult));
+}
+
 } // namespace WebKit
 
 #endif // PLATFORM(MAC)
index 53f54a9fbaa3740e40b7a6186d2a519e2727142b..00ada6394cc3db995eada4ccf2f1d2d83bfa1e74 100644 (file)
@@ -1,3 +1,17 @@
+2014-10-29  Tim Horton  <timothy_horton@apple.com>
+
+        Implement action menus for data detected items
+        https://bugs.webkit.org/show_bug.cgi?id=138178
+        <rdar://problem/18709436>
+
+        Reviewed by Anders Carlsson.
+
+        * WebKitSystemInterface.h:
+        * libWebKitSystemInterfaceMavericks.a:
+        * libWebKitSystemInterfaceMountainLion.a:
+        * libWebKitSystemInterfaceYosemite.a:
+        Update WebKitSystemInterface.
+
 2014-10-14  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Enable Encrypted Media Support
index 09fbe350bf2825406d10322136416dd669e17fca..d6e7b6df0f089189eff7999bee613dc45e4ea6d0 100644 (file)
@@ -22,6 +22,7 @@
 
 @class AVAsset;
 @class AVPlayer;
+@class DDActionContext;
 @class QTMovie;
 @class QTMovieView;
 
@@ -128,8 +129,9 @@ void WKSetDragImage(NSImage *image, NSPoint offset);
 
 void WKDrawBezeledTextArea(NSRect, BOOL enabled);
 
-void WKPopupMenu(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*, NSControlSize controlSize, bool hideArrows);
+void WKPopupMenu(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*, NSControlSize controlSize, bool usesCustomAppearance);
 void WKPopupContextMenu(NSMenu *menu, NSPoint screenLocation);
+void WKSetDDActionContextIsForActionMenu(DDActionContext *actionContext);
 void WKSendUserChangeNotifications(void);
 #ifndef __LP64__
 BOOL WKConvertNSEventToCarbonEvent(EventRecord *carbonEvent, NSEvent *cocoaEvent);
index b881fc41797ed29e642f1b9662fe34bdd036efb7..2a0ed4d6e393d2a4f248d9e57224caea8e9b7690 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceMavericks.a and b/WebKitLibraries/libWebKitSystemInterfaceMavericks.a differ
index ce42769b4cb1840b0b86aa7ea483e23660840764..30ac0652f602a1421e56d3f432453c571f4ab1bd 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceMountainLion.a and b/WebKitLibraries/libWebKitSystemInterfaceMountainLion.a differ
index 185764abf67edc9e37e19028a8ccad3cd1fb74ff..6c9ce03905d684f9a2c5b45fea62d4c5fc1db05e 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceYosemite.a and b/WebKitLibraries/libWebKitSystemInterfaceYosemite.a differ