diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart
index 6a27d910916cc..0fe5de1d9df75 100644
--- a/lib/web_ui/lib/src/engine/embedder.dart
+++ b/lib/web_ui/lib/src/engine/embedder.dart
@@ -525,20 +525,15 @@ void applyGlobalCssRulesToSheet(
// TODO(web): use more efficient CSS selectors; descendant selectors are slow.
// More info: https://csswizardry.com/2011/09/writing-efficient-css-selectors
- // This undoes browser's default layout attributes for paragraphs. We
- // compute paragraph layout ourselves.
if (isFirefox) {
// For firefox set line-height, otherwise textx at same font-size will
// measure differently in ruler.
+ //
+ // - See: https://github.com/flutter/flutter/issues/44803
sheet.insertRule(
- 'flt-ruler-host p, flt-scene p '
- '{ margin: 0; line-height: 100%;}',
- sheet.cssRules.length);
- } else {
- sheet.insertRule(
- 'flt-ruler-host p, flt-scene p '
- '{ margin: 0; }',
- sheet.cssRules.length);
+ 'flt-paragraph, flt-span {line-height: 100%;}',
+ sheet.cssRules.length,
+ );
}
// This undoes browser's default painting and layout attributes of range
diff --git a/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart b/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart
index 9d86fd49dda1d..b291549ecb3c5 100644
--- a/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart
+++ b/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart
@@ -9,7 +9,6 @@ import 'package:ui/ui.dart' as ui;
import '../embedder.dart';
import '../html/bitmap_canvas.dart';
import '../profiler.dart';
-import '../util.dart';
import 'layout_service.dart';
import 'paint_service.dart';
import 'paragraph.dart';
@@ -148,11 +147,10 @@ class CanvasParagraph implements ui.Paragraph {
html.HtmlElement _createDomElement() {
final html.HtmlElement rootElement =
- html.document.createElement('p') as html.HtmlElement;
+ html.document.createElement('flt-paragraph') as html.HtmlElement;
// 1. Set paragraph-level styles.
- _applyNecessaryParagraphStyles(element: rootElement, style: paragraphStyle);
- _applySpanStylesToParagraph(element: rootElement, spans: spans);
+
final html.CssStyleDeclaration cssStyle = rootElement.style;
cssStyle
..position = 'absolute'
@@ -175,7 +173,7 @@ class CanvasParagraph implements ui.Paragraph {
final RangeBox box = boxes[j++];
if (box is SpanBox) {
- lastSpanElement = html.document.createElement('span') as html.HtmlElement;
+ lastSpanElement = html.document.createElement('flt-span') as html.HtmlElement;
applyTextStyleToElement(
element: lastSpanElement,
style: box.span.style,
@@ -253,67 +251,6 @@ class CanvasParagraph implements ui.Paragraph {
}
}
-/// Applies a paragraph [style] to an [element], translating the properties to
-/// their corresponding CSS equivalents.
-///
-/// As opposed to [_applyParagraphStyleToElement], this method only applies
-/// styles that are necessary at the paragraph level. Other styles (e.g. font
-/// size) are always applied at the span level so they aren't needed at the
-/// paragraph level.
-void _applyNecessaryParagraphStyles({
- required html.HtmlElement element,
- required EngineParagraphStyle style,
-}) {
- final html.CssStyleDeclaration cssStyle = element.style;
-
- // TODO(mdebbar): Now that we absolutely position each span inside the
- // paragraph, do we still need these style on
?
-
- if (style.textAlign != null) {
- cssStyle.textAlign = textAlignToCssValue(
- style.textAlign, style.textDirection ?? ui.TextDirection.ltr);
- }
- if (style.lineHeight != null) {
- cssStyle.lineHeight = '${style.lineHeight}';
- }
- if (style.textDirection != null) {
- cssStyle.direction = textDirectionToCss(style.textDirection);
- }
-}
-
-/// Applies some span-level style to a paragraph [element].
-///
-/// For example, it looks for the greatest font size among spans, and applies it
-/// to the paragraph. While this seems to have no effect, it prevents the
-/// paragraph from inheriting its font size from the body tag, which leads to
-/// incorrect vertical alignment of spans.
-void _applySpanStylesToParagraph({
- required html.HtmlElement element,
- required List spans,
-}) {
- double fontSize = 0.0;
- String? fontFamily;
- for (final ParagraphSpan span in spans) {
- if (span is FlatTextSpan) {
- final double? spanFontSize = span.style.fontSize;
- if (spanFontSize != null && spanFontSize > fontSize) {
- fontSize = spanFontSize;
- if (span.style.isFontFamilyProvided) {
- fontFamily = span.style.effectiveFontFamily;
- }
- }
- }
- }
-
- final html.CssStyleDeclaration cssStyle = element.style;
- if (fontSize != 0.0) {
- cssStyle.fontSize = '${fontSize}px';
- }
- if (fontFamily != null) {
- cssStyle.fontFamily = canonicalizeFontFamily(fontFamily);
- }
-}
-
void _positionSpanElement(html.Element element, EngineLineMetrics line, RangeBox box) {
final ui.Rect boxRect = box.toTextBox(line, forPainting: true).toRect();
element.style
diff --git a/lib/web_ui/lib/src/engine/text/paragraph.dart b/lib/web_ui/lib/src/engine/text/paragraph.dart
index 590e126603e43..0c34403a48c11 100644
--- a/lib/web_ui/lib/src/engine/text/paragraph.dart
+++ b/lib/web_ui/lib/src/engine/text/paragraph.dart
@@ -759,51 +759,6 @@ void applyTextStyleToElement({
}
}
-html.Element createPlaceholderElement({
- required ParagraphPlaceholder placeholder,
-}) {
- final html.Element element = html.document.createElement('span');
- final html.CssStyleDeclaration style = element.style;
- style
- ..display = 'inline-block'
- ..width = '${placeholder.width}px'
- ..height = '${placeholder.height}px'
- ..verticalAlign = _placeholderAlignmentToCssVerticalAlign(placeholder);
-
- return element;
-}
-
-String _placeholderAlignmentToCssVerticalAlign(
- ParagraphPlaceholder placeholder,
-) {
- // For more details about the vertical-align CSS property, see:
- // - https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
- switch (placeholder.alignment) {
- case ui.PlaceholderAlignment.top:
- return 'top';
-
- case ui.PlaceholderAlignment.middle:
- return 'middle';
-
- case ui.PlaceholderAlignment.bottom:
- return 'bottom';
-
- case ui.PlaceholderAlignment.aboveBaseline:
- return 'baseline';
-
- case ui.PlaceholderAlignment.belowBaseline:
- return '-${placeholder.height}px';
-
- case ui.PlaceholderAlignment.baseline:
- // In CSS, the placeholder is already placed above the baseline. But
- // Flutter's `baselineOffset` assumes the placeholder is placed below the
- // baseline. That's why we need to subtract the placeholder's height from
- // `baselineOffset`.
- final double offset = placeholder.baselineOffset - placeholder.height;
- return '${offset}px';
- }
-}
-
String _shadowListToCss(List shadows) {
if (shadows.isEmpty) {
return '';
@@ -881,37 +836,6 @@ String? _decorationStyleToCssString(ui.TextDecorationStyle decorationStyle) {
}
}
-/// Converts [textDirection] to its corresponding CSS value.
-///
-/// This value is used for the "direction" CSS property, e.g.:
-///
-/// ```css
-/// direction: rtl;
-/// ```
-String? textDirectionToCss(ui.TextDirection? textDirection) {
- if (textDirection == null) {
- return null;
- }
- return textDirectionIndexToCss(textDirection.index);
-}
-
-String? textDirectionIndexToCss(int textDirectionIndex) {
- switch (textDirectionIndex) {
- case 0:
- return 'rtl';
- case 1:
- return null; // ltr is the default
- }
-
- assert(() {
- throw AssertionError(
- 'Failed to convert text direction $textDirectionIndex to CSS',
- );
- }());
-
- return null;
-}
-
/// Converts [align] to its corresponding CSS value.
///
/// This value is used as the "text-align" CSS property, e.g.:
diff --git a/lib/web_ui/lib/src/engine/text/ruler.dart b/lib/web_ui/lib/src/engine/text/ruler.dart
index 1bb267b91c80b..fac90ef52b20a 100644
--- a/lib/web_ui/lib/src/engine/text/ruler.dart
+++ b/lib/web_ui/lib/src/engine/text/ruler.dart
@@ -95,7 +95,7 @@ class TextHeightStyle {
class TextDimensions {
TextDimensions(this._element);
- final html.HtmlElement _element;
+ final html.Element _element;
html.Rectangle? _cachedBoundingClientRect;
void _invalidateBoundsCache() {
@@ -165,7 +165,7 @@ class TextHeightRuler {
// Elements used to measure the line-height metric.
late final html.HtmlElement _probe = _createProbe();
late final html.HtmlElement _host = _createHost();
- final TextDimensions _dimensions = TextDimensions(html.ParagraphElement());
+ final TextDimensions _dimensions = TextDimensions(html.document.createElement('flt-paragraph'));
/// The alphabetic baseline for this ruler's [textHeightStyle].
late final double alphabeticBaseline = _probe.getBoundingClientRect().bottom.toDouble();
diff --git a/lib/web_ui/test/engine/host_node_test.dart b/lib/web_ui/test/engine/host_node_test.dart
index a2364c86d01df..0d18398dd8a9b 100644
--- a/lib/web_ui/test/engine/host_node_test.dart
+++ b/lib/web_ui/test/engine/host_node_test.dart
@@ -66,7 +66,7 @@ void _runDomTests(HostNode hostNode) {
hostNode.nodes.addAll([
html.document.createElement('div'),
target,
- html.document.createElement('span'),
+ html.document.createElement('flt-span'),
html.document.createElement('div'),
]);
});
diff --git a/lib/web_ui/test/engine/surface/scene_builder_test.dart b/lib/web_ui/test/engine/surface/scene_builder_test.dart
index b6a1d1569c264..7e230cf8b1840 100644
--- a/lib/web_ui/test/engine/surface/scene_builder_test.dart
+++ b/lib/web_ui/test/engine/surface/scene_builder_test.dart
@@ -513,10 +513,10 @@ void testMain() {
renderedLayers[char] = pushChild(builder, char, oldLayer: renderedLayers[char]);
}
final SurfaceScene scene = builder.build();
- final List pTags = scene.webOnlyRootElement!.querySelectorAll('p');
+ final List pTags = scene.webOnlyRootElement!.querySelectorAll('flt-paragraph');
expect(pTags, hasLength(string.length));
expect(
- scene.webOnlyRootElement!.querySelectorAll('p').map((html.Element p) => p.innerText).join(''),
+ scene.webOnlyRootElement!.querySelectorAll('flt-paragraph').map((html.Element p) => p.innerText).join(''),
string,
);
renderedLayers.removeWhere((String key, ui.EngineLayer value) => !string.contains(key));
diff --git a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart
index 5e339c8615274..a4b2f2af8eb4e 100644
--- a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart
+++ b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart
@@ -171,7 +171,7 @@ Future testMain() async {
canvas.drawParagraph(paragraph, Offset(8.5, 8.5 + innerClip.top));
expect(
- canvas.rootElement.querySelectorAll('p').map((html.Element e) => e.innerText).toList(),
+ canvas.rootElement.querySelectorAll('flt-paragraph').map((html.Element e) => e.innerText).toList(),
['Am I blurry?', 'Am I blurry?'],
reason: 'Expected to render text using HTML',
);
@@ -229,7 +229,7 @@ Future testMain() async {
canvas.drawParagraph(paragraph, const Offset(180, 50));
expect(
- canvas.rootElement.querySelectorAll('p').map((html.Element e) => e.text).toList(),
+ canvas.rootElement.querySelectorAll('flt-paragraph').map((html.Element e) => e.text).toList(),
[text],
reason: 'Expected to render text using HTML',
);
diff --git a/lib/web_ui/test/html/compositing/compositing_golden_test.dart b/lib/web_ui/test/html/compositing/compositing_golden_test.dart
index 4cfb4f4c2be13..d6339cd919b5d 100644
--- a/lib/web_ui/test/html/compositing/compositing_golden_test.dart
+++ b/lib/web_ui/test/html/compositing/compositing_golden_test.dart
@@ -872,7 +872,7 @@ void _testCullRectComputation() {
final html.Element sceneElement = builder.build().webOnlyRootElement!;
expect(
sceneElement
- .querySelectorAll('p')
+ .querySelectorAll('flt-paragraph')
.map((html.Element e) => e.innerText)
.toList(),
['Am I blurry?', 'Am I blurry?'],
diff --git a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/text/canvas_paragraph_builder_test.dart
index bd7a526d4125e..82536da04349d 100644
--- a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart
+++ b/lib/web_ui/test/text/canvas_paragraph_builder_test.dart
@@ -50,11 +50,11 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -62,14 +62,14 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: 39.0));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hel'
- ''
- ''
+ ''
+ ''
'lo'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -94,11 +94,11 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expect(
paragraph.toDomElement().outerHtml,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- '
',
+ ''
+ '',
);
final FlatTextSpan textSpan = paragraph.spans.single as FlatTextSpan;
@@ -118,11 +118,11 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expect(
paragraph.toDomElement().outerHtml,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- '
',
+ ''
+ '',
);
});
@@ -139,11 +139,11 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: 100.0));
expect(
paragraph.toDomElement().outerHtml,
- ''
- ''
+ ''
+ ''
'Hell...'
- ''
- '
',
+ ''
+ '',
);
});
@@ -167,11 +167,11 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -206,17 +206,17 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'world'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -224,18 +224,17 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: 75.0));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- // Trailing space.
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'world'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -280,20 +279,20 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'Hello'
- ''
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'world'
- ''
- ''
+ ''
+ ''
'!'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -348,20 +347,20 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'First'
- ''
- ''
+ ''
+ ''
'Second'
- ''
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'ThirdLongLine'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
@@ -369,21 +368,21 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: 180.0));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'First'
- ''
- ''
+ ''
+ ''
'Second'
- ''
+ ''
// Trailing space.
- ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'ThirdLongLine'
- ''
- '
',
+ ''
+ '',
ignorePositions: !isBlink,
);
});
@@ -411,23 +410,23 @@ Future testMain() async {
paragraph.layout(const ParagraphConstraints(width: double.infinity));
expectOuterHtml(
paragraph,
- ''
- ''
+ ''
+ ''
'First'
- ''
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'Second'
- ''
- ''
+ ''
+ ''
' '
- ''
- ''
+ ''
+ ''
'Third'
- ''
- '
',
+ ''
+ '',
// Since we are using unknown font families, we can't predict the text
// measurements.
ignorePositions: true,
@@ -439,15 +438,8 @@ Future testMain() async {
const String defaultFontFamily = 'Ahem';
const num defaultFontSize = 14;
-String paragraphStyle({
- String fontFamily = defaultFontFamily,
- num fontSize = defaultFontSize,
- num? lineHeight,
-}) {
+String paragraphStyle() {
return [
- if (lineHeight != null) 'line-height: $lineHeight;',
- 'font-size: ${fontSize}px;',
- 'font-family: ${fontFamilyToAttribute(fontFamily)};',
'position: absolute;',
'white-space: pre;',
].join(' ');
diff --git a/lib/web_ui/test/text_test.dart b/lib/web_ui/test/text_test.dart
index 5f0ff655a465d..2d0b6ade6734c 100644
--- a/lib/web_ui/test/text_test.dart
+++ b/lib/web_ui/test/text_test.dart
@@ -224,8 +224,8 @@ Future testMain() async {
final CanvasParagraph paragraph = builder.build() as CanvasParagraph;
paragraph.layout(const ParagraphConstraints(width: 800.0));
expect(paragraph.plainText, 'abcdef');
- final List spans =
- paragraph.toDomElement().querySelectorAll('span');
+ final List spans =
+ paragraph.toDomElement().querySelectorAll('flt-span');
expect(spans[0].style.fontFamily, 'Ahem, $fallback, sans-serif');
// The nested span here should not set it's family to default sans-serif.
expect(spans[1].style.fontFamily, 'Ahem, $fallback, sans-serif');
@@ -245,7 +245,7 @@ Future testMain() async {
), 'Hello');
paragraph.layout(constrain(double.infinity));
- expect(paragraph.toDomElement().style.fontFamily,
+ expect(paragraph.toDomElement().children.single.style.fontFamily,
'SomeFont, $fallback, sans-serif');
debugEmulateFlutterTesterEnvironment = true;
@@ -265,7 +265,7 @@ Future testMain() async {
), 'Hello');
paragraph.layout(constrain(double.infinity));
- expect(paragraph.toDomElement().style.fontFamily, 'serif');
+ expect(paragraph.toDomElement().children.single.style.fontFamily, 'serif');
debugEmulateFlutterTesterEnvironment = true;
});
@@ -280,7 +280,7 @@ Future testMain() async {
), 'Hello');
paragraph.layout(constrain(double.infinity));
- expect(paragraph.toDomElement().style.fontFamily,
+ expect(paragraph.toDomElement().children.single.style.fontFamily,
'"MyFont 2000", $fallback, sans-serif');
debugEmulateFlutterTesterEnvironment = true;