AX: PDF plugin needs to support PDF-DOM Mode
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Apr 2017 16:26:21 +0000 (16:26 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Apr 2017 16:26:21 +0000 (16:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170589

Reviewed by Tim Horton.

Source/WebCore:

Provide WebCore support for accessibility connect to PDF document.
This includes the ability to connect a PDF annotation created node within WebKit to
 its PDFAnnotation parent (through use of shadowPluginParent).

* accessibility/AXObjectCache.h:
* accessibility/mac/AXObjectCacheMac.mm:
(WebCore::AXPostNotificationWithUserInfo):
* accessibility/mac/WebAccessibilityObjectWrapperMac.h:
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper shadowPluginParent]):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
* html/HTMLAttributeNames.in:
* plugins/PluginViewBase.h:
(WebCore::PluginViewBase::accessibilityShadowPluginParentForElement):

Source/WebKit2:

Provide access to DOM objects with PDF document. This mean:
   1) Support a different set of attributes for WKPDFPluginAccessibilityObject.
        WKPDFPluginAccessibilityObject is now a group instead of forwarding attribute calls to the pdf layer.
   2) Connect the focused UI element to the active annotation if possible.
   3) Mark the PDF associated nodes with an attribute so they can be identified later so their correct parent can be found.

* WebProcess/Plugins/PDF/PDFLayerControllerSPI.h:
* WebProcess/Plugins/PDF/PDFPlugin.h:
* WebProcess/Plugins/PDF/PDFPlugin.mm:
(-[WKPDFPluginAccessibilityObject pdfLayerController]):
(-[WKPDFPluginAccessibilityObject setPdfLayerController:]):
(-[WKPDFPluginAccessibilityObject convertRectToScreenSpace:]):
(-[WKPDFPluginAccessibilityObject accessibilityAttributeValue:]):
(-[WKPDFPluginAccessibilityObject accessibilityAttributeNames]):
(-[WKPDFPluginAccessibilityObject accessibilityActionNames]):
(-[WKPDFPluginAccessibilityObject accessibilityParameterizedAttributeNames]):
(-[WKPDFPluginAccessibilityObject accessibilityFocusedUIElement]):
(-[WKPDFPluginAccessibilityObject accessibilityAssociatedControlForAnnotation:]):
(-[WKPDFPluginAccessibilityObject accessibilityHitTest:]):
(WebKit::PDFPlugin::convertFromRootViewToPDFView):
(WebKit::PDFPlugin::convertFromPDFViewToScreen):
(WebKit::PDFPlugin::pluginHandlesContentOffsetForAccessibilityHitTest):
(WebKit::PDFPlugin::axObjectCache):
(WebKit::PDFPlugin::accessibilityShadowPluginParentForElement):
* WebProcess/Plugins/PDF/PDFPluginAnnotation.mm:
(WebKit::PDFPluginAnnotation::attach):
* WebProcess/Plugins/Plugin.h:
(WebKit::Plugin::accessibilityShadowPluginParentForElement):
(WebKit::Plugin::pluginHandlesContentOffsetForAccessibilityHitTest):
* WebProcess/Plugins/PluginView.cpp:
(WebKit::PluginView::accessibilityShadowPluginParentForElement):
* WebProcess/Plugins/PluginView.h:
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/mac/WKAccessibilityWebPageObjectMac.mm:
(-[WKAccessibilityWebPageObject accessibilityHitTest:]):

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

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AXObjectCache.h
Source/WebCore/accessibility/mac/AXObjectCacheMac.mm
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.h
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Source/WebCore/html/HTMLAttributeNames.in
Source/WebCore/plugins/PluginViewBase.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/Plugins/PDF/PDFLayerControllerSPI.h
Source/WebKit2/WebProcess/Plugins/PDF/PDFPlugin.h
Source/WebKit2/WebProcess/Plugins/PDF/PDFPlugin.mm
Source/WebKit2/WebProcess/Plugins/PDF/PDFPluginAnnotation.mm
Source/WebKit2/WebProcess/Plugins/Plugin.h
Source/WebKit2/WebProcess/Plugins/PluginView.cpp
Source/WebKit2/WebProcess/Plugins/PluginView.h
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/mac/WKAccessibilityWebPageObjectMac.mm

