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