Open dkwingsmt opened 5 months ago
cc @jmagman
@jason-simmons do you know how the letter spacing is controlled?
The initial positioning of glyphs is done by HarfBuzz.
Additional letter spacing specified by TextStyle.letterSpacing
is applied by SkParagraph's Run::addSpacesEvenly
.
@Rusino
Yes, positioning is done by harfbuzz (and is defined by harfbuzz logic and the font metrics). The letter spacing is done by SkParagraph.
which complained about HarfBuzz's text tracking deviates from that of macOS in 2019. Although I don't quite get the content in that page and whether the issue was considered fixed.
The harfbuzz maintainers say they decided to keep track of the issue via this chrome issue, which was marked fixed January 2020.
Flutter's
Text()
has noticeably different letter spacing from iOS'sText()
by default.Background
iOS renders text with "SF Pro Text" font for font size <20, and "SF Pro Display" font for font size >= 20. In Flutter they're called "CupertinoSystemText" and "CupertinoSystemDisplay" respectively.
Comparison with current Flutter
(light grey Flutter, black native iOS)
Adjustment
I tried to apply
letterSpacing
to Flutter's text to get a result close to the native one. The needed adjustment turns out to be a non-linear curve, which is interpolated as a cubic polynomial.Comparison after adjustment
(light grey Flutter, black native iOS)
(Yes, I know line height at small font size still deviates noticeably.)
Note
Reproduction code
Dart code
```dart import 'dart:math'; import 'package:flutter/cupertino.dart'; void main() => runApp(const Main()); class Main extends StatelessWidget { const Main({super.key}); @override Widget build(BuildContext context) { return CupertinoPageScaffold( child: SafeArea( child: Center( child: Transform.translate( offset: const Offset(0, -0), child: Container( width: 400, height: 500, decoration: BoxDecoration( border: Border.all(), ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children:SwiftUI code
```swift import SwiftUI struct ContentView: View { var body: some View { Rectangle() .fill(Color.white) .frame(width: 400, height: 500) .overlay( VStack { ForEach([3, 4, 5, 7, 8, 9, 10, 11, 13, 15, 17, 19], id: \.self) { i in Text(String(format: "CupertinoSystemText size %d", Int(i))) .font(.system(size: i)) .foregroundColor(.black) } ForEach([20, 22, 25, 28, 32, 36], id: \.self) { i in Text(String(format: "SystemDisplay size %d", Int(i))) .font(.system(size: i)) .foregroundColor(.black) } } ) } } #Preview { ContentView() } ```