Dimension.php 5.2 KB

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