Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / browser_accessibility_manager_win.cc
index c4aaed9..69c8891 100644 (file)
 
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
 
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlcom.h>
-#include <atlcrack.h>
-#include <oleacc.h>
-
 #include "base/command_line.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/windows_version.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/accessibility/browser_accessibility_win.h"
+#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
 #include "content/common/accessibility_messages.h"
 
 namespace content {
 
-// Some screen readers expect every tab / every unique web content container
-// to be in its own HWND, like it was before Aura, but with Aura there's just
-// one main HWND for a frame, or even for the whole desktop. So, we need a
-// fake HWND as the root of the accessibility tree for each tab.
-// We should get rid of this code when the latest two versions of all
-// supported screen readers no longer make this assumption.
-//
-// This class implements a child HWND with zero size, that delegates its
-// accessibility implementation to the root of the BrowserAccessibilityManager
-// tree. This HWND is hooked up as the parent of the root object in the
-// BrowserAccessibilityManager tree, so when any accessibility client
-// calls ::WindowFromAccessibleObject, they get this HWND instead of the
-// DesktopWindowTreeHostWin.
-class AccessibleHWND
-    : public ATL::CWindowImpl<AccessibleHWND,
-                              ATL::CWindow,
-                              ATL::CWinTraits<WS_CHILD> > {
- public:
-  // Unfortunately, some screen readers look for this exact window class
-  // to enable certain features. It'd be great to remove this.
-  DECLARE_WND_CLASS_EX(L"Chrome_RenderWidgetHostHWND", CS_DBLCLKS, 0);
-
-  BEGIN_MSG_MAP_EX(AccessibleHWND)
-    MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
-  END_MSG_MAP()
-
-  AccessibleHWND(HWND parent, BrowserAccessibilityManagerWin* manager)
-      : manager_(manager) {
-    Create(parent);
-    ShowWindow(true);
-    MoveWindow(0, 0, 0, 0);
-
-    HRESULT hr = ::CreateStdAccessibleObject(
-        hwnd(), OBJID_WINDOW, IID_IAccessible,
-        reinterpret_cast<void **>(window_accessible_.Receive()));
-    DCHECK(SUCCEEDED(hr));
-  }
-
-  HWND hwnd() {
-    DCHECK(::IsWindow(m_hWnd));
-    return m_hWnd;
-  }
-
-  IAccessible* window_accessible() { return window_accessible_; }
-
-  void OnManagerDeleted() {
-    manager_ = NULL;
-  }
-
- protected:
-  virtual void OnFinalMessage(HWND hwnd) OVERRIDE {
-    if (manager_)
-      manager_->OnAccessibleHwndDeleted();
-    delete this;
-  }
-
- private:
-  LRESULT OnGetObject(UINT message,
-                      WPARAM w_param,
-                      LPARAM l_param) {
-    if (OBJID_CLIENT != l_param || !manager_)
-      return static_cast<LRESULT>(0L);
-
-    base::win::ScopedComPtr<IAccessible> root(
-        manager_->GetRoot()->ToBrowserAccessibilityWin());
-    return LresultFromObject(IID_IAccessible, w_param,
-        static_cast<IAccessible*>(root.Detach()));
-  }
-
-  BrowserAccessibilityManagerWin* manager_;
-  base::win::ScopedComPtr<IAccessible> window_accessible_;
-
-  DISALLOW_COPY_AND_ASSIGN(AccessibleHWND);
-};
-
-
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
-    const ui::AXNodeData& src,
+    const ui::AXTreeUpdate& initial_tree,
     BrowserAccessibilityDelegate* delegate,
     BrowserAccessibilityFactory* factory) {
   return new BrowserAccessibilityManagerWin(
-      GetDesktopWindow(), NULL, src, delegate, factory);
+      content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()).get(),
+      NULL, initial_tree, delegate, factory);
 }
 
 BrowserAccessibilityManagerWin*
@@ -110,16 +30,17 @@ BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() {
 }
 
 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
-    HWND parent_hwnd,
+    LegacyRenderWidgetHostHWND* accessible_hwnd,
     IAccessible* parent_iaccessible,
-    const ui::AXNodeData& src,
+    const ui::AXTreeUpdate& initial_tree,
     BrowserAccessibilityDelegate* delegate,
     BrowserAccessibilityFactory* factory)
-    : BrowserAccessibilityManager(src, delegate, factory),
-      parent_hwnd_(parent_hwnd),
+    : BrowserAccessibilityManager(initial_tree, delegate, factory),
+      parent_hwnd_(accessible_hwnd->GetParent()),
       parent_iaccessible_(parent_iaccessible),
       tracked_scroll_object_(NULL),
-      accessible_hwnd_(NULL) {
+      accessible_hwnd_(accessible_hwnd) {
+  accessible_hwnd_->set_browser_accessibility_manager(this);
 }
 
 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
@@ -132,15 +53,18 @@ BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
 }
 
 // static
