Class: Fontisan::Variation::VariationContext

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/variation/variation_context.rb

Overview

Provides shared context for variation operations

This class centralizes the initialization of common variation components (axes, interpolator, region matcher) that are needed by most variation operations. It ensures consistent initialization and validation.

Examples:

Creating a variation context

context = VariationContext.new(font)
context.validate!
puts "Axes: #{context.axes.map(&:axis_tag)}"

Using in a variation class

class MyGenerator
  def initialize(font)
    @context = VariationContext.new(font)
    @context.validate!
  end

  def generate
    @context.interpolator.normalize_coordinate(value, "wght")
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(font) ⇒ VariationContext

Initialize variation context

Loads fvar table and initializes all common variation components. Does not validate - call validate! explicitly if needed.

Parameters:



52
53
54
55
56
57
58
# File 'lib/fontisan/variation/variation_context.rb', line 52

def initialize(font)
  @font = font
  @fvar = font.has_table?("fvar") ? font.table("fvar") : nil
  @axes = @fvar ? @fvar.axes : []
  @interpolator = Interpolator.new(@axes)
  @region_matcher = RegionMatcher.new(@axes)
end

Instance Attribute Details

#axesArray<VariationAxisRecord> (readonly)

Returns Variation axes.

Returns:

  • (Array<VariationAxisRecord>)

    Variation axes



38
39
40
# File 'lib/fontisan/variation/variation_context.rb', line 38

def axes
  @axes
end

#fontTrueTypeFont, OpenTypeFont (readonly)

Returns Font instance.

Returns:



32
33
34
# File 'lib/fontisan/variation/variation_context.rb', line 32

def font
  @font
end

#fvarFvar? (readonly)

Returns fvar table.

Returns:

  • (Fvar, nil)

    fvar table



35
36
37
# File 'lib/fontisan/variation/variation_context.rb', line 35

def fvar
  @fvar
end

#interpolatorInterpolator (readonly)

Returns Coordinate interpolator.

Returns:



41
42
43
# File 'lib/fontisan/variation/variation_context.rb', line 41

def interpolator
  @interpolator
end

#region_matcherRegionMatcher (readonly)

Returns Region matcher.

Returns:



44
45
46
# File 'lib/fontisan/variation/variation_context.rb', line 44

def region_matcher
  @region_matcher
end

Instance Method Details

#axis_countInteger

Get number of axes

Returns:

  • (Integer)

    Axis count



98
99
100
# File 'lib/fontisan/variation/variation_context.rb', line 98

def axis_count
  @axes.length
end

#axis_tagsArray<String>

Get axis tags

Returns:

  • (Array<String>)

    Array of axis tags



117
118
119
# File 'lib/fontisan/variation/variation_context.rb', line 117

def axis_tags
  @axes.map(&:axis_tag)
end

#default_coordinatesHash<String, Float>

Get default coordinates

Returns coordinates at default values for all axes.

Returns:

  • (Hash<String, Float>)

    Default coordinates



160
161
162
163
164
165
166
# File 'lib/fontisan/variation/variation_context.rb', line 160

def default_coordinates
  coordinates = {}
  @axes.each do |axis|
    coordinates[axis.axis_tag] = axis.default_value
  end
  coordinates
end

#find_axis(axis_tag) ⇒ VariationAxisRecord?

Find axis by tag

Examples:

Find weight axis

wght_axis = context.find_axis("wght")
puts "Range: #{wght_axis.min_value} - #{wght_axis.max_value}"

Parameters:

  • axis_tag (String)

    Axis tag (e.g., “wght”, “wdth”)

Returns:

  • (VariationAxisRecord, nil)

    Axis or nil if not found



110
111
112
# File 'lib/fontisan/variation/variation_context.rb', line 110

def find_axis(axis_tag)
  @axes.find { |axis| axis.axis_tag == axis_tag }
end

#has_glyph_variations?Boolean

Check if font has glyph variations

Returns:

  • (Boolean)

    True if gvar or CFF2 present



197
198
199
# File 'lib/fontisan/variation/variation_context.rb', line 197

def has_glyph_variations?
  @font.has_table?("gvar") || @font.has_table?("CFF2")
end

#has_metrics_variations?Boolean

Check if font has metrics variations

Returns:

  • (Boolean)

    True if HVAR, VVAR, or MVAR present



204
205
206
207
208
# File 'lib/fontisan/variation/variation_context.rb', line 204

def has_metrics_variations?
  @font.has_table?("HVAR") ||
    @font.has_table?("VVAR") ||
    @font.has_table?("MVAR")
end

#normalize_coordinates(coordinates) ⇒ Hash<String, Float>

Normalize coordinates to [-1, 1] range

Convenience method that delegates to interpolator.

Parameters:

  • coordinates (Hash<String, Float>)

    User-space coordinates

Returns:

  • (Hash<String, Float>)

    Normalized coordinates



174
175
176
# File 'lib/fontisan/variation/variation_context.rb', line 174

def normalize_coordinates(coordinates)
  @interpolator.normalize_coordinates(coordinates)
end

#validate!void

This method returns an undefined value.

Validate that font is a proper variable font

Checks for fvar table and axes definition. Raises errors if font is not a valid variable font.

Examples:

Validate before processing

context = VariationContext.new(font)
context.validate!
# Safe to proceed

Raises:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/fontisan/variation/variation_context.rb', line 73

def validate!
  unless @fvar
    raise MissingVariationTableError.new(
      table: "fvar",
      message: "Font is not a variable font (missing fvar table)",
    )
  end

  if @axes.empty?
    raise InvalidVariationDataError.new(
      message: "Variable font has no axes defined in fvar table",
    )
  end
end

#validate_coordinates(coordinates) ⇒ void

This method returns an undefined value.

Validate coordinates against axes

Checks that all coordinate values are within valid axis ranges.

Examples:

Validate coordinates

context.validate_coordinates({ "wght" => 700 })

Parameters:

  • coordinates (Hash<String, Float>)

    Design space coordinates

Raises:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/fontisan/variation/variation_context.rb', line 131

def validate_coordinates(coordinates)
  coordinates.each do |axis_tag, value|
    axis = find_axis(axis_tag)

    unless axis
      raise InvalidCoordinatesError.new(
        axis: axis_tag,
        value: value,
        range: [],
        message: "Unknown axis '#{axis_tag}'",
      )
    end

    if value < axis.min_value || value > axis.max_value
      raise InvalidCoordinatesError.new(
        axis: axis_tag,
        value: value,
        range: [axis.min_value, axis.max_value],
        message: "Coordinate #{value} for axis '#{axis_tag}' outside valid range [#{axis.min_value}, #{axis.max_value}]",
      )
    end
  end
end

#variable_font?Boolean

Check if font is a variable font

Returns:

  • (Boolean)

    True if fvar table exists



91
92
93
# File 'lib/fontisan/variation/variation_context.rb', line 91

def variable_font?
  !@fvar.nil?
end

#variation_typeSymbol

Get variation type

Determines whether font uses TrueType (gvar) or PostScript (CFF2) variation format.

Returns:

  • (Symbol)

    :truetype, :postscript, or :none



184
185
186
187
188
189
190
191
192
# File 'lib/fontisan/variation/variation_context.rb', line 184

def variation_type
  if @font.has_table?("CFF2")
    :postscript
  elsif @font.has_table?("gvar")
    :truetype
  else
    :none
  end
end