Completed
Push — develop ( 91417a...f02c33 )
by Adrien
18:11
created

Font   D

Complexity

Total Complexity 117

Size/Duplication

Total Lines 700
Duplicated Lines 26.86 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 4.92%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
c 6
b 0
f 0
dl 188
loc 700
ccs 13
cts 264
cp 0.0492
rs 4.4444
wmc 117
lcom 2
cbo 5

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setAutoSizeMethod() 0 9 2
A getAutoSizeMethod() 0 4 1
A setTrueTypeFontPath() 0 4 1
A getTrueTypeFontPath() 0 4 1
C calculateColumnWidth() 0 44 7
A getTextWidthPixelsExact() 0 22 2
B getTextWidthPixelsApprox() 22 47 6
A fontSizeToPixels() 0 4 1
A inchSizeToPixels() 0 4 1
A centimeterSizeToPixels() 0 4 1
D getTrueTypeFontFileFromFont() 36 105 49
B getCharsetFromFontName() 0 16 5
B getDefaultColumnWidthByFont() 0 23 5
D getDefaultRowHeightByFont() 130 143 35

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Font often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Font, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpSpreadsheet\Shared;
4
5
/**
6
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 *
22
 * @category   PhpSpreadsheet
23
 * @copyright  Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
24
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25
 * @version    ##VERSION##, ##DATE##
26
 */
