1<?php
2
3namespace Mpdf;
4
5use Psr\Log\LoggerInterface;
6use Mpdf\Log\Context as LogContext;
7
8class SizeConverter implements \Psr\Log\LoggerAwareInterface
9{
10
11	private $dpi;
12
13	private $defaultFontSize;
14
15	/**
16	 * @var \Mpdf\Mpdf
17	 */
18	private $mpdf;
19
20	/**
21	 * @var \Psr\Log\LoggerInterface
22	 */
23	private $logger;
24
25	public function __construct($dpi, $defaultFontSize, Mpdf $mpdf, LoggerInterface $logger)
26	{
27		$this->dpi = $dpi;
28		$this->defaultFontSize = $defaultFontSize;
29		$this->mpdf = $mpdf;
30		$this->logger = $logger;
31	}
32
33	public function setLogger(LoggerInterface $logger)
34	{
35		$this->logger = $logger;
36	}
37
38	/**
39	 * Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
40	 * For text $maxsize = $fontsize
41	 * Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
42	 *
43	 * @param mixed $size
44	 * @param mixed $maxsize
45	 * @param mixed $fontsize
46	 * @param mixed $usefontsize Set false for e.g. margins - will ignore fontsize for % values
47	 *
48	 * @return float Final size in mm
49	 */
50	public function convert($size = 5, $maxsize = 0, $fontsize = false, $usefontsize = true)
51	{
52		$size = trim(strtolower($size));
53		$res = preg_match('/^(?P<size>[-0-9.,]+([eE]\-?[0-9]+)?)?(?P<unit>[%a-z-]+)?$/', $size, $parts);
54		if (!$res) {
55			// ignore definition
56			$this->logger->warning(sprintf('Invalid size representation "%s"', $size), ['context' => LogContext::CSS_SIZE_CONVERSION]);
57		}
58
59		$unit = !empty($parts['unit']) ? $parts['unit'] : null;
60		$size = !empty($parts['size']) ? (float) $parts['size'] : 0.0;
61
62		switch ($unit) {
63			case 'mm':
64				// do nothing
65				break;
66
67			case 'cm':
68				$size *= 10;
69				break;
70
71			case 'pt':
72				$size *= 1 / Mpdf::SCALE;
73				break;
74
75			case 'rem':
76				$size *= $this->mpdf->default_font_size / Mpdf::SCALE;
77				break;
78
79			case '%':
80				if ($fontsize && $usefontsize) {
81					$size *= $fontsize / 100;
82				} else {
83					$size *= $maxsize / 100;
84				}
85				break;
86
87			case 'in':
88				// mm in an inch
89				$size *= 25.4;
90				break;
91
92			case 'pc':
93				// PostScript picas
94				$size *= 38.1 / 9;
95				break;
96
97			case 'ex':
98				// Approximates "ex" as half of font height
99				$size *= $this->multiplyFontSize($fontsize, $maxsize, 0.5);
100				break;
101
102			case 'em':
103				$size *= $this->multiplyFontSize($fontsize, $maxsize, 1);
104				break;
105
106			case 'thin':
107				$size = 1 * (25.4 / $this->dpi);
108				break;
109
110			case 'medium':
111				$size = 3 * (25.4 / $this->dpi);
112				// Commented-out dead code from legacy method
113				// $size *= $this->multiplyFontSize($fontsize, $maxsize, 1);
114				break;
115
116			case 'thick':
117				$size = 5 * (25.4 / $this->dpi); // 5 pixel width for table borders
118				break;
119
120			case 'xx-small':
121				$size *= $this->multiplyFontSize($fontsize, $maxsize, 0.7);
122				break;
123
124			case 'x-small':
125				$size *= $this->multiplyFontSize($fontsize, $maxsize, 0.77);
126				break;
127
128			case 'small':
129				$size *= $this->multiplyFontSize($fontsize, $maxsize, 0.86);
130				break;
131
132			case 'large':
133				$size *= $this->multiplyFontSize($fontsize, $maxsize, 1.2);
134				break;
135
136			case 'x-large':
137				$size *= $this->multiplyFontSize($fontsize, $maxsize, 1.5);
138				break;
139
140			case 'xx-large':
141				$size *= $this->multiplyFontSize($fontsize, $maxsize, 2);
142				break;
143
144			case 'px':
145			default:
146				$size *= (25.4 / $this->dpi);
147				break;
148		}
149
150		return $size;
151	}
152
153	private function multiplyFontSize($fontsize, $maxsize, $ratio)
154	{
155		if ($fontsize) {
156			return $fontsize * $ratio;
157		}
158
159		return $maxsize * $ratio;
160	}
161}
162