// Copyright 2013 The Flutter 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 "accessibility_bridge.h"

#include <functional>
#include <utility>

#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h"
#include "flutter/third_party/accessibility/ax/ax_tree_update.h"
#include "flutter/third_party/accessibility/base/logging.h"

namespace flutter {  // namespace

constexpr int kHasScrollingAction =
    FlutterSemanticsAction::kFlutterSemanticsActionScrollLeft |
    FlutterSemanticsAction::kFlutterSemanticsActionScrollRight |
    FlutterSemanticsAction::kFlutterSemanticsActionScrollUp |
    FlutterSemanticsAction::kFlutterSemanticsActionScrollDown;

// AccessibilityBridge
AccessibilityBridge::AccessibilityBridge()
    : tree_(std::make_unique<ui::AXTree>()) {
  event_generator_.SetTree(tree_.get());
  tree_->AddObserver(static_cast<ui::AXTreeObserver*>(this));
  ui::AXTreeData data = tree_->data();
  data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
  tree_->UpdateData(data);
  ui::AXTreeManagerMap::GetInstance().AddTreeManager(tree_->GetAXTreeID(),
                                                     this);
}

AccessibilityBridge::~AccessibilityBridge() {
  event_generator_.ReleaseTree();
  tree_->RemoveObserver(static_cast<ui::AXTreeObserver*>(this));
}

void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(
    const FlutterSemanticsNode2& node) {
  pending_semantics_node_updates_[node.id] = FromFlutterSemanticsNode(node);
}

void AccessibilityBridge::AddFlutterSemanticsCustomActionUpdate(
    const FlutterSemanticsCustomAction2& action) {
  pending_semantics_custom_action_updates_[action.id] =
      FromFlutterSemanticsCustomAction(action);
}

void AccessibilityBridge::CommitUpdates() {
  // AXTree cannot move a node in a single update.
  // This must be split across two updates:
  //
  // * Update 1: remove nodes from their old parents.
  // * Update 2: re-add nodes (including their children) to their new parents.
  //
  // First, start by removing nodes if necessary.
  std::optional<ui::AXTreeUpdate> remove_reparented =
      CreateRemoveReparentedNodesUpdate();
  if (remove_reparented.has_value()) {
    tree_->Unserialize(remove_reparented.value());

    std::string error = tree_->error();
    if (!error.empty()) {
      FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error;
      assert(false);
      return;
    }
  }

  // Second, apply the pending node updates. This also moves reparented nodes to
  // their new parents if needed.
  ui::AXTreeUpdate update{.tree_data = tree_->data()};

  // Figure out update order, ui::AXTree only accepts update in tree order,
  // where parent node must come before the child node in
  // ui::AXTreeUpdate.nodes. We start with picking a random node and turn the
  // entire subtree into a list. We pick another node from the remaining update,
  // and keep doing so until the update map is empty. We then concatenate the
  // lists in the reversed order, this guarantees parent updates always come
  // before child updates. If the root is in the update, it is guaranteed to
  // be the first node of the last list.
  std::vector<std::vector<SemanticsNode>> results;
  while (!pending_semantics_node_updates_.empty()) {
    auto begin = pending_semantics_node_updates_.begin();
    SemanticsNode target = begin->second;
    std::vector<SemanticsNode> sub_tree_list;
    GetSubTreeList(target, sub_tree_list);
    results.push_back(sub_tree_list);
    pending_semantics_node_updates_.erase(begin);
  }

  for (size_t i = results.size(); i > 0; i--) {
    for (SemanticsNode node : results[i - 1]) {
      ConvertFlutterUpdate(node, update);
    }
  }

  // The first update must set the tree's root, which is guaranteed to be the
  // last list's first node. A tree's root node never changes, though it can be
  // modified.
  if (!results.empty() && GetRootAsAXNode()->id() == ui::AXNode::kInvalidAXID) {
    FML_DCHECK(!results.back().empty());

    update.root_id = results.back().front().id;
  }

  tree_->Unserialize(update);
  pending_semantics_node_updates_.clear();
  pending_semantics_custom_action_updates_.clear();

  std::string error = tree_->error();
  if (!error.empty()) {
    FML_LOG(ERROR) << "Failed to update ui::AXTree, error: " << error;
    return;
  }
  // Handles accessibility events as the result of the semantics update.
  for (const auto& targeted_event : event_generator_) {
    auto event_target =
        GetFlutterPlatformNodeDelegateFromID(targeted_event.node->id());
    if (event_target.expired()) {
      continue;
    }

    OnAccessibilityEvent(targeted_event);
  }
  event_generator_.ClearEvents();
}

std::weak_ptr<FlutterPlatformNodeDelegate>
AccessibilityBridge::GetFlutterPlatformNodeDelegateFromID(
    AccessibilityNodeId id) const {
  const auto iter = id_wrapper_map_.find(id);
  if (iter != id_wrapper_map_.end()) {
    return iter->second;
  }

  return std::weak_ptr<FlutterPlatformNodeDelegate>();
}

const ui::AXTreeData& AccessibilityBridge::GetAXTreeData() const {
  return tree_->data();
}

const std::vector<ui::AXEventGenerator::TargetedEvent>
AccessibilityBridge::GetPendingEvents() const {
  std::vector<ui::AXEventGenerator::TargetedEvent> result(
      event_generator_.begin(), event_generator_.end());
  return result;
}

void AccessibilityBridge::OnNodeWillBeDeleted(ui::AXTree* tree,
                                              ui::AXNode* node) {}

void AccessibilityBridge::OnSubtreeWillBeDeleted(ui::AXTree* tree,
                                                 ui::AXNode* node) {}

void AccessibilityBridge::OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) {
}