index f9ddfd8..bce9f47 100644 (file)
@@ -1,3 +1,25 @@
+2017-04-11  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: PDF plugin needs to support PDF-DOM Mode
+        https://bugs.webkit.org/show_bug.cgi?id=170589
+
+        Reviewed by Tim Horton.
+
+        Provide WebCore support for accessibility connect to PDF document.
+        This includes the ability to connect a PDF annotation created node within WebKit to 
+         its PDFAnnotation parent (through use of shadowPluginParent).
+
+        * accessibility/AXObjectCache.h:
+        * accessibility/mac/AXObjectCacheMac.mm:
+        (WebCore::AXPostNotificationWithUserInfo):
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.h:
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (-[WebAccessibilityObjectWrapper shadowPluginParent]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+        * html/HTMLAttributeNames.in:
+        * plugins/PluginViewBase.h:
+        (WebCore::PluginViewBase::accessibilityShadowPluginParentForElement):
+
 2017-04-11  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         REGRESSION(r215153): Request Animation Frame broken when building without REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR
index a3664d0..fb1e691 100644 (file)
@@ -143,7 +143,7 @@ public:
     // For AX objects with elements that back them.
     AccessibilityObject* getOrCreate(RenderObject*);
     AccessibilityObject* getOrCreate(Widget*);
-    AccessibilityObject* getOrCreate(Node*);
+    WEBCORE_EXPORT AccessibilityObject* getOrCreate(Node*);
 
     // used for objects without backing elements
     AccessibilityObject* getOrCreate(AccessibilityRole);
index 9bc6eb1..cbafb80 100644 (file)
@@ -250,8 +250,11 @@ void AXObjectCache::setShouldRepostNotificationsForTests(bool value)
     axShouldRepostNotificationsForTests = value;
 }
 
-static void AXPostNotificationWithUserInfo(id object, NSString *notification, id userInfo)
+static void AXPostNotificationWithUserInfo(AccessibilityObjectWrapper *object, NSString *notification, id userInfo)
 {
+    if (id associatedPluginParent = [object associatedPluginParent])
+        object = associatedPluginParent;
+    
     NSAccessibilityPostNotificationWithUserInfo(object, notification, userInfo);
     // To simplify monitoring for notifications in tests, repost as a simple NSNotification instead of forcing test infrastucture to setup an IPC client and do all the translation between WebCore types and platform specific IPC types and back
     if (UNLIKELY(axShouldRepostNotificationsForTests))
index a00e8d1..2decdd0 100644 (file)
@@ -35,4 +35,7 @@
 - (id)textMarkerRangeFromVisiblePositions:(const WebCore::VisiblePosition&)startPosition endPosition:(const WebCore::VisiblePosition&)endPosition;
 - (id)textMarkerForVisiblePosition:(const WebCore::VisiblePosition&)visiblePos;
 
+// When a plugin uses a WebKit control to act as a surrogate view (e.g. PDF use WebKit to create text fields).
+- (id)associatedPluginParent;
+
 @end
index c43d8f3..b80b66a 100644 (file)
@@ -63,6 +63,8 @@
 #import "LocalizedStrings.h"
 #import "MainFrame.h"
 #import "Page.h"
+#import "PluginDocument.h"
+#import "PluginViewBase.h"
 #import "RenderTextControl.h"
 #import "RenderView.h"
 #import "RenderWidget.h"
@@ -1682,6 +1684,21 @@ static NSMutableArray *convertStringsToNSArray(const Vector<String>& vector)
     return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
 }
 
