Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
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
1 change: 1 addition & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@
../../../flutter/runtime/fixtures
../../../flutter/runtime/no_dart_plugin_registrant_unittests.cc
../../../flutter/runtime/platform_isolate_manager_unittests.cc
../../../flutter/runtime/runtime_controller_unittests.cc
../../../flutter/runtime/type_conversions_unittests.cc
../../../flutter/shell/common/animator_unittests.cc
../../../flutter/shell/common/base64_unittests.cc
Expand Down
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -44693,6 +44693,7 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios.
ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios_test.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/ios/platform_view_ios_test.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -47646,6 +47647,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios_test.mm
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.h
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios_test.mm
FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h
FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h
Expand Down
1 change: 1 addition & 0 deletions lib/ui/dart_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ typedef CanvasPath Path;
V(PlatformConfigurationNativeApi::UpdateSemantics) \
V(PlatformConfigurationNativeApi::SetNeedsReportTimings) \
V(PlatformConfigurationNativeApi::SetIsolateDebugName) \
V(PlatformConfigurationNativeApi::SetSemanticsTreeEnabled) \
V(PlatformConfigurationNativeApi::RequestDartPerformanceMode) \
V(PlatformConfigurationNativeApi::GetPersistentIsolateData) \
V(PlatformConfigurationNativeApi::ComputePlatformResolvedLocale) \
Expand Down
25 changes: 22 additions & 3 deletions lib/ui/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,8 @@ class FlutterView {

/// Change the retained semantics data about this [FlutterView].
///
/// If [PlatformDispatcher.semanticsEnabled] is true, the user has requested that this function
/// be called whenever the semantic content of this [FlutterView]
/// changes.
/// Th [setSemanticsTreeEnabled] must be called with true before sending
/// update through this method.
///
/// This function disposes the given update, which means the semantics update
/// cannot be used further.
Expand All @@ -393,6 +392,26 @@ class FlutterView {
@Native<Void Function(Pointer<Void>)>(symbol: 'PlatformConfigurationNativeApi::UpdateSemantics')
external static void _updateSemantics(_NativeSemanticsUpdate update);

/// Informs the engine whether the framework is generating a semantics tree.
///
/// Only framework knows when semantics tree should be generated. It uses this
/// method to notify the engine such event.
///
/// In the case where platforms want to enable semantics, e.g. when detected running
/// assitive technologies, it notifies framework through the
/// [PlatformDispatcher.onSemanticsEnabledChanged].
///
/// After this has been set to true, platforms are expected to prepare for accepting
/// semantics update sent via [updateSemantics]. When this is set to false, platforms
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, it is possible that either the platform OR the framework turns on semantics. Who is in charge of keeping track of this? If the platform turned on semantics and then the framework turns off semantics by calling this method - do we just leave the platform hanging and not provide it with a semantics tree anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

framework is keep track of this since it is the one who knows how many semantics handles are generated.

platform can send signal through SetSemanticsEnabled to framework, but it shouldnt initialize resource for accessibility until framework sends setSemanticsTreeEnabled back.

when framework turn off semantics(can happen when last handle is disposed), it will send setSemanticsTreeEnabled(false), platform will then know it can dispose its accessibility resource

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we document that contract here? And on where the signal from the platform is send to the framework?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it tricky to write document in this class, this api is facing framework so i find it weird to document framework behavior in this doc, so I mainly document what this function does and when the consume should call this function. let me try to see what I can come up with

/// may dispose any resources associated with processing semantics as no further
/// semantics updates will be sent via [updateSemantics].
///
/// One must call this method with true before sending update through [updateSemantics].
void setSemanticsTreeEnabled(bool enabled) => _setSemanticsTreeEnabled(enabled);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the framework only allowed to call updateSemantics after setting this to true? We should document that here and on updateSemantics.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should we just call this setSemanticsEnabled? I don't think we officially call this a tree anywhere else in the API.

Copy link
Contributor Author

@chunhtai chunhtai Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setSemanticsEnabled is used exclusively by platform to let framework know it "wants" semantics to turn on. SetSemanticsTreeEnabled is framework signal to tell platform that "yes i will start compiling semantics"

don't think we officially call this a tree anywhere else in the API.

Do you have other name suggestion? how about setSemanticsCompilingEnabled ?


@Native<Void Function(Bool)>(symbol: 'PlatformConfigurationNativeApi::SetSemanticsTreeEnabled')
external static void _setSemanticsTreeEnabled(bool update);

@override
String toString() => 'FlutterView(id: $viewId)';
}
Expand Down
8 changes: 8 additions & 0 deletions lib/ui/window/platform_configuration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,14 @@ void PlatformConfigurationNativeApi::UpdateSemantics(SemanticsUpdate* update) {
update);
}

