Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Unified Diff: ui/accessibility/platform/ax_android_snapshot.cc

Issue 2808383004: Refactor and send voice interaction structure (Closed)
Patch Set: fix WmShell position Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/accessibility/platform/ax_android_snapshot.cc
diff --git a/ui/accessibility/platform/ax_android_snapshot.cc b/ui/accessibility/platform/ax_android_snapshot.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b2b67eb22239fee7607fe752c40edbf86e2853a0
--- /dev/null
+++ b/ui/accessibility/platform/ax_android_snapshot.cc
@@ -0,0 +1,252 @@
+// 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 "ui/accessibility/platform/ax_android_snapshot.h"
+
+#include <memory>
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_serializable_tree.h"
+#include "ui/accessibility/platform/ax_android_constants.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace ui {
+
+namespace {
+
+bool HasFocusableChild(const AXNode* node) {
+ for (auto* child : node->children()) {
+ if ((child->data().state & ui::AX_STATE_FOCUSABLE) != 0 ||
+ HasFocusableChild(child)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsLeaf(const AXNode* node) {
+ if (node->child_count() == 0)
+ return true;
+
+ if (node->IsTextNode()) {
+ return true;
+ }
+
+ switch (node->data().role) {
+ case ui::AX_ROLE_IMAGE:
+ case ui::AX_ROLE_METER:
+ case ui::AX_ROLE_SCROLL_BAR:
+ case ui::AX_ROLE_SLIDER:
+ case ui::AX_ROLE_SPLITTER:
+ case ui::AX_ROLE_PROGRESS_INDICATOR:
+ case ui::AX_ROLE_DATE:
+ case ui::AX_ROLE_DATE_TIME:
+ case ui::AX_ROLE_INPUT_TIME:
+ return true;
+ default:
+ return false;
+ }
+}
+
+std::unique_ptr<AXSnapshotNodeAndroid> WalkAXTreeDepthFirst(
+ const AXNode* node,
+ gfx::Rect rect,
+ const ui::AXTreeUpdate& update,
+ const AXTree* tree) {
+ auto result = base::MakeUnique<AXSnapshotNodeAndroid>();
+ if (node->IsTextNode())
+ result->text = GetText(node);
+ result->class_name = GetClassName(node);
+
+ result->text_size = -1.0;
+ result->bgcolor = 0;
+ result->color = 0;
+ result->bold = 0;
+ result->italic = 0;
+ result->line_through = 0;
+ result->underline = 0;
+
+ if (node->data().HasFloatAttribute(ui::AX_ATTR_FONT_SIZE)) {
+ gfx::RectF text_size_rect(
+ 0, 0, 1, node->data().GetFloatAttribute(ui::AX_ATTR_FONT_SIZE));
+ gfx::Rect scaled_text_size_rect =
+ RelativeToAbsoluteBounds(node, text_size_rect, tree);
+ result->text_size = scaled_text_size_rect.height();
+
+ const int text_style = node->data().GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+ result->color = node->data().GetIntAttribute(ui::AX_ATTR_COLOR);
+ result->bgcolor =
+ node->data().GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR);
+ 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;
+ }
+
+ const gfx::Rect& absolute_rect = GetPageBoundsRect(node, tree);
+ gfx::Rect parent_relative_rect = absolute_rect;
+ bool is_root = node->parent() == 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 (IsLeaf(node)) {
+ int start_selection = 0;
+ int end_selection = 0;
+ if (update.tree_data.sel_anchor_object_id == node->data().id) {
+ start_selection = update.tree_data.sel_anchor_offset;
+ end_selection = GetText(node).length();
+ }
+ if (update.tree_data.sel_focus_object_id == node->data().id) {
+ 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 (auto* child : node->children()) {
+ result->children.push_back(
+ WalkAXTreeDepthFirst(child, absolute_rect, update, tree));
+ }
+
+ return result;
+}
+}
+
+AX_EXPORT AXSnapshotNodeAndroid::AXSnapshotNodeAndroid() = default;
+AX_EXPORT AXSnapshotNodeAndroid::~AXSnapshotNodeAndroid() = default;
+
+AX_EXPORT std::unique_ptr<AXSnapshotNodeAndroid> AXSnapshotNodeAndroid::Create(
+ const AXTreeUpdate& update) {
+ auto tree = base::MakeUnique<ui::AXSerializableTree>();
+ if (!tree->Unserialize(update)) {
+ LOG(FATAL) << tree->error();
+ }
+ return WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get());
+}
+
+std::string GetClassName(const AXNode* node) {
+ switch (node->data().role) {
+ 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->parent() == 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;
+ }
+}
+
+base::string16 GetText(const AXNode* node) {
+ if (node->IsTextNode()) {
+ return node->data().GetString16Attribute(ui::AX_ATTR_NAME);
+ }
+ base::string16 text;
+ for (auto* child : node->children()) {
+ text += GetText(child);
+ }
+ return text;
+}
+
+gfx::Rect GetPageBoundsRect(const AXNode* node, const AXTree* tree) {
+ gfx::RectF bounds = node->data().location;
+ FixEmptyBounds(node, &bounds, tree);
+ return RelativeToAbsoluteBounds(node, bounds, tree);
+}
+
+void FixEmptyBounds(const AXNode* node,
+ gfx::RectF* bounds,
+ const AXTree* tree) {
+ if (bounds->width() > 0 && bounds->height() > 0)
+ return;
+ for (auto* child : node->children()) {
+ gfx::Rect child_bounds = GetPageBoundsRect(child, tree);
+ if (child_bounds.width() == 0 || child_bounds.height() == 0)
+ continue;
+ if (bounds->width() == 0 || bounds->height() == 0) {
+ *bounds = gfx::RectF(child_bounds);
+ continue;
+ }
+ bounds->Union(gfx::RectF(child_bounds));
+ }
+}
+
+gfx::Rect RelativeToAbsoluteBounds(const AXNode* node,
+ gfx::RectF bounds,
+ const AXTree* tree) {
+ const AXNode* current = node;
+ while (current != nullptr) {
+ if (current->data().transform)
+ current->data().transform->TransformRect(&bounds);
+ auto* container = tree->GetFromId(current->data().offset_container_id);
+ if (!container) {
+ if (current == tree->root())
+ container = current->parent();
+ else
+ container = tree->root();
+ }
+ if (!container || container == current)
+ break;
+
+ gfx::RectF container_bounds = container->data().location;
+ bounds.Offset(container_bounds.x(), container_bounds.y());
+ current = container;
+ }
+ return gfx::ToEnclosingRect(bounds);
+}
+
+} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698