diff --git a/lib/web_ui/dev/goldens_lock.yaml b/lib/web_ui/dev/goldens_lock.yaml index c89bd196e6ea7..f6189193a9057 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: 1e65186b73045bb1034ade9f12b810caabd00462 +revision: ca17cd88e5cc8155672e0b58bb7c0424a9612950 diff --git a/lib/web_ui/lib/src/engine/text/paint_service.dart b/lib/web_ui/lib/src/engine/text/paint_service.dart index 64debd40f017f..fd8cd81539e7e 100644 --- a/lib/web_ui/lib/src/engine/text/paint_service.dart +++ b/lib/web_ui/lib/src/engine/text/paint_service.dart @@ -52,7 +52,21 @@ class TextPaintService { box.start.index, box.end.indexWithoutTrailingNewlines, ); - canvas.fillText(text, x, y, shadows: span.style._shadows); + final double? letterSpacing = span.style._letterSpacing; + if (letterSpacing == null || letterSpacing == 0.0) { + canvas.fillText(text, x, y, shadows: span.style._shadows); + } else { + // TODO(mdebbar): Implement letter-spacing on canvas more efficiently: + // https://github.com/flutter/flutter/issues/51234 + double charX = x; + final int len = text.length; + for (int i = 0; i < len; i++) { + final String char = text[i]; + canvas.fillText(char, charX.roundToDouble(), y, + shadows: span.style._shadows); + charX += letterSpacing + canvas.measureText(char).width!; + } + } // Paint the ellipsis using the same span styles. final String? ellipsis = line.ellipsis; 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 6871a2a3e9cf9..ba9cb5a74b13b 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 @@ -146,4 +146,23 @@ void testMain() async { return takeScreenshot(canvas, bounds, 'canvas_paragraph_varying_heights'); }); + + test('respects letter-spacing', () { + final canvas = BitmapCanvas(bounds, RenderStrategy()); + + final CanvasParagraph paragraph = rich( + ParagraphStyle(fontFamily: 'Roboto'), + (builder) { + builder.pushStyle(EngineTextStyle.only(color: blue)); + builder.addText('Lorem '); + builder.pushStyle(EngineTextStyle.only(color: green, letterSpacing: 1)); + builder.addText('Lorem '); + builder.pushStyle(EngineTextStyle.only(color: red, letterSpacing: 3)); + builder.addText('Lorem'); + }, + )..layout(constrain(double.infinity)); + canvas.drawParagraph(paragraph, Offset.zero); + + return takeScreenshot(canvas, bounds, 'canvas_paragraph_letter_spacing'); + }); } diff --git a/lib/web_ui/test/golden_tests/engine/compositing_golden_test.dart b/lib/web_ui/test/golden_tests/engine/compositing_golden_test.dart index 0cfc7de5c3d44..18fd6c77ef647 100644 --- a/lib/web_ui/test/golden_tests/engine/compositing_golden_test.dart +++ b/lib/web_ui/test/golden_tests/engine/compositing_golden_test.dart @@ -547,8 +547,8 @@ void _testCullRectComputation() { 'renders clipped text with high quality', () async { // To reproduce blurriness we need real clipping. - final Paragraph paragraph = - (ParagraphBuilder(ParagraphStyle(fontFamily: 'Roboto'))..addText('Am I blurry?')).build(); + final DomParagraph paragraph = + (DomParagraphBuilder(ParagraphStyle(fontFamily: 'Roboto'))..addText('Am I blurry?')).build(); paragraph.layout(const ParagraphConstraints(width: 1000)); final Rect canvasSize = Rect.fromLTRB(