27
class Font
28
{
29
    /* Methods for resolving autosize value */
30
    const AUTOSIZE_METHOD_APPROX = 'approx';
31
    const AUTOSIZE_METHOD_EXACT = 'exact';
32
33
    private static $autoSizeMethods = [
34
        self::AUTOSIZE_METHOD_APPROX,
35
        self::AUTOSIZE_METHOD_EXACT,
36
    ];
37
38
    /** Character set codes used by BIFF5-8 in Font records */
39
    const CHARSET_ANSI_LATIN = 0x00;
40
    const CHARSET_SYSTEM_DEFAULT = 0x01;
41
    const CHARSET_SYMBOL = 0x02;
42
    const CHARSET_APPLE_ROMAN = 0x4D;
43
    const CHARSET_ANSI_JAPANESE_SHIFTJIS = 0x80;
44
    const CHARSET_ANSI_KOREAN_HANGUL = 0x81;
45
    const CHARSET_ANSI_KOREAN_JOHAB = 0x82;
46
    const CHARSET_ANSI_CHINESE_SIMIPLIFIED = 0x86; //    gb2312
47
    const CHARSET_ANSI_CHINESE_TRADITIONAL = 0x88; //    big5
48
    const CHARSET_ANSI_GREEK = 0xA1;
49
    const CHARSET_ANSI_TURKISH = 0xA2;
50
    const CHARSET_ANSI_VIETNAMESE = 0xA3;
51
    const CHARSET_ANSI_HEBREW = 0xB1;
52
    const CHARSET_ANSI_ARABIC = 0xB2;
53
    const CHARSET_ANSI_BALTIC = 0xBA;
54
    const CHARSET_ANSI_CYRILLIC = 0xCC;
55
    const CHARSET_ANSI_THAI = 0xDD;
56
    const CHARSET_ANSI_LATIN_II = 0xEE;
57
    const CHARSET_OEM_LATIN_I = 0xFF;
58
59
    //  XXX: Constants created!
60
    /** Font filenames */
61
    const ARIAL = 'arial.ttf';
62
    const ARIAL_BOLD = 'arialbd.ttf';
63
    const ARIAL_ITALIC = 'ariali.ttf';
64
    const ARIAL_BOLD_ITALIC = 'arialbi.ttf';
65
66
    const CALIBRI = 'CALIBRI.TTF';
67
    const CALIBRI_BOLD = 'CALIBRIB.TTF';
68
    const CALIBRI_ITALIC = 'CALIBRII.TTF';
69
    const CALIBRI_BOLD_ITALIC = 'CALIBRIZ.TTF';
70
71
    const COMIC_SANS_MS = 'comic.ttf';
72
    const COMIC_SANS_MS_BOLD = 'comicbd.ttf';
73
74
    const COURIER_NEW = 'cour.ttf';
75
    const COURIER_NEW_BOLD = 'courbd.ttf';
76
    const COURIER_NEW_ITALIC = 'couri.ttf';
77
    const COURIER_NEW_BOLD_ITALIC = 'courbi.ttf';
78
79
    const GEORGIA = 'georgia.ttf';
80
    const GEORGIA_BOLD = 'georgiab.ttf';
81
    const GEORGIA_ITALIC = 'georgiai.ttf';
82
    const GEORGIA_BOLD_ITALIC = 'georgiaz.ttf';
83
84
    const IMPACT = 'impact.ttf';
85
86
    const LIBERATION_SANS = 'LiberationSans-Regular.ttf';
87
    const LIBERATION_SANS_BOLD = 'LiberationSans-Bold.ttf';
88
    const LIBERATION_SANS_ITALIC = 'LiberationSans-Italic.ttf';
89
    const LIBERATION_SANS_BOLD_ITALIC = 'LiberationSans-BoldItalic.ttf';
90
91
    const LUCIDA_CONSOLE = 'lucon.ttf';
92
    const LUCIDA_SANS_UNICODE = 'l_10646.ttf';
93
94
    const MICROSOFT_SANS_SERIF = 'micross.ttf';
95
96
    const PALATINO_LINOTYPE = 'pala.ttf';
97
    const PALATINO_LINOTYPE_BOLD = 'palab.ttf';
98
    const PALATINO_LINOTYPE_ITALIC = 'palai.ttf';
99
    const PALATINO_LINOTYPE_BOLD_ITALIC = 'palabi.ttf';
100
101
    const SYMBOL = 'symbol.ttf';
102
103
    const TAHOMA = 'tahoma.ttf';
104
    const TAHOMA_BOLD = 'tahomabd.ttf';
105
106
    const TIMES_NEW_ROMAN = 'times.ttf';
107
    const TIMES_NEW_ROMAN_BOLD = 'timesbd.ttf';
108
    const TIMES_NEW_ROMAN_ITALIC = 'timesi.ttf';
109
    const TIMES_NEW_ROMAN_BOLD_ITALIC = 'timesbi.ttf';
110
111
    const TREBUCHET_MS = 'trebuc.ttf';
112
    const TREBUCHET_MS_BOLD = 'trebucbd.ttf';
113
    const TREBUCHET_MS_ITALIC = 'trebucit.ttf';
114
    const TREBUCHET_MS_BOLD_ITALIC = 'trebucbi.ttf';
115
116
    const VERDANA = 'verdana.ttf';
117
    const VERDANA_BOLD = 'verdanab.ttf';
118
    const VERDANA_ITALIC = 'verdanai.ttf';
119
    const VERDANA_BOLD_ITALIC = 'verdanaz.ttf';
120
121
    /**
122
     * AutoSize method
123
     *
124
     * @var string
125
     */
126
    private static $autoSizeMethod = self::AUTOSIZE_METHOD_APPROX;
127
128
    /**
129
     * Path to folder containing TrueType font .ttf files
130
     *
131
     * @var string
132
     */
133
    private static $trueTypeFontPath = null;
134
135
    /**
136
     * How wide is a default column for a given default font and size?
137
     * Empirical data found by inspecting real Excel files and reading off the pixel width
138
     * in Microsoft Office Excel 2007.
139
     *
140
     * @var array
141
     */
142
    public static $defaultColumnWidths = [
143
        'Arial' => [
144
            1 => ['px' => 24, 'width' => 12.00000000],
145
            2 => ['px' => 24, 'width' => 12.00000000],
146
            3 => ['px' => 32, 'width' => 10.66406250],
147
            4 => ['px' => 32, 'width' => 10.66406250],
148
            5 => ['px' => 40, 'width' => 10.00000000],
149
            6 => ['px' => 48, 'width' => 9.59765625],
150
            7 => ['px' => 48, 'width' => 9.59765625],
151
            8 => ['px' => 56, 'width' => 9.33203125],
152
            9 => ['px' => 64, 'width' => 9.14062500],
153
            10 => ['px' => 64, 'width' => 9.14062500],
154
        ],
155
        'Calibri' => [
156
            1 => ['px' => 24, 'width' => 12.00000000],
157
            2 => ['px' => 24, 'width' => 12.00000000],
158
            3 => ['px' => 32, 'width' => 10.66406250],
159
            4 => ['px' => 32, 'width' => 10.66406250],
160
            5 => ['px' => 40, 'width' => 10.00000000],
161
            6 => ['px' => 48, 'width' => 9.59765625],
162
            7 => ['px' => 48, 'width' => 9.59765625],
163
            8 => ['px' => 56, 'width' => 9.33203125],
164
            9 => ['px' => 56, 'width' => 9.33203125],
165
            10 => ['px' => 64, 'width' => 9.14062500],
166
            11 => ['px' => 64, 'width' => 9.14062500],
167
        ],
168
        'Verdana' => [
169
            1 => ['px' => 24, 'width' => 12.00000000],
170
            2 => ['px' => 24, 'width' => 12.00000000],
171
            3 => ['px' => 32, 'width' => 10.66406250],
172
            4 => ['px' => 32, 'width' => 10.66406250],
173
            5 => ['px' => 40, 'width' => 10.00000000],
174
            6 => ['px' => 48, 'width' => 9.59765625],
175
            7 => ['px' => 48, 'width' => 9.59765625],
176
            8 => ['px' => 64, 'width' => 9.14062500],
177
            9 => ['px' => 72, 'width' => 9.00000000],
178
            10 => ['px' => 72, 'width' => 9.00000000],
179
        ],
180
    ];
181
182
    /**
183
     * Set autoSize method
184
     *
185
     * @param string $pValue
186
     * @return     bool                    Success or failure
187
     */
188 2
    public static function setAutoSizeMethod($pValue = self::AUTOSIZE_METHOD_APPROX)
189
    {
190 2
        if (!in_array($pValue, self::$autoSizeMethods)) {
191 1
            return false;
192
        }
193 1
        self::$autoSizeMethod = $pValue;
194
195 1
        return true;
196
    }
197
198
    /**
199
     * Get autoSize method
200
     *
201
     * @return string
202
     */
203 1
    public static function getAutoSizeMethod()
204
    {
205 1
        return self::$autoSizeMethod;
206
    }
207
208
    /**
209
     * Set the path to the folder containing .ttf files. There should be a trailing slash.
210
     * Typical locations on variout some platforms:
211
     *    <ul>
212
     *        <li>C:/Windows/Fonts/</li>
213
     *        <li>/usr/share/fonts/truetype/</li>
214
     *        <li>~/.fonts/</li>
215
     *    </ul>
216
     *
217
     * @param string $pValue
218
     */
219
    public static function setTrueTypeFontPath($pValue = '')
220
    {
221
        self::$trueTypeFontPath = $pValue;
222
    }
223
224
    /**
225
     * Get the path to the folder containing .ttf files.
226
     *
227
     * @return string
228
     */
229
    public static function getTrueTypeFontPath()
230
    {
231
        return self::$trueTypeFontPath;
232
    }
233
234
    /**
235
     * Calculate an (approximate) OpenXML column width, based on font size and text contained
236
     *
237
     * @param     \PhpSpreadsheet\Style\Font            $font            Font object
238
     * @param     \PhpSpreadsheet\RichText|string    $cellText        Text to calculate width
239
     * @param     int                        $rotation        Rotation angle
240
     * @param     \PhpSpreadsheet\Style\Font|null    $defaultFont    Font object
241
     * @return     int        Column width
242
     */
243
    public static function calculateColumnWidth(\PhpSpreadsheet\Style\Font $font, $cellText = '', $rotation = 0, \PhpSpreadsheet\Style\Font $defaultFont = null)
244
    {
245
        // If it is rich text, use plain text
246
        if ($cellText instanceof \PhpSpreadsheet\RichText) {
247
            $cellText = $cellText->getPlainText();
248
        }
249
250
        // Special case if there are one or more newline characters ("\n")
251
        if (strpos($cellText, "\n") !== false) {
252
            $lineTexts = explode("\n", $cellText);
253
            $lineWidths = [];
254
            foreach ($lineTexts as $lineText) {
255
                $lineWidths[] = self::calculateColumnWidth($font, $lineText, $rotation = 0, $defaultFont);
256
            }
257
258
            return max($lineWidths); // width of longest line in cell
259
        }
260
261
        // Try to get the exact text width in pixels
262
        $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
263
        if (!$approximate) {
264
            $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);
265
            try {
266
                // Width of text in pixels excl. padding
267
                // and addition because Excel adds some padding, just use approx width of 'n' glyph
268
                $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust;
269
            } catch (\PhpSpreadsheet\Exception $e) {
270
                $approximate = true;
271
            }
272
        }
273
274
        if ($approximate) {
275
            $columnWidthAdjust = self::getTextWidthPixelsApprox('n', $font, 0);
276
            // Width of text in pixels excl. padding, approximation
277
            // and addition because Excel adds some padding, just use approx width of 'n' glyph
278
            $columnWidth = self::getTextWidthPixelsApprox($cellText, $font, $rotation) + $columnWidthAdjust;
279
        }
280
281
        // Convert from pixel width to column width
282
        $columnWidth = Drawing::pixelsToCellDimension($columnWidth, $defaultFont);
0 ignored issues
show
Bug introduced by
The variable $columnWidth does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
It seems like $defaultFont defined by parameter $defaultFont on line 243 can be null; however, PhpSpreadsheet\Shared\Dr...pixelsToCellDimension() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
283
284
        // Return
285
        return round($columnWidth, 6);
286
    }
