Source/WebCore:
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Apr 2015 21:23:54 +0000 (21:23 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Apr 2015 21:23:54 +0000 (21:23 +0000)
[Mac] Extend action menus to support PDF
https://bugs.webkit.org/show_bug.cgi?id=143895
<rdar://problem/19003333>

Reviewed by Tim Horton.

Tested by TestWebKitAPI ActionMenus.mm.

Add a new dictionary lookup method to support PDF Selections. This code replicates the
DOM Range-based logic used for HTML documents, but does so using the PDFKit API and
its support types.

* Configurations/Base.xcconfig: Add PDFKit include path for build.
* editing/mac/DictionaryLookup.h:
* editing/mac/DictionaryLookup.mm:
(WebCore::expandSelectionByCharacters): Helper function for PDF support.
(WebCore::dictionaryLookupForPDFSelection): Added.

Source/WebKit/mac:
Extend action menus to support PDF
https://bugs.webkit.org/show_bug.cgi?id=143895
<rdar://problem/19003333>

Reviewed by Tim Horton.

Prevent a crash when someone attempts to invoke an action menu on a PDF hosted
in a WK1 view.

* WebView/WebActionMenuController.mm:
(-[WebActionMenuController performHitTestAtPoint:]): Handle WebPDFView as well as
the WebHTMLView case.
* WebView/WebDocument.h:
* WebView/WebHTMLView.h:
* WebView/WebHTMLView.mm:
(-[WebHTMLView _frame]):
* WebView/WebHTMLViewInternal.h:
* WebView/WebPDFView.h:
* WebView/WebPDFView.mm:
(-[WebPDFView _frame]): Added.

Source/WebKit2:
Extend action menus to support PDF
https://bugs.webkit.org/show_bug.cgi?id=143895
<rdar://problem/19003333>

Reviewed by Tim Horton.

If the mouse pointer is over a PDF, try to provide a relevant action menu for whatever
content is under the mouse. For now, we only support copying text and handling URLs.

If no text is selected, use the dictionary lookup service to find a semantically appropriate
selection underneath the mouse. This is consistent with how normal text is treated in pure HTML
views. If some text is already selected, and the mouse is over the existing selection, continue
using the selected text. Otherwise, discard the old selection and select the most appropriate
region under the mouse pointer.

* Shared/API/c/WKActionMenuTypes.h: Add PDF menu option.
* Shared/WebMouseEvent.cpp: Recognize mouse force events as valid mouse events.
* UIProcess/mac/WKActionMenuController.mm:
(-[WKActionMenuController _defaultMenuItemsForPDF]): Add simply copy text option.
(-[WKActionMenuController _defaultMenuItems]): Recognize PDFs and add relevant action
menu entries.
* WebProcess/Plugins/Netscape/NetscapePlugin.h: Provide stub for new method.
* WebProcess/Plugins/PDF/PDFLayerControllerDetails.h: Expose 'rectsForSelectionInLayerSpace',
'rectsForAnnotationInLayoutSpace', 'layout', and 'currentPage'.
* WebProcess/Plugins/PDF/PDFPlugin.h:
* WebProcess/Plugins/PDF/PDFPlugin.mm:
(WebKit::PDFPlugin::getSelectionForWordAtPoint): Added.
(WebKit::PDFPlugin::existingSelectionContainsPoint): Added.
(WebKit::PDFPlugin::lookupTextAtLocation): Added.
* WebProcess/Plugins/Plugin.h: Add declaration for new 'getSelectionForWordAtPoint' method.
* WebProcess/Plugins/PluginProxy.h: Provide stub for new method.
* WebProcess/Plugins/PluginView.cpp:
(WebKit::PluginView::getSelectionForWordAtPoint): Added.
(WebKit::PluginView::existingSelectionContainsPoint): Added.
(WebKit::PluginView::lookupTextAtLocation): Added.
* WebProcess/Plugins/PluginView.h:
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::performActionMenuHitTestAtLocation): Update to support PDF documents and retrieve
relevant content to support later action menu handling.

Tools:
[Mac] Extend action menus to support PDF
https://bugs.webkit.org/show_bug.cgi?id=143895
<rdar://problem/19003333>

Reviewed by Tim Horton.

Reactivate the action menu tests, and add a new PDF-based test to make sure that selection
of PDF content works.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add new 'test.pdf' resource to bundle.
* TestWebKitAPI/Tests/WebKit2/action-menu-targets.html: Update with a new PDF pane.
* TestWebKitAPI/Tests/WebKit2/test.pdf: Added.
* TestWebKitAPI/Tests/WebKit2ObjC/ActionMenus.mm:
(-[ActionMenusTestWKView _actionMenuItemsForHitTestResult:withType:defaultActionMenuItems:userData:]):
Update to support PDF tests.
(TestWebKitAPI::windowPointForTarget): Add new target for PDF test.
(TestWebKitAPI::waitForPDFToLoad): New helper function to avoid starting test before the PDF is available.

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

