Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(862)

Side by Side Diff: content/browser/accessibility/browser_accessibility_manager_android.cc

Issue 290633002: Implement Android accessible hit testing using an IPC to the renderer process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@better_logging_2
Patch Set: Remove unused function Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/accessibility/browser_accessibility_manager_android.h" 5 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 #include "base/android/jni_android.h" 9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h" 10 #include "base/android/jni_string.h"
(...skipping 15 matching lines...) Expand all
26 ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192 26 ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192
27 }; 27 };
28 28
29 enum AndroidHtmlElementType { 29 enum AndroidHtmlElementType {
30 HTML_ELEMENT_TYPE_SECTION, 30 HTML_ELEMENT_TYPE_SECTION,
31 HTML_ELEMENT_TYPE_LIST, 31 HTML_ELEMENT_TYPE_LIST,
32 HTML_ELEMENT_TYPE_CONTROL, 32 HTML_ELEMENT_TYPE_CONTROL,
33 HTML_ELEMENT_TYPE_ANY 33 HTML_ELEMENT_TYPE_ANY
34 }; 34 };
35 35
36 // Restricts |val| to the range [min, max].
37 int Clamp(int val, int min, int max) {
38 return std::min(std::max(val, min), max);
39 }
40
41 // These are special unofficial strings sent from TalkBack/BrailleBack 36 // These are special unofficial strings sent from TalkBack/BrailleBack
42 // to jump to certain categories of web elements. 37 // to jump to certain categories of web elements.
43 AndroidHtmlElementType HtmlElementTypeFromString(base::string16 element_type) { 38 AndroidHtmlElementType HtmlElementTypeFromString(base::string16 element_type) {
44 if (element_type == base::ASCIIToUTF16("SECTION")) 39 if (element_type == base::ASCIIToUTF16("SECTION"))
45 return HTML_ELEMENT_TYPE_SECTION; 40 return HTML_ELEMENT_TYPE_SECTION;
46 else if (element_type == base::ASCIIToUTF16("LIST")) 41 else if (element_type == base::ASCIIToUTF16("LIST"))
47 return HTML_ELEMENT_TYPE_LIST; 42 return HTML_ELEMENT_TYPE_LIST;
48 else if (element_type == base::ASCIIToUTF16("CONTROL")) 43 else if (element_type == base::ASCIIToUTF16("CONTROL"))
49 return HTML_ELEMENT_TYPE_CONTROL; 44 return HTML_ELEMENT_TYPE_CONTROL;
50 else 45 else
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 ui::AXEvent event_type, 115 ui::AXEvent event_type,
121 BrowserAccessibility* node) { 116 BrowserAccessibility* node) {
122 JNIEnv* env = AttachCurrentThread(); 117 JNIEnv* env = AttachCurrentThread();
123 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 118 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
124 if (obj.is_null()) 119 if (obj.is_null())
125 return; 120 return;
126 121
127 if (event_type == ui::AX_EVENT_HIDE) 122 if (event_type == ui::AX_EVENT_HIDE)
128 return; 123 return;
129 124
125 if (event_type == ui::AX_EVENT_HOVER) {
126 HandleHoverEvent(node);
127 return;
128 }
129
130 // Always send AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED to notify 130 // Always send AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED to notify
131 // the Android system that the accessibility hierarchy rooted at this 131 // the Android system that the accessibility hierarchy rooted at this
132 // node has changed. 132 // node has changed.
133 Java_BrowserAccessibilityManager_handleContentChanged( 133 Java_BrowserAccessibilityManager_handleContentChanged(
134 env, obj.obj(), node->GetId()); 134 env, obj.obj(), node->GetId());
135 135
136 switch (event_type) { 136 switch (event_type) {
137 case ui::AX_EVENT_LOAD_COMPLETE: 137 case ui::AX_EVENT_LOAD_COMPLETE:
138 Java_BrowserAccessibilityManager_handlePageLoaded( 138 Java_BrowserAccessibilityManager_handlePageLoaded(
139 env, obj.obj(), focus_->id()); 139 env, obj.obj(), focus_->id());
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 189
190 jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) { 190 jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) {
191 return static_cast<jint>(GetRoot()->GetId()); 191 return static_cast<jint>(GetRoot()->GetId());
192 } 192 }
193 193
194 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid( 194 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid(
195 JNIEnv* env, jobject obj, jint id) { 195 JNIEnv* env, jobject obj, jint id) {
196 return GetFromID(id) != NULL; 196 return GetFromID(id) != NULL;
197 } 197 }
198 198
199 jint BrowserAccessibilityManagerAndroid::HitTest( 199 void BrowserAccessibilityManagerAndroid::HitTest(
200 JNIEnv* env, jobject obj, jint x, jint y) { 200 JNIEnv* env, jobject obj, jint x, jint y) {
201 BrowserAccessibilityAndroid* result = 201 if (delegate())
202 static_cast<BrowserAccessibilityAndroid*>( 202 delegate()->AccessibilityHitTest(gfx::Point(x, y));
203 GetRoot()->BrowserAccessibilityForPoint(gfx::Point(x, y)));
204
205 if (!result)
206 return GetRoot()->GetId();
207
208 if (result->IsFocusable())
209 return result->GetId();
210
211 // Examine the children of |result| to find the nearest accessibility focus
212 // candidate
213 BrowserAccessibility* nearest_node = FuzzyHitTest(x, y, result);
214 if (nearest_node)
215 return nearest_node->GetId();
216
217 return GetRoot()->GetId();
218 } 203 }
219 204
220 jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( 205 jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
221 JNIEnv* env, jobject obj, jobject info, jint id) { 206 JNIEnv* env, jobject obj, jobject info, jint id) {
222 BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>( 207 BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
223 GetFromID(id)); 208 GetFromID(id));
224 if (!node) 209 if (!node)
225 return false; 210 return false;
226 211
227 if (node->GetParent()) { 212 if (node->GetParent()) {
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 SetFocus(GetRoot(), true); 394 SetFocus(GetRoot(), true);
410 } 395 }
411 396
412 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( 397 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible(
413 JNIEnv* env, jobject obj, jint id) { 398 JNIEnv* env, jobject obj, jint id) {
414 BrowserAccessibility* node = GetFromID(id); 399 BrowserAccessibility* node = GetFromID(id);
415 if (node) 400 if (node)
416 ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size())); 401 ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size()));
417 } 402 }
418 403
419 BrowserAccessibility* BrowserAccessibilityManagerAndroid::FuzzyHitTest( 404 void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
420 int x, int y, BrowserAccessibility* start_node) { 405 BrowserAccessibility* node) {
421 BrowserAccessibility* nearest_node = NULL; 406 JNIEnv* env = AttachCurrentThread();
422 int min_distance = INT_MAX; 407 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
423 FuzzyHitTestImpl(x, y, start_node, &nearest_node, &min_distance); 408 if (obj.is_null())
424 return nearest_node; 409 return;
425 }
426 410
427 // static 411 BrowserAccessibilityAndroid* ancestor =
428 void BrowserAccessibilityManagerAndroid::FuzzyHitTestImpl( 412 static_cast<BrowserAccessibilityAndroid*>(node->GetParent());
429 int x, int y, BrowserAccessibility* start_node, 413 while (ancestor) {
430 BrowserAccessibility** nearest_candidate, int* nearest_distance) { 414 if (ancestor->PlatformIsLeaf() ||
431 BrowserAccessibilityAndroid* node = 415 (ancestor->IsFocusable() && !ancestor->HasFocusableChild())) {
432 static_cast<BrowserAccessibilityAndroid*>(start_node); 416 node = ancestor;
433 int distance = CalculateDistanceSquared(x, y, node); 417 // Don't break - we want the highest ancestor that's focusable or a
434 418 // leaf node.
435 if (node->IsFocusable()) {
436 if (distance < *nearest_distance) {
437 *nearest_candidate = node;
438 *nearest_distance = distance;
439 } 419 }
440 // Don't examine any more children of focusable node 420 ancestor = static_cast<BrowserAccessibilityAndroid*>(ancestor->GetParent());
441 // TODO(aboxhall): what about focusable children?
442 return;
443 } 421 }
444 422
445 if (!node->GetText().empty()) { 423 Java_BrowserAccessibilityManager_handleHover(
446 if (distance < *nearest_distance) { 424 env, obj.obj(), node->GetId());
447 *nearest_candidate = node;
448 *nearest_distance = distance;
449 }
450 return;
451 }
452
453 for (uint32 i = 0; i < node->PlatformChildCount(); i++) {
454 BrowserAccessibility* child = node->PlatformGetChild(i);
455 FuzzyHitTestImpl(x, y, child, nearest_candidate, nearest_distance);
456 }
457 }
458
459 // static
460 int BrowserAccessibilityManagerAndroid::CalculateDistanceSquared(
461 int x, int y, BrowserAccessibility* node) {
462 gfx::Rect node_bounds = node->GetLocalBoundsRect();
463 int nearest_x = Clamp(x, node_bounds.x(), node_bounds.right());
464 int nearest_y = Clamp(y, node_bounds.y(), node_bounds.bottom());
465 int dx = std::abs(x - nearest_x);
466 int dy = std::abs(y - nearest_y);
467 return dx * dx + dy * dy;
468 } 425 }
469 426
470 jint BrowserAccessibilityManagerAndroid::FindElementType( 427 jint BrowserAccessibilityManagerAndroid::FindElementType(
471 JNIEnv* env, jobject obj, jint start_id, jstring element_type_str, 428 JNIEnv* env, jobject obj, jint start_id, jstring element_type_str,
472 jboolean forwards) { 429 jboolean forwards) {
473 BrowserAccessibility* node = GetFromID(start_id); 430 BrowserAccessibility* node = GetFromID(start_id);
474 if (!node) 431 if (!node)
475 return 0; 432 return 0;
476 433
477 AndroidHtmlElementType element_type = HtmlElementTypeFromString( 434 AndroidHtmlElementType element_type = HtmlElementTypeFromString(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() { 494 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() {
538 // The Java layer handles the root scroll offset. 495 // The Java layer handles the root scroll offset.
539 return false; 496 return false;
540 } 497 }
541 498
542 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { 499 bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
543 return RegisterNativesImpl(env); 500 return RegisterNativesImpl(env);
544 } 501 }
545 502
546 } // namespace content 503 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698