287
288
    /**
289
     * Get GD text width in pixels for a string of text in a certain font at a certain rotation angle
290
     *
291
     * @param string $text
292
     * @param \PhpSpreadsheet\Style\Font
293
     * @param int $rotation
294
     * @throws \PhpSpreadsheet\Exception
295
     * @return int
296
     */
297
    public static function getTextWidthPixelsExact($text, \PhpSpreadsheet\Style\Font $font, $rotation = 0)
298
    {
299
        if (!function_exists('imagettfbbox')) {
300
            throw new \PhpSpreadsheet\Exception('GD library needs to be enabled');
301
        }
302
303
        // font size should really be supplied in pixels in GD2,
304
        // but since GD2 seems to assume 72dpi, pixels and points are the same
305
        $fontFile = self::getTrueTypeFontFileFromFont($font);
306
        $textBox = imagettfbbox($font->getSize(), $rotation, $fontFile, $text);
307
308
        // Get corners positions
309
        $lowerLeftCornerX = $textBox[0];
310
        $lowerRightCornerX = $textBox[2];
311
        $upperRightCornerX = $textBox[4];
312
        $upperLeftCornerX = $textBox[6];
313
314
        // Consider the rotation when calculating the width
315
        $textWidth = max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
316
317
        return $textWidth;
318
    }