26 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Configurations/WebCore.xcconfig
Source/WebCore/editing/mac/DictionaryLookup.h
Source/WebCore/editing/mac/DictionaryLookup.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebActionMenuController.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebHitTestResult.h
Source/WebKit2/Shared/WebMouseEvent.cpp
Source/WebKit2/UIProcess/API/C/WKHitTestResult.cpp
Source/WebKit2/UIProcess/API/C/WKHitTestResult.h
Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.h
Source/WebKit2/WebProcess/Plugins/PDF/PDFLayerControllerDetails.h
Source/WebKit2/WebProcess/Plugins/PDF/PDFPlugin.h
Source/WebKit2/WebProcess/Plugins/PDF/PDFPlugin.mm
Source/WebKit2/WebProcess/Plugins/Plugin.h
Source/WebKit2/WebProcess/Plugins/PluginProxy.h
Source/WebKit2/WebProcess/Plugins/PluginView.cpp
Source/WebKit2/WebProcess/Plugins/PluginView.h
Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2/action-menu-target.pdf [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/action-menu-targets.html
Tools/TestWebKitAPI/Tests/WebKit2/test.pdf [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2ObjC/ActionMenus.mm

index 38be525..2ac590e 100644 (file)
@@ -1,3 +1,23 @@
+2015-04-21  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] Extend action menus to support PDF
+        https://bugs.webkit.org/show_bug.cgi?id=143895
+        <rdar://problem/19003333>
+
+        Reviewed by Tim Horton.
+
+        Tested by TestWebKitAPI ActionMenus.mm.
+
+        Add a new dictionary lookup method to support PDF Selections. This code replicates the
+        DOM Range-based logic used for HTML documents, but does so using the PDFKit API and
+        its support types.
+
+        * Configurations/Base.xcconfig: Add PDFKit include path for build.
+        * editing/mac/DictionaryLookup.h:
+        * editing/mac/DictionaryLookup.mm:
+        (WebCore::expandSelectionByCharacters): Helper function for PDF support.
+        (WebCore::dictionaryLookupForPDFSelection): Added.
+
 2015-04-22  Zalan Bujtas  <zalan@apple.com>
 
         Move render ruby initialization logic from RenderElement::createFor() to *::createElementRenderer()
index 3a330c6..1a7f320 100644 (file)
@@ -32,7 +32,7 @@ FRAMEWORK_SEARCH_PATHS_ios_Release = $(FRAMEWORK_SEARCH_PATHS_ios_Debug);
 FRAMEWORK_SEARCH_PATHS_ios_Production = $(PRODUCTION_FRAMEWORKS_DIR);
 FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(STAGED_FRAMEWORKS_SEARCH_PATH) $(FRAMEWORK_SEARCH_PATHS);
 
-OTHER_CFLAGS = $(inherited) -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks;
+OTHER_CFLAGS = $(inherited) -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks -iframework $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks;
 OTHER_CPLUSPLUSFLAGS = $(OTHER_CFLAGS);
 
 STAGED_FRAMEWORKS_SEARCH_PATH = $(STAGED_FRAMEWORKS_SEARCH_PATH_$(USE_STAGING_INSTALL_PATH));
index 01a287d..b345bc9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include <wtf/PassRefPtr.h>
 
 OBJC_CLASS NSDictionary;
+OBJC_CLASS PDFSelection;
 
 namespace WebCore {
 
@@ -47,6 +48,7 @@ bool shouldUseSelection(const VisiblePosition&, const VisibleSelection&);
 PassRefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition&, int numberOfCharactersToExpand);
 WEBCORE_EXPORT PassRefPtr<Range> rangeForDictionaryLookupForSelection(const VisibleSelection&, NSDictionary **options);
 WEBCORE_EXPORT PassRefPtr<Range> rangeForDictionaryLookupAtHitTestResult(const HitTestResult&, NSDictionary **options);
+WEBCORE_EXPORT NSString *dictionaryLookupForPDFSelection(PDFSelection *, NSDictionary **options);
 
 } // namespace WebCore
 
index e47b7fd..f2fe624 100644 (file)
@@ -44,6 +44,7 @@
 #import "VisibleUnits.h"
 #import "WebCoreSystemInterface.h"
 #import "htmlediting.h"
+#import <PDFKit/PDFKit.h>
 #import <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -162,6 +163,54 @@ PassRefPtr<Range> rangeForDictionaryLookupAtHitTestResult(const HitTestResult& h
     return TextIterator::subrange(fullCharacterRange.get(), extractedRange.location, extractedRange.length);
 }
 
+static void expandSelectionByCharacters(PDFSelection *selection, NSInteger numberOfCharactersToExpand, NSInteger& charactersAddedBeforeStart, NSInteger& charactersAddedAfterEnd)
+{
+    size_t originalLength = selection.string.length;
+    [selection extendSelectionAtStart:numberOfCharactersToExpand];
+    
+    charactersAddedBeforeStart = selection.string.length - originalLength;
+    
+    [selection extendSelectionAtEnd:numberOfCharactersToExpand];
+    charactersAddedAfterEnd = selection.string.length - originalLength - charactersAddedBeforeStart;
+}
+
+NSString *dictionaryLookupForPDFSelection(PDFSelection *selection, NSDictionary **options)
+{
+    // Don't do anything if there is no character at the point.
+    if (!selection || !selection.string.length)
+        return @"";
+    
+    RetainPtr<PDFSelection> selectionForLookup = adoptNS([selection copy]);
+    
+    // As context, we are going to use 250 characters of text before and after the point.
+    NSInteger originalLength = [selectionForLookup string].length;
+    NSInteger charactersAddedBeforeStart = 0;
+    NSInteger charactersAddedAfterEnd = 0;
+    expandSelectionByCharacters(selectionForLookup.get(), 250, charactersAddedBeforeStart, charactersAddedAfterEnd);
+    
+    NSString *fullPlainTextString = [selectionForLookup string];
+    NSRange rangeToPass = NSMakeRange(charactersAddedBeforeStart, 0);
+    
+    NSRange extractedRange = NSMakeRange(rangeToPass.location, 0);
+    if (Class luLookupDefinitionModule = getLULookupDefinitionModuleClass())
+        extractedRange = [luLookupDefinitionModule tokenRangeForString:fullPlainTextString range:rangeToPass options:options];
+    
+    // This function sometimes returns {NSNotFound, 0} if it was unable to determine a good string.
+    if (extractedRange.location == NSNotFound)
+        return selection.string;
+    
+    NSInteger lookupAddedBefore = (extractedRange.location < rangeToPass.location) ? rangeToPass.location - extractedRange.location : 0;
+    NSInteger lookupAddedAfter = 0;
+    if ((extractedRange.location + extractedRange.length) > (rangeToPass.location + originalLength))
+        lookupAddedAfter = (extractedRange.location + extractedRange.length) - (rangeToPass.location + originalLength);
+    
+    [selection extendSelectionAtStart:lookupAddedBefore];
+    [selection extendSelectionAtEnd:lookupAddedAfter];
+    
+    ASSERT([selection.string isEqualToString:[fullPlainTextString substringWithRange:extractedRange]]);
+    return selection.string;
+}
+
 } // namespace WebCore
 
 #endif // PLATFORM(MAC)
