David PHAM-VAN

Implement TextStyle.letterSpacing

... ... @@ -4,6 +4,7 @@
- Allow MultiPage to relayout individual pages with support for flex
- Implement BoxShadow for rect and circle BoxDecorations
- Implement TextStyle.letterSpacing
## 1.8.1
... ...
... ... @@ -140,7 +140,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management
@Deprecated('Use `glyphMetrics` instead')
PdfRect glyphBounds(int charCode) => glyphMetrics(charCode).toPdfRect();
PdfFontMetrics stringMetrics(String s) {
PdfFontMetrics stringMetrics(String s, {double letterSpacing = 0}) {
if (s.isEmpty) {
return PdfFontMetrics.zero;
}
... ... @@ -148,7 +148,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management
try {
final Uint8List chars = latin1.encode(s);
final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics);
return PdfFontMetrics.append(metrics);
return PdfFontMetrics.append(metrics, letterSpacing: letterSpacing);
} catch (_) {
assert(() {
print(_cannotDecodeMessage);
... ...
... ... @@ -39,7 +39,10 @@ class PdfFontMetrics {
assert(top <= bottom),
assert((descent ?? top) <= (ascent ?? bottom));
factory PdfFontMetrics.append(Iterable<PdfFontMetrics> metrics) {
factory PdfFontMetrics.append(
Iterable<PdfFontMetrics> metrics, {
double letterSpacing = 0,
}) {
if (metrics.isEmpty) {
return PdfFontMetrics.zero;
}
... ... @@ -51,10 +54,12 @@ class PdfFontMetrics {
double ascent;
double descent;
double lastBearing;
double spacing;
for (PdfFontMetrics metric in metrics) {
left ??= metric.left;
right += metric.advanceWidth;
spacing = metric.advanceWidth > 0 ? letterSpacing : 0;
right += metric.advanceWidth + spacing;
lastBearing = metric.rightBearing;
top = math.min(top ?? metric.top, metric.top);
... ... @@ -66,11 +71,11 @@ class PdfFontMetrics {
return PdfFontMetrics(
left: left,
top: top,
right: right - lastBearing,
right: right - lastBearing - spacing,
bottom: bottom,
ascent: ascent,
descent: descent,
advanceWidth: right);
advanceWidth: right - spacing);
}
static const PdfFontMetrics zero =
... ...
... ... @@ -156,9 +156,9 @@ class PdfTtfFont extends PdfFont {
}
@override
PdfFontMetrics stringMetrics(String s) {
PdfFontMetrics stringMetrics(String s, {double letterSpacing = 0}) {
if (s.isEmpty || !font.unicode) {
return super.stringMetrics(s);
return super.stringMetrics(s, letterSpacing: letterSpacing);
}
final Runes runes = s.runes;
... ... @@ -166,6 +166,6 @@ class PdfTtfFont extends PdfFont {
runes.forEach(bytes.add);
final Iterable<PdfFontMetrics> metrics = bytes.map(glyphMetrics);
return PdfFontMetrics.append(metrics);
return PdfFontMetrics.append(metrics, letterSpacing: letterSpacing);
}
}
... ...
... ... @@ -262,6 +262,7 @@ class _Word extends _Span {
point.x + offset.x,
point.y + offset.y,
mode: style.renderingMode,
charSpace: style.letterSpacing,
);
}
... ... @@ -569,12 +570,15 @@ class RichText extends Widget {
for (int line = 0; line < spanLines.length; line++) {
for (String word in spanLines[line].split(RegExp(r'\s'))) {
if (word.isEmpty) {
offsetX += space.advanceWidth * style.wordSpacing;
offsetX +=
space.advanceWidth * style.wordSpacing + style.letterSpacing;
continue;
}
final PdfFontMetrics metrics =
font.stringMetrics(word) * (style.fontSize * textScaleFactor);
final PdfFontMetrics metrics = font.stringMetrics(word,
letterSpacing: style.letterSpacing /
(style.fontSize * textScaleFactor)) *
(style.fontSize * textScaleFactor);
if (offsetX + metrics.width > constraintWidth && spanCount > 0) {
width = math.max(
... ... @@ -583,7 +587,9 @@ class RichText extends Widget {
_spans.sublist(spanStart),
_decorations.sublist(decorationStart),
constraintWidth,
offsetX - space.advanceWidth * style.wordSpacing,
offsetX -
space.advanceWidth * style.wordSpacing -
style.letterSpacing,
false,
bottom,
));
... ... @@ -632,8 +638,9 @@ class RichText extends Widget {
),
);
offsetX +=
metrics.advanceWidth + space.advanceWidth * style.wordSpacing;
offsetX += metrics.advanceWidth +
space.advanceWidth * style.wordSpacing +
style.letterSpacing;
}
if (softWrap && line < spanLines.length - 1) {
... ... @@ -643,7 +650,9 @@ class RichText extends Widget {
_spans.sublist(spanStart),
_decorations.sublist(decorationStart),
constraintWidth,
offsetX - space.advanceWidth * style.wordSpacing,
offsetX -
space.advanceWidth * style.wordSpacing -
style.letterSpacing,
true,
bottom,
));
... ... @@ -672,7 +681,7 @@ class RichText extends Widget {
}
}
offsetX -= space.advanceWidth * style.wordSpacing;
offsetX -= space.advanceWidth * style.wordSpacing - style.letterSpacing;
} else if (span is WidgetSpan) {
span.child.layout(
context,
... ...
... ... @@ -157,10 +157,10 @@ class TextStyle {
fontSize: _defaultFontSize,
fontWeight: FontWeight.normal,
fontStyle: FontStyle.normal,
letterSpacing: 1.0,
wordSpacing: 1.0,
lineSpacing: 0.0,
height: 1.0,
letterSpacing: 0,
wordSpacing: 1,
lineSpacing: 0,
height: 1,
decoration: TextDecoration.none,
decorationColor: null,
decorationStyle: TextDecorationStyle.solid,
... ...
... ... @@ -131,9 +131,12 @@ void main() {
final String para = LoremText().paragraph(40);
final List<Widget> widgets = <Widget>[];
for (double spacing = 0.0; spacing < 10.0; spacing += 2.0) {
for (double spacing = -1.0; spacing < 8.0; spacing += 2.0) {
widgets.add(
Text(para, style: TextStyle(font: ttf, letterSpacing: spacing)),
Text(
'[$spacing] $para',
style: TextStyle(font: ttf, letterSpacing: spacing),
),
);
widgets.add(
SizedBox(height: 30),
... ...