blob: 1670d7c7341e6b5fd3d7cee4b33ef286bd13b7db [file] [log] [blame]
// 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 "flutter/shell/platform/embedder/embedder_semantics_update.h"
namespace flutter {
EmbedderSemanticsUpdate::EmbedderSemanticsUpdate(
const SemanticsNodeUpdates& nodes,
const CustomAccessibilityActionUpdates& actions) {
for (const auto& value : nodes) {
AddNode(value.second);
}
for (const auto& value : actions) {
AddAction(value.second);
}
update_ = {
.struct_size = sizeof(FlutterSemanticsUpdate),
.nodes_count = nodes_.size(),
.nodes = nodes_.data(),
.custom_actions_count = actions_.size(),
.custom_actions = actions_.data(),
};
}
void EmbedderSemanticsUpdate::AddNode(const SemanticsNode& node) {
SkMatrix transform = node.transform.asM33();
FlutterTransformation flutter_transform{
transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX),
transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY),
transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY),
transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1),
transform.get(SkMatrix::kMPersp2)};
// Do not add new members to FlutterSemanticsNode.
// This would break the forward compatibility of FlutterSemanticsUpdate.
// All new members must be added to FlutterSemanticsNode2 instead.
nodes_.push_back({
sizeof(FlutterSemanticsNode),
node.id,
static_cast<FlutterSemanticsFlag>(node.flags),
static_cast<FlutterSemanticsAction>(node.actions),
node.textSelectionBase,
node.textSelectionExtent,
node.scrollChildren,
node.scrollIndex,
node.scrollPosition,
node.scrollExtentMax,
node.scrollExtentMin,
node.elevation,
node.thickness,
node.label.c_str(),
node.hint.c_str(),
node.value.c_str(),
node.increasedValue.c_str(),
node.decreasedValue.c_str(),
static_cast<FlutterTextDirection>(node.textDirection),
FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
node.rect.fBottom},
flutter_transform,
node.childrenInTraversalOrder.size(),
node.childrenInTraversalOrder.data(),
node.childrenInHitTestOrder.data(),
node.customAccessibilityActions.size(),
node.customAccessibilityActions.data(),
node.platformViewId,
node.tooltip.c_str(),
});
}
void EmbedderSemanticsUpdate::AddAction(
const CustomAccessibilityAction& action) {
// Do not add new members to FlutterSemanticsCustomAction.
// This would break the forward compatibility of FlutterSemanticsUpdate.
// All new members must be added to FlutterSemanticsCustomAction2 instead.
actions_.push_back({
sizeof(FlutterSemanticsCustomAction),
action.id,
static_cast<FlutterSemanticsAction>(action.overrideId),
action.label.c_str(),
action.hint.c_str(),
});
}
EmbedderSemanticsUpdate::~EmbedderSemanticsUpdate() {}
EmbedderSemanticsUpdate2::EmbedderSemanticsUpdate2(
const SemanticsNodeUpdates& nodes,
const CustomAccessibilityActionUpdates& actions) {
nodes_.reserve(nodes.size());
node_pointers_.reserve(nodes.size());
actions_.reserve(actions.size());
action_pointers_.reserve(actions.size());
for (const auto& value : nodes) {
AddNode(value.second);
}
for (const auto& value : actions) {
AddAction(value.second);
}
for (size_t i = 0; i < nodes_.size(); i++) {
node_pointers_.push_back(&nodes_[i]);
}
for (size_t i = 0; i < actions_.size(); i++) {
action_pointers_.push_back(&actions_[i]);
}
update_ = {
.struct_size = sizeof(FlutterSemanticsUpdate2),
.node_count = node_pointers_.size(),
.nodes = node_pointers_.data(),
.custom_action_count = action_pointers_.size(),
.custom_actions = action_pointers_.data(),
};
}
EmbedderSemanticsUpdate2::~EmbedderSemanticsUpdate2() {}
void EmbedderSemanticsUpdate2::AddNode(const SemanticsNode& node) {
SkMatrix transform = node.transform.asM33();
FlutterTransformation flutter_transform{
transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX),
transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY),
transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY),
transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1),
transform.get(SkMatrix::kMPersp2)};
auto label_attributes = CreateStringAttributes(node.labelAttributes);
auto hint_attributes = CreateStringAttributes(node.hintAttributes);
auto value_attributes = CreateStringAttributes(node.valueAttributes);
auto increased_value_attributes =
CreateStringAttributes(node.increasedValueAttributes);
auto decreased_value_attributes =
CreateStringAttributes(node.decreasedValueAttributes);
nodes_.push_back({
sizeof(FlutterSemanticsNode2),
node.id,
static_cast<FlutterSemanticsFlag>(node.flags),
static_cast<FlutterSemanticsAction>(node.actions),
node.textSelectionBase,
node.textSelectionExtent,
node.scrollChildren,
node.scrollIndex,
node.scrollPosition,
node.scrollExtentMax,
node.scrollExtentMin,
node.elevation,
node.thickness,
node.label.c_str(),
node.hint.c_str(),
node.value.c_str(),
node.increasedValue.c_str(),
node.decreasedValue.c_str(),
static_cast<FlutterTextDirection>(node.textDirection),
FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
node.rect.fBottom},
flutter_transform,
node.childrenInTraversalOrder.size(),
node.childrenInTraversalOrder.data(),
node.childrenInHitTestOrder.data(),
node.customAccessibilityActions.size(),
node.customAccessibilityActions.data(),
node.platformViewId,
node.tooltip.c_str(),
label_attributes.count,
label_attributes.attributes,
hint_attributes.count,
hint_attributes.attributes,
value_attributes.count,
value_attributes.attributes,
increased_value_attributes.count,
increased_value_attributes.attributes,
decreased_value_attributes.count,
decreased_value_attributes.attributes,
});
}
void EmbedderSemanticsUpdate2::AddAction(
const CustomAccessibilityAction& action) {
actions_.push_back({
sizeof(FlutterSemanticsCustomAction2),
action.id,
static_cast<FlutterSemanticsAction>(action.overrideId),
action.label.c_str(),
action.hint.c_str(),
});
}
EmbedderSemanticsUpdate2::EmbedderStringAttributes
EmbedderSemanticsUpdate2::CreateStringAttributes(
const StringAttributes& attributes) {
// Minimize allocations if attributes are empty.
if (attributes.empty()) {
return {.count = 0, .attributes = nullptr};
}
// Translate the engine attributes to embedder attributes.
// The result vector's data is returned by this method.
// The result vector will be owned by |node_string_attributes_|
// so that the embedder attributes are cleaned up at the end of the
// semantics update callback when when the |EmbedderSemanticsUpdate2|
// is destroyed.
auto result = std::make_unique<std::vector<const FlutterStringAttribute*>>();
result->reserve(attributes.size());
for (const auto& attribute : attributes) {
auto embedder_attribute = std::make_unique<FlutterStringAttribute>();
embedder_attribute->struct_size = sizeof(FlutterStringAttribute);
embedder_attribute->start = attribute->start;
embedder_attribute->end = attribute->end;
switch (attribute->type) {
case StringAttributeType::kLocale: {
std::shared_ptr<flutter::LocaleStringAttribute> locale_attribute =
std::static_pointer_cast<flutter::LocaleStringAttribute>(attribute);
auto embedder_locale = std::make_unique<FlutterLocaleStringAttribute>();
embedder_locale->struct_size = sizeof(FlutterLocaleStringAttribute);
embedder_locale->locale = locale_attribute->locale.c_str();
locale_attributes_.push_back(std::move(embedder_locale));
embedder_attribute->type = FlutterStringAttributeType::kLocale;
embedder_attribute->locale = locale_attributes_.back().get();
break;
}
case flutter::StringAttributeType::kSpellOut: {
// All spell out attributes are identical and share a lazily created
// instance.
if (!spell_out_attribute_) {
auto spell_out_attribute_ =
std::make_unique<FlutterSpellOutStringAttribute>();
spell_out_attribute_->struct_size =
sizeof(FlutterSpellOutStringAttribute);
}
embedder_attribute->type = FlutterStringAttributeType::kSpellOut;
embedder_attribute->spell_out = spell_out_attribute_.get();
break;
}
}
string_attributes_.push_back(std::move(embedder_attribute));
result->push_back(string_attributes_.back().get());
}
node_string_attributes_.push_back(std::move(result));
return {
.count = node_string_attributes_.back()->size(),
.attributes = node_string_attributes_.back()->data(),
};
}
} // namespace flutter