Index: content/renderer/renderer_accessibility_complete.cc |
diff --git a/content/renderer/renderer_accessibility_complete.cc b/content/renderer/renderer_accessibility_complete.cc |
deleted file mode 100644 |
index 1e203b3d43bd658a0dbed483c70f9f71f104f397..0000000000000000000000000000000000000000 |
--- a/content/renderer/renderer_accessibility_complete.cc |
+++ /dev/null |
@@ -1,546 +0,0 @@ |
-// 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/renderer/renderer_accessibility_complete.h" |
- |
-#include "base/bind.h" |
-#include "base/message_loop.h" |
-#include "content/renderer/accessibility_node_serializer.h" |
-#include "content/renderer/render_view_impl.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityObject.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
- |
-using WebKit::WebAccessibilityNotification; |
-using WebKit::WebAccessibilityObject; |
-using WebKit::WebDocument; |
-using WebKit::WebFrame; |
-using WebKit::WebNode; |
-using WebKit::WebPoint; |
-using WebKit::WebRect; |
-using WebKit::WebSize; |
-using WebKit::WebView; |
- |
-namespace content { |
- |
-bool WebAccessibilityNotificationToAccessibilityNotification( |
- WebAccessibilityNotification notification, |
- AccessibilityNotification* type) { |
- switch (notification) { |
- case WebKit::WebAccessibilityNotificationActiveDescendantChanged: |
- *type = AccessibilityNotificationActiveDescendantChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationCheckedStateChanged: |
- *type = AccessibilityNotificationCheckStateChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationChildrenChanged: |
- *type = AccessibilityNotificationChildrenChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationFocusedUIElementChanged: |
- *type = AccessibilityNotificationFocusChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationLayoutComplete: |
- *type = AccessibilityNotificationLayoutComplete; |
- break; |
- case WebKit::WebAccessibilityNotificationLiveRegionChanged: |
- *type = AccessibilityNotificationLiveRegionChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationLoadComplete: |
- *type = AccessibilityNotificationLoadComplete; |
- break; |
- case WebKit::WebAccessibilityNotificationMenuListItemSelected: |
- *type = AccessibilityNotificationMenuListItemSelected; |
- break; |
- case WebKit::WebAccessibilityNotificationMenuListValueChanged: |
- *type = AccessibilityNotificationMenuListValueChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationRowCollapsed: |
- *type = AccessibilityNotificationRowCollapsed; |
- break; |
- case WebKit::WebAccessibilityNotificationRowCountChanged: |
- *type = AccessibilityNotificationRowCountChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationRowExpanded: |
- *type = AccessibilityNotificationRowExpanded; |
- break; |
- case WebKit::WebAccessibilityNotificationScrolledToAnchor: |
- *type = AccessibilityNotificationScrolledToAnchor; |
- break; |
- case WebKit::WebAccessibilityNotificationSelectedChildrenChanged: |
- *type = AccessibilityNotificationSelectedChildrenChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationSelectedTextChanged: |
- *type = AccessibilityNotificationSelectedTextChanged; |
- break; |
- case WebKit::WebAccessibilityNotificationValueChanged: |
- *type = AccessibilityNotificationValueChanged; |
- break; |
- default: |
- DLOG(WARNING) |
- << "WebKit accessibility notification not handled in switch!"; |
- return false; |
- } |
- return true; |
-} |
- |
-RendererAccessibilityComplete::RendererAccessibilityComplete( |
- RenderViewImpl* render_view) |
- : RendererAccessibility(render_view), |
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
- browser_root_(NULL), |
- last_scroll_offset_(gfx::Size()), |
- ack_pending_(false) { |
- WebAccessibilityObject::enableAccessibility(); |
- |
- const WebDocument& document = GetMainDocument(); |
- if (!document.isNull()) { |
- // It's possible that the webview has already loaded a webpage without |
- // accessibility being enabled. Initialize the browser's cached |
- // accessibility tree by sending it a 'load complete' notification. |
- HandleAccessibilityNotification( |
- document.accessibilityObject(), |
- AccessibilityNotificationLayoutComplete); |
- } |
-} |
- |
-RendererAccessibilityComplete::~RendererAccessibilityComplete() { |
-} |
- |
-bool RendererAccessibilityComplete::OnMessageReceived( |
- const IPC::Message& message) { |
- bool handled = true; |
- IPC_BEGIN_MESSAGE_MAP(RendererAccessibilityComplete, message) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_SetFocus, OnSetFocus) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_DoDefaultAction, |
- OnDoDefaultAction) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_Notifications_ACK, |
- OnNotificationsAck) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToMakeVisible, |
- OnScrollToMakeVisible) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToPoint, |
- OnScrollToPoint) |
- IPC_MESSAGE_HANDLER(AccessibilityMsg_SetTextSelection, |
- OnSetTextSelection) |
- IPC_MESSAGE_UNHANDLED(handled = false) |
- IPC_END_MESSAGE_MAP() |
- return handled; |
-} |
- |
-void RendererAccessibilityComplete::FocusedNodeChanged(const WebNode& node) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- if (node.isNull()) { |
- // When focus is cleared, implicitly focus the document. |
- // TODO(dmazzoni): Make WebKit send this notification instead. |
- HandleAccessibilityNotification( |
- document.accessibilityObject(), |
- AccessibilityNotificationBlur); |
- } |
-} |
- |
-void RendererAccessibilityComplete::DidFinishLoad(WebKit::WebFrame* frame) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- // Check to see if the root accessibility object has changed, to work |
- // around WebKit bugs that cause AXObjectCache to be cleared |
- // unnecessarily. |
- // TODO(dmazzoni): remove this once rdar://5794454 is fixed. |
- WebAccessibilityObject new_root = document.accessibilityObject(); |
- if (!browser_root_ || new_root.axID() != browser_root_->id) { |
- HandleAccessibilityNotification( |
- new_root, |
- AccessibilityNotificationLayoutComplete); |
- } |
-} |
- |
-void RendererAccessibilityComplete::HandleWebAccessibilityNotification( |
- const WebAccessibilityObject& obj, |
- WebAccessibilityNotification notification) { |
- AccessibilityNotification temp; |
- if (!WebAccessibilityNotificationToAccessibilityNotification( |
- notification, &temp)) { |
- return; |
- } |
- |
- HandleAccessibilityNotification(obj, temp); |
-} |
- |
-void RendererAccessibilityComplete::HandleAccessibilityNotification( |
- const WebKit::WebAccessibilityObject& obj, |
- AccessibilityNotification notification) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- gfx::Size scroll_offset = document.frame()->scrollOffset(); |
- if (scroll_offset != last_scroll_offset_) { |
- // Make sure the browser is always aware of the scroll position of |
- // the root document element by posting a generic notification that |
- // will update it. |
- // TODO(dmazzoni): remove this as soon as |
- // https://bugs.webkit.org/show_bug.cgi?id=73460 is fixed. |
- last_scroll_offset_ = scroll_offset; |
- if (!obj.equals(document.accessibilityObject())) { |
- HandleAccessibilityNotification( |
- document.accessibilityObject(), |
- AccessibilityNotificationLayoutComplete); |
- } |
- } |
- |
- // Add the accessibility object to our cache and ensure it's valid. |
- AccessibilityHostMsg_NotificationParams acc_notification; |
- acc_notification.id = obj.axID(); |
- acc_notification.notification_type = notification; |
- |
- // Discard duplicate accessibility notifications. |
- for (uint32 i = 0; i < pending_notifications_.size(); ++i) { |
- if (pending_notifications_[i].id == acc_notification.id && |
- pending_notifications_[i].notification_type == |
- acc_notification.notification_type) { |
- return; |
- } |
- } |
- pending_notifications_.push_back(acc_notification); |
- |
- if (!ack_pending_ && !weak_factory_.HasWeakPtrs()) { |
- // When no accessibility notifications are in-flight post a task to send |
- // the notifications to the browser. We use PostTask so that we can queue |
- // up additional notifications. |
- MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind( |
- &RendererAccessibilityComplete:: |
- SendPendingAccessibilityNotifications, |
- weak_factory_.GetWeakPtr())); |
- } |
-} |
- |
-RendererAccessibilityComplete::BrowserTreeNode::BrowserTreeNode() : id(0) {} |
- |
-RendererAccessibilityComplete::BrowserTreeNode::~BrowserTreeNode() {} |
- |
-void RendererAccessibilityComplete::SendPendingAccessibilityNotifications() { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- if (pending_notifications_.empty()) |
- return; |
- |
- ack_pending_ = true; |
- |
- // Make a copy of the notifications, because it's possible that |
- // actions inside this loop will cause more notifications to be |
- // queued up. |
- std::vector<AccessibilityHostMsg_NotificationParams> src_notifications = |
- pending_notifications_; |
- pending_notifications_.clear(); |
- |
- // Allow WebKit to cache intermediate results since we're doing a bunch |
- // of read-only queries at once. |
- WebAccessibilityObject rootObject = document.accessibilityObject(); |
- rootObject.startCachingComputedObjectAttributesUntilTreeMutates(); |
- |
- // Generate a notification message from each WebKit notification. |
- std::vector<AccessibilityHostMsg_NotificationParams> notification_msgs; |
- |
- // Loop over each notification and generate an updated notification message. |
- for (size_t i = 0; i < src_notifications.size(); ++i) { |
- AccessibilityHostMsg_NotificationParams& notification = |
- src_notifications[i]; |
- |
- // TODO(dtseng): Come up with a cleaner way of deciding to include children. |
- int root_id = rootObject.axID(); |
- bool includes_children = ShouldIncludeChildren(notification) || |
- root_id == notification.id; |
- WebAccessibilityObject obj = document.accessibilityObjectFromID( |
- notification.id); |
- if (!obj.updateBackingStoreAndCheckValidity()) |
- continue; |
- |
- // The browser may not have this object yet, for example if we get a |
- // notification on an object that was recently added, or if we get a |
- // notification on a node before the page has loaded. Work our way |
- // up the parent chain until we find a node the browser has, or until |
- // we reach the root. |
- while (browser_id_map_.find(obj.axID()) == browser_id_map_.end() && |
- !obj.isDetached() && |
- obj.axID() != root_id) { |
- obj = obj.parentObject(); |
- includes_children = true; |
- if (notification.notification_type == |
- AccessibilityNotificationChildrenChanged) { |
- notification.id = obj.axID(); |
- } |
- } |
- |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) |
- LOG(WARNING) << "Got notification on object that is invalid or has" |
- << " invalid ancestor. Id: " << obj.axID(); |
-#endif |
- continue; |
- } |
- |
- // Another potential problem is that this notification may be on an |
- // object that is detached from the tree. Determine if this node is not a |
- // child of its parent, and if so move the notification to the parent. |
- // TODO(dmazzoni): see if this can be removed after |
- // https://bugs.webkit.org/show_bug.cgi?id=68466 is fixed. |
- if (obj.axID() != root_id) { |
- WebAccessibilityObject parent = obj.parentObject(); |
- while (!parent.isDetached() && |
- parent.accessibilityIsIgnored()) { |
- parent = parent.parentObject(); |
- } |
- |
- if (parent.isDetached()) { |
- NOTREACHED(); |
- continue; |
- } |
- bool is_child_of_parent = false; |
- for (unsigned int i = 0; i < parent.childCount(); ++i) { |
- if (parent.childAt(i).equals(obj)) { |
- is_child_of_parent = true; |
- break; |
- } |
- } |
- |
- if (!is_child_of_parent) { |
- obj = parent; |
- notification.id = obj.axID(); |
- includes_children = true; |
- } |
- } |
- |
- AccessibilityHostMsg_NotificationParams notification_msg; |
- notification_msg.notification_type = notification.notification_type; |
- notification_msg.id = notification.id; |
- notification_msg.includes_children = includes_children; |
- SerializeAccessibilityNode(obj, |
- ¬ification_msg.acc_tree, |
- includes_children); |
- if (obj.axID() == root_id) { |
- DCHECK_EQ(notification_msg.acc_tree.role, |
- AccessibilityNodeData::ROLE_WEB_AREA); |
- notification_msg.acc_tree.role = |
- AccessibilityNodeData::ROLE_ROOT_WEB_AREA; |
- } |
- notification_msgs.push_back(notification_msg); |
- |
- if (includes_children) |
- UpdateBrowserTree(notification_msg.acc_tree); |
- |
-#ifndef NDEBUG |
- if (logging_) { |
- LOG(INFO) << "Accessibility update: \n" |
- << "routing id=" << routing_id() |
- << " notification=" |
- << AccessibilityNotificationToString(notification.notification_type) |
- << "\n" << notification_msg.acc_tree.DebugString(true); |
- } |
-#endif |
- } |
- |
- Send(new AccessibilityHostMsg_Notifications(routing_id(), notification_msgs)); |
-} |
- |
-void RendererAccessibilityComplete::UpdateBrowserTree( |
- const AccessibilityNodeData& renderer_node) { |
- BrowserTreeNode* browser_node = NULL; |
- base::hash_map<int32, BrowserTreeNode*>::iterator iter = |
- browser_id_map_.find(renderer_node.id); |
- if (iter != browser_id_map_.end()) { |
- browser_node = iter->second; |
- ClearBrowserTreeNode(browser_node); |
- } else { |
- DCHECK_EQ(renderer_node.role, AccessibilityNodeData::ROLE_ROOT_WEB_AREA); |
- if (browser_root_) { |
- ClearBrowserTreeNode(browser_root_); |
- browser_id_map_.erase(browser_root_->id); |
- delete browser_root_; |
- } |
- browser_root_ = new BrowserTreeNode; |
- browser_node = browser_root_; |
- browser_node->id = renderer_node.id; |
- browser_id_map_[browser_node->id] = browser_node; |
- } |
- browser_node->children.reserve(renderer_node.children.size()); |
- for (size_t i = 0; i < renderer_node.children.size(); ++i) { |
- BrowserTreeNode* browser_child_node = new BrowserTreeNode; |
- browser_child_node->id = renderer_node.children[i].id; |
- browser_id_map_[browser_child_node->id] = browser_child_node; |
- browser_node->children.push_back(browser_child_node); |
- UpdateBrowserTree(renderer_node.children[i]); |
- } |
-} |
- |
-void RendererAccessibilityComplete::ClearBrowserTreeNode( |
- BrowserTreeNode* browser_node) { |
- for (size_t i = 0; i < browser_node->children.size(); ++i) { |
- browser_id_map_.erase(browser_node->children[i]->id); |
- ClearBrowserTreeNode(browser_node->children[i]); |
- delete browser_node->children[i]; |
- } |
- browser_node->children.clear(); |
-} |
- |
-void RendererAccessibilityComplete::OnDoDefaultAction(int acc_obj_id) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- WebAccessibilityObject obj = document.accessibilityObjectFromID(acc_obj_id); |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) |
- LOG(WARNING) << "DoDefaultAction on invalid object id " << acc_obj_id; |
-#endif |
- return; |
- } |
- |
- obj.performDefaultAction(); |
-} |
- |
-void RendererAccessibilityComplete::OnScrollToMakeVisible( |
- int acc_obj_id, gfx::Rect subfocus) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- WebAccessibilityObject obj = document.accessibilityObjectFromID(acc_obj_id); |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) |
- LOG(WARNING) << "ScrollToMakeVisible on invalid object id " << acc_obj_id; |
-#endif |
- return; |
- } |
- |
- obj.scrollToMakeVisibleWithSubFocus( |
- WebRect(subfocus.x(), subfocus.y(), |
- subfocus.width(), subfocus.height())); |
- |
- // Make sure the browser gets a notification when the scroll |
- // position actually changes. |
- // TODO(dmazzoni): remove this once this bug is fixed: |
- // https://bugs.webkit.org/show_bug.cgi?id=73460 |
- HandleAccessibilityNotification( |
- document.accessibilityObject(), |
- AccessibilityNotificationLayoutComplete); |
-} |
- |
-void RendererAccessibilityComplete::OnScrollToPoint( |
- int acc_obj_id, gfx::Point point) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- WebAccessibilityObject obj = document.accessibilityObjectFromID(acc_obj_id); |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) |
- LOG(WARNING) << "ScrollToPoint on invalid object id " << acc_obj_id; |
-#endif |
- return; |
- } |
- |
- obj.scrollToGlobalPoint(WebPoint(point.x(), point.y())); |
- |
- // Make sure the browser gets a notification when the scroll |
- // position actually changes. |
- // TODO(dmazzoni): remove this once this bug is fixed: |
- // https://bugs.webkit.org/show_bug.cgi?id=73460 |
- HandleAccessibilityNotification( |
- document.accessibilityObject(), |
- AccessibilityNotificationLayoutComplete); |
-} |
- |
-void RendererAccessibilityComplete::OnSetTextSelection( |
- int acc_obj_id, int start_offset, int end_offset) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- WebAccessibilityObject obj = document.accessibilityObjectFromID(acc_obj_id); |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) |
- LOG(WARNING) << "SetTextSelection on invalid object id " << acc_obj_id; |
-#endif |
- return; |
- } |
- |
- // TODO(dmazzoni): support elements other than <input>. |
- WebKit::WebNode node = obj.node(); |
- if (!node.isNull() && node.isElementNode()) { |
- WebKit::WebElement element = node.to<WebKit::WebElement>(); |
- WebKit::WebInputElement* input_element = |
- WebKit::toWebInputElement(&element); |
- if (input_element && input_element->isTextField()) |
- input_element->setSelectionRange(start_offset, end_offset); |
- } |
-} |
- |
-void RendererAccessibilityComplete::OnNotificationsAck() { |
- DCHECK(ack_pending_); |
- ack_pending_ = false; |
- SendPendingAccessibilityNotifications(); |
-} |
- |
-void RendererAccessibilityComplete::OnSetFocus(int acc_obj_id) { |
- const WebDocument& document = GetMainDocument(); |
- if (document.isNull()) |
- return; |
- |
- WebAccessibilityObject obj = document.accessibilityObjectFromID(acc_obj_id); |
- if (obj.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) { |
- LOG(WARNING) << "OnSetAccessibilityFocus on invalid object id " |
- << acc_obj_id; |
- } |
-#endif |
- return; |
- } |
- |
- WebAccessibilityObject root = document.accessibilityObject(); |
- if (root.isDetached()) { |
-#ifndef NDEBUG |
- if (logging_) { |
- LOG(WARNING) << "OnSetAccessibilityFocus but root is invalid"; |
- } |
-#endif |
- return; |
- } |
- |
- // By convention, calling SetFocus on the root of the tree should clear the |
- // current focus. Otherwise set the focus to the new node. |
- if (acc_obj_id == root.axID()) |
- render_view()->GetWebView()->clearFocusedNode(); |
- else |
- obj.setFocused(true); |
-} |
- |
-bool RendererAccessibilityComplete::ShouldIncludeChildren( |
- const AccessibilityHostMsg_NotificationParams& notification) { |
- AccessibilityNotification type = notification.notification_type; |
- if (type == AccessibilityNotificationChildrenChanged || |
- type == AccessibilityNotificationLoadComplete || |
- type == AccessibilityNotificationLiveRegionChanged || |
- type == AccessibilityNotificationSelectedChildrenChanged) { |
- return true; |
- } |
- return false; |
-} |
- |
-} // namespace content |