index 9a2519f..7fb04a3 100644 (file)
@@ -1,3 +1,26 @@
+2015-04-21  Brent Fulgham  <bfulgham@apple.com>
+
+        Extend action menus to support PDF
+        https://bugs.webkit.org/show_bug.cgi?id=143895
+        <rdar://problem/19003333>
+
+        Reviewed by Tim Horton.
+
+        Prevent a crash when someone attempts to invoke an action menu on a PDF hosted
+        in a WK1 view.
+
+        * WebView/WebActionMenuController.mm:
+        (-[WebActionMenuController performHitTestAtPoint:]): Handle WebPDFView as well as
+        the WebHTMLView case.
+        * WebView/WebDocument.h:
+        * WebView/WebHTMLView.h:
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView _frame]):
+        * WebView/WebHTMLViewInternal.h:
+        * WebView/WebPDFView.h:
+        * WebView/WebPDFView.mm:
+        (-[WebPDFView _frame]): Added.
+
 2015-04-22  Eric Carlson  <eric.carlson@apple.com>
 
         Unreviewed post-review clean up after r183096.
index 45fe739..7a3eb81 100644 (file)
 #import "DOMElementInternal.h"
 #import "DOMNodeInternal.h"
 #import "DOMRangeInternal.h"
+#import "WebDataSource.h"
 #import "WebDocumentInternal.h"
 #import "WebElementDictionary.h"
 #import "WebFrameInternal.h"
 #import "WebHTMLView.h"
 #import "WebHTMLViewInternal.h"
+#import "WebPDFView.h"
 #import "WebSystemInterface.h"
 #import "WebUIDelegatePrivate.h"
 #import "WebViewInternal.h"
@@ -94,12 +96,15 @@ using namespace WebCore;
 
 - (WebElementDictionary *)performHitTestAtPoint:(NSPoint)windowPoint
 {
-    WebHTMLView *documentView = [[[_webView _selectedOrMainFrame] frameView] documentView];
-    NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
-
-    Frame* coreFrame = core([documentView _frame]);
+    NSView<WebDocumentView> *documentView = [[[_webView _selectedOrMainFrame] frameView] documentView];
+    if (![documentView isKindOfClass:[WebHTMLView class]])
+        return nil;
+        
+    Frame* coreFrame = core([(WebHTMLView *)documentView _frame]);
     if (!coreFrame)
         return nil;
+
+    NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
     _hitTestResult = coreFrame->eventHandler().hitTestResultAtPoint(IntPoint(point));
 
     return [[[WebElementDictionary alloc] initWithHitTestResult:_hitTestResult] autorelease];
index 19dff01..e9742ef 100644 (file)
@@ -1,3 +1,45 @@
+2015-04-21  Brent Fulgham  <bfulgham@apple.com>
+
+        Extend action menus to support PDF
+        https://bugs.webkit.org/show_bug.cgi?id=143895
+        <rdar://problem/19003333>
+
+        Reviewed by Tim Horton.
+
+        If the mouse pointer is over a PDF, try to provide a relevant action menu for whatever
+        content is under the mouse. For now, we only support copying text and handling URLs.
+
+        If no text is selected, use the dictionary lookup service to find a semantically appropriate
+        selection underneath the mouse. This is consistent with how normal text is treated in pure HTML
+        views. If some text is already selected, and the mouse is over the existing selection, continue
+        using the selected text. Otherwise, discard the old selection and select the most appropriate
+        region under the mouse pointer.
+
+        * Shared/API/c/WKActionMenuTypes.h: Add PDF menu option.
+        * Shared/WebMouseEvent.cpp: Recognize mouse force events as valid mouse events.
+        * UIProcess/mac/WKActionMenuController.mm:
+        (-[WKActionMenuController _defaultMenuItemsForPDF]): Add simply copy text option.
+        (-[WKActionMenuController _defaultMenuItems]): Recognize PDFs and add relevant action
+        menu entries.
+        * WebProcess/Plugins/Netscape/NetscapePlugin.h: Provide stub for new method.
+        * WebProcess/Plugins/PDF/PDFLayerControllerDetails.h: Expose 'rectsForSelectionInLayerSpace',
+        'rectsForAnnotationInLayoutSpace', 'layout', and 'currentPage'.
+        * WebProcess/Plugins/PDF/PDFPlugin.h:
+        * WebProcess/Plugins/PDF/PDFPlugin.mm:
+        (WebKit::PDFPlugin::getSelectionForWordAtPoint): Added.
+        (WebKit::PDFPlugin::existingSelectionContainsPoint): Added.
+        (WebKit::PDFPlugin::lookupTextAtLocation): Added.
+        * WebProcess/Plugins/Plugin.h: Add declaration for new 'getSelectionForWordAtPoint' method.
+        * WebProcess/Plugins/PluginProxy.h: Provide stub for new method.
+        * WebProcess/Plugins/PluginView.cpp:
+        (WebKit::PluginView::getSelectionForWordAtPoint): Added.
+        (WebKit::PluginView::existingSelectionContainsPoint): Added.
+        (WebKit::PluginView::lookupTextAtLocation): Added.
+        * WebProcess/Plugins/PluginView.h:
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::performActionMenuHitTestAtLocation): Update to support PDF documents and retrieve
+        relevant content to support later action menu handling.
+
 2015-04-22  Eric Carlson  <eric.carlson@apple.com>
 
         Update AirPlay sandbox rules
index a8485d9..4c531e8 100644 (file)
@@ -104,6 +104,7 @@ public:
 
     String linkLabel() const { return m_data.linkLabel; }
     String linkTitle() const { return m_data.linkTitle; }
+    String lookupText() const { return m_data.lookupText; }
 
     bool isContentEditable() const { return m_data.isContentEditable; }
 
index 72c63e2..b8ddae2 100644 (file)
@@ -120,7 +120,7 @@ bool WebMouseEvent::decode(IPC::ArgumentDecoder& decoder, WebMouseEvent& result)
 
 bool WebMouseEvent::isMouseEventType(Type type)
 {
-    return type == MouseDown || type == MouseUp || type == MouseMove;
+    return type == MouseDown || type == MouseUp || type == MouseMove || type == MouseForceUp || type == MouseForceDown || type == MouseForceChanged;
 }
     
 } // namespace WebKit
index e746fda..fc1ad72 100644 (file)
@@ -67,6 +67,11 @@ WKStringRef WKHitTestResultCopyLinkTitle(WKHitTestResultRef hitTestResultRef)
     return toCopiedAPI(toImpl(hitTestResultRef)->linkTitle());
 }
 
