OLD | NEW |
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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 ui::AXEvent event_type, | 120 ui::AXEvent event_type, |
121 BrowserAccessibility* node) { | 121 BrowserAccessibility* node) { |
122 JNIEnv* env = AttachCurrentThread(); | 122 JNIEnv* env = AttachCurrentThread(); |
123 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); | 123 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
124 if (obj.is_null()) | 124 if (obj.is_null()) |
125 return; | 125 return; |
126 | 126 |
127 if (event_type == ui::AX_EVENT_HIDE) | 127 if (event_type == ui::AX_EVENT_HIDE) |
128 return; | 128 return; |
129 | 129 |
| 130 if (event_type == ui::AX_EVENT_HOVER) { |
| 131 HandleHoverEvent(node); |
| 132 return; |
| 133 } |
| 134 |
130 // Always send AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED to notify | 135 // Always send AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED to notify |
131 // the Android system that the accessibility hierarchy rooted at this | 136 // the Android system that the accessibility hierarchy rooted at this |
132 // node has changed. | 137 // node has changed. |
133 Java_BrowserAccessibilityManager_handleContentChanged( | 138 Java_BrowserAccessibilityManager_handleContentChanged( |
134 env, obj.obj(), node->GetId()); | 139 env, obj.obj(), node->GetId()); |
135 | 140 |
136 switch (event_type) { | 141 switch (event_type) { |
137 case ui::AX_EVENT_LOAD_COMPLETE: | 142 case ui::AX_EVENT_LOAD_COMPLETE: |
138 Java_BrowserAccessibilityManager_handlePageLoaded( | 143 Java_BrowserAccessibilityManager_handlePageLoaded( |
139 env, obj.obj(), focus_->id()); | 144 env, obj.obj(), focus_->id()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 | 194 |
190 jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) { | 195 jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) { |
191 return static_cast<jint>(GetRoot()->GetId()); | 196 return static_cast<jint>(GetRoot()->GetId()); |
192 } | 197 } |
193 | 198 |
194 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid( | 199 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid( |
195 JNIEnv* env, jobject obj, jint id) { | 200 JNIEnv* env, jobject obj, jint id) { |
196 return GetFromID(id) != NULL; | 201 return GetFromID(id) != NULL; |
197 } | 202 } |
198 | 203 |
199 jint BrowserAccessibilityManagerAndroid::HitTest( | 204 void BrowserAccessibilityManagerAndroid::HitTest( |
200 JNIEnv* env, jobject obj, jint x, jint y) { | 205 JNIEnv* env, jobject obj, jint x, jint y) { |
201 BrowserAccessibilityAndroid* result = | 206 if (delegate()) |
202 static_cast<BrowserAccessibilityAndroid*>( | 207 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 } | 208 } |
219 | 209 |
220 jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( | 210 jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( |
221 JNIEnv* env, jobject obj, jobject info, jint id) { | 211 JNIEnv* env, jobject obj, jobject info, jint id) { |
222 BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>( | 212 BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>( |
223 GetFromID(id)); | 213 GetFromID(id)); |
224 if (!node) | 214 if (!node) |
225 return false; | 215 return false; |
226 | 216 |
227 if (node->GetParent()) { | 217 if (node->GetParent()) { |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 SetFocus(GetRoot(), true); | 399 SetFocus(GetRoot(), true); |
410 } | 400 } |
411 | 401 |
412 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( | 402 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( |
413 JNIEnv* env, jobject obj, jint id) { | 403 JNIEnv* env, jobject obj, jint id) { |
414 BrowserAccessibility* node = GetFromID(id); | 404 BrowserAccessibility* node = GetFromID(id); |
415 if (node) | 405 if (node) |
416 ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size())); | 406 ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size())); |
417 } | 407 } |
418 | 408 |
419 BrowserAccessibility* BrowserAccessibilityManagerAndroid::FuzzyHitTest( | 409 void BrowserAccessibilityManagerAndroid::HandleHoverEvent( |
420 int x, int y, BrowserAccessibility* start_node) { | 410 BrowserAccessibility* node) { |
421 BrowserAccessibility* nearest_node = NULL; | 411 JNIEnv* env = AttachCurrentThread(); |
422 int min_distance = INT_MAX; | 412 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
423 FuzzyHitTestImpl(x, y, start_node, &nearest_node, &min_distance); | 413 if (obj.is_null()) |
424 return nearest_node; | 414 return; |
425 } | |
426 | 415 |
427 // static | 416 BrowserAccessibilityAndroid* ancestor = |
428 void BrowserAccessibilityManagerAndroid::FuzzyHitTestImpl( | 417 static_cast<BrowserAccessibilityAndroid*>(node->GetParent()); |
429 int x, int y, BrowserAccessibility* start_node, | 418 while (ancestor) { |
430 BrowserAccessibility** nearest_candidate, int* nearest_distance) { | 419 if (ancestor->PlatformIsLeaf() || |
431 BrowserAccessibilityAndroid* node = | 420 (ancestor->IsFocusable() && !ancestor->HasFocusableChild())) { |
432 static_cast<BrowserAccessibilityAndroid*>(start_node); | 421 node = ancestor; |
433 int distance = CalculateDistanceSquared(x, y, node); | 422 // Don't break - we want the highest ancestor that's focusable or a |
434 | 423 // leaf node. |
435 if (node->IsFocusable()) { | |
436 if (distance < *nearest_distance) { | |
437 *nearest_candidate = node; | |
438 *nearest_distance = distance; | |
439 } | 424 } |
440 // Don't examine any more children of focusable node | 425 ancestor = static_cast<BrowserAccessibilityAndroid*>(ancestor->GetParent()); |
441 // TODO(aboxhall): what about focusable children? | |
442 return; | |
443 } | 426 } |
444 | 427 |
445 if (!node->GetText().empty()) { | 428 Java_BrowserAccessibilityManager_handleHover( |
446 if (distance < *nearest_distance) { | 429 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 } | 430 } |
469 | 431 |
470 jint BrowserAccessibilityManagerAndroid::FindElementType( | 432 jint BrowserAccessibilityManagerAndroid::FindElementType( |
471 JNIEnv* env, jobject obj, jint start_id, jstring element_type_str, | 433 JNIEnv* env, jobject obj, jint start_id, jstring element_type_str, |
472 jboolean forwards) { | 434 jboolean forwards) { |
473 BrowserAccessibility* node = GetFromID(start_id); | 435 BrowserAccessibility* node = GetFromID(start_id); |
474 if (!node) | 436 if (!node) |
475 return 0; | 437 return 0; |
476 | 438 |
477 AndroidHtmlElementType element_type = HtmlElementTypeFromString( | 439 AndroidHtmlElementType element_type = HtmlElementTypeFromString( |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() { | 499 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() { |
538 // The Java layer handles the root scroll offset. | 500 // The Java layer handles the root scroll offset. |
539 return false; | 501 return false; |
540 } | 502 } |
541 | 503 |
542 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { | 504 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { |
543 return RegisterNativesImpl(env); | 505 return RegisterNativesImpl(env); |
544 } | 506 } |
545 | 507 |
546 } // namespace content | 508 } // namespace content |
OLD | NEW |