1/*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "WebAccessibilityObject.h"
33
34#include "AccessibilityObject.h"
35#include "EventHandler.h"
36#include "FrameView.h"
37#include "PlatformKeyboardEvent.h"
38#include "WebPoint.h"
39#include "WebRect.h"
40#include "WebString.h"
41
42using namespace WebCore;
43
44namespace WebKit {
45
46class WebAccessibilityObjectPrivate : public WebCore::AccessibilityObject {
47};
48
49void WebAccessibilityObject::reset()
50{
51    assign(0);
52}
53
54void WebAccessibilityObject::assign(const WebKit::WebAccessibilityObject& other)
55{
56    WebAccessibilityObjectPrivate* p = const_cast<WebAccessibilityObjectPrivate*>(other.m_private);
57    if (p)
58        p->ref();
59    assign(p);
60}
61
62WebString WebAccessibilityObject::accessibilityDescription() const
63{
64    if (!m_private)
65        return WebString();
66
67    m_private->updateBackingStore();
68    return m_private->accessibilityDescription();
69}
70
71WebString WebAccessibilityObject::actionVerb() const
72{
73    if (!m_private)
74        return WebString();
75
76    m_private->updateBackingStore();
77    return m_private->actionVerb();
78}
79
80bool WebAccessibilityObject::canSetFocusAttribute() const
81{
82    if (!m_private)
83        return false;
84
85    m_private->updateBackingStore();
86    return m_private->canSetFocusAttribute();
87}
88
89bool WebAccessibilityObject::canSetValueAttribute() const
90{
91    if (!m_private)
92        return false;
93
94    m_private->updateBackingStore();
95    return m_private->canSetValueAttribute();
96}
97
98unsigned WebAccessibilityObject::childCount() const
99{
100    if (!m_private)
101        return 0;
102
103    m_private->updateBackingStore();
104    return m_private->children().size();
105}
106
107WebAccessibilityObject WebAccessibilityObject::childAt(unsigned index) const
108{
109    if (!m_private)
110        return WebAccessibilityObject();
111
112    m_private->updateBackingStore();
113    if (m_private->children().size() <= index)
114        return WebAccessibilityObject();
115
116    return WebAccessibilityObject(m_private->children()[index]);
117}
118
119WebAccessibilityObject WebAccessibilityObject::firstChild() const
120{
121    if (!m_private)
122        return WebAccessibilityObject();
123
124    m_private->updateBackingStore();
125    return WebAccessibilityObject(m_private->firstChild());
126}
127
128WebAccessibilityObject WebAccessibilityObject::focusedChild() const
129{
130    if (!m_private)
131        return WebAccessibilityObject();
132
133    m_private->updateBackingStore();
134    RefPtr<AccessibilityObject> focused = m_private->focusedUIElement();
135    if (m_private == focused.get() || focused->parentObject() == m_private)
136        return WebAccessibilityObject(focused);
137
138    return WebAccessibilityObject();
139}
140
141WebAccessibilityObject WebAccessibilityObject::lastChild() const
142{
143    if (!m_private)
144        return WebAccessibilityObject();
145
146    m_private->updateBackingStore();
147    return WebAccessibilityObject(m_private->lastChild());
148}
149
150
151WebAccessibilityObject WebAccessibilityObject::nextSibling() const
152{
153    if (!m_private)
154        return WebAccessibilityObject();
155
156    m_private->updateBackingStore();
157    return WebAccessibilityObject(m_private->nextSibling());
158}
159
160WebAccessibilityObject WebAccessibilityObject::parentObject() const
161{
162    if (!m_private)
163        return WebAccessibilityObject();
164
165    m_private->updateBackingStore();
166    return WebAccessibilityObject(m_private->parentObject());
167}
168
169
170WebAccessibilityObject WebAccessibilityObject::previousSibling() const
171{
172    if (!m_private)
173        return WebAccessibilityObject();
174
175    m_private->updateBackingStore();
176    return WebAccessibilityObject(m_private->previousSibling());
177}
178
179bool WebAccessibilityObject::isAnchor() const
180{
181    if (!m_private)
182        return 0;
183
184    m_private->updateBackingStore();
185    return m_private->isAnchor();
186}
187
188bool WebAccessibilityObject::isChecked() const
189{
190    if (!m_private)
191        return 0;
192
193    m_private->updateBackingStore();
194    return m_private->isChecked();
195}
196
197
198bool WebAccessibilityObject::isFocused() const
199{
200    if (!m_private)
201        return 0;
202
203    m_private->updateBackingStore();
204    return m_private->isFocused();
205}
206
207bool WebAccessibilityObject::isEnabled() const
208{
209    if (!m_private)
210        return 0;
211
212    m_private->updateBackingStore();
213    return m_private->isEnabled();
214}
215
216bool WebAccessibilityObject::isHovered() const
217{
218    if (!m_private)
219        return 0;
220
221    m_private->updateBackingStore();
222    return m_private->isHovered();
223}
224
225bool WebAccessibilityObject::isIndeterminate() const
226{
227    if (!m_private)
228        return 0;
229
230    m_private->updateBackingStore();
231    return m_private->isIndeterminate();
232}
233
234bool WebAccessibilityObject::isMultiSelectable() const
235{
236    if (!m_private)
237        return 0;
238
239    m_private->updateBackingStore();
240    return m_private->isMultiSelectable();
241}
242
243bool WebAccessibilityObject::isOffScreen() const
244{
245    if (!m_private)
246        return 0;
247
248    m_private->updateBackingStore();
249    return m_private->isOffScreen();
250}
251
252bool WebAccessibilityObject::isPasswordField() const
253{
254    if (!m_private)
255        return 0;
256
257    m_private->updateBackingStore();
258    return m_private->isPasswordField();
259}
260
261bool WebAccessibilityObject::isPressed() const
262{
263    if (!m_private)
264        return 0;
265
266    m_private->updateBackingStore();
267    return m_private->isPressed();
268}
269
270bool WebAccessibilityObject::isReadOnly() const
271{
272    if (!m_private)
273        return 0;
274
275    m_private->updateBackingStore();
276    return m_private->isReadOnly();
277}
278
279bool WebAccessibilityObject::isVisited() const
280{
281    if (!m_private)
282        return 0;
283
284    m_private->updateBackingStore();
285    return m_private->isVisited();
286}
287
288WebRect WebAccessibilityObject::boundingBoxRect() const
289{
290    if (!m_private)
291        return WebRect();
292
293    m_private->updateBackingStore();
294    return m_private->documentFrameView()->contentsToWindow(m_private->boundingBoxRect());
295}
296
297WebString WebAccessibilityObject::helpText() const
298{
299    if (!m_private)
300        return WebString();
301
302    m_private->updateBackingStore();
303    return m_private->helpText();
304}
305
306WebAccessibilityObject WebAccessibilityObject::hitTest(const WebPoint& point) const
307{
308    if (!m_private)
309        return WebAccessibilityObject();
310
311    m_private->updateBackingStore();
312    IntPoint contentsPoint = m_private->documentFrameView()->windowToContents(point);
313    RefPtr<AccessibilityObject> hit = m_private->doAccessibilityHitTest(contentsPoint);
314
315    if (hit.get())
316        return WebAccessibilityObject(hit);
317
318    if (m_private->boundingBoxRect().contains(contentsPoint))
319        return *this;
320
321    return WebAccessibilityObject();
322}
323
324WebString WebAccessibilityObject::keyboardShortcut() const
325{
326    if (!m_private)
327        return WebString();
328
329    m_private->updateBackingStore();
330    String accessKey = m_private->accessKey();
331    if (accessKey.isNull())
332        return WebString();
333
334    static String modifierString;
335    if (modifierString.isNull()) {
336        unsigned modifiers = EventHandler::accessKeyModifiers();
337        // Follow the same order as Mozilla MSAA implementation:
338        // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
339        // should not be localized and defines the separator as "+".
340        if (modifiers & PlatformKeyboardEvent::CtrlKey)
341            modifierString += "Ctrl+";
342        if (modifiers & PlatformKeyboardEvent::AltKey)
343            modifierString += "Alt+";
344        if (modifiers & PlatformKeyboardEvent::ShiftKey)
345            modifierString += "Shift+";
346        if (modifiers & PlatformKeyboardEvent::MetaKey)
347            modifierString += "Win+";
348    }
349
350    return modifierString + accessKey;
351}
352
353bool WebAccessibilityObject::performDefaultAction() const
354{
355    if (!m_private)
356        return false;
357
358    m_private->updateBackingStore();
359    return m_private->performDefaultAction();
360}
361
362WebAccessibilityRole WebAccessibilityObject::roleValue() const
363{
364    if (!m_private)
365        return WebKit::WebAccessibilityRoleUnknown;
366
367    m_private->updateBackingStore();
368    return static_cast<WebAccessibilityRole>(m_private->roleValue());
369}
370
371WebString WebAccessibilityObject::stringValue() const
372{
373    if (!m_private)
374        return WebString();
375
376    m_private->updateBackingStore();
377    return m_private->stringValue();
378}
379
380WebString WebAccessibilityObject::title() const
381{
382    if (!m_private)
383        return WebString();
384
385    m_private->updateBackingStore();
386    return m_private->title();
387}
388
389WebAccessibilityObject::WebAccessibilityObject(const WTF::PassRefPtr<WebCore::AccessibilityObject>& object)
390    : m_private(static_cast<WebAccessibilityObjectPrivate*>(object.releaseRef()))
391{
392}
393
394WebAccessibilityObject& WebAccessibilityObject::operator=(const WTF::PassRefPtr<WebCore::AccessibilityObject>& object)
395{
396    assign(static_cast<WebAccessibilityObjectPrivate*>(object.releaseRef()));
397    return *this;
398}
399
400WebAccessibilityObject::operator WTF::PassRefPtr<WebCore::AccessibilityObject>() const
401{
402    return PassRefPtr<WebCore::AccessibilityObject>(const_cast<WebAccessibilityObjectPrivate*>(m_private));
403}
404
405void WebAccessibilityObject::assign(WebAccessibilityObjectPrivate* p)
406{
407    // p is already ref'd for us by the caller
408    if (m_private)
409        m_private->deref();
410    m_private = p;
411}
412
413} // namespace WebKit
414