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