void AccessibilityBridge::OnRoleChanged(ui::AXTree* tree,
                                        ui::AXNode* node,
                                        ax::mojom::Role old_role,
                                        ax::mojom::Role new_role) {}

void AccessibilityBridge::OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) {
  BASE_DCHECK(node);
  id_wrapper_map_[node->id()] = CreateFlutterPlatformNodeDelegate();
  id_wrapper_map_[node->id()]->Init(
      std::static_pointer_cast<FlutterPlatformNodeDelegate::OwnerBridge>(
          shared_from_this()),
      node);
}

void AccessibilityBridge::OnNodeDeleted(ui::AXTree* tree,
                                        AccessibilityNodeId node_id) {
  BASE_DCHECK(node_id != ui::AXNode::kInvalidAXID);
  if (id_wrapper_map_.find(node_id) != id_wrapper_map_.end()) {
    id_wrapper_map_.erase(node_id);
  }
}

void AccessibilityBridge::OnAtomicUpdateFinished(
    ui::AXTree* tree,
    bool root_changed,
    const std::vector<ui::AXTreeObserver::Change>& changes) {
  // The Flutter semantics update does not include child->parent relationship
  // We have to update the relative bound offset container id here in order
  // to calculate the screen bound correctly.
  for (const auto& change : changes) {
    ui::AXNode* node = change.node;
    const ui::AXNodeData& data = node->data();
    AccessibilityNodeId offset_container_id = -1;
    if (node->parent()) {
      offset_container_id = node->parent()->id();
    }
    node->SetLocation(offset_container_id, data.relative_bounds.bounds,
                      data.relative_bounds.transform.get());
  }
}

std::optional<ui::AXTreeUpdate>
AccessibilityBridge::CreateRemoveReparentedNodesUpdate() {
  std::unordered_map<int32_t, ui::AXNodeData> updates;

  for (auto node_update : pending_semantics_node_updates_) {
    for (int32_t child_id : node_update.second.children_in_traversal_order) {
      // Skip nodes that don't exist or have a parent in the current tree.
      ui::AXNode* child = tree_->GetFromId(child_id);
      if (!child) {
        continue;
      }

      // Flutter's root node should never be reparented.
      assert(child->parent());

      // Skip nodes whose parents are unchanged.
      if (child->parent()->id() == node_update.second.id) {
        continue;
      }

      // This pending update moves the current child node.
      // That new child must have a corresponding pending update.
      assert(pending_semantics_node_updates_.find(child_id) !=
             pending_semantics_node_updates_.end());

      // Create an update to remove the child from its previous parent.
      int32_t parent_id = child->parent()->id();
      if (updates.find(parent_id) == updates.end()) {
        updates[parent_id] = tree_->GetFromId(parent_id)->data();
      }

      ui::AXNodeData* parent = &updates[parent_id];
      auto iter = std::find(parent->child_ids.begin(), parent->child_ids.end(),
                            child_id);

      assert(iter != parent->child_ids.end());
      parent->child_ids.erase(iter);
    }
  }

  if (updates.empty()) {
    return std::nullopt;
  }

  ui::AXTreeUpdate update{
      .tree_data = tree_->data(),
      .nodes = std::vector<ui::AXNodeData>(),
  };

  for (std::pair<int32_t, ui::AXNodeData> data : updates) {
    update.nodes.push_back(std::move(data.second));
  }

  return update;
}

