blob: f7b05f11824d594f74ad323488a49dad0b5872c2 [file] [log] [blame]
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001/*
2 * Copyright (C) 2008 Nuanti Ltd.
jmalonzo@webkit.orgaaaea3b2009-08-08 07:39:48 +00003 * Copyright (C) 2009 Jan Alonzo
mario@webkit.org9adab662012-01-23 10:21:03 +00004 * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
mario@webkit.orgfecbacd2013-03-04 17:06:15 +00005 * Copyright (C) 2013 Samsung Electronics
xan@webkit.orge4387102009-04-09 11:08:48 +00006 *
7 * Portions from Mozilla a11y, copyright as follows:
8 *
9 * The Original Code is mozilla.org code.
10 *
11 * The Initial Developer of the Original Code is
12 * Sun Microsystems, Inc.
13 * Portions created by the Initial Developer are Copyright (C) 2002
14 * the Initial Developer. All Rights Reserved.
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000015 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Library General Public
18 * License as published by the Free Software Foundation; either
19 * version 2 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Library General Public License for more details.
25 *
26 * You should have received a copy of the GNU Library General Public License
27 * along with this library; see the file COPYING.LIB. If not, write to
28 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 * Boston, MA 02110-1301, USA.
30 */
31
32#include "config.h"
mario@webkit.org9adab662012-01-23 10:21:03 +000033#include "WebKitAccessibleWrapperAtk.h"
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000034
ddkilzer@apple.com8d878632008-11-09 19:50:37 +000035#if HAVE(ACCESSIBILITY)
36
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000037#include "AXObjectCache.h"
mario.prada@samsung.com4fb934b2013-12-17 18:08:34 +000038#include "AccessibilityList.h"
akling@apple.com88e05f62013-09-16 15:17:24 +000039#include "AccessibilityListBoxOption.h"
cdumez@apple.comb04d5742014-10-22 21:45:20 +000040#include "AccessibilityTable.h"
alp@webkit.orgc7738992008-05-27 02:48:14 +000041#include "Document.h"
alp@webkit.orgc7738992008-05-27 02:48:14 +000042#include "Frame.h"
43#include "FrameView.h"
xan@webkit.org9561b2c2009-05-20 14:33:19 +000044#include "HTMLNames.h"
xan@webkit.org45b26ac2009-10-27 12:20:35 +000045#include "HTMLTableElement.h"
mario@webkit.org9adab662012-01-23 10:21:03 +000046#include "HostWindow.h"
jdiggs@igalia.com3504d462016-03-16 01:45:57 +000047#include "RenderAncestorIterator.h"
48#include "RenderFieldset.h"
mario@webkit.org970eaf32012-01-24 18:37:45 +000049#include "RenderObject.h"
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +000050#include "SVGElement.h"
mario@webkit.org6a24ba12010-12-14 15:35:22 +000051#include "Settings.h"
commit-queue@webkit.org74bd2e82010-09-12 11:16:14 +000052#include "TextIterator.h"
tkent@chromium.org8c35c122013-03-06 13:00:14 +000053#include "VisibleUnits.h"
mario@webkit.org7f95c622010-11-01 15:05:36 +000054#include "WebKitAccessibleHyperlink.h"
mario@webkit.orgdeec8392012-01-23 14:45:23 +000055#include "WebKitAccessibleInterfaceAction.h"
mario@webkit.orgbe1ce552012-01-24 11:03:51 +000056#include "WebKitAccessibleInterfaceComponent.h"
mario@webkit.orgf8344ff2012-01-24 11:40:44 +000057#include "WebKitAccessibleInterfaceDocument.h"
mario@webkit.orgfc51ca62012-01-24 11:47:51 +000058#include "WebKitAccessibleInterfaceEditableText.h"
mario@webkit.org4dbd9822012-01-24 11:55:18 +000059#include "WebKitAccessibleInterfaceHyperlinkImpl.h"
mario@webkit.org70243532012-01-24 11:58:52 +000060#include "WebKitAccessibleInterfaceHypertext.h"
mario@webkit.orgda3e6082012-01-24 12:04:16 +000061#include "WebKitAccessibleInterfaceImage.h"
mario@webkit.org7e5931d2012-01-24 12:25:13 +000062#include "WebKitAccessibleInterfaceSelection.h"
mario@webkit.orgcd9f1b32012-01-24 18:28:22 +000063#include "WebKitAccessibleInterfaceTable.h"
k.czech@samsung.com2608de92014-02-27 11:28:31 +000064#include "WebKitAccessibleInterfaceTableCell.h"
mario@webkit.org987d7372012-01-24 18:02:08 +000065#include "WebKitAccessibleInterfaceText.h"
mario@webkit.org980269e2012-01-24 16:22:57 +000066#include "WebKitAccessibleInterfaceValue.h"
mario@webkit.org7ceffa42012-01-23 11:55:01 +000067#include "WebKitAccessibleUtil.h"
mario@webkit.orgba16aea2011-04-13 16:33:02 +000068#include "htmlediting.h"
xan@webkit.orge4387102009-04-09 11:08:48 +000069#include <glib/gprintf.h>
benjamin@webkit.org9d72cb02013-04-22 22:52:23 +000070#include <wtf/text/CString.h>
mario@webkit.org8c5dd902012-11-09 19:47:40 +000071
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000072using namespace WebCore;
73
mario@webkit.orgfecbacd2013-03-04 17:06:15 +000074struct _WebKitAccessiblePrivate {
75 // Cached data for AtkObject.
76 CString accessibleName;
77 CString accessibleDescription;
78
79 // Cached data for AtkAction.
80 CString actionName;
81 CString actionKeyBinding;
82
83 // Cached data for AtkDocument.
84 CString documentLocale;
85 CString documentType;
86 CString documentEncoding;
87 CString documentURI;
88
89 // Cached data for AtkImage.
90 CString imageDescription;
91};
92
93#define WEBKIT_ACCESSIBLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessiblePrivate))
94
xan@webkit.orgc886cc62009-04-09 11:17:48 +000095static AccessibilityObject* fallbackObject()
96{
akling@apple.comad2beb52014-12-25 07:50:20 +000097 static AccessibilityObject* object = &AccessibilityListBoxOption::create().leakRef();
xan@webkit.orgc886cc62009-04-09 11:17:48 +000098 return object;
99}
100
alp@webkit.orgc7738992008-05-27 02:48:14 +0000101static AccessibilityObject* core(AtkObject* object)
102{
103 if (!WEBKIT_IS_ACCESSIBLE(object))
104 return 0;
105
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000106 return webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(object));
alp@webkit.orgc7738992008-05-27 02:48:14 +0000107}
108
mario@webkit.org5c966772012-01-24 18:48:50 +0000109static const gchar* webkitAccessibleGetName(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000110{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000111 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
112 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
113
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000114 Vector<AccessibilityText> textOrder;
115 core(object)->accessibilityText(textOrder);
116
117 for (const auto& text : textOrder) {
118 // FIXME: This check is here because AccessibilityNodeObject::titleElementText()
119 // appends an empty String for the LabelByElementText source when there is a
120 // titleUIElement(). Removing this check makes some fieldsets lose their name.
121 if (text.text.isEmpty())
122 continue;
123
124 // WebCore Accessibility should provide us with the text alternative computation
125 // in the order defined by that spec. So take the first thing that our platform
126 // does not expose via the AtkObject description.
127 if (text.textSource != HelpText && text.textSource != SummaryText)
128 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, text.text);
commit-queue@webkit.org802c0122012-09-11 01:41:27 +0000129 }
130
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000131 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, "");
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000132}
133
mario@webkit.org5c966772012-01-24 18:48:50 +0000134static const gchar* webkitAccessibleGetDescription(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000135{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000136 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
137 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
138
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000139 Vector<AccessibilityText> textOrder;
140 core(object)->accessibilityText(textOrder);
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000141
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000142 bool nameTextAvailable = false;
143 for (const auto& text : textOrder) {
144 // WebCore Accessibility should provide us with the text alternative computation
145 // in the order defined by that spec. So take the first thing that our platform
146 // does not expose via the AtkObject name.
147 if (text.textSource == HelpText || text.textSource == SummaryText)
148 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000149
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000150 // If there is no other text alternative, the title tag contents will have been
151 // used for the AtkObject name. We don't want to duplicate it here.
152 if (text.textSource == TitleTagText && nameTextAvailable)
153 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
154
155 nameTextAvailable = true;
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000156 }
157
jdiggs@igalia.come184cee2016-05-18 07:12:09 +0000158 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, "");
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000159}
160
m.pakula@samsung.come026b6a2013-11-06 18:17:03 +0000161static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType)
162{
163 int count = atk_relation_set_get_n_relations(relationSet);
164 for (int i = 0; i < count; i++) {
165 AtkRelation* relation = atk_relation_set_get_relation(relationSet, i);
166 if (atk_relation_get_relation_type(relation) == relationType) {
167 atk_relation_set_remove(relationSet, relation);
168 break;
169 }
170 }
171}
172
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000173static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
174{
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000175 // FIXME: We're not implementing all the relation types, most notably the inverse/reciprocal
176 // types. Filed as bug 155494.
commit-queue@webkit.org802c0122012-09-11 01:41:27 +0000177
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000178 // Elements with aria-labelledby should have the labelled-by relation as per the ARIA AAM spec.
179 // Controls with a label element and fieldsets with a legend element should also use this relation
180 // as per the HTML AAM spec. The reciprocal label-for relation should also be used.
181 removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
mario@webkit.org7e9f2412011-04-06 16:50:25 +0000182 if (coreObject->isControl()) {
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000183 if (AccessibilityObject* label = coreObject->correspondingLabelForControlElement())
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000184 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000185 } else if (coreObject->isFieldset()) {
186 if (AccessibilityObject* label = coreObject->titleUIElement())
187 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
188 } else if (coreObject->roleValue() == LegendRole) {
189 if (RenderFieldset* renderFieldset = ancestorsOfType<RenderFieldset>(*coreObject->renderer()).first()) {
190 AccessibilityObject* fieldset = coreObject->axObjectCache()->getOrCreate(renderFieldset);
191 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, fieldset->wrapper());
m.pakula@samsung.come026b6a2013-11-06 18:17:03 +0000192 }
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000193 } else if (AccessibilityObject* control = coreObject->correspondingControlForLabelElement()) {
194 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000195 } else {
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000196 AccessibilityObject::AccessibilityChildrenVector ariaLabelledByElements;
197 coreObject->ariaLabelledByElements(ariaLabelledByElements);
198 for (const auto& accessibilityObject : ariaLabelledByElements)
199 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, accessibilityObject->wrapper());
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000200 }
k.czech@samsung.com22545812014-01-21 09:10:25 +0000201
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000202 // Elements with aria-flowto should have the flows-to relation as per the ARIA AAM spec.
203 removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
204 AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
205 coreObject->ariaFlowToElements(ariaFlowToElements);
206 for (const auto& accessibilityObject : ariaFlowToElements)
207 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, accessibilityObject->wrapper());
k.czech@samsung.com7e9868e2014-01-29 13:16:27 +0000208
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000209 // Elements with aria-describedby should have the described-by relation as per the ARIA AAM spec.
210 removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIBED_BY);
211 AccessibilityObject::AccessibilityChildrenVector ariaDescribedByElements;
212 coreObject->ariaDescribedByElements(ariaDescribedByElements);
213 for (const auto& accessibilityObject : ariaDescribedByElements)
214 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY, accessibilityObject->wrapper());
k.czech@samsung.comb8ad4bf2014-02-03 09:16:54 +0000215
jdiggs@igalia.com3504d462016-03-16 01:45:57 +0000216 // Elements with aria-controls should have the controller-for relation as per the ARIA AAM spec.
217 removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLER_FOR);
218 AccessibilityObject::AccessibilityChildrenVector ariaControls;
219 coreObject->ariaControlsElements(ariaControls);
220 for (const auto& accessibilityObject : ariaControls)
221 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLER_FOR, accessibilityObject->wrapper());
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000222}
223
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +0000224static gpointer webkitAccessibleParentClass = nullptr;
eric@webkit.orgb84b4742009-10-20 21:20:50 +0000225
mario@webkit.org86390a12011-01-07 17:34:02 +0000226static bool isRootObject(AccessibilityObject* coreObject)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000227{
mario@webkit.org86390a12011-01-07 17:34:02 +0000228 // The root accessible object in WebCore is always an object with
229 // the ScrolledArea role with one child with the WebArea role.
230 if (!coreObject || !coreObject->isScrollView())
231 return false;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000232
mario@webkit.org86390a12011-01-07 17:34:02 +0000233 AccessibilityObject* firstChild = coreObject->firstChild();
234 if (!firstChild || !firstChild->isWebArea())
235 return false;
236
237 return true;
238}
239
240static AtkObject* atkParentOfRootObject(AtkObject* object)
241{
242 AccessibilityObject* coreObject = core(object);
243 AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
244
245 // The top level object claims to not have a parent. This makes it
eric@webkit.org03b220b2009-10-19 11:58:38 +0000246 // impossible for assistive technologies to ascend the accessible
247 // hierarchy all the way to the application. (Bug 30489)
mario@webkit.org86390a12011-01-07 17:34:02 +0000248 if (!coreParent && isRootObject(coreObject)) {
mario@webkit.org8d00fa72011-04-13 16:27:23 +0000249 Document* document = coreObject->document();
250 if (!document)
251 return 0;
eric@webkit.org03b220b2009-10-19 11:58:38 +0000252 }
253
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000254 if (!coreParent)
eric@webkit.org1f5f7fe2009-11-04 10:35:56 +0000255 return 0;
256
257 return coreParent->wrapper();
258}
259
mario@webkit.org5c966772012-01-24 18:48:50 +0000260static AtkObject* webkitAccessibleGetParent(AtkObject* object)
eric@webkit.org1f5f7fe2009-11-04 10:35:56 +0000261{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000262 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
263 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
264
mario@webkit.org46e9b262011-11-17 11:50:07 +0000265 // Check first if the parent has been already set.
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000266 AtkObject* accessibleParent = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->get_parent(object);
mario@webkit.org46e9b262011-11-17 11:50:07 +0000267 if (accessibleParent)
268 return accessibleParent;
269
270 // Parent not set yet, so try to find it in the hierarchy.
mario@webkit.org86390a12011-01-07 17:34:02 +0000271 AccessibilityObject* coreObject = core(object);
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000272 if (!coreObject)
273 return 0;
274
mario@webkit.org86390a12011-01-07 17:34:02 +0000275 AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000276
mario@webkit.org86390a12011-01-07 17:34:02 +0000277 if (!coreParent && isRootObject(coreObject))
278 return atkParentOfRootObject(object);
eric@webkit.org1f5f7fe2009-11-04 10:35:56 +0000279
280 if (!coreParent)
281 return 0;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000282
283 return coreParent->wrapper();
284}
285
mario@webkit.org5c966772012-01-24 18:48:50 +0000286static gint webkitAccessibleGetNChildren(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000287{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000288 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
289 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
290
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000291 AccessibilityObject* coreObject = core(object);
292
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000293 return coreObject->children().size();
294}
295
mario@webkit.org5c966772012-01-24 18:48:50 +0000296static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000297{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000298 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
299 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
300
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000301 if (index < 0)
eric@webkit.orgdbd4d402009-11-04 09:31:06 +0000302 return 0;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000303
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000304 AccessibilityObject* coreObject = core(object);
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +0000305 AccessibilityObject* coreChild = nullptr;
mario@webkit.org868b5ea2011-06-24 09:06:32 +0000306
jdiggs@igalia.come8a090d2014-12-03 02:02:36 +0000307 const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
308 if (static_cast<size_t>(index) >= children.size())
309 return 0;
310 coreChild = children.at(index).get();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000311
312 if (!coreChild)
eric@webkit.org4ff6fd72009-11-10 09:53:33 +0000313 return 0;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000314
315 AtkObject* child = coreChild->wrapper();
eric@webkit.orgb84b4742009-10-20 21:20:50 +0000316 atk_object_set_parent(child, object);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000317 g_object_ref(child);
318
319 return child;
320}
321
mario@webkit.org5c966772012-01-24 18:48:50 +0000322static gint webkitAccessibleGetIndexInParent(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000323{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000324 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), -1);
325 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), -1);
326
xan@webkit.org1f5349a2009-10-27 09:20:21 +0000327 AccessibilityObject* coreObject = core(object);
328 AccessibilityObject* parent = coreObject->parentObjectUnignored();
329
mario@webkit.org86390a12011-01-07 17:34:02 +0000330 if (!parent && isRootObject(coreObject)) {
331 AtkObject* atkParent = atkParentOfRootObject(object);
eric@webkit.org1f5f7fe2009-11-04 10:35:56 +0000332 if (!atkParent)
333 return -1;
334
335 unsigned count = atk_object_get_n_accessible_children(atkParent);
336 for (unsigned i = 0; i < count; ++i) {
337 AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
338 bool childIsObject = child == object;
339 g_object_unref(child);
340 if (childIsObject)
341 return i;
342 }
343 }
xan@webkit.org1f5349a2009-10-27 09:20:21 +0000344
commit-queue@webkit.org54a624e2013-01-16 18:00:17 +0000345 if (!parent)
346 return -1;
347
commit-queue@webkit.orgbf183552012-02-22 09:28:57 +0000348 size_t index = parent->children().find(coreObject);
349 return (index == WTF::notFound) ? -1 : index;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000350}
351
mario@webkit.org5c966772012-01-24 18:48:50 +0000352static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
eric@webkit.org84496192009-10-17 20:00:33 +0000353{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000354 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
355 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
356
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +0000357 AtkAttributeSet* attributeSet = nullptr;
mario@webkit.org8c5dd902012-11-09 19:47:40 +0000358#if PLATFORM(GTK)
mario@webkit.orgf8344ff2012-01-24 11:40:44 +0000359 attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
commit-queue@webkit.orgd9947352012-12-05 17:56:12 +0000360#elif PLATFORM(EFL)
361 attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitEfl");
mario@webkit.org8c5dd902012-11-09 19:47:40 +0000362#endif
eric@webkit.orgf4efc402010-05-15 09:55:52 +0000363
commit-queue@webkit.orga9398dd2010-10-26 19:19:29 +0000364 AccessibilityObject* coreObject = core(object);
365 if (!coreObject)
366 return attributeSet;
367
commit-queue@webkit.org357dc222013-01-10 00:09:41 +0000368 // Hack needed for WebKit2 tests because obtaining an element by its ID
369 // cannot be done from the UIProcess. Assistive technologies have no need
370 // for this information.
jdiggs@igalia.combcff9522014-11-28 00:24:43 +0000371 Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
372 if (element) {
jdiggs@igalia.com5a8352d2015-06-17 20:03:13 +0000373 String tagName = element->tagName();
374 if (!tagName.isEmpty())
darin@apple.com4d716f22016-02-01 05:46:20 +0000375 attributeSet = addToAtkAttributeSet(attributeSet, "tag", tagName.convertToASCIILowercase().utf8().data());
jdiggs@igalia.combcff9522014-11-28 00:24:43 +0000376 String id = element->getIdAttribute().string();
commit-queue@webkit.org357dc222013-01-10 00:09:41 +0000377 if (!id.isEmpty())
378 attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
379 }
380
commit-queue@webkit.orga9398dd2010-10-26 19:19:29 +0000381 int headingLevel = coreObject->headingLevel();
eric@webkit.org84496192009-10-17 20:00:33 +0000382 if (headingLevel) {
383 String value = String::number(headingLevel);
mario@webkit.orgf8344ff2012-01-24 11:40:44 +0000384 attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
eric@webkit.org84496192009-10-17 20:00:33 +0000385 }
commit-queue@webkit.orga9398dd2010-10-26 19:19:29 +0000386
jdiggs@igalia.com6b8c1732015-01-28 17:02:32 +0000387 if (coreObject->roleValue() == MathElementRole) {
388 if (coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PreSubscript))
389 attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
390 else if (coreObject->isMathMultiscriptObject(PostSuperscript) || coreObject->isMathMultiscriptObject(PostSubscript))
391 attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
392 }
393
commit-queue@webkit.orga9398dd2010-10-26 19:19:29 +0000394 // Set the 'layout-guess' attribute to help Assistive
395 // Technologies know when an exposed table is not data table.
cdumez@apple.comb04d5742014-10-22 21:45:20 +0000396 if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposableThroughAccessibility() && !coreObject->isDataTable())
mario@webkit.orgf8344ff2012-01-24 11:40:44 +0000397 attributeSet = addToAtkAttributeSet(attributeSet, "layout-guess", "true");
commit-queue@webkit.orga9398dd2010-10-26 19:19:29 +0000398
commit-queue@webkit.org2db4aaa2012-12-10 01:09:32 +0000399 String placeholder = coreObject->placeholderValue();
400 if (!placeholder.isEmpty())
401 attributeSet = addToAtkAttributeSet(attributeSet, "placeholder-text", placeholder.utf8().data());
402
commit-queue@webkit.org5945f762013-07-16 12:55:56 +0000403 if (coreObject->ariaHasPopup())
mario@webkit.orge2f7e782013-09-18 08:28:59 +0000404 attributeSet = addToAtkAttributeSet(attributeSet, "haspopup", "true");
commit-queue@webkit.org5945f762013-07-16 12:55:56 +0000405
commit-queue@webkit.org88d00b62013-09-03 11:29:33 +0000406 AccessibilitySortDirection sortDirection = coreObject->sortDirection();
mario@webkit.orge2f7e782013-09-18 08:28:59 +0000407 if (sortDirection != SortDirectionNone) {
mario@webkit.org9bf82612013-09-27 08:58:08 +0000408 // WAI-ARIA spec says to translate the value as is from the attribute.
409 const AtomicString& sortAttribute = coreObject->getAttribute(HTMLNames::aria_sortAttr);
410 attributeSet = addToAtkAttributeSet(attributeSet, "sort", sortAttribute.string().utf8().data());
mario@webkit.orge2f7e782013-09-18 08:28:59 +0000411 }
commit-queue@webkit.org88d00b62013-09-03 11:29:33 +0000412
k.czech@samsung.comdcc76c72014-03-11 09:04:08 +0000413 if (coreObject->supportsARIAPosInSet())
414 attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->ariaPosInSet()).utf8().data());
415
416 if (coreObject->supportsARIASetSize())
417 attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->ariaSetSize()).utf8().data());
418
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +0000419 String isReadOnly = coreObject->ariaReadOnlyValue();
420 if (!isReadOnly.isEmpty())
421 attributeSet = addToAtkAttributeSet(attributeSet, "readonly", isReadOnly.utf8().data());
422
jdiggs@igalia.com6ccb7782016-05-18 18:57:33 +0000423 String valueDescription = coreObject->valueDescription();
424 if (!valueDescription.isEmpty())
425 attributeSet = addToAtkAttributeSet(attributeSet, "valuetext", valueDescription.utf8().data());
426
jdiggs@igalia.com55b92622015-05-22 06:12:05 +0000427 // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
428 // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
429 // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
430 // The computedRoleString is primarily for testing, and not limited to elements with ARIA roles.
431 // Because the computedRoleString currently contains the ARIA role string, we'll use it for
432 // both purposes, as the "computed-role" object attribute for all elements which have a value
433 // and also via the "xml-roles" attribute for elements with ARIA, as well as for landmarks.
434 String roleString = coreObject->computedRoleString();
435 if (!roleString.isEmpty()) {
436 if (coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isLandmark())
437 attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", roleString.utf8().data());
438 attributeSet = addToAtkAttributeSet(attributeSet, "computed-role", roleString.utf8().data());
mario.prada@samsung.come10ceaa2013-12-11 19:49:39 +0000439 }
440
jdiggs@igalia.com9cef8aa2016-04-29 16:44:30 +0000441 String roleDescription = coreObject->roleDescription();
442 if (!roleDescription.isEmpty())
443 attributeSet = addToAtkAttributeSet(attributeSet, "roledescription", roleDescription.utf8().data());
444
eric@webkit.org84496192009-10-17 20:00:33 +0000445 return attributeSet;
446}
447
mario.prada@samsung.com4fb934b2013-12-17 18:08:34 +0000448static AtkRole atkRole(AccessibilityObject* coreObject)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000449{
mario.prada@samsung.com4fb934b2013-12-17 18:08:34 +0000450 AccessibilityRole role = coreObject->roleValue();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000451 switch (role) {
mario.prada@samsung.com810148f2013-12-10 20:11:18 +0000452 case ApplicationAlertDialogRole:
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000453 case ApplicationAlertRole:
454 return ATK_ROLE_ALERT;
455 case ApplicationDialogRole:
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000456 return ATK_ROLE_DIALOG;
457 case ApplicationStatusRole:
458 return ATK_ROLE_STATUSBAR;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000459 case UnknownRole:
460 return ATK_ROLE_UNKNOWN;
mario@webkit.org53239522013-11-07 11:12:23 +0000461 case AudioRole:
jdiggs@igalia.comc7a2f562014-11-16 07:32:08 +0000462#if ATK_CHECK_VERSION(2, 11, 3)
463 return ATK_ROLE_AUDIO;
464#endif
mario@webkit.org53239522013-11-07 11:12:23 +0000465 case VideoRole:
jdiggs@igalia.comc7a2f562014-11-16 07:32:08 +0000466#if ATK_CHECK_VERSION(2, 11, 3)
467 return ATK_ROLE_VIDEO;
468#endif
mario@webkit.org53239522013-11-07 11:12:23 +0000469 return ATK_ROLE_EMBEDDED;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000470 case ButtonRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000471 return ATK_ROLE_PUSH_BUTTON;
jdiggs@igalia.com26fff3c2015-02-25 01:43:42 +0000472 case SwitchRole:
commit-queue@webkit.org6152cb92012-08-23 00:36:06 +0000473 case ToggleButtonRole:
474 return ATK_ROLE_TOGGLE_BUTTON;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000475 case RadioButtonRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000476 return ATK_ROLE_RADIO_BUTTON;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000477 case CheckBoxRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000478 return ATK_ROLE_CHECK_BOX;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000479 case SliderRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000480 return ATK_ROLE_SLIDER;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000481 case TabGroupRole:
commit-queue@webkit.org52553892012-12-13 15:43:38 +0000482 case TabListRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000483 return ATK_ROLE_PAGE_TAB_LIST;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000484 case TextFieldRole:
485 case TextAreaRole:
jdiggs@igalia.com2588aa12015-02-25 10:04:16 +0000486 case SearchFieldRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000487 return ATK_ROLE_ENTRY;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000488 case StaticTextRole:
jdiggs@igalia.com12f11cb2016-04-29 13:08:03 +0000489#if ATK_CHECK_VERSION(2, 15, 2)
490 return ATK_ROLE_STATIC;
491#else
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000492 return ATK_ROLE_TEXT;
jdiggs@igalia.com12f11cb2016-04-29 13:08:03 +0000493#endif
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000494 case OutlineRole:
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000495 case TreeRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000496 return ATK_ROLE_TREE;
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000497 case TreeItemRole:
498 return ATK_ROLE_TREE_ITEM;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000499 case MenuBarRole:
500 return ATK_ROLE_MENU_BAR;
eric@webkit.orga0669292010-04-22 14:36:19 +0000501 case MenuListPopupRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000502 case MenuRole:
503 return ATK_ROLE_MENU;
eric@webkit.orga0669292010-04-22 14:36:19 +0000504 case MenuListOptionRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000505 case MenuItemRole:
506 return ATK_ROLE_MENU_ITEM;
mario.prada@samsung.com092b72a2013-12-16 15:58:34 +0000507 case MenuItemCheckboxRole:
508 return ATK_ROLE_CHECK_MENU_ITEM;
commit-queue@webkit.org413f75b2013-09-11 11:31:14 +0000509 case MenuItemRadioRole:
510 return ATK_ROLE_RADIO_MENU_ITEM;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000511 case ColumnRole:
mario@webkit.org9adab662012-01-23 10:21:03 +0000512 // return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000513 return ATK_ROLE_UNKNOWN; // Matches Mozilla
514 case RowRole:
jdiggs@igalia.come8a090d2014-12-03 02:02:36 +0000515 return ATK_ROLE_TABLE_ROW;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000516 case ToolbarRole:
517 return ATK_ROLE_TOOL_BAR;
518 case BusyIndicatorRole:
519 return ATK_ROLE_PROGRESS_BAR; // Is this right?
520 case ProgressIndicatorRole:
jdiggs@igalia.com6ccb7782016-05-18 18:57:33 +0000521 return coreObject->isMeter() ? ATK_ROLE_LEVEL_BAR : ATK_ROLE_PROGRESS_BAR;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000522 case WindowRole:
523 return ATK_ROLE_WINDOW;
eric@webkit.orga0669292010-04-22 14:36:19 +0000524 case PopUpButtonRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000525 case ComboBoxRole:
526 return ATK_ROLE_COMBO_BOX;
527 case SplitGroupRole:
528 return ATK_ROLE_SPLIT_PANE;
529 case SplitterRole:
mario.prada@samsung.comae97a652013-12-10 20:12:56 +0000530 return ATK_ROLE_SEPARATOR;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000531 case ColorWellRole:
jdiggs@igalia.comfeb6f002015-02-24 17:20:01 +0000532#if PLATFORM(GTK)
533 // ATK_ROLE_COLOR_CHOOSER is defined as a dialog (i.e. it's what appears when you push the button).
534 return ATK_ROLE_PUSH_BUTTON;
535#elif PLATFORM(EFL)
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000536 return ATK_ROLE_COLOR_CHOOSER;
jdiggs@igalia.comfeb6f002015-02-24 17:20:01 +0000537#endif
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000538 case ListRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000539 return ATK_ROLE_LIST;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000540 case ScrollBarRole:
541 return ATK_ROLE_SCROLL_BAR;
mario@webkit.org86390a12011-01-07 17:34:02 +0000542 case ScrollAreaRole:
543 return ATK_ROLE_SCROLL_PANE;
jdiggs@igalia.com99deeb32015-12-08 11:07:11 +0000544 case GridRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000545 case TableRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000546 return ATK_ROLE_TABLE;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000547 case ApplicationRole:
548 return ATK_ROLE_APPLICATION;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000549 case RadioGroupRole:
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000550 case SVGRootRole:
commit-queue@webkit.org52553892012-12-13 15:43:38 +0000551 case TabPanelRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000552 return ATK_ROLE_PANEL;
jdiggs@igalia.com6bb2ed42016-04-06 19:13:50 +0000553 case GroupRole:
554 return coreObject->isStyleFormatGroup() ? ATK_ROLE_SECTION : ATK_ROLE_PANEL;
commit-queue@webkit.orgc150a072014-10-10 08:32:58 +0000555 case RowHeaderRole:
556 return ATK_ROLE_ROW_HEADER;
557 case ColumnHeaderRole:
558 return ATK_ROLE_COLUMN_HEADER;
jdiggs@igalia.come8a090d2014-12-03 02:02:36 +0000559 case CaptionRole:
560 return ATK_ROLE_CAPTION;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000561 case CellRole:
jdiggs@igalia.com99deeb32015-12-08 11:07:11 +0000562 case GridCellRole:
jdiggs@igalia.com63bfc542014-06-05 23:53:17 +0000563 return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000564 case LinkRole:
565 case WebCoreLinkRole:
566 case ImageMapLinkRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000567 return ATK_ROLE_LINK;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000568 case ImageMapRole:
jdiggs@igalia.com51d2ebf2014-11-22 18:18:11 +0000569 return ATK_ROLE_IMAGE_MAP;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000570 case ImageRole:
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000571 return ATK_ROLE_IMAGE;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000572 case ListMarkerRole:
jmalonzo@webkit.orgad9783b2009-05-23 22:22:52 +0000573 return ATK_ROLE_TEXT;
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000574 case DocumentArticleRole:
mario.prada@samsung.com2a1d5622013-12-16 15:17:58 +0000575#if ATK_CHECK_VERSION(2, 11, 3)
576 return ATK_ROLE_ARTICLE;
577#endif
578 case DocumentRole:
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000579 return ATK_ROLE_DOCUMENT_FRAME;
mario.prada@samsung.comc4a5eca2013-12-16 16:18:30 +0000580 case DocumentNoteRole:
581 return ATK_ROLE_COMMENT;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000582 case HeadingRole:
583 return ATK_ROLE_HEADING;
584 case ListBoxRole:
jdiggs@igalia.comb0b62552016-11-19 21:12:24 +0000585 // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-listbox
586 return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU : ATK_ROLE_LIST_BOX;
cfleizach@apple.com432ee572010-06-15 06:17:18 +0000587 case ListItemRole:
jdiggs@igalia.com63bfc542014-06-05 23:53:17 +0000588 return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
xan@webkit.org0ea2f732009-04-27 21:56:05 +0000589 case ListBoxOptionRole:
jdiggs@igalia.comb0b62552016-11-19 21:12:24 +0000590 return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU_ITEM : ATK_ROLE_LIST_ITEM;
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000591 case ParagraphRole:
592 return ATK_ROLE_PARAGRAPH;
593 case LabelRole:
commit-queue@webkit.org802c0122012-09-11 01:41:27 +0000594 case LegendRole:
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000595 return ATK_ROLE_LABEL;
jdiggs@igalia.comabd4d5f2014-11-16 16:51:08 +0000596 case BlockquoteRole:
597#if ATK_CHECK_VERSION(2, 11, 3)
598 return ATK_ROLE_BLOCK_QUOTE;
599#endif
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000600 case DivRole:
jdiggs@igalia.com7d43a732015-05-07 17:30:00 +0000601 case PreRole:
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000602 case SVGTextRole:
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000603 return ATK_ROLE_SECTION;
jdiggs@igalia.com45e97142014-11-16 07:26:41 +0000604 case FooterRole:
605 return ATK_ROLE_FOOTER;
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000606 case FormRole:
607 return ATK_ROLE_FORM;
commit-queue@webkit.org52f67612012-09-07 05:09:04 +0000608 case CanvasRole:
609 return ATK_ROLE_CANVAS;
dmazzoni@google.comf3cf2c42012-09-07 23:46:45 +0000610 case HorizontalRuleRole:
611 return ATK_ROLE_SEPARATOR;
commit-queue@webkit.orgc985400e2012-09-21 20:03:57 +0000612 case SpinButtonRole:
613 return ATK_ROLE_SPIN_BUTTON;
commit-queue@webkit.org52553892012-12-13 15:43:38 +0000614 case TabRole:
615 return ATK_ROLE_PAGE_TAB;
commit-queue@webkit.orgb68dfdf2013-12-06 13:58:38 +0000616 case UserInterfaceTooltipRole:
617 return ATK_ROLE_TOOL_TIP;
618 case WebAreaRole:
619 return ATK_ROLE_DOCUMENT_WEB;
jdiggs@igalia.com4ccb70f2016-04-09 01:19:07 +0000620 case WebApplicationRole:
mario.prada@samsung.come10ceaa2013-12-11 19:49:39 +0000621 return ATK_ROLE_EMBEDDED;
622#if ATK_CHECK_VERSION(2, 11, 3)
mario.prada@samsung.comc4a5eca2013-12-16 16:18:30 +0000623 case ApplicationLogRole:
624 return ATK_ROLE_LOG;
625 case ApplicationMarqueeRole:
626 return ATK_ROLE_MARQUEE;
627 case ApplicationTimerRole:
628 return ATK_ROLE_TIMER;
629 case DefinitionRole:
630 return ATK_ROLE_DEFINITION;
631 case DocumentMathRole:
632 return ATK_ROLE_MATH;
jdiggs@igalia.com0f83ca32014-12-09 18:31:53 +0000633 case MathElementRole:
634 if (coreObject->isMathRow())
635 return ATK_ROLE_PANEL;
636 if (coreObject->isMathTable())
637 return ATK_ROLE_TABLE;
638 if (coreObject->isMathTableRow())
639 return ATK_ROLE_TABLE_ROW;
640 if (coreObject->isMathTableCell())
641 return ATK_ROLE_TABLE_CELL;
jdiggs@igalia.com6b8c1732015-01-28 17:02:32 +0000642 if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
643 return ATK_ROLE_SECTION;
644#if ATK_CHECK_VERSION(2, 15, 4)
645 if (coreObject->isMathFraction())
646 return ATK_ROLE_MATH_FRACTION;
647 if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
648 return ATK_ROLE_MATH_ROOT;
649 if (coreObject->isMathScriptObject(Subscript)
650 || coreObject->isMathMultiscriptObject(PreSubscript) || coreObject->isMathMultiscriptObject(PostSubscript))
651 return ATK_ROLE_SUBSCRIPT;
652 if (coreObject->isMathScriptObject(Superscript)
653 || coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PostSuperscript))
654 return ATK_ROLE_SUPERSCRIPT;
655#endif
jdiggs@igalia.com0f83ca32014-12-09 18:31:53 +0000656#if ATK_CHECK_VERSION(2, 15, 2)
657 if (coreObject->isMathToken())
658 return ATK_ROLE_STATIC;
659#endif
660 return ATK_ROLE_UNKNOWN;
mario.prada@samsung.come10ceaa2013-12-11 19:49:39 +0000661 case LandmarkBannerRole:
662 case LandmarkComplementaryRole:
663 case LandmarkContentInfoRole:
664 case LandmarkMainRole:
665 case LandmarkNavigationRole:
jdiggs@igalia.com571fd1a62016-05-04 12:54:59 +0000666 case LandmarkRegionRole:
mario.prada@samsung.come10ceaa2013-12-11 19:49:39 +0000667 case LandmarkSearchRole:
668 return ATK_ROLE_LANDMARK;
669#endif
mario.prada@samsung.com4fb934b2013-12-17 18:08:34 +0000670#if ATK_CHECK_VERSION(2, 11, 4)
671 case DescriptionListRole:
672 return ATK_ROLE_DESCRIPTION_LIST;
673 case DescriptionListTermRole:
674 return ATK_ROLE_DESCRIPTION_TERM;
675 case DescriptionListDetailRole:
676 return ATK_ROLE_DESCRIPTION_VALUE;
677#endif
jdiggs@igalia.com85721d12014-12-03 19:51:28 +0000678 case InlineRole:
jdiggs@igalia.com0ec0d332016-04-29 01:30:34 +0000679#if ATK_CHECK_VERSION(2, 15, 4)
680 if (coreObject->isSubscriptStyleGroup())
681 return ATK_ROLE_SUBSCRIPT;
682 if (coreObject->isSuperscriptStyleGroup())
683 return ATK_ROLE_SUPERSCRIPT;
684#endif
685#if ATK_CHECK_VERSION(2, 15, 2)
686 return ATK_ROLE_STATIC;
jdiggs@igalia.com2f555dc2016-03-05 21:35:57 +0000687 case SVGTextPathRole:
688 case SVGTSpanRole:
jdiggs@igalia.com85721d12014-12-03 19:51:28 +0000689 return ATK_ROLE_STATIC;
690#endif
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000691 default:
692 return ATK_ROLE_UNKNOWN;
693 }
694}
695
mario@webkit.org5c966772012-01-24 18:48:50 +0000696static AtkRole webkitAccessibleGetRole(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000697{
jdiggs@igalia.com00e44c42014-11-13 22:11:41 +0000698 // ATK_ROLE_UNKNOWN should only be applied in cases where there is a valid
699 // WebCore accessible object for which the platform role mapping is unknown.
700 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), ATK_ROLE_INVALID);
701 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), ATK_ROLE_INVALID);
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000702
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000703 AccessibilityObject* coreObject = core(object);
jmalonzo@webkit.org7ce37142009-05-20 11:16:01 +0000704
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000705 if (!coreObject)
jdiggs@igalia.com00e44c42014-11-13 22:11:41 +0000706 return ATK_ROLE_INVALID;
jmalonzo@webkit.org7ce37142009-05-20 11:16:01 +0000707
708 // Note: Why doesn't WebCore have a password field for this
mario@webkit.org56f6bf22011-03-30 16:51:08 +0000709 if (coreObject->isPasswordField())
jmalonzo@webkit.org7ce37142009-05-20 11:16:01 +0000710 return ATK_ROLE_PASSWORD_TEXT;
711
mario.prada@samsung.com4fb934b2013-12-17 18:08:34 +0000712 return atkRole(coreObject);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000713}
714
mario@webkit.org6a24ba12010-12-14 15:35:22 +0000715static bool isTextWithCaret(AccessibilityObject* coreObject)
716{
717 if (!coreObject || !coreObject->isAccessibilityRenderObject())
718 return false;
719
720 Document* document = coreObject->document();
721 if (!document)
722 return false;
723
724 Frame* frame = document->frame();
725 if (!frame)
726 return false;
727
akling@apple.com17523502013-08-17 10:58:40 +0000728 if (!frame->settings().caretBrowsingEnabled())
mario@webkit.org6a24ba12010-12-14 15:35:22 +0000729 return false;
730
731 // Check text objects and paragraphs only.
732 AtkObject* axObject = coreObject->wrapper();
733 AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
734 if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
735 return false;
736
737 // Finally, check whether the caret is set in the current object.
738 VisibleSelection selection = coreObject->selection();
739 if (!selection.isCaret())
740 return false;
741
742 return selectionBelongsToObject(coreObject, selection);
743}
744
xan@webkit.org8be15d62009-04-09 11:20:57 +0000745static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
746{
eric@webkit.org2dd47342009-10-26 11:42:42 +0000747 AccessibilityObject* parent = coreObject->parentObject();
748 bool isListBoxOption = parent && parent->isListBox();
xan@webkit.org8be15d62009-04-09 11:20:57 +0000749
eric@webkit.org2dd47342009-10-26 11:42:42 +0000750 // Please keep the state list in alphabetical order
commit-queue@webkit.orgc4299262013-12-02 10:40:07 +0000751 if (isListBoxOption && coreObject->isSelectedOptionActive())
752 atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
753
jdiggs@igalia.com77cdc2a2016-11-19 08:08:03 +0000754 if (coreObject->isBusy())
755 atk_state_set_add_state(stateSet, ATK_STATE_BUSY);
756
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +0000757#if ATK_CHECK_VERSION(2,11,2)
758 if (coreObject->supportsChecked() && coreObject->canSetValueAttribute())
759 atk_state_set_add_state(stateSet, ATK_STATE_CHECKABLE);
760#endif
761
xan@webkit.org8be15d62009-04-09 11:20:57 +0000762 if (coreObject->isChecked())
763 atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
764
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +0000765 if ((coreObject->isTextControl() || coreObject->isNonNativeTextControl()) && coreObject->canSetValueAttribute())
xan@webkit.org8be15d62009-04-09 11:20:57 +0000766 atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
767
xan@webkit.orgdf7d13a2009-06-26 09:12:44 +0000768 // FIXME: Put both ENABLED and SENSITIVE together here for now
769 if (coreObject->isEnabled()) {
xan@webkit.org8be15d62009-04-09 11:20:57 +0000770 atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
xan@webkit.orgdf7d13a2009-06-26 09:12:44 +0000771 atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
772 }
xan@webkit.org8be15d62009-04-09 11:20:57 +0000773
mario@webkit.org8ce6a152010-11-30 21:16:14 +0000774 if (coreObject->canSetExpandedAttribute())
775 atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
776
777 if (coreObject->isExpanded())
778 atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
779
xan@webkit.org8be15d62009-04-09 11:20:57 +0000780 if (coreObject->canSetFocusAttribute())
781 atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
782
mario@webkit.org6a24ba12010-12-14 15:35:22 +0000783 if (coreObject->isFocused() || isTextWithCaret(coreObject))
xan@webkit.org8be15d62009-04-09 11:20:57 +0000784 atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
785
commit-queue@webkit.org471dff52013-03-20 08:12:15 +0000786 if (coreObject->orientation() == AccessibilityOrientationHorizontal)
787 atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);
788 else if (coreObject->orientation() == AccessibilityOrientationVertical)
789 atk_state_set_add_state(stateSet, ATK_STATE_VERTICAL);
xan@webkit.org8be15d62009-04-09 11:20:57 +0000790
791 if (coreObject->isIndeterminate())
792 atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
793
k.czech@samsung.com43a89312014-01-07 11:28:04 +0000794 if (coreObject->isCheckboxOrRadio() || coreObject->isMenuItem()) {
795 if (coreObject->checkboxOrRadioValue() == ButtonStateMixed)
796 atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
797 }
798
mario@webkit.orge0f00f12013-10-08 10:55:25 +0000799 if (coreObject->invalidStatus() != "false")
800 atk_state_set_add_state(stateSet, ATK_STATE_INVALID_ENTRY);
801
jhoneycutt@apple.com8acea082010-01-14 01:16:15 +0000802 if (coreObject->isMultiSelectable())
xan@webkit.org8be15d62009-04-09 11:20:57 +0000803 atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
804
805 // TODO: ATK_STATE_OPAQUE
806
807 if (coreObject->isPressed())
808 atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
809
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +0000810#if ATK_CHECK_VERSION(2,15,3)
811 if (!coreObject->canSetValueAttribute() && (coreObject->supportsARIAReadOnly()))
812 atk_state_set_add_state(stateSet, ATK_STATE_READ_ONLY);
813#endif
814
commit-queue@webkit.org60f8d312013-06-21 10:33:34 +0000815 if (coreObject->isRequired())
816 atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
817
xan@webkit.org8be15d62009-04-09 11:20:57 +0000818 // TODO: ATK_STATE_SELECTABLE_TEXT
819
eric@webkit.org2dd47342009-10-26 11:42:42 +0000820 if (coreObject->canSetSelectedAttribute()) {
821 atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
mario@webkit.org8c5dd902012-11-09 19:47:40 +0000822 // Items in focusable lists have both STATE_SELECT{ABLE,ED}
823 // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on
824 // the former.
eric@webkit.org2dd47342009-10-26 11:42:42 +0000825 if (isListBoxOption)
826 atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
827 }
828
829 if (coreObject->isSelected()) {
xan@webkit.org8be15d62009-04-09 11:20:57 +0000830 atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
mario@webkit.org8c5dd902012-11-09 19:47:40 +0000831 // Items in focusable lists have both STATE_SELECT{ABLE,ED}
eric@webkit.org2dd47342009-10-26 11:42:42 +0000832 // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
833 // former.
834 if (isListBoxOption)
835 atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
836 }
xan@webkit.org8be15d62009-04-09 11:20:57 +0000837
xan@webkit.orgdf7d13a2009-06-26 09:12:44 +0000838 // FIXME: Group both SHOWING and VISIBLE here for now
839 // Not sure how to handle this in WebKit, see bug
840 // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
mario@webkit.org8c5dd902012-11-09 19:47:40 +0000841 // issues with SHOWING vs VISIBLE.
xan@webkit.orgdf7d13a2009-06-26 09:12:44 +0000842 if (!coreObject->isOffScreen()) {
xan@webkit.org8be15d62009-04-09 11:20:57 +0000843 atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
xan@webkit.orgdf7d13a2009-06-26 09:12:44 +0000844 atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
845 }
xan@webkit.org8be15d62009-04-09 11:20:57 +0000846
847 // Mutually exclusive, so we group these two
jdiggs@igalia.com18b89b82016-11-14 17:39:10 +0000848 if (coreObject->roleValue() == TextAreaRole || coreObject->ariaIsMultiline())
xan@webkit.org8be15d62009-04-09 11:20:57 +0000849 atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
jdiggs@igalia.com18b89b82016-11-14 17:39:10 +0000850 else if (coreObject->roleValue() == TextFieldRole || coreObject->roleValue() == SearchFieldRole)
851 atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
xan@webkit.org8be15d62009-04-09 11:20:57 +0000852
853 // TODO: ATK_STATE_SENSITIVE
854
xan@webkit.org8be15d62009-04-09 11:20:57 +0000855 if (coreObject->isVisited())
856 atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
857}
858
mario@webkit.org5c966772012-01-24 18:48:50 +0000859static AtkStateSet* webkitAccessibleRefStateSet(AtkObject* object)
xan@webkit.org8be15d62009-04-09 11:20:57 +0000860{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000861 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
862
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000863 AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_state_set(object);
xan@webkit.org8be15d62009-04-09 11:20:57 +0000864 AccessibilityObject* coreObject = core(object);
865
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000866 // Make sure the layout is updated to really know whether the object
867 // is defunct or not, so we can return the proper state.
868 coreObject->updateBackingStore();
869
xan@webkit.org8be15d62009-04-09 11:20:57 +0000870 if (coreObject == fallbackObject()) {
871 atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
872 return stateSet;
873 }
874
mario@webkit.org6a24ba12010-12-14 15:35:22 +0000875 // Text objects must be focusable.
876 AtkRole role = atk_object_get_role(object);
877 if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
878 atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
xan@webkit.org8be15d62009-04-09 11:20:57 +0000879
mario@webkit.org6a24ba12010-12-14 15:35:22 +0000880 setAtkStateSetFromCoreObject(coreObject, stateSet);
xan@webkit.org8be15d62009-04-09 11:20:57 +0000881 return stateSet;
882}
883
mario@webkit.org5c966772012-01-24 18:48:50 +0000884static AtkRelationSet* webkitAccessibleRefRelationSet(AtkObject* object)
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000885{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000886 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
887 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
888
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000889 AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_relation_set(object);
eric@webkit.org0f6cb452009-10-22 23:07:56 +0000890 AccessibilityObject* coreObject = core(object);
891
892 setAtkRelationSetFromCoreObject(coreObject, relationSet);
893
894 return relationSet;
895}
896
mario@webkit.org5c966772012-01-24 18:48:50 +0000897static void webkitAccessibleInit(AtkObject* object, gpointer data)
xan@webkit.orge4387102009-04-09 11:08:48 +0000898{
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000899 if (ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize)
900 ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize(object, data);
xan@webkit.orge4387102009-04-09 11:08:48 +0000901
mario@webkit.orgfecbacd2013-03-04 17:06:15 +0000902 WebKitAccessible* accessible = WEBKIT_ACCESSIBLE(object);
903 accessible->m_object = reinterpret_cast<AccessibilityObject*>(data);
904 accessible->priv = WEBKIT_ACCESSIBLE_GET_PRIVATE(accessible);
xan@webkit.orge4387102009-04-09 11:08:48 +0000905}
906
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000907static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
908{
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000909 g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
910 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000911
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +0000912 AccessibilityObject* coreObject = core(object);
913 if (!coreObject)
914 return 0;
915
916 if (ATK_IS_DOCUMENT(object)) {
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000917 // TODO: Should we fall back on lang xml:lang when the following comes up empty?
918 String language = coreObject->language();
919 if (!language.isEmpty())
920 return cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, language);
921
922 } else if (ATK_IS_TEXT(object)) {
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +0000923 const gchar* locale = nullptr;
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000924
925 AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
commit-queue@webkit.org44a695d2013-07-04 12:10:45 +0000926 for (AtkAttributeSet* attributes = textAttributes; attributes; attributes = attributes->next) {
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000927 AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
928 if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
929 locale = cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, String::fromUTF8(atkAttribute->value));
930 break;
931 }
932 }
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000933 atk_attribute_set_free(textAttributes);
934
935 return locale;
936 }
937
938 return 0;
939}
940
mario@webkit.org5c966772012-01-24 18:48:50 +0000941static void webkitAccessibleFinalize(GObject* object)
xan@webkit.orge4387102009-04-09 11:08:48 +0000942{
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000943 G_OBJECT_CLASS(webkitAccessibleParentClass)->finalize(object);
xan@webkit.orge4387102009-04-09 11:08:48 +0000944}
945
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000946static void webkitAccessibleClassInit(AtkObjectClass* klass)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000947{
xan@webkit.orge4387102009-04-09 11:08:48 +0000948 GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000949
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000950 webkitAccessibleParentClass = g_type_class_peek_parent(klass);
xan@webkit.orge4387102009-04-09 11:08:48 +0000951
mario@webkit.org5c966772012-01-24 18:48:50 +0000952 gobjectClass->finalize = webkitAccessibleFinalize;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000953
mario@webkit.org5c966772012-01-24 18:48:50 +0000954 klass->initialize = webkitAccessibleInit;
955 klass->get_name = webkitAccessibleGetName;
956 klass->get_description = webkitAccessibleGetDescription;
957 klass->get_parent = webkitAccessibleGetParent;
958 klass->get_n_children = webkitAccessibleGetNChildren;
959 klass->ref_child = webkitAccessibleRefChild;
960 klass->get_role = webkitAccessibleGetRole;
961 klass->ref_state_set = webkitAccessibleRefStateSet;
962 klass->get_index_in_parent = webkitAccessibleGetIndexInParent;
963 klass->get_attributes = webkitAccessibleGetAttributes;
964 klass->ref_relation_set = webkitAccessibleRefRelationSet;
commit-queue@webkit.org120f5652013-06-12 21:39:42 +0000965 klass->get_object_locale = webkitAccessibleGetObjectLocale;
mario@webkit.orgfecbacd2013-03-04 17:06:15 +0000966
967 g_type_class_add_private(klass, sizeof(WebKitAccessiblePrivate));
xan@webkit.orge4387102009-04-09 11:08:48 +0000968}
969
970GType
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000971webkitAccessibleGetType(void)
xan@webkit.orge4387102009-04-09 11:08:48 +0000972{
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000973 static volatile gsize typeVolatile = 0;
xan@webkit.orge4387102009-04-09 11:08:48 +0000974
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000975 if (g_once_init_enter(&typeVolatile)) {
xan@webkit.orge4387102009-04-09 11:08:48 +0000976 static const GTypeInfo tinfo = {
977 sizeof(WebKitAccessibleClass),
eric@webkit.org4ff6fd72009-11-10 09:53:33 +0000978 (GBaseInitFunc) 0,
979 (GBaseFinalizeFunc) 0,
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000980 (GClassInitFunc) webkitAccessibleClassInit,
eric@webkit.org4ff6fd72009-11-10 09:53:33 +0000981 (GClassFinalizeFunc) 0,
982 0, /* class data */
xan@webkit.orge4387102009-04-09 11:08:48 +0000983 sizeof(WebKitAccessible), /* instance size */
984 0, /* nb preallocs */
eric@webkit.org4ff6fd72009-11-10 09:53:33 +0000985 (GInstanceInitFunc) 0,
986 0 /* value table */
xan@webkit.orge4387102009-04-09 11:08:48 +0000987 };
988
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000989 GType type = g_type_register_static(ATK_TYPE_OBJECT, "WebKitAccessible", &tinfo, GTypeFlags(0));
990 g_once_init_leave(&typeVolatile, type);
xan@webkit.orge4387102009-04-09 11:08:48 +0000991 }
992
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +0000993 return typeVolatile;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000994}
995
xan@webkit.orge4387102009-04-09 11:08:48 +0000996static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
mario@webkit.orgdeec8392012-01-23 14:45:23 +0000997 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleActionInterfaceInit), 0, 0},
mario@webkit.org7e5931d2012-01-24 12:25:13 +0000998 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleSelectionInterfaceInit), 0, 0},
mario@webkit.orgfc51ca62012-01-24 11:47:51 +0000999 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleEditableTextInterfaceInit), 0, 0},
mario@webkit.org987d7372012-01-24 18:02:08 +00001000 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTextInterfaceInit), 0, 0},
mario@webkit.orgbe1ce552012-01-24 11:03:51 +00001001 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleComponentInterfaceInit), 0, 0},
mario@webkit.orgda3e6082012-01-24 12:04:16 +00001002 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleImageInterfaceInit), 0, 0},
mario@webkit.orgcd9f1b32012-01-24 18:28:22 +00001003 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableInterfaceInit), 0, 0},
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001004#if ATK_CHECK_VERSION(2,11,90)
1005 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableCellInterfaceInit), 0, 0},
1006#endif
mario@webkit.org70243532012-01-24 11:58:52 +00001007 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHypertextInterfaceInit), 0, 0},
mario@webkit.org4dbd9822012-01-24 11:55:18 +00001008 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHyperlinkImplInterfaceInit), 0, 0},
mario@webkit.orgf8344ff2012-01-24 11:40:44 +00001009 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleDocumentInterfaceInit), 0, 0},
mario@webkit.org980269e2012-01-24 16:22:57 +00001010 {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleValueInterfaceInit), 0, 0}
xan@webkit.orge4387102009-04-09 11:08:48 +00001011};
1012
1013enum WAIType {
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001014 WAIAction,
1015 WAISelection,
1016 WAIEditableText,
1017 WAIText,
1018 WAIComponent,
1019 WAIImage,
1020 WAITable,
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001021#if ATK_CHECK_VERSION(2,11,90)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001022 WAITableCell,
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001023#endif
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001024 WAIHypertext,
1025 WAIHyperlink,
1026 WAIDocument,
1027 WAIValue,
xan@webkit.orge4387102009-04-09 11:08:48 +00001028};
1029
1030static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001031{
mario@webkit.org7f95c622010-11-01 15:05:36 +00001032 switch (type) {
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001033 case WAIAction:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001034 return ATK_TYPE_ACTION;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001035 case WAISelection:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001036 return ATK_TYPE_SELECTION;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001037 case WAIEditableText:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001038 return ATK_TYPE_EDITABLE_TEXT;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001039 case WAIText:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001040 return ATK_TYPE_TEXT;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001041 case WAIComponent:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001042 return ATK_TYPE_COMPONENT;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001043 case WAIImage:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001044 return ATK_TYPE_IMAGE;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001045 case WAITable:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001046 return ATK_TYPE_TABLE;
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001047#if ATK_CHECK_VERSION(2,11,90)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001048 case WAITableCell:
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001049 return ATK_TYPE_TABLE_CELL;
1050#endif
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001051 case WAIHypertext:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001052 return ATK_TYPE_HYPERTEXT;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001053 case WAIHyperlink:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001054 return ATK_TYPE_HYPERLINK_IMPL;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001055 case WAIDocument:
mario@webkit.org7f95c622010-11-01 15:05:36 +00001056 return ATK_TYPE_DOCUMENT;
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001057 case WAIValue:
mario@webkit.org04e38e92011-03-28 10:16:38 +00001058 return ATK_TYPE_VALUE;
mario@webkit.org7f95c622010-11-01 15:05:36 +00001059 }
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001060
mario@webkit.org7f95c622010-11-01 15:05:36 +00001061 return G_TYPE_INVALID;
xan@webkit.orge4387102009-04-09 11:08:48 +00001062}
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001063
commit-queue@webkit.orgca1b1d22012-08-22 01:37:04 +00001064static bool roleIsTextType(AccessibilityRole role)
1065{
commit-queue@webkit.orgd8a8ec32014-06-13 16:12:27 +00001066 return role == ParagraphRole || role == HeadingRole || role == DivRole || role == CellRole
jdiggs@igalia.com99deeb32015-12-08 11:07:11 +00001067 || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole || role == PreRole
1068 || role == GridCellRole;
commit-queue@webkit.orgca1b1d22012-08-22 01:37:04 +00001069}
1070
xan@webkit.orge4387102009-04-09 11:08:48 +00001071static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
1072{
1073 guint16 interfaceMask = 0;
alp@webkit.orgc7738992008-05-27 02:48:14 +00001074
xan@webkit.org92b91692009-04-21 07:02:17 +00001075 // Component interface is always supported
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001076 interfaceMask |= 1 << WAIComponent;
xan@webkit.org92b91692009-04-21 07:02:17 +00001077
mario@webkit.org7f95c622010-11-01 15:05:36 +00001078 AccessibilityRole role = coreObject->roleValue();
1079
xan@webkit.orgb3c59bf2009-04-21 07:01:27 +00001080 // Action
mario@webkit.org8ce6a152010-11-30 21:16:14 +00001081 // As the implementation of the AtkAction interface is a very
1082 // basic one (just relays in executing the default action for each
1083 // object, and only supports having one action per object), it is
1084 // better just to implement this interface for every instance of
1085 // the WebKitAccessible class and let WebCore decide what to do.
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001086 interfaceMask |= 1 << WAIAction;
xan@webkit.orgb3c59bf2009-04-21 07:01:27 +00001087
eric@webkit.orgf84ff632009-10-29 17:34:39 +00001088 // Selection
jdiggs@igalia.comb0b62552016-11-19 21:12:24 +00001089 if (coreObject->canHaveSelectedChildren() || coreObject->isMenuList())
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001090 interfaceMask |= 1 << WAISelection;
eric@webkit.orgf84ff632009-10-29 17:34:39 +00001091
mario@webkit.org9f0aee12011-04-11 21:02:23 +00001092 // Get renderer if available.
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +00001093 RenderObject* renderer = nullptr;
mario@webkit.org9f0aee12011-04-11 21:02:23 +00001094 if (coreObject->isAccessibilityRenderObject())
1095 renderer = coreObject->renderer();
1096
1097 // Hyperlink (links and embedded objects).
1098 if (coreObject->isLink() || (renderer && renderer->isReplaced()))
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001099 interfaceMask |= 1 << WAIHyperlink;
mario@webkit.org9f0aee12011-04-11 21:02:23 +00001100
mario.prada@samsung.com56598be2014-04-09 15:05:58 +00001101 // Text, Editable Text & Hypertext
mario@webkit.org8ce6a152010-11-30 21:16:14 +00001102 if (role == StaticTextRole || coreObject->isMenuListOption())
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001103 interfaceMask |= 1 << WAIText;
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +00001104 else if (coreObject->isTextControl() || coreObject->isNonNativeTextControl()) {
mario.prada@samsung.com56598be2014-04-09 15:05:58 +00001105 interfaceMask |= 1 << WAIText;
jdiggs@igalia.com23022cc2016-05-11 07:14:31 +00001106 if (coreObject->canSetValueAttribute())
mario.prada@samsung.com56598be2014-04-09 15:05:58 +00001107 interfaceMask |= 1 << WAIEditableText;
1108 } else if (!coreObject->isWebArea()) {
1109 if (role != TableRole) {
1110 interfaceMask |= 1 << WAIHypertext;
jdiggs@igalia.comad83c352014-12-10 19:57:33 +00001111 if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
mario.prada@samsung.com56598be2014-04-09 15:05:58 +00001112 interfaceMask |= 1 << WAIText;
1113 }
mario@webkit.org7f95c622010-11-01 15:05:36 +00001114
mario.prada@samsung.com56598be2014-04-09 15:05:58 +00001115 // Add the TEXT interface for list items whose
1116 // first accessible child has a text renderer
1117 if (role == ListItemRole) {
1118 const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
1119 if (children.size()) {
1120 AccessibilityObject* axRenderChild = children.at(0).get();
1121 interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
commit-queue@webkit.org1f3aafe2010-09-22 07:49:34 +00001122 }
1123 }
mario@webkit.org7f95c622010-11-01 15:05:36 +00001124 }
xan@webkit.orge4387102009-04-09 11:08:48 +00001125
xan@webkit.orge43e70b2009-04-27 21:33:55 +00001126 // Image
1127 if (coreObject->isImage())
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001128 interfaceMask |= 1 << WAIImage;
xan@webkit.orge43e70b2009-04-27 21:33:55 +00001129
xan@webkit.org45b26ac2009-10-27 12:20:35 +00001130 // Table
jdiggs@igalia.com73824862015-12-08 16:02:50 +00001131 if (role == TableRole || role == GridRole)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001132 interfaceMask |= 1 << WAITable;
xan@webkit.org45b26ac2009-10-27 12:20:35 +00001133
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001134#if ATK_CHECK_VERSION(2,11,90)
commit-queue@webkit.orgc150a072014-10-10 08:32:58 +00001135 if (role == CellRole || role == ColumnHeaderRole || role == RowHeaderRole)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001136 interfaceMask |= 1 << WAITableCell;
k.czech@samsung.com2608de92014-02-27 11:28:31 +00001137#endif
1138
eric@webkit.org65e12ba2009-11-01 21:22:30 +00001139 // Document
1140 if (role == WebAreaRole)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001141 interfaceMask |= 1 << WAIDocument;
eric@webkit.org65e12ba2009-11-01 21:22:30 +00001142
mario@webkit.org04e38e92011-03-28 10:16:38 +00001143 // Value
commit-queue@webkit.org35af6cf2013-09-16 14:00:35 +00001144 if (role == SliderRole || role == SpinButtonRole || role == ScrollBarRole || role == ProgressIndicatorRole)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001145 interfaceMask |= 1 << WAIValue;
mario@webkit.org04e38e92011-03-28 10:16:38 +00001146
commit-queue@webkit.orgfd70fd32013-09-04 14:19:02 +00001147#if ENABLE(INPUT_TYPE_COLOR)
1148 // Color type.
1149 if (role == ColorWellRole)
k.czech@samsung.com3871a7a2014-02-27 14:22:14 +00001150 interfaceMask |= 1 << WAIText;
commit-queue@webkit.orgfd70fd32013-09-04 14:19:02 +00001151#endif
1152
xan@webkit.orge4387102009-04-09 11:08:48 +00001153 return interfaceMask;
1154}
1155
1156static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
1157{
1158#define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
1159 static char name[WAI_TYPE_NAME_LEN + 1];
eric@webkit.org4ff6fd72009-11-10 09:53:33 +00001160
xan@webkit.orge4387102009-04-09 11:08:48 +00001161 g_sprintf(name, "WAIType%x", interfaceMask);
1162 name[WAI_TYPE_NAME_LEN] = '\0';
eric@webkit.org4ff6fd72009-11-10 09:53:33 +00001163
xan@webkit.orge4387102009-04-09 11:08:48 +00001164 return name;
1165}
1166
1167static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
1168{
1169 static const GTypeInfo typeInfo = {
1170 sizeof(WebKitAccessibleClass),
eric@webkit.org4ff6fd72009-11-10 09:53:33 +00001171 (GBaseInitFunc) 0,
1172 (GBaseFinalizeFunc) 0,
1173 (GClassInitFunc) 0,
1174 (GClassFinalizeFunc) 0,
1175 0, /* class data */
xan@webkit.orge4387102009-04-09 11:08:48 +00001176 sizeof(WebKitAccessible), /* instance size */
1177 0, /* nb preallocs */
eric@webkit.org4ff6fd72009-11-10 09:53:33 +00001178 (GInstanceInitFunc) 0,
1179 0 /* value table */
xan@webkit.orge4387102009-04-09 11:08:48 +00001180 };
1181
1182 guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
1183 const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
1184 GType type = g_type_from_name(atkTypeName);
1185 if (type)
1186 return type;
1187
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +00001188 type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE, atkTypeName, &typeInfo, GTypeFlags(0));
xan@webkit.orge4387102009-04-09 11:08:48 +00001189 for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
1190 if (interfaceMask & (1 << i))
1191 g_type_add_interface_static(type,
mario@webkit.orgf88ffcb2012-11-16 13:47:03 +00001192 GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
1193 &AtkInterfacesInitFunctions[i]);
xan@webkit.orge4387102009-04-09 11:08:48 +00001194 }
1195
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001196 return type;
1197}
1198
mario@webkit.orgaacb2172012-01-23 11:43:28 +00001199WebKitAccessible* webkitAccessibleNew(AccessibilityObject* coreObject)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001200{
xan@webkit.orge4387102009-04-09 11:08:48 +00001201 GType type = getAccessibilityTypeFromObject(coreObject);
eric@webkit.org4ff6fd72009-11-10 09:53:33 +00001202 AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
xan@webkit.orge4387102009-04-09 11:08:48 +00001203
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001204 atk_object_initialize(object, coreObject);
xan@webkit.orge4387102009-04-09 11:08:48 +00001205
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001206 return WEBKIT_ACCESSIBLE(object);
1207}
1208
mario@webkit.orgaacb2172012-01-23 11:43:28 +00001209AccessibilityObject* webkitAccessibleGetAccessibilityObject(WebKitAccessible* accessible)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001210{
1211 return accessible->m_object;
1212}
1213
mario@webkit.orgaacb2172012-01-23 11:43:28 +00001214void webkitAccessibleDetach(WebKitAccessible* accessible)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001215{
alp@webkit.orgc7738992008-05-27 02:48:14 +00001216 ASSERT(accessible->m_object);
1217
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +00001218 if (accessible->m_object->roleValue() == WebAreaRole)
mario@webkit.orgca849062013-10-21 14:02:03 +00001219 atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, true);
mario@webkit.org92daa812011-02-16 17:12:38 +00001220
alp@webkit.orgc7738992008-05-27 02:48:14 +00001221 // We replace the WebCore AccessibilityObject with a fallback object that
1222 // provides default implementations to avoid repetitive null-checking after
1223 // detachment.
xan@webkit.orgc886cc62009-04-09 11:17:48 +00001224 accessible->m_object = fallbackObject();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001225}
1226
mario@webkit.orgff8cf0f2013-09-27 09:44:20 +00001227bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
1228{
1229 ASSERT(accessible->m_object);
1230 return accessible->m_object == fallbackObject();
1231}
1232
mario@webkit.org4c778d72012-01-09 10:16:20 +00001233AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* referenceObject, int& offset)
eric@webkit.org2fade492010-01-11 12:03:36 +00001234{
eric@webkit.org9cf227c2010-01-19 21:31:01 +00001235 // Indication that something bogus has transpired.
1236 offset = -1;
eric@webkit.org2fade492010-01-11 12:03:36 +00001237
mario@webkit.org4c778d72012-01-09 10:16:20 +00001238 Document* document = referenceObject->document();
1239 if (!document)
mrobinson@webkit.orgbc2c5f22010-09-29 17:58:13 +00001240 return 0;
eric@webkit.org2fade492010-01-11 12:03:36 +00001241
mario@webkit.org4c778d72012-01-09 10:16:20 +00001242 Node* focusedNode = referenceObject->selection().end().containerNode();
1243 if (!focusedNode)
mrobinson@webkit.orgbc2c5f22010-09-29 17:58:13 +00001244 return 0;
eric@webkit.org2fade492010-01-11 12:03:36 +00001245
mario@webkit.org4c778d72012-01-09 10:16:20 +00001246 RenderObject* focusedRenderer = focusedNode->renderer();
1247 if (!focusedRenderer)
1248 return 0;
mario@webkit.org6698d352011-02-01 09:49:25 +00001249
mario@webkit.org4c778d72012-01-09 10:16:20 +00001250 AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
1251 if (!focusedObject)
1252 return 0;
mario@webkit.org6698d352011-02-01 09:49:25 +00001253
mario@webkit.org4c778d72012-01-09 10:16:20 +00001254 // Look for the actual (not ignoring accessibility) selected object.
mario@webkit.orgd048f762012-01-22 19:29:04 +00001255 AccessibilityObject* firstUnignoredParent = focusedObject;
1256 if (firstUnignoredParent->accessibilityIsIgnored())
1257 firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1258 if (!firstUnignoredParent)
mario@webkit.org4c778d72012-01-09 10:16:20 +00001259 return 0;
1260
commit-queue@webkit.org3499c512014-06-24 11:09:22 +00001261 // Don't ignore links if the offset is being requested for a link
1262 // or if the link is a block.
1263 if (!referenceObject->isLink() && firstUnignoredParent->isLink()
1264 && !(firstUnignoredParent->renderer() && !firstUnignoredParent->renderer()->isInline()))
mario@webkit.orgd048f762012-01-22 19:29:04 +00001265 firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1266 if (!firstUnignoredParent)
mario@webkit.org4c778d72012-01-09 10:16:20 +00001267 return 0;
1268
mario@webkit.orgd048f762012-01-22 19:29:04 +00001269 // The reference object must either coincide with the focused
1270 // object being considered, or be a descendant of it.
1271 if (referenceObject->isDescendantOfObject(firstUnignoredParent))
1272 referenceObject = firstUnignoredParent;
1273
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +00001274 Node* startNode = nullptr;
mario@webkit.orgd048f762012-01-22 19:29:04 +00001275 if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
mario@webkit.org4c778d72012-01-09 10:16:20 +00001276 // We need to use the first child's node of the reference
1277 // object as the start point to calculate the caret offset
1278 // because we want it to be relative to the object of
1279 // reference, not just to the focused object (which could have
1280 // previous siblings which should be taken into account too).
1281 AccessibilityObject* axFirstChild = referenceObject->firstChild();
1282 if (axFirstChild)
1283 startNode = axFirstChild->node();
1284 }
commit-queue@webkit.orgfb3e9152013-02-01 00:37:22 +00001285 // Getting the Position of a PseudoElement now triggers an assertion.
1286 // This can occur when clicking on empty space in a render block.
1287 if (!startNode || startNode->isPseudoElement())
mario@webkit.orgd048f762012-01-22 19:29:04 +00001288 startNode = firstUnignoredParent->node();
mario@webkit.org4c778d72012-01-09 10:16:20 +00001289
mario@webkit.orgb311bdb2012-02-01 17:58:57 +00001290 // Check if the node for the first parent object not ignoring
1291 // accessibility is null again before using it. This might happen
1292 // with certain kind of accessibility objects, such as the root
1293 // one (the scroller containing the webArea object).
1294 if (!startNode)
1295 return 0;
1296
mario@webkit.orgd048f762012-01-22 19:29:04 +00001297 VisiblePosition startPosition = VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
1298 VisiblePosition endPosition = firstUnignoredParent->selection().visibleEnd();
mario@webkit.org4c778d72012-01-09 10:16:20 +00001299
1300 if (startPosition == endPosition)
1301 offset = 0;
1302 else if (!isStartOfLine(endPosition)) {
1303 RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
1304 offset = TextIterator::rangeLength(range.get(), true) + 1;
1305 } else {
1306 RefPtr<Range> range = makeRange(startPosition, endPosition);
1307 offset = TextIterator::rangeLength(range.get(), true);
eric@webkit.org9cf227c2010-01-19 21:31:01 +00001308 }
mario@webkit.orgff7fd422011-01-27 19:38:03 +00001309
mario@webkit.orgd048f762012-01-22 19:29:04 +00001310 return firstUnignoredParent;
eric@webkit.org2fade492010-01-11 12:03:36 +00001311}
1312
mario@webkit.orgfecbacd2013-03-04 17:06:15 +00001313const char* cacheAndReturnAtkProperty(AtkObject* object, AtkCachedProperty property, String value)
1314{
1315 WebKitAccessiblePrivate* priv = WEBKIT_ACCESSIBLE(object)->priv;
commit-queue@webkit.org9a24e2d2015-05-29 04:53:35 +00001316 CString* propertyPtr = nullptr;
mario@webkit.orgfecbacd2013-03-04 17:06:15 +00001317
1318 switch (property) {
1319 case AtkCachedAccessibleName:
1320 propertyPtr = &priv->accessibleName;
1321 break;
1322
1323 case AtkCachedAccessibleDescription:
1324 propertyPtr = &priv->accessibleDescription;
1325 break;
1326
1327 case AtkCachedActionName:
1328 propertyPtr = &priv->actionName;
1329 break;
1330
1331 case AtkCachedActionKeyBinding:
1332 propertyPtr = &priv->actionKeyBinding;
1333 break;
1334
1335 case AtkCachedDocumentLocale:
1336 propertyPtr = &priv->documentLocale;
1337 break;
1338
1339 case AtkCachedDocumentType:
1340 propertyPtr = &priv->documentType;
1341 break;
1342
1343 case AtkCachedDocumentEncoding:
1344 propertyPtr = &priv->documentEncoding;
1345 break;
1346
1347 case AtkCachedDocumentURI:
1348 propertyPtr = &priv->documentURI;
1349 break;
1350
1351 case AtkCachedImageDescription:
1352 propertyPtr = &priv->imageDescription;
1353 break;
1354
1355 default:
1356 ASSERT_NOT_REACHED();
1357 }
1358
1359 // Don't invalidate old memory if not stricly needed, since other
1360 // callers might be still holding on to it.
1361 if (*propertyPtr != value.utf8())
1362 *propertyPtr = value.utf8();
1363
1364 return (*propertyPtr).data();
1365}
1366
ddkilzer@apple.com8d878632008-11-09 19:50:37 +00001367#endif // HAVE(ACCESSIBILITY)