font_metrics.dart
5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'dart:math' as math;
import 'package:meta/meta.dart';
import 'rect.dart';
/// Describe dimensions for glyphs in a font
@immutable
class PdfFontMetrics {
/// Create a PdfFontMetrics object
const PdfFontMetrics({
@required this.left,
@required this.top,
@required this.right,
@required this.bottom,
double ascent,
double descent,
double advanceWidth,
double leftBearing,
}) : ascent = ascent ?? bottom,
descent = descent ?? top,
advanceWidth = advanceWidth ?? right - left,
leftBearing = leftBearing ?? left,
assert(left != null),
assert(top != null),
assert(right != null),
assert(bottom != null),
assert(left <= right),
assert(top <= bottom),
assert((descent ?? top) <= (ascent ?? bottom));
/// Add another metric
factory PdfFontMetrics.append(
Iterable<PdfFontMetrics> metrics, {
double letterSpacing = 0,
}) {
if (metrics.isEmpty) {
return PdfFontMetrics.zero;
}
double left;
double top;
var right = 0.0;
double bottom;
double ascent;
double descent;
double lastBearing;
double firstBearing;
double spacing;
for (var metric in metrics) {
firstBearing ??= metric.leftBearing;
left ??= metric.left;
spacing = metric.advanceWidth > 0 ? letterSpacing : 0.0;
right += metric.advanceWidth + spacing;
lastBearing = metric.rightBearing;
top = math.min(top ?? metric.top, metric.top);
bottom = math.max(bottom ?? metric.bottom, metric.bottom);
descent = math.min(descent ?? metric.descent, metric.descent);
ascent = math.max(ascent ?? metric.ascent, metric.ascent);
}
return PdfFontMetrics(
left: left,
top: top,
right: right - lastBearing - spacing,
bottom: bottom,
ascent: ascent,
descent: descent,
advanceWidth: right - spacing,
leftBearing: firstBearing,
);
}
/// Zero-sized dimensions
static const PdfFontMetrics zero =
PdfFontMetrics(left: 0, top: 0, right: 0, bottom: 0);
/// Left most of the bounding box
final double left;
/// Top most of the bounding box
final double top;
/// Bottom most of the bounding box
final double bottom;
/// Right most of the bounding box
final double right;
/// Spans the distance between the baseline and the top of the glyph that
/// reaches farthest from the baseline
final double ascent;
/// Spans the distance between the baseline and the lowest descending glyph
final double descent;
/// distance to move right to draw the next glyph
final double advanceWidth;
/// Width of the glyph
double get width => right - left;
/// Height of the glyph
double get height => bottom - top;
/// Maximum Width any glyph from this font can have
double get maxWidth =>
math.max(advanceWidth, right) + math.max(-leftBearing, 0.0);
/// Maximum Height any glyph from this font can have
double get maxHeight => ascent - descent;
/// Real left position. The glyph may overflow on the left
double get effectiveLeft => math.min(leftBearing, 0);
/// Starting point
final double leftBearing;
/// Ending point
double get rightBearing => advanceWidth - right;
@override
String toString() =>
'PdfFontMetrics(left:$left, top:$top, right:$right, bottom:$bottom, ascent:$ascent, descent:$descent, advanceWidth:$advanceWidth, leftBearing:$leftBearing, rightBearing:$rightBearing)';
/// Make a copy of this object
PdfFontMetrics copyWith({
double left,
double top,
double right,
double bottom,
double ascent,
double descent,
double advanceWidth,
double leftBearing,
}) {
return PdfFontMetrics(
left: left ?? this.left,
top: top ?? this.top,
right: right ?? this.right,
bottom: bottom ?? this.bottom,
ascent: ascent ?? this.ascent,
descent: descent ?? this.descent,
advanceWidth: advanceWidth ?? this.advanceWidth,
leftBearing: leftBearing ?? this.leftBearing,
);
}
/// Multiply this metrics object with a font size
PdfFontMetrics operator *(double factor) {
return copyWith(
left: left * factor,
top: top * factor,
right: right * factor,
bottom: bottom * factor,
ascent: ascent * factor,
descent: descent * factor,
advanceWidth: advanceWidth * factor,
leftBearing: leftBearing * factor,
);
}
/// Get the bounding box
PdfRect toPdfRect() => PdfRect.fromLTRB(left, top, right, bottom);
}