• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
6 
7 #include "content/renderer/render_view_impl.h"
8 #include "third_party/WebKit/public/web/WebDocument.h"
9 #include "third_party/WebKit/public/web/WebElement.h"
10 #include "third_party/WebKit/public/web/WebLocalFrame.h"
11 #include "third_party/WebKit/public/web/WebNode.h"
12 #include "third_party/WebKit/public/web/WebView.h"
13 #include "ui/accessibility/ax_node_data.h"
14 
15 using blink::WebDocument;
16 using blink::WebElement;
17 using blink::WebNode;
18 using blink::WebView;
19 
20 namespace {
21 // The root node will always have id 1. Let each child node have a new
22 // id starting with 2.
23 const int kInitialId = 2;
24 }
25 
26 namespace content {
27 
RendererAccessibilityFocusOnly(RenderViewImpl * render_view)28 RendererAccessibilityFocusOnly::RendererAccessibilityFocusOnly(
29     RenderViewImpl* render_view)
30     : RendererAccessibility(render_view),
31       next_id_(kInitialId) {
32 }
33 
~RendererAccessibilityFocusOnly()34 RendererAccessibilityFocusOnly::~RendererAccessibilityFocusOnly() {
35 }
36 
HandleWebAccessibilityEvent(const blink::WebAXObject & obj,blink::WebAXEvent event)37 void RendererAccessibilityFocusOnly::HandleWebAccessibilityEvent(
38     const blink::WebAXObject& obj, blink::WebAXEvent event) {
39   // Do nothing.
40 }
41 
GetType()42 RendererAccessibilityType RendererAccessibilityFocusOnly::GetType() {
43   return RendererAccessibilityTypeFocusOnly;
44 }
45 
FocusedNodeChanged(const WebNode & node)46 void RendererAccessibilityFocusOnly::FocusedNodeChanged(const WebNode& node) {
47   // Send the new accessible tree and post a native focus event.
48   HandleFocusedNodeChanged(node, true);
49 }
50 
DidFinishLoad(blink::WebLocalFrame * frame)51 void RendererAccessibilityFocusOnly::DidFinishLoad(
52     blink::WebLocalFrame* frame) {
53   WebView* view = render_view()->GetWebView();
54   if (view->focusedFrame() != frame)
55     return;
56 
57   WebDocument document = frame->document();
58   // Send an accessible tree to the browser, but do not post a native
59   // focus event. This is important so that if focus is initially in an
60   // editable text field, Windows will know to pop up the keyboard if the
61   // user touches it and focus doesn't change.
62   HandleFocusedNodeChanged(document.focusedElement(), false);
63 }
64 
HandleFocusedNodeChanged(const WebNode & node,bool send_focus_event)65 void RendererAccessibilityFocusOnly::HandleFocusedNodeChanged(
66     const WebNode& node,
67     bool send_focus_event) {
68   const WebDocument& document = GetMainDocument();
69   if (document.isNull())
70     return;
71 
72   bool node_has_focus;
73   bool node_is_editable_text;
74   // Check HasIMETextFocus first, because it will correctly handle
75   // focus in a text box inside a ppapi plug-in. Otherwise fall back on
76   // checking the focused node in Blink.
77   if (render_view_->HasIMETextFocus()) {
78     node_has_focus = true;
79     node_is_editable_text = true;
80   } else {
81     node_has_focus = !node.isNull();
82     node_is_editable_text =
83         node_has_focus && render_view_->IsEditableNode(node);
84   }
85 
86   std::vector<AccessibilityHostMsg_EventParams> events;
87   events.push_back(AccessibilityHostMsg_EventParams());
88   AccessibilityHostMsg_EventParams& event = events[0];
89 
90   // If we want to update the browser's accessibility tree but not send a
91   // native focus changed event, we can send a LayoutComplete
92   // event, which doesn't post a native event on Windows.
93   event.event_type =
94       send_focus_event ? ui::AX_EVENT_FOCUS : ui::AX_EVENT_LAYOUT_COMPLETE;
95 
96   // Set the id that the event applies to: the root node if nothing
97   // has focus, otherwise the focused node.
98   event.id = node_has_focus ? next_id_ : 1;
99 
100   event.update.nodes.resize(2);
101   ui::AXNodeData& root = event.update.nodes[0];
102   ui::AXNodeData& child = event.update.nodes[1];
103 
104   // Always include the root of the tree, the document. It always has id 1.
105   root.id = 1;
106   root.role = ui::AX_ROLE_ROOT_WEB_AREA;
107   root.state =
108       (1 << ui::AX_STATE_READ_ONLY) |
109       (1 << ui::AX_STATE_FOCUSABLE);
110   if (!node_has_focus)
111     root.state |= (1 << ui::AX_STATE_FOCUSED);
112   root.location = gfx::Rect(render_view_->size());
113   root.child_ids.push_back(next_id_);
114 
115   child.id = next_id_;
116   child.role = ui::AX_ROLE_GROUP;
117 
118   if (!node.isNull() && node.isElementNode()) {
119     child.location = gfx::Rect(
120         const_cast<WebNode&>(node).to<WebElement>().boundsInViewportSpace());
121   } else if (render_view_->HasIMETextFocus()) {
122     child.location = root.location;
123   } else {
124     child.location = gfx::Rect();
125   }
126 
127   if (node_has_focus) {
128     child.state =
129         (1 << ui::AX_STATE_FOCUSABLE) |
130         (1 << ui::AX_STATE_FOCUSED);
131     if (!node_is_editable_text)
132       child.state |= (1 << ui::AX_STATE_READ_ONLY);
133   }
134 
135 #ifndef NDEBUG
136   /**
137   if (logging_) {
138     VLOG(0) << "Accessibility update: \n"
139         << "routing id=" << routing_id()
140         << " event="
141         << AccessibilityEventToString(event.event_type)
142         << "\n" << event.nodes[0].DebugString(true);
143   }
144   **/
145 #endif
146 
147   Send(new AccessibilityHostMsg_Events(routing_id(), events));
148 
149   // Increment the id, wrap back when we get past a million.
150   next_id_++;
151   if (next_id_ > 1000000)
152     next_id_ = kInitialId;
153 }
154 
155 }  // namespace content
156