// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/accessibility/browser_accessibility_gtk.h" #include #include "base/strings/utf_string_conversions.h" #include "content/browser/accessibility/browser_accessibility_manager_gtk.h" #include "content/common/accessibility_messages.h" namespace content { // The maximum length of an autogenerated unique type name string, // generated from the 16-bit interface mask from an AtkObject. // 30 is enough for the prefix "WAIType" + 5 hex chars (max) */ static const int kWAITypeNameLen = 30; static gpointer browser_accessibility_parent_class = NULL; static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( BrowserAccessibilityAtk* atk_object) { if (!atk_object) return NULL; return atk_object->m_object; } static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( AtkObject* atk_object) { if (!IS_BROWSER_ACCESSIBILITY(atk_object)) return NULL; return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object)); } static const gchar* browser_accessibility_get_name(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return NULL; return obj->atk_acc_name().c_str(); } static const gchar* browser_accessibility_get_description( AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return NULL; return obj->atk_acc_description().c_str(); } static AtkObject* browser_accessibility_get_parent(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return NULL; if (obj->parent()) return obj->parent()->ToBrowserAccessibilityGtk()->GetAtkObject(); BrowserAccessibilityManagerGtk* manager = static_cast(obj->manager()); return gtk_widget_get_accessible(manager->parent_widget()); } static gint browser_accessibility_get_n_children(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return 0; return obj->children().size(); } static AtkObject* browser_accessibility_ref_child( AtkObject* atk_object, gint index) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return NULL; AtkObject* result = obj->children()[index]->ToBrowserAccessibilityGtk()->GetAtkObject(); g_object_ref(result); return result; } static gint browser_accessibility_get_index_in_parent(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return 0; return obj->index_in_parent(); } static AtkAttributeSet* browser_accessibility_get_attributes( AtkObject* atk_object) { return NULL; } static AtkRole browser_accessibility_get_role(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return ATK_ROLE_INVALID; return obj->atk_role(); } static AtkStateSet* browser_accessibility_ref_state_set(AtkObject* atk_object) { BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); if (!obj) return NULL; AtkStateSet* state_set = ATK_OBJECT_CLASS(browser_accessibility_parent_class)-> ref_state_set(atk_object); int32 state = obj->state(); if ((state >> AccessibilityNodeData::STATE_FOCUSABLE) & 1) atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); if (obj->manager()->GetFocus(NULL) == obj) atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); return state_set; } static AtkRelationSet* browser_accessibility_ref_relation_set( AtkObject* atk_object) { AtkRelationSet* relation_set = ATK_OBJECT_CLASS(browser_accessibility_parent_class) ->ref_relation_set(atk_object); return relation_set; } static void browser_accessibility_init(AtkObject* atk_object, gpointer data) { if (ATK_OBJECT_CLASS(browser_accessibility_parent_class)->initialize) { ATK_OBJECT_CLASS(browser_accessibility_parent_class)->initialize( atk_object, data); } BROWSER_ACCESSIBILITY(atk_object)->m_object = reinterpret_cast(data); } static void browser_accessibility_finalize(GObject* atk_object) { G_OBJECT_CLASS(browser_accessibility_parent_class)->finalize(atk_object); } static void browser_accessibility_class_init(AtkObjectClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS(klass); browser_accessibility_parent_class = g_type_class_peek_parent(klass); gobject_class->finalize = browser_accessibility_finalize; klass->initialize = browser_accessibility_init; klass->get_name = browser_accessibility_get_name; klass->get_description = browser_accessibility_get_description; klass->get_parent = browser_accessibility_get_parent; klass->get_n_children = browser_accessibility_get_n_children; klass->ref_child = browser_accessibility_ref_child; klass->get_role = browser_accessibility_get_role; klass->ref_state_set = browser_accessibility_ref_state_set; klass->get_index_in_parent = browser_accessibility_get_index_in_parent; klass->get_attributes = browser_accessibility_get_attributes; klass->ref_relation_set = browser_accessibility_ref_relation_set; } GType browser_accessibility_get_type() { static volatile gsize type_volatile = 0; if (g_once_init_enter(&type_volatile)) { static const GTypeInfo tinfo = { sizeof(BrowserAccessibilityAtkClass), (GBaseInitFunc) 0, (GBaseFinalizeFunc) 0, (GClassInitFunc) browser_accessibility_class_init, (GClassFinalizeFunc) 0, 0, /* class data */ sizeof(BrowserAccessibilityAtk), /* instance size */ 0, /* nb preallocs */ (GInstanceInitFunc) 0, 0 /* value table */ }; GType type = g_type_register_static( ATK_TYPE_OBJECT, "BrowserAccessibility", &tinfo, GTypeFlags(0)); g_once_init_leave(&type_volatile, type); } return type_volatile; } static guint16 GetInterfaceMaskFromObject(BrowserAccessibilityGtk* obj) { return 0; } static const char* GetUniqueAccessibilityTypeName(guint16 interface_mask) { static char name[kWAITypeNameLen + 1]; sprintf(name, "WAIType%x", interface_mask); name[kWAITypeNameLen] = '\0'; return name; } static const GInterfaceInfo AtkInterfacesInitFunctions[] = { }; enum WAIType { WAI_ACTION, WAI_SELECTION, WAI_EDITABLE_TEXT, WAI_TEXT, WAI_COMPONENT, WAI_IMAGE, WAI_TABLE, WAI_HYPERTEXT, WAI_HYPERLINK, WAI_DOCUMENT, WAI_VALUE, }; static GType GetAtkInterfaceTypeFromWAIType(WAIType type) { switch (type) { case WAI_ACTION: return ATK_TYPE_ACTION; case WAI_SELECTION: return ATK_TYPE_SELECTION; case WAI_EDITABLE_TEXT: return ATK_TYPE_EDITABLE_TEXT; case WAI_TEXT: return ATK_TYPE_TEXT; case WAI_COMPONENT: return ATK_TYPE_COMPONENT; case WAI_IMAGE: return ATK_TYPE_IMAGE; case WAI_TABLE: return ATK_TYPE_TABLE; case WAI_HYPERTEXT: return ATK_TYPE_HYPERTEXT; case WAI_HYPERLINK: return ATK_TYPE_HYPERLINK_IMPL; case WAI_DOCUMENT: return ATK_TYPE_DOCUMENT; case WAI_VALUE: return ATK_TYPE_VALUE; } return G_TYPE_INVALID; } static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { static const GTypeInfo type_info = { sizeof(BrowserAccessibilityAtkClass), (GBaseInitFunc) 0, (GBaseFinalizeFunc) 0, (GClassInitFunc) 0, (GClassFinalizeFunc) 0, 0, /* class data */ sizeof(BrowserAccessibilityAtk), /* instance size */ 0, /* nb preallocs */ (GInstanceInitFunc) 0, 0 /* value table */ }; guint16 interface_mask = GetInterfaceMaskFromObject(obj); const char* atk_type_name = GetUniqueAccessibilityTypeName(interface_mask); GType type = g_type_from_name(atk_type_name); if (type) return type; type = g_type_register_static(BROWSER_ACCESSIBILITY_TYPE, atk_type_name, &type_info, GTypeFlags(0)); for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) { if (interface_mask & (1 << i)) { g_type_add_interface_static( type, GetAtkInterfaceTypeFromWAIType(static_cast(i)), &AtkInterfacesInitFunctions[i]); } } return type; } BrowserAccessibilityAtk* browser_accessibility_new( BrowserAccessibilityGtk* obj) { GType type = GetAccessibilityTypeFromObject(obj); AtkObject* atk_object = static_cast(g_object_new(type, 0)); atk_object_initialize(atk_object, obj); return BROWSER_ACCESSIBILITY(atk_object); } void browser_accessibility_detach(BrowserAccessibilityAtk* atk_object) { atk_object->m_object = NULL; } // static BrowserAccessibility* BrowserAccessibility::Create() { return new BrowserAccessibilityGtk(); } BrowserAccessibilityGtk* BrowserAccessibility::ToBrowserAccessibilityGtk() { return static_cast(this); } BrowserAccessibilityGtk::BrowserAccessibilityGtk() { atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); } BrowserAccessibilityGtk::~BrowserAccessibilityGtk() { browser_accessibility_detach(BROWSER_ACCESSIBILITY(atk_object_)); g_object_unref(atk_object_); } AtkObject* BrowserAccessibilityGtk::GetAtkObject() const { if (!G_IS_OBJECT(atk_object_)) return NULL; return atk_object_; } void BrowserAccessibilityGtk::PreInitialize() { BrowserAccessibility::PreInitialize(); InitRoleAndState(); if (this->parent()) { atk_object_set_parent( atk_object_, this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject()); } } bool BrowserAccessibilityGtk::IsNative() const { return true; } void BrowserAccessibilityGtk::InitRoleAndState() { atk_acc_name_ = UTF16ToUTF8(name()); string16 description; GetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, &description); atk_acc_description_ = UTF16ToUTF8(description); switch(role_) { case AccessibilityNodeData::ROLE_BUTTON: atk_role_ = ATK_ROLE_PUSH_BUTTON; break; case AccessibilityNodeData::ROLE_CHECKBOX: atk_role_ = ATK_ROLE_CHECK_BOX; break; case AccessibilityNodeData::ROLE_COMBO_BOX: atk_role_ = ATK_ROLE_COMBO_BOX; break; case AccessibilityNodeData::ROLE_LINK: atk_role_ = ATK_ROLE_LINK; break; case AccessibilityNodeData::ROLE_RADIO_BUTTON: atk_role_ = ATK_ROLE_RADIO_BUTTON; break; case AccessibilityNodeData::ROLE_TEXTAREA: atk_role_ = ATK_ROLE_ENTRY; break; case AccessibilityNodeData::ROLE_TEXT_FIELD: atk_role_ = ATK_ROLE_ENTRY; break; case AccessibilityNodeData::ROLE_WEBCORE_LINK: atk_role_ = ATK_ROLE_LINK; break; default: atk_role_ = ATK_ROLE_UNKNOWN; break; } } } // namespace content