+- (id)associatedPluginParent
+{
+    if (!m_object || !m_object->hasAttribute(x_apple_pdf_annotationAttr))
+        return nil;
+    
+    if (!m_object->document()->isPluginDocument())
+        return nil;
+        
+    Widget* pluginWidget = static_cast<PluginDocument*>(m_object->document())->pluginWidget();
+    if (!pluginWidget || !pluginWidget->isPluginViewBase())
+        return nil;
+
+    return static_cast<PluginViewBase*>(pluginWidget)->accessibilityAssociatedPluginParentForElement(m_object->element());
+}
+
 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
 {
     FrameView* frameView = m_object->documentFrameView();
@@ -3083,6 +3100,10 @@ static NSString* roleValueToNSString(AccessibilityRole value)
         return convertStringsToNSArray(classList);
     }
     
+    // This allows us to connect to a plugin that creates a shadow node for editing (like PDFs).
+    if ([attributeName isEqualToString:@"_AXAssociatedPluginParent"])
+        return [self associatedPluginParent];
+    
     // this is used only by DumpRenderTree for testing
     if ([attributeName isEqualToString:@"AXClickPoint"])
         return [NSValue valueWithPoint:m_object->clickPoint()];
index 88f1a43..f554513 100644 (file)
@@ -392,3 +392,5 @@ x-itunes-inherit-uri-query-component
 x-apple-data-detectors
 x-apple-data-detectors-type
 x-apple-data-detectors-result
+
+x-apple-pdf-annotation
index 5d8e321..5f0db8a 100644 (file)
 #include "Widget.h"
 #include <wtf/text/WTFString.h>
 
+#if PLATFORM(COCOA)
+typedef struct objc_object* id;
+#endif
+
 namespace JSC {
     class ExecState;
     class JSGlobalObject;
@@ -83,6 +87,10 @@ public:
     
     virtual void willDetatchRenderer() { }
 
+#if PLATFORM(COCOA)
+    virtual id accessibilityAssociatedPluginParentForElement(Element*) const { return nullptr; }
+#endif
+    
 protected:
     explicit PluginViewBase(PlatformWidget widget = 0) : Widget(widget) { }
 };
index 57a7726..d53ae06 100644 (file)
@@ -1,3 +1,46 @@
+2017-04-11  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: PDF plugin needs to support PDF-DOM Mode
+        https://bugs.webkit.org/show_bug.cgi?id=170589
+
+        Reviewed by Tim Horton.
+
+        Provide access to DOM objects with PDF document. This mean:
+           1) Support a different set of attributes for WKPDFPluginAccessibilityObject.
+                WKPDFPluginAccessibilityObject is now a group instead of forwarding attribute calls to the pdf layer.
+           2) Connect the focused UI element to the active annotation if possible.
+           3) Mark the PDF associated nodes with an attribute so they can be identified later so their correct parent can be found.
+
+        * WebProcess/Plugins/PDF/PDFLayerControllerSPI.h:
+        * WebProcess/Plugins/PDF/PDFPlugin.h:
+        * WebProcess/Plugins/PDF/PDFPlugin.mm:
+        (-[WKPDFPluginAccessibilityObject pdfLayerController]):
+        (-[WKPDFPluginAccessibilityObject setPdfLayerController:]):
+        (-[WKPDFPluginAccessibilityObject convertRectToScreenSpace:]):
+        (-[WKPDFPluginAccessibilityObject accessibilityAttributeValue:]):
+        (-[WKPDFPluginAccessibilityObject accessibilityAttributeNames]):
+        (-[WKPDFPluginAccessibilityObject accessibilityActionNames]):
+        (-[WKPDFPluginAccessibilityObject accessibilityParameterizedAttributeNames]):
+        (-[WKPDFPluginAccessibilityObject accessibilityFocusedUIElement]):
+        (-[WKPDFPluginAccessibilityObject accessibilityAssociatedControlForAnnotation:]):
+        (-[WKPDFPluginAccessibilityObject accessibilityHitTest:]):
+        (WebKit::PDFPlugin::convertFromRootViewToPDFView):
+        (WebKit::PDFPlugin::convertFromPDFViewToScreen):
+        (WebKit::PDFPlugin::pluginHandlesContentOffsetForAccessibilityHitTest):
+        (WebKit::PDFPlugin::axObjectCache):
+        (WebKit::PDFPlugin::accessibilityShadowPluginParentForElement):
+        * WebProcess/Plugins/PDF/PDFPluginAnnotation.mm:
+        (WebKit::PDFPluginAnnotation::attach):
+        * WebProcess/Plugins/Plugin.h:
+        (WebKit::Plugin::accessibilityShadowPluginParentForElement):
+        (WebKit::Plugin::pluginHandlesContentOffsetForAccessibilityHitTest):
+        * WebProcess/Plugins/PluginView.cpp:
+        (WebKit::PluginView::accessibilityShadowPluginParentForElement):
+        * WebProcess/Plugins/PluginView.h:
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/mac/WKAccessibilityWebPageObjectMac.mm:
+        (-[WKAccessibilityWebPageObject accessibilityHitTest:]):
+
 2017-04-11  Adrian Perez de Castro  <aperez@igalia.com>
 
         [GTK] Attach popup menu to web view widget
