Chromium Code Reviews| Index: content/browser/accessibility/browser_accessibility_gtk.cc |
| diff --git a/content/browser/accessibility/browser_accessibility_gtk.cc b/content/browser/accessibility/browser_accessibility_gtk.cc |
| index f5539b78b5d42ec8a1eb12e0da5553c891f4b7ea..dd4b5bc58e441bebf63a61ebd2be686b0f787a9b 100644 |
| --- a/content/browser/accessibility/browser_accessibility_gtk.cc |
| +++ b/content/browser/accessibility/browser_accessibility_gtk.cc |
| @@ -12,11 +12,6 @@ |
| 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( |
| @@ -27,6 +22,153 @@ static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( |
| return atk_object->m_object; |
| } |
| +// |
| +// AtkComponent interface. |
| +// |
| + |
| +static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( |
| + AtkComponent* atk_object) { |
| + if (!IS_BROWSER_ACCESSIBILITY(atk_object)) |
| + return NULL; |
| + |
| + return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object)); |
| +} |
| + |
| +static AtkObject* browser_accessibility_accessible_at_point( |
| + AtkComponent* component, gint x, gint y, AtkCoordType coord_type) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); |
| + if (!obj) |
| + return 0; |
|
aboxhall
2013/07/29 22:23:09
Why return 0 instead of NULL here?
dmazzoni
2013/07/29 22:34:28
Done.
|
| + |
| + gfx::Point point(x, y); |
| + if (!obj->GetGlobalBoundsRect().Contains(point)) |
| + return NULL; |
| + |
| + BrowserAccessibility* result = obj->BrowserAccessibilityForPoint(point); |
| + if (!result) |
| + return NULL; |
| + |
| + AtkObject* atk_result = result->ToBrowserAccessibilityGtk()->GetAtkObject(); |
| + g_object_ref(atk_result); |
| + return atk_result; |
| +} |
| + |
| +static void browser_accessibility_get_extents( |
| + AtkComponent* component, gint* x, gint* y, gint* width, gint* height, |
| + AtkCoordType coord_type) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); |
| + if (!obj) |
| + return; |
| + |
| + gfx::Rect bounds = obj->GetGlobalBoundsRect(); |
|
aboxhall
2013/07/29 22:23:09
Does bounds need any sanity (null) checking?
dmazzoni
2013/07/29 22:34:28
Not needed, it's just a struct.
|
| + *x = bounds.x(); |
| + *y = bounds.y(); |
| + *width = bounds.width(); |
| + *height = bounds.height(); |
| +} |
| + |
| +static gboolean browser_accessibility_grab_focus(AtkComponent* component) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(component); |
| + if (!obj) |
| + return false; |
| + |
| + obj->manager()->SetFocus(obj, true); |
| + return true; |
| +} |
| + |
| +static void ComponentInterfaceInit(AtkComponentIface* iface) { |
| + iface->ref_accessible_at_point = browser_accessibility_accessible_at_point; |
| + iface->get_extents = browser_accessibility_get_extents; |
| + iface->grab_focus = browser_accessibility_grab_focus; |
| +} |
| + |
| +static const GInterfaceInfo ComponentInfo = { |
| + reinterpret_cast<GInterfaceInitFunc>(ComponentInterfaceInit), 0, 0 |
| +}; |
| + |
| +// |
| +// AtkValue interface. |
| +// |
| + |
| +static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( |
| + AtkValue* atk_object) { |
| + if (!IS_BROWSER_ACCESSIBILITY(atk_object)) |
| + return NULL; |
| + |
| + return ToBrowserAccessibilityGtk(BROWSER_ACCESSIBILITY(atk_object)); |
| +} |
| + |
| +static void browser_accessibility_get_current_value( |
| + AtkValue* atk_object, GValue* value) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); |
| + if (!obj) |
| + return; |
| + |
| + float float_val; |
| + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, |
| + &float_val)) { |
| + memset(value, 0, sizeof(value)); |
| + g_value_init(value, G_TYPE_FLOAT); |
| + g_value_set_float(value, float_val); |
| + } |
| +} |
| + |
| +static void browser_accessibility_get_minimum_value( |
| + AtkValue* atk_object, GValue* value) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); |
| + if (!obj) |
| + return; |
| + |
| + float float_val; |
| + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE, |
| + &float_val)) { |
| + memset(value, 0, sizeof(value)); |
| + g_value_init(value, G_TYPE_FLOAT); |
| + g_value_set_float(value, float_val); |
| + } |
| +} |
| + |
| +static void browser_accessibility_get_maximum_value( |
| + AtkValue* atk_object, GValue* value) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); |
| + if (!obj) |
| + return; |
| + |
| + float float_val; |
| + if (obj->GetFloatAttribute(AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE, |
| + &float_val)) { |
| + memset(value, 0, sizeof(value)); |
| + g_value_init(value, G_TYPE_FLOAT); |
| + g_value_set_float(value, float_val); |
| + } |
| +} |
| + |
| +static void browser_accessibility_get_minimum_increment( |
| + AtkValue* atk_object, GValue* value) { |
| + BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object); |
|
aboxhall
2013/07/29 22:23:09
obj isn't used below; do we still need this check?
dmazzoni
2013/07/29 22:34:28
Done.
|
| + if (!obj) |
| + return; |
| + |
| + memset(value, 0, sizeof(value)); |
| + g_value_init(value, G_TYPE_FLOAT); |
| + g_value_set_float(value, 1.0); |
|
aboxhall
2013/07/29 22:23:09
Is this always correct?
dmazzoni
2013/07/29 22:34:28
No. I added a TODO; I believe the other platforms
|
| +} |
| + |
| +static void ValueInterfaceInit(AtkValueIface* iface) { |
| + iface->get_current_value = browser_accessibility_get_current_value; |
| + iface->get_minimum_value = browser_accessibility_get_minimum_value; |
| + iface->get_maximum_value = browser_accessibility_get_maximum_value; |
| + iface->get_minimum_increment = browser_accessibility_get_minimum_increment; |
| +} |
| + |
| +static const GInterfaceInfo ValueInfo = { |
| + reinterpret_cast<GInterfaceInitFunc>(ValueInterfaceInit), 0, 0 |
| +}; |
| + |
| +// |
| +// AtkObject interface |
| +// |
| + |
| static BrowserAccessibilityGtk* ToBrowserAccessibilityGtk( |
| AtkObject* atk_object) { |
| if (!IS_BROWSER_ACCESSIBILITY(atk_object)) |
| @@ -126,6 +268,11 @@ static AtkRelationSet* browser_accessibility_ref_relation_set( |
| return relation_set; |
| } |
| +// |
| +// The rest of the BrowserAccessibilityGtk code, not specific to one |
| +// of the Atk* interfaces. |
| +// |
| + |
| 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( |
| @@ -183,64 +330,42 @@ GType browser_accessibility_get_type() { |
| return type_volatile; |
| } |
| -static guint16 GetInterfaceMaskFromObject(BrowserAccessibilityGtk* obj) { |
| - return 0; |
| -} |
| - |
| -static const char* GetUniqueAccessibilityTypeName(guint16 interface_mask) |
| +static const char* GetUniqueAccessibilityTypeName(int interface_mask) |
| { |
| - static char name[kWAITypeNameLen + 1]; |
| - |
| - sprintf(name, "WAIType%x", interface_mask); |
| - name[kWAITypeNameLen] = '\0'; |
| - |
| + // 20 characters is enough for "Chrome%x" with any conceivable integer. |
|
aboxhall
2013/07/29 22:23:09
What does 'conceivable' mean here?
dmazzoni
2013/07/29 22:34:28
Done.
|
| + static char name[20]; |
| + snprintf(name, sizeof(name), "Chrome%x", interface_mask); |
| return name; |
| } |
| -static const GInterfaceInfo AtkInterfacesInitFunctions[] = { |
| +enum AtkInterfaces { |
| + ATK_ACTION_INTERFACE, |
| + ATK_COMPONENT_INTERFACE, |
| + ATK_DOCUMENT_INTERFACE, |
| + ATK_EDITABLE_TEXT_INTERFACE, |
| + ATK_HYPERLINK_INTERFACE, |
| + ATK_HYPERTEXT_INTERFACE, |
| + ATK_IMAGE_INTERFACE, |
| + ATK_SELECTION_INTERFACE, |
| + ATK_TABLE_INTERFACE, |
| + ATK_TEXT_INTERFACE, |
| + ATK_VALUE_INTERFACE, |
| }; |
| -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 int GetInterfaceMaskFromObject(BrowserAccessibilityGtk* obj) { |
| + int interface_mask = 0; |
| + |
| + // Component interface is always supported. |
| + interface_mask |= 1 << ATK_COMPONENT_INTERFACE; |
| -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; |
| + int role = obj->role(); |
| + if (role == AccessibilityNodeData::ROLE_PROGRESS_INDICATOR || |
|
aboxhall
2013/07/29 22:23:09
So we'll need to go through each of the roles and
dmazzoni
2013/07/29 22:34:28
Yes. Usually it's pretty easy; for example the TAB
|
| + role == AccessibilityNodeData::ROLE_SCROLLBAR || |
| + role == AccessibilityNodeData::ROLE_SLIDER) { |
| + interface_mask |= 1 << ATK_VALUE_INTERFACE; |
| } |
| - return G_TYPE_INVALID; |
| + return interface_mask; |
| } |
| static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { |
| @@ -257,7 +382,7 @@ static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { |
| 0 /* value table */ |
| }; |
| - guint16 interface_mask = GetInterfaceMaskFromObject(obj); |
| + int interface_mask = GetInterfaceMaskFromObject(obj); |
| const char* atk_type_name = GetUniqueAccessibilityTypeName(interface_mask); |
| GType type = g_type_from_name(atk_type_name); |
| if (type) |
| @@ -267,14 +392,10 @@ static GType GetAccessibilityTypeFromObject(BrowserAccessibilityGtk* obj) { |
| 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<WAIType>(i)), |
| - &AtkInterfacesInitFunctions[i]); |
| - } |
| - } |
| + if (interface_mask & (1 << ATK_COMPONENT_INTERFACE)) |
| + g_type_add_interface_static(type, ATK_TYPE_COMPONENT, &ComponentInfo); |
| + if (interface_mask & (1 << ATK_VALUE_INTERFACE)) |
| + g_type_add_interface_static(type, ATK_TYPE_VALUE, &ValueInfo); |
| return type; |
| } |
| @@ -302,13 +423,14 @@ BrowserAccessibilityGtk* BrowserAccessibility::ToBrowserAccessibilityGtk() { |
| return static_cast<BrowserAccessibilityGtk*>(this); |
| } |
| -BrowserAccessibilityGtk::BrowserAccessibilityGtk() { |
| - atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); |
| +BrowserAccessibilityGtk::BrowserAccessibilityGtk() |
| + : atk_object_(NULL) { |
| } |
| BrowserAccessibilityGtk::~BrowserAccessibilityGtk() { |
| browser_accessibility_detach(BROWSER_ACCESSIBILITY(atk_object_)); |
| - g_object_unref(atk_object_); |
| + if (atk_object_) |
| + g_object_unref(atk_object_); |
| } |
| AtkObject* BrowserAccessibilityGtk::GetAtkObject() const { |
| @@ -321,10 +443,25 @@ void BrowserAccessibilityGtk::PreInitialize() { |
| BrowserAccessibility::PreInitialize(); |
| InitRoleAndState(); |
| - if (this->parent()) { |
| - atk_object_set_parent( |
| - atk_object_, |
| - this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject()); |
| + if (atk_object_) { |
| + // If the object's role changes and that causes its |
| + // interface mask to change, we need to create a new |
| + // AtkObject for it. |
| + int interface_mask = GetInterfaceMaskFromObject(this); |
| + if (interface_mask != interface_mask_) { |
| + g_object_unref(atk_object_); |
| + atk_object_ = NULL; |
| + } |
| + } |
| + |
| + if (!atk_object_) { |
| + interface_mask_ = GetInterfaceMaskFromObject(this); |
| + atk_object_ = ATK_OBJECT(browser_accessibility_new(this)); |
| + if (this->parent()) { |
| + atk_object_set_parent( |
| + atk_object_, |
| + this->parent()->ToBrowserAccessibilityGtk()->GetAtkObject()); |
| + } |
| } |
| } |