+WKStringRef WKHitTestResultCopyLookupText(WKHitTestResultRef hitTestResult)
+{
+    return toCopiedAPI(toImpl(hitTestResult)->lookupText());
+}
+
 bool WKHitTestResultIsContentEditable(WKHitTestResultRef hitTestResultRef)
 {
     return toImpl(hitTestResultRef)->isContentEditable();
index f981964..3c70813 100644 (file)
@@ -43,6 +43,7 @@ WK_EXPORT WKURLRef WKHitTestResultCopyAbsoluteMediaURL(WKHitTestResultRef hitTes
 
 WK_EXPORT WKStringRef WKHitTestResultCopyLinkLabel(WKHitTestResultRef hitTestResult);
 WK_EXPORT WKStringRef WKHitTestResultCopyLinkTitle(WKHitTestResultRef hitTestResult);
+WK_EXPORT WKStringRef WKHitTestResultCopyLookupText(WKHitTestResultRef hitTestResult);
 
 WK_EXPORT bool WKHitTestResultIsContentEditable(WKHitTestResultRef hitTestResult);
 
index 2a931fd..7b0164a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <wtf/text/CString.h>
 #include <wtf/text/StringHash.h>
 
+#if PLATFORM(COCOA)
+#include "WebHitTestResult.h"
+#endif
+
 namespace WebCore {
 class MachSendRight;
 class HTTPHeaderMap;
@@ -237,6 +241,7 @@ private:
     void setComplexTextInputEnabled(bool);
 
     void updatePluginLayer();
+    String lookupTextAtLocation(const WebCore::FloatPoint&, WebHitTestResult::Data&, PDFSelection** selection, NSDictionary**) const override { return String(); }
 #endif
 
     virtual void contentsScaleFactorChanged(float) override;
@@ -260,7 +265,9 @@ private:
 
     virtual bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&) override { return false; }
 
-    virtual String getSelectionString() const override { return String(); }
+    String getSelectionString() const override { return String(); }
+    String getSelectionForWordAtPoint(const WebCore::FloatPoint&) const override { return String(); }
+    bool existingSelectionContainsPoint(const WebCore::FloatPoint&) const override { return false; }
 
     virtual void mutedStateChanged(bool) override;
 
index a1d4af7..ca35022 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
 #import <PDFKit/PDFKit.h>
 
 @class CPReadingModel;
+@class PDFViewLayout;
 
 @protocol PDFLayerControllerDelegate <NSObject>
 
 - (void)setSearchSelection:(PDFSelection *)selection;
 - (void)gotoSelection:(PDFSelection *)selection;
 - (PDFSelection *)getSelectionForWordAtPoint:(CGPoint)point;
+- (NSArray *)rectsForSelectionInLayoutSpace:(PDFSelection *)selection;
+- (NSArray *)rectsForAnnotationInLayoutSpace:(PDFAnnotation *)annotation;
+- (PDFViewLayout *)layout;
+- (NSRect)frame;
 
+- (PDFPage *)currentPage;
 - (NSUInteger)lastPageIndex;
 - (NSUInteger)currentPageIndex;
 - (void)gotoNextPage;
index 78d49db..acceaee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 
 #include "Plugin.h"
 #include "WebEvent.h"
+#include "WebHitTestResult.h"
 #include <WebCore/AffineTransform.h>
 #include <WebCore/FindOptions.h>
 #include <WebCore/ScrollableArea.h>
@@ -165,8 +166,11 @@ private:
 
     PDFSelection *nextMatchForString(const String& target, BOOL searchForward, BOOL caseSensitive, BOOL wrapSearch, PDFSelection *initialSelection, BOOL startInSelection);
 
-    virtual bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&) override;
-    virtual String getSelectionString() const override;
+    bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&) override;
+    String getSelectionString() const override;
+    String getSelectionForWordAtPoint(const WebCore::FloatPoint&) const override;
+    bool existingSelectionContainsPoint(const WebCore::FloatPoint&) const override;
+    String lookupTextAtLocation(const WebCore::FloatPoint&, WebHitTestResult::Data&, PDFSelection **, NSDictionary **) const override;
 
     virtual bool shouldAllowScripting() override { return false; }
     virtual bool shouldAllowNavigationFromDrags() override { return true; }
index c0894e9..41350f5 100644 (file)
@@ -56,6 +56,7 @@
 #import <WebCore/ArchiveResource.h>
 #import <WebCore/Chrome.h>
 #import <WebCore/Cursor.h>
+#import <WebCore/DictionaryLookup.h>
 #import <WebCore/DocumentLoader.h>
 #import <WebCore/FocusController.h>
 #import <WebCore/FormState.h>
@@ -392,6 +393,11 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
 
 @end
 
+@interface PDFViewLayout
+- (NSPoint)convertPoint:(NSPoint)point toPage:(PDFPage *)page forScaleFactor:(CGFloat)scaleFactor;
+- (PDFPage *)pageNearestPoint:(NSPoint)point currentPage:(PDFPage *)currentPage;
+@end
+
 static const char* postScriptMIMEType = "application/postscript";
 const uint64_t pdfDocumentRequestID = 1; // PluginController supports loading multiple streams, but we only need one for PDF.
 
@@ -1829,6 +1835,104 @@ String PDFPlugin::getSelectionString() const
     return [[m_pdfLayerController currentSelection] string];
 }
 
