1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/browser_accessibility_gtk.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/accessibility/browser_accessibility_manager_gtk.h"
11 #include "content/common/accessibility_messages.h"
15 static gpointer browser_accessibility_parent_class
= NULL
;
17 static BrowserAccessibilityGtk
* ToBrowserAccessibilityGtk(
18 BrowserAccessibilityAtk
* atk_object
) {
22 return atk_object
->m_object
;
26 // AtkComponent interface.
29 static BrowserAccessibilityGtk
* ToBrowserAccessibilityGtk(
30 AtkComponent
* atk_object
) {
31 if (!IS_BROWSER_ACCESSIBILITY(atk_object
))
34 return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object
));
37 static AtkObject
* browser_accessibility_accessible_at_point(
38 AtkComponent
* component
, gint x
, gint y
, AtkCoordType coord_type
) {
39 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(component
);
43 gfx::Point
point(x
, y
);
44 if (!obj
->GetGlobalBoundsRect().Contains(point
))
47 BrowserAccessibility
* result
= obj
->BrowserAccessibilityForPoint(point
);
51 AtkObject
* atk_result
= result
->ToBrowserAccessibilityGtk()->GetAtkObject();
52 g_object_ref(atk_result
);
56 static void browser_accessibility_get_extents(
57 AtkComponent
* component
, gint
* x
, gint
* y
, gint
* width
, gint
* height
,
58 AtkCoordType coord_type
) {
59 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(component
);
63 gfx::Rect bounds
= obj
->GetGlobalBoundsRect();
66 *width
= bounds
.width();
67 *height
= bounds
.height();
70 static gboolean
browser_accessibility_grab_focus(AtkComponent
* component
) {
71 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(component
);
75 obj
->manager()->SetFocus(obj
, true);
79 static void ComponentInterfaceInit(AtkComponentIface
* iface
) {
80 iface
->ref_accessible_at_point
= browser_accessibility_accessible_at_point
;
81 iface
->get_extents
= browser_accessibility_get_extents
;
82 iface
->grab_focus
= browser_accessibility_grab_focus
;
85 static const GInterfaceInfo ComponentInfo
= {
86 reinterpret_cast<GInterfaceInitFunc
>(ComponentInterfaceInit
), 0, 0
90 // AtkValue interface.
93 static BrowserAccessibilityGtk
* ToBrowserAccessibilityGtk(
94 AtkValue
* atk_object
) {
95 if (!IS_BROWSER_ACCESSIBILITY(atk_object
))
98 return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object
));
101 static void browser_accessibility_get_current_value(
102 AtkValue
* atk_object
, GValue
* value
) {
103 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
108 if (obj
->GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE
,
110 memset(value
, 0, sizeof(*value
));
111 g_value_init(value
, G_TYPE_FLOAT
);
112 g_value_set_float(value
, float_val
);
116 static void browser_accessibility_get_minimum_value(
117 AtkValue
* atk_object
, GValue
* value
) {
118 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
123 if (obj
->GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE
,
125 memset(value
, 0, sizeof(*value
));
126 g_value_init(value
, G_TYPE_FLOAT
);
127 g_value_set_float(value
, float_val
);
131 static void browser_accessibility_get_maximum_value(
132 AtkValue
* atk_object
, GValue
* value
) {
133 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
138 if (obj
->GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE
,
140 memset(value
, 0, sizeof(*value
));
141 g_value_init(value
, G_TYPE_FLOAT
);
142 g_value_set_float(value
, float_val
);
146 static void browser_accessibility_get_minimum_increment(
147 AtkValue
* atk_object
, GValue
* value
) {
148 // TODO(dmazzoni): get the correct value from an <input type=range>.
149 memset(value
, 0, sizeof(*value
));
150 g_value_init(value
, G_TYPE_FLOAT
);
151 g_value_set_float(value
, 1.0);
154 static void ValueInterfaceInit(AtkValueIface
* iface
) {
155 iface
->get_current_value
= browser_accessibility_get_current_value
;
156 iface
->get_minimum_value
= browser_accessibility_get_minimum_value
;
157 iface
->get_maximum_value
= browser_accessibility_get_maximum_value
;
158 iface
->get_minimum_increment
= browser_accessibility_get_minimum_increment
;
161 static const GInterfaceInfo ValueInfo
= {
162 reinterpret_cast<GInterfaceInitFunc
>(ValueInterfaceInit
), 0, 0
166 // AtkObject interface
169 static BrowserAccessibilityGtk
* ToBrowserAccessibilityGtk(
170 AtkObject
* atk_object
) {
171 if (!IS_BROWSER_ACCESSIBILITY(atk_object
))
174 return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object
));
177 static const gchar
* browser_accessibility_get_name(AtkObject
* atk_object
) {
178 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
182 return obj
->GetStringAttribute(ui::AX_ATTR_NAME
).c_str();
185 static const gchar
* browser_accessibility_get_description(
186 AtkObject
* atk_object
) {
187 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
191 return obj
->GetStringAttribute(
192 ui::AX_ATTR_DESCRIPTION
).c_str();
195 static AtkObject
* browser_accessibility_get_parent(AtkObject
* atk_object
) {
196 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
200 return obj
->parent()->ToBrowserAccessibilityGtk()->GetAtkObject();
202 BrowserAccessibilityManagerGtk
* manager
=
203 static_cast<BrowserAccessibilityManagerGtk
*>(obj
->manager());
204 return gtk_widget_get_accessible(manager
->parent_widget());
207 static gint
browser_accessibility_get_n_children(AtkObject
* atk_object
) {
208 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
212 return obj
->PlatformChildCount();
215 static AtkObject
* browser_accessibility_ref_child(
216 AtkObject
* atk_object
, gint index
) {
217 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
221 if (index
< 0 || index
>= static_cast<gint
>(obj
->PlatformChildCount()))
225 obj
->children()[index
]->ToBrowserAccessibilityGtk()->GetAtkObject();
226 g_object_ref(result
);
230 static gint
browser_accessibility_get_index_in_parent(AtkObject
* atk_object
) {
231 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
234 return obj
->index_in_parent();
237 static AtkAttributeSet
* browser_accessibility_get_attributes(
238 AtkObject
* atk_object
) {
242 static AtkRole
browser_accessibility_get_role(AtkObject
* atk_object
) {
243 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
245 return ATK_ROLE_INVALID
;
246 return obj
->atk_role();
249 static AtkStateSet
* browser_accessibility_ref_state_set(AtkObject
* atk_object
) {
250 BrowserAccessibilityGtk
* obj
= ToBrowserAccessibilityGtk(atk_object
);
253 AtkStateSet
* state_set
=
254 ATK_OBJECT_CLASS(browser_accessibility_parent_class
)->
255 ref_state_set(atk_object
);
256 int32 state
= obj
->state();
258 if (state
& (1 << ui::AX_STATE_FOCUSABLE
))
259 atk_state_set_add_state(state_set
, ATK_STATE_FOCUSABLE
);
260 if (obj
->manager()->GetFocus(NULL
) == obj
)
261 atk_state_set_add_state(state_set
, ATK_STATE_FOCUSED
);
262 if (state
& (1 << ui::AX_STATE_ENABLED
))
263 atk_state_set_add_state(state_set
, ATK_STATE_ENABLED
);
268 static AtkRelationSet
* browser_accessibility_ref_relation_set(
269 AtkObject
* atk_object
) {
270 AtkRelationSet
* relation_set
=
271 ATK_OBJECT_CLASS(browser_accessibility_parent_class
)
272 ->ref_relation_set(atk_object
);
277 // The rest of the BrowserAccessibilityGtk code, not specific to one
278 // of the Atk* interfaces.
281 static void browser_accessibility_init(AtkObject
* atk_object
, gpointer data
) {
282 if (ATK_OBJECT_CLASS(browser_accessibility_parent_class
)->initialize
) {
283 ATK_OBJECT_CLASS(browser_accessibility_parent_class
)->initialize(
287 BROWSER_ACCESSIBILITY(atk_object
)->m_object
=
288 reinterpret_cast<BrowserAccessibilityGtk
*>(data
);
291 static void browser_accessibility_finalize(GObject
* atk_object
) {
292 G_OBJECT_CLASS(browser_accessibility_parent_class
)->finalize(atk_object
);
295 static void browser_accessibility_class_init(AtkObjectClass
* klass
) {
296 GObjectClass
* gobject_class
= G_OBJECT_CLASS(klass
);
297 browser_accessibility_parent_class
= g_type_class_peek_parent(klass
);
299 gobject_class
->finalize
= browser_accessibility_finalize
;
300 klass
->initialize
= browser_accessibility_init
;
301 klass
->get_name
= browser_accessibility_get_name
;
302 klass
->get_description
= browser_accessibility_get_description
;
303 klass
->get_parent
= browser_accessibility_get_parent
;
304 klass
->get_n_children
= browser_accessibility_get_n_children
;
305 klass
->ref_child
= browser_accessibility_ref_child
;
306 klass
->get_role
= browser_accessibility_get_role
;
307 klass
->ref_state_set
= browser_accessibility_ref_state_set
;
308 klass
->get_index_in_parent
= browser_accessibility_get_index_in_parent
;
309 klass
->get_attributes
= browser_accessibility_get_attributes
;
310 klass
->ref_relation_set
= browser_accessibility_ref_relation_set
;
313 GType
browser_accessibility_get_type() {
314 static volatile gsize type_volatile
= 0;
316 if (g_once_init_enter(&type_volatile
)) {
317 static const GTypeInfo tinfo
= {
318 sizeof(BrowserAccessibilityAtkClass
),
320 (GBaseFinalizeFunc
) 0,
321 (GClassInitFunc
) browser_accessibility_class_init
,
322 (GClassFinalizeFunc
) 0,
324 sizeof(BrowserAccessibilityAtk
), /* instance size */
325 0, /* nb preallocs */
326 (GInstanceInitFunc
) 0,
330 GType type
= g_type_register_static(
331 ATK_TYPE_OBJECT
, "BrowserAccessibility", &tinfo
, GTypeFlags(0));
332 g_once_init_leave(&type_volatile
, type
);
335 return type_volatile
;
338 static const char* GetUniqueAccessibilityTypeName(int interface_mask
)
340 // 20 characters is enough for "Chrome%x" with any integer value.
341 static char name
[20];
342 snprintf(name
, sizeof(name
), "Chrome%x", interface_mask
);
347 ATK_ACTION_INTERFACE
,
348 ATK_COMPONENT_INTERFACE
,
349 ATK_DOCUMENT_INTERFACE
,
350 ATK_EDITABLE_TEXT_INTERFACE
,
351 ATK_HYPERLINK_INTERFACE
,
352 ATK_HYPERTEXT_INTERFACE
,
354 ATK_SELECTION_INTERFACE
,
360 static int GetInterfaceMaskFromObject(BrowserAccessibilityGtk
* obj
) {
361 int interface_mask
= 0;
363 // Component interface is always supported.
364 interface_mask
|= 1 << ATK_COMPONENT_INTERFACE
;
366 int role
= obj
->role();
367 if (role
== ui::AX_ROLE_PROGRESS_INDICATOR
||
368 role
== ui::AX_ROLE_SCROLL_BAR
||
369 role
== ui::AX_ROLE_SLIDER
) {
370 interface_mask
|= 1 << ATK_VALUE_INTERFACE
;
373 return interface_mask
;
376 static GType
GetAccessibilityTypeFromObject(BrowserAccessibilityGtk
* obj
) {
377 static const GTypeInfo type_info
= {
378 sizeof(BrowserAccessibilityAtkClass
),
380 (GBaseFinalizeFunc
) 0,
382 (GClassFinalizeFunc
) 0,
384 sizeof(BrowserAccessibilityAtk
), /* instance size */
385 0, /* nb preallocs */
386 (GInstanceInitFunc
) 0,
390 int interface_mask
= GetInterfaceMaskFromObject(obj
);
391 const char* atk_type_name
= GetUniqueAccessibilityTypeName(interface_mask
);
392 GType type
= g_type_from_name(atk_type_name
);
396 type
= g_type_register_static(BROWSER_ACCESSIBILITY_TYPE
,
400 if (interface_mask
& (1 << ATK_COMPONENT_INTERFACE
))
401 g_type_add_interface_static(type
, ATK_TYPE_COMPONENT
, &ComponentInfo
);
402 if (interface_mask
& (1 << ATK_VALUE_INTERFACE
))
403 g_type_add_interface_static(type
, ATK_TYPE_VALUE
, &ValueInfo
);
408 BrowserAccessibilityAtk
* browser_accessibility_new(
409 BrowserAccessibilityGtk
* obj
) {
410 GType type
= GetAccessibilityTypeFromObject(obj
);
411 AtkObject
* atk_object
= static_cast<AtkObject
*>(g_object_new(type
, 0));
413 atk_object_initialize(atk_object
, obj
);
415 return BROWSER_ACCESSIBILITY(atk_object
);
418 void browser_accessibility_detach(BrowserAccessibilityAtk
* atk_object
) {
419 atk_object
->m_object
= NULL
;
423 BrowserAccessibility
* BrowserAccessibility::Create() {
424 return new BrowserAccessibilityGtk();
427 BrowserAccessibilityGtk
* BrowserAccessibility::ToBrowserAccessibilityGtk() {
428 return static_cast<BrowserAccessibilityGtk
*>(this);
431 BrowserAccessibilityGtk::BrowserAccessibilityGtk()
432 : atk_object_(NULL
) {
435 BrowserAccessibilityGtk::~BrowserAccessibilityGtk() {
436 browser_accessibility_detach(BROWSER_ACCESSIBILITY(atk_object_
));
438 g_object_unref(atk_object_
);
441 AtkObject
* BrowserAccessibilityGtk::GetAtkObject() const {
442 if (!G_IS_OBJECT(atk_object_
))
447 void BrowserAccessibilityGtk::PreInitialize() {
448 BrowserAccessibility::PreInitialize();
452 // If the object's role changes and that causes its
453 // interface mask to change, we need to create a new
455 int interface_mask
= GetInterfaceMaskFromObject(this);
456 if (interface_mask
!= interface_mask_
) {
457 g_object_unref(atk_object_
);
463 interface_mask_
= GetInterfaceMaskFromObject(this);
464 atk_object_
= ATK_OBJECT(browser_accessibility_new(this));
465 if (this->parent()) {
466 atk_object_set_parent(
468 this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject());
473 bool BrowserAccessibilityGtk::IsNative() const {
477 void BrowserAccessibilityGtk::InitRoleAndState() {
479 case ui::AX_ROLE_DOCUMENT
:
480 case ui::AX_ROLE_ROOT_WEB_AREA
:
481 case ui::AX_ROLE_WEB_AREA
:
482 atk_role_
= ATK_ROLE_DOCUMENT_WEB
;
484 case ui::AX_ROLE_GROUP
:
485 case ui::AX_ROLE_DIV
:
486 atk_role_
= ATK_ROLE_SECTION
;
488 case ui::AX_ROLE_BUTTON
:
489 atk_role_
= ATK_ROLE_PUSH_BUTTON
;
491 case ui::AX_ROLE_CHECK_BOX
:
492 atk_role_
= ATK_ROLE_CHECK_BOX
;
494 case ui::AX_ROLE_COMBO_BOX
:
495 atk_role_
= ATK_ROLE_COMBO_BOX
;
497 case ui::AX_ROLE_LINK
:
498 atk_role_
= ATK_ROLE_LINK
;
500 case ui::AX_ROLE_RADIO_BUTTON
:
501 atk_role_
= ATK_ROLE_RADIO_BUTTON
;
503 case ui::AX_ROLE_STATIC_TEXT
:
504 atk_role_
= ATK_ROLE_TEXT
;
506 case ui::AX_ROLE_TEXT_AREA
:
507 atk_role_
= ATK_ROLE_ENTRY
;
509 case ui::AX_ROLE_TEXT_FIELD
:
510 atk_role_
= ATK_ROLE_ENTRY
;
513 atk_role_
= ATK_ROLE_UNKNOWN
;
518 } // namespace content