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