Reviewed and landed by Sam Weinig.
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / mac / AccessibilityWebPageObject.mm
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "AccessibilityWebPageObject.h"
28
29 #import "WebFrame.h"
30 #import "WebPage.h"
31 #import <WebCore/AXObjectCache.h>
32 #import <WebCore/Frame.h>
33 #import <WebCore/FrameView.h>
34 #import <WebCore/ScrollView.h>
35 #import <WebCore/Scrollbar.h>
36 #import <WebKitSystemInterface.h>
37
38 using namespace WebCore;
39 using namespace WebKit;
40
41 @implementation AccessibilityWebPageObject
42
43 - (id)accessibilityRootObjectWrapper
44 {
45     WebCore::Page* page = m_page->corePage();
46     if (!page)
47         return nil;
48     
49     WebCore::Frame* core = page->mainFrame();
50     if (!core || !core->document())
51         return nil;
52     
53     AccessibilityObject* root = core->document()->axObjectCache()->rootObject();
54     if (!root)
55         return nil;
56     
57     return root->wrapper();
58 }
59
60 - (void)setWebPage:(WebPage*)page
61 {
62     m_page = page;
63 }
64
65 - (void)setRemoteParent:(id)parent
66 {
67     if (parent != m_parent) {
68         [m_parent release];
69         m_parent = [parent retain];
70     }
71 }
72
73 - (void)dealloc
74 {
75     WKUnregisterUniqueIdForElement(self);
76     [m_accessibilityChildren release];
77     [m_attributeNames release];
78     [m_parent release];
79     [super dealloc];
80 }
81
82 - (BOOL)accessibilityIsIgnored
83 {
84     return NO;
85 }
86
87 - (NSArray *)accessibilityAttributeNames
88 {
89     if (!m_attributeNames)
90         m_attributeNames = [[NSArray alloc] initWithObjects:
91                            NSAccessibilityRoleAttribute, NSAccessibilityRoleDescriptionAttribute, NSAccessibilityFocusedAttribute,
92                            NSAccessibilityParentAttribute, NSAccessibilityWindowAttribute, NSAccessibilityTopLevelUIElementAttribute,
93                            NSAccessibilityPositionAttribute, NSAccessibilitySizeAttribute, NSAccessibilityChildrenAttribute, nil];
94
95     return m_attributeNames;
96 }
97
98 - (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute
99 {
100     return NO;
101 }
102
103 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute 
104 {
105     return;
106 }
107
108 - (NSArray *)accessibilityActionNames
109 {
110     return [NSArray array];
111 }
112
113 - (NSArray *)accessibilityChildren
114 {
115     id wrapper = [self accessibilityRootObjectWrapper];
116     if (!wrapper)
117         return [NSArray array];
118     
119     return [NSArray arrayWithObject:wrapper];
120 }
121
122 - (id)accessibilityAttributeValue:(NSString *)attribute
123 {
124     if (!WebCore::AXObjectCache::accessibilityEnabled())
125         WebCore::AXObjectCache::enableAccessibility();
126     
127     if ([attribute isEqualToString:NSAccessibilityParentAttribute])
128         return m_parent;
129     if ([attribute isEqualToString:NSAccessibilityWindowAttribute])
130         return [m_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
131     if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
132         return [m_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
133     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
134         return NSAccessibilityGroupRole;
135     if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute])
136         return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil);
137     if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
138         return [NSNumber numberWithBool:NO];
139
140     if (!m_page)
141         return nil;
142
143     if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
144         WebCore::IntPoint point = m_page->accessibilityPosition();
145         return [NSValue valueWithPoint:NSMakePoint(point.x(), point.y())];
146     }
147     if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
148         const IntSize& s = m_page->size();
149         return [NSValue valueWithSize:NSMakeSize(s.width(), s.height())];
150     }
151     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
152         return [self accessibilityChildren];
153
154     return [super accessibilityAttributeValue:attribute];
155 }
156
157 - (BOOL)accessibilityShouldUseUniqueId
158 {
159     return YES;
160 }
161
162 - (id)accessibilityHitTest:(NSPoint)point 
163 {
164     // Hit-test point comes in as bottom-screen coordinates. Needs to be normalized to the frame of the web page.
165     NSPoint remotePosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue];
166     NSSize remoteSize = [[self accessibilityAttributeValue:NSAccessibilitySizeAttribute] sizeValue];
167     
168     // Get the y position of the WKView (we have to screen-flip and go from bottom left to top left).
169     CGFloat screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
170     remotePosition.y = (screenHeight - remotePosition.y) - remoteSize.height;
171     
172     point.y = screenHeight - point.y;
173
174     // Re-center point into the web page's frame.
175     point.y -= remotePosition.y;
176     point.x -= remotePosition.x;
177     
178     WebCore::FrameView* fv = m_page->mainFrame()->coreFrame()->view();
179     if (fv) {
180         point.y += fv->scrollPosition().y();
181         point.x += fv->scrollPosition().x();
182     }
183     
184     return [[self accessibilityRootObjectWrapper] accessibilityHitTest:point];
185 }
186
187 - (id)accessibilityFocusedUIElement 
188 {
189     return NSAccessibilityUnignoredDescendant(self);
190 }
191
192
193 @end