index 610bc68..35b6b48 100644 (file)
@@ -158,8 +158,19 @@ typedef NS_ENUM(NSInteger, PDFLayerControllerCursorType) {
 - (NSValue *)accessibilityRangeForLineAttributeForParameter:(id)parameter;
 - (NSString *)accessibilityStringForRangeAttributeForParameter:(id)parameter;
 - (NSValue *)accessibilityBoundsForRangeAttributeForParameter:(id)parameter;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+- (NSArray *)accessibilityChildren;
+- (void)setAccessibilityParent:(id)parent;
+- (id)accessibilityElementForAnnotation:(PDFAnnotation *)annotation;
+#endif
+
+@end
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+@interface PDFAnnotation (AccessibilityPrivate)
+- (id)accessibilityNode;
 @end
+#endif
 
 #endif
 
index 9cad41d..1de1b7e 100644 (file)
@@ -33,6 +33,7 @@
 #include "Plugin.h"
 #include "WebEvent.h"
 #include "WebHitTestResultData.h"
+#include <WebCore/AXObjectCache.h>
 #include <WebCore/AffineTransform.h>
 #include <WebCore/FindOptions.h>
 #include <WebCore/ScrollableArea.h>
@@ -57,6 +58,7 @@ class DataReference;
 }
 
 namespace WebCore {
+class AXObjectCache;
 class Element;
 struct PluginInfo;
 }
@@ -103,6 +105,7 @@ public:
     void attemptToUnlockPDF(const String& password);
 
     WebCore::FloatRect convertFromPDFViewToScreen(const WebCore::FloatRect&) const;
+    WebCore::IntPoint convertFromRootViewToPDFView(const WebCore::IntPoint&) const;
     WebCore::IntRect boundsOnScreen() const;
     
     bool showContextMenuAtPoint(const WebCore::IntPoint&);
@@ -114,6 +117,9 @@ public:
 
     bool shouldPlaceBlockDirectionScrollbarOnLeft() const override { return false; }
 
+    PDFPluginAnnotation* activeAnnotation() const { return m_activeAnnotation.get(); }
+    WebCore::AXObjectCache* axObjectCache() const;
+    
 private:
     explicit PDFPlugin(WebFrame*);
 
@@ -168,11 +174,13 @@ private:
     bool handleScroll(WebCore::ScrollDirection, WebCore::ScrollGranularity) override;
     RefPtr<WebCore::SharedBuffer> liveResourceData() const override;
     void willDetatchRenderer() override;
-
+    bool pluginHandlesContentOffsetForAccessibilityHitTest() const override;
+    
     bool isBeingAsynchronouslyInitialized() const override { return false; }
 
     RetainPtr<PDFDocument> pdfDocumentForPrinting() const override { return m_pdfDocument; }
     NSObject *accessibilityObject() const override;
