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 "CSSPrimitiveValueMappings.h"
36#include "Document.h"
37#include "EventHandler.h"
38#include "FrameView.h"
39#include "Node.h"
40#include "PlatformKeyboardEvent.h"
41#include "RenderStyle.h"
42#include "UserGestureIndicator.h"
43#include "WebDocument.h"
44#include "WebNode.h"
45#include "WebPoint.h"
46#include "WebRect.h"
47#include "WebString.h"
48#include "WebURL.h"
49
50using namespace WebCore;
51
52namespace WebKit {
53
54class WebAccessibilityObjectPrivate : public WebCore::AccessibilityObject {
55};
56
57void WebAccessibilityObject::reset()
58{
59    assign(0);
60}
61
62void WebAccessibilityObject::assign(const WebKit::WebAccessibilityObject& other)
63{
64    WebAccessibilityObjectPrivate* p = const_cast<WebAccessibilityObjectPrivate*>(other.m_private);
65    if (p)
66        p->ref();
67    assign(p);
68}
69
70bool WebAccessibilityObject::equals(const WebAccessibilityObject& n) const
71{
72    return (m_private == n.m_private);
73}
74
75WebString WebAccessibilityObject::accessibilityDescription() const
76{
77    if (!m_private)
78        return WebString();
79
80    m_private->updateBackingStore();
81    return m_private->accessibilityDescription();
82}
83
84WebString WebAccessibilityObject::actionVerb() const
85{
86    if (!m_private)
87        return WebString();
88
89    m_private->updateBackingStore();
90    return m_private->actionVerb();
91}
92
93bool WebAccessibilityObject::canSetFocusAttribute() const
94{
95    if (!m_private)
96        return false;
97
98    m_private->updateBackingStore();
99    return m_private->canSetFocusAttribute();
100}
101
102bool WebAccessibilityObject::canSetValueAttribute() const
103{
104    if (!m_private)
105        return false;
106
107    m_private->updateBackingStore();
108    return m_private->canSetValueAttribute();
109}
110
111bool WebAccessibilityObject::isValid() const
112{
113    if (!m_private)
114        return false;
115
116    m_private->updateBackingStore();
117    return m_private->axObjectID();
118}
119
120unsigned WebAccessibilityObject::childCount() const
121{
122    if (!m_private)
123        return 0;
124
125    m_private->updateBackingStore();
126    return m_private->children().size();
127}
128
129WebAccessibilityObject WebAccessibilityObject::childAt(unsigned index) const
130{
131    if (!m_private)
132        return WebAccessibilityObject();
133
134    m_private->updateBackingStore();
135    if (m_private->children().size() <= index)
136        return WebAccessibilityObject();
137
138    return WebAccessibilityObject(m_private->children()[index]);
139}
140
141WebAccessibilityObject WebAccessibilityObject::firstChild() const
142{
143    if (!m_private)
144        return WebAccessibilityObject();
145
146    m_private->updateBackingStore();
147    return WebAccessibilityObject(m_private->firstChild());
148}
149
150WebAccessibilityObject WebAccessibilityObject::focusedChild() const
151{
152    if (!m_private)
153        return WebAccessibilityObject();
154
155    m_private->updateBackingStore();
156    RefPtr<AccessibilityObject> focused = m_private->focusedUIElement();
157    if (m_private == focused.get() || focused->parentObject() == m_private)
158        return WebAccessibilityObject(focused);
159
160    return WebAccessibilityObject();
161}
162
163WebAccessibilityObject WebAccessibilityObject::lastChild() const
164{
165    if (!m_private)
166        return WebAccessibilityObject();
167
168    m_private->updateBackingStore();
169    return WebAccessibilityObject(m_private->lastChild());
170}
171
172
173WebAccessibilityObject WebAccessibilityObject::nextSibling() const
174{
175    if (!m_private)
176        return WebAccessibilityObject();
177
178    m_private->updateBackingStore();
179    return WebAccessibilityObject(m_private->nextSibling());
180}
181
182WebAccessibilityObject WebAccessibilityObject::parentObject() const
183{
184    if (!m_private)
185        return WebAccessibilityObject();
186
187    m_private->updateBackingStore();
188    return WebAccessibilityObject(m_private->parentObject());
189}
190
191
192WebAccessibilityObject WebAccessibilityObject::previousSibling() const
193{
194    if (!m_private)
195        return WebAccessibilityObject();
196
197    m_private->updateBackingStore();
198    return WebAccessibilityObject(m_private->previousSibling());
199}
200
201bool WebAccessibilityObject::canSetSelectedAttribute() const
202{
203    if (!m_private)
204        return 0;
205
206    m_private->updateBackingStore();
207    return m_private->canSetSelectedAttribute();
208}
209
210bool WebAccessibilityObject::isAnchor() const
211{
212    if (!m_private)
213        return 0;
214
215    m_private->updateBackingStore();
216    return m_private->isAnchor();
217}
218
219bool WebAccessibilityObject::isChecked() const
220{
221    if (!m_private)
222        return 0;
223
224    m_private->updateBackingStore();
225    return m_private->isChecked();
226}
227
228bool WebAccessibilityObject::isCollapsed() const
229{
230    if (!m_private)
231        return 0;
232
233    m_private->updateBackingStore();
234    return m_private->isCollapsed();
235}
236
237
238bool WebAccessibilityObject::isFocused() const
239{
240    if (!m_private)
241        return 0;
242
243    m_private->updateBackingStore();
244    return m_private->isFocused();
245}
246
247bool WebAccessibilityObject::isEnabled() const
248{
249    if (!m_private)
250        return 0;
251
252    m_private->updateBackingStore();
253    return m_private->isEnabled();
254}
255
256bool WebAccessibilityObject::isHovered() const
257{
258    if (!m_private)
259        return 0;
260
261    m_private->updateBackingStore();
262    return m_private->isHovered();
263}
264
265bool WebAccessibilityObject::isIndeterminate() const
266{
267    if (!m_private)
268        return 0;
269
270    m_private->updateBackingStore();
271    return m_private->isIndeterminate();
272}
273
274bool WebAccessibilityObject::isLinked() const
275{
276    if (!m_private)
277        return 0;
278
279    m_private->updateBackingStore();
280    return m_private->isLinked();
281}
282
283bool WebAccessibilityObject::isMultiSelectable() const
284{
285    if (!m_private)
286        return 0;
287
288    m_private->updateBackingStore();
289    return m_private->isMultiSelectable();
290}
291
292bool WebAccessibilityObject::isOffScreen() const
293{
294    if (!m_private)
295        return 0;
296
297    m_private->updateBackingStore();
298    return m_private->isOffScreen();
299}
300
301bool WebAccessibilityObject::isPasswordField() const
302{
303    if (!m_private)
304        return 0;
305
306    m_private->updateBackingStore();
307    return m_private->isPasswordField();
308}
309
310bool WebAccessibilityObject::isPressed() const
311{
312    if (!m_private)
313        return 0;
314
315    m_private->updateBackingStore();
316    return m_private->isPressed();
317}
318
319bool WebAccessibilityObject::isReadOnly() const
320{
321    if (!m_private)
322        return 0;
323
324    m_private->updateBackingStore();
325    return m_private->isReadOnly();
326}
327
328bool WebAccessibilityObject::isSelected() const
329{
330    if (!m_private)
331        return 0;
332
333    m_private->updateBackingStore();
334    return m_private->isSelected();
335}
336
337bool WebAccessibilityObject::isVisible() const
338{
339    if (!m_private)
340        return 0;
341
342    m_private->updateBackingStore();
343    return m_private->isVisible();
344}
345
346bool WebAccessibilityObject::isVisited() const
347{
348    if (!m_private)
349        return 0;
350
351    m_private->updateBackingStore();
352    return m_private->isVisited();
353}
354
355WebRect WebAccessibilityObject::boundingBoxRect() const
356{
357    if (!m_private)
358        return WebRect();
359
360    m_private->updateBackingStore();
361    return m_private->boundingBoxRect();
362}
363
364WebString WebAccessibilityObject::helpText() const
365{
366    if (!m_private)
367        return WebString();
368
369    m_private->updateBackingStore();
370    return m_private->helpText();
371}
372
373int WebAccessibilityObject::headingLevel() const
374{
375    if (!m_private)
376        return 0;
377
378    m_private->updateBackingStore();
379    return m_private->headingLevel();
380}
381
382WebAccessibilityObject WebAccessibilityObject::hitTest(const WebPoint& point) const
383{
384    if (!m_private)
385        return WebAccessibilityObject();
386
387    m_private->updateBackingStore();
388    IntPoint contentsPoint = m_private->documentFrameView()->windowToContents(point);
389    RefPtr<AccessibilityObject> hit = m_private->accessibilityHitTest(contentsPoint);
390
391    if (hit.get())
392        return WebAccessibilityObject(hit);
393
394    if (m_private->boundingBoxRect().contains(contentsPoint))
395        return *this;
396
397    return WebAccessibilityObject();
398}
399
400WebString WebAccessibilityObject::keyboardShortcut() const
401{
402    if (!m_private)
403        return WebString();
404
405    m_private->updateBackingStore();
406    String accessKey = m_private->accessKey();
407    if (accessKey.isNull())
408        return WebString();
409
410    static String modifierString;
411    if (modifierString.isNull()) {
412        unsigned modifiers = EventHandler::accessKeyModifiers();
413        // Follow the same order as Mozilla MSAA implementation:
414        // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
415        // should not be localized and defines the separator as "+".
416        if (modifiers & PlatformKeyboardEvent::CtrlKey)
417            modifierString += "Ctrl+";
418        if (modifiers & PlatformKeyboardEvent::AltKey)
419            modifierString += "Alt+";
420        if (modifiers & PlatformKeyboardEvent::ShiftKey)
421            modifierString += "Shift+";
422        if (modifiers & PlatformKeyboardEvent::MetaKey)
423            modifierString += "Win+";
424    }
425
426    return modifierString + accessKey;
427}
428
429bool WebAccessibilityObject::performDefaultAction() const
430{
431    if (!m_private)
432        return false;
433
434    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
435
436    m_private->updateBackingStore();
437    return m_private->performDefaultAction();
438}
439
440WebAccessibilityRole WebAccessibilityObject::roleValue() const
441{
442    if (!m_private)
443        return WebKit::WebAccessibilityRoleUnknown;
444
445    m_private->updateBackingStore();
446    return static_cast<WebAccessibilityRole>(m_private->roleValue());
447}
448
449void WebAccessibilityObject::setFocused(bool on) const
450{
451    if (m_private)
452        m_private->setFocused(on);
453}
454
455WebString WebAccessibilityObject::stringValue() const
456{
457    if (!m_private)
458        return WebString();
459
460    m_private->updateBackingStore();
461    return m_private->stringValue();
462}
463
464WebString WebAccessibilityObject::title() const
465{
466    if (!m_private)
467        return WebString();
468
469    m_private->updateBackingStore();
470    return m_private->title();
471}
472
473WebURL WebAccessibilityObject::url() const
474{
475    if (!m_private)
476        return WebURL();
477
478    m_private->updateBackingStore();
479    return m_private->url();
480}
481
482WebNode WebAccessibilityObject::node() const
483{
484    if (!m_private)
485        return WebNode();
486
487    m_private->updateBackingStore();
488
489    Node* node = m_private->node();
490    if (!node)
491        return WebNode();
492
493    return WebNode(node);
494}
495
496WebDocument WebAccessibilityObject::document() const
497{
498    if (!m_private)
499        return WebDocument();
500
501    m_private->updateBackingStore();
502
503    Document* document = m_private->document();
504    if (!document)
505        return WebDocument();
506
507    return WebDocument(document);
508}
509
510bool WebAccessibilityObject::hasComputedStyle() const
511{
512    Document* document = m_private->document();
513    if (document)
514        document->updateStyleIfNeeded();
515
516    Node* node = m_private->node();
517    if (!node)
518        return false;
519
520    return node->computedStyle();
521}
522
523WebString WebAccessibilityObject::computedStyleDisplay() const
524{
525    Document* document = m_private->document();
526    if (document)
527        document->updateStyleIfNeeded();
528
529    Node* node = m_private->node();
530    if (!node)
531        return WebString();
532
533    RenderStyle* renderStyle = node->computedStyle();
534    if (!renderStyle)
535        return WebString();
536
537    return WebString(CSSPrimitiveValue::create(renderStyle->display())->getStringValue());
538}
539
540bool WebAccessibilityObject::accessibilityIsIgnored() const
541{
542    m_private->updateBackingStore();
543    return m_private->accessibilityIsIgnored();
544}
545
546WebAccessibilityObject::WebAccessibilityObject(const WTF::PassRefPtr<WebCore::AccessibilityObject>& object)
547    : m_private(static_cast<WebAccessibilityObjectPrivate*>(object.releaseRef()))
548{
549}
550
551WebAccessibilityObject& WebAccessibilityObject::operator=(const WTF::PassRefPtr<WebCore::AccessibilityObject>& object)
552{
553    assign(static_cast<WebAccessibilityObjectPrivate*>(object.releaseRef()));
554    return *this;
555}
556
557WebAccessibilityObject::operator WTF::PassRefPtr<WebCore::AccessibilityObject>() const
558{
559    return PassRefPtr<WebCore::AccessibilityObject>(const_cast<WebAccessibilityObjectPrivate*>(m_private));
560}
561
562void WebAccessibilityObject::assign(WebAccessibilityObjectPrivate* p)
563{
564    // p is already ref'd for us by the caller
565    if (m_private)
566        m_private->deref();
567    m_private = p;
568}
569
570} // namespace WebKit
571