Index: content/browser/accessibility/browser_accessibility_manager_android.cc |
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..911eff730fd3724cb3e7b3e8a489a182431ccf20 |
--- /dev/null |
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc |
@@ -0,0 +1,225 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/accessibility/browser_accessibility_manager_android.h" |
+ |
+#include <cmath> |
+ |
+#include "base/android/jni_android.h" |
+#include "base/android/jni_string.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/utf_string_conversions.h" |
+#include "base/values.h" |
+#include "content/browser/accessibility/browser_accessibility_android.h" |
+#include "content/common/accessibility_messages.h" |
+#include "jni/BrowserAccessibilityManager_jni.h" |
+ |
+using base::android::AttachCurrentThread; |
+ |
+namespace content { |
+ |
+namespace aria_strings { |
+ const char kAriaLivePolite[] = "polite"; |
+ const char kAriaLiveAssertive[] = "assertive"; |
+} |
+ |
+// static |
+BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
+ const AccessibilityNodeData& src, |
+ BrowserAccessibilityDelegate* delegate, |
+ BrowserAccessibilityFactory* factory) { |
+ return new BrowserAccessibilityManagerAndroid(NULL, src, delegate, factory); |
+} |
+ |
+BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid( |
+ ContentViewCoreImpl* content_view_core, |
+ const AccessibilityNodeData& src, |
+ BrowserAccessibilityDelegate* delegate, |
+ BrowserAccessibilityFactory* factory) |
+ : BrowserAccessibilityManager(src, delegate, factory), |
+ content_view_core_(content_view_core) { |
+ if (!content_view_core) |
+ return; |
+ JNIEnv* env = AttachCurrentThread(); |
+ base::android::ScopedJavaLocalRef<jobject> content_view_core_java = |
+ content_view_core->GetJavaObject(); |
+ java_ref_.Reset(Java_BrowserAccessibilityManager_create( |
+ env, reinterpret_cast<jint>(this), content_view_core_java.obj())); |
+} |
+ |
+BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() { |
+ if (java_ref_.is_null()) |
+ return; |
+ JNIEnv* env = AttachCurrentThread(); |
+ Java_BrowserAccessibilityManager_onNativeObjectDestroyed( |
+ env, java_ref_.obj()); |
+} |
+ |
+// static |
+AccessibilityNodeData BrowserAccessibilityManagerAndroid::GetEmptyDocument() { |
+ AccessibilityNodeData empty_document; |
+ empty_document.id = 0; |
+ empty_document.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; |
+ empty_document.state = 1 << AccessibilityNodeData::STATE_READONLY; |
+ return empty_document; |
+} |
+ |
+void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( |
+ int type, |
+ BrowserAccessibility* node) { |
+ if (java_ref_.is_null()) |
+ return; |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ switch (type) { |
+ case AccessibilityNotificationLoadComplete: |
+ Java_BrowserAccessibilityManager_handlePageLoaded( |
+ env, java_ref_.obj(), focus_->renderer_id()); |
+ break; |
+ case AccessibilityNotificationFocusChanged: |
+ Java_BrowserAccessibilityManager_handleFocusChanged( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ break; |
+ case AccessibilityNotificationCheckStateChanged: |
+ Java_BrowserAccessibilityManager_handleCheckStateChanged( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ break; |
+ case AccessibilityNotificationScrolledToAnchor: |
+ Java_BrowserAccessibilityManager_handleScrolledToAnchor( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ break; |
+ case AccessibilityNotificationAlert: |
+ Java_BrowserAccessibilityManager_announceObjectShow( |
+ env, java_ref_.obj(), node->renderer_id(), JNI_TRUE); |
+ case AccessibilityNotificationObjectShow: |
+ Java_BrowserAccessibilityManager_announceObjectShow( |
+ env, java_ref_.obj(), node->renderer_id(), JNI_FALSE); |
+ case AccessibilityNotificationSelectedTextChanged: |
+ Java_BrowserAccessibilityManager_handleTextSelectionChanged( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ break; |
+ case AccessibilityNotificationChildrenChanged: |
+ case AccessibilityNotificationTextChanged: |
+ case AccessibilityNotificationValueChanged: |
+ if (node->IsEditableText()) { |
+ Java_BrowserAccessibilityManager_handleEditableTextChanged( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ } else { |
+ Java_BrowserAccessibilityManager_handleContentChanged( |
+ env, java_ref_.obj(), node->renderer_id()); |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+} |
+ |
+jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) { |
+ return static_cast<jint>(root_->renderer_id()); |
+} |
+ |
+jint BrowserAccessibilityManagerAndroid::HitTest( |
+ JNIEnv* env, jobject obj, jint x, jint y) { |
+ BrowserAccessibilityAndroid* result = |
+ static_cast<BrowserAccessibilityAndroid*>( |
+ root_->BrowserAccessibilityForPoint(gfx::Point(x, y))); |
+ |
+ if (!result) |
+ return root_->renderer_id(); |
+ |
+ if (result->IsFocusable()) |
+ return result->renderer_id(); |
+ |
+ // Examine the children of |result| to find the nearest accessibility focus |
+ // candidate |
+ BrowserAccessibility* nearest_node = FuzzyHitTest(x, y, result); |
+ if (nearest_node) |
+ return nearest_node->renderer_id(); |
+ |
+ return root_->renderer_id(); |
+} |
+ |
+BrowserAccessibility* BrowserAccessibilityManagerAndroid::FuzzyHitTest( |
+ int x, int y, BrowserAccessibility* start_node) { |
+ BrowserAccessibility* nearest_node = NULL; |
+ float min_distance = MAXFLOAT; |
+ FuzzyHitTestImpl(x, y, start_node, &nearest_node, &min_distance); |
+ return nearest_node; |
+} |
+ |
+void BrowserAccessibilityManagerAndroid::FuzzyHitTestImpl( |
David Trainor- moved to gerrit
2013/06/04 20:27:18
Could this also be static?
dmazzoni
2013/06/07 20:23:16
Done.
|
+ int x, int y, BrowserAccessibility* start_node, |
+ BrowserAccessibility** nearest_candidate, float* nearest_distance) { |
+ BrowserAccessibilityAndroid* node = |
+ static_cast<BrowserAccessibilityAndroid*>(start_node); |
+ float distance = CalculateDistance(x, y, node); |
+ |
+ if (node->IsFocusable()) { |
+ if (distance < *nearest_distance) { |
+ *nearest_candidate = node; |
+ *nearest_distance = distance; |
+ } |
+ // Don't examine any more children of focusable node |
+ // TODO(aboxhall): what about focusable children? |
+ return; |
+ } |
+ |
+ if (!node->ComputeName().empty()) { |
+ if (distance < *nearest_distance) { |
+ *nearest_candidate = node; |
+ *nearest_distance = distance; |
+ } |
+ return; |
+ } |
+ |
+ if (!node->IsLeaf()) { |
+ for (uint32 i = 0; i < node->child_count(); i++) { |
+ BrowserAccessibility* child = node->GetChild(i); |
+ FuzzyHitTestImpl(x, y, child, nearest_candidate, nearest_distance); |
+ } |
+ } |
+} |
+ |
+// Restricts |val| to the range [min, max]. |
+static int clamp(int val, int min, int max) { |
David Trainor- moved to gerrit
2013/06/04 20:27:18
anonymous namespace instead of static?
dmazzoni
2013/06/07 20:23:16
Done.
|
+ if (val < min) |
David Trainor- moved to gerrit
2013/06/04 20:27:18
Since you're std in most places: std::min(std::max
dmazzoni
2013/06/07 20:23:16
Done.
dmazzoni
2013/06/07 20:23:16
Done.
|
+ return min; |
+ else if (val > max) |
+ return max; |
+ else |
+ return val; |
+} |
+ |
+// static |
+float BrowserAccessibilityManagerAndroid::CalculateDistance( |
+ int x, int y, BrowserAccessibility* node) { |
+ gfx::Rect node_bounds = node->GetLocalBoundsRect(); |
+ int nearest_x = clamp(x, node_bounds.x(), node_bounds.right()); |
+ int nearest_y = clamp(y, node_bounds.y(), node_bounds.bottom()); |
+ float dx = std::abs(x - nearest_x); |
+ float dy = std::abs(y - nearest_y); |
+ return std::sqrt(dx * dx + dy * dy); |
David Trainor- moved to gerrit
2013/06/04 20:27:18
You could always just track MinDistanceSquared ins
dmazzoni
2013/06/07 20:23:16
Done.
|
+} |
+ |
+jint BrowserAccessibilityManagerAndroid::GetNativeNodeById( |
+ JNIEnv* env, jobject obj, jint id) { |
+ return reinterpret_cast<jint>(GetFromRendererID(id)); |
+} |
+ |
+void BrowserAccessibilityManagerAndroid::NotifyRootChanged() { |
+ JNIEnv* env = AttachCurrentThread(); |
+ Java_BrowserAccessibilityManager_handleNavigate(env, java_ref_.obj()); |
+} |
+ |
+bool |
+BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() { |
+ // The Java layer handles the root scroll offset. |
+ return false; |
+} |
+ |
+bool RegisterBrowserAccessibilityManager(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace content |