Chromium Code Reviews| 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 |