+String PDFPlugin::getSelectionForWordAtPoint(const WebCore::FloatPoint& point) const
+{
+    IntPoint pointInView = convertFromPluginToPDFView(convertFromRootViewToPlugin(roundedIntPoint(point)));
+    PDFSelection *selectionForWord = [m_pdfLayerController getSelectionForWordAtPoint:pointInView];
+    [m_pdfLayerController setCurrentSelection:selectionForWord];
+    
+    return [selectionForWord string];
+}
+
+bool PDFPlugin::existingSelectionContainsPoint(const WebCore::FloatPoint& point) const
+{
+    PDFSelection *currentSelection = [m_pdfLayerController currentSelection];
+    if (!currentSelection)
+        return false;
+    
+    IntPoint pointInView = convertFromPluginToPDFView(roundedIntPoint(point));
+    PDFSelection *selectionForWord = [m_pdfLayerController getSelectionForWordAtPoint:pointInView];
+
+    NSUInteger currentPageIndex = [m_pdfLayerController currentPageIndex];
+    
+    NSArray *selectionRects = [m_pdfLayerController rectsForSelectionInLayoutSpace:currentSelection];
+    if (!selectionRects || !selectionRects.count)
+        return false;
+    
+    if (currentPageIndex >= selectionRects.count)
+        currentPageIndex = selectionRects.count - 1;
+
+    NSArray *wordSelectionRects = [m_pdfLayerController rectsForSelectionInLayoutSpace:selectionForWord];
+    if (!wordSelectionRects || !wordSelectionRects.count)
+        return false;
+
+    NSValue *selectionBounds = [selectionRects objectAtIndex:currentPageIndex];
+    NSValue *wordSelectionBounds = [wordSelectionRects objectAtIndex:0];
+
+    NSRect selectionBoundsRect = selectionBounds.rectValue;
+    NSRect wordSelectionBoundsRect = wordSelectionBounds.rectValue;
+    return NSIntersectsRect(wordSelectionBoundsRect, selectionBoundsRect);
+}
+
+static NSPoint pointInLayoutSpaceForPointInWindowSpace(PDFLayerController* pdfLayerController, NSPoint pointInView)
+{
+    CGPoint point = NSPointToCGPoint(pointInView);
+    CGPoint scrollOffset = [pdfLayerController scrollPosition];
+    CGFloat scaleFactor = [pdfLayerController contentScaleFactor];
+
+    scrollOffset.y = [pdfLayerController contentSizeRespectingZoom].height - NSRectToCGRect([pdfLayerController frame]).size.height - scrollOffset.y;
+    
+    CGPoint newPoint = CGPointMake(scrollOffset.x + point.x, scrollOffset.y + point.y);
+    newPoint.x /= scaleFactor;
+    newPoint.y /= scaleFactor;
+    return NSPointFromCGPoint(newPoint);
+}
+
+String PDFPlugin::lookupTextAtLocation(const WebCore::FloatPoint& locationInViewCoordinates, WebHitTestResult::Data& data, PDFSelection **selectionPtr, NSDictionary **options) const
+{
+    PDFSelection*& selection = *selectionPtr;
+
+    selection = [m_pdfLayerController currentSelection];
+    if (existingSelectionContainsPoint(locationInViewCoordinates))
+        return [selection string];
+        
+    IntPoint pointInView = convertFromPluginToPDFView(roundedIntPoint(locationInViewCoordinates));
+    selection = [m_pdfLayerController getSelectionForWordAtPoint:pointInView];
+    if (!selection)
+        return @"";
+
+    NSPoint pointInLayoutSpace = pointInLayoutSpaceForPointInWindowSpace(m_pdfLayerController.get(), pointInView);
+
+    PDFPage *currentPage = [[m_pdfLayerController layout] pageNearestPoint:pointInLayoutSpace currentPage:[m_pdfLayerController currentPage]];
+    
+    NSPoint pointInPageSpace = [[m_pdfLayerController layout] convertPoint:pointInLayoutSpace toPage:currentPage forScaleFactor:1.0];
+    
+    for (PDFAnnotation *annotation in [currentPage annotations]) {
+        if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
+            continue;
+    
+        NSRect bounds = [annotation bounds];
+        if (!NSPointInRect(pointInPageSpace, bounds))
+            continue;
+        
+        PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
+        NSURL *url = [linkAnnotation URL];
+        if (!url)
+            continue;
+        
+        data.absoluteLinkURL = [url absoluteString];
+        data.linkLabel = [selection string];
+        return [selection string];
+    }
+    
+    NSString *lookupText = dictionaryLookupForPDFSelection(selection, options);
+    if (!lookupText || !lookupText.length)
+        return @"";
+
+    [m_pdfLayerController setCurrentSelection:selection];
+    return lookupText;
+}
+
 void PDFPlugin::performWebSearch(NSString *string)
 {
     webFrame()->page()->send(Messages::WebPageProxy::SearchTheWeb(string));
index b8f518b..c89fcb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if PLATFORM(COCOA)
 #include "LayerHostingContext.h"
+#include "WebHitTestResult.h"
 
+OBJC_CLASS NSDictionary;
 OBJC_CLASS NSObject;
 OBJC_CLASS PDFDocument;
+OBJC_CLASS PDFSelection;
 #endif
 
 struct NPObject;
@@ -277,7 +280,12 @@ public:
     virtual bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&) = 0;
 
     virtual String getSelectionString() const = 0;
-    
+    virtual String getSelectionForWordAtPoint(const WebCore::FloatPoint&) const = 0;
+    virtual bool existingSelectionContainsPoint(const WebCore::FloatPoint&) const = 0;
+#if PLATFORM(COCOA)
+    virtual String lookupTextAtLocation(const WebCore::FloatPoint&, WebHitTestResult::Data&, PDFSelection**, NSDictionary**) const = 0;
+#endif
+
     virtual WebCore::AudioHardwareActivityType audioHardwareActivity() const { return WebCore::AudioHardwareActivityType::Unknown; }
 
     virtual void mutedStateChanged(bool) { }
index 0bd886f..4d57a95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,6 +38,7 @@
 #include <memory>
 
 #if PLATFORM(COCOA)
+#include "WebHitTestResult.h"
 #include <wtf/RetainPtr.h>
 OBJC_CLASS CALayer;
 #endif
@@ -122,6 +123,7 @@ private:
     virtual uint64_t pluginComplexTextInputIdentifier() const override;
     virtual void sendComplexTextInput(const String& textInput) override;
     virtual void setLayerHostingMode(LayerHostingMode) override;
+    String lookupTextAtLocation(const WebCore::FloatPoint&, WebHitTestResult::Data&, PDFSelection**, NSDictionary**) const override { return String(); }
 #endif
 
     virtual void contentsScaleFactorChanged(float) override;
@@ -141,7 +143,9 @@ private:
     virtual PassRefPtr<WebCore::SharedBuffer> liveResourceData() const override;
     virtual bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&) override { return false; }
 
-    virtual String getSelectionString() const override { return String(); }
+    String getSelectionString() const override { return String(); }
+    String getSelectionForWordAtPoint(const WebCore::FloatPoint&) const override { return String(); }
+    bool existingSelectionContainsPoint(const WebCore::FloatPoint&) const override { return false; }
 
 #if PLATFORM(COCOA)
     virtual WebCore::AudioHardwareActivityType audioHardwareActivity() const override;
