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:



49
50
51
52
53
54
55
# File 'lib/fontisan/variation/variation_context.rb', line 49

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



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

def axes
  @axes
end

#fontTrueTypeFont, OpenTypeFont (readonly)

Returns Font instance.

Returns:



29
30
31
# File 'lib/fontisan/variation/variation_context.rb', line 29

def font
  @font
end

#fvarFvar? (readonly)

Returns fvar table.

Returns:

  • (Fvar, nil)

    fvar table



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

def fvar
  @fvar
end

#interpolatorInterpolator (readonly)

Returns Coordinate interpolator.

Returns:



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

def interpolator
  @interpolator
end

#region_matcherRegionMatcher (readonly)

Returns Region matcher.

Returns:



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

def region_matcher
  @region_matcher
end

Instance Method Details

#axis_countInteger

Get number of axes

Returns:

  • (Integer)

    Axis count



95
96
97
# File 'lib/fontisan/variation/variation_context.rb', line 95

def axis_count
  @axes.length
end

#axis_tagsArray<String>

Get axis tags

Returns:

  • (Array<String>)

    Array of axis tags



114
115
116
# File 'lib/fontisan/variation/variation_context.rb', line 114

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



157
158
159
160
161
162
163
# File 'lib/fontisan/variation/variation_context.rb', line 157

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



107
108
109
# File 'lib/fontisan/variation/variation_context.rb', line 107

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



194
195
196
# File 'lib/fontisan/variation/variation_context.rb', line 194

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



201
202
203
204
205
# File 'lib/fontisan/variation/variation_context.rb', line 201

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



171
172
173
# File 'lib/fontisan/variation/variation_context.rb', line 171

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:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/fontisan/variation/variation_context.rb', line 70

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:



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

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



88
89
90
# File 'lib/fontisan/variation/variation_context.rb', line 88

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



181
182
183
184
185
186
187
188
189
# File 'lib/fontisan/variation/variation_context.rb', line 181

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