+    id accessibilityAssociatedPluginParentForElement(WebCore::Element*) const override;
 
     unsigned countFindMatches(const String& target, WebCore::FindOptions, unsigned maxMatchCount) override;
     bool findString(const String& target, WebCore::FindOptions, unsigned maxMatchCount) override;
index 30b0388..130bf05 100644 (file)
@@ -50,6 +50,7 @@
 #import <JavaScriptCore/JSStringRefCF.h>
 #import <PDFKit/PDFKit.h>
 #import <QuartzCore/QuartzCore.h>
+#import <WebCore/AXObjectCache.h>
 #import <WebCore/ArchiveResource.h>
 #import <WebCore/Chrome.h>
 #import <WebCore/Cursor.h>
@@ -132,7 +133,6 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
 
 @implementation WKPDFPluginAccessibilityObject
 
-@synthesize pdfLayerController=_pdfLayerController;
 @synthesize parent=_parent;
 @synthesize pdfPlugin=_pdfPlugin;
 
@@ -146,15 +146,51 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
     return self;
 }
 
+- (PDFLayerController *)pdfLayerController
+{
+    return _pdfLayerController;
+}
+
+- (void)setPdfLayerController:(PDFLayerController *)pdfLayerController
+{
+    _pdfLayerController = pdfLayerController;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    [_pdfLayerController setAccessibilityParent:self];
+#endif
+}
+
 - (BOOL)accessibilityIsIgnored
 {
     return NO;
 }
 
+// This is called by PDFAccessibilityNodes from inside PDFKit to get final bounds.
+- (NSRect)convertRectToScreenSpace:(NSRect)rect
+{
+    return _pdfPlugin->convertFromPDFViewToScreen(rect);
+}
+
 - (id)accessibilityAttributeValue:(NSString *)attribute
 {
     if ([attribute isEqualToString:NSAccessibilityParentAttribute])
         return _parent;
+    if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
+        return [_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
+    if ([attribute isEqualToString:NSAccessibilityWindowAttribute])
+        return [_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
+    if ([attribute isEqualToString:NSAccessibilitySizeAttribute])
+        return [NSValue valueWithSize:_pdfPlugin->boundsOnScreen().size()];
+    if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
+        return [_parent accessibilityAttributeValue:NSAccessibilityEnabledAttribute];
+    if ([attribute isEqualToString:NSAccessibilityPositionAttribute])
+        return [NSValue valueWithPoint:_pdfPlugin->boundsOnScreen().location()];
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
+        return @[ _pdfLayerController ];
+    if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
+        return NSAccessibilityGroupRole;
+#else
     if ([attribute isEqualToString:NSAccessibilityValueAttribute])
         return [_pdfLayerController accessibilityValueAttribute];
     if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute])
@@ -165,22 +201,13 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
         return [_pdfLayerController accessibilityNumberOfCharactersAttribute];
     if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
         return [_pdfLayerController accessibilityVisibleCharacterRangeAttribute];
-    if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
-        return [_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
         return [_pdfLayerController accessibilityRoleAttribute];
     if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute])
         return [_pdfLayerController accessibilityRoleDescriptionAttribute];
-    if ([attribute isEqualToString:NSAccessibilityWindowAttribute])
-        return [_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
-    if ([attribute isEqualToString:NSAccessibilitySizeAttribute])
-        return [NSValue valueWithSize:_pdfPlugin->boundsOnScreen().size()];
     if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
         return [_parent accessibilityAttributeValue:NSAccessibilityFocusedAttribute];
-    if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
-        return [_parent accessibilityAttributeValue:NSAccessibilityEnabledAttribute];
-    if ([attribute isEqualToString:NSAccessibilityPositionAttribute])
-        return [NSValue valueWithPoint:_pdfPlugin->boundsOnScreen().location()];
+#endif
 
     return 0;
 }
