1: | <?php
|
2: |
|
3: | |
4: | |
5: | |
6: |
|
7: | class HTMLPurifier_UnitConverter
|
8: | {
|
9: |
|
10: | const ENGLISH = 1;
|
11: | const METRIC = 2;
|
12: | const DIGITAL = 3;
|
13: |
|
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: |
|
23: | protected static $units = array(
|
24: | self::ENGLISH => array(
|
25: | 'px' => 3,
|
26: | 'pt' => 4,
|
27: | 'pc' => 48,
|
28: | 'in' => 288,
|
29: | self::METRIC => array('pt', '0.352777778', 'mm'),
|
30: | ),
|
31: | self::METRIC => array(
|
32: | 'mm' => 1,
|
33: | 'cm' => 10,
|
34: | self::ENGLISH => array('mm', '2.83464567', 'pt'),
|
35: | ),
|
36: | );
|
37: |
|
38: | |
39: | |
40: | |
41: |
|
42: | protected $outputPrecision;
|
43: |
|
44: | |
45: | |
46: | |
47: |
|
48: | protected $internalPrecision;
|
49: |
|
50: | |
51: | |
52: | |
53: |
|
54: | private $bcmath;
|
55: |
|
56: | public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false)
|
57: | {
|
58: | $this->outputPrecision = $output_precision;
|
59: | $this->internalPrecision = $internal_precision;
|
60: | $this->bcmath = !$force_no_bcmath && function_exists('bcmul');
|
61: | }
|
62: |
|
63: | |
64: | |
65: | |
66: | |
67: | |
68: | |
69: | |
70: | |
71: | |
72: | |
73: | |
74: | |
75: | |
76: | |
77: | |
78: | |
79: | |
80: | |
81: |
|
82: | public function convert($length, $to_unit)
|
83: | {
|
84: | if (!$length->isValid()) {
|
85: | return false;
|
86: | }
|
87: |
|
88: | $n = $length->getN();
|
89: | $unit = $length->getUnit();
|
90: |
|
91: | if ($n === '0' || $unit === false) {
|
92: | return new HTMLPurifier_Length('0', false);
|
93: | }
|
94: |
|
95: | $state = $dest_state = false;
|
96: | foreach (self::$units as $k => $x) {
|
97: | if (isset($x[$unit])) {
|
98: | $state = $k;
|
99: | }
|
100: | if (isset($x[$to_unit])) {
|
101: | $dest_state = $k;
|
102: | }
|
103: | }
|
104: | if (!$state || !$dest_state) {
|
105: | return false;
|
106: | }
|
107: |
|
108: |
|
109: |
|
110: | $sigfigs = $this->getSigFigs($n);
|
111: | if ($sigfigs < $this->outputPrecision) {
|
112: | $sigfigs = $this->outputPrecision;
|
113: | }
|
114: |
|
115: |
|
116: |
|
117: |
|
118: |
|
119: | $log = (int)floor(log(abs($n), 10));
|
120: | $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision;
|
121: |
|
122: | for ($i = 0; $i < 2; $i++) {
|
123: |
|
124: |
|
125: | if ($dest_state === $state) {
|
126: |
|
127: | $dest_unit = $to_unit;
|
128: | } else {
|
129: |
|
130: | $dest_unit = self::$units[$state][$dest_state][0];
|
131: | }
|
132: |
|
133: |
|
134: | if ($dest_unit !== $unit) {
|
135: | $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp);
|
136: | $n = $this->mul($n, $factor, $cp);
|
137: | $unit = $dest_unit;
|
138: | }
|
139: |
|
140: |
|
141: | if ($n === '') {
|
142: | $n = '0';
|
143: | $unit = $to_unit;
|
144: | break;
|
145: | }
|
146: |
|
147: |
|
148: | if ($dest_state === $state) {
|
149: | break;
|
150: | }
|
151: |
|
152: | if ($i !== 0) {
|
153: |
|
154: |
|
155: | return false;
|
156: | }
|
157: |
|
158: |
|
159: |
|
160: |
|
161: | $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp);
|
162: | $unit = self::$units[$state][$dest_state][2];
|
163: | $state = $dest_state;
|
164: |
|
165: |
|
166: |
|
167: | }
|
168: |
|
169: |
|
170: | if ($unit !== $to_unit) {
|
171: | return false;
|
172: | }
|
173: |
|
174: |
|
175: |
|
176: |
|
177: |
|
178: | $n = $this->round($n, $sigfigs);
|
179: | if (strpos($n, '.') !== false) {
|
180: | $n = rtrim($n, '0');
|
181: | }
|
182: | $n = rtrim($n, '.');
|
183: |
|
184: | return new HTMLPurifier_Length($n, $unit);
|
185: | }
|
186: |
|
187: | |
188: | |
189: | |
190: | |
191: |
|
192: | public function getSigFigs($n)
|
193: | {
|
194: | $n = ltrim($n, '0+-');
|
195: | $dp = strpos($n, '.');
|
196: | if ($dp === false) {
|
197: | $sigfigs = strlen(rtrim($n, '0'));
|
198: | } else {
|
199: | $sigfigs = strlen(ltrim($n, '0.'));
|
200: | if ($dp !== 0) {
|
201: | $sigfigs--;
|
202: | }
|
203: | }
|
204: | return $sigfigs;
|
205: | }
|
206: |
|
207: | |
208: | |
209: | |
210: | |
211: | |
212: | |
213: |
|
214: | private function add($s1, $s2, $scale)
|
215: | {
|
216: | if ($this->bcmath) {
|
217: | return bcadd($s1, $s2, $scale);
|
218: | } else {
|
219: | return $this->scale((float)$s1 + (float)$s2, $scale);
|
220: | }
|
221: | }
|
222: |
|
223: | |
224: | |
225: | |
226: | |
227: | |
228: | |
229: |
|
230: | private function mul($s1, $s2, $scale)
|
231: | {
|
232: | if ($this->bcmath) {
|
233: | return bcmul($s1, $s2, $scale);
|
234: | } else {
|
235: | return $this->scale((float)$s1 * (float)$s2, $scale);
|
236: | }
|
237: | }
|
238: |
|
239: | |
240: | |
241: | |
242: | |
243: | |
244: | |
245: |
|
246: | private function div($s1, $s2, $scale)
|
247: | {
|
248: | if ($this->bcmath) {
|
249: | return bcdiv($s1, $s2, $scale);
|
250: | } else {
|
251: | return $this->scale((float)$s1 / (float)$s2, $scale);
|
252: | }
|
253: | }
|
254: |
|
255: | |
256: | |
257: | |
258: | |
259: | |
260: | |
261: |
|
262: | private function round($n, $sigfigs)
|
263: | {
|
264: | $new_log = (int)floor(log(abs($n), 10));
|
265: | $rp = $sigfigs - $new_log - 1;
|
266: | $neg = $n < 0 ? '-' : '';
|
267: | if ($this->bcmath) {
|
268: | if ($rp >= 0) {
|
269: | $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1);
|
270: | $n = bcdiv($n, '1', $rp);
|
271: | } else {
|
272: |
|
273: |
|
274: | $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0);
|
275: | $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1);
|
276: | }
|
277: | return $n;
|
278: | } else {
|
279: | return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1);
|
280: | }
|
281: | }
|
282: |
|
283: | |
284: | |
285: | |
286: | |
287: | |
288: |
|
289: | private function scale($r, $scale)
|
290: | {
|
291: | if ($scale < 0) {
|
292: |
|
293: |
|
294: | $r = sprintf('%.0f', (float)$r);
|
295: |
|
296: |
|
297: |
|
298: |
|
299: | $precise = (string)round(substr($r, 0, strlen($r) + $scale), -1);
|
300: |
|
301: | return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
|
302: | }
|
303: | return sprintf('%.' . $scale . 'f', (float)$r);
|
304: | }
|
305: | }
|
306: |
|
307: |
|
308: | |