Chromium Code Reviews| Index: content/public/browser/voice_interaction_helper.cc |
| diff --git a/content/public/browser/voice_interaction_helper.cc b/content/public/browser/voice_interaction_helper.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a55a26c1f79c743b4dd5f06cc54ef14aa855b057 |
| --- /dev/null |
| +++ b/content/public/browser/voice_interaction_helper.cc |
| @@ -0,0 +1,172 @@ |
| +// Copyright 2017 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/public/browser/voice_interaction_helper.h" |
| + |
| +#include "content/browser/accessibility/browser_accessibility.h" |
| +#include "content/browser/web_contents/web_contents_impl.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "ui/accessibility/platform/ax_android_constants.h" |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +std::string GetClassName(BrowserAccessibility* node) { |
| + const char* class_name = nullptr; |
|
Luis Héctor Chávez
2017/04/03 23:24:12
Since you're only setting this once per branch, ho
Muyuan
2017/04/04 00:39:39
Done.
|
| + |
| + switch (node->GetRole()) { |
| + case ui::AX_ROLE_SEARCH_BOX: |
| + case ui::AX_ROLE_SPIN_BUTTON: |
| + case ui::AX_ROLE_TEXT_FIELD: |
| + class_name = ui::kAXEditTextClassname; |
| + break; |
| + case ui::AX_ROLE_SLIDER: |
| + class_name = ui::kAXSeekBarClassname; |
| + break; |
| + case ui::AX_ROLE_COLOR_WELL: |
| + case ui::AX_ROLE_COMBO_BOX: |
| + case ui::AX_ROLE_DATE: |
| + case ui::AX_ROLE_POP_UP_BUTTON: |
| + case ui::AX_ROLE_INPUT_TIME: |
| + class_name = ui::kAXSpinnerClassname; |
| + break; |
| + case ui::AX_ROLE_BUTTON: |
| + case ui::AX_ROLE_MENU_BUTTON: |
| + class_name = ui::kAXButtonClassname; |
| + break; |
| + case ui::AX_ROLE_CHECK_BOX: |
| + case ui::AX_ROLE_SWITCH: |
| + class_name = ui::kAXCheckBoxClassname; |
| + break; |
| + case ui::AX_ROLE_RADIO_BUTTON: |
| + class_name = ui::kAXRadioButtonClassname; |
| + break; |
| + case ui::AX_ROLE_TOGGLE_BUTTON: |
| + class_name = ui::kAXToggleButtonClassname; |
| + break; |
| + case ui::AX_ROLE_CANVAS: |
| + case ui::AX_ROLE_IMAGE: |
| + case ui::AX_ROLE_SVG_ROOT: |
| + class_name = ui::kAXImageClassname; |
| + break; |
| + case ui::AX_ROLE_METER: |
| + case ui::AX_ROLE_PROGRESS_INDICATOR: |
| + class_name = ui::kAXProgressBarClassname; |
| + break; |
| + case ui::AX_ROLE_TAB_LIST: |
| + class_name = ui::kAXTabWidgetClassname; |
| + break; |
| + case ui::AX_ROLE_GRID: |
| + case ui::AX_ROLE_TABLE: |
| + class_name = ui::kAXGridViewClassname; |
| + break; |
| + case ui::AX_ROLE_LIST: |
| + case ui::AX_ROLE_LIST_BOX: |
| + case ui::AX_ROLE_DESCRIPTION_LIST: |
| + class_name = ui::kAXListViewClassname; |
| + break; |
| + case ui::AX_ROLE_DIALOG: |
| + class_name = ui::kAXDialogClassname; |
| + break; |
| + case ui::AX_ROLE_ROOT_WEB_AREA: |
| + if (node->PlatformGetParent() == nullptr) { |
| + class_name = ui::kAXWebViewClassname; |
| + } else { |
| + class_name = ui::kAXViewClassname; |
| + } |
| + break; |
| + case ui::AX_ROLE_MENU_ITEM: |
| + case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: |
| + case ui::AX_ROLE_MENU_ITEM_RADIO: |
| + class_name = ui::kAXMenuItemClassname; |
| + break; |
| + default: |
| + class_name = ui::kAXViewClassname; |
| + break; |
| + } |
| + |
| + return std::string(class_name); |
| +} |
| + |
| +// TODO(muyuanli): refactor code in web_contents_android |
| +// to use this function as well. |
| +std::unique_ptr<AXViewStructure> WalkAXTreeDepthFirst( |
| + BrowserAccessibility* node, |
| + gfx::Rect rect, |
| + const ui::AXTreeUpdate& update) { |
| + auto result = base::MakeUnique<AXViewStructure>(); |
| + result->text = node->GetText(); |
| + result->class_name = GetClassName(node); |
| + |
| + const int text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE); |
| + result->bold = (text_style & ui::AX_TEXT_STYLE_BOLD) != 0; |
| + result->italic = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0; |
| + result->line_through = (text_style & ui::AX_TEXT_STYLE_LINE_THROUGH) != 0; |
| + result->underline = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0; |
| + |
| + result->text_size = node->GetFloatAttribute(ui::AX_ATTR_FONT_SIZE); |
| + result->bgcolor = node->GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR); |
| + |
| + const gfx::Rect& absolute_rect = node->GetPageBoundsRect(); |
| + gfx::Rect parent_relative_rect = absolute_rect; |
| + bool is_root = node->GetParent() == nullptr; |
| + if (!is_root) { |
| + parent_relative_rect.Offset(-rect.OffsetFromOrigin()); |
| + } |
| + result->rect = gfx::Rect(parent_relative_rect.x(), parent_relative_rect.y(), |
| + absolute_rect.width(), absolute_rect.height()); |
| + result->has_selection = false; |
| + |
| + if (node->PlatformIsLeaf()) { |
| + int start_selection = 0; |
| + int end_selection = 0; |
| + if (update.tree_data.sel_anchor_object_id == node->GetId()) { |
| + start_selection = update.tree_data.sel_anchor_offset; |
| + end_selection = node->GetText().length(); |
| + } |
| + if (update.tree_data.sel_focus_object_id == node->GetId()) { |
| + end_selection = update.tree_data.sel_focus_offset; |
| + } |
| + if (end_selection > 0) { |
| + result->has_selection = true; |
| + result->start_selection = start_selection; |
| + result->end_selection = end_selection; |
| + } |
| + } |
| + |
| + for (unsigned int i = 0; i < node->PlatformChildCount(); i++) { |
| + auto child = |
| + WalkAXTreeDepthFirst(node->PlatformGetChild(i), absolute_rect, update); |
| + result->children.push_back(std::move(child)); |
| + } |
| + |
| + return result; |
| +} |
| + |
| +void AXSnapshotCallback( |
| + const base::Callback<void(std::unique_ptr<AXViewStructure>)>& callback, |
| + const ui::AXTreeUpdate& ax_tree_update) { |
| + auto manager = std::unique_ptr<content::BrowserAccessibilityManager>( |
| + content::BrowserAccessibilityManager::Create(ax_tree_update, nullptr)); |
| + callback.Run( |
| + WalkAXTreeDepthFirst(manager->GetRoot(), gfx::Rect(), ax_tree_update)); |
| +} |
| + |
| +} // namespace |
| + |
| +AXViewStructure::AXViewStructure() {} |
| + |
| +AXViewStructure::~AXViewStructure() {} |
| + |
| +void GetAXViewStructure( |
| + WebContents* web_contents, |
| + const base::Callback<void(std::unique_ptr<AXViewStructure>)>& callback) { |
| + WebContentsImpl* web_contents_impl = |
| + static_cast<WebContentsImpl*>(web_contents); |
| + web_contents_impl->RequestAXTreeSnapshot( |
| + base::Bind(&AXSnapshotCallback, callback)); |
| +} |
| + |
| +} // namespace content |