@@ -213,20 +240,27 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
     static NSArray *attributeNames = 0;
 
     if (!attributeNames) {
-        attributeNames = @[NSAccessibilityValueAttribute,
-            NSAccessibilitySelectedTextAttribute,
-            NSAccessibilitySelectedTextRangeAttribute,
-            NSAccessibilityNumberOfCharactersAttribute,
-            NSAccessibilityVisibleCharacterRangeAttribute,
+        attributeNames = @[
             NSAccessibilityParentAttribute,
-            NSAccessibilityRoleAttribute,
             NSAccessibilityWindowAttribute,
             NSAccessibilityTopLevelUIElementAttribute,
             NSAccessibilityRoleDescriptionAttribute,
             NSAccessibilitySizeAttribute,
-            NSAccessibilityFocusedAttribute,
             NSAccessibilityEnabledAttribute,
-            NSAccessibilityPositionAttribute];
+            NSAccessibilityPositionAttribute,
+            NSAccessibilityFocusedAttribute,
+            // PDFLayerController has its own accessibilityChildren.
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+            NSAccessibilityChildrenAttribute
+#else
+            NSAccessibilityRoleAttribute,
+            NSAccessibilityValueAttribute,
+            NSAccessibilitySelectedTextAttribute,
+            NSAccessibilitySelectedTextRangeAttribute,
+            NSAccessibilityNumberOfCharactersAttribute,
+            NSAccessibilityVisibleCharacterRangeAttribute
+#endif
+            ];
         [attributeNames retain];
     }
 
@@ -235,12 +269,16 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
 
 - (NSArray *)accessibilityActionNames
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    return nil;
+#else
     static NSArray *actionNames = 0;
     
     if (!actionNames)
         actionNames = [[NSArray arrayWithObject:NSAccessibilityShowMenuAction] retain];
     
     return actionNames;
+#endif
 }
 
 - (void)accessibilityPerformAction:(NSString *)action
@@ -261,17 +299,59 @@ static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
 
 - (NSArray *)accessibilityParameterizedAttributeNames
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    return nil;
+#else
     return [_pdfLayerController accessibilityParameterizedAttributeNames];
+#endif
 }
 
 - (id)accessibilityFocusedUIElement
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    if (WebKit::PDFPluginAnnotation* activeAnnotation = _pdfPlugin->activeAnnotation()) {
+        if (AXObjectCache* existingCache = _pdfPlugin->axObjectCache()) {
+            if (AccessibilityObject* object = existingCache->getOrCreate(activeAnnotation->element()))
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+                return [object->wrapper() accessibilityAttributeValue:@"_AXAssociatedPluginParent"];
+#pragma clang diagnostic pop
+        }
+    }
+    return nil;
+#else
     return self;
+#endif
 }
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+- (id)accessibilityAssociatedControlForAnnotation:(PDFAnnotation *)annotation
+{
+    // Only active annotations seem to have their associated controls available.
+    WebKit::PDFPluginAnnotation* activeAnnotation = _pdfPlugin->activeAnnotation();
+    if (!activeAnnotation || ![activeAnnotation->annotation() isEqual:annotation])
+        return nil;
+    
+    AXObjectCache* cache = _pdfPlugin->axObjectCache();
+    if (!cache)
+        return nil;
+    
+    AccessibilityObject* object = cache->getOrCreate(activeAnnotation->element());
+    if (!object)
+        return nil;
+
+    return object->wrapper();
+}
+#endif
+
 - (id)accessibilityHitTest:(NSPoint)point
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    point = _pdfPlugin->convertFromRootViewToPDFView(IntPoint(point));
+    return [_pdfLayerController accessibilityHitTest:point];
+#else
     return self;
+#endif
 }
 
 @end
@@ -1206,6 +1286,12 @@ IntPoint PDFPlugin::convertFromPDFViewToRootView(const IntPoint& point) const
     IntPoint pointInPluginCoordinates(point.x(), size().height() - point.y());
     return m_rootViewToPluginTransform.inverse().value_or(AffineTransform()).mapPoint(pointInPluginCoordinates);
 }
