Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

PoC: SVG canvas #38602

Closed
wants to merge 2 commits into from
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
3 changes: 3 additions & 0 deletions lib/web_ui/lib/src/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export 'engine/html/shaders/shader_builder.dart';
export 'engine/html/shaders/vertex_shaders.dart';
export 'engine/html/surface.dart';
export 'engine/html/surface_stats.dart';
export 'engine/html/svg/svg_canvas.dart';
export 'engine/html/svg/svg_picture.dart';
export 'engine/html/transform.dart';
export 'engine/html_image_codec.dart';
export 'engine/initialization.dart';
Expand Down Expand Up @@ -146,6 +148,7 @@ export 'engine/services/message_codecs.dart';
export 'engine/services/serialization.dart';
export 'engine/shadow.dart';
export 'engine/svg.dart';
export 'engine/svg_filter.dart';
export 'engine/test_embedding.dart';
export 'engine/text/canvas_paragraph.dart';
export 'engine/text/font_collection.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import '../dom.dart';
import '../html/path_to_svg_clip.dart';
import '../platform_views/slots.dart';
import '../svg.dart';
import '../svg_filter.dart';
import '../util.dart';
import '../vector_math.dart';
import '../window.dart';
Expand Down
234 changes: 234 additions & 0 deletions lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,16 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
set transformOrigin(String value) => setProperty('transform-origin', value);
set opacity(String value) => setProperty('opacity', value);
set color(String value) => setProperty('color', value);

// SVG only
set fill(String value) => setProperty('fill', value);
// SVG only
set stroke(String value) => setProperty('stroke', value);

// Skip this: not supported in Safari, use `stroke-width` element attribute instead
// set strokeWidth(String value) => setProperty('strokeWidth', value);

set vectorEffect(String value) => setProperty('vectorEffect', value);
set top(String value) => setProperty('top', value);
set left(String value) => setProperty('left', value);
set right(String value) => setProperty('right', value);
Expand Down Expand Up @@ -381,6 +391,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
set alignContent(String value) => setProperty('align-content', value);
set textAlign(String value) => setProperty('text-align', value);
set font(String value) => setProperty('font', value);
set dominantBaseline(String value) => setProperty('dominant-baseline', value);
String get width => getPropertyValue('width');
String get height => getPropertyValue('height');
String get position => getPropertyValue('position');
Expand All @@ -390,6 +401,16 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
String get transformOrigin => getPropertyValue('transform-origin');
String get opacity => getPropertyValue('opacity');
String get color => getPropertyValue('color');

// SVG only
String get fill => getPropertyValue('fill');
// SVG only
String get stroke => getPropertyValue('stroke');

// Skip this: not supported in Safari
// String get strokeWidth => getPropertyValue('strokeWidth');

String get vectorEffect => getPropertyValue('vectorEffect');
String get top => getPropertyValue('top');
String get left => getPropertyValue('left');
String get right => getPropertyValue('right');
Expand Down Expand Up @@ -445,6 +466,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
String get alignContent => getPropertyValue('align-content');
String get textAlign => getPropertyValue('text-align');
String get font => getPropertyValue('font');
String get dominantBaseline => getPropertyValue('dominant-baseline');

external String getPropertyValue(String property);
void setProperty(String propertyName, String value, [String? priority]) {
Expand Down Expand Up @@ -1740,3 +1762,215 @@ DomV8BreakIterator createV8BreakIterator() {
],
);
}

@JS()
@staticInterop
class DOMPoint {}
extension DOMPointExtension on DOMPoint {
external double get x;
external double get y;
external double get z;
external double get w;
}

@JS()
@anonymous
@staticInterop
class DOMPointInit {
external factory DOMPointInit({
double x = 0,
double y = 0,
double z = 0,
double w = 1,
});
Comment on lines +1780 to +1785
Copy link
Member

@ditman ditman Jan 3, 2023

Choose a reason for hiding this comment

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

I normally don't separate the external factory from the staticInterop class that it creates. I think you should be able to do this:

@JS()
@anonymous
@staticInterop
class DOMPoint {
  external factory DOMPoint({
    double x = 0,
    double y = 0,
    double z = 0,
    double w = 1,
  });
}

extension DOMPointExtension on DOMPoint {
  external double get x;
  external double get y;
  external double get z;
  external double get w;
}

(And then the types of stuff elsewhere can receive a DOMPoint and a DOMMatrix rather than the ...Init versions?)

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 might remove this. I was confused by MDN docs saying that SVGMatrix is deprecated and we must use DOMMatrix, but when I tried using it the browser didn't accept it. So I changed it to SVGMatrix.

}