-ui::AXNodeData BrowserAccessibilityManagerWin::GetEmptyDocument() {
+ui::AXTreeUpdate BrowserAccessibilityManagerWin::GetEmptyDocument() {
   ui::AXNodeData empty_document;
   empty_document.id = 0;
   empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
   empty_document.state =
-      (1 << blink::WebAXStateEnabled) |
-      (1 << ui::AX_STATE_READONLY) |
+      (1 << ui::AX_STATE_ENABLED) |
+      (1 << ui::AX_STATE_READ_ONLY) |
       (1 << ui::AX_STATE_BUSY);
-  return empty_document;
+
+  ui::AXTreeUpdate update;
+  update.nodes.push_back(empty_document);
+  return update;
 }
 
 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
@@ -149,39 +73,56 @@ void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
   if (!parent_iaccessible())
     return;
 
-  // If on Win 7 and complete accessibility is enabled, create a fake child HWND
+  // If on Win 7 and complete accessibility is enabled, use the fake child HWND
   // to use as the root of the accessibility tree. See comments above
-  // AccessibleHWND for details.
-  if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser() &&
-      !accessible_hwnd_) {
-    accessible_hwnd_ = new AccessibleHWND(parent_hwnd_, this);
+  // LegacyRenderWidgetHostHWND for details.
+  if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
+    DCHECK(accessible_hwnd_);
     parent_hwnd_ = accessible_hwnd_->hwnd();
     parent_iaccessible_ = accessible_hwnd_->window_accessible();
   }
-
   ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
 }
 
-void BrowserAccessibilityManagerWin::AddNodeToMap(BrowserAccessibility* node) {
-  BrowserAccessibilityManager::AddNodeToMap(node);
-  LONG unique_id_win = node->ToBrowserAccessibilityWin()->unique_id_win();
-  unique_id_to_renderer_id_map_[unique_id_win] = node->renderer_id();
+
+void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) {
+  BrowserAccessibilityManager::OnNodeCreated(node);
+  BrowserAccessibility* obj = GetFromAXNode(node);
+  LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
+  unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
 }
 
-void BrowserAccessibilityManagerWin::RemoveNode(BrowserAccessibility* node) {
-  unique_id_to_renderer_id_map_.erase(
-      node->ToBrowserAccessibilityWin()->unique_id_win());
-  BrowserAccessibilityManager::RemoveNode(node);
-  if (node == tracked_scroll_object_) {
+void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
+  BrowserAccessibilityManager::OnNodeWillBeDeleted(node);
+  BrowserAccessibility* obj = GetFromAXNode(node);
+  if (!obj)
+    return;
+  unique_id_to_ax_id_map_.erase(
+      obj->ToBrowserAccessibilityWin()->unique_id_win());
+  if (obj == tracked_scroll_object_) {
     tracked_scroll_object_->Release();
     tracked_scroll_object_ = NULL;
   }
 }
 
+void BrowserAccessibilityManagerWin::OnWindowFocused() {
+  // Fire a focus event on the root first and then the focused node.
+  if (focus_ != tree_->GetRoot())
+    NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
+  BrowserAccessibilityManager::OnWindowFocused();
+}
+
+void BrowserAccessibilityManagerWin::OnWindowBlurred() {
+  // Fire a blur event on the focused node first and then the root.
+  BrowserAccessibilityManager::OnWindowBlurred();
+  if (focus_ != tree_->GetRoot())
+    NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetRoot());
+}
+
 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
     ui::AXEvent event_type,
     BrowserAccessibility* node) {
-  if (node->role() == ui::AX_ROLE_INLINE_TEXT_BOX)
+  if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
     return;
 
   LONG event_id = EVENT_MIN;
@@ -216,10 +157,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
       event_id = EVENT_OBJECT_STATECHANGE;
       break;
     case ui::AX_EVENT_LIVE_REGION_CHANGED:
-      // TODO: try not firing a native notification at all, since
-      // on Windows, each individual item in a live region that changes
-      // already gets its own notification.
-      event_id = EVENT_OBJECT_REORDER;
+      if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY))
+        return;
+      event_id = EVENT_OBJECT_LIVEREGIONCHANGED;
       break;
     case ui::AX_EVENT_LOAD_COMPLETE:
       event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE;
@@ -236,6 +176,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
     case ui::AX_EVENT_SHOW:
       event_id = EVENT_OBJECT_SHOW;
       break;
+    case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
+      event_id = EVENT_SYSTEM_SCROLLINGEND;
+      break;
     case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
       event_id = EVENT_SYSTEM_SCROLLINGSTART;
       break;
@@ -286,6 +229,11 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
   }
 }
 
+void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
+  if (delegate_ && delegate_->AccessibilityViewHasFocus())
+    NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
+}
+
 void BrowserAccessibilityManagerWin::TrackScrollingObject(
     BrowserAccessibilityWin* node) {
   if (tracked_scroll_object_)
@@ -297,9 +245,9 @@ void BrowserAccessibilityManagerWin::TrackScrollingObject(
 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
     LONG unique_id_win) {
   base::hash_map<LONG, int32>::iterator iter =
-      unique_id_to_renderer_id_map_.find(unique_id_win);
-  if (iter != unique_id_to_renderer_id_map_.end()) {
-    BrowserAccessibility* result = GetFromRendererID(iter->second);
+      unique_id_to_ax_id_map_.find(unique_id_win);
+  if (iter != unique_id_to_ax_id_map_.end()) {
+    BrowserAccessibility* result = GetFromID(iter->second);
     if (result)
       return result->ToBrowserAccessibilityWin();
   }