+    
+IntPoint PDFPlugin::convertFromRootViewToPDFView(const IntPoint& point) const
+{
+    IntPoint pointInPluginCoordinates = m_rootViewToPluginTransform.mapPoint(point);
+    return IntPoint(pointInPluginCoordinates.x(), size().height() - pointInPluginCoordinates.y());
+}
 
 FloatRect PDFPlugin::convertFromPDFViewToScreen(const FloatRect& rect) const
 {
@@ -1214,10 +1300,9 @@ FloatRect PDFPlugin::convertFromPDFViewToScreen(const FloatRect& rect) const
     if (!frameView)
         return FloatRect();
 
-    FloatPoint originInPluginCoordinates(rect.x(), size().height() - rect.y() - rect.height());
-    FloatRect rectInRootViewCoordinates = m_rootViewToPluginTransform.inverse().value_or(AffineTransform()).mapRect(FloatRect(originInPluginCoordinates, rect.size()));
-
-    return frameView->contentsToScreen(enclosingIntRect(rectInRootViewCoordinates));
+    FloatRect updatedRect = rect;
+    updatedRect.setLocation(convertFromPDFViewToRootView(IntPoint(updatedRect.location())));
+    return webFrame()->coreFrame()->page()->chrome().rootViewToScreen(enclosingIntRect(updatedRect));
 }
 
 IntRect PDFPlugin::boundsOnScreen() const
@@ -1674,6 +1759,17 @@ RefPtr<SharedBuffer> PDFPlugin::liveResourceData() const
     return SharedBuffer::wrapNSData(pdfData);
 }
 
+bool PDFPlugin::pluginHandlesContentOffsetForAccessibilityHitTest() const
+{
+    // The PDF plugin handles the scroll view offset natively as part of the layer conversions.
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    return true;
+#else
+    return false;
+#endif
+}
+
+    
 void PDFPlugin::saveToPDF()
 {
     // FIXME: We should probably notify the user that they can't save before the document is finished loading.
@@ -2014,6 +2110,11 @@ static NSRect rectInViewSpaceForRectInLayoutSpace(PDFLayerController* pdfLayerCo
 
     return NSRectFromCGRect(newRect);
 }
+    
+WebCore::AXObjectCache* PDFPlugin::axObjectCache() const
+{
+    return webFrame()->coreFrame()->document()->axObjectCache();
+}
 
 WebCore::FloatRect PDFPlugin::rectForSelectionInRootView(PDFSelection *selection) const
 {
@@ -2103,6 +2204,21 @@ NSData *PDFPlugin::liveData() const
     return rawData();
 }
 
+id PDFPlugin::accessibilityAssociatedPluginParentForElement(WebCore::Element* element) const
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
+    if (!m_activeAnnotation)
+        return nil;
+    
+    if (m_activeAnnotation->element() != element)
+        return nil;
+    
+    return [m_activeAnnotation->annotation() accessibilityNode];
+#else
+    return nil;
+#endif
+}
+    
 NSObject *PDFPlugin::accessibilityObject() const
 {
     return m_accessibilityObject.get();
index 838743f..422bdac 100644 (file)
@@ -70,6 +70,7 @@ void PDFPluginAnnotation::attach(Element* parent)
     m_element = createAnnotationElement();
 
     m_element->setAttributeWithoutSynchronization(classAttr, AtomicString("annotation", AtomicString::ConstructFromLiteral));
+    m_element->setAttributeWithoutSynchronization(x_apple_pdf_annotationAttr, AtomicString("true", AtomicString::ConstructFromLiteral));
     m_element->addEventListener(eventNames().changeEvent, *m_eventListener, false);
     m_element->addEventListener(eventNames().blurEvent, *m_eventListener, false);
 
index a86773c..a56825a 100644 (file)
@@ -37,6 +37,7 @@
 
 #if PLATFORM(COCOA)
 #include "LayerHostingContext.h"
+typedef struct objc_object* id;
 
 OBJC_CLASS NSDictionary;
 OBJC_CLASS NSObject;
@@ -274,6 +275,7 @@ public:
 #if PLATFORM(COCOA)
     virtual RetainPtr<PDFDocument> pdfDocumentForPrinting() const { return 0; }
     virtual NSObject *accessibilityObject() const { return 0; }
+    virtual id accessibilityAssociatedPluginParentForElement(WebCore::Element*) const { return nullptr; }
 #endif
 
     virtual unsigned countFindMatches(const String& target, WebCore::FindOptions, unsigned maxMatchCount) = 0;
@@ -300,6 +302,8 @@ public:
 
     virtual void willDetatchRenderer() { }
 
+    virtual bool pluginHandlesContentOffsetForAccessibilityHitTest() const { return false; }
+
 protected:
     Plugin(PluginType);
 
index ba07690..f383281 100644 (file)
@@ -555,6 +555,13 @@ bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier,
     return true;
 }
     
