| 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 |