@JS()
@staticInterop
class DOMMatrixReadOnly {}
extension DOMMatrixReadOnlyExtension on DOMMatrixReadOnly {
external static DOMMatrixReadOnly fromMatrix(DOMMatrixInit other);
external static DOMMatrixReadOnly fromFloat32Array(Float32List array32);
external static DOMMatrixReadOnly fromFloat64Array(Float64List array64);

external double get m11;
external double get m12;
external double get m13;
external double get m14;
external double get m21;
external double get m22;
external double get m23;
external double get m24;
external double get m31;
external double get m32;
external double get m33;
external double get m34;
external double get m41;
external double get m42;
external double get m43;
external double get m44;

external bool get is2D;
external bool get isIdentity;

// Immutable transform methods
external DOMMatrix translate([double tx = 0, double ty = 0, double tz = 0]);

external DOMMatrix scale(
double scaleX,
double scaleY, [
double scaleZ = 1,
double originX = 0,
double originY = 0,
double originZ = 0,
]);

external DOMMatrix scaleNonUniform(
double scaleX,
double scaleY,
);

external DOMMatrix scale3d(
double scale, [
double originX = 0,
double originY = 0,
double originZ = 0,
]);

external DOMMatrix rotate([
double rotX = 0,
double? rotY,
double? rotZ,
]);

external DOMMatrix rotateFromVector([
double x = 0,
double y = 0,
]);

external DOMMatrix rotateAxisAngle([
double x = 0,
double y = 0,
double z = 0,
double angle = 0,
]);

external DOMMatrix skewX([double sx = 0]);
external DOMMatrix skewY([double sy = 0]);
external DOMMatrix multiply([DOMMatrixInit other]);
external DOMMatrix flipX();
external DOMMatrix flipY();
external DOMMatrix inverse();

external DOMPoint transformPoint([DOMPointInit point]);
external Float32List toFloat32Array();
external Float64List toFloat64Array();
}

@JS()
@staticInterop
class DOMMatrix extends DOMMatrixReadOnly {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Not specific to this PR, but can we use this and delete our vector_math.dart implementation? Seems to be widely available in modern browsers, and implements most (all?) of our Matrix4.

extension DOMMatrixExtension on DOMMatrix {
external static DOMMatrix fromMatrix(DOMMatrixInit other);
external static DOMMatrix fromFloat32Array(Float32List array32);
external static DOMMatrix fromFloat64Array(Float64List array64);

external set m11(double value);
external set m12(double value);
external set m13(double value);
external set m14(double value);
external set m21(double value);
external set m22(double value);
external set m23(double value);
external set m24(double value);
external set m31(double value);
external set m32(double value);
external set m33(double value);
external set m34(double value);
external set m41(double value);
external set m42(double value);
external set m43(double value);
external set m44(double value);

// Mutable transform methods
external DOMMatrix multiplySelf(DOMMatrixInit other);
external DOMMatrix preMultiplySelf(DOMMatrixInit other);
external DOMMatrix translateSelf([
double tx = 0,
double ty = 0,
double tz = 0,
]);
external DOMMatrix scaleSelf([
double scaleX = 1,
double scaleY = 1,
double scaleZ = 1,
double originX = 0,
double originY = 0,
double originZ = 0,
]);
external DOMMatrix scale3dSelf([
double scale = 1,
double originX = 0,
double originY = 0,
double originZ = 0,
]);
external DOMMatrix rotateSelf([
double rotX = 0,
double? rotY,
double? rotZ,
]);
external DOMMatrix rotateFromVectorSelf([
double x = 0,
double y = 0,
]);
external DOMMatrix rotateAxisAngleSelf([
double x = 0,
double y = 0,
double z = 0,
double angle = 0,
]);
external DOMMatrix skewXSelf(double sx);
external DOMMatrix skewYSelf(double sy);
external DOMMatrix invertSelf();

external DOMMatrix setMatrixValue(String transformList);
}

@JS()
@anonymous
@staticInterop
class DOMMatrix2DInit {
external factory DOMMatrix2DInit({
required double m11,
required double m12,
required double m21,
required double m22,
required double m41,
required double m42,
});
}

@JS()
@anonymous
@staticInterop
class DOMMatrixInit {
external factory DOMMatrixInit({
required double m11,
required double m12,
required double m21,
required double m22,
required double m41,
required double m42,
double? m13 = 0,
double? m14 = 0,
double? m23 = 0,
double? m24 = 0,
double? m31 = 0,
double? m32 = 0,
double? m33 = 1,
double? m34 = 0,
double? m43 = 0,
double? m44 = 1,
required bool is2D,
});
}
5 changes: 3 additions & 2 deletions lib/web_ui/lib/src/engine/embedder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,9 @@ class FlutterViewEmbedder {
_glassPaneShadow = glassPaneElementHostNode;

// Don't allow the scene to receive pointer events.
_sceneHostElement = domDocument.createElement('flt-scene-host')
..style.pointerEvents = 'none';
_sceneHostElement = domDocument.createElement('flt-scene-host');
// DO_NOT_SUBMIT: revert this before submitting.
Copy link
Member

@ditman ditman Jan 3, 2023

Choose a reason for hiding this comment

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

(Just to make the PR "red" :P)

// ..style.pointerEvents = 'none';
Comment on lines +175 to +176
Copy link
Contributor

Choose a reason for hiding this comment

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

REMINDER TO NOT SUBMIT THIS.

Copy link
Contributor

Choose a reason for hiding this comment

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

fwiw, one trick for this kind of thing is to use // TODO: revert before submitting because then the todo style lint will make the analyzer shard red, preventing you from landing.


renderer.reset(this);

Expand Down
16 changes: 0 additions & 16 deletions lib/web_ui/lib/src/engine/engine_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,6 @@ abstract class EngineCanvas {
void endOfPaint();
}

/// Adds an [offset] transformation to a [transform] matrix and returns the
/// combined result.
///
/// If the given offset is zero, returns [transform] matrix as is. Otherwise,
/// returns a new [Matrix4] object representing the combined transformation.
Matrix4 transformWithOffset(Matrix4 transform, ui.Offset offset) {
if (offset == ui.Offset.zero) {
return transform;
}

// Clone to avoid mutating transform.
final Matrix4 effectiveTransform = transform.clone();
effectiveTransform.translate(offset.dx, offset.dy);
return effectiveTransform;
}

class SaveStackEntry {
SaveStackEntry({
required this.transform,
Expand Down
Loading