diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 66fdc6c94173b..61cb7b1a2d696 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1985,6 +1985,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/buffers.dart + ../.. ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codec.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codecs.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/shader_data.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart + ../../../flutter/LICENSE @@ -2004,9 +2005,11 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_pa ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart + ../../../flutter/LICENSE @@ -2058,6 +2061,7 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/picture.cpp + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/skwasm/shaders.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/wrappers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/runtime/dart_isolate.cc + ../../../flutter/LICENSE @@ -4572,6 +4576,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/buffers.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codec.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codecs.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/shader_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart @@ -4591,9 +4596,11 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_pain FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart @@ -4645,6 +4652,7 @@ FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp FILE: ../../../flutter/lib/web_ui/skwasm/picture.cpp +FILE: ../../../flutter/lib/web_ui/skwasm/shaders.cpp FILE: ../../../flutter/lib/web_ui/skwasm/surface.cpp FILE: ../../../flutter/lib/web_ui/skwasm/wrappers.h FILE: ../../../flutter/runtime/dart_isolate.cc diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index a18bf52d24a27..6a63871e9ccd6 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -392,7 +392,7 @@ class PlatformDispatcher { // * pointer_data.cc // * pointer.dart // * AndroidTouchProcessor.java - static const int _kPointerDataFieldCount = 36; + static const int _kPointerDataFieldCount = 35; static PointerDataPacket _unpackPointerDataPacket(ByteData packet) { const int kStride = Int64List.bytesPerElement; @@ -438,7 +438,6 @@ class PlatformDispatcher { panDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), scale: packet.getFloat64(kStride * offset++, _kFakeHostEndian), rotation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - preferredStylusAuxiliaryAction: PointerPreferredStylusAuxiliaryAction.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], )); assert(offset == (i + 1) * _kPointerDataFieldCount); } diff --git a/lib/ui/pointer.dart b/lib/ui/pointer.dart index 4585fbcbf0a87..608a4d49aded5 100644 --- a/lib/ui/pointer.dart +++ b/lib/ui/pointer.dart @@ -133,31 +133,10 @@ enum PointerSignalKind { /// A pointer-generated scale event (e.g. trackpad pinch). scale, - /// A stylus generated action (e.g. double tap on Apple Pencil 2) - stylusAuxiliaryAction, - /// An unknown pointer signal kind. unknown } - /// The preferred action for stylus action -enum PointerPreferredStylusAuxiliaryAction { - /// Ignore pointer input - ignore, - - /// Show colour palette if available - showColorPalette, - - /// Switch to eraser if available - switchEraser, - - /// Switch to previous tool - switchPrevious, - - /// unknown preferred action - unknown, -} - /// Information about the state of a pointer. class PointerData { /// Creates an object that represents the state of a pointer. @@ -197,7 +176,6 @@ class PointerData { this.panDeltaY = 0.0, this.scale = 0.0, this.rotation = 0.0, - this.preferredStylusAuxiliaryAction = PointerPreferredStylusAuxiliaryAction.ignore, }); /// Unique identifier that ties the [PointerEvent] to embedder event created it. @@ -396,11 +374,6 @@ class PointerData { /// The current angle of the pan/zoom in radians, with 0.0 as the initial angle. final double rotation; - /// For events with signal kind of stylusAuxiliaryAction - /// - /// The current preferred action for stylusAuxiliaryAction, with ignore as the default. - final PointerPreferredStylusAuxiliaryAction preferredStylusAuxiliaryAction; - @override String toString() => 'PointerData(x: $physicalX, y: $physicalY)'; @@ -440,8 +413,7 @@ class PointerData { 'panDeltaX: $panDeltaX, ' 'panDeltaY: $panDeltaY, ' 'scale: $scale, ' - 'rotation: $rotation, ' - 'preferredStylusAuxiliaryAction: $preferredStylusAuxiliaryAction' + 'rotation: $rotation' ')'; } } diff --git a/lib/ui/window/pointer_data.h b/lib/ui/window/pointer_data.h index 1dc159554ad74..1f323cc4f8169 100644 --- a/lib/ui/window/pointer_data.h +++ b/lib/ui/window/pointer_data.h @@ -11,7 +11,7 @@ namespace flutter { // If this value changes, update the pointer data unpacking code in // platform_dispatcher.dart. -static constexpr int kPointerDataFieldCount = 36; +static constexpr int kPointerDataFieldCount = 35; static constexpr int kBytesPerField = sizeof(int64_t); // Must match the button constants in events.dart. enum PointerButtonMouse : int64_t { @@ -63,16 +63,6 @@ struct alignas(8) PointerData { kScroll, kScrollInertiaCancel, kScale, - kStylusAuxiliaryAction, - }; - - // Must match the PreferredStylusAuxiliaryAction enum in pointer.dart. - enum class PreferredStylusAuxiliaryAction : int64_t { - kIgnore, - kShowColorPalette, - kSwitchEraser, - kSwitchPrevious, - kUnknown }; int64_t embedder_id; @@ -110,7 +100,6 @@ struct alignas(8) PointerData { double pan_delta_y; double scale; double rotation; - PreferredStylusAuxiliaryAction preferred_auxiliary_stylus_action; void Clear(); }; diff --git a/lib/ui/window/pointer_data_packet_converter.cc b/lib/ui/window/pointer_data_packet_converter.cc index d3b19f64bea05..6750a7da22761 100644 --- a/lib/ui/window/pointer_data_packet_converter.cc +++ b/lib/ui/window/pointer_data_packet_converter.cc @@ -293,7 +293,6 @@ void PointerDataPacketConverter::ConvertPointerData( switch (pointer_data.signal_kind) { case PointerData::SignalKind::kScroll: case PointerData::SignalKind::kScrollInertiaCancel: - case PointerData::SignalKind::kStylusAuxiliaryAction: case PointerData::SignalKind::kScale: { // Makes sure we have an existing pointer auto iter = states_.find(pointer_data.device); diff --git a/lib/ui/window/pointer_data_packet_converter_unittests.cc b/lib/ui/window/pointer_data_packet_converter_unittests.cc index 235f2f9a39c52..7c4c98162a3eb 100644 --- a/lib/ui/window/pointer_data_packet_converter_unittests.cc +++ b/lib/ui/window/pointer_data_packet_converter_unittests.cc @@ -45,8 +45,6 @@ void CreateSimulatedPointerData(PointerData& data, // NOLINT data.platformData = 0; data.scroll_delta_x = 0.0; data.scroll_delta_y = 0.0; - data.preferred_auxiliary_stylus_action = - PointerData::PreferredStylusAuxiliaryAction::kIgnore; } void CreateSimulatedMousePointerData(PointerData& data, // NOLINT @@ -86,8 +84,6 @@ void CreateSimulatedMousePointerData(PointerData& data, // NOLINT data.platformData = 0; data.scroll_delta_x = scroll_delta_x; data.scroll_delta_y = scroll_delta_y; - data.preferred_auxiliary_stylus_action = - PointerData::PreferredStylusAuxiliaryAction::kIgnore; } void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT @@ -133,8 +129,6 @@ void CreateSimulatedTrackpadGestureData(PointerData& data, // NOLINT data.pan_delta_y = 0.0; data.scale = scale; data.rotation = rotation; - data.preferred_auxiliary_stylus_action = - PointerData::PreferredStylusAuxiliaryAction::kIgnore; } void UnpackPointerPacket(std::vector& output, // NOLINT diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 05c6182108c4e..59e3773ceabce 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -272,7 +272,7 @@ abstract class Shader { bool get debugDisposed; } -abstract class Gradient extends Shader { +abstract class Gradient implements Shader { factory Gradient.linear( Offset from, Offset to, @@ -736,7 +736,7 @@ class Shadow { String toString() => 'TextShadow($color, $offset, $blurRadius)'; } -abstract class ImageShader extends Shader { +abstract class ImageShader implements Shader { factory ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4, { FilterQuality? filterQuality, }) => engine.renderer.createImageShader(image, tmx, tmy, matrix4, filterQuality); diff --git a/lib/web_ui/lib/pointer.dart b/lib/web_ui/lib/pointer.dart index fd7981bc354a7..542f5c70c90c3 100644 --- a/lib/web_ui/lib/pointer.dart +++ b/lib/web_ui/lib/pointer.dart @@ -34,24 +34,6 @@ enum PointerSignalKind { unknown } - /// The preferred action for stylus action -enum PointerPreferredStylusAuxiliaryAction { - /// Ignore pointer input - ignore, - - /// Show colour palette if available - showColorPalette, - - /// Switch to eraser if available - switchEraser, - - /// Switch to previous tool - switchPrevious, - - /// unknown preferred action - unknown, -} - class PointerData { const PointerData({ this.embedderId = 0, @@ -89,7 +71,6 @@ class PointerData { this.panDeltaY = 0.0, this.scale = 0.0, this.rotation = 0.0, - this.preferredStylusAuxiliaryAction = PointerPreferredStylusAuxiliaryAction.ignore, }); final int embedderId; final Duration timeStamp; @@ -126,7 +107,6 @@ class PointerData { final double panDeltaY; final double scale; final double rotation; - final PointerPreferredStylusAuxiliaryAction preferredStylusAuxiliaryAction; @override String toString() => 'PointerData(x: $physicalX, y: $physicalY)'; @@ -165,8 +145,7 @@ class PointerData { 'panDeltaX: $panDeltaX, ' 'panDeltaY: $panDeltaY, ' 'scale: $scale, ' - 'rotation: $rotation, ' - 'preferredStylusAuxiliaryAction: $preferredStylusAuxiliaryAction' + 'rotation: $rotation' ')'; } } diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 07e54ca03c127..8c6b9fcef6558 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -146,6 +146,7 @@ export 'engine/services/buffers.dart'; export 'engine/services/message_codec.dart'; export 'engine/services/message_codecs.dart'; export 'engine/services/serialization.dart'; +export 'engine/shader_data.dart'; export 'engine/shadow.dart'; export 'engine/svg.dart'; export 'engine/test_embedding.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/painting.dart b/lib/web_ui/lib/src/engine/canvaskit/painting.dart index 91e808f0c32cb..f046359b898f0 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/painting.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/painting.dart @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:convert'; import 'dart:typed_data'; +import 'package:ui/src/engine/shader_data.dart'; import 'package:ui/ui.dart' as ui; import '../color_filter.dart'; @@ -318,130 +318,23 @@ final Float32List _invertColorMatrix = Float32List.fromList(const [ final ManagedSkColorFilter _invertColorFilter = ManagedSkColorFilter(CkMatrixColorFilter(_invertColorMatrix)); -class UniformData { - const UniformData({ - required this.name, - required this.location, - required this.type, - }); - - final String name; - final UniformType type; - final int location; - - static const UniformData empty = - UniformData(name: '', location: -1, type: UniformType.Float); -} - -enum UniformType { - Boolean, - SByte, - UByte, - Short, - UShort, - Int, - Uint, - Int64, - Uint64, - Half, - Float, - Double, - SampledImage, -} - -UniformType? uniformTypeFromJson(int value) { - switch (value) { - case 0: - return UniformType.Boolean; - case 1: - return UniformType.SByte; - case 2: - return UniformType.UByte; - case 3: - return UniformType.Short; - case 4: - return UniformType.UShort; - case 5: - return UniformType.Int; - case 6: - return UniformType.Uint; - case 7: - return UniformType.Int64; - case 8: - return UniformType.Uint64; - case 9: - return UniformType.Half; - case 10: - return UniformType.Float; - case 11: - return UniformType.Double; - case 12: - return UniformType.SampledImage; - } - return null; -} - class CkFragmentProgram implements ui.FragmentProgram { CkFragmentProgram(this.name, this.effect, this.uniforms, this.floatCount, this.textureCount); - static Future fromBytes(String name, Uint8List data) async { - final String contents = utf8.decode(data); - final Object? rawShaderData = json.decode(contents); - if (rawShaderData is! Map) { - throw const FormatException('Invalid Shader Data'); - } - final Object? source = rawShaderData['sksl']; - final Object? rawUniforms = rawShaderData['uniforms']; - if (source is! String || rawUniforms is! List) { - throw const FormatException('Invalid Shader Data'); - } - final SkRuntimeEffect? effect = MakeRuntimeEffect(source); + factory CkFragmentProgram.fromBytes(String name, Uint8List data) { + final ShaderData shaderData = ShaderData.fromBytes(data); + final SkRuntimeEffect? effect = MakeRuntimeEffect(shaderData.source); if (effect == null) { - throw const FormatException('Invalid Shader Data'); + throw const FormatException('Invalid Shader Source'); } - final List uniforms = List.filled(rawUniforms.length, UniformData.empty); - - int textureCount = 0; - int floatCount = 0; - for (int i = 0; i < rawUniforms.length; i += 1) { - final Object? rawUniformData = rawUniforms[i]; - if (rawUniformData is! Map) { - throw const FormatException('Invalid Shader Data'); - } - final Object? name = rawUniformData['name']; - final Object? location = rawUniformData['location']; - final Object? rawType = rawUniformData['type']; - if (name is! String || location is! int || rawType is! int) { - throw const FormatException('Invalid Shader Data'); - } - final UniformType? type = uniformTypeFromJson(rawType); - if (type == null) { - throw const FormatException('Invalid Shader Data'); - } - if (type == UniformType.SampledImage) { - textureCount += 1; - } else { - final Object? rows = rawUniformData['rows']; - final Object? bitWidth = rawUniformData['bit_width']; - if (bitWidth is! int || rows is! int) { - throw const FormatException('Invalid Shader Data'); - } - floatCount += (bitWidth ~/ 32) * rows; - } - uniforms[location] = UniformData( - name: name, - location: location, - type: type, - ); - } return CkFragmentProgram( name, effect, - uniforms, - floatCount, - textureCount, + shaderData.uniforms, + shaderData.floatCount, + shaderData.textureCount, ); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 5a78d009ca0d9..06db1bc9a2a61 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -138,8 +138,6 @@ class CanvasKitRenderer implements Renderer { List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4, - ui.Offset? focal, - double focalRadius = 0.0, ]) => CkGradientRadial(center, radius, colors, colorStops, tileMode, matrix4); @override diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index dd155f2fc0efb..21de71dd1baee 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -91,8 +91,6 @@ class HtmlRenderer implements Renderer { List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4, - ui.Offset? focal, - double focalRadius = 0.0, ]) => GradientRadial(center, radius, colors, colorStops, tileMode, matrix4); @override diff --git a/lib/web_ui/lib/src/engine/shader_data.dart b/lib/web_ui/lib/src/engine/shader_data.dart new file mode 100644 index 0000000000000..9984e7123b7d0 --- /dev/null +++ b/lib/web_ui/lib/src/engine/shader_data.dart @@ -0,0 +1,138 @@ +// 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. + +import 'dart:convert'; +import 'dart:typed_data'; + +class ShaderData { + ShaderData({ + required this.source, + required this.uniforms, + required this.floatCount, + required this.textureCount, + }); + + factory ShaderData.fromBytes(Uint8List data) { + final String contents = utf8.decode(data); + final Object? rawShaderData = json.decode(contents); + if (rawShaderData is! Map) { + throw const FormatException('Invalid Shader Data'); + } + final Object? source = rawShaderData['sksl']; + final Object? rawUniforms = rawShaderData['uniforms']; + if (source is! String || rawUniforms is! List) { + throw const FormatException('Invalid Shader Data'); + } + + final List uniforms = List.filled(rawUniforms.length, UniformData.empty); + + int textureCount = 0; + int floatCount = 0; + for (int i = 0; i < rawUniforms.length; i += 1) { + final Object? rawUniformData = rawUniforms[i]; + if (rawUniformData is! Map) { + throw const FormatException('Invalid Shader Data'); + } + final Object? name = rawUniformData['name']; + final Object? location = rawUniformData['location']; + final Object? rawType = rawUniformData['type']; + if (name is! String || location is! int || rawType is! int) { + throw const FormatException('Invalid Shader Data'); + } + final UniformType? type = uniformTypeFromJson(rawType); + if (type == null) { + throw const FormatException('Invalid Shader Data'); + } + if (type == UniformType.SampledImage) { + textureCount += 1; + } else { + final Object? rows = rawUniformData['rows']; + final Object? bitWidth = rawUniformData['bit_width']; + if (bitWidth is! int || rows is! int) { + throw const FormatException('Invalid Shader Data'); + } + floatCount += (bitWidth ~/ 32) * rows; + } + uniforms[location] = UniformData( + name: name, + location: location, + type: type, + ); + } + return ShaderData( + source: source, + uniforms: uniforms, + floatCount: floatCount, + textureCount: textureCount, + ); + } + + String source; + List uniforms; + int floatCount; + int textureCount; +} + +class UniformData { + const UniformData({ + required this.name, + required this.location, + required this.type, + }); + + final String name; + final UniformType type; + final int location; + + static const UniformData empty = + UniformData(name: '', location: -1, type: UniformType.Float); +} + +enum UniformType { + Boolean, + SByte, + UByte, + Short, + UShort, + Int, + Uint, + Int64, + Uint64, + Half, + Float, + Double, + SampledImage, +} + +UniformType? uniformTypeFromJson(int value) { + switch (value) { + case 0: + return UniformType.Boolean; + case 1: + return UniformType.SByte; + case 2: + return UniformType.UByte; + case 3: + return UniformType.Short; + case 4: + return UniformType.UShort; + case 5: + return UniformType.Int; + case 6: + return UniformType.Uint; + case 7: + return UniformType.Int64; + case 8: + return UniformType.Uint64; + case 9: + return UniformType.Half; + case 10: + return UniformType.Float; + case 11: + return UniformType.Double; + case 12: + return UniformType.SampledImage; + } + return null; +} diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart index 566a2c88679d3..9d489df3ab489 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -26,8 +26,10 @@ export 'skwasm_impl/raw/raw_paint.dart'; export 'skwasm_impl/raw/raw_path.dart'; export 'skwasm_impl/raw/raw_path_metrics.dart'; export 'skwasm_impl/raw/raw_picture.dart'; +export 'skwasm_impl/raw/raw_shaders.dart'; export 'skwasm_impl/raw/raw_surface.dart'; export 'skwasm_impl/renderer.dart'; export 'skwasm_impl/scene_builder.dart'; +export 'skwasm_impl/shaders.dart'; export 'skwasm_impl/surface.dart'; export 'skwasm_impl/vertices.dart'; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/layers.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/layers.dart index c2004d390581f..4bda6822b11d6 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/layers.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/layers.dart @@ -23,7 +23,7 @@ class BackdropFilterOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { // TODO(jacksongardner): Implement backdrop filter } } @@ -50,7 +50,7 @@ class ClipPathOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { if (clip == ui.Clip.antiAliasWithSaveLayer) { canvas.restore(); } @@ -80,7 +80,7 @@ class ClipRectOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { if (clip == ui.Clip.antiAliasWithSaveLayer) { canvas.restore(); } @@ -110,7 +110,7 @@ class ClipRRectOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { if (clip == ui.Clip.antiAliasWithSaveLayer) { canvas.restore(); } @@ -133,7 +133,7 @@ class ColorFilterOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { // TODO(jacksongardner): Implement color filter } } @@ -151,7 +151,7 @@ class ImageFilterOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { // TODO(jacksongardner): Implement image filter } } @@ -175,7 +175,7 @@ class OffsetOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { canvas.restore(); } } @@ -205,7 +205,7 @@ class OpacityOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { canvas.restore(); if (offset != ui.Offset.zero) { canvas.restore(); @@ -232,11 +232,48 @@ class TransformOperation implements LayerOperation { } @override - void post(ui.Canvas canvas) { + void post(ui.Canvas canvas, ui.Rect contentRect) { canvas.restore(); } } +class ShaderMaskLayer + with PictureLayer + implements ui.ShaderMaskEngineLayer {} +class ShaderMaskOperation implements LayerOperation { + ShaderMaskOperation(this.shader, this.maskRect, this.blendMode); + + final ui.Shader shader; + final ui.Rect maskRect; + final ui.BlendMode blendMode; + + @override + ui.Rect cullRect(ui.Rect contentRect) => contentRect; + + @override + void pre(ui.Canvas canvas, ui.Rect contentRect) { + canvas.saveLayer( + contentRect, + ui.Paint(), + ); + } + + @override + void post(ui.Canvas canvas, ui.Rect contentRect) { + canvas.save(); + canvas.translate(maskRect.left, maskRect.top); + canvas.drawRect( + ui.Rect.fromLTWH(0, 0, maskRect.width, maskRect.height), + ui.Paint() + ..blendMode = blendMode + ..shader = shader + ); + canvas.restore(); + canvas.restore(); + } +} + + mixin PictureLayer implements ui.EngineLayer { ui.Picture? picture; @@ -251,7 +288,7 @@ abstract class LayerOperation { ui.Rect cullRect(ui.Rect contentRect); void pre(ui.Canvas canvas, ui.Rect contentRect); - void post(ui.Canvas canvas); + void post(ui.Canvas canvas, ui.Rect contentRect); } class PictureDrawCommand { @@ -284,14 +321,15 @@ class LayerBuilder { final PictureLayer? layer; final LayerOperation? operation; final List drawCommands = []; - ui.Rect contentRect = ui.Rect.zero; + ui.Rect? contentRect; ui.Picture build() { - final ui.Rect rect = operation?.cullRect(contentRect) ?? contentRect; + final ui.Rect drawnRect = contentRect ?? ui.Rect.zero; + final ui.Rect rect = operation?.cullRect(drawnRect) ?? drawnRect; final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, rect); - operation?.pre(canvas, contentRect); + operation?.pre(canvas, rect); for (final PictureDrawCommand command in drawCommands) { if (command.offset != ui.Offset.zero) { canvas.save(); @@ -302,7 +340,7 @@ class LayerBuilder { canvas.drawPicture(command.picture); } } - operation?.post(canvas); + operation?.post(canvas, rect); final ui.Picture picture = recorder.endRecording(); layer?.picture = picture; return picture; @@ -316,6 +354,7 @@ class LayerBuilder { }) { drawCommands.add(PictureDrawCommand(offset, picture)); final ui.Rect cullRect = (picture as SkwasmPicture).cullRect; - contentRect = contentRect.expandToInclude(cullRect.shift(offset)); + final ui.Rect shiftedRect = cullRect.shift(offset); + contentRect = contentRect?.expandToInclude(shiftedRect) ?? shiftedRect; } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart index daabca6a03ce8..3c953df026394 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ffi'; + import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart' as ui; @@ -17,6 +19,8 @@ class SkwasmPaint implements ui.Paint { ui.BlendMode _cachedBlendMode = ui.BlendMode.srcOver; + SkwasmShader? _shader; + @override ui.BlendMode get blendMode { return _cachedBlendMode; @@ -89,5 +93,14 @@ class SkwasmPaint implements ui.Paint { ui.MaskFilter? maskFilter; @override - ui.Shader? shader; + ui.Shader? get shader => _shader; + + @override + set shader(ui.Shader? uiShader) { + final SkwasmShader? skwasmShader = uiShader as SkwasmShader?; + _shader = skwasmShader; + final ShaderHandle shaderHandle = + skwasmShader != null ? skwasmShader.handle : nullptr; + paintSetShader(_handle, shaderHandle); + } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart index 177d30feadfd5..276fc0dd02461 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart @@ -108,7 +108,7 @@ external void canvasDrawCircle( CanvasHandle canvas, double x, double y, double radius, PaintHandle paint); @Native( - symbol: 'canvas_drawCircle', isLeaf: true) + symbol: 'canvas_drawArc', isLeaf: true) external void canvasDrawArc( CanvasHandle canvas, RawRect rect, diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart index 74fc835bb920b..3bf14ad9b25c7 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart @@ -10,3 +10,4 @@ typedef RawRRect = Pointer; typedef RawPointArray = Pointer; typedef RawMatrix33 = Pointer; typedef RawMatrix44 = Pointer; +typedef RawColorArray = Pointer; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart index 6a5c68a7479a8..9c88cc55091d2 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart @@ -36,7 +36,7 @@ class StackScope { return pointer; } - Pointer convertMatrix4toSkMatrix(Float64List matrix4) { + Pointer convertMatrix4toSkMatrix(List matrix4) { final Pointer pointer = allocFloatArray(9); final int matrixLength = matrix4.length; @@ -132,6 +132,14 @@ class StackScope { return pointer; } + Pointer convertDoublesToNative(List values) { + final Pointer pointer = allocFloatArray(values.length); + for (int i = 0; i < values.length; i++) { + pointer[i] = values[i]; + } + return pointer; + } + Pointer convertPointArrayToNative(List points) { final Pointer pointer = allocFloatArray(points.length * 2); for (int i = 0; i < points.length; i++) { @@ -141,6 +149,14 @@ class StackScope { return pointer; } + Pointer convertColorArrayToNative(List colors) { + final Pointer pointer = allocUint32Array(colors.length); + for (int i = 0; i < colors.length; i++) { + pointer[i] = colors[i].value; + } + return pointer; + } + Pointer allocInt8Array(int count) { final int length = count * sizeOf(); return stackAlloc(length).cast(); @@ -151,10 +167,20 @@ class StackScope { return stackAlloc(length).cast(); } + Pointer allocUint32Array(int count) { + final int length = count * sizeOf(); + return stackAlloc(length).cast(); + } + Pointer allocFloatArray(int count) { final int length = count * sizeOf(); return stackAlloc(length).cast(); } + + Pointer> allocPointerArray(int count) { + final int length = count * sizeOf>(); + return stackAlloc(length).cast>(); + } } T withStackScope(T Function(StackScope scope) f) { diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart index 5d59a362db27d..0ac1262663cd9 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart @@ -7,6 +7,8 @@ library skwasm_impl; import 'dart:ffi'; +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; + final class RawPaint extends Opaque {} typedef PaintHandle = Pointer; @@ -61,3 +63,6 @@ external void paintSetMiterLimit(PaintHandle paint, double miterLimit); @Native(symbol: 'paint_getMiterLimit', isLeaf: true) external double paintGetMiterLimit(PaintHandle paint); + +@Native(symbol: 'paint_setShader', isLeaf: true) +external void paintSetShader(PaintHandle handle, ShaderHandle shader); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart new file mode 100644 index 0000000000000..beadca256a28d --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart @@ -0,0 +1,147 @@ +// 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. + +@DefaultAsset('skwasm') +library skwasm_impl; + +import 'dart:ffi'; + +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; + +final class RawShader extends Opaque {} +typedef ShaderHandle = Pointer; + +final class RawSkString extends Opaque {} +typedef SkStringHandle = Pointer; + +final class RawSkData extends Opaque {} +typedef SkDataHandle = Pointer; + +final class RawRuntimeEffect extends Opaque {} +typedef RuntimeEffectHandle = Pointer; + +@Native, + Int, + Int, + RawMatrix33, +)>(symbol: 'shader_createLinearGradient', isLeaf: true) +external ShaderHandle shaderCreateLinearGradient( + RawPointArray endPoints, // two points + RawColorArray colors, + Pointer stops, // Can be nullptr + int count, // Number of stops/colors + int tileMode, + RawMatrix33 matrix, // Can be nullptr +); + +@Native, + Int, + Int, + RawMatrix33, +)>(symbol: 'shader_createRadialGradient', isLeaf: true) +external ShaderHandle shaderCreateRadialGradient( + double centerX, + double centerY, + double radius, + RawColorArray colors, + Pointer stops, + int count, + int tileMode, + RawMatrix33 localMatrix, +); + +@Native, + Int, + Int, + RawMatrix33, +)>(symbol: 'shader_createConicalGradient', isLeaf: true) +external ShaderHandle shaderCreateConicalGradient( + RawPointArray endPoints, // Two points, + double startRadius, + double endRadius, + RawColorArray colors, + Pointer stops, + int count, + int tileMode, + RawMatrix33 localMatrix, +); + +@Native, + Int, + Int, + Float, + Float, + RawMatrix33, +)>(symbol: 'shader_createSweepGradient', isLeaf: true) +external ShaderHandle shaderCreateSweepGradient( + double centerX, + double centerY, + RawColorArray colors, + Pointer stops, + int count, + int tileMode, + double startAngle, + double endAngle, + RawMatrix33 localMatrix +); + +@Native(symbol: 'shader_dispose', isLeaf: true) +external void shaderDispose(ShaderHandle handle); + +@Native(symbol: 'shaderSource_allocate', isLeaf: true) +external SkStringHandle shaderSourceAllocate(int size); + +@Native Function(SkStringHandle)>(symbol: 'shaderSource_getData', isLeaf: true) +external Pointer shaderSourceGetData(SkStringHandle handle); + +@Native(symbol: 'shaderSource_free', isLeaf: true) +external void shaderSourceFree(SkStringHandle handle); + +@Native(symbol: 'runtimeEffect_create', isLeaf: true) +external RuntimeEffectHandle runtimeEffectCreate(SkStringHandle source); + +@Native(symbol: 'runtimeEffect_dispose', isLeaf: true) +external void runtimeEffectDispose(RuntimeEffectHandle handle); + +@Native(symbol: 'runtimeEffect_getUniformSize', isLeaf: true) +external int runtimeEffectGetUniformSize(RuntimeEffectHandle handle); + +@Native(symbol: 'data_create', isLeaf: true) +external SkDataHandle dataCreate(int size); + +@Native Function(SkDataHandle)>(symbol: 'data_getPointer', isLeaf: true) +external Pointer dataGetPointer(SkDataHandle handle); + +@Native(symbol: 'data_dispose', isLeaf: true) +external void dataDispose(SkDataHandle handle); + +@Native, + Size +)>(symbol: 'shader_createRuntimeEffectShader', isLeaf: true) +external ShaderHandle shaderCreateRuntimeEffectShader( + RuntimeEffectHandle runtimeEffect, + SkDataHandle uniforms, + Pointer childShaders, + int childCount +); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index d43bcd01e1a43..4740a2f4e9724 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -45,9 +45,24 @@ class SkwasmRenderer implements Renderer { } @override - ui.Gradient createConicalGradient(ui.Offset focal, double focalRadius, ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix]) { - throw UnimplementedError('createConicalGradient not yet implemented'); - } + ui.Gradient createConicalGradient( + ui.Offset focal, + double focalRadius, + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix]) => SkwasmGradient.conical( + focal: focal, + focalRadius: focalRadius, + center: center, + centerRadius: radius, + colors: colors, + colorStops: colorStops, + tileMode: tileMode, + matrix4: matrix, + ); @override ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { @@ -65,9 +80,21 @@ class SkwasmRenderer implements Renderer { } @override - ui.Gradient createLinearGradient(ui.Offset from, ui.Offset to, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { - throw UnimplementedError('createLinearGradientn not yet implemented'); - } + ui.Gradient createLinearGradient( + ui.Offset from, + ui.Offset to, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4 + ]) => SkwasmGradient.linear( + from: from, + to: to, + colors: colors, + colorStops: colorStops, + tileMode: tileMode, + matrix4: matrix4, + ); @override ui.ImageFilter createMatrixImageFilter(Float64List matrix4, {ui.FilterQuality filterQuality = ui.FilterQuality.low}) { @@ -102,9 +129,21 @@ class SkwasmRenderer implements Renderer { ui.PictureRecorder createPictureRecorder() => SkwasmPictureRecorder(); @override - ui.Gradient createRadialGradient(ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { - throw UnimplementedError('createRadialGradient not yet implemented'); - } + ui.Gradient createRadialGradient( + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4 + ]) => SkwasmGradient.radial( + center: center, + radius: radius, + colors: colors, + colorStops: colorStops, + tileMode: tileMode, + matrix4: matrix4 + ); @override ui.SceneBuilder createSceneBuilder() => SkwasmSceneBuilder(); @@ -133,9 +172,15 @@ class SkwasmRenderer implements Renderer { double startAngle = 0.0, double endAngle = math.pi * 2, Float32List? matrix4 - ]) { - throw UnimplementedError('createSweepGradient not yet implemented'); - } + ]) => SkwasmGradient.sweep( + center: center, + colors: colors, + colorStops: colorStops, + tileMode: tileMode, + startAngle: startAngle, + endAngle: endAngle, + matrix4: matrix4 + ); @override ui.TextStyle createTextStyle({ @@ -251,11 +296,20 @@ class SkwasmRenderer implements Renderer { embedder.addSceneToSceneHost(sceneElement); } + static final Map> _programs = >{}; + @override - void clearFragmentProgramCache() { } + void clearFragmentProgramCache() { + _programs.clear(); + } @override Future createFragmentProgram(String assetKey) { - throw UnimplementedError('createFragmentProgram not yet implemented'); + if (_programs.containsKey(assetKey)) { + return _programs[assetKey]!; + } + return _programs[assetKey] = assetManager.load(assetKey).then((ByteData data) { + return SkwasmFragmentProgram.fromBytes(assetKey, data.buffer.asUint8List()); + }); } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart index 8afc70a8f3a8c..e2cc62508bf03 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart @@ -90,36 +90,30 @@ class SkwasmSceneBuilder implements ui.SceneBuilder { ui.ImageFilter filter, { ui.BlendMode blendMode = ui.BlendMode.srcOver, ui.BackdropFilterEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( BackdropFilterLayer(), BackdropFilterOperation() ); - } @override ui.ClipPathEngineLayer pushClipPath( ui.Path path, { ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipPathEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( ClipPathLayer(), ClipPathOperation(path, clipBehavior), ); - } @override ui.ClipRRectEngineLayer pushClipRRect( ui.RRect rrect, { required ui.Clip clipBehavior, ui.ClipRRectEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( ClipRRectLayer(), ClipRRectOperation(rrect, clipBehavior) ); - } @override ui.ClipRectEngineLayer pushClipRect( @@ -137,47 +131,39 @@ class SkwasmSceneBuilder implements ui.SceneBuilder { ui.ColorFilterEngineLayer pushColorFilter( ui.ColorFilter filter, { ui.ColorFilterEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( ColorFilterLayer(), ColorFilterOperation(), ); - } @override ui.ImageFilterEngineLayer pushImageFilter( ui.ImageFilter filter, { ui.Offset offset = ui.Offset.zero, ui.ImageFilterEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( ImageFilterLayer(), ImageFilterOperation(), ); - } @override ui.OffsetEngineLayer pushOffset( double dx, double dy, { ui.OffsetEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( OffsetLayer(), OffsetOperation(dx, dy) ); - } @override ui.OpacityEngineLayer pushOpacity(int alpha, { ui.Offset offset = ui.Offset.zero, ui.OpacityEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( OpacityLayer(), OpacityOperation(alpha, offset), ); - } @override ui.PhysicalShapeEngineLayer pushPhysicalShape({ @@ -199,21 +185,19 @@ class SkwasmSceneBuilder implements ui.SceneBuilder { ui.BlendMode blendMode, { ui.ShaderMaskEngineLayer? oldLayer, ui.FilterQuality filterQuality = ui.FilterQuality.low - }) { - // TODO(jacksongardner): implement pushShaderMask - throw UnimplementedError(); - } + }) => pushLayer( + ShaderMaskLayer(), + ShaderMaskOperation(shader, maskRect, blendMode) + ); @override ui.TransformEngineLayer pushTransform( Float64List matrix4, { ui.TransformEngineLayer? oldLayer - }) { - return pushLayer( + }) => pushLayer( TransformLayer(), TransformOperation(matrix4), ); - } @override void setCheckerboardOffscreenLayers(bool checkerboard) { diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart new file mode 100644 index 0000000000000..dc37b92666143 --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart @@ -0,0 +1,254 @@ +// 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. + +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:typed_data'; + +import 'package:ui/src/engine.dart'; +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; +import 'package:ui/ui.dart' as ui; + +abstract class SkwasmShader implements ui.Shader { + ShaderHandle get handle; + + @override + bool get debugDisposed => handle == nullptr; + + @override + void dispose() { + if (handle != nullptr) { + shaderDispose(handle); + } + } +} + +class SkwasmGradient extends SkwasmShader implements ui.Gradient { + factory SkwasmGradient.linear({ + required ui.Offset from, + required ui.Offset to, + required List colors, + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + }) => withStackScope((StackScope scope) { + final RawPointArray endPoints = + scope.convertPointArrayToNative([from, to]); + final RawColorArray nativeColors = scope.convertColorArrayToNative(colors); + final Pointer stops = colorStops != null + ? scope.convertDoublesToNative(colorStops) + : nullptr; + final Pointer matrix = matrix4 != null + ? scope.convertMatrix4toSkMatrix(matrix4) + : nullptr; + final ShaderHandle handle = shaderCreateLinearGradient( + endPoints, + nativeColors, + stops, + colors.length, + tileMode.index, + matrix + ); + return SkwasmGradient._(handle); + }); + + factory SkwasmGradient.radial({ + required ui.Offset center, + required double radius, + required List colors, + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + }) => withStackScope((StackScope scope) { + final RawColorArray rawColors = scope.convertColorArrayToNative(colors); + final Pointer rawStops = colorStops != null + ? scope.convertDoublesToNative(colorStops) + : nullptr; + final Pointer matrix = matrix4 != null + ? scope.convertMatrix4toSkMatrix(matrix4) + : nullptr; + final ShaderHandle handle = shaderCreateRadialGradient( + center.dx, + center.dy, + radius, + rawColors, + rawStops, + colors.length, + tileMode.index, + matrix, + ); + return SkwasmGradient._(handle); + }); + + factory SkwasmGradient.conical({ + required ui.Offset focal, + required double focalRadius, + required ui.Offset center, + required double centerRadius, + required List colors, + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + }) => withStackScope((StackScope scope) { + final RawPointArray endPoints = + scope.convertPointArrayToNative([focal, center]); + final RawColorArray rawColors = scope.convertColorArrayToNative(colors); + final Pointer rawStops = colorStops != null + ? scope.convertDoublesToNative(colorStops) + : nullptr; + final Pointer matrix = matrix4 != null + ? scope.convertMatrix4toSkMatrix(matrix4) + : nullptr; + final ShaderHandle handle = shaderCreateConicalGradient( + endPoints, + focalRadius, + centerRadius, + rawColors, + rawStops, + colors.length, + tileMode.index, + matrix + ); + return SkwasmGradient._(handle); + }); + + factory SkwasmGradient.sweep({ + required ui.Offset center, + required List colors, + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + required double startAngle, + required double endAngle, + Float32List? matrix4, + }) => withStackScope((StackScope scope) { + final RawColorArray rawColors = scope.convertColorArrayToNative(colors); + final Pointer rawStops = colorStops != null + ? scope.convertDoublesToNative(colorStops) + : nullptr; + final Pointer matrix = matrix4 != null + ? scope.convertMatrix4toSkMatrix(matrix4) + : nullptr; + final ShaderHandle handle = shaderCreateSweepGradient( + center.dx, + center.dy, + rawColors, + rawStops, + colors.length, + tileMode.index, + ui.toDegrees(startAngle), + ui.toDegrees(endAngle), + matrix + ); + return SkwasmGradient._(handle); + }); + + SkwasmGradient._(this.handle); + + @override + ShaderHandle handle; + + @override + void dispose() { + super.dispose(); + handle = nullptr; + } +} + +class SkwasmFragmentProgram implements ui.FragmentProgram { + SkwasmFragmentProgram._(this.name, this.handle); + factory SkwasmFragmentProgram.fromBytes(String name, Uint8List bytes) { + final ShaderData shaderData = ShaderData.fromBytes(bytes); + + // TODO(jacksongardner): Can we avoid this copy? + final List sourceData = utf8.encode(shaderData.source); + final SkStringHandle sourceString = shaderSourceAllocate(sourceData.length); + final Pointer sourceBuffer = shaderSourceGetData(sourceString); + int i = 0; + for (final int byte in sourceData) { + sourceBuffer[i] = byte; + i++; + } + final RuntimeEffectHandle handle = runtimeEffectCreate(sourceString); + shaderSourceFree(sourceString); + return SkwasmFragmentProgram._(name, handle); + } + + RuntimeEffectHandle handle; + String name; + + @override + ui.FragmentShader fragmentShader() => + SkwasmFragmentShader(this); + + int get uniformSize => runtimeEffectGetUniformSize(handle); + + void dispose() { + runtimeEffectDispose(handle); + } +} + +class SkwasmFragmentShader extends SkwasmShader implements ui.FragmentShader { + SkwasmFragmentShader( + SkwasmFragmentProgram program, { + List? childShaders, + }) : _program = program, + _uniformData = dataCreate(program.uniformSize), + _childShaders = childShaders; + + @override + ShaderHandle get handle { + if (_handle == nullptr) { + _handle = withStackScope((StackScope s) { + Pointer childShaders = nullptr; + final int childCount = _childShaders != null ? _childShaders!.length : 0; + if (childCount != 0) { + childShaders = s.allocPointerArray(childCount) + .cast(); + final List shaders = _childShaders!; + for (int i = 0; i < childCount; i++) { + childShaders[i] = shaders[i].handle; + } + } + return shaderCreateRuntimeEffectShader( + _program.handle, + _uniformData, + childShaders, + childCount, + ); + }); + } + return _handle; + } + + ShaderHandle _handle = nullptr; + final SkwasmFragmentProgram _program; + SkDataHandle _uniformData; + final List? _childShaders; + + @override + void setFloat(int index, double value) { + if (_handle != nullptr) { + // Invalidate the previous shader so that it is recreated with the new + // uniform data. + shaderDispose(_handle); + _handle = nullptr; + } + final Pointer dataPointer = dataGetPointer(_uniformData).cast(); + dataPointer[index] = value; + } + + @override + void setImageSampler(int index, ui.Image image) { + // TODO(jacksongardner): implement this when images are implemented + } + + @override + void dispose() { + super.dispose(); + if (_uniformData != nullptr) { + dataDispose(_uniformData); + _uniformData = nullptr; + } + } +} diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart index 9102aed5d4fba..40082de28d793 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart @@ -6,13 +6,9 @@ import 'dart:async'; import 'dart:math' as math; import 'dart:typed_data'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../embedder.dart'; -import '../../fonts.dart'; -import '../../html_image_codec.dart'; -import '../../renderer.dart'; - class SkwasmRenderer implements Renderer { @override ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) { @@ -166,10 +162,17 @@ class SkwasmRenderer implements Renderer { } @override - void clearFragmentProgramCache() { } + void clearFragmentProgramCache() => _programs.clear(); + + static final Map> _programs = >{}; @override Future createFragmentProgram(String assetKey) { - throw UnimplementedError('Skwasm not implemented on this platform.'); + if (_programs.containsKey(assetKey)) { + return _programs[assetKey]!; + } + return _programs[assetKey] = assetManager.load(assetKey).then((ByteData data) { + return CkFragmentProgram.fromBytes(assetKey, data.buffer.asUint8List()); + }); } } diff --git a/lib/web_ui/skwasm/BUILD.gn b/lib/web_ui/skwasm/BUILD.gn index 301716de81762..7ad61d87fefcd 100644 --- a/lib/web_ui/skwasm/BUILD.gn +++ b/lib/web_ui/skwasm/BUILD.gn @@ -13,6 +13,7 @@ wasm_lib("skwasm") { "paint.cpp", "path.cpp", "picture.cpp", + "shaders.cpp", "surface.cpp", "wrappers.h", ] diff --git a/lib/web_ui/skwasm/paint.cpp b/lib/web_ui/skwasm/paint.cpp index 84f1b90bd39ef..eb66fff6e292a 100644 --- a/lib/web_ui/skwasm/paint.cpp +++ b/lib/web_ui/skwasm/paint.cpp @@ -6,6 +6,7 @@ #include "export.h" #include "helpers.h" #include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkShader.h" using namespace Skwasm; @@ -82,3 +83,12 @@ SKWASM_EXPORT void paint_setMiterLimit(SkPaint* paint, SkScalar miterLimit) { SKWASM_EXPORT SkScalar paint_getMiterLImit(SkPaint* paint) { return paint->getStrokeMiter(); } + +SKWASM_EXPORT void paint_setShader(SkPaint* paint, SkShader* shader) { + if (shader == nullptr) { + paint->setShader(nullptr); + return; + } + shader->ref(); + return paint->setShader(sk_sp(shader)); +} diff --git a/lib/web_ui/skwasm/shaders.cpp b/lib/web_ui/skwasm/shaders.cpp new file mode 100644 index 0000000000000..1c29c10e844fb --- /dev/null +++ b/lib/web_ui/skwasm/shaders.cpp @@ -0,0 +1,163 @@ +// 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 +#include "export.h" +#include "helpers.h" +#include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/effects/SkRuntimeEffect.h" +#include "wrappers.h" + +using namespace Skwasm; + +SKWASM_EXPORT SkShader* shader_createLinearGradient( + SkPoint* endPoints, // Two points + SkColor* colors, + SkScalar* stops, + int count, // Number of stops/colors + SkTileMode tileMode, + SkScalar* matrix33 // Can be nullptr +) { + if (matrix33) { + SkMatrix localMatrix = createMatrix(matrix33); + return SkGradientShader::MakeLinear(endPoints, colors, stops, count, + tileMode, 0, &localMatrix) + .release(); + } else { + return SkGradientShader::MakeLinear(endPoints, colors, stops, count, + tileMode) + .release(); + } +} + +SKWASM_EXPORT SkShader* shader_createRadialGradient(SkScalar centerX, + SkScalar centerY, + SkScalar radius, + SkColor* colors, + SkScalar* stops, + int count, + SkTileMode tileMode, + SkScalar* matrix33) { + if (matrix33) { + SkMatrix localMatrix = createMatrix(matrix33); + return SkGradientShader::MakeRadial({centerX, centerY}, radius, colors, + stops, count, tileMode, 0, &localMatrix) + .release(); + } else { + return SkGradientShader::MakeRadial({centerX, centerY}, radius, colors, + stops, count, tileMode) + .release(); + } +} + +SKWASM_EXPORT SkShader* shader_createConicalGradient( + SkPoint* endPoints, // Two points + SkScalar startRadius, + SkScalar endRadius, + SkColor* colors, + SkScalar* stops, + int count, + SkTileMode tileMode, + SkScalar* matrix33) { + if (matrix33) { + SkMatrix localMatrix = createMatrix(matrix33); + return SkGradientShader::MakeTwoPointConical( + endPoints[0], startRadius, endPoints[1], endRadius, colors, + stops, count, tileMode, 0, &localMatrix) + .release(); + + } else { + return SkGradientShader::MakeTwoPointConical(endPoints[0], startRadius, + endPoints[1], endRadius, + colors, stops, count, tileMode) + .release(); + } +} + +SKWASM_EXPORT SkShader* shader_createSweepGradient(SkScalar centerX, + SkScalar centerY, + SkColor* colors, + SkScalar* stops, + int count, + SkTileMode tileMode, + SkScalar startAngle, + SkScalar endAngle, + SkScalar* matrix33) { + if (matrix33) { + SkMatrix localMatrix = createMatrix(matrix33); + return SkGradientShader::MakeSweep(centerX, centerY, colors, stops, count, + tileMode, startAngle, endAngle, 0, + &localMatrix) + .release(); + } else { + return SkGradientShader::MakeSweep(centerX, centerY, colors, stops, count, + tileMode, startAngle, endAngle, 0, + nullptr) + .release(); + } +} + +SKWASM_EXPORT void shader_dispose(SkShader* shader) { + shader->unref(); +} + +SKWASM_EXPORT SkString* shaderSource_allocate(size_t length) { + return new SkString(length); +} + +SKWASM_EXPORT char* shaderSource_getData(SkString* string) { + return string->data(); +} + +SKWASM_EXPORT void shaderSource_free(SkString* string) { + return delete string; +} + +SKWASM_EXPORT SkRuntimeEffect* runtimeEffect_create(SkString* source) { + auto result = SkRuntimeEffect::MakeForShader(*source); + if (result.effect == nullptr) { + printf("Failed to compile shader. Error text:\n%s", + result.errorText.data()); + return nullptr; + } else { + return result.effect.release(); + } +} + +SKWASM_EXPORT void runtimeEffect_dispose(SkRuntimeEffect* effect) { + effect->unref(); +} + +SKWASM_EXPORT size_t runtimeEffect_getUniformSize(SkRuntimeEffect* effect) { + return effect->uniformSize(); +} + +SKWASM_EXPORT SkData* data_create(size_t size) { + return SkData::MakeUninitialized(size).release(); +} + +SKWASM_EXPORT void* data_getPointer(SkData* data) { + return data->writable_data(); +} + +SKWASM_EXPORT void data_dispose(SkData* data) { + return data->unref(); +} + +SKWASM_EXPORT SkShader* shader_createRuntimeEffectShader( + SkRuntimeEffect* runtimeEffect, + SkData* uniforms, + SkShader** children, + size_t childCount) { + std::vector> childPointers; + for (size_t i = 0; i < childCount; i++) { + auto child = children[i]; + child->ref(); + childPointers.emplace_back(child); + } + return runtimeEffect + ->makeShader(SkData::MakeWithCopy(uniforms->data(), uniforms->size()), + childPointers.data(), childCount, nullptr) + .release(); +} diff --git a/lib/web_ui/test/canvaskit/fragment_program_test.dart b/lib/web_ui/test/canvaskit/fragment_program_test.dart index 178188ccf6635..632ba07792091 100644 --- a/lib/web_ui/test/canvaskit/fragment_program_test.dart +++ b/lib/web_ui/test/canvaskit/fragment_program_test.dart @@ -185,9 +185,9 @@ void testMain() { await ui.webOnlyInitializePlatform(); }); - test('FragmentProgram can be created from JSON IPLR bundle', () async { + test('FragmentProgram can be created from JSON IPLR bundle', () { final Uint8List data = utf8.encode(kJsonIPLR) as Uint8List; - final CkFragmentProgram program = await CkFragmentProgram.fromBytes('test', data); + final CkFragmentProgram program = CkFragmentProgram.fromBytes('test', data); expect(program.effect, isNotNull); expect(program.floatCount, 32); diff --git a/lib/web_ui/test/ui/canvas_curves_golden_test.dart b/lib/web_ui/test/ui/canvas_curves_golden_test.dart new file mode 100644 index 0000000000000..e067e9f944b8f --- /dev/null +++ b/lib/web_ui/test/ui/canvas_curves_golden_test.dart @@ -0,0 +1,74 @@ +// 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. + +import 'dart:math' as math; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/ui.dart'; +import 'package:web_engine_tester/golden_tester.dart'; + +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + setUpUiTest(); + + const Rect region = Rect.fromLTWH(0, 0, 300, 300); + + test('draw arc', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawArc( + const Rect.fromLTRB(100, 100, 200, 200), + math.pi / 3.0, + 4.0 * math.pi / 3.0, + false, + Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 3.0 + ..color = const Color(0xFFFF00FF) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('ui_canvas_draw_arc.png', region: region); + }); + + test('draw circle', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawCircle( + const Offset(150, 150), + 50, + Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 3.0 + ..color = const Color(0xFFFF0000) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('ui_canvas_draw_circle.png', region: region); + }); + + test('draw oval', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawOval( + const Rect.fromLTRB(100, 125, 200, 175), + Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 3.0 + ..color = const Color(0xFF00FFFF) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('ui_canvas_draw_oval.png', region: region); + }); +} diff --git a/lib/web_ui/test/ui/fragment_shader_test.dart b/lib/web_ui/test/ui/fragment_shader_test.dart new file mode 100644 index 0000000000000..1fef73e8e0f55 --- /dev/null +++ b/lib/web_ui/test/ui/fragment_shader_test.dart @@ -0,0 +1,72 @@ +// 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. + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; +import 'package:web_engine_tester/golden_tester.dart'; + +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +// This fragment shader generates some voronoi noise. It uses a pseudo-random +// number generator implemented in the shader itself, so its output is +// deterministic. +const String kVoronoiShaderSksl = r''' +{ + "sksl": "// This SkSL shader is autogenerated by spirv-cross.\n\nfloat4 flutter_FragCoord;\n\nuniform float uTileSize;\n\nvec4 fragColor;\n\nvec2 FLT_flutter_local_FlutterFragCoord()\n{\n return flutter_FragCoord.xy;\n}\n\nfloat FLT_flutter_local_rand(vec2 co)\n{\n return fract(sin(dot(co, vec2(12.98980045318603515625, 78.233001708984375))) * 43758.546875);\n}\n\nvec2 FLT_flutter_local_fuzzGridPoint(vec2 coordinate)\n{\n vec2 param = coordinate * 400.0;\n vec2 param_1 = coordinate * 400.0;\n return coordinate + vec2((FLT_flutter_local_rand(param) - 0.5) * 0.800000011920928955078125, (FLT_flutter_local_rand(param_1) - 0.5) * 0.800000011920928955078125);\n}\n\nvec3 FLT_flutter_local_getColorForGridPoint(vec2 coordinate)\n{\n vec2 param = coordinate * 100.0;\n vec2 param_1 = coordinate * 200.0;\n vec2 param_2 = coordinate * 300.0;\n return vec3(FLT_flutter_local_rand(param), FLT_flutter_local_rand(param_1), FLT_flutter_local_rand(param_2));\n}\n\nvoid FLT_main()\n{\n vec2 uv = FLT_flutter_local_FlutterFragCoord() / vec2(uTileSize);\n vec2 upperLeft = floor(uv);\n vec2 upperRight = vec2(ceil(uv.x), floor(uv.y));\n vec2 bottomLeft = vec2(floor(uv.x), ceil(uv.y));\n vec2 bottomRight = ceil(uv);\n vec2 closestPoint = upperLeft;\n vec2 param_3 = upperLeft;\n float dist = distance(uv, FLT_flutter_local_fuzzGridPoint(param_3));\n vec2 param_4 = upperRight;\n float upperRightDistance = distance(uv, FLT_flutter_local_fuzzGridPoint(param_4));\n if (upperRightDistance < dist)\n {\n dist = upperRightDistance;\n closestPoint = upperRight;\n }\n vec2 param_5 = bottomLeft;\n float bottomLeftDistance = distance(uv, FLT_flutter_local_fuzzGridPoint(param_5));\n if (bottomLeftDistance < dist)\n {\n dist = bottomLeftDistance;\n closestPoint = bottomLeft;\n }\n vec2 param_6 = bottomRight;\n float bottomRightDistance = distance(uv, FLT_flutter_local_fuzzGridPoint(param_6));\n if (bottomRightDistance < dist)\n {\n dist = bottomRightDistance;\n closestPoint = bottomRight;\n }\n vec2 param_7 = closestPoint;\n fragColor = vec4(FLT_flutter_local_getColorForGridPoint(param_7), 1.0);\n}\n\nhalf4 main(float2 iFragCoord)\n{\n flutter_FragCoord = float4(iFragCoord, 0, 0);\n FLT_main();\n return fragColor;\n}\n", + "stage": 1, + "target_platform": 2, + "uniforms": [ + { + "array_elements": 0, + "bit_width": 32, + "columns": 1, + "location": 0, + "name": "uTileSize", + "rows": 1, + "type": 10 + } + ] +} +'''; + +Future testMain() async { + setUpUiTest(); + + const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); + + test('fragment shader', () async { + fakeAssetManager.setAsset( + 'voronoi_shader', + Uint8List.fromList(utf8.encode(kVoronoiShaderSksl)).buffer.asByteData() + ); + final ui.FragmentProgram program = await renderer.createFragmentProgram('voronoi_shader'); + final ui.FragmentShader shader = program.fragmentShader(); + + Future drawCircle(String goldenFilename) async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder, region); + canvas.drawCircle(const ui.Offset(150, 150), 100, ui.Paint()..shader = shader); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile(goldenFilename, region: region); + } + + shader.setFloat(0, 10.0); + await drawCircle('fragment_shader_voronoi_tile10px.png'); + + // Make sure we can reuse the shader object with a new uniform value. + shader.setFloat(0, 25.0); + await drawCircle('fragment_shader_voronoi_tile25px.png'); + }, skip: isHtml); // Fragment shaders are not supported by the HTML renderer. +} diff --git a/lib/web_ui/test/ui/gradient_golden_test.dart b/lib/web_ui/test/ui/gradient_golden_test.dart new file mode 100644 index 0000000000000..96ba0f7d7fd20 --- /dev/null +++ b/lib/web_ui/test/ui/gradient_golden_test.dart @@ -0,0 +1,123 @@ +// 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. + +import 'dart:math' as math; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine/browser_detection.dart'; +import 'package:ui/ui.dart'; +import 'package:web_engine_tester/golden_tester.dart'; + +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + setUpUiTest(); + + const Rect region = Rect.fromLTWH(0, 0, 300, 300); + + group('Gradients', () { + test('Using a linear gradient on a paint', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawRect( + const Rect.fromLTRB(50, 50, 250, 250), + Paint() + ..shader = Gradient.linear( + const Offset(50, 50), + const Offset(250, 250), + [ + const Color(0xFFFF0000), + const Color(0xFF00FF00), + const Color(0xFF0000FF), + ], + [0.0, 0.5, 1.0], + ) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('linear_gradient_paint.png', region: region); + }); + + test('Using a radial gradient on a paint', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawRect( + const Rect.fromLTRB(50, 50, 250, 250), + Paint() + ..shader = Gradient.radial( + const Offset(150, 150), + 100, + [ + const Color(0xFFFF0000), + const Color(0xFF00FF00), + const Color(0xFF0000FF), + ], + [0.0, 0.5, 1.0], + ) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('radial_gradient_paint.png', region: region); + }); + + test('Using a conical gradient on a paint', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawRect( + const Rect.fromLTRB(50, 50, 250, 250), + Paint() + ..shader = Gradient.radial( + const Offset(200, 200), + 100, + [ + const Color(0xFFFF0000), + const Color(0xFF00FF00), + const Color(0xFF0000FF), + ], + [0.0, 0.5, 1.0], + TileMode.clamp, + null, + const Offset(50, 50), + 5, + ) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('conical_gradient_paint.png', region: region); + }); + + test('Using a sweep gradient on a paint', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder, region); + canvas.drawRect( + const Rect.fromLTRB(50, 50, 250, 250), + Paint() + ..shader = Gradient.sweep( + const Offset(150, 150), + [ + const Color(0xFFFF0000), + const Color(0xFF00FF00), + const Color(0xFF0000FF), + ], + [0.0, 0.5, 1.0], + TileMode.clamp, + math.pi / 3.0, + 4.0 * math.pi / 3.0, + ) + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('sweep_gradient_paint.png', region: region); + }); + }, skip: isFirefox && isHtml); // https://github.com/flutter/flutter/issues/86623 +} diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index c9969072a3ca4..18bb6a4ab7076 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -142,6 +142,47 @@ Future testMain() async { await awaitNextFrame(); await matchGoldenFile('scene_builder_opacity_circles_on_square.png', region: region); }); + + test('shader mask layer', () async { + final ui.SceneBuilder sceneBuilder = ui.SceneBuilder(); + + sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) { + final ui.Paint paint = ui.Paint()..color = const ui.Color(0xFFFF0000); + canvas.drawCircle( + const ui.Offset(125, 150), + 50, + paint + ); + canvas.drawCircle( + const ui.Offset(175, 150), + 50, + paint + ); + })); + + final ui.Shader shader = ui.Gradient.linear( + ui.Offset.zero, + const ui.Offset(50, 50), [ + const ui.Color(0xFFFFFFFF), + const ui.Color(0x00000000), + ]); + sceneBuilder.pushShaderMask( + shader, + const ui.Rect.fromLTRB(125, 125, 175, 175), + ui.BlendMode.srcATop + ); + + sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) { + canvas.drawRect( + ui.Rect.fromCircle(center: const ui.Offset(150, 150), radius: 50), + ui.Paint()..color = const ui.Color(0xFF00FF00) + ); + })); + + await renderer.renderScene(sceneBuilder.build()); + await awaitNextFrame(); + await matchGoldenFile('scene_builder_shader_mask.png', region: region); + }, skip: isFirefox && isHtml); // https://github.com/flutter/flutter/issues/86623 }); } diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index a97935837f9c6..01b42125383bb 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -4,20 +4,53 @@ import 'dart:async'; import 'dart:js_interop'; +import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; +class FakeAssetManager implements AssetManager { + FakeAssetManager(this._parent); + + @override + String get assetsDir => 'assets'; + + @override + String getAssetUrl(String asset) => asset; + + @override + Future load(String assetKey) async { + final ByteData? data = _assetMap[assetKey]; + if (data == null) { + return _parent.load(assetKey); + } + return data; + } + + @override + Future loadAsset(String asset) { + return _parent.loadAsset(asset); + } + + void setAsset(String assetKey, ByteData assetData) { + _assetMap[assetKey] = assetData; + } + + final Map _assetMap = {}; + final AssetManager _parent; +} + +FakeAssetManager fakeAssetManager = FakeAssetManager(WebOnlyMockAssetManager()); + /// Initializes the renderer for this test. void setUpUiTest() { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); + await initializeEngine(assetManager: fakeAssetManager); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); - }); } diff --git a/shell/common/input_events_unittests.cc b/shell/common/input_events_unittests.cc index d9d1e52618788..3f117c006c65f 100644 --- a/shell/common/input_events_unittests.cc +++ b/shell/common/input_events_unittests.cc @@ -176,8 +176,6 @@ void CreateSimulatedPointerData(PointerData& data, data.platformData = 0; data.scroll_delta_x = 0.0; data.scroll_delta_y = 0.0; - data.preferred_auxiliary_stylus_action = - PointerData::PreferredStylusAuxiliaryAction::kIgnore; } TEST_F(ShellTest, MissAtMostOneFrameForIrregularInputEvents) { diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index ea36686e7c8b7..b3db5df1eb99b 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -66,7 +66,6 @@ public class AndroidTouchProcessor { PointerSignalKind.SCROLL, PointerSignalKind.SCROLL_INERTIA_CANCEL, PointerSignalKind.SCALE, - PointerSignalKind.STYLUS_AUXILIARY_ACTION, PointerSignalKind.UNKNOWN }) public @interface PointerSignalKind { @@ -74,28 +73,11 @@ public class AndroidTouchProcessor { int SCROLL = 1; int SCROLL_INERTIA_CANCEL = 2; int SCALE = 3; - int STYLUS_AUXILIARY_ACTION = 4; - int UNKNOWN = 5; - } - - // Must match the PointerPreferredStylusAuxiliaryAction enum in pointer.dart. - @IntDef({ - PointerPreferredStylusAuxiliaryAction.IGNORE, - PointerPreferredStylusAuxiliaryAction.SHOW_COLOR_PALETTE, - PointerPreferredStylusAuxiliaryAction.SWITCH_ERASER, - PointerPreferredStylusAuxiliaryAction.SWITCH_PREVIOUS, - PointerPreferredStylusAuxiliaryAction.UNKNOWN - }) - public @interface PointerPreferredStylusAuxiliaryAction { - int IGNORE = 0; - int SHOW_COLOR_PALETTE = 1; - int SWITCH_ERASER = 2; - int SWITCH_PREVIOUS = 3; int UNKNOWN = 4; } // Must match the unpacking code in hooks.dart. - private static final int POINTER_DATA_FIELD_COUNT = 36; + private static final int POINTER_DATA_FIELD_COUNT = 35; @VisibleForTesting static final int BYTES_PER_FIELD = 8; // This value must match the value in framework's platform_view.dart. @@ -373,8 +355,6 @@ private void addPointerForIndex( packet.putDouble(1.0); // scale packet.putDouble(0.0); // rotation - packet.putLong(PointerPreferredStylusAuxiliaryAction.IGNORE); // preferred stylus action - if (isTrackpadPan && getPointerChangeForPanZoom(pointerChange) == PointerChange.PAN_ZOOM_END) { ongoingPans.remove(event.getPointerId(pointerIndex)); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index fcf9989762a5e..5f628675f87e8 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -56,9 +56,7 @@ // This is left a FlutterBinaryMessenger privately for now to give people a chance to notice the // change. Unfortunately unless you have Werror turned on, incompatible pointers as arguments are // just a warning. -@interface FlutterViewController () +@interface FlutterViewController () @property(nonatomic, readwrite, getter=isDisplayingFlutterUI) BOOL displayingFlutterUI; @property(nonatomic, assign) BOOL isHomeIndicatorHidden; @property(nonatomic, assign) BOOL isPresentingViewControllerAnimating; @@ -99,7 +97,7 @@ @interface FlutterViewController () (1); - packet->SetPointerData(/*index=*/0, pointer_data); - [_engine.get() dispatchPointerDataPacket:std::move(packet)]; -} - -- (flutter::PointerData)createAuxillaryStylusActionData API_AVAILABLE(ios(13.4)) { - flutter::PointerData pointer_data; - pointer_data.Clear(); - - switch (UIPencilInteraction.preferredTapAction) { - case UIPencilPreferredActionIgnore: - pointer_data.preferred_auxiliary_stylus_action = - flutter::PointerData::PreferredStylusAuxiliaryAction::kIgnore; - break; - case UIPencilPreferredActionShowColorPalette: - pointer_data.preferred_auxiliary_stylus_action = - flutter::PointerData::PreferredStylusAuxiliaryAction::kShowColorPalette; - break; - case UIPencilPreferredActionSwitchEraser: - pointer_data.preferred_auxiliary_stylus_action = - flutter::PointerData::PreferredStylusAuxiliaryAction::kSwitchEraser; - break; - case UIPencilPreferredActionSwitchPrevious: - pointer_data.preferred_auxiliary_stylus_action = - flutter::PointerData::PreferredStylusAuxiliaryAction::kSwitchPrevious; - break; - default: - pointer_data.preferred_auxiliary_stylus_action = - flutter::PointerData::PreferredStylusAuxiliaryAction::kUnknown; - break; - } - - pointer_data.time_stamp = [[NSProcessInfo processInfo] systemUptime] * kMicrosecondsPerSecond; - pointer_data.kind = flutter::PointerData::DeviceKind::kStylus; - pointer_data.signal_kind = flutter::PointerData::SignalKind::kStylusAuxiliaryAction; - - return pointer_data; -} - #pragma mark - Handle view resizing - (void)updateViewportMetrics { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index 4a5d6fd6176a9..594a264ddbe6c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -112,8 +112,7 @@ @interface FlutterEmbedderKeyResponder (Tests) @property(nonatomic, copy, readonly) FlutterSendKeyEvent sendEvent; @end -@interface FlutterViewController (Tests) -; +@interface FlutterViewController (Tests) @property(nonatomic, assign) double targetViewInsetBottom; @property(nonatomic, assign) BOOL isKeyboardInOrTransitioningFromBackground; @@ -125,7 +124,6 @@ - (void)performOrientationUpdate:(UIInterfaceOrientationMask)new_preferences; - (void)handlePressEvent:(FlutterUIPressProxy*)press nextAction:(void (^)())next API_AVAILABLE(ios(13.4)); - (void)discreteScrollEvent:(UIPanGestureRecognizer*)recognizer; -- (flutter::PointerData)createAuxillaryStylusActionData; - (void)updateViewportMetrics; - (void)onUserSettingsChanged:(NSNotification*)notification; - (void)applicationWillTerminate:(NSNotification*)notification; @@ -1483,6 +1481,11 @@ - (void)sendMessage:(id _Nullable)message reply:(FlutterReply _Nullable)callback } - (void)testValidKeyUpEvent API_AVAILABLE(ios(13.4)) { + if (@available(iOS 13.4, *)) { + // noop + } else { + return; + } FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init]; mockEngine.keyEventChannel = OCMClassMock([FlutterBasicMessageChannel class]); OCMStub([mockEngine.keyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]]) @@ -1513,6 +1516,12 @@ - (void)testValidKeyUpEvent API_AVAILABLE(ios(13.4)) { } - (void)testValidKeyDownEvent API_AVAILABLE(ios(13.4)) { + if (@available(iOS 13.4, *)) { + // noop + } else { + return; + } + FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init]; mockEngine.keyEventChannel = OCMClassMock([FlutterBasicMessageChannel class]); OCMStub([mockEngine.keyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]]) @@ -1544,6 +1553,11 @@ - (void)testValidKeyDownEvent API_AVAILABLE(ios(13.4)) { } - (void)testIgnoredKeyEvents API_AVAILABLE(ios(13.4)) { + if (@available(iOS 13.4, *)) { + // noop + } else { + return; + } id keyEventChannel = OCMClassMock([FlutterBasicMessageChannel class]); OCMStub([keyEventChannel sendMessage:[OCMArg any] reply:[OCMArg any]]) .andCall(self, @selector(sendMessage:reply:)); @@ -1577,6 +1591,12 @@ - (void)testIgnoredKeyEvents API_AVAILABLE(ios(13.4)) { } - (void)testPanGestureRecognizer API_AVAILABLE(ios(13.4)) { + if (@available(iOS 13.4, *)) { + // noop + } else { + return; + } + FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; @@ -1597,6 +1617,12 @@ - (void)testPanGestureRecognizer API_AVAILABLE(ios(13.4)) { } - (void)testMouseSupport API_AVAILABLE(ios(13.4)) { + if (@available(iOS 13.4, *)) { + // noop + } else { + return; + } + FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil]; @@ -1611,80 +1637,6 @@ - (void)testMouseSupport API_AVAILABLE(ios(13.4)) { dispatchPointerDataPacket:std::make_unique(0)]; } -- (void)testPencilSupport API_AVAILABLE(ios(13.4)) { - FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine - nibName:nil - bundle:nil]; - XCTAssertNotNil(vc); - - id mockPencilInteraction = OCMClassMock([UIPencilInteraction class]); - - OCMStub([mockPencilInteraction preferredTapAction]) - .andReturn(UIPencilPreferredActionShowColorPalette); - - // Check that the helper function is being called - FlutterViewController* viewControllerMock = OCMPartialMock(vc); - [viewControllerMock pencilInteractionDidTap:mockPencilInteraction]; - OCMVerify([viewControllerMock createAuxillaryStylusActionData]); - - [mockPencilInteraction stopMocking]; -} - -- (void)testCreateAuxillaryStylusActionData API_AVAILABLE(ios(13.4)) { - FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine - nibName:nil - bundle:nil]; - XCTAssertNotNil(vc); - - id mockPencilInteraction = OCMClassMock([UIPencilInteraction class]); - - OCMExpect([mockPencilInteraction preferredTapAction]) - .andReturn(UIPencilPreferredActionShowColorPalette); - - // Check the return value of the helper function - flutter::PointerData pointer_data = [vc createAuxillaryStylusActionData]; - - XCTAssertEqual(pointer_data.kind, flutter::PointerData::DeviceKind::kStylus); - XCTAssertEqual(pointer_data.signal_kind, - flutter::PointerData::SignalKind::kStylusAuxiliaryAction); - XCTAssertEqual(pointer_data.preferred_auxiliary_stylus_action, - flutter::PointerData::PreferredStylusAuxiliaryAction::kShowColorPalette); - - OCMExpect([mockPencilInteraction preferredTapAction]) - .andReturn(UIPencilPreferredActionSwitchEraser); - - pointer_data = [vc createAuxillaryStylusActionData]; - - XCTAssertEqual(pointer_data.kind, flutter::PointerData::DeviceKind::kStylus); - XCTAssertEqual(pointer_data.signal_kind, - flutter::PointerData::SignalKind::kStylusAuxiliaryAction); - XCTAssertEqual(pointer_data.preferred_auxiliary_stylus_action, - flutter::PointerData::PreferredStylusAuxiliaryAction::kSwitchEraser); - - OCMExpect([mockPencilInteraction preferredTapAction]) - .andReturn(UIPencilPreferredActionSwitchPrevious); - - pointer_data = [vc createAuxillaryStylusActionData]; - - XCTAssertEqual(pointer_data.kind, flutter::PointerData::DeviceKind::kStylus); - XCTAssertEqual(pointer_data.signal_kind, - flutter::PointerData::SignalKind::kStylusAuxiliaryAction); - XCTAssertEqual(pointer_data.preferred_auxiliary_stylus_action, - flutter::PointerData::PreferredStylusAuxiliaryAction::kSwitchPrevious); - - OCMExpect([mockPencilInteraction preferredTapAction]).andReturn(UIPencilPreferredActionIgnore); - - pointer_data = [vc createAuxillaryStylusActionData]; - - XCTAssertEqual(pointer_data.kind, flutter::PointerData::DeviceKind::kStylus); - XCTAssertEqual(pointer_data.signal_kind, - flutter::PointerData::SignalKind::kStylusAuxiliaryAction); - XCTAssertEqual(pointer_data.preferred_auxiliary_stylus_action, - flutter::PointerData::PreferredStylusAuxiliaryAction::kIgnore); - - [mockPencilInteraction stopMocking]; -} - - (void)testFakeEventTimeStamp { FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index e1c74cf041d08..6e59644216064 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2152,8 +2152,6 @@ inline flutter::PointerData::SignalKind ToPointerDataSignalKind( return flutter::PointerData::SignalKind::kScrollInertiaCancel; case kFlutterPointerSignalKindScale: return flutter::PointerData::SignalKind::kScale; - case kFlutterPointerSignalKindStylusAuxiliaryAction: - return flutter::PointerData::SignalKind::kStylusAuxiliaryAction; } return flutter::PointerData::SignalKind::kNone; } diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 5cdba06ef505d..1710299f6555d 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -896,7 +896,6 @@ typedef enum { kFlutterPointerSignalKindScroll, kFlutterPointerSignalKindScrollInertiaCancel, kFlutterPointerSignalKindScale, - kFlutterPointerSignalKindStylusAuxiliaryAction, } FlutterPointerSignalKind; typedef struct { diff --git a/shell/platform/fuchsia/flutter/component_v2.cc b/shell/platform/fuchsia/flutter/component_v2.cc index 9893de69e1765..3ad4169869ad4 100644 --- a/shell/platform/fuchsia/flutter/component_v2.cc +++ b/shell/platform/fuchsia/flutter/component_v2.cc @@ -628,16 +628,6 @@ void ComponentV2::OnEngineTerminate(const Engine* shell_holder) { } } -void ComponentV2::CreateView( - zx::eventpair token, - fidl::InterfaceRequest /*incoming_services*/, - fidl::InterfaceHandle< - fuchsia::sys::ServiceProvider> /*outgoing_services*/) { - auto view_ref_pair = scenic::ViewRefPair::New(); - CreateViewWithViewRef(std::move(token), std::move(view_ref_pair.control_ref), - std::move(view_ref_pair.view_ref)); -} - void ComponentV2::CreateViewWithViewRef( zx::eventpair view_token, fuchsia::ui::views::ViewRefControl control_ref, diff --git a/shell/platform/fuchsia/flutter/component_v2.h b/shell/platform/fuchsia/flutter/component_v2.h index c23f4406ed7fa..57a0aa62cdfe5 100644 --- a/shell/platform/fuchsia/flutter/component_v2.h +++ b/shell/platform/fuchsia/flutter/component_v2.h @@ -110,12 +110,6 @@ class ComponentV2 final // |fuchsia::component::runner::ComponentController| void Stop() override; - // |fuchsia::ui::app::ViewProvider| - void CreateView( - zx::eventpair token, - fidl::InterfaceRequest incoming_services, - fuchsia::sys::ServiceProviderHandle outgoing_services) override; - // |fuchsia::ui::app::ViewProvider| void CreateViewWithViewRef(zx::eventpair view_token, fuchsia::ui::views::ViewRefControl control_ref, diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart index 5fd521661150d..93ab0c585fd57 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart @@ -238,9 +238,13 @@ ViewHolderToken _launchGfxChildView() { final viewTokens = EventPairPair(); assert(viewTokens.status == ZX.OK); final viewHolderToken = ViewHolderToken(value: viewTokens.first); - final viewToken = ViewToken(value: viewTokens.second); - viewProvider.createView(viewToken.value, null, null); + final viewRefs = EventPairPair(); + assert(viewRefs.status == ZX.OK); + final viewRefControl = ViewRefControl(reference: viewRefs.first.duplicate(ZX.DEFAULT_EVENTPAIR_RIGHTS & ~ZX.RIGHT_DUPLICATE)); + final viewRef = ViewRef(reference: viewRefs.second.duplicate(ZX.RIGHTS_BASIC)); + + viewProvider.createViewWithViewRef(viewTokens.second, viewRefControl, viewRef); viewProvider.ctrl.close(); return viewHolderToken; diff --git a/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/lib/embedding-flutter-view.dart b/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/lib/embedding-flutter-view.dart index 7473fbdeebbe9..252ee55342cd2 100644 --- a/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/lib/embedding-flutter-view.dart +++ b/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/lib/embedding-flutter-view.dart @@ -238,9 +238,13 @@ ViewHolderToken _launchGfxChildView() { final viewTokens = EventPairPair(); assert(viewTokens.status == ZX.OK); final viewHolderToken = ViewHolderToken(value: viewTokens.first); - final viewToken = ViewToken(value: viewTokens.second); - viewProvider.createView(viewToken.value, null, null); + final viewRefs = EventPairPair(); + assert(viewRefs.status == ZX.OK); + final viewRefControl = ViewRefControl(reference: viewRefs.first.duplicate(ZX.DEFAULT_EVENTPAIR_RIGHTS & ~ZX.RIGHT_DUPLICATE)); + final viewRef = ViewRef(reference: viewRefs.second.duplicate(ZX.RIGHTS_BASIC)); + + viewProvider.createViewWithViewRef(viewTokens.second, viewRefControl, viewRef); viewProvider.ctrl.close(); return viewHolderToken;