319
320
    /**
321
     * Get approximate width in pixels for a string of text in a certain font at a certain rotation angle
322
     *
323
     * @param string $columnText
324
     * @param \PhpSpreadsheet\Style\Font $font
325
     * @param int $rotation
326
     * @return int Text width in pixels (no padding added)
327
     */
328
    public static function getTextWidthPixelsApprox($columnText, \PhpSpreadsheet\Style\Font $font = null, $rotation = 0)
329
    {
330
        $fontName = $font->getName();
0 ignored issues
show
Bug introduced by
It seems like $font is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
331
        $fontSize = $font->getSize();
332
333
        // Calculate column width in pixels. We assume fixed glyph width. Result varies with font name and size.
334
        switch ($fontName) {
335 View Code Duplication
            case 'Calibri':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
                // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font.
337
                $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText));
338
                $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
339
                break;
340
341 View Code Duplication
            case 'Arial':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
342
                // value 8 was set because of experience in different exports at Arial 10 font.
343
                $columnWidth = (int) (8 * StringHelper::countCharacters($columnText));
344
                $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
345
                break;
346
347 View Code Duplication
            case 'Verdana':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
348
                // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font.
349
                $columnWidth = (int) (8 * StringHelper::countCharacters($columnText));
350
                $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
351
                break;
352
353 View Code Duplication
            default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
354
                // just assume Calibri
355
                $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText));
356
                $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
357
                break;
358
        }
359
360
        // Calculate approximate rotated column width
361
        if ($rotation !== 0) {
362
            if ($rotation == -165) {
363
                // stacked text
364
                $columnWidth = 4; // approximation
365
            } else {
366
                // rotated text
367
                $columnWidth = $columnWidth * cos(deg2rad($rotation))
368
                                + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation
369
            }
370
        }
371
372
        // pixel width is an integer
373
        return (int) $columnWidth;
374
    }
375
376
    /**
377
     * Calculate an (approximate) pixel size, based on a font points size
378
     *
379
     * @param     int        $fontSizeInPoints    Font size (in points)
380
     * @return     int        Font size (in pixels)
381
     */
382 16
    public static function fontSizeToPixels($fontSizeInPoints = 11)
383
    {
384 16
        return (int) ((4 / 3) * $fontSizeInPoints);
385
    }