// Private method.
void AccessibilityBridge::GetSubTreeList(const SemanticsNode& target,
                                         std::vector<SemanticsNode>& result) {
  result.push_back(target);
  for (int32_t child : target.children_in_traversal_order) {
    auto iter = pending_semantics_node_updates_.find(child);
    if (iter != pending_semantics_node_updates_.end()) {
      SemanticsNode node = iter->second;
      GetSubTreeList(node, result);
      pending_semantics_node_updates_.erase(iter);
    }
  }
}

void AccessibilityBridge::ConvertFlutterUpdate(const SemanticsNode& node,
                                               ui::AXTreeUpdate& tree_update) {
  ui::AXNodeData node_data;
  node_data.id = node.id;
  SetRoleFromFlutterUpdate(node_data, node);
  SetStateFromFlutterUpdate(node_data, node);
  SetActionsFromFlutterUpdate(node_data, node);
  SetBooleanAttributesFromFlutterUpdate(node_data, node);
  SetIntAttributesFromFlutterUpdate(node_data, node);
  SetIntListAttributesFromFlutterUpdate(node_data, node);
  SetStringListAttributesFromFlutterUpdate(node_data, node);
  SetNameFromFlutterUpdate(node_data, node);
  SetValueFromFlutterUpdate(node_data, node);
  SetTooltipFromFlutterUpdate(node_data, node);
  node_data.relative_bounds.bounds.SetRect(node.rect.left, node.rect.top,
                                           node.rect.right - node.rect.left,
                                           node.rect.bottom - node.rect.top);
  node_data.relative_bounds.transform = std::make_unique<gfx::Transform>(
      node.transform.scaleX, node.transform.skewX, node.transform.transX, 0,
      node.transform.skewY, node.transform.scaleY, node.transform.transY, 0,
      node.transform.pers0, node.transform.pers1, node.transform.pers2, 0, 0, 0,
      0, 0);
  for (auto child : node.children_in_traversal_order) {
    node_data.child_ids.push_back(child);
  }
  SetTreeData(node, tree_update);
  tree_update.nodes.push_back(node_data);
}

void AccessibilityBridge::SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
                                                   const SemanticsNode& node) {
  FlutterSemanticsFlag flags = node.flags;
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsButton) {
    node_data.role = ax::mojom::Role::kButton;
    return;
  }
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
      !(flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly)) {
    node_data.role = ax::mojom::Role::kTextField;
    return;
  }
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsHeader) {
    node_data.role = ax::mojom::Role::kHeader;
    return;
  }
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsImage) {
    node_data.role = ax::mojom::Role::kImage;
    return;
  }
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsLink) {
    node_data.role = ax::mojom::Role::kLink;
    return;
  }

  if (flags & kFlutterSemanticsFlagIsInMutuallyExclusiveGroup &&
      flags & kFlutterSemanticsFlagHasCheckedState) {
    node_data.role = ax::mojom::Role::kRadioButton;
    return;
  }
  if (flags & kFlutterSemanticsFlagHasCheckedState) {
    node_data.role = ax::mojom::Role::kCheckBox;
    return;
  }
  if (flags & kFlutterSemanticsFlagHasToggledState) {
    node_data.role = ax::mojom::Role::kToggleButton;
    return;
  }
  if (flags & kFlutterSemanticsFlagIsSlider) {
    node_data.role = ax::mojom::Role::kSlider;
    return;
  }
  // If the state cannot be derived from the flutter flags, we fallback to group
  // or static text.
  if (node.children_in_traversal_order.empty()) {
    node_data.role = ax::mojom::Role::kStaticText;
  } else {
    node_data.role = ax::mojom::Role::kGroup;
  }
}

void AccessibilityBridge::SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
                                                    const SemanticsNode& node) {
  FlutterSemanticsFlag flags = node.flags;
  FlutterSemanticsAction actions = node.actions;
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
      (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly) == 0) {
    node_data.AddState(ax::mojom::State::kEditable);
  }
  if (node_data.role == ax::mojom::Role::kStaticText &&
      (actions & kHasScrollingAction) == 0 && node.value.empty() &&
      node.label.empty() && node.hint.empty()) {
    node_data.AddState(ax::mojom::State::kIgnored);
  } else {
    // kFlutterSemanticsFlagIsFocusable means a keyboard focusable, it is
    // different from semantics focusable.
    // TODO(chunhtai): figure out whether something is not semantics focusable.
    node_data.AddState(ax::mojom::State::kFocusable);
  }
}