index c9a6642..8db8e9f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -993,6 +993,32 @@ bool PluginView::performDictionaryLookupAtLocation(const WebCore::FloatPoint& po
     return m_plugin->performDictionaryLookupAtLocation(point);
 }
 
+String PluginView::getSelectionForWordAtPoint(const WebCore::FloatPoint& point) const
+{
+    if (!m_isInitialized || !m_plugin)
+        return String();
+    
+    return m_plugin->getSelectionForWordAtPoint(point);
+}
+
+bool PluginView::existingSelectionContainsPoint(const WebCore::FloatPoint& point) const
+{
+    if (!m_isInitialized || !m_plugin)
+        return false;
+    
+    return m_plugin->existingSelectionContainsPoint(point);
+}
+
+#if PLATFORM(COCOA)
+String PluginView::lookupTextAtLocation(const WebCore::FloatPoint& point, WebHitTestResult::Data& data, PDFSelection **selection, NSDictionary **options) const
+{
+    if (!m_isInitialized || !m_plugin)
+        return String();
+
+    return m_plugin->lookupTextAtLocation(point, data, selection, options);
+}
+#endif
+
 void PluginView::notifyWidget(WidgetNotification notification)
 {
     switch (notification) {
index 9a6b88f..6d4348c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 // FIXME: Eventually this should move to WebCore.
 
+#if PLATFORM(COCOA)
+#include "WebHitTestResult.h"
+
+OBJC_CLASS NSDictionary;
+OBJC_CLASS PDFSelection;
+#endif
+
 namespace WebCore {
 class Frame;
 class HTMLPlugInElement;
@@ -82,6 +89,7 @@ public:
     bool sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput);
     RetainPtr<PDFDocument> pdfDocumentForPrinting() const { return m_plugin->pdfDocumentForPrinting(); }
     NSObject *accessibilityObject() const;
+    String lookupTextAtLocation(const WebCore::FloatPoint&, WebHitTestResult::Data&, PDFSelection**, NSDictionary**) const;
 #endif
 
     WebCore::HTMLPlugInElement* pluginElement() const { return m_pluginElement.get(); }
@@ -111,6 +119,8 @@ public:
 
     PassRefPtr<WebCore::SharedBuffer> liveResourceData() const;
     bool performDictionaryLookupAtLocation(const WebCore::FloatPoint&);
+    String getSelectionForWordAtPoint(const WebCore::FloatPoint&) const;
+    bool existingSelectionContainsPoint(const WebCore::FloatPoint&) const;
     virtual WebCore::AudioHardwareActivityType audioHardwareActivity() const override;
 
 private:
index 1ba52c3..e40a073 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,6 +65,7 @@
 #import <WebCore/FrameView.h>
 #import <WebCore/GraphicsContext.h>
 #import <WebCore/HTMLConverter.h>
+#import <WebCore/HTMLPluginImageElement.h>
 #import <WebCore/HitTestResult.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/MIMETypeRegistry.h>
@@ -1100,6 +1101,30 @@ void WebPage::performActionMenuHitTestAtLocation(WebCore::FloatPoint locationInV
         }
     }
 
+#if ENABLE(PDFKIT_PLUGIN)
+    // See if we have a PDF
+    if (element && is<HTMLPlugInImageElement>(*element)) {
+        HTMLPlugInImageElement& pluginImageElement = downcast<HTMLPlugInImageElement>(*element);
+        if (PluginView* pluginView = reinterpret_cast<PluginView*>(pluginImageElement.pluginWidget())) {
+            // FIXME: We don't have API to identify images inside PDFs based on position.
+            NSDictionary *options = nil;
+            PDFSelection *selection = nil;
+            String selectedText = pluginView->lookupTextAtLocation(locationInContentCoordinates, actionMenuResult, &selection, &options);
+            if (!selectedText.isEmpty()) {
+                if (element->document().isPluginDocument()) {
+                    // FIXME(144030): Focus does not seem to get set to the PDF when invoking the menu.
+                    PluginDocument& pluginDocument = static_cast<PluginDocument&>(element->document());
+                    pluginDocument.setFocusedElement(element);
+                }
+
+                actionMenuResult.lookupText = selectedText;
+                actionMenuResult.isSelected = true;
+                actionMenuResult.allowsCopy = true;
+            }
+        }
+    }
+#endif
+
     RefPtr<API::Object> userData;
     injectedBundleContextMenuClient().prepareForActionMenu(*this, hitTestResult, userData);
 
index d1e36ca..4c3a0ee 100644 (file)
@@ -1,3 +1,23 @@
+2015-04-21  Brent Fulgham  <bfulgham@apple.com>
+
+        [Mac] Extend action menus to support PDF
+        https://bugs.webkit.org/show_bug.cgi?id=143895
+        <rdar://problem/19003333>
+
+        Reviewed by Tim Horton.
+
+        Reactivate the action menu tests, and add a new PDF-based test to make sure that selection
+        of PDF content works.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add new 'test.pdf' resource to bundle.
+        * TestWebKitAPI/Tests/WebKit2/action-menu-targets.html: Update with a new PDF pane.
+        * TestWebKitAPI/Tests/WebKit2/test.pdf: Added.
+        * TestWebKitAPI/Tests/WebKit2ObjC/ActionMenus.mm:
+        (-[ActionMenusTestWKView _actionMenuItemsForHitTestResult:withType:defaultActionMenuItems:userData:]):
+        Update to support PDF tests.
+        (TestWebKitAPI::windowPointForTarget): Add new target for PDF test.
+        (TestWebKitAPI::waitForPDFToLoad): New helper function to avoid starting test before the PDF is available.
+
 2015-04-22  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Do not run GTK+ user media unit tests when ENABLE_MEDIA_STREAM is disabled.
index 20dd81a..5928dd7 100644 (file)
@@ -63,6 +63,8 @@
                7A99D9941AD4A29D00373141 /* MenuTypesForMouseEvents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */; };
                7AA021BB1AB09EA70052953F /* DateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA021BA1AB09EA70052953F /* DateMath.cpp */; };
                7AA6A1521AAC0B31002B2ED3 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA6A1511AAC0B31002B2ED3 /* WorkQueue.cpp */; };
