1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Shared; |
6
|
|
|
|
7
|
|
|
use PhpOffice\PhpSpreadsheet\RichText\RichText; |
8
|
|
|
use PhpOffice\PhpSpreadsheet\RichText\Run; |
9
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\Font; |
10
|
|
|
use PhpOffice\PhpSpreadsheet\Style\Font as StyleFont; |
11
|
|
|
use PHPUnit\Framework\TestCase; |
12
|
|
|
|
13
|
|
|
class ExactFontTest extends TestCase |
14
|
|
|
{ |
15
|
|
|
// Results from this test are not necessarily portable between |
16
|
|
|
// systems and Php Releases. |
17
|
|
|
// See https://github.com/php/php-src/issues/9073 |
18
|
|
|
// Extra tests are added to determine if test should |
19
|
|
|
// be marked incomplete. |
20
|
|
|
const EXTRA_FONTS = [ |
21
|
|
|
'DejaVu Sans' => [ |
22
|
|
|
'x' => 'DejaVuSans.ttf', |
23
|
|
|
'xb' => 'DejaVuSans-Bold.ttf', |
24
|
|
|
'xi' => 'DejaVuSans-Oblique.ttf', |
25
|
|
|
'xbi' => 'DejaVuSans-BoldOblique.ttf', |
26
|
|
|
], |
27
|
|
|
'DejaVu Sans Mono' => [ |
28
|
|
|
'x' => 'DejaVuSansMono.ttf', |
29
|
|
|
'xb' => 'DejaVuSansMono-Bold.ttf', |
30
|
|
|
'xi' => 'DejaVuSansMono-Oblique.ttf', |
31
|
|
|
'xbi' => 'DejaVuSansMono-BoldOblique.ttf', |
32
|
|
|
], |
33
|
|
|
'DejaVu Serif Condensed' => [ |
34
|
|
|
'x' => 'DejaVuSerifCondensed.ttf', |
35
|
|
|
'xb' => 'DejaVuSerifCondensed-Bold.ttf', |
36
|
|
|
'xi' => 'DejaVuSerifCondensed-Italic.ttf', |
37
|
|
|
'xbi' => 'DejaVuSerifCondensed-BoldItalic.ttf', |
38
|
|
|
], |
39
|
|
|
]; |
40
|
|
|
|
41
|
|
|
private string $holdDirectory; |
42
|
|
|
|
43
|
|
|
private string $holdAutoSizeMethod; |
44
|
|
|
|
45
|
|
|
private string $directoryName = ''; |
46
|
|
|
|
47
|
|
|
private string $incompleteMessage = ''; |
48
|
|
|
|
49
|
|
|
private const KNOWN_MD5 = [ |
50
|
|
|
'6a15e0a7c0367ba77a959ea27ebf11cf', |
51
|
|
|
'b0e31de57cd5307954a3c54136ce68ae', |
52
|
|
|
'be189a7e2711cdf2a7f6275c60cbc7e2', |
53
|
|
|
]; |
54
|
|
|
|
55
|
|
|
private float|int|null $paddingAmountExact; |
56
|
|
|
|
57
|
|
|
protected function setUp(): void |
58
|
|
|
{ |
59
|
|
|
$this->paddingAmountExact = Font::getPaddingAmountExact(); |
60
|
|
|
$this->holdDirectory = Font::getTrueTypeFontPath(); |
61
|
|
|
$this->holdAutoSizeMethod = Font::getAutoSizeMethod(); |
62
|
|
|
$direc = realpath('vendor/mpdf/mpdf/ttfonts') . DIRECTORY_SEPARATOR; |
63
|
|
|
$fontFile = 'DejaVuSans.ttf'; |
64
|
|
|
$fontPath = $direc . $fontFile; |
65
|
|
|
$this->incompleteMessage = ''; |
66
|
|
|
if (@is_readable($fontPath)) { |
67
|
|
|
$hash = md5_file($fontPath); |
68
|
|
|
if (!in_array($hash, self::KNOWN_MD5, true)) { |
69
|
|
|
$this->incompleteMessage = "Unrecognized Font file MD5 hash $hash"; |
70
|
|
|
} |
71
|
|
|
} else { |
72
|
|
|
$this->incompleteMessage = 'Unable to locate font file'; |
73
|
|
|
} |
74
|
|
|
$this->directoryName = $direc; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
protected function tearDown(): void |
78
|
|
|
{ |
79
|
|
|
Font::setTrueTypeFontPath($this->holdDirectory); |
80
|
|
|
Font::setAutoSizeMethod($this->holdAutoSizeMethod); |
81
|
|
|
Font::setPaddingAmountExact($this->paddingAmountExact); |
82
|
|
|
$this->directoryName = ''; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
#[\PHPUnit\Framework\Attributes\DataProvider('providerFontData')] |
86
|
|
|
public function testExact(string $fontName, float $excelWidth, float $xmlWidth, float $winWidth, float $ubuntuWidth): void |
87
|
|
|
{ |
88
|
|
|
if ($this->incompleteMessage !== '') { |
89
|
|
|
self::markTestIncomplete($this->incompleteMessage); |
90
|
|
|
} |
91
|
|
|
$font = new StyleFont(); |
92
|
|
|
$font->setName($fontName); |
93
|
|
|
$font->setSize(11); |
94
|
|
|
Font::setTrueTypeFontPath($this->directoryName); |
95
|
|
|
Font::setExtraFontArray(self::EXTRA_FONTS); |
96
|
|
|
Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT); |
97
|
|
|
$exactWidth = Font::calculateColumnWidth($font, "This is $fontName"); |
98
|
|
|
Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_APPROX); |
99
|
|
|
$approxWidth = Font::calculateColumnWidth($font, "This is $fontName"); |
100
|
|
|
if ($excelWidth > 0) { |
101
|
|
|
self::assertGreaterThanOrEqual(max($excelWidth, $xmlWidth), $exactWidth); |
102
|
|
|
// Give ourselves a little wiggle room on upper bound. |
103
|
|
|
self::assertLessThanOrEqual(1.05 * max($winWidth, $ubuntuWidth), $exactWidth); |
104
|
|
|
self::assertNotEquals($exactWidth, $approxWidth); |
105
|
|
|
} else { |
106
|
|
|
self::assertEquals($exactWidth, $approxWidth, 'Use approx when exact font file not found'); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public static function providerFontData(): array |
111
|
|
|
{ |
112
|
|
|
return [ |
113
|
|
|
['DejaVu Sans', 19.82, 20.453125, 22.5659, 21.709], |
114
|
|
|
['DejaVu Sans Mono', 29.18, 29.81640625, 31.9922, 31.8494], |
115
|
|
|
['DejaVu Serif Condensed', 29.55, 30.1796875, 31.9922, 31.1353], |
116
|
|
|
['Arial', -29.55, 30.1796875, 31.9922, 31.1353], |
117
|
|
|
]; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
public function testRichText(): void |
121
|
|
|
{ |
122
|
|
|
// RichText treated as text, using Cell font, not Run Font |
123
|
|
|
$courier = new StyleFont(); |
124
|
|
|
$courier->setName('Courier New'); |
125
|
|
|
$courier->setSize(11); |
126
|
|
|
Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_APPROX); |
127
|
|
|
$element1 = new Run('A'); |
128
|
|
|
$element2 = new Run('B'); |
129
|
|
|
$element3 = new Run('C'); |
130
|
|
|
$element1->setFont($courier); |
131
|
|
|
$element2->setFont($courier); |
132
|
|
|
$element3->setFont($courier); |
133
|
|
|
$richText = new RichText(); |
134
|
|
|
$richText->setRichTextElements([$element1, $element2, $element3]); |
135
|
|
|
$arial = new StyleFont(); |
136
|
|
|
$arial->setName('Arial'); |
137
|
|
|
$arial->setSize(9); |
138
|
|
|
$widthRich = Font::calculateColumnWidth($arial, $richText); |
139
|
|
|
$widthText = Font::calculateColumnWidth($arial, 'ABC'); |
140
|
|
|
self::assertSame($widthRich, $widthText); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
public function testIssue3626NoPad(): void |
144
|
|
|
{ |
145
|
|
|
$fontName = 'DejaVu Sans'; |
146
|
|
|
if ($this->incompleteMessage !== '') { |
147
|
|
|
self::markTestIncomplete($this->incompleteMessage); |
148
|
|
|
} |
149
|
|
|
Font::setTrueTypeFontPath($this->directoryName); |
150
|
|
|
Font::setExtraFontArray(self::EXTRA_FONTS); |
151
|
|
|
Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT); |
152
|
|
|
Font::setPaddingAmountExact(0); |
153
|
|
|
|
154
|
|
|
$font = new StyleFont(); |
155
|
|
|
$font->setName($fontName); |
156
|
|
|
$font->setSize(20); |
157
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Column2'); |
158
|
|
|
$expectedWidth = 16.853; |
159
|
|
|
self::assertTrue( |
160
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
161
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
162
|
|
|
); |
163
|
|
|
|
164
|
|
|
$font = new StyleFont(); |
165
|
|
|
$font->setName($fontName); |
166
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Col3'); |
167
|
|
|
$expectedWidth = 4.5703; |
168
|
|
|
self::assertTrue( |
169
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
170
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
171
|
|
|
); |
172
|
|
|
|
173
|
|
|
$font = new StyleFont(); |
174
|
|
|
$font->setName($fontName); |
175
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Big Column in 4 position'); |
176
|
|
|
$expectedWidth = 26.2793; |
177
|
|
|
self::assertTrue( |
178
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
179
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
180
|
|
|
); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
public function testIssue3626Pad(): void |
184
|
|
|
{ |
185
|
|
|
$fontName = 'DejaVu Sans'; |
186
|
|
|
if ($this->incompleteMessage !== '') { |
187
|
|
|
self::markTestIncomplete($this->incompleteMessage); |
188
|
|
|
} |
189
|
|
|
Font::setTrueTypeFontPath($this->directoryName); |
190
|
|
|
Font::setExtraFontArray(self::EXTRA_FONTS); |
191
|
|
|
Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT); |
192
|
|
|
//Font::setPaddingAmountExact(null); // default - not needed |
193
|
|
|
|
194
|
|
|
$font = new StyleFont(); |
195
|
|
|
$font->setName($fontName); |
196
|
|
|
$font->setSize(20); |
197
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Column2'); |
198
|
|
|
$expectedWidth = 18.8525; |
199
|
|
|
self::assertTrue( |
200
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
201
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
$font = new StyleFont(); |
205
|
|
|
$font->setName($fontName); |
206
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Col3'); |
207
|
|
|
$expectedWidth = 5.8557; |
208
|
|
|
self::assertTrue( |
209
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
210
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
211
|
|
|
); |
212
|
|
|
|
213
|
|
|
$font = new StyleFont(); |
214
|
|
|
$font->setName($fontName); |
215
|
|
|
$exactWidth = Font::calculateColumnWidth($font, 'Big Column in 4 position'); |
216
|
|
|
$expectedWidth = 27.5647; |
217
|
|
|
self::assertTrue( |
218
|
|
|
$exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth, |
219
|
|
|
"$exactWidth is not within 5% of expected $expectedWidth" |
220
|
|
|
); |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|