Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.27% covered (warning)
84.27%
75 / 89
66.67% covered (warning)
66.67%
6 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Tree_Dimension
84.27% covered (warning)
84.27%
75 / 89
66.67% covered (warning)
66.67%
6 / 9
52.88
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 accept
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toColor
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 genCSS
70.59% covered (warning)
70.59%
12 / 17
0.00% covered (danger)
0.00%
0 / 1
15.66
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 operate
85.71% covered (warning)
85.71%
24 / 28
0.00% covered (danger)
0.00%
0 / 1
12.42
 compare
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 unify
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 convertTo
79.17% covered (warning)
79.17%
19 / 24
0.00% covered (danger)
0.00%
0 / 1
9.73
1<?php
2declare( strict_types = 1 );
3
4/**
5 * @private
6 * @see less-2.5.3.js#Dimension.prototype
7 */
8class Less_Tree_Dimension extends Less_Tree implements Less_Tree_HasValueProperty {
9
10    /** @var float */
11    public $value;
12    /** @var Less_Tree_Unit */
13    public $unit;
14
15    public function __construct( $value, $unit = null ) {
16        $this->value = floatval( $value );
17
18        if ( $unit instanceof Less_Tree_Unit ) {
19            $this->unit = $unit;
20        } elseif ( $unit ) {
21            $this->unit = new Less_Tree_Unit( [ $unit ] );
22        } else {
23            $this->unit = new Less_Tree_Unit();
24        }
25    }
26
27    public function accept( $visitor ) {
28        $this->unit = $visitor->visitObj( $this->unit );
29    }
30
31    public function toColor() {
32        return new Less_Tree_Color( [ $this->value, $this->value, $this->value ] );
33    }
34
35    /**
36     * @see Less_Tree::genCSS
37     */
38    public function genCSS( $output ) {
39        if ( Less_Parser::$options['strictUnits'] && !$this->unit->isSingular() ) {
40            throw new Less_Exception_Compiler(
41                "Multiple units in dimension. Correct the units or use the unit function. Bad unit: " . $this->unit->toString()
42            );
43        }
44
45        $value = $this->fround( $this->value );
46        $strValue = (string)$value;
47
48        if ( $value !== 0 && $value < 0.000001 && $value > -0.000001 ) {
49            // would be output 1e-6 etc.
50            $strValue = number_format( (float)$strValue, 10 );
51            $strValue = preg_replace( '/\.?0+$/', '', $strValue );
52        }
53
54        if ( Less_Parser::$options['compress'] ) {
55            // Zero values doesn't need a unit
56            if ( $value === 0 && $this->unit->isLength() ) {
57                $output->add( $strValue );
58                return;
59            }
60
61            // Float values doesn't need a leading zero
62            if ( $value > 0 && $value < 1 && $strValue[0] === '0' ) {
63                $strValue = substr( $strValue, 1 );
64            }
65        }
66
67        $output->add( $strValue );
68        $this->unit->genCSS( $output );
69    }
70
71    public function __toString() {
72        return $this->toCSS();
73    }
74
75    // In an operation between two Dimensions,
76    // we default to the first Dimension's unit,
77    // so `1px + 2em` will yield `3px`.
78
79    /**
80     * @param string $op
81     * @param self $other
82     */
83    public function operate( $op, $other ) {
84        $value = $this->_operate( $op, $this->value, $other->value );
85        $unit = $this->unit->clone();
86
87        if ( $op === '+' || $op === '-' ) {
88            if ( !$unit->numerator && !$unit->denominator ) {
89                $unit = $other->unit->clone();
90                if ( $this->unit->backupUnit ) {
91                    $unit->backupUnit = $this->unit->backupUnit;
92                }
93            } elseif ( !$other->unit->numerator && !$other->unit->denominator ) {
94                // do nothing
95            } else {
96                $other = $other->convertTo( $this->unit->usedUnits() );
97
98                if ( Less_Parser::$options['strictUnits'] && $other->unit->toString() !== $unit->toCSS() ) {
99                    throw new Less_Exception_Compiler(
100                        "Incompatible units. Change the units or use the unit function. Bad units: '" .
101                            $unit->toString() . "' and " . $other->unit->toString() . "'."
102                    );
103                }
104
105                $value = $this->_operate( $op, $this->value, $other->value );
106            }
107        } elseif ( $op === '*' ) {
108            $unit->numerator = array_merge( $unit->numerator, $other->unit->numerator );
109            $unit->denominator = array_merge( $unit->denominator, $other->unit->denominator );
110            sort( $unit->numerator );
111            sort( $unit->denominator );
112            $unit->cancel();
113        } elseif ( $op === '/' ) {
114            $unit->numerator = array_merge( $unit->numerator, $other->unit->denominator );
115            $unit->denominator = array_merge( $unit->denominator, $other->unit->numerator );
116            sort( $unit->numerator );
117            sort( $unit->denominator );
118            $unit->cancel();
119        }
120        return new self( $value, $unit );
121    }
122
123    /**
124     * @param Less_Tree $other
125     * @return int|null
126     * @see less-2.5.3.js#Dimension.prototype.compare
127     */
128    public function compare( $other ) {
129        if ( !$other instanceof self ) {
130            return null;
131        }
132
133        if ( $this->unit->isEmpty() || $other->unit->isEmpty() ) {
134            $a = $this;
135            $b = $other;
136        } else {
137            $a = $this->unify();
138            $b = $other->unify();
139            if ( $a->unit->compare( $b->unit ) !== 0 ) {
140                return null;
141            }
142        }
143
144        return Less_Tree::numericCompare( $a->value, $b->value );
145    }
146
147    public function unify() {
148        return $this->convertTo( [ 'length' => 'px', 'duration' => 's', 'angle' => 'rad' ] );
149    }
150
151    public function convertTo( $conversions ) {
152        $value = $this->value;
153        $unit = $this->unit->clone();
154
155        if ( is_string( $conversions ) ) {
156            $derivedConversions = [];
157            foreach ( Less_Tree_UnitConversions::$groups as $i ) {
158                if ( isset( Less_Tree_UnitConversions::${$i}[$conversions] ) ) {
159                    $derivedConversions = [ $i => $conversions ];
160                }
161            }
162            $conversions = $derivedConversions;
163        }
164
165        foreach ( $conversions as $groupName => $targetUnit ) {
166            $group = Less_Tree_UnitConversions::${$groupName};
167
168            // numerator
169            foreach ( $unit->numerator as $i => $atomicUnit ) {
170                $atomicUnit = $unit->numerator[$i];
171                if ( !isset( $group[$atomicUnit] ) ) {
172                    continue;
173                }
174
175                $value *= $group[$atomicUnit] / $group[$targetUnit];
176
177                $unit->numerator[$i] = $targetUnit;
178            }
179
180            // denominator
181            foreach ( $unit->denominator as $i => $atomicUnit ) {
182                $atomicUnit = $unit->denominator[$i];
183                if ( !isset( $group[$atomicUnit] ) ) {
184                    continue;
185                }
186
187                $value /= $group[$atomicUnit] / $group[$targetUnit];
188
189                $unit->denominator[$i] = $targetUnit;
190            }
191        }
192
193        $unit->cancel();
194
195        return new self( $value, $unit );
196    }
197}