386
387
    /**
388
     * Calculate an (approximate) pixel size, based on inch size
389
     *
390
     * @param     int        $sizeInInch    Font size (in inch)
391
     * @return     int        Size (in pixels)
392
     */
393 5
    public static function inchSizeToPixels($sizeInInch = 1)
394
    {
395 5
        return $sizeInInch * 96;
396
    }
397
398
    /**
399
     * Calculate an (approximate) pixel size, based on centimeter size
400
     *
401
     * @param     int        $sizeInCm    Font size (in centimeters)
402
     * @return     float        Size (in pixels)
403
     */
404 5
    public static function centimeterSizeToPixels($sizeInCm = 1)
405
    {
406 5
        return $sizeInCm * 37.795275591;
407
    }
408
409
    /**
410
     * Returns the font path given the font
411
     *
412
     * @param \PhpSpreadsheet\Style\Font $font
413
     * @return string Path to TrueType font file
414
     */
415
    public static function getTrueTypeFontFileFromFont($font)
416
    {
417
        if (!file_exists(self::$trueTypeFontPath) || !is_dir(self::$trueTypeFontPath)) {
418
            throw new \PhpSpreadsheet\Exception('Valid directory to TrueType Font files not specified');
419
        }
420
421
        $name = $font->getName();
422
        $bold = $font->getBold();
423
        $italic = $font->getItalic();
424
425
        // Check if we can map font to true type font file
426
        switch ($name) {
427
            case 'Arial':
428
                $fontFile = (
429
                    $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD)
430
                          : ($italic ? self::ARIAL_ITALIC : self::ARIAL)
431
                );
432
                break;
433
            case 'Calibri':
434
                $fontFile = (
435
                    $bold ? ($italic ? self::CALIBRI_BOLD_ITALIC : self::CALIBRI_BOLD)
436
                          : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI)
437
                );
438
                break;
439 View Code Duplication
            case 'Courier New':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
440
                $fontFile = (
441
                    $bold ? ($italic ? self::COURIER_NEW_BOLD_ITALIC : self::COURIER_NEW_BOLD)
442
                          : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW)
443
                );
444
                break;
445
            case 'Comic Sans MS':
446
                $fontFile = (
447
                    $bold ? self::COMIC_SANS_MS_BOLD : self::COMIC_SANS_MS
448
                );
449
                break;
450
            case 'Georgia':
451
                $fontFile = (
452
                    $bold ? ($italic ? self::GEORGIA_BOLD_ITALIC : self::GEORGIA_BOLD)
453
                          : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA)
454
                );
455
                break;
456
            case 'Impact':
457
                $fontFile = self::IMPACT;
458
                break;
459 View Code Duplication
            case 'Liberation Sans':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
460
                $fontFile = (
461
                    $bold ? ($italic ? self::LIBERATION_SANS_BOLD_ITALIC : self::LIBERATION_SANS_BOLD)
462
                          : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS)
463
                );
464
                break;
465
            case 'Lucida Console':
466
                $fontFile = self::LUCIDA_CONSOLE;
467
                break;
468
            case 'Lucida Sans Unicode':
469
                $fontFile = self::LUCIDA_SANS_UNICODE;
470
                break;
471
            case 'Microsoft Sans Serif':
472
                $fontFile = self::MICROSOFT_SANS_SERIF;
473
                break;
474 View Code Duplication
            case 'Palatino Linotype':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
475
                $fontFile = (
476
                    $bold ? ($italic ? self::PALATINO_LINOTYPE_BOLD_ITALIC : self::PALATINO_LINOTYPE_BOLD)
477
                          : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE)
478
                );
479
                break;
480
            case 'Symbol':
481
                $fontFile = self::SYMBOL;
482
                break;
483
            case 'Tahoma':
484
                $fontFile = (
485
                    $bold ? self::TAHOMA_BOLD : self::TAHOMA
486
                );
487
                break;
488 View Code Duplication
            case 'Times New Roman':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
489
                $fontFile = (
490
                    $bold ? ($italic ? self::TIMES_NEW_ROMAN_BOLD_ITALIC : self::TIMES_NEW_ROMAN_BOLD)
491
                          : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN)
492
                );
493
                break;
494 View Code Duplication
            case 'Trebuchet MS':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
495
                $fontFile = (
496
                    $bold ? ($italic ? self::TREBUCHET_MS_BOLD_ITALIC : self::TREBUCHET_MS_BOLD)
497
                          : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS)