+id PluginView::accessibilityAssociatedPluginParentForElement(Element* element) const
+{
+    if (!m_plugin)
+        return nil;
+    return m_plugin->accessibilityAssociatedPluginParentForElement(element);
+}
+    
 NSObject *PluginView::accessibilityObject() const
 {
     if (!m_isInitialized || !m_plugin)
index 38be621..f7bcddc 100644 (file)
@@ -86,6 +86,7 @@ public:
     bool sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput);
     RetainPtr<PDFDocument> pdfDocumentForPrinting() const { return m_plugin->pdfDocumentForPrinting(); }
     NSObject *accessibilityObject() const;
+    id accessibilityAssociatedPluginParentForElement(WebCore::Element*) const override;
 #endif
 
     WebCore::HTMLPlugInElement* pluginElement() const { return m_pluginElement.get(); }
index 4201ad4..e36ae15 100644 (file)
@@ -972,6 +972,8 @@ public:
     WebURLSchemeHandlerProxy* urlSchemeHandlerForScheme(const String&);
     std::optional<double> backgroundCPULimit() const { return m_backgroundCPULimit; }
 
+    static PluginView* pluginViewForFrame(WebCore::Frame*);
+
 private:
     WebPage(uint64_t pageID, WebPageCreationParameters&&);
 
@@ -1212,7 +1214,6 @@ private:
     static bool platformCanHandleRequest(const WebCore::ResourceRequest&);
 
     static PluginView* focusedPluginViewForFrame(WebCore::Frame&);
-    static PluginView* pluginViewForFrame(WebCore::Frame*);
 
     static RefPtr<WebCore::Range> rangeFromEditingRange(WebCore::Frame&, const EditingRange&, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot);
 
index 164ae57..94c09cb 100644 (file)
@@ -28,6 +28,7 @@
 
 #if PLATFORM(MAC)
 
+#import "PluginView.h"
 #import "WebFrame.h"
 #import "WebPage.h"
 #import "WKArray.h"
@@ -193,13 +194,21 @@ using namespace WebKit;
 {
     if (!m_page)
         return nil;
-    
+
     IntPoint convertedPoint = m_page->screenToRootView(IntPoint(point));
-    if (WebCore::FrameView* frameView = m_page->mainFrameView())
-        convertedPoint.moveBy(frameView->scrollPosition());
-    if (WebCore::Page* page = m_page->corePage())
-        convertedPoint.move(0, -page->topContentInset());
     
+    // Some plugins may be able to figure out the scroll position and inset on their own.
+    bool applyContentOffset = true;
+    if (auto pluginView = m_page->pluginViewForFrame(m_page->mainFrame()))
+        applyContentOffset = !pluginView->plugin()->pluginHandlesContentOffsetForAccessibilityHitTest();
+
+    if (applyContentOffset) {
+        if (WebCore::FrameView* frameView = m_page->mainFrameView())
+            convertedPoint.moveBy(frameView->scrollPosition());
+        if (WebCore::Page* page = m_page->corePage())
+            convertedPoint.move(0, -page->topContentInset());
+    }
+
     return [[self accessibilityRootObjectWrapper] accessibilityHitTest:convertedPoint];
 }
 #pragma clang diagnostic pop