| 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..a038b79db2d7b05b932508753cf9b818a764b62b
|
| --- /dev/null
|
| +++ b/content/public/browser/voice_interaction_helper.cc
|
| @@ -0,0 +1,149 @@
|
| +// 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) {
|
| + switch (node->GetRole()) {
|
| + case ui::AX_ROLE_SEARCH_BOX:
|
| + case ui::AX_ROLE_SPIN_BUTTON:
|
| + case ui::AX_ROLE_TEXT_FIELD:
|
| + return ui::kAXEditTextClassname;
|
| + case ui::AX_ROLE_SLIDER:
|
| + return ui::kAXSeekBarClassname;
|
| + 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:
|
| + return ui::kAXSpinnerClassname;
|
| + case ui::AX_ROLE_BUTTON:
|
| + case ui::AX_ROLE_MENU_BUTTON:
|
| + return ui::kAXButtonClassname;
|
| + case ui::AX_ROLE_CHECK_BOX:
|
| + case ui::AX_ROLE_SWITCH:
|
| + return ui::kAXCheckBoxClassname;
|
| + case ui::AX_ROLE_RADIO_BUTTON:
|
| + return ui::kAXRadioButtonClassname;
|
| + case ui::AX_ROLE_TOGGLE_BUTTON:
|
| + return ui::kAXToggleButtonClassname;
|
| + case ui::AX_ROLE_CANVAS:
|
| + case ui::AX_ROLE_IMAGE:
|
| + case ui::AX_ROLE_SVG_ROOT:
|
| + return ui::kAXImageClassname;
|
| + case ui::AX_ROLE_METER:
|
| + case ui::AX_ROLE_PROGRESS_INDICATOR:
|
| + return ui::kAXProgressBarClassname;
|
| + case ui::AX_ROLE_TAB_LIST:
|
| + return ui::kAXTabWidgetClassname;
|
| + case ui::AX_ROLE_GRID:
|
| + case ui::AX_ROLE_TABLE:
|
| + return ui::kAXGridViewClassname;
|
| + case ui::AX_ROLE_LIST:
|
| + case ui::AX_ROLE_LIST_BOX:
|
| + case ui::AX_ROLE_DESCRIPTION_LIST:
|
| + return ui::kAXListViewClassname;
|
| + case ui::AX_ROLE_DIALOG:
|
| + return ui::kAXDialogClassname;
|
| + case ui::AX_ROLE_ROOT_WEB_AREA:
|
| + return node->PlatformGetParent() == nullptr ? ui::kAXWebViewClassname
|
| + : ui::kAXViewClassname;
|
| + case ui::AX_ROLE_MENU_ITEM:
|
| + case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
|
| + case ui::AX_ROLE_MENU_ITEM_RADIO:
|
| + return ui::kAXMenuItemClassname;
|
| + default:
|
| + return ui::kAXViewClassname;
|
| + }
|
| +}
|
| +
|
| +// 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() = default;
|
| +
|
| +AXViewStructure::~AXViewStructure() = default;
|
| +
|
| +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
|
|
|