diff --git a/lib/web_ui/dev/goldens_lock.yaml b/lib/web_ui/dev/goldens_lock.yaml index 4574022fa25e4..c6d6a25dd35bc 100644 --- a/lib/web_ui/dev/goldens_lock.yaml +++ b/lib/web_ui/dev/goldens_lock.yaml @@ -1,2 +1,2 @@ repository: https://github.com/flutter/goldens.git -revision: 6839c709f859a1abe50e6322dfee17a3a3817c5c +revision: 92381b8ca48729e9b21c6b19dd39ed605a98d4ee 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 670a9b32cec50..5ef684206102c 100644 --- a/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart +++ b/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart @@ -133,7 +133,7 @@ class CanvasParagraph implements EngineParagraph { domRenderer.createElement('p') as html.HtmlElement; // 1. Set paragraph-level styles. - _applyParagraphStyleToElement(element: rootElement, style: paragraphStyle); + _applyNecessaryParagraphStyles(element: rootElement, style: paragraphStyle); final html.CssStyleDeclaration cssStyle = rootElement.style; cssStyle ..position = 'absolute' @@ -259,6 +259,31 @@ class CanvasParagraph implements EngineParagraph { } } +/// 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; + + 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); + } +} + /// A common interface for all types of spans that make up a paragraph. /// /// These spans are stored as a flat list in the paragraph object. diff --git a/lib/web_ui/test/golden_tests/engine/canvas_draw_image_golden_test.dart b/lib/web_ui/test/golden_tests/engine/canvas_draw_image_golden_test.dart index 4aa6ef99cbb18..2137367a03dd5 100644 --- a/lib/web_ui/test/golden_tests/engine/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/golden_tests/engine/canvas_draw_image_golden_test.dart @@ -334,15 +334,18 @@ void testMain() async { // Yellow text should be behind image and rectangle. // Cyan text should be above everything. test('Paints text above and below image', () async { + // Use a non-Ahem font so that text is visible. + debugEmulateFlutterTesterEnvironment = false; final RecordingCanvas rc = RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300)); rc.save(); Image testImage = createTestImage(); double testWidth = testImage.width.toDouble(); double testHeight = testImage.height.toDouble(); + final Color orange = Color(0xFFFF9800); final Paragraph paragraph1 = createTestParagraph( - 'should be below...............', - color: Color(0xFFFFFF40)); + 'Should be below below below below below', + color: orange); paragraph1.layout(const ParagraphConstraints(width: 400.0)); rc.drawParagraph(paragraph1, const Offset(20, 100)); rc.drawImageRect(testImage, Rect.fromLTRB(0, 0, testWidth, testHeight), @@ -352,14 +355,19 @@ void testMain() async { Paint() ..strokeWidth = 3 ..color = Color(0xA0000000)); + final Color cyan = Color(0xFF0097A7); final Paragraph paragraph2 = createTestParagraph( - 'Should be above...............', - color: Color(0xFF00FFFF)); + 'Should be above above above above above', + color: cyan); paragraph2.layout(const ParagraphConstraints(width: 400.0)); rc.drawParagraph(paragraph2, const Offset(20, 150)); rc.restore(); - await _checkScreenshot(rc, 'draw_text_composite_order_below', - maxDiffRatePercent: 1.0); + await _checkScreenshot( + rc, + 'draw_text_composite_order_below', + maxDiffRatePercent: 1.0, + region: Rect.fromLTWH(0, 0, 350, 300), + ); }); // Creates a picture @@ -723,7 +731,7 @@ HtmlImage createTestImage({int width = 100, int height = 50}) { Paragraph createTestParagraph(String text, {Color color = const Color(0xFF000000)}) { final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle( - fontFamily: 'Ahem', + fontFamily: 'Roboto', fontStyle: FontStyle.normal, fontWeight: FontWeight.normal, fontSize: 14.0, diff --git a/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart b/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart index 8c4538897ddb0..c67462816cff7 100644 --- a/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart +++ b/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart @@ -151,7 +151,7 @@ void testMain() async { canvas.drawParagraph(paragraph, offset); offset = offset.translate(0, paragraph.height + 10); - return takeScreenshot(canvas, bounds, 'canvas_paragraph_align_dom'); + return takeScreenshot(canvas, bounds, 'canvas_paragraph_align_dom', maxDiffRatePercent: 0.3); }); void testAlignAndTransform(EngineCanvas canvas) { @@ -174,8 +174,7 @@ void testMain() async { canvas.save(); canvas.translate(offset.dx, offset.dy); canvas.rotate(math.pi / 4); - final Rect rect = - Rect.fromLTRB(0.0, 0.0, 150.0, paragraph.height); + final Rect rect = Rect.fromLTRB(0.0, 0.0, 150.0, paragraph.height); canvas.drawRect(rect, SurfacePaintData()..color = black); canvas.drawParagraph(paragraph, Offset.zero); canvas.restore(); @@ -198,6 +197,35 @@ void testMain() async { return takeScreenshot(canvas, bounds, 'canvas_paragraph_align_transform_dom'); }); + void testGiantParagraphStyles(EngineCanvas canvas) { + final CanvasParagraph paragraph = rich( + ParagraphStyle(fontFamily: 'Roboto', fontSize: 80.0), + (CanvasParagraphBuilder builder) { + builder.pushStyle(EngineTextStyle.only(color: yellow, fontSize: 24.0)); + builder.addText('Lorem '); + builder.pushStyle(EngineTextStyle.only(color: red, fontSize: 32.0)); + builder.addText('ipsum'); + }, + )..layout(constrain(double.infinity)); + final Rect rect = Rect.fromLTRB(0.0, 0.0, paragraph.maxIntrinsicWidth, paragraph.height); + canvas.drawRect(rect, SurfacePaintData()..color = black); + canvas.drawParagraph(paragraph, Offset.zero); + } + + test('giant paragraph style', () { + const Rect bounds = Rect.fromLTWH(0, 0, 300, 200); + final canvas = BitmapCanvas(bounds, RenderStrategy()); + testGiantParagraphStyles(canvas); + return takeScreenshot(canvas, bounds, 'canvas_paragraph_giant_paragraph_style'); + }); + + test('giant paragraph style (DOM)', () { + const Rect bounds = Rect.fromLTWH(0, 0, 300, 200); + final canvas = DomCanvas(domRenderer.createElement('flt-picture')); + testGiantParagraphStyles(canvas); + return takeScreenshot(canvas, bounds, 'canvas_paragraph_giant_paragraph_style_dom'); + }); + test('paints spans with varying heights/baselines', () { final canvas = BitmapCanvas(bounds, RenderStrategy()); 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 8567abd18eeb9..9baad5a0f31f0 100644 --- a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/text/canvas_paragraph_builder_test.dart @@ -23,7 +23,7 @@ String get defaultFontFamily { const String defaultColor = 'color: rgb(255, 0, 0);'; const String defaultFontSize = 'font-size: 14px;'; final String paragraphStyle = - '$defaultFontFamily position: absolute; white-space: pre;'; + 'position: absolute; white-space: pre;'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -50,7 +50,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: double.infinity)); expect( paragraph.toDomElement().outerHtml, - '
' + '
' '' 'Hello' '' @@ -61,7 +61,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: 39.0)); expect( paragraph.toDomElement().outerHtml, - '
' + '
'
''
'Hel
lo'
''
@@ -168,7 +168,7 @@ void testMain() async {
paragraph.layout(ParagraphConstraints(width: double.infinity));
expect(
paragraph.toDomElement().outerHtml,
- '
' + '
' '' 'Hello' '' @@ -206,7 +206,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: double.infinity)); expect( paragraph.toDomElement().outerHtml, - '
' + '
' '' 'Hello' '' @@ -220,7 +220,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: 75.0)); expect( paragraph.toDomElement().outerHtml, - '
' + '
' '' 'Hello' '' @@ -271,7 +271,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: double.infinity)); expect( paragraph.toDomElement().outerHtml, - '
' + '
' '' 'Hello' '' @@ -335,7 +335,7 @@ void testMain() async { paragraph.layout(ParagraphConstraints(width: double.infinity)); expect( paragraph.toDomElement().outerHtml, - '
' + '
'
''
'First
Second '
''
@@ -349,7 +349,7 @@ void testMain() async {
paragraph.layout(ParagraphConstraints(width: 180.0));
expect(
paragraph.toDomElement().outerHtml,
- '
' + '
'
''
'First
Second
'
''