void AccessibilityBridge::SetActionsFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  FlutterSemanticsAction actions = node.actions;
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionTap) {
    node_data.AddAction(ax::mojom::Action::kDoDefault);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollLeft) {
    node_data.AddAction(ax::mojom::Action::kScrollLeft);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollRight) {
    node_data.AddAction(ax::mojom::Action::kScrollRight);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollUp) {
    node_data.AddAction(ax::mojom::Action::kScrollUp);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionScrollDown) {
    node_data.AddAction(ax::mojom::Action::kScrollDown);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionIncrease) {
    node_data.AddAction(ax::mojom::Action::kIncrement);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionDecrease) {
    node_data.AddAction(ax::mojom::Action::kDecrement);
  }
  // Every node has show on screen action.
  node_data.AddAction(ax::mojom::Action::kScrollToMakeVisible);

  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionSetSelection) {
    node_data.AddAction(ax::mojom::Action::kSetSelection);
  }
  if (actions & FlutterSemanticsAction::
                    kFlutterSemanticsActionDidGainAccessibilityFocus) {
    node_data.AddAction(ax::mojom::Action::kSetAccessibilityFocus);
  }
  if (actions & FlutterSemanticsAction::
                    kFlutterSemanticsActionDidLoseAccessibilityFocus) {
    node_data.AddAction(ax::mojom::Action::kClearAccessibilityFocus);
  }
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
    node_data.AddAction(ax::mojom::Action::kCustomAction);
  }
}

void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  FlutterSemanticsAction actions = node.actions;
  FlutterSemanticsFlag flags = node.flags;
  node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kScrollable,
                             actions & kHasScrollingAction);
  node_data.AddBoolAttribute(
      ax::mojom::BoolAttribute::kClickable,
      actions & FlutterSemanticsAction::kFlutterSemanticsActionTap);
  // TODO(chunhtai): figure out if there is a node that does not clip overflow.
  node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren,
                             !node.children_in_traversal_order.empty());
  node_data.AddBoolAttribute(
      ax::mojom::BoolAttribute::kSelected,
      flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsSelected);
  node_data.AddBoolAttribute(
      ax::mojom::BoolAttribute::kEditableRoot,
      flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
          (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly) == 0);
  // Mark nodes as line breaking so that screen readers don't
  // merge all consecutive objects into one.
  // TODO(schectman): When should a node have this attribute set?
  // https://github.com/flutter/flutter/issues/118184
  node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
                             true);
}

void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  FlutterSemanticsFlag flags = node.flags;
  node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
                            node.text_direction);

  int sel_start = node.text_selection_base;
  int sel_end = node.text_selection_extent;
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
      (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly) == 0 &&
      !node.value.empty()) {
    // By default the text field selection should be at the end.
    sel_start = sel_start == -1 ? node.value.length() : sel_start;
    sel_end = sel_end == -1 ? node.value.length() : sel_end;
  }
  node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart, sel_start);
  node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, sel_end);

  if (node_data.role == ax::mojom::Role::kRadioButton ||
      node_data.role == ax::mojom::Role::kCheckBox) {
    node_data.AddIntAttribute(
        ax::mojom::IntAttribute::kCheckedState,
        static_cast<int32_t>(
            flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed
                ? ax::mojom::CheckedState::kMixed
            : flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked
                ? ax::mojom::CheckedState::kTrue
                : ax::mojom::CheckedState::kFalse));
  } else if (node_data.role == ax::mojom::Role::kToggleButton) {
    node_data.AddIntAttribute(
        ax::mojom::IntAttribute::kCheckedState,
        static_cast<int32_t>(
            flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled
                ? ax::mojom::CheckedState::kTrue
                : ax::mojom::CheckedState::kFalse));
  }
}

void AccessibilityBridge::SetIntListAttributesFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  FlutterSemanticsAction actions = node.actions;
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
    std::vector<int32_t> custom_action_ids;
    for (size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
      custom_action_ids.push_back(node.custom_accessibility_actions[i]);
    }
    node_data.AddIntListAttribute(ax::mojom::IntListAttribute::kCustomActionIds,
                                  custom_action_ids);
  }
}