498
                );
499
                break;
500 View Code Duplication
            case 'Verdana':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
501
                $fontFile = (
502
                    $bold ? ($italic ? self::VERDANA_BOLD_ITALIC : self::VERDANA_BOLD)
503
                          : ($italic ? self::VERDANA_ITALIC : self::VERDANA)
504
                );
505
                break;
506
            default:
507
                throw new \PhpSpreadsheet\Exception('Unknown font name "' . $name . '". Cannot map to TrueType font file');
508
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
509
        }
510
511
        $fontFile = self::$trueTypeFontPath . $fontFile;
512
513
        // Check if file actually exists
514
        if (!file_exists($fontFile)) {
515
            throw new \PhpSpreadsheet\Exception('TrueType Font file not found');
516
        }
517
518
        return $fontFile;
519
    }
520
521
    /**
522
     * Returns the associated charset for the font name.
523
     *
524
     * @param string $name Font name
525
     * @return int Character set code
526
     */
527
    public static function getCharsetFromFontName($name)
528
    {
529
        switch ($name) {
530
            // Add more cases. Check FONT records in real Excel files.
531
            case 'EucrosiaUPC':
532
                return self::CHARSET_ANSI_THAI;
533
            case 'Wingdings':
534
                return self::CHARSET_SYMBOL;
535
            case 'Wingdings 2':
536
                return self::CHARSET_SYMBOL;
537
            case 'Wingdings 3':
538
                return self::CHARSET_SYMBOL;
539
            default:
540
                return self::CHARSET_ANSI_LATIN;
541
        }
542
    }
543
544
    /**
545
     * Get the effective column width for columns without a column dimension or column with width -1
546
     * For example, for Calibri 11 this is 9.140625 (64 px)
547
     *
548
     * @param \PhpSpreadsheet\Style\Font $font The workbooks default font
549
     * @param bool $pPixels true = return column width in pixels, false = return in OOXML units
550
     * @return mixed Column width
551
     */
552
    public static function getDefaultColumnWidthByFont(\PhpSpreadsheet\Style\Font $font, $pPixels = false)
553
    {
554
        if (isset(self::$defaultColumnWidths[$font->getName()][$font->getSize()])) {
555
            // Exact width can be determined
556
            $columnWidth = $pPixels ?
557
                self::$defaultColumnWidths[$font->getName()][$font->getSize()]['px']
558
                    : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width'];
559
        } else {
560
            // We don't have data for this particular font and size, use approximation by
561
            // extrapolating from Calibri 11
562
            $columnWidth = $pPixels ?
563
                self::$defaultColumnWidths['Calibri'][11]['px']
564
                    : self::$defaultColumnWidths['Calibri'][11]['width'];
565
            $columnWidth = $columnWidth * $font->getSize() / 11;
566
567
            // Round pixels to closest integer
568
            if ($pPixels) {
569
                $columnWidth = (int) round($columnWidth);
570
            }
571
        }
572
573
        return $columnWidth;
574
    }
575
576
    /**
577
     * Get the effective row height for rows without a row dimension or rows with height -1
578
     * For example, for Calibri 11 this is 15 points
579
     *
580
     * @param \PhpSpreadsheet\Style\Font $font The workbooks default font
581
     * @return float Row height in points
582
     */
583
    public static function getDefaultRowHeightByFont(\PhpSpreadsheet\Style\Font $font)