+               7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7AE9E5081AE5AE8B00CF874B /* test.pdf */; };
+               7AE9E50B1AE5F97000CF874B /* action-menu-target.pdf in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7AE9E50A1AE5F91300CF874B /* action-menu-target.pdf */; };
                7C486BA11AA12567003F6F9B /* bundle-file.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7C486BA01AA1254B003F6F9B /* bundle-file.html */; };
                7C54A4BE1AA11CCA00380F78 /* WKBundleFileHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C54A4BC1AA11CCA00380F78 /* WKBundleFileHandle.cpp */; };
                7C54A4C11AA11CE400380F78 /* WKBundleFileHandle_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C54A4BF1AA11CE400380F78 /* WKBundleFileHandle_Bundle.cpp */; };
                        dstPath = TestWebKitAPI.resources;
                        dstSubfolderSpec = 7;
                        files = (
+                               7AE9E50B1AE5F97000CF874B /* action-menu-target.pdf in Copy Resources */,
+                               7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */,
                                7A1458FC1AD5C07000E06772 /* mouse-button-listener.html in Copy Resources */,
                                7C486BA11AA12567003F6F9B /* bundle-file.html in Copy Resources */,
                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
                7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MenuTypesForMouseEvents.mm; sourceTree = "<group>"; };
                7AA021BA1AB09EA70052953F /* DateMath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateMath.cpp; sourceTree = "<group>"; };
                7AA6A1511AAC0B31002B2ED3 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
+               7AE9E5081AE5AE8B00CF874B /* test.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test.pdf; sourceTree = "<group>"; };
+               7AE9E50A1AE5F91300CF874B /* action-menu-target.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "action-menu-target.pdf"; sourceTree = "<group>"; };
                7C486BA01AA1254B003F6F9B /* bundle-file.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "bundle-file.html"; sourceTree = "<group>"; };
                7C54A4BC1AA11CCA00380F78 /* WKBundleFileHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKBundleFileHandle.cpp; sourceTree = "<group>"; };
                7C54A4BF1AA11CE400380F78 /* WKBundleFileHandle_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKBundleFileHandle_Bundle.cpp; sourceTree = "<group>"; };
                BC90977B125571AE00083756 /* Resources */ = {
                        isa = PBXGroup;
                        children = (
+                               7AE9E50A1AE5F91300CF874B /* action-menu-target.pdf */,
+                               7AE9E5081AE5AE8B00CF874B /* test.pdf */,
                                7A1458FB1AD5C03500E06772 /* mouse-button-listener.html */,
                                C045F9461385C2F800C0F3CD /* 18-characters.html */,
                                2D950FBF1A230C1E00012434 /* action-menu-targets.html */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/action-menu-target.pdf b/Tools/TestWebKitAPI/Tests/WebKit2/action-menu-target.pdf
new file mode 100644 (file)
index 0000000..a5f457f
Binary files /dev/null and b/Tools/TestWebKitAPI/Tests/WebKit2/action-menu-target.pdf differ
index d4182de..80b02c8 100644 (file)
@@ -5,6 +5,14 @@ div {
     overflow: hidden;
     border: 1px solid black;
 }
+
+embed {
+    position: absolute;
+    width: 100%; height: 100%;
+    overflow: hidden;
+    padding: 0;
+    margin: 0;
+}
 </style>
 
 <script>
@@ -102,6 +110,8 @@ function isVideoReady()
 <div style="top: 250px; left: 0px;"><img src="icon.png" height="100%"></div><br/>
 <div style="top: 250px; left: 200px;"><a href="http://example.org/"><img src="icon.png" height="100%"></a></div><br/>
 
+<div style="top: 250px; left: 400px; height: 350px"><embed src="test.pdf"></embed></div><br/>
+
 <div style="top: 300px; left: 0px; width: 95px;"><a href="http://example.org/">http</a></div><br/>
 <div style="top: 300px; left: 100px; width: 95px;"><a href="ftp://example.org/">ftp</a></div><br/>
 <div style="top: 300px; left: 200px; width: 95px;"><a href="mailto:example@example.org">mailto link</a></div><br/>
@@ -110,5 +120,4 @@ function isVideoReady()
 <div style="top: 350px; left: 0px;"><video src="test.mp4"></video></div><br/>
 <div style="top: 350px; left: 200px;"><video id="mse-video"></video></div><br/>
 
-
 <div style="top: 0px; left: 750px; height: 600px;">data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text data detectors menu text </div><br/>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/test.pdf b/Tools/TestWebKitAPI/Tests/WebKit2/test.pdf
new file mode 100644 (file)
index 0000000..8bc77c1
Binary files /dev/null and b/Tools/TestWebKitAPI/Tests/WebKit2/test.pdf differ
index 4a84d3b..897ab20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -82,6 +82,9 @@ struct ActionMenuResult {
     if (type != kWKActionMenuNone)
         EXPECT_GT(defaultMenuItems.count, (NSUInteger)0);
 
+    if (!hitTestResult)
+        return defaultMenuItems;
+
     // Clients should be able to pass userData from the Web to UI process, between
     // the WKBundlePageContextMenuClient's prepareForActionMenu, and here.
     // http://trac.webkit.org/changeset/175444
@@ -363,6 +366,8 @@ enum class TargetType {
     PageWhitespace,
     Video,
     MSEVideo,
+    PDFEmbed,
+    PDFDocument
 };
 
 static NSPoint windowPointForTarget(TargetType target)
@@ -432,15 +437,29 @@ static NSPoint windowPointForTarget(TargetType target)
     case TargetType::MSEVideo:
         contentPoint = NSMakePoint(200, 350);
         break;
+    case TargetType::PDFEmbed:
+        contentPoint = NSMakePoint(410, 420);
+        break;
+    case TargetType::PDFDocument:
+        contentPoint = NSMakePoint(141, 374);
+        break;
     }
 
     return NSMakePoint(contentPoint.x + 8, 600 - contentPoint.y - 8);
 }
 
+static void waitForPDFToLoad(ActionMenusTestWKView* wkView)
+{
+    __block bool pdfSeemsLoaded = false;
+    [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::PDFEmbed) preDidCloseMenuHandler:^() {
+        pdfSeemsLoaded = kWKActionMenuReadOnlyText == [wkView _actionMenuResult].type;
+    }];
+    Util::run(&didFinishLoad);
+}
+
 // FIXME: Ideally, each of these would be able to run as its own subtest in a suite, sharing a WKView (for performance reasons),
 // but we cannot because run-api-tests explicitly runs each test in a separate process. So, we use a single test for many tests instead.