void AccessibilityBridge::SetStringListAttributesFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  FlutterSemanticsAction actions = node.actions;
  if (actions & FlutterSemanticsAction::kFlutterSemanticsActionCustomAction) {
    std::vector<std::string> custom_action_description;
    for (size_t i = 0; i < node.custom_accessibility_actions.size(); i++) {
      auto iter = pending_semantics_custom_action_updates_.find(
          node.custom_accessibility_actions[i]);
      BASE_DCHECK(iter != pending_semantics_custom_action_updates_.end());
      custom_action_description.push_back(iter->second.label);
    }
    node_data.AddStringListAttribute(
        ax::mojom::StringListAttribute::kCustomActionDescriptions,
        custom_action_description);
  }
}

void AccessibilityBridge::SetNameFromFlutterUpdate(ui::AXNodeData& node_data,
                                                   const SemanticsNode& node) {
  node_data.SetName(node.label);
}

void AccessibilityBridge::SetValueFromFlutterUpdate(ui::AXNodeData& node_data,
                                                    const SemanticsNode& node) {
  node_data.SetValue(node.value);
}

void AccessibilityBridge::SetTooltipFromFlutterUpdate(
    ui::AXNodeData& node_data,
    const SemanticsNode& node) {
  node_data.SetTooltip(node.tooltip);
}

void AccessibilityBridge::SetTreeData(const SemanticsNode& node,
                                      ui::AXTreeUpdate& tree_update) {
  FlutterSemanticsFlag flags = node.flags;
  // Set selection of the focused node if:
  // 1. this text field has a valid selection
  // 2. this text field doesn't have a valid selection but had selection stored
  //    in the tree.
  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
      flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocused) {
    if (node.text_selection_base != -1) {
      tree_update.tree_data.sel_anchor_object_id = node.id;
      tree_update.tree_data.sel_anchor_offset = node.text_selection_base;
      tree_update.tree_data.sel_focus_object_id = node.id;
      tree_update.tree_data.sel_focus_offset = node.text_selection_extent;
      tree_update.has_tree_data = true;
    } else if (tree_update.tree_data.sel_anchor_object_id == node.id) {
      tree_update.tree_data.sel_anchor_object_id = ui::AXNode::kInvalidAXID;
      tree_update.tree_data.sel_anchor_offset = -1;
      tree_update.tree_data.sel_focus_object_id = ui::AXNode::kInvalidAXID;
      tree_update.tree_data.sel_focus_offset = -1;
      tree_update.has_tree_data = true;
    }
  }

  if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocused &&
      tree_update.tree_data.focus_id != node.id) {
    tree_update.tree_data.focus_id = node.id;
    tree_update.has_tree_data = true;
  } else if ((flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocused) ==
                 0 &&
             tree_update.tree_data.focus_id == node.id) {
    tree_update.tree_data.focus_id = ui::AXNode::kInvalidAXID;
    tree_update.has_tree_data = true;
  }
}

AccessibilityBridge::SemanticsNode
AccessibilityBridge::FromFlutterSemanticsNode(
    const FlutterSemanticsNode2& flutter_node) {
  SemanticsNode result;
  result.id = flutter_node.id;
  result.flags = flutter_node.flags;
  result.actions = flutter_node.actions;
  result.text_selection_base = flutter_node.text_selection_base;
  result.text_selection_extent = flutter_node.text_selection_extent;
  result.scroll_child_count = flutter_node.scroll_child_count;
  result.scroll_index = flutter_node.scroll_index;
  result.scroll_position = flutter_node.scroll_position;
  result.scroll_extent_max = flutter_node.scroll_extent_max;
  result.scroll_extent_min = flutter_node.scroll_extent_min;
  result.elevation = flutter_node.elevation;
  result.thickness = flutter_node.thickness;
  if (flutter_node.label) {
    result.label = std::string(flutter_node.label);
  }
  if (flutter_node.hint) {
    result.hint = std::string(flutter_node.hint);
  }
  if (flutter_node.value) {
    result.value = std::string(flutter_node.value);
  }
  if (flutter_node.increased_value) {
    result.increased_value = std::string(flutter_node.increased_value);
  }
  if (flutter_node.decreased_value) {
    result.decreased_value = std::string(flutter_node.decreased_value);
  }
  if (flutter_node.tooltip) {
    result.tooltip = std::string(flutter_node.tooltip);
  }
  result.text_direction = flutter_node.text_direction;
  result.rect = flutter_node.rect;
  result.transform = flutter_node.transform;
  if (flutter_node.child_count > 0) {
    result.children_in_traversal_order = std::vector<int32_t>(
        flutter_node.children_in_traversal_order,
        flutter_node.children_in_traversal_order + flutter_node.child_count);
  }
  if (flutter_node.custom_accessibility_actions_count > 0) {
    result.custom_accessibility_actions = std::vector<int32_t>(
        flutter_node.custom_accessibility_actions,
        flutter_node.custom_accessibility_actions +
            flutter_node.custom_accessibility_actions_count);
  }
  return result;
}

