module Magick::RVG::Stretchable

def add_viewbox_primitives(width, height, gc)

Establish the viewbox as necessary
def add_viewbox_primitives(width, height, gc)
    @vbx_width  ||= width
    @vbx_height ||= height
    @vbx_x ||= 0.0
    @vbx_y ||= 0.0
    if @align == 'none'
        sx, sy = set_viewbox_none(width, height)
        tx, ty = 0, 0
    elsif @meet_or_slice == 'meet'
        sx, sy = set_viewbox_meet(width, height)
        tx, ty = align_to_viewport(width, height, sx, sy)
    else
        sx, sy = set_viewbox_slice(width, height)
        tx, ty = align_to_viewport(width, height, sx, sy)
    end
    # Establish clipping path around the current viewport
    name = __id__.to_s
    gc.define_clip_path(name) do
        gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
    end
    gc.clip_path(name)
    # Add a non-scaled translation if meet or slice
    gc.translate(tx, ty) if tx.abs > 1.0e-10 || ty.abs > 1.0e-10
    # Scale viewbox as necessary
    gc.scale(sx, sy) if sx != 1.0 || sy != 1.0
    # Add a scaled translation if non-0 origin
    gc.translate(-@vbx_x, -@vbx_y) if @vbx_x.abs != 0.0 || @vbx_y.abs != 0
end

def align_to_viewport(width, height, sx, sy)

Use align attribute to compute x- and y-offset from viewport's upper-left corner.
def align_to_viewport(width, height, sx, sy)
    tx = case @align
             when /\AxMin/
                 0
             when NilClass, /\AxMid/
                 (width - @vbx_width*sx) / 2.0
             when /\AxMax/
                 width - @vbx_width*sx
    end
    ty = case @align
             when /YMin\z/
                 0
             when NilClass, /YMid\z/
                 (height - @vbx_height*sy) / 2.0
             when /YMax\z/
                 height - @vbx_height*sy
    end
    [tx, ty]
end

def initialize(*args, &block)

def initialize(*args, &block)
    super()
    @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
    @meet_or_slice = 'meet'
    @align = nil
end

def set_viewbox_meet(width, height)

Scale to smaller viewbox dimension
def set_viewbox_meet(width, height)
    sx = sy = [width / @vbx_width, height / @vbx_height].min
    [sx, sy]
end

def set_viewbox_none(width, height)

Scale to fit
def set_viewbox_none(width, height)
    sx, sy = 1.0, 1.0
    if @vbx_width
        sx = width / @vbx_width
    end
    if @vbx_height
        sy = height / @vbx_height
    end
    [sx, sy]
end

def set_viewbox_slice(width, height)

Scale to larger viewbox dimension
def set_viewbox_slice(width, height)
    sx = sy = [width / @vbx_width, height / @vbx_height].max
    [sx, sy]
end

def viewbox(x, y, width, height)

arguments must be positive.
The arguments must be numbers and the +width+ and +height+
Describe a user coordinate system to be imposed on the viewbox.
def viewbox(x, y, width, height)
    begin
        @vbx_x = Float(x)
        @vbx_y = Float(y)
        @vbx_width = Float(width)
        @vbx_height = Float(height)
    rescue ArgumentError
        raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
    end
    fail(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
    fail(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0
    # return the user-coordinate space attributes if defined
    class << self
      unless defined? @redefined
        @redefined = true
        define_method(:x) { @vbx_x }
        define_method(:y) { @vbx_y }
        define_method(:width) { @vbx_width}
        define_method(:height) { @vbx_height }
      end
    end
    yield(self) if block_given?
    self
end