| 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: | |