-// FIXME: Temporarily disabled.
-TEST(WebKit2, DISABLED_ActionMenusTest)
+TEST(WebKit2, ActionMenusTest)
 {
     WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("ActionMenusTest"));
 
@@ -452,7 +471,7 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
     PlatformWebView platformWebView(context.get(), pageGroup.get(), [ActionMenusTestWKView class]);
     RetainPtr<ActionMenusTestWKView> wkView = (ActionMenusTestWKView *)platformWebView.platformView();
 
-    if (![wkView respondsToSelector:@selector(setActionMenu:)])
+    if (![wkView respondsToSelector:@selector(_setActionMenu:)])
         return;
 
     WKPageLoaderClientV0 loaderClient;
@@ -476,6 +495,11 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
 
     Util::run(&didFinishLoad);
 
+    waitForVideoReady([wkView pageRef]);
+
+    // PDF embeds should have selectable/copyable text.
+    waitForPDFToLoad(wkView.get());
+
     // Read-only text.
     [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::Word) preDidCloseMenuHandler:^() {
         EXPECT_EQ(kWKActionMenuReadOnlyText, [wkView _actionMenuResult].type);
@@ -494,18 +518,14 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
 
     // Read-only text, on an address.
     [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::Address) preDidCloseMenuHandler:^() {
-        EXPECT_EQ(kWKActionMenuDataDetectedItem, [wkView _actionMenuResult].type);
-
-        // Addresses don't get selected, because they immediately show a TextIndicator.
-        EXPECT_WK_STREQ(@"<no selection>", retrieveSelection([wkView pageRef]));
+        EXPECT_EQ(kWKActionMenuReadOnlyText, [wkView _actionMenuResult].type);
+        EXPECT_WK_STREQ(@"1 Infinite Loop, Cupertino, CA 95014", retrieveSelection([wkView pageRef]));
     }];
 
     // Read-only text, on a date.
     [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::Date) preDidCloseMenuHandler:^() {
-        EXPECT_EQ(kWKActionMenuDataDetectedItem, [wkView _actionMenuResult].type);
-
-        // Dates don't get selected, because they immediately show a TextIndicator.
-        EXPECT_WK_STREQ(@"<no selection>", retrieveSelection([wkView pageRef]));
+        EXPECT_EQ(kWKActionMenuReadOnlyText, [wkView _actionMenuResult].type);
+        EXPECT_WK_STREQ(@"May 17th, 2012", retrieveSelection([wkView pageRef]));
     }];
 
     // Read-only text, on a phone number.
@@ -662,8 +682,6 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
         EXPECT_EQ(kWKActionMenuLink, [wkView _actionMenuResult].type);
     }];
 
-    waitForVideoReady([wkView pageRef]);
-
     // Copy a video URL.
     [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::Video) preDidCloseMenuHandler:^() {
         EXPECT_EQ(kWKActionMenuVideo, [wkView _actionMenuResult].type);
@@ -716,6 +734,14 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
         EXPECT_FALSE(callJavaScriptReturningBool([wkView pageRef], "wasFailCalled()"));
     }];
 
+    // PDF text content
+    [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::PDFEmbed) preDidCloseMenuHandler:^() {
+        EXPECT_EQ(kWKActionMenuReadOnlyText, [wkView _actionMenuResult].type);
+        EXPECT_WK_STREQ("Test", WKHitTestResultCopyLookupText([wkView _actionMenuResult].hitTestResult.get()));
+
+        // FIXME(14408): You cannot copy from PDFs hosted in <embed> tags. When this is fixed, we should test it works here.
+    }];
+
     // Clients should be able to customize the menu by overriding WKView's _actionMenuItemsForHitTestResult.
     // http://trac.webkit.org/changeset/174908
     RetainPtr<NSMenuItem> item = adoptNS([[NSMenuItem alloc] initWithTitle:@"Some Action" action:@selector(copy:) keyEquivalent:@""]);
@@ -740,6 +766,42 @@ TEST(WebKit2, DISABLED_ActionMenusTest)
     }];
 }
 
+TEST(WebKit2, ActionMenusPDFTest)
+{
+    WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("ActionMenusTest"));
+    
+    WKRetainPtr<WKPageGroupRef> pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(Util::toWK("ActionMenusPDFTestGroup").get()));
+    WKPreferencesRef preferences = WKPageGroupGetPreferences(pageGroup.get());
+    WKPreferencesSetMediaSourceEnabled(preferences, true);
+    WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
+    
+    PlatformWebView platformWebView(context.get(), pageGroup.get(), [ActionMenusTestWKView class]);
+    RetainPtr<ActionMenusTestWKView> wkView = (ActionMenusTestWKView *)platformWebView.platformView();
+    
+    if (![wkView respondsToSelector:@selector(_setActionMenu:)])
+        return;
+    
+    WKPageLoaderClientV0 loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+    loaderClient.base.version = 0;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrameCallback;
+    WKPageSetPageLoaderClient([wkView pageRef], &loaderClient.base);
+    
+    ActiveDownloadContext activeDownloadContext;
+    
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("action-menu-target", "pdf"));
+    WKPageLoadURL([wkView pageRef], url.get());
+    
+    Util::run(&didFinishLoad);
+
+    [wkView runMenuSequenceAtPoint:windowPointForTarget(TargetType::PDFDocument) preDidCloseMenuHandler:^() {
+        EXPECT_EQ(kWKActionMenuReadOnlyText, [wkView _actionMenuResult].type);
+        EXPECT_WK_STREQ("Happiness", WKHitTestResultCopyLookupText([wkView _actionMenuResult].hitTestResult.get()));
+        performMenuItemAtIndexOfTypeAsync([wkView _actionMenu], 0, kWKContextActionItemTagCopyText);
+        EXPECT_WK_STREQ(@"Happiness", watchPasteboardForString());
+    }];
+}
+
 } // namespace TestWebKitAPI
 
 #endif