module Compass::Core::SassExtensions::Functions::GradientSupport::Functions
Public Instance Methods
_build_linear_gradient(position_or_angle, *color_stops)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 595 def _build_linear_gradient(position_or_angle, *color_stops) if color_stop?(position_or_angle) color_stops.unshift(position_or_angle) position_or_angle = nil elsif list_of_color_stops?(position_or_angle) color_stops = position_or_angle.value + color_stops position_or_angle = nil end position_or_angle = nil if position_or_angle && !position_or_angle.to_bool # Support legacy use of the color-stops() function if color_stops.size == 1 && (stops = list_of_color_stops?(color_stops.first)) color_stops = stops end return [position_or_angle, color_stops] end
_linear_gradient(position_or_angle, *color_stops)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 612 def _linear_gradient(position_or_angle, *color_stops) position_or_angle, color_stops = _build_linear_gradient(position_or_angle, *color_stops) LinearGradient.new(position_or_angle, send(:color_stops, *color_stops)) end
_linear_gradient_legacy(position_or_angle, *color_stops)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 617 def _linear_gradient_legacy(position_or_angle, *color_stops) position_or_angle, color_stops = _build_linear_gradient(position_or_angle, *color_stops) LinearGradient.new(position_or_angle, send(:color_stops, *color_stops), true) end
color_stops(*args)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 542 def color_stops(*args) opts(list(args.map do |arg| if ColorStop === arg arg elsif Sass::Script::Value::Color === arg ColorStop.new(arg) elsif Sass::Script::Value::List === arg ColorStop.new(*arg.value) elsif Sass::Script::Value::String === arg && arg.value == "transparent" ColorStop.new(arg) elsif Sass::Script::Value::String === arg && arg.value == "currentColor" ColorStop.new(arg) else raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}" end end, :comma)) end
color_stops_in_percentages(color_list)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 630 def color_stops_in_percentages(color_list) assert_type color_list, :List color_list = normalize_stops(color_list) max = color_list.value.last.stop last_value = nil color_list.value.map do |pos| next [pos.stop, pos.color] if pos.stop.is_a?(Sass::Script::Value::String) # have to convert absolute units to percentages for use in color stop functions. stop = pos.stop stop = stop.div(max).times(number(100, "%")) if stop.numerator_units == max.numerator_units && max.numerator_units != ["%"] # Make sure the color stops are specified in the right order. if last_value && stop.numerator_units == last_value.numerator_units && stop.denominator_units == last_value.denominator_units && (stop.value * 1000).round < (last_value.value * 1000).round raise Sass::SyntaxError.new("Color stops must be specified in increasing order. #{stop.value} came after #{last_value.value}.") end last_value = stop [stop, pos.color] end end
convert_angle_from_offical(deg)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 481 def convert_angle_from_offical(deg) if deg.is_a?(Sass::Script::Value::Number) return number((deg.value.to_f - 450).abs % 360, 'deg') else args = deg.value direction = [] if args[0] == identifier('to') if args.size < 2 direction = args else direction << opposite_position(args[1]) end else direction << identifier('to') args.each do |pos| direction << opposite_position(pos) end end return opts(list(direction, :space)) end end
grad_color_stops(color_list)
click to toggle source
returns color-stop() calls for use in webkit.
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 623 def grad_color_stops(color_list) stops = color_stops_in_percentages(color_list).map do |stop, color| Sass::Script::String.new("color-stop(#{stop.to_s}, #{ColorStop.color_to_s(color)})") end opts(list(stops, :comma)) end
grad_end_position(color_list, radial = bool(false))
click to toggle source
returns the end position of the gradient from the color stop
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 673 def grad_end_position(color_list, radial = bool(false)) assert_type color_list, :List default = number(100) grad_position(color_list, number(color_list.value.size), default, radial) end
grad_point(position)
click to toggle source
given a position list, return a corresponding position in percents otherwise, returns the original argument
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 505 def grad_point(position) original_value = position position = unless position.is_a?(Sass::Script::Value::List) opts(list([position], :space)) else opts(list(position.value.dup, position.separator)) end # Handle unknown arguments by passing them along untouched. unless position.value.all?{|p| is_position(p) } return original_value end if (position.value.first.value =~ /top|bottom/) or (position.value.last.value =~ /left|right/) # browsers are pretty forgiving of reversed positions so we are too. position = opts(list(position.value.reverse, position.separator)) end if position.value.size == 1 if position.value.first.value =~ /top|bottom/ position = opts(list(identifier("center"), position.value.first, position.separator)) elsif position.value.first.value =~ /left|right/ position = opts(list(position.value.first, identifier("center"), position.separator)) end end position = opts(list(position.value.map do |p| case p.value when /top|left/ number(0, "%") when /bottom|right/ number(100, "%") when /center/ number(50, "%") else p end end, position.separator)) position end
grad_position(color_list, index, default, radial = bool(false))
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 679 def grad_position(color_list, index, default, radial = bool(false)) assert_type color_list, :List stop = color_list.value[index.value - 1].stop if stop && radial.to_bool orig_stop = stop if stop.unitless? if stop.value <= 1 # A unitless number is assumed to be a percentage when it's between 0 and 1 stop = stop.times(number(100, "%")) else # Otherwise, a unitless number is assumed to be in pixels stop = stop.times(number(1, "px")) end end if stop.numerator_units == ["%"] && color_list.value.last.stop && color_list.value.last.stop.numerator_units == ["px"] stop = stop.times(color_list.value.last.stop).div(number(100, "%")) end Compass::Logger.new.record(:warning, "Webkit only supports pixels for the start and end stops for radial gradients. Got: #{orig_stop}") if stop.numerator_units != ["px"] stop.div(Sass::Script::Value::Number.new(1, stop.numerator_units, stop.denominator_units)) elsif stop stop else default end end
linear_end_position(position_or_angle, start_point, end_target)
click to toggle source
only used for webkit
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 650 def linear_end_position(position_or_angle, start_point, end_target) end_point = grad_point(opposite_position(position_or_angle)) if end_target && end_target.numerator_units == ["px"] if start_point.value.first == end_point.value.first && start_point.value.last.value == 0 # this means top-to-bottom new_end_point = end_point.value.dup new_end_point[1] = number(end_target.value) end_point = opts(list(new_end_point, end_point.separator)) elsif start_point.value.last == end_point.value.last && start_point.value.first.value == 0 # this implies left-to-right new_end_point = end_point.value.dup new_end_point[0] = number(end_target.value) end_point = opts(list(new_end_point, end_point.separator)) end end end_point end
linear_svg_gradient(color_stops, start)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 705 def linear_svg_gradient(color_stops, start) converter = CSS3AngleToSVGConverter.new(start) stops = color_stops_in_percentages(color_stops) svg = linear_svg(stops, converter.x1, converter.y1, converter.x2, converter.y2) inline_image_string(svg.gsub(/\s+/, ' '), 'image/svg+xml') end
radial_gradient(position_or_angle, shape_and_size, *color_stops)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 560 def radial_gradient(position_or_angle, shape_and_size, *color_stops) # Have to deal with variable length/meaning arguments. if color_stop?(shape_and_size) color_stops.unshift(shape_and_size) shape_and_size = nil elsif list_of_color_stops?(shape_and_size) # Support legacy use of the color-stops() function color_stops = shape_and_size.value + color_stops shape_and_size = nil end shape_and_size = nil if shape_and_size && !shape_and_size.to_bool # nil out explictly passed falses # ditto for position_or_angle if color_stop?(position_or_angle) color_stops.unshift(position_or_angle) position_or_angle = nil elsif list_of_color_stops?(position_or_angle) color_stops = position_or_angle.value + color_stops position_or_angle = nil end position_or_angle = nil if position_or_angle && !position_or_angle.to_bool # Support legacy use of the color-stops() function if color_stops.size == 1 && list_of_color_stops?(color_stops.first) color_stops = color_stops.first.value end if position_or_angle.is_a?(Sass::Script::Value::List) && (i = position_or_angle.value.index {|word| word.is_a?(Sass::Script::Value::String) && word.value == "at"}) shape_and_size = list(position_or_angle.value[0..(i-1)], :space) shape_and_size.options = options position_or_angle = list(position_or_angle.value[(i+1)..-1], :space) position_or_angle.options = options end RadialGradient.new(position_or_angle, shape_and_size, send(:color_stops, *color_stops)) end
radial_svg_gradient(color_stops, center)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 713 def radial_svg_gradient(color_stops, center) cx, cy = *grad_point(center).value r = grad_end_position(color_stops, bool(true)) stops = color_stops_in_percentages(color_stops) svg = radial_svg(stops, cx, cy, r) inline_image_string(svg.gsub(/\s+/, ' '), 'image/svg+xml') end
reverse_side_or_corner(position)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 463 def reverse_side_or_corner(position) position_array = position.nil? ? [identifier('top')] : position.value.dup if position_array.first == identifier('to') # Remove the 'to' element from the array position_array.shift # Reverse all the positions reversed_position = position_array.map do |pos| opposite_position(pos) end else # When the position does not have the 'to' element we don't need to # reverse the direction of the gradient reversed_position = position_array end opts(list(reversed_position, :space)) end
Private Instance Methods
_center_position()
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 826 def _center_position opts(list(identifier("center"), identifier("center"), :space)) end
color_stop?(arg)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 724 def color_stop?(arg) arg.is_a?(ColorStop) || (arg.is_a?(Sass::Script::Value::List) && ColorStop.new(*arg.value)) || ColorStop.new(arg) rescue nil end
color_stops_svg(color_stops)
click to toggle source
#color_stops = array of: [stop, color]
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 809 def color_stops_svg(color_stops) color_stops.each.map{ |stop, color| s = %Q{<stop offset="#{stop.to_s}"} s << %Q{ stop-color="#{ColorStop.color_to_svg_s(color)}"} alpha = ColorStop.color_to_svg_alpha(color) s << %Q{ stop-opacity="#{alpha}"} if alpha != 1 s << "/>" }.join end
linear_svg(color_stops, x1, y1, x2, y2)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 798 def linear_svg(color_stops, x1, y1, x2, y2) gradient = %Q{<linearGradient id="grad" gradientUnits="objectBoundingBox" x1="#{x1}" y1="#{y1}" x2="#{x2}" y2="#{y2}">#{color_stops_svg(color_stops)}</linearGradient>} svg(gradient) end
list_of_color_stops?(arg)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 790 def list_of_color_stops?(arg) if arg.respond_to?(:value) arg.value.is_a?(Array) && arg.value.all?{|a| color_stop?(a)} ? arg.value : nil elsif arg.is_a?(Array) arg.all?{|a| color_stop?(a)} ? arg : nil end end
normalize_stops(color_list)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 732 def normalize_stops(color_list) positions = color_list.value.map{|obj| obj.dup} # fill in the start and end positions, if unspecified positions.first.stop = number(0) unless positions.first.stop positions.last.stop = number(100, "%") unless positions.last.stop # fill in empty values for i in 0...positions.size if positions[i].stop.nil? num = 2.0 for j in (i+1)...positions.size if positions[j].stop positions[i].stop = positions[i-1].stop.plus((positions[j].stop.minus(positions[i-1].stop)).div(number(num))) break else num += 1 end end end end # normalize unitless numbers positions.each do |pos| next pos if pos.stop.is_a?(Sass::Script::Value::String) if pos.stop.unitless? && pos.stop.value <= 1 pos.stop = pos.stop.times(number(100, "%")) elsif pos.stop.unitless? pos.stop = pos.stop.times(number(1, "px")) end end if (positions.last.stop.eq(number(0, "px")).to_bool || positions.last.stop.eq(number(0, "%")).to_bool) raise Sass::SyntaxError.new("Color stops must be specified in increasing order") end opts(list(positions, color_list.separator)) end
opts(v)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 830 def opts(v) v.options = options v end
parse_color_stop(arg)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 767 def parse_color_stop(arg) return ColorStop.new(arg) if arg.is_a?(Sass::Script::Value::Color) return nil unless arg.is_a?(Sass::Script::Value::String) color = stop = nil expr = Sass::Script::Parser.parse(arg.value, 0, 0) case expr when Sass::Script::Value::Color color = expr when Sass::Script::Tree::Funcall color = expr when Sass::Script::Tree::Operation unless [:concat, :space].include?(expr.instance_variable_get("@operator")) # This should never happen. raise Sass::SyntaxError, "Couldn't parse a color stop from: #{arg.value}" end color = expr.instance_variable_get("@operand1") stop = expr.instance_variable_get("@operand2") else raise Sass::SyntaxError, "Couldn't parse a color stop from: #{arg.value}" end ColorStop.new(color, stop) end
radial_svg(color_stops, cx, cy, r)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 803 def radial_svg(color_stops, cx, cy, r) gradient = %Q{<radialGradient id="grad" gradientUnits="userSpaceOnUse" cx="#{cx}" cy="#{cy}" r="#{r}%">#{color_stops_svg(color_stops)}</radialGradient>} svg(gradient) end
svg(gradient)
click to toggle source
# File lib/compass/core/sass_extensions/functions/gradient_support.rb, line 819 def svg(gradient) svg = <<-EOS <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>#{gradient}</defs><rect x="0" y="0" width="100%" height="100%" fill="url(#grad)" /></svg> EOS end