Dimension.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. }