584
    {
585
        switch ($font->getName()) {
586 View Code Duplication
            case 'Arial':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
587
                switch ($font->getSize()) {
588
                    case 10:
589
                        // inspection of Arial 10 workbook says 12.75pt ~17px
590
                        $rowHeight = 12.75;
591
                        break;
592
                    case 9:
593
                        // inspection of Arial 9 workbook says 12.00pt ~16px
594
                        $rowHeight = 12;
595
                        break;
596
                    case 8:
597
                        // inspection of Arial 8 workbook says 11.25pt ~15px
598
                        $rowHeight = 11.25;
599
                        break;
600
                    case 7:
601
                        // inspection of Arial 7 workbook says 9.00pt ~12px
602
                        $rowHeight = 9;
603
                        break;
604
                    case 6:
605
                    case 5:
606
                        // inspection of Arial 5,6 workbook says 8.25pt ~11px
607
                        $rowHeight = 8.25;
608
                        break;
609
                    case 4:
610
                        // inspection of Arial 4 workbook says 6.75pt ~9px
611
                        $rowHeight = 6.75;
612
                        break;
613
                    case 3:
614
                        // inspection of Arial 3 workbook says 6.00pt ~8px
615
                        $rowHeight = 6;
616
                        break;
617
                    case 2:
618
                    case 1:
619
                        // inspection of Arial 1,2 workbook says 5.25pt ~7px
620
                        $rowHeight = 5.25;
621
                        break;
622
                    default:
623
                        // use Arial 10 workbook as an approximation, extrapolation
624
                        $rowHeight = 12.75 * $font->getSize() / 10;
625
                        break;
626
                }
627
                break;
628
629 View Code Duplication
            case 'Calibri':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
630
                switch ($font->getSize()) {
631
                    case 11:
632
                        // inspection of Calibri 11 workbook says 15.00pt ~20px
633
                        $rowHeight = 15;
634
                        break;
635
                    case 10:
636
                        // inspection of Calibri 10 workbook says 12.75pt ~17px
637
                        $rowHeight = 12.75;
638
                        break;
639
                    case 9:
640
                        // inspection of Calibri 9 workbook says 12.00pt ~16px
641
                        $rowHeight = 12;
642
                        break;
643
                    case 8:
644
                        // inspection of Calibri 8 workbook says 11.25pt ~15px
645
                        $rowHeight = 11.25;
646
                        break;
647
                    case 7:
648
                        // inspection of Calibri 7 workbook says 9.00pt ~12px
649
                        $rowHeight = 9;
650
                        break;
651
                    case 6:
652
                    case 5:
653
                        // inspection of Calibri 5,6 workbook says 8.25pt ~11px
654
                        $rowHeight = 8.25;
655
                        break;
656
                    case 4:
657
                        // inspection of Calibri 4 workbook says 6.75pt ~9px
658
                        $rowHeight = 6.75;
659
                        break;
660
                    case 3:
661
                        // inspection of Calibri 3 workbook says 6.00pt ~8px
662
                        $rowHeight = 6.00;
663
                        break;
664
                    case 2:
665
                    case 1:
666
                        // inspection of Calibri 1,2 workbook says 5.25pt ~7px
667
                        $rowHeight = 5.25;
668
                        break;
669
                    default:
670
                        // use Calibri 11 workbook as an approximation, extrapolation
671
                        $rowHeight = 15 * $font->getSize() / 11;
672
                        break;
673
                }
674
                break;
675
676 View Code Duplication
            case 'Verdana':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
677
                switch ($font->getSize()) {
678
                    case 10:
679
                        // inspection of Verdana 10 workbook says 12.75pt ~17px
680
                        $rowHeight = 12.75;
681
                        break;
682
                    case 9:
683
                        // inspection of Verdana 9 workbook says 11.25pt ~15px
684
                        $rowHeight = 11.25;
685
                        break;
686
                    case 8:
687
                        // inspection of Verdana 8 workbook says 10.50pt ~14px
688
                        $rowHeight = 10.50;
689
                        break;
690
                    case 7:
691
                        // inspection of Verdana 7 workbook says 9.00pt ~12px
692
                        $rowHeight = 9.00;
693
                        break;
694
                    case 6:
695
                    case 5:
696
                        // inspection of Verdana 5,6 workbook says 8.25pt ~11px
697
                        $rowHeight = 8.25;
698
                        break;
699
                    case 4:
700
                        // inspection of Verdana 4 workbook says 6.75pt ~9px
701
                        $rowHeight = 6.75;
702
                        break;
703
                    case 3:
704
                        // inspection of Verdana 3 workbook says 6.00pt ~8px
705
                        $rowHeight = 6;
706
                        break;
707
                    case 2:
708
                    case 1:
709
                        // inspection of Verdana 1,2 workbook says 5.25pt ~7px
710
                        $rowHeight = 5.25;
711
                        break;
712
                    default:
713
                        // use Verdana 10 workbook as an approximation, extrapolation
714
                        $rowHeight = 12.75 * $font->getSize() / 10;
715
                        break;
716
                }
717
                break;
718
            default:
719
                // just use Calibri as an approximation
720
                $rowHeight = 15 * $font->getSize() / 11;
721
                break;
722
        }
723
724
        return $rowHeight;
725
    }
726
}
727