AccessibilityBridge::SemanticsCustomAction
AccessibilityBridge::FromFlutterSemanticsCustomAction(
    const FlutterSemanticsCustomAction2& flutter_custom_action) {
  SemanticsCustomAction result;
  result.id = flutter_custom_action.id;
  result.override_action = flutter_custom_action.override_action;
  if (flutter_custom_action.label) {
    result.label = std::string(flutter_custom_action.label);
  }
  if (flutter_custom_action.hint) {
    result.hint = std::string(flutter_custom_action.hint);
  }
  return result;
}

void AccessibilityBridge::SetLastFocusedId(AccessibilityNodeId node_id) {
  if (last_focused_id_ != node_id) {
    auto last_focused_child =
        GetFlutterPlatformNodeDelegateFromID(last_focused_id_);
    if (!last_focused_child.expired()) {
      DispatchAccessibilityAction(
          last_focused_id_,
          FlutterSemanticsAction::
              kFlutterSemanticsActionDidLoseAccessibilityFocus,
          {});
    }
    last_focused_id_ = node_id;
  }
}

AccessibilityNodeId AccessibilityBridge::GetLastFocusedId() {
  return last_focused_id_;
}

gfx::NativeViewAccessible AccessibilityBridge::GetNativeAccessibleFromId(
    AccessibilityNodeId id) {
  auto platform_node_delegate = GetFlutterPlatformNodeDelegateFromID(id).lock();
  if (!platform_node_delegate) {
    return nullptr;
  }
  return platform_node_delegate->GetNativeViewAccessible();
}

gfx::RectF AccessibilityBridge::RelativeToGlobalBounds(const ui::AXNode* node,
                                                       bool& offscreen,
                                                       bool clip_bounds) {
  return tree_->RelativeToTreeBounds(node, gfx::RectF(), &offscreen,
                                     clip_bounds);
}

ui::AXNode* AccessibilityBridge::GetNodeFromTree(
    ui::AXTreeID tree_id,
    ui::AXNode::AXID node_id) const {
  return GetNodeFromTree(node_id);
}

ui::AXNode* AccessibilityBridge::GetNodeFromTree(
    ui::AXNode::AXID node_id) const {
  return tree_->GetFromId(node_id);
}

ui::AXTreeID AccessibilityBridge::GetTreeID() const {
  return tree_->GetAXTreeID();
}

ui::AXTreeID AccessibilityBridge::GetParentTreeID() const {
  return ui::AXTreeIDUnknown();
}

ui::AXNode* AccessibilityBridge::GetRootAsAXNode() const {
  return tree_->root();
}

ui::AXNode* AccessibilityBridge::GetParentNodeFromParentTreeAsAXNode() const {
  return nullptr;
}

ui::AXTree* AccessibilityBridge::GetTree() const {
  return tree_.get();
}

ui::AXPlatformNode* AccessibilityBridge::GetPlatformNodeFromTree(
    const ui::AXNode::AXID node_id) const {
  auto platform_delegate_weak = GetFlutterPlatformNodeDelegateFromID(node_id);
  auto platform_delegate = platform_delegate_weak.lock();
  if (!platform_delegate) {
    return nullptr;
  }
  return platform_delegate->GetPlatformNode();
}

ui::AXPlatformNode* AccessibilityBridge::GetPlatformNodeFromTree(
    const ui::AXNode& node) const {
  return GetPlatformNodeFromTree(node.id());
}

ui::AXPlatformNodeDelegate* AccessibilityBridge::RootDelegate() const {
  return GetFlutterPlatformNodeDelegateFromID(GetRootAsAXNode()->id())
      .lock()
      .get();
}

}  // namespace flutter
