#if !defined(OS_MACOSX) && \
!defined(OS_WIN) && \
- !defined(TOOLKIT_GTK) && \
!defined(OS_ANDROID)
-// We have subclassess of BrowserAccessibility on Mac, Linux/GTK,
-// and Win. For any other platform, instantiate the base class.
+// We have subclassess of BrowserAccessibility on Mac and Win. For any other
+// platform, instantiate the base class.
// static
BrowserAccessibility* BrowserAccessibility::Create() {
return new BrowserAccessibility();
BrowserAccessibility::BrowserAccessibility()
: manager_(NULL),
- parent_(NULL),
- index_in_parent_(0),
- renderer_id_(0),
- role_(0),
- state_(0),
- instance_active_(false) {
+ node_(NULL) {
}
BrowserAccessibility::~BrowserAccessibility() {
}
+void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
+ ui::AXNode* node) {
+ manager_ = manager;
+ node_ = node;
+}
+
+void BrowserAccessibility::OnDataChanged() {
+ GetStringAttribute(ui::AX_ATTR_NAME, &name_);
+ GetStringAttribute(ui::AX_ATTR_VALUE, &value_);
+}
+
bool BrowserAccessibility::PlatformIsLeaf() const {
- if (child_count() == 0)
+ if (InternalChildCount() == 0)
return true;
// All of these roles may have children that we use as internal
// implementation details, but we want to expose them as leaves
// to platform accessibility APIs.
- switch (role_) {
+ switch (GetRole()) {
case ui::AX_ROLE_EDITABLE_TEXT:
case ui::AX_ROLE_SLIDER:
case ui::AX_ROLE_STATIC_TEXT:
}
uint32 BrowserAccessibility::PlatformChildCount() const {
- return PlatformIsLeaf() ? 0 : children_.size();
-}
-
-void BrowserAccessibility::DetachTree(
- std::vector<BrowserAccessibility*>* nodes) {
- nodes->push_back(this);
- for (size_t i = 0; i < children_.size(); ++i)
- children_[i]->DetachTree(nodes);
- children_.clear();
- parent_ = NULL;
-}
-
-void BrowserAccessibility::InitializeTreeStructure(
- BrowserAccessibilityManager* manager,
- BrowserAccessibility* parent,
- int32 renderer_id,
- int32 index_in_parent) {
- manager_ = manager;
- parent_ = parent;
- renderer_id_ = renderer_id;
- index_in_parent_ = index_in_parent;
-}
-
-void BrowserAccessibility::InitializeData(const ui::AXNodeData& src) {
- DCHECK_EQ(renderer_id_, src.id);
- role_ = src.role;
- state_ = src.state;
- string_attributes_ = src.string_attributes;
- int_attributes_ = src.int_attributes;
- float_attributes_ = src.float_attributes;
- bool_attributes_ = src.bool_attributes;
- intlist_attributes_ = src.intlist_attributes;
- html_attributes_ = src.html_attributes;
- location_ = src.location;
- instance_active_ = true;
-
- GetStringAttribute(ui::AX_ATTR_NAME, &name_);
- GetStringAttribute(ui::AX_ATTR_VALUE, &value_);
-
- PreInitialize();
+ return PlatformIsLeaf() ? 0 : InternalChildCount();
}
bool BrowserAccessibility::IsNative() const {
return false;
}
-void BrowserAccessibility::SwapChildren(
- std::vector<BrowserAccessibility*>& children) {
- children.swap(children_);
-}
-
-void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent,
- int index_in_parent) {
- parent_ = parent;
- index_in_parent_ = index_in_parent;
-}
-
-void BrowserAccessibility::SetLocation(const gfx::Rect& new_location) {
- location_ = new_location;
-}
-
bool BrowserAccessibility::IsDescendantOf(
BrowserAccessibility* ancestor) {
if (this == ancestor) {
return true;
- } else if (parent_) {
- return parent_->IsDescendantOf(ancestor);
+ } else if (GetParent()) {
+ return GetParent()->IsDescendantOf(ancestor);
}
return false;
BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
uint32 child_index) const {
- DCHECK(child_index < children_.size());
- return children_[child_index];
+ DCHECK(child_index < InternalChildCount());
+ BrowserAccessibility* result = InternalGetChild(child_index);
+
+ if (result->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
+ BrowserAccessibilityManager* child_manager =
+ manager_->delegate()->AccessibilityGetChildFrame(result->GetId());
+ if (child_manager)
+ result = child_manager->GetRoot();
+ }
+
+ return result;
}
BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
- if (parent_ && index_in_parent_ > 0)
- return parent_->children_[index_in_parent_ - 1];
+ if (GetParent() && GetIndexInParent() > 0)
+ return GetParent()->InternalGetChild(GetIndexInParent() - 1);
return NULL;
}
BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
- if (parent_ &&
- index_in_parent_ >= 0 &&
- index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
- return parent_->children_[index_in_parent_ + 1];
+ if (GetParent() &&
+ GetIndexInParent() >= 0 &&
+ GetIndexInParent() < static_cast<int>(
+ GetParent()->InternalChildCount() - 1)) {
+ return GetParent()->InternalGetChild(GetIndexInParent() + 1);
}
return NULL;
}
+uint32 BrowserAccessibility::InternalChildCount() const {
+ if (!node_ || !manager_)
+ return 0;
+ return static_cast<uint32>(node_->child_count());
+}
+
+BrowserAccessibility* BrowserAccessibility::InternalGetChild(
+ uint32 child_index) const {
+ if (!node_ || !manager_)
+ return NULL;
+ return manager_->GetFromAXNode(node_->children()[child_index]);
+}
+
+BrowserAccessibility* BrowserAccessibility::GetParent() const {
+ if (!node_ || !manager_)
+ return NULL;
+ ui::AXNode* parent = node_->parent();
+ if (parent)
+ return manager_->GetFromAXNode(parent);
+
+ if (!manager_->delegate())
+ return NULL;
+
+ BrowserAccessibility* host_node =
+ manager_->delegate()->AccessibilityGetParentFrame();
+ if (!host_node)
+ return NULL;
+
+ return host_node->GetParent();
+}
+
+int32 BrowserAccessibility::GetIndexInParent() const {
+ return node_ ? node_->index_in_parent() : -1;
+}
+
+int32 BrowserAccessibility::GetId() const {
+ return node_ ? node_->id() : -1;
+}
+
+const ui::AXNodeData& BrowserAccessibility::GetData() const {
+ CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ());
+ if (node_)
+ return node_->data();
+ else
+ return empty_data;
+}
+
+gfx::Rect BrowserAccessibility::GetLocation() const {
+ return GetData().location;
+}
+
+int32 BrowserAccessibility::GetRole() const {
+ return GetData().role;
+}
+
+int32 BrowserAccessibility::GetState() const {
+ return GetData().state;
+}
+
+const BrowserAccessibility::HtmlAttributes&
+BrowserAccessibility::GetHtmlAttributes() const {
+ return GetData().html_attributes;
+}
+
gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
- gfx::Rect bounds = location_;
+ gfx::Rect bounds = GetLocation();
// Walk up the parent chain. Every time we encounter a Web Area, offset
// based on the scroll bars and then offset based on the origin of that
// nested web area.
- BrowserAccessibility* parent = parent_;
+ BrowserAccessibility* parent = GetParent();
bool need_to_offset_web_area =
- (role_ == ui::AX_ROLE_WEB_AREA ||
- role_ == ui::AX_ROLE_ROOT_WEB_AREA);
+ (GetRole() == ui::AX_ROLE_WEB_AREA ||
+ GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
while (parent) {
if (need_to_offset_web_area &&
- parent->location().width() > 0 &&
- parent->location().height() > 0) {
- bounds.Offset(parent->location().x(), parent->location().y());
+ parent->GetLocation().width() > 0 &&
+ parent->GetLocation().height() > 0) {
+ bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
need_to_offset_web_area = false;
}
// On some platforms, we don't want to take the root scroll offsets
// into account.
- if (parent->role() == ui::AX_ROLE_ROOT_WEB_AREA &&
+ if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
!manager()->UseRootScrollOffsetsWhenComputingBounds()) {
break;
}
- if (parent->role() == ui::AX_ROLE_WEB_AREA ||
- parent->role() == ui::AX_ROLE_ROOT_WEB_AREA) {
+ if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
int sx = 0;
int sy = 0;
if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
}
need_to_offset_web_area = true;
}
- parent = parent->parent();
+ parent = parent->GetParent();
}
return bounds;
gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
const {
- if (role() != ui::AX_ROLE_STATIC_TEXT) {
+ if (GetRole() != ui::AX_ROLE_STATIC_TEXT) {
// Apply recursively to all static text descendants. For example, if
// you call it on a div with two text node children, it just calls
// GetLocalBoundsForRange on each of the two children (adjusting
// |start| for each one) and unions the resulting rects.
gfx::Rect bounds;
- for (size_t i = 0; i < children_.size(); ++i) {
- BrowserAccessibility* child = children_[i];
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ BrowserAccessibility* child = InternalGetChild(i);
int child_len = child->GetStaticTextLenRecursive();
if (start < child_len && start + len > 0) {
gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len);
int child_end = 0;
gfx::Rect bounds;
- for (size_t i = 0; i < children_.size() && child_end < start + len; ++i) {
- BrowserAccessibility* child = children_[i];
- DCHECK_EQ(child->role(), ui::AX_ROLE_INLINE_TEXT_BOX);
+ for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
+ BrowserAccessibility* child = InternalGetChild(i);
+ DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
std::string child_text;
child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
int child_len = static_cast<int>(child_text.size());
int local_start = overlap_start - child_start;
int local_end = overlap_end - child_start;
- gfx::Rect child_rect = child->location();
+ gfx::Rect child_rect = child->GetLocation();
int text_direction = child->GetIntAttribute(
ui::AX_ATTR_TEXT_DIRECTION);
const std::vector<int32>& character_offsets = child->GetIntListAttribute(
BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
const gfx::Point& point) {
+ // The best result found that's a child of this object.
+ BrowserAccessibility* child_result = NULL;
+ // The best result that's an indirect descendant like grandchild, etc.
+ BrowserAccessibility* descendant_result = NULL;
+
// Walk the children recursively looking for the BrowserAccessibility that
- // most tightly encloses the specified point.
+ // most tightly encloses the specified point. Walk backwards so that in
+ // the absence of any other information, we assume the object that occurs
+ // later in the tree is on top of one that comes before it.
for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) {
BrowserAccessibility* child = PlatformGetChild(i);
- if (child->GetGlobalBoundsRect().Contains(point))
- return child->BrowserAccessibilityForPoint(point);
+
+ // Skip table columns because cells are only contained in rows,
+ // not columns.
+ if (child->GetRole() == ui::AX_ROLE_COLUMN)
+ continue;
+
+ if (child->GetGlobalBoundsRect().Contains(point)) {
+ BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point);
+ if (result == child && !child_result)
+ child_result = result;
+ if (result != child && !descendant_result)
+ descendant_result = result;
+ }
+
+ if (child_result && descendant_result)
+ break;
}
+
+ // Explanation of logic: it's possible that this point overlaps more than
+ // one child of this object. If so, as a heuristic we prefer if the point
+ // overlaps a descendant of one of the two children and not the other.
+ // As an example, suppose you have two rows of buttons - the buttons don't
+ // overlap, but the rows do. Without this heuristic, we'd greedily only
+ // consider one of the containers.
+ if (descendant_result)
+ return descendant_result;
+ if (child_result)
+ return child_result;
+
return this;
}
void BrowserAccessibility::Destroy() {
- for (std::vector<BrowserAccessibility*>::iterator iter = children_.begin();
- iter != children_.end();
- ++iter) {
- (*iter)->Destroy();
- }
- children_.clear();
-
// Allow the object to fire a TextRemoved notification.
name_.clear();
value_.clear();
- PostInitialize();
manager_->NotifyAccessibilityEvent(ui::AX_EVENT_HIDE, this);
+ node_ = NULL;
+ manager_ = NULL;
- instance_active_ = false;
- manager_->RemoveNode(this);
NativeReleaseReference();
}
bool BrowserAccessibility::HasBoolAttribute(
ui::AXBoolAttribute attribute) const {
- for (size_t i = 0; i < bool_attributes_.size(); ++i) {
- if (bool_attributes_[i].first == attribute)
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
+ if (data.bool_attributes[i].first == attribute)
return true;
}
bool BrowserAccessibility::GetBoolAttribute(
ui::AXBoolAttribute attribute) const {
- for (size_t i = 0; i < bool_attributes_.size(); ++i) {
- if (bool_attributes_[i].first == attribute)
- return bool_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
+ if (data.bool_attributes[i].first == attribute)
+ return data.bool_attributes[i].second;
}
return false;
bool BrowserAccessibility::GetBoolAttribute(
ui::AXBoolAttribute attribute, bool* value) const {
- for (size_t i = 0; i < bool_attributes_.size(); ++i) {
- if (bool_attributes_[i].first == attribute) {
- *value = bool_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
+ if (data.bool_attributes[i].first == attribute) {
+ *value = data.bool_attributes[i].second;
return true;
}
}
bool BrowserAccessibility::HasFloatAttribute(
ui::AXFloatAttribute attribute) const {
- for (size_t i = 0; i < float_attributes_.size(); ++i) {
- if (float_attributes_[i].first == attribute)
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.float_attributes.size(); ++i) {
+ if (data.float_attributes[i].first == attribute)
return true;
}
float BrowserAccessibility::GetFloatAttribute(
ui::AXFloatAttribute attribute) const {
- for (size_t i = 0; i < float_attributes_.size(); ++i) {
- if (float_attributes_[i].first == attribute)
- return float_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.float_attributes.size(); ++i) {
+ if (data.float_attributes[i].first == attribute)
+ return data.float_attributes[i].second;
}
return 0.0;
bool BrowserAccessibility::GetFloatAttribute(
ui::AXFloatAttribute attribute, float* value) const {
- for (size_t i = 0; i < float_attributes_.size(); ++i) {
- if (float_attributes_[i].first == attribute) {
- *value = float_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.float_attributes.size(); ++i) {
+ if (data.float_attributes[i].first == attribute) {
+ *value = data.float_attributes[i].second;
return true;
}
}
bool BrowserAccessibility::HasIntAttribute(
ui::AXIntAttribute attribute) const {
- for (size_t i = 0; i < int_attributes_.size(); ++i) {
- if (int_attributes_[i].first == attribute)
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.int_attributes.size(); ++i) {
+ if (data.int_attributes[i].first == attribute)
return true;
}
}
int BrowserAccessibility::GetIntAttribute(ui::AXIntAttribute attribute) const {
- for (size_t i = 0; i < int_attributes_.size(); ++i) {
- if (int_attributes_[i].first == attribute)
- return int_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.int_attributes.size(); ++i) {
+ if (data.int_attributes[i].first == attribute)
+ return data.int_attributes[i].second;
}
return 0;
bool BrowserAccessibility::GetIntAttribute(
ui::AXIntAttribute attribute, int* value) const {
- for (size_t i = 0; i < int_attributes_.size(); ++i) {
- if (int_attributes_[i].first == attribute) {
- *value = int_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.int_attributes.size(); ++i) {
+ if (data.int_attributes[i].first == attribute) {
+ *value = data.int_attributes[i].second;
return true;
}
}
bool BrowserAccessibility::HasStringAttribute(
ui::AXStringAttribute attribute) const {
- for (size_t i = 0; i < string_attributes_.size(); ++i) {
- if (string_attributes_[i].first == attribute)
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.string_attributes.size(); ++i) {
+ if (data.string_attributes[i].first == attribute)
return true;
}
const std::string& BrowserAccessibility::GetStringAttribute(
ui::AXStringAttribute attribute) const {
+ const ui::AXNodeData& data = GetData();
CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ());
- for (size_t i = 0; i < string_attributes_.size(); ++i) {
- if (string_attributes_[i].first == attribute)
- return string_attributes_[i].second;
+ for (size_t i = 0; i < data.string_attributes.size(); ++i) {
+ if (data.string_attributes[i].first == attribute)
+ return data.string_attributes[i].second;
}
return empty_string;
bool BrowserAccessibility::GetStringAttribute(
ui::AXStringAttribute attribute, std::string* value) const {
- for (size_t i = 0; i < string_attributes_.size(); ++i) {
- if (string_attributes_[i].first == attribute) {
- *value = string_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.string_attributes.size(); ++i) {
+ if (data.string_attributes[i].first == attribute) {
+ *value = data.string_attributes[i].second;
return true;
}
}
void BrowserAccessibility::SetStringAttribute(
ui::AXStringAttribute attribute, const std::string& value) {
- for (size_t i = 0; i < string_attributes_.size(); ++i) {
- if (string_attributes_[i].first == attribute) {
- string_attributes_[i].second = value;
+ if (!node_)
+ return;
+ ui::AXNodeData data = GetData();
+ for (size_t i = 0; i < data.string_attributes.size(); ++i) {
+ if (data.string_attributes[i].first == attribute) {
+ data.string_attributes[i].second = value;
+ node_->SetData(data);
return;
}
}
- if (!value.empty())
- string_attributes_.push_back(std::make_pair(attribute, value));
+ if (!value.empty()) {
+ data.string_attributes.push_back(std::make_pair(attribute, value));
+ node_->SetData(data);
+ }
}
bool BrowserAccessibility::HasIntListAttribute(
ui::AXIntListAttribute attribute) const {
- for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
- if (intlist_attributes_[i].first == attribute)
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
+ if (data.intlist_attributes[i].first == attribute)
return true;
}
const std::vector<int32>& BrowserAccessibility::GetIntListAttribute(
ui::AXIntListAttribute attribute) const {
+ const ui::AXNodeData& data = GetData();
CR_DEFINE_STATIC_LOCAL(std::vector<int32>, empty_vector, ());
- for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
- if (intlist_attributes_[i].first == attribute)
- return intlist_attributes_[i].second;
+ for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
+ if (data.intlist_attributes[i].first == attribute)
+ return data.intlist_attributes[i].second;
}
return empty_vector;
bool BrowserAccessibility::GetIntListAttribute(
ui::AXIntListAttribute attribute,
std::vector<int32>* value) const {
- for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
- if (intlist_attributes_[i].first == attribute) {
- *value = intlist_attributes_[i].second;
+ const ui::AXNodeData& data = GetData();
+ for (size_t i = 0; i < data.intlist_attributes.size(); ++i) {
+ if (data.intlist_attributes[i].first == attribute) {
+ *value = data.intlist_attributes[i].second;
return true;
}
}
bool BrowserAccessibility::GetHtmlAttribute(
const char* html_attr, std::string* value) const {
- for (size_t i = 0; i < html_attributes_.size(); ++i) {
- const std::string& attr = html_attributes_[i].first;
+ for (size_t i = 0; i < GetHtmlAttributes().size(); ++i) {
+ const std::string& attr = GetHtmlAttributes()[i].first;
if (LowerCaseEqualsASCII(attr, html_attr)) {
- *value = html_attributes_[i].second;
+ *value = GetHtmlAttributes()[i].second;
return true;
}
}
}
bool BrowserAccessibility::HasState(ui::AXState state_enum) const {
- return (state_ >> state_enum) & 1;
+ return (GetState() >> state_enum) & 1;
}
bool BrowserAccessibility::IsEditableText() const {
// These roles don't have readonly set, but they're not editable text.
- if (role_ == ui::AX_ROLE_SCROLL_AREA ||
- role_ == ui::AX_ROLE_COLUMN ||
- role_ == ui::AX_ROLE_TABLE_HEADER_CONTAINER) {
+ if (GetRole() == ui::AX_ROLE_SCROLL_AREA ||
+ GetRole() == ui::AX_ROLE_COLUMN ||
+ GetRole() == ui::AX_ROLE_TABLE_HEADER_CONTAINER) {
return false;
}
// or contenteditable. We also check for editable text roles to cover
// another element that has role=textbox set on it.
return (!HasState(ui::AX_STATE_READ_ONLY) ||
- role_ == ui::AX_ROLE_TEXT_FIELD ||
- role_ == ui::AX_ROLE_TEXT_AREA);
+ GetRole() == ui::AX_ROLE_TEXT_FIELD ||
+ GetRole() == ui::AX_ROLE_TEXT_AREA);
}
std::string BrowserAccessibility::GetTextRecursive() const {
}
int BrowserAccessibility::GetStaticTextLenRecursive() const {
- if (role_ == blink::WebAXRoleStaticText)
+ if (GetRole() == ui::AX_ROLE_STATIC_TEXT)
return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
int len = 0;
- for (size_t i = 0; i < children_.size(); ++i)
- len += children_[i]->GetStaticTextLenRecursive();
+ for (size_t i = 0; i < InternalChildCount(); ++i)
+ len += InternalGetChild(i)->GetStaticTextLenRecursive();
return len;
}