43a7380db4b0e90e69ca7a35200dafa22de460df
[WebKit-https.git] / WebKitTools / DumpRenderTree / chromium / AccessibilityUIElement.cpp
1 /*
2  * Copyright (C) 2010 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 "AccessibilityUIElement.h"
33
34 #include "WebAccessibilityObject.h"
35 #include "WebCString.h"
36 #include "WebString.h"
37 #include <wtf/Assertions.h>
38
39 using namespace WebKit;
40 using namespace std;
41
42 // Map role value to string, matching Safari/Mac platform implementation to
43 // avoid rebaselining layout tests.
44 static string roleToString(WebAccessibilityRole role)
45 {
46     string result = "AXRole: AX";
47     switch (role) {
48     case WebAccessibilityRoleButton:
49         return result.append("Button");
50     case WebAccessibilityRoleRadioButton:
51         return result.append("RadioButton");
52     case WebAccessibilityRoleCheckBox:
53         return result.append("CheckBox");
54     case WebAccessibilityRoleSlider:
55         return result.append("Slider");
56     case WebAccessibilityRoleTabGroup:
57         return result.append("TabGroup");
58     case WebAccessibilityRoleTextField:
59         return result.append("TextField");
60     case WebAccessibilityRoleStaticText:
61         return result.append("StaticText");
62     case WebAccessibilityRoleTextArea:
63         return result.append("TextArea");
64     case WebAccessibilityRoleScrollArea:
65         return result.append("ScrollArea");
66     case WebAccessibilityRolePopUpButton:
67         return result.append("PopUpButton");
68     case WebAccessibilityRoleMenuButton:
69         return result.append("MenuButton");
70     case WebAccessibilityRoleTable:
71         return result.append("Table");
72     case WebAccessibilityRoleApplication:
73         return result.append("Application");
74     case WebAccessibilityRoleGroup:
75         return result.append("Group");
76     case WebAccessibilityRoleRadioGroup:
77         return result.append("RadioGroup");
78     case WebAccessibilityRoleList:
79         return result.append("List");
80     case WebAccessibilityRoleScrollBar:
81         return result.append("ScrollBar");
82     case WebAccessibilityRoleValueIndicator:
83         return result.append("ValueIndicator");
84     case WebAccessibilityRoleImage:
85         return result.append("Image");
86     case WebAccessibilityRoleMenuBar:
87         return result.append("MenuBar");
88     case WebAccessibilityRoleMenu:
89         return result.append("Menu");
90     case WebAccessibilityRoleMenuItem:
91         return result.append("MenuItem");
92     case WebAccessibilityRoleColumn:
93         return result.append("Column");
94     case WebAccessibilityRoleRow:
95         return result.append("Row");
96     case WebAccessibilityRoleToolbar:
97         return result.append("Toolbar");
98     case WebAccessibilityRoleBusyIndicator:
99         return result.append("BusyIndicator");
100     case WebAccessibilityRoleProgressIndicator:
101         return result.append("ProgressIndicator");
102     case WebAccessibilityRoleWindow:
103         return result.append("Window");
104     case WebAccessibilityRoleDrawer:
105         return result.append("Drawer");
106     case WebAccessibilityRoleSystemWide:
107         return result.append("SystemWide");
108     case WebAccessibilityRoleOutline:
109         return result.append("Outline");
110     case WebAccessibilityRoleIncrementor:
111         return result.append("Incrementor");
112     case WebAccessibilityRoleBrowser:
113         return result.append("Browser");
114     case WebAccessibilityRoleComboBox:
115         return result.append("ComboBox");
116     case WebAccessibilityRoleSplitGroup:
117         return result.append("SplitGroup");
118     case WebAccessibilityRoleSplitter:
119         return result.append("Splitter");
120     case WebAccessibilityRoleColorWell:
121         return result.append("ColorWell");
122     case WebAccessibilityRoleGrowArea:
123         return result.append("GrowArea");
124     case WebAccessibilityRoleSheet:
125         return result.append("Sheet");
126     case WebAccessibilityRoleHelpTag:
127         return result.append("HelpTag");
128     case WebAccessibilityRoleMatte:
129         return result.append("Matte");
130     case WebAccessibilityRoleRuler:
131         return result.append("Ruler");
132     case WebAccessibilityRoleRulerMarker:
133         return result.append("RulerMarker");
134     case WebAccessibilityRoleLink:
135         return result.append("Link");
136     case WebAccessibilityRoleDisclosureTriangle:
137         return result.append("DisclosureTriangle");
138     case WebAccessibilityRoleGrid:
139         return result.append("Grid");
140     case WebAccessibilityRoleCell:
141         return result.append("Cell");
142     case WebAccessibilityRoleColumnHeader:
143         return result.append("ColumnHeader");
144     case WebAccessibilityRoleRowHeader:
145         return result.append("RowHeader");
146     case WebAccessibilityRoleWebCoreLink:
147         // Maps to Link role.
148         return result.append("Link");
149     case WebAccessibilityRoleImageMapLink:
150         return result.append("ImageMapLink");
151     case WebAccessibilityRoleImageMap:
152         return result.append("ImageMap");
153     case WebAccessibilityRoleListMarker:
154         return result.append("ListMarker");
155     case WebAccessibilityRoleWebArea:
156         return result.append("WebArea");
157     case WebAccessibilityRoleHeading:
158         return result.append("Heading");
159     case WebAccessibilityRoleListBox:
160         return result.append("ListBox");
161     case WebAccessibilityRoleListBoxOption:
162         return result.append("ListBoxOption");
163     case WebAccessibilityRoleTableHeaderContainer:
164         return result.append("TableHeaderContainer");
165     case WebAccessibilityRoleDefinitionListTerm:
166         return result.append("DefinitionListTerm");
167     case WebAccessibilityRoleDefinitionListDefinition:
168         return result.append("DefinitionListDefinition");
169     case WebAccessibilityRoleAnnotation:
170         return result.append("Annotation");
171     case WebAccessibilityRoleSliderThumb:
172         return result.append("SliderThumb");
173     case WebAccessibilityRoleLandmarkApplication:
174         return result.append("LandmarkApplication");
175     case WebAccessibilityRoleLandmarkBanner:
176         return result.append("LandmarkBanner");
177     case WebAccessibilityRoleLandmarkComplementary:
178         return result.append("LandmarkComplementary");
179     case WebAccessibilityRoleLandmarkContentInfo:
180         return result.append("LandmarkContentInfo");
181     case WebAccessibilityRoleLandmarkMain:
182         return result.append("LandmarkMain");
183     case WebAccessibilityRoleLandmarkNavigation:
184         return result.append("LandmarkNavigation");
185     case WebAccessibilityRoleLandmarkSearch:
186         return result.append("LandmarkSearch");
187     case WebAccessibilityRoleApplicationLog:
188         return result.append("ApplicationLog");
189     case WebAccessibilityRoleApplicationMarquee:
190         return result.append("ApplicationMarquee");
191     case WebAccessibilityRoleApplicationStatus:
192         return result.append("ApplicationStatus");
193     case WebAccessibilityRoleApplicationTimer:
194         return result.append("ApplicationTimer");
195     case WebAccessibilityRoleDocument:
196         return result.append("Document");
197     case WebAccessibilityRoleDocumentArticle:
198         return result.append("DocumentArticle");
199     case WebAccessibilityRoleDocumentNote:
200         return result.append("DocumentNote");
201     case WebAccessibilityRoleDocumentRegion:
202         return result.append("DocumentRegion");
203     case WebAccessibilityRoleUserInterfaceTooltip:
204         return result.append("UserInterfaceTooltip");
205     default:
206         // Also matches WebAccessibilityRoleUnknown.
207         return result.append("Unknown");
208     }
209 }
210
211 string getDescription(const WebAccessibilityObject& object)
212 {
213     string description = object.accessibilityDescription().utf8();
214     return description.insert(0, "AXDescription: ");
215 }
216
217 string getRole(const WebAccessibilityObject& object)
218 {
219     return roleToString(object.roleValue());
220 }
221
222 string getTitle(const WebAccessibilityObject& object)
223 {
224     string title = object.title().utf8();
225     return title.insert(0, "AXTitle: ");
226 }
227
228 string getAttributes(const WebAccessibilityObject& object)
229 {
230     // FIXME: Concatenate all attributes of the AccessibilityObject.
231     string attributes(getTitle(object));
232     attributes.append("\n");
233     attributes.append(getRole(object));
234     attributes.append("\n");
235     attributes.append(getDescription(object));
236     return attributes;
237 }
238
239
240 // Collects attributes into a string, delimited by dashes. Used by all methods
241 // that output lists of attributes: attributesOfLinkedUIElementsCallback,
242 // AttributesOfChildrenCallback, etc.
243 class AttributesCollector {
244 public:
245     void collectAttributes(const WebAccessibilityObject& object)
246     {
247         m_attributes.append("\n------------\n");
248         m_attributes.append(getAttributes(object));
249     }
250
251     string attributes() const { return m_attributes; }
252
253 private:
254     string m_attributes;
255 };
256
257 AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory)
258     : m_accessibilityObject(object)
259     , m_factory(factory)
260 {
261
262     ASSERT(factory);
263
264     bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
265     bindMethod("attributesOfLinkedUIElements",
266                &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
267     bindMethod("attributesOfDocumentLinks",
268                &AccessibilityUIElement::attributesOfDocumentLinksCallback);
269     bindMethod("attributesOfChildren",
270                &AccessibilityUIElement::attributesOfChildrenCallback);
271     bindMethod("parameterizedAttributeNames",
272                &AccessibilityUIElement::parametrizedAttributeNamesCallback);
273     bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback);
274     bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback);
275     bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback);
276     bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback);
277     bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback);
278     bindMethod("attributesOfColumnHeaders",
279                &AccessibilityUIElement::attributesOfColumnHeadersCallback);
280     bindMethod("attributesOfRowHeaders",
281                &AccessibilityUIElement::attributesOfRowHeadersCallback);
282     bindMethod("attributesOfColumns",
283                &AccessibilityUIElement::attributesOfColumnsCallback);
284     bindMethod("attributesOfRows",
285                &AccessibilityUIElement::attributesOfRowsCallback);
286     bindMethod("attributesOfVisibleCells",
287                &AccessibilityUIElement::attributesOfVisibleCellsCallback);
288     bindMethod("attributesOfHeader",
289                &AccessibilityUIElement::attributesOfHeaderCallback);
290     bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback);
291     bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback);
292     bindMethod("columnIndexRange",
293                &AccessibilityUIElement::columnIndexRangeCallback);
294     bindMethod("cellForColumnAndRow",
295                &AccessibilityUIElement::cellForColumnAndRowCallback);
296     bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback);
297     bindMethod("setSelectedTextRange",
298                &AccessibilityUIElement::setSelectedTextRangeCallback);
299     bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback);
300     bindMethod("isAttributeSettable",
301                &AccessibilityUIElement::isAttributeSettableCallback);
302     bindMethod("isActionSupported",
303                &AccessibilityUIElement::isActionSupportedCallback);
304     bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback);
305     bindMethod("increment", &AccessibilityUIElement::incrementCallback);
306     bindMethod("decrement", &AccessibilityUIElement::decrementCallback);
307     bindMethod("isEqual", &AccessibilityUIElement::isEqualCallback);
308
309     bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
310     bindProperty("subrole", &m_subrole);
311     bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
312     bindProperty("description",
313                  &AccessibilityUIElement::descriptionGetterCallback);
314     bindProperty("language", &m_language);
315     bindProperty("x", &m_x);
316     bindProperty("y", &m_y);
317     bindProperty("width", &m_width);
318     bindProperty("height", &m_height);
319     bindProperty("clickPointX", &m_clickPointX);
320     bindProperty("clickPointY", &m_clickPointY);
321     bindProperty("intValue", &m_intValue);
322     bindProperty("minValue", &m_minValue);
323     bindProperty("maxValue", &m_maxValue);
324     bindProperty("childrenCount",
325                  &AccessibilityUIElement::childrenCountGetterCallback);
326     bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber);
327     bindProperty("selectedTextRange", &m_selectedTextRange);
328     bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
329     bindProperty("isRequired", &m_isRequired);
330     bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
331     bindProperty("valueDescription", &m_valueDescription);
332
333     bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
334 }
335
336 AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
337 {
338     return m_factory->create(accessibilityObject().childAt(index));
339 }
340
341 void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result)
342 {
343     result->set(getAttributes(accessibilityObject()));
344 }
345
346 void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result)
347 {
348     result->setNull();
349 }
350
351 void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result)
352 {
353     result->setNull();
354 }
355
356 void AccessibilityUIElement::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result)
357 {
358     AttributesCollector collector;
359     unsigned size = accessibilityObject().childCount();
360     for (unsigned i = 0; i < size; ++i)
361         collector.collectAttributes(accessibilityObject().childAt(i));
362     result->set(collector.attributes());
363 }
364
365 void AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result)
366 {
367     result->setNull();
368 }
369
370 void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result)
371 {
372     result->setNull();
373 }
374
375 void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result)
376 {
377     result->setNull();
378 }
379
380 void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result)
381 {
382     result->setNull();
383 }
384
385 void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
386 {
387     if (!arguments.size() || !arguments[0].isNumber()) {
388         result->setNull();
389         return;
390     }
391
392     AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32());
393     if (!child) {
394         result->setNull();
395         return;
396     }
397
398     result->set(*(child->getAsCppVariant()));
399 }
400
401 void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result)
402 {
403     result->setNull();
404 }
405
406 void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result)
407 {
408     result->setNull();
409 }
410
411 void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result)
412 {
413     result->setNull();
414 }
415
416 void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result)
417 {
418     result->setNull();
419 }
420
421 void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result)
422 {
423     result->setNull();
424 }
425
426 void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result)
427 {
428     result->setNull();
429 }
430
431 void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result)
432 {
433     result->setNull();
434 }
435
436 void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result)
437 {
438     result->setNull();
439 }
440
441 void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
442 {
443     result->setNull();
444 }
445
446 void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
447 {
448     result->setNull();
449 }
450
451 void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result)
452 {
453     result->setNull();
454 }
455
456 void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
457 {
458     result->setNull();
459 }
460
461 void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result)
462 {
463     result->setNull();
464 }
465
466 void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result)
467 {
468     result->setNull();
469 }
470
471 void AccessibilityUIElement::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result)
472 {
473     if (arguments.size() < 1 && !arguments[0].isString()) {
474         result->setNull();
475         return;
476     }
477
478     string attribute = arguments[0].toString();
479     bool settable = false;
480     if (attribute == "AXValue")
481         settable = accessibilityObject().canSetValueAttribute();
482     result->set(settable);
483 }
484
485 void AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result)
486 {
487     // This one may be really hard to implement.
488     // Not exposed by AccessibilityObject.
489     result->setNull();
490 }
491
492 void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result)
493 {
494     AccessibilityUIElement* parent = m_factory->create(accessibilityObject().parentObject());
495     if (parent)
496         result->set(*(parent->getAsCppVariant()));
497     else
498         result->setNull();        
499 }
500
501 void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result)
502 {
503     result->setNull();
504 }
505
506 void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result)
507 {
508     result->setNull();
509 }
510
511 void AccessibilityUIElement::isEqualCallback(const CppArgumentList& arguments, CppVariant* result)
512 {
513     bool equal = false;
514     AccessibilityUIElement* element = static_cast<AccessibilityUIElement*>(CppBoundClass::getFromCppVariant(arguments[0]));
515     if (element)
516         equal = accessibilityObject().equals(element->accessibilityObject());
517     result->set(equal);
518 }
519
520 void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
521 {
522     // FIXME: Implement this.
523     result->setNull();
524 }
525
526 void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result)
527 {
528     int count = 1; // Root object always has only one child, the WebView.
529     if (!isRoot())
530         count = accessibilityObject().childCount();
531     result->set(count);
532 }
533
534 void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result)
535 {
536     result->set(getDescription(accessibilityObject()));
537 }
538
539 void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
540 {
541     result->set(accessibilityObject().isEnabled());
542 }
543
544 void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
545 {
546     result->setNull();
547 }
548
549 void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
550 {
551     result->set(getRole(accessibilityObject()));
552 }
553
554 void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
555 {
556     result->set(getTitle(accessibilityObject()));
557 }
558
559
560 RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
561     : AccessibilityUIElement(object, factory) { }
562
563 AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
564 {
565     if (index)
566         return 0;
567
568     return factory()->create(accessibilityObject());
569 }
570
571
572 AccessibilityUIElementList ::~AccessibilityUIElementList()
573 {
574     clear();
575 }
576
577 void AccessibilityUIElementList::clear()
578 {
579     for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
580         delete (*i);
581     m_elements.clear();
582 }
583
584 AccessibilityUIElement* AccessibilityUIElementList::create(const WebAccessibilityObject& object)
585 {
586     if (object.isNull())
587         return 0;
588
589     AccessibilityUIElement* element = new AccessibilityUIElement(object, this);
590     m_elements.append(element);
591     return element;
592 }
593
594 AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object)
595 {
596     AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this);
597     m_elements.append(element);
598     return element;
599 }