void PlatformConfigurationNativeApi::SetSemanticsTreeEnabled(bool enabled) {
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()
->platform_configuration()
->client()
->SetSemanticsTreeEnabled(enabled);
}

Dart_Handle PlatformConfigurationNativeApi::ComputePlatformResolvedLocale(
Dart_Handle supportedLocalesHandle) {
UIDartState::ThrowIfUIOperationsProhibited();
Expand Down
9 changes: 9 additions & 0 deletions lib/ui/window/platform_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ class PlatformConfigurationClient {
///
virtual void UpdateSemantics(SemanticsUpdate* update) = 0;

//--------------------------------------------------------------------------
/// @brief Notifies whether Framework starts generating semantics tree.
///
/// @param[in] enabled True if Framework starts generating semantics tree.
///
virtual void SetSemanticsTreeEnabled(bool enabled) = 0;

//--------------------------------------------------------------------------
/// @brief When the Flutter application has a message to send to the
/// underlying platform, the message needs to be forwarded to
Expand Down Expand Up @@ -594,6 +601,8 @@ class PlatformConfigurationNativeApi {

static void UpdateSemantics(SemanticsUpdate* update);

static void SetSemanticsTreeEnabled(bool enabled);

static void SetNeedsReportTimings(bool value);

static Dart_Handle GetPersistentIsolateData();
Expand Down
8 changes: 8 additions & 0 deletions lib/web_ui/lib/src/engine/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ class EngineFlutterView implements ui.FlutterView {
semantics.updateSemantics(update);
}

@override
void setSemanticsTreeEnabled(bool enabled) {
assert(!isDisposed, 'Trying to update semantics on a disposed EngineFlutterView.');
if (!enabled) {
semantics.reset();
}
}

late final GlobalHtmlAttributes _globalHtmlAttributes = GlobalHtmlAttributes(
rootElement: dom.rootElement,
hostElement: embeddingStrategy.hostElement,
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ abstract class FlutterView {
Display get display;
void render(Scene scene, {Size? size});
void updateSemantics(SemanticsUpdate update) => platformDispatcher.updateSemantics(update);
void setSemanticsTreeEnabled(bool enabled) {}
}

abstract class SingletonFlutterWindow extends FlutterView {
Expand Down
4 changes: 4 additions & 0 deletions lib/web_ui/test/engine/scene_view_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ class StubFlutterView implements EngineFlutterView {
void updateSemantics(ui.SemanticsUpdate update) {
}

@override
void setSemanticsTreeEnabled(bool enabled) {
}

@override
int get viewId => throw UnimplementedError();

Expand Down
2 changes: 2 additions & 0 deletions runtime/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ if (enable_unittests) {
"dart_service_isolate_unittests.cc",
"dart_vm_unittests.cc",
"platform_isolate_manager_unittests.cc",
"runtime_controller_unittests.cc",
"type_conversions_unittests.cc",
]

Expand All @@ -153,6 +154,7 @@ if (enable_unittests) {
"//flutter/common",
"//flutter/fml",
"//flutter/lib/snapshot",
"//flutter/shell/common:shell_test_fixture_sources",
"//flutter/skia",
"//flutter/testing",
"//flutter/testing:dart",
Expand Down
1 change: 1 addition & 0 deletions runtime/dart_isolate_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ class FakePlatformConfigurationClient : public PlatformConfigurationClient {
double width,
double height) override {}
void UpdateSemantics(SemanticsUpdate* update) override {}
void SetSemanticsTreeEnabled(bool enabled) override {}
void HandlePlatformMessage(
std::unique_ptr<PlatformMessage> message) override {}
FontCollection& GetFontCollection() override {
Expand Down
99 changes: 99 additions & 0 deletions runtime/fixtures/runtime_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui';

import 'split_lib_test.dart' deferred as splitlib;

Expand Down Expand Up @@ -219,3 +221,100 @@ Function createEntryPointForPlatIsoSendAndRecvTest() {
void mainForPlatformIsolatesThrowError() {
throw AssertionError('Error from platform isolate');
}

@pragma('vm:entry-point')
void sendSemanticsUpdate() {
final SemanticsUpdateBuilder builder = SemanticsUpdateBuilder();
const String identifier = 'identifier';
const String label = 'label';
final List<StringAttribute> labelAttributes = <StringAttribute> [
SpellOutStringAttribute(range: const TextRange(start: 1, end: 2)),
];

const String value = 'value';
final List<StringAttribute> valueAttributes = <StringAttribute> [
SpellOutStringAttribute(range: const TextRange(start: 2, end: 3)),
];

const String increasedValue = 'increasedValue';
final List<StringAttribute> increasedValueAttributes = <StringAttribute> [
SpellOutStringAttribute(range: const TextRange(start: 4, end: 5)),
];

const String decreasedValue = 'decreasedValue';
final List<StringAttribute> decreasedValueAttributes = <StringAttribute> [
SpellOutStringAttribute(range: const TextRange(start: 5, end: 6)),
];

const String hint = 'hint';
final List<StringAttribute> hintAttributes = <StringAttribute> [
LocaleStringAttribute(
locale: const Locale('en', 'MX'), range: const TextRange(start: 0, end: 1),
),
];

const String tooltip = 'tooltip';

final Float64List transform = Float64List(16);
final Int32List childrenInTraversalOrder = Int32List(0);
final Int32List childrenInHitTestOrder = Int32List(0);
final Int32List additionalActions = Int32List(0);
transform[0] = 1;
transform[1] = 0;
transform[2] = 0;
transform[3] = 0;

transform[4] = 0;
transform[5] = 1;
transform[6] = 0;
transform[7] = 0;

transform[8] = 0;
transform[9] = 0;
transform[10] = 1;
transform[11] = 0;

transform[12] = 0;
transform[13] = 0;
transform[14] = 0;
transform[15] = 0;
builder.updateNode(
id: 0,
flags: 0,
actions: 0,
maxValueLength: 0,
currentValueLength: 0,
textSelectionBase: -1,
textSelectionExtent: -1,
platformViewId: -1,
scrollChildren: 0,
scrollIndex: 0,
scrollPosition: 0,
scrollExtentMax: 0,
scrollExtentMin: 0,
rect: const Rect.fromLTRB(0, 0, 10, 10),
elevation: 0,
thickness: 0,
identifier: identifier,
label: label,
labelAttributes: labelAttributes,
value: value,
valueAttributes: valueAttributes,
increasedValue: increasedValue,
increasedValueAttributes: increasedValueAttributes,
decreasedValue: decreasedValue,
decreasedValueAttributes: decreasedValueAttributes,
hint: hint,
hintAttributes: hintAttributes,
tooltip: tooltip,
textDirection: TextDirection.ltr,
transform: transform,
childrenInTraversalOrder: childrenInTraversalOrder,
childrenInHitTestOrder: childrenInHitTestOrder,
additionalActions: additionalActions,
);
_semanticsUpdate(builder.build());
}

@pragma('vm:external-name', 'SemanticsUpdate')
external void _semanticsUpdate(SemanticsUpdate update);
8 changes: 7 additions & 1 deletion runtime/runtime_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -440,11 +440,17 @@ void RuntimeController::CheckIfAllViewsRendered() {

// |PlatformConfigurationClient|
void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
if (platform_data_.semantics_enabled) {
if (semantics_tree_enabled_) {
client_.UpdateSemantics(update->takeNodes(), update->takeActions());
}
}

// |PlatformConfigurationClient|
void RuntimeController::SetSemanticsTreeEnabled(bool enabled) {
semantics_tree_enabled_ = enabled;
client_.SetSemanticsTreeEnabled(enabled);
}

// |PlatformConfigurationClient|
void RuntimeController::HandlePlatformMessage(
std::unique_ptr<PlatformMessage> message) {
Expand Down
9 changes: 9 additions & 0 deletions runtime/runtime_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class RuntimeDelegate;
class View;
class Window;

namespace testing {
class RuntimeControllerTester;
}

//------------------------------------------------------------------------------
/// Represents an instance of a running root isolate with window bindings. In
/// normal operation, a single instance of this object is owned by the engine
Expand Down Expand Up @@ -700,6 +704,7 @@ class RuntimeController : public PlatformConfigurationClient,
std::shared_ptr<PlatformIsolateManager> platform_isolate_manager_ =
std::shared_ptr<PlatformIsolateManager>(new PlatformIsolateManager());
bool has_flushed_runtime_state_ = false;
bool semantics_tree_enabled_ = false;

// Callbacks when `AddView` was called before the Dart isolate is launched.
//
Expand Down Expand Up @@ -752,6 +757,9 @@ class RuntimeController : public PlatformConfigurationClient,
// |PlatformConfigurationClient|
void UpdateSemantics(SemanticsUpdate* update) override;

// |PlatformConfigurationClient|
void SetSemanticsTreeEnabled(bool enabled) override;

// |PlatformConfigurationClient|
void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;

Expand Down Expand Up @@ -779,6 +787,7 @@ class RuntimeController : public PlatformConfigurationClient,
double GetScaledFontSize(double unscaled_font_size,
int configuration_id) const override;

friend class testing::RuntimeControllerTester;
FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
};

Expand Down
Loading
Loading