Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ deps = {
'src/third_party/libcxx': 'https://llvm.googlesource.com/llvm-project/libcxx@bd557f6f764d1e40b62528a13b124ce740624f8f',
'src/third_party/libcxxabi': 'https://llvm.googlesource.com/llvm-project/libcxxabi@a4dda1589d37a7e4b4f7a81ebad01b1083f2e726',
'src/third_party/googletest': 'https://github.com/google/googletest@7f036c5563af7d0329f20e8bb42effb04629f0c0',
'src/third_party/dart': 'https://dart.googlesource.com/sdk.git@b04011c77cd93e6ab9144af37976733b558d716c',
'src/third_party/dart': 'https://dart.googlesource.com/sdk.git@a29e08c72e2ce21813c1edf50cbcdfcac7a7acdd',
'src/third_party/clang': {
'packages': [
{
Expand Down
11 changes: 10 additions & 1 deletion flutter/shell/platform/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ source_set("common_cpp_library_headers") {

copy("publish_headers") {
sources = _public_headers
outputs = [ "$root_out_dir/public/{{source_file_part}}" ]
outputs = [ "$root_out_dir/{{source_file_part}}" ]
}

source_set("common_cpp_input") {
Expand All @@ -54,6 +54,13 @@ source_set("common_cpp_input") {
deps = [ "//flutter/fml:fml" ]
}

source_set("common_cpp_isolate_scope") {
public = [ "isolate_scope.h" ]
sources = [ "isolate_scope.cc" ]

deps = [ "//flutter/fml:fml" ]
}

source_set("common_cpp_enums") {
public = [
"app_lifecycle_state.h",
Expand Down Expand Up @@ -116,6 +123,7 @@ source_set("common_cpp") {
deps = [
":common_cpp_library_headers",
"//flutter/shell/platform/common/client_wrapper:client_wrapper",
"//flutter/shell/platform/embedder:embedder_headers",
]

public_deps = [
Expand All @@ -132,6 +140,7 @@ source_set("common_cpp_core") {
public = [
"geometry.h",
"path_utils.h",
"windowing.h",
]

sources = [ "path_utils.cc" ]
Expand Down
78 changes: 35 additions & 43 deletions flutter/shell/platform/common/accessibility_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -311,43 +311,43 @@ void AccessibilityBridge::ConvertFlutterUpdate(const SemanticsNode& node,

void AccessibilityBridge::SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
const SemanticsNode& node) {
FlutterSemanticsFlag flags = node.flags;
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsButton) {
const FlutterSemanticsFlags* flags = node.flags;
FML_DCHECK(flags) << "SemanticsNode::flags must not be null";
if (flags->is_button) {
node_data.role = ax::mojom::Role::kButton;
return;
}
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
!(flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly)) {
if (flags->is_text_field && !flags->is_read_only) {
node_data.role = ax::mojom::Role::kTextField;
return;
}
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsHeader) {
if (flags->is_header) {
node_data.role = ax::mojom::Role::kHeader;
return;
}
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsImage) {
if (flags->is_image) {
node_data.role = ax::mojom::Role::kImage;
return;
}
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsLink) {
if (flags->is_link) {
node_data.role = ax::mojom::Role::kLink;
return;
}

if (flags & kFlutterSemanticsFlagIsInMutuallyExclusiveGroup &&
flags & kFlutterSemanticsFlagHasCheckedState) {
if (flags->is_in_mutually_exclusive_group &&
flags->is_checked != FlutterCheckState::kFlutterCheckStateNone) {
node_data.role = ax::mojom::Role::kRadioButton;
return;
}
if (flags & kFlutterSemanticsFlagHasCheckedState) {
if (flags->is_checked != FlutterCheckState::kFlutterCheckStateNone) {
node_data.role = ax::mojom::Role::kCheckBox;
return;
}
if (flags & kFlutterSemanticsFlagHasToggledState) {
if (flags->is_toggled != FlutterTristate::kFlutterTristateNone) {
node_data.role = ax::mojom::Role::kSwitch;
return;
}
if (flags & kFlutterSemanticsFlagIsSlider) {
if (flags->is_slider) {
node_data.role = ax::mojom::Role::kSlider;
return;
}
Expand All @@ -362,17 +362,14 @@ void AccessibilityBridge::SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,

void AccessibilityBridge::SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
const SemanticsNode& node) {
FlutterSemanticsFlag flags = node.flags;
const FlutterSemanticsFlags* flags = node.flags;
FlutterSemanticsAction actions = node.actions;
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState &&
flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsExpanded) {
if (flags->is_expanded == FlutterTristate::kFlutterTristateTrue) {
node_data.AddState(ax::mojom::State::kExpanded);
} else if (flags &
FlutterSemanticsFlag::kFlutterSemanticsFlagHasExpandedState) {
} else if (flags->is_expanded == FlutterTristate::kFlutterTristateFalse) {
node_data.AddState(ax::mojom::State::kCollapsed);
}
if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField &&
(flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly) == 0) {
if (flags->is_text_field && !flags->is_read_only) {
node_data.AddState(ax::mojom::State::kEditable);
}
if (node_data.role == ax::mojom::Role::kStaticText &&
Expand Down Expand Up @@ -435,7 +432,7 @@ void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
ui::AXNodeData& node_data,
const SemanticsNode& node) {
FlutterSemanticsAction actions = node.actions;
FlutterSemanticsFlag flags = node.flags;
const FlutterSemanticsFlags* flags = node.flags;
node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kScrollable,
actions & kHasScrollingAction);
node_data.AddBoolAttribute(
Expand All @@ -444,13 +441,10 @@ void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
// 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);
node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
flags->is_selected);
node_data.AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot,
flags->is_text_field && !flags->is_read_only);
// 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?
Expand All @@ -462,15 +456,13 @@ void AccessibilityBridge::SetBooleanAttributesFromFlutterUpdate(
void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
ui::AXNodeData& node_data,
const SemanticsNode& node) {
FlutterSemanticsFlag flags = node.flags;
const FlutterSemanticsFlags* 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()) {
if (flags->is_text_field && !flags->is_read_only && !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;
Expand All @@ -483,16 +475,16 @@ void AccessibilityBridge::SetIntAttributesFromFlutterUpdate(
node_data.AddIntAttribute(
ax::mojom::IntAttribute::kCheckedState,
static_cast<int32_t>(
flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsCheckStateMixed
(flags->is_checked == FlutterCheckState::kFlutterCheckStateMixed)
? ax::mojom::CheckedState::kMixed
: flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked
: (flags->is_checked == FlutterCheckState::kFlutterCheckStateTrue)
? ax::mojom::CheckedState::kTrue
: ax::mojom::CheckedState::kFalse));
} else if (node_data.role == ax::mojom::Role::kSwitch) {
node_data.AddIntAttribute(
ax::mojom::IntAttribute::kCheckedState,
static_cast<int32_t>(
flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsToggled
(flags->is_toggled == FlutterTristate::kFlutterTristateTrue)
? ax::mojom::CheckedState::kTrue
: ax::mojom::CheckedState::kFalse));
}
Expand Down Expand Up @@ -548,13 +540,13 @@ void AccessibilityBridge::SetTooltipFromFlutterUpdate(

void AccessibilityBridge::SetTreeData(const SemanticsNode& node,
ui::AXTreeUpdate& tree_update) {
FlutterSemanticsFlag flags = node.flags;
const FlutterSemanticsFlags* 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 (flags->is_text_field &&
flags->is_focused == FlutterTristate::kFlutterTristateTrue) {
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;
Expand All @@ -570,12 +562,11 @@ void AccessibilityBridge::SetTreeData(const SemanticsNode& node,
}
}

if (flags & FlutterSemanticsFlag::kFlutterSemanticsFlagIsFocused &&
if (flags->is_focused == FlutterTristate::kFlutterTristateTrue &&
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 &&
} else if (flags->is_focused != FlutterTristate::kFlutterTristateTrue &&
tree_update.tree_data.focus_id == node.id) {
tree_update.tree_data.focus_id = ui::AXNode::kInvalidAXID;
tree_update.has_tree_data = true;
Expand All @@ -587,7 +578,10 @@ AccessibilityBridge::FromFlutterSemanticsNode(
const FlutterSemanticsNode2& flutter_node) {
SemanticsNode result;
result.id = flutter_node.id;
result.flags = flutter_node.flags;
FML_DCHECK(flutter_node.flags2)
<< "FlutterSemanticsNode2::flags2 must not be null";

result.flags = flutter_node.flags2;
result.actions = flutter_node.actions;
result.text_selection_base = flutter_node.text_selection_base;
result.text_selection_extent = flutter_node.text_selection_extent;
Expand All @@ -596,8 +590,6 @@ AccessibilityBridge::FromFlutterSemanticsNode(
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);
}
Expand Down
4 changes: 1 addition & 3 deletions flutter/shell/platform/common/accessibility_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class AccessibilityBridge
// See FlutterSemanticsNode in embedder.h
typedef struct {
int32_t id;
FlutterSemanticsFlag flags;
FlutterSemanticsFlags* flags;
FlutterSemanticsAction actions;
int32_t text_selection_base;
int32_t text_selection_extent;
Expand All @@ -170,8 +170,6 @@ class AccessibilityBridge
double scroll_position;
double scroll_extent_max;
double scroll_extent_min;
double elevation;
double thickness;
std::string label;
std::string hint;
std::string value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,57 @@ class EncodableValue : public internal::EncodableValueVariant {
return std::get<int64_t>(*this);
}

// Explicitly provide operator<, delegating to std::variant's operator<.
// There are issues with with the way the standard library-provided
// < and <=> comparisons interact with classes derived from variant.
// The C++ Standard Library implementations can get into issues with recursive
// constraint satisfaction when (among other things) objects of this type (which
// is an `std::variant` subclass) are put into containers like `std::vector`.
//
// A definition of `operator<` is provided to break that recursion. However, in
// C++20 with the latest compilers (Clang compilers newer than 20 and the latest
// GCC variants, see https://gcc.godbolt.org/z/KM6n6qane) requiring that that
// the `std::three_way_comparable` constraint be satisfied requires the
// provision of `operator<=>` to do the same thing.
//
// The code below makes this translation unit be safe to include from both C++17
// and C++20 translation units while also using the newest compilers.
//
// The correctness of the compiler's gripes with this code and the subsequent
// need for these workarounds is not fully understood or explored. If you run
// into issues with this code again, the following breadcrumbs may prove
// useful. If you cannot access some or all of these links, the compiler
// explorer link above should serve a reduced test case to base an investigation
// off of.
//
// * b/423885648#comment8
// * b/423885648#comment19
// * cl/542631351
// * cl/542541552
// * https://github.com/flutter/engine/pull/43091
//
#if __cplusplus >= 202002L
friend std::partial_ordering operator<=>(const EncodableValue& lhs,
const EncodableValue& rhs) {
auto& lv = static_cast<const super&>(lhs);
auto& rv = static_cast<const super&>(rhs);

if (lv < rv) {
return std::partial_ordering::less;
}

if (rv < lv) {
return std::partial_ordering::greater;
}

if (lv == rv) {
return std::partial_ordering::equivalent;
}

return std::partial_ordering::unordered;
}
#else // __cplusplus >= 202002L
friend bool operator<(const EncodableValue& lhs, const EncodableValue& rhs) {
return static_cast<const super&>(lhs) < static_cast<const super&>(rhs);
}
#endif // __cplusplus >= 202002L
};

} // namespace flutter
Expand Down
24 changes: 24 additions & 0 deletions flutter/shell/platform/common/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define FLUTTER_SHELL_PLATFORM_COMMON_GEOMETRY_H_

#include <cmath>
#include <limits>
#include <optional>

namespace flutter {

Expand Down Expand Up @@ -45,6 +47,7 @@ class Size {
bool operator==(const Size& other) const {
return width_ == other.width_ && height_ == other.height_;
}
bool operator!=(const Size& other) const { return !(*this == other); }

private:
double width_ = 0.0;
Expand Down Expand Up @@ -78,6 +81,27 @@ class Rect {
Size size_;
};

// Encapsulates a min and max size that represents the constraints that some
// arbitrary box is able to take up.
class BoxConstraints {
public:
BoxConstraints() = default;
BoxConstraints(const std::optional<Size>& smallest,
const std::optional<Size>& biggest)
: smallest_(smallest.value_or(Size(0, 0))),
biggest_(
biggest.value_or(Size(std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::infinity()))) {}
BoxConstraints(const BoxConstraints& other) = default;
Size biggest() const { return biggest_; }
Size smallest() const { return smallest_; }

private:
Size smallest_ = Size(0, 0);
Size biggest_ = Size(std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::infinity());
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_COMMON_GEOMETRY_H_
Loading