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 = 0
    ty = 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)

def initialize(*_args)
  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 = 1.0
  sy = 1.0
  sx = width / @vbx_width if @vbx_width
  sy = height / @vbx_height if @vbx_height
  [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
  raise(ArgumentError, "viewbox width must be > 0 (#{@vbx_width} given)") unless @vbx_width >= 0
  raise(ArgumentError, "viewbox height must be > 0 (#{@vbx_height} given)") unless @vbx_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