Showing
8 changed files
with
43 additions
and
25 deletions
@@ -4,6 +4,7 @@ | @@ -4,6 +4,7 @@ | ||
4 | 4 | ||
5 | - Allow MultiPage to relayout individual pages with support for flex | 5 | - Allow MultiPage to relayout individual pages with support for flex |
6 | - Implement BoxShadow for rect and circle BoxDecorations | 6 | - Implement BoxShadow for rect and circle BoxDecorations |
7 | +- Implement TextStyle.letterSpacing | ||
7 | 8 | ||
8 | ## 1.8.1 | 9 | ## 1.8.1 |
9 | 10 |
@@ -140,7 +140,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | @@ -140,7 +140,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
140 | @Deprecated('Use `glyphMetrics` instead') | 140 | @Deprecated('Use `glyphMetrics` instead') |
141 | PdfRect glyphBounds(int charCode) => glyphMetrics(charCode).toPdfRect(); | 141 | PdfRect glyphBounds(int charCode) => glyphMetrics(charCode).toPdfRect(); |
142 | 142 | ||
143 | - PdfFontMetrics stringMetrics(String s) { | 143 | + PdfFontMetrics stringMetrics(String s, {double letterSpacing = 0}) { |
144 | if (s.isEmpty) { | 144 | if (s.isEmpty) { |
145 | return PdfFontMetrics.zero; | 145 | return PdfFontMetrics.zero; |
146 | } | 146 | } |
@@ -148,7 +148,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | @@ -148,7 +148,7 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
148 | try { | 148 | try { |
149 | final Uint8List chars = latin1.encode(s); | 149 | final Uint8List chars = latin1.encode(s); |
150 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); | 150 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); |
151 | - return PdfFontMetrics.append(metrics); | 151 | + return PdfFontMetrics.append(metrics, letterSpacing: letterSpacing); |
152 | } catch (_) { | 152 | } catch (_) { |
153 | assert(() { | 153 | assert(() { |
154 | print(_cannotDecodeMessage); | 154 | print(_cannotDecodeMessage); |
@@ -39,7 +39,10 @@ class PdfFontMetrics { | @@ -39,7 +39,10 @@ class PdfFontMetrics { | ||
39 | assert(top <= bottom), | 39 | assert(top <= bottom), |
40 | assert((descent ?? top) <= (ascent ?? bottom)); | 40 | assert((descent ?? top) <= (ascent ?? bottom)); |
41 | 41 | ||
42 | - factory PdfFontMetrics.append(Iterable<PdfFontMetrics> metrics) { | 42 | + factory PdfFontMetrics.append( |
43 | + Iterable<PdfFontMetrics> metrics, { | ||
44 | + double letterSpacing = 0, | ||
45 | + }) { | ||
43 | if (metrics.isEmpty) { | 46 | if (metrics.isEmpty) { |
44 | return PdfFontMetrics.zero; | 47 | return PdfFontMetrics.zero; |
45 | } | 48 | } |
@@ -51,10 +54,12 @@ class PdfFontMetrics { | @@ -51,10 +54,12 @@ class PdfFontMetrics { | ||
51 | double ascent; | 54 | double ascent; |
52 | double descent; | 55 | double descent; |
53 | double lastBearing; | 56 | double lastBearing; |
57 | + double spacing; | ||
54 | 58 | ||
55 | for (PdfFontMetrics metric in metrics) { | 59 | for (PdfFontMetrics metric in metrics) { |
56 | left ??= metric.left; | 60 | left ??= metric.left; |
57 | - right += metric.advanceWidth; | 61 | + spacing = metric.advanceWidth > 0 ? letterSpacing : 0; |
62 | + right += metric.advanceWidth + spacing; | ||
58 | lastBearing = metric.rightBearing; | 63 | lastBearing = metric.rightBearing; |
59 | 64 | ||
60 | top = math.min(top ?? metric.top, metric.top); | 65 | top = math.min(top ?? metric.top, metric.top); |
@@ -66,11 +71,11 @@ class PdfFontMetrics { | @@ -66,11 +71,11 @@ class PdfFontMetrics { | ||
66 | return PdfFontMetrics( | 71 | return PdfFontMetrics( |
67 | left: left, | 72 | left: left, |
68 | top: top, | 73 | top: top, |
69 | - right: right - lastBearing, | 74 | + right: right - lastBearing - spacing, |
70 | bottom: bottom, | 75 | bottom: bottom, |
71 | ascent: ascent, | 76 | ascent: ascent, |
72 | descent: descent, | 77 | descent: descent, |
73 | - advanceWidth: right); | 78 | + advanceWidth: right - spacing); |
74 | } | 79 | } |
75 | 80 | ||
76 | static const PdfFontMetrics zero = | 81 | static const PdfFontMetrics zero = |
@@ -156,9 +156,9 @@ class PdfTtfFont extends PdfFont { | @@ -156,9 +156,9 @@ class PdfTtfFont extends PdfFont { | ||
156 | } | 156 | } |
157 | 157 | ||
158 | @override | 158 | @override |
159 | - PdfFontMetrics stringMetrics(String s) { | 159 | + PdfFontMetrics stringMetrics(String s, {double letterSpacing = 0}) { |
160 | if (s.isEmpty || !font.unicode) { | 160 | if (s.isEmpty || !font.unicode) { |
161 | - return super.stringMetrics(s); | 161 | + return super.stringMetrics(s, letterSpacing: letterSpacing); |
162 | } | 162 | } |
163 | 163 | ||
164 | final Runes runes = s.runes; | 164 | final Runes runes = s.runes; |
@@ -166,6 +166,6 @@ class PdfTtfFont extends PdfFont { | @@ -166,6 +166,6 @@ class PdfTtfFont extends PdfFont { | ||
166 | runes.forEach(bytes.add); | 166 | runes.forEach(bytes.add); |
167 | 167 | ||
168 | final Iterable<PdfFontMetrics> metrics = bytes.map(glyphMetrics); | 168 | final Iterable<PdfFontMetrics> metrics = bytes.map(glyphMetrics); |
169 | - return PdfFontMetrics.append(metrics); | 169 | + return PdfFontMetrics.append(metrics, letterSpacing: letterSpacing); |
170 | } | 170 | } |
171 | } | 171 | } |
@@ -262,6 +262,7 @@ class _Word extends _Span { | @@ -262,6 +262,7 @@ class _Word extends _Span { | ||
262 | point.x + offset.x, | 262 | point.x + offset.x, |
263 | point.y + offset.y, | 263 | point.y + offset.y, |
264 | mode: style.renderingMode, | 264 | mode: style.renderingMode, |
265 | + charSpace: style.letterSpacing, | ||
265 | ); | 266 | ); |
266 | } | 267 | } |
267 | 268 | ||
@@ -569,12 +570,15 @@ class RichText extends Widget { | @@ -569,12 +570,15 @@ class RichText extends Widget { | ||
569 | for (int line = 0; line < spanLines.length; line++) { | 570 | for (int line = 0; line < spanLines.length; line++) { |
570 | for (String word in spanLines[line].split(RegExp(r'\s'))) { | 571 | for (String word in spanLines[line].split(RegExp(r'\s'))) { |
571 | if (word.isEmpty) { | 572 | if (word.isEmpty) { |
572 | - offsetX += space.advanceWidth * style.wordSpacing; | 573 | + offsetX += |
574 | + space.advanceWidth * style.wordSpacing + style.letterSpacing; | ||
573 | continue; | 575 | continue; |
574 | } | 576 | } |
575 | 577 | ||
576 | - final PdfFontMetrics metrics = | ||
577 | - font.stringMetrics(word) * (style.fontSize * textScaleFactor); | 578 | + final PdfFontMetrics metrics = font.stringMetrics(word, |
579 | + letterSpacing: style.letterSpacing / | ||
580 | + (style.fontSize * textScaleFactor)) * | ||
581 | + (style.fontSize * textScaleFactor); | ||
578 | 582 | ||
579 | if (offsetX + metrics.width > constraintWidth && spanCount > 0) { | 583 | if (offsetX + metrics.width > constraintWidth && spanCount > 0) { |
580 | width = math.max( | 584 | width = math.max( |
@@ -583,7 +587,9 @@ class RichText extends Widget { | @@ -583,7 +587,9 @@ class RichText extends Widget { | ||
583 | _spans.sublist(spanStart), | 587 | _spans.sublist(spanStart), |
584 | _decorations.sublist(decorationStart), | 588 | _decorations.sublist(decorationStart), |
585 | constraintWidth, | 589 | constraintWidth, |
586 | - offsetX - space.advanceWidth * style.wordSpacing, | 590 | + offsetX - |
591 | + space.advanceWidth * style.wordSpacing - | ||
592 | + style.letterSpacing, | ||
587 | false, | 593 | false, |
588 | bottom, | 594 | bottom, |
589 | )); | 595 | )); |
@@ -632,8 +638,9 @@ class RichText extends Widget { | @@ -632,8 +638,9 @@ class RichText extends Widget { | ||
632 | ), | 638 | ), |
633 | ); | 639 | ); |
634 | 640 | ||
635 | - offsetX += | ||
636 | - metrics.advanceWidth + space.advanceWidth * style.wordSpacing; | 641 | + offsetX += metrics.advanceWidth + |
642 | + space.advanceWidth * style.wordSpacing + | ||
643 | + style.letterSpacing; | ||
637 | } | 644 | } |
638 | 645 | ||
639 | if (softWrap && line < spanLines.length - 1) { | 646 | if (softWrap && line < spanLines.length - 1) { |
@@ -643,7 +650,9 @@ class RichText extends Widget { | @@ -643,7 +650,9 @@ class RichText extends Widget { | ||
643 | _spans.sublist(spanStart), | 650 | _spans.sublist(spanStart), |
644 | _decorations.sublist(decorationStart), | 651 | _decorations.sublist(decorationStart), |
645 | constraintWidth, | 652 | constraintWidth, |
646 | - offsetX - space.advanceWidth * style.wordSpacing, | 653 | + offsetX - |
654 | + space.advanceWidth * style.wordSpacing - | ||
655 | + style.letterSpacing, | ||
647 | true, | 656 | true, |
648 | bottom, | 657 | bottom, |
649 | )); | 658 | )); |
@@ -672,7 +681,7 @@ class RichText extends Widget { | @@ -672,7 +681,7 @@ class RichText extends Widget { | ||
672 | } | 681 | } |
673 | } | 682 | } |
674 | 683 | ||
675 | - offsetX -= space.advanceWidth * style.wordSpacing; | 684 | + offsetX -= space.advanceWidth * style.wordSpacing - style.letterSpacing; |
676 | } else if (span is WidgetSpan) { | 685 | } else if (span is WidgetSpan) { |
677 | span.child.layout( | 686 | span.child.layout( |
678 | context, | 687 | context, |
@@ -157,10 +157,10 @@ class TextStyle { | @@ -157,10 +157,10 @@ class TextStyle { | ||
157 | fontSize: _defaultFontSize, | 157 | fontSize: _defaultFontSize, |
158 | fontWeight: FontWeight.normal, | 158 | fontWeight: FontWeight.normal, |
159 | fontStyle: FontStyle.normal, | 159 | fontStyle: FontStyle.normal, |
160 | - letterSpacing: 1.0, | ||
161 | - wordSpacing: 1.0, | ||
162 | - lineSpacing: 0.0, | ||
163 | - height: 1.0, | 160 | + letterSpacing: 0, |
161 | + wordSpacing: 1, | ||
162 | + lineSpacing: 0, | ||
163 | + height: 1, | ||
164 | decoration: TextDecoration.none, | 164 | decoration: TextDecoration.none, |
165 | decorationColor: null, | 165 | decorationColor: null, |
166 | decorationStyle: TextDecorationStyle.solid, | 166 | decorationStyle: TextDecorationStyle.solid, |
@@ -131,9 +131,12 @@ void main() { | @@ -131,9 +131,12 @@ void main() { | ||
131 | final String para = LoremText().paragraph(40); | 131 | final String para = LoremText().paragraph(40); |
132 | 132 | ||
133 | final List<Widget> widgets = <Widget>[]; | 133 | final List<Widget> widgets = <Widget>[]; |
134 | - for (double spacing = 0.0; spacing < 10.0; spacing += 2.0) { | 134 | + for (double spacing = -1.0; spacing < 8.0; spacing += 2.0) { |
135 | widgets.add( | 135 | widgets.add( |
136 | - Text(para, style: TextStyle(font: ttf, letterSpacing: spacing)), | 136 | + Text( |
137 | + '[$spacing] $para', | ||
138 | + style: TextStyle(font: ttf, letterSpacing: spacing), | ||
139 | + ), | ||
137 | ); | 140 | ); |
138 | widgets.add( | 141 | widgets.add( |
139 | SizedBox(height: 30), | 142 | SizedBox(height: 30), |
No preview for this file type
-
Please register or login to post a comment