lib/sass/script/value/number.rb in sass-3.3.14 vs lib/sass/script/value/number.rb in sass-3.4.0.rc.1

- old
+ new

@@ -445,28 +445,74 @@ @numerator_units.delete_at(@numerator_units.index(u)) end end end - # A hash of unit names to their index in the conversion table - CONVERTABLE_UNITS = %w(in cm pc mm pt px).inject({}) {|m, v| m[v] = m.size; m} + # This is the source data for all the unit logic. It's pre-processed to make + # it efficient to figure out whether a set of units is mutually compatible + # and what the conversion ratio is between two units. + # + # These come from http://www.w3.org/TR/2012/WD-css3-values-20120308/. + relative_sizes = [ + { + 'in' => Rational(1), + 'cm' => Rational(1, 2.54), + 'pc' => Rational(1, 6), + 'mm' => Rational(1, 25.4), + 'pt' => Rational(1, 72), + 'px' => Rational(1, 96) + }, + { + 'deg' => Rational(1, 360), + 'grad' => Rational(1, 400), + 'rad' => Rational(1, 2 * Math::PI), + 'turn' => Rational(1) + }, + { + 's' => Rational(1), + 'ms' => Rational(1, 1000) + }, + { + 'Hz' => Rational(1), + 'kHz' => Rational(1000) + }, + { + 'dpi' => Rational(1), + 'dpcm' => Rational(1, 2.54), + 'dppx' => Rational(1, 96) + } + ] - # in cm pc mm pt px - CONVERSION_TABLE = [[1, 2.54, 6, 25.4, 72 , 96], # in - [nil, 1, 2.36220473, 10, 28.3464567, 37.795275591], # cm - [nil, nil, 1, 4.23333333, 12 , 16], # pc - [nil, nil, nil, 1, 2.83464567, 3.7795275591], # mm - [nil, nil, nil, nil, 1 , 1.3333333333], # pt - [nil, nil, nil, nil, nil , 1]] # px + # A hash from each known unit to the set of units that it's mutually + # convertible with. + MUTUALLY_CONVERTIBLE = {} + relative_sizes.map do |values| + set = values.keys.to_set + values.keys.each {|name| MUTUALLY_CONVERTIBLE[name] = set} + end + # A two-dimensional hash from two units to the conversion ratio between + # them. Multiply `X` by `CONVERSION_TABLE[X][Y]` to convert it to `Y`. + CONVERSION_TABLE = {} + relative_sizes.each do |values| + values.each do |(name1, value1)| + CONVERSION_TABLE[name1] ||= {} + values.each do |(name2, value2)| + value = value1 / value2 + CONVERSION_TABLE[name1][name2] = value.denominator == 1 ? value.to_i : value.to_f + end + end + end + def conversion_factor(from_unit, to_unit) - res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]] - return 1.0 / conversion_factor(to_unit, from_unit) if res.nil? - res + CONVERSION_TABLE[from_unit][to_unit] end def convertable?(units) - Array(units).all? {|u| CONVERTABLE_UNITS.include?(u)} + units = Array(units).to_set + return true if units.empty? + return false unless (mutually_convertible = MUTUALLY_CONVERTIBLE[units.first]) + units.subset?(mutually_convertible) end def sans_common_units(units1, units2) units2 = units2.dup # Can't just use -, because we want px*px to coerce properly to px*mm