Class: Fontisan::Tables::CompoundGlyph

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/tables/glyf/compound_glyph.rb

Overview

Represents a compound TrueType glyph composed of other glyphs

A compound glyph is built by referencing other glyphs (components) and applying transformations to them. Each component references another glyph by ID and specifies positioning and optional scaling, rotation, or affine transformation.

The glyph structure consists of:

  • Header: numberOfContours (-1), xMin, yMin, xMax, yMax (10 bytes)
  • Components: array of component descriptions (variable length)
  • Instructions: optional TrueType hinting instructions

Each component has:

  • flags (uint16): component flags
  • glyphIndex (uint16): referenced glyph ID
  • arguments: positioning (arg1, arg2) - interpretation depends on flags
  • transformation: optional scale/rotation/affine matrix

Component flags (16-bit) indicate:

  • Bit 0 (0x0001): ARG_1_AND_2_ARE_WORDS - arguments are 16-bit
  • Bit 1 (0x0002): ARGS_ARE_XY_VALUES - arguments are x,y offsets
  • Bit 2 (0x0004): ROUND_XY_TO_GRID - round x,y to grid
  • Bit 3 (0x0008): WE_HAVE_A_SCALE - uniform scale follows
  • Bit 5 (0x0020): MORE_COMPONENTS - more components follow
  • Bit 6 (0x0040): WE_HAVE_AN_X_AND_Y_SCALE - separate x,y scale
  • Bit 7 (0x0080): WE_HAVE_A_TWO_BY_TWO - 2x2 affine matrix
  • Bit 8 (0x0100): WE_HAVE_INSTRUCTIONS - instructions follow components
  • Bit 9 (0x0200): USE_MY_METRICS - use this component's metrics
  • Bit 10 (0x0400): OVERLAP_COMPOUND - component outlines overlap
  • Bit 11 (0x0800): SCALED_COMPONENT_OFFSET - scale offset values
  • Bit 12 (0x1000): UNSCALED_COMPONENT_OFFSET - don't scale offsets

Reference: OpenType specification, glyf table - Compound Glyph Description https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#compound-glyph-description

Defined Under Namespace

Classes: Component

Constant Summary collapse

ARG_1_AND_2_ARE_WORDS =

Component flag constants

0x0001
ARGS_ARE_XY_VALUES =
0x0002
ROUND_XY_TO_GRID =
0x0004
WE_HAVE_A_SCALE =
0x0008
MORE_COMPONENTS =
0x0020
WE_HAVE_AN_X_AND_Y_SCALE =
0x0040
WE_HAVE_A_TWO_BY_TWO =
0x0080
WE_HAVE_INSTRUCTIONS =
0x0100
USE_MY_METRICS =
0x0200
OVERLAP_COMPOUND =
0x0400
SCALED_COMPONENT_OFFSET =
0x0800
UNSCALED_COMPONENT_OFFSET =
0x1000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(glyph_id) ⇒ CompoundGlyph

Initialize a new compound glyph

Parameters:

  • glyph_id (Integer)

    Glyph ID



135
136
137
138
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 135

def initialize(glyph_id)
  @glyph_id = glyph_id
  @components = []
end

Instance Attribute Details

#componentsObject (readonly)

Compound glyph data



118
119
120
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 118

def components
  @components
end

#glyph_idObject (readonly)

Glyph header fields



113
114
115
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 113

def glyph_id
  @glyph_id
end

#instruction_lengthObject (readonly)

Returns the value of attribute instruction_length.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def instruction_length
  @instruction_length
end

#instructionsObject (readonly)

Returns the value of attribute instructions.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def instructions
  @instructions
end

#x_maxObject (readonly)

Returns the value of attribute x_max.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def x_max
  @x_max
end

#x_minObject (readonly)

Returns the value of attribute x_min.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def x_min
  @x_min
end

#y_maxObject (readonly)

Returns the value of attribute y_max.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def y_max
  @y_max
end

#y_minObject (readonly)

Returns the value of attribute y_min.



114
115
116
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 114

def y_min
  @y_min
end

Class Method Details

.parse(data, glyph_id) ⇒ CompoundGlyph

Parse compound glyph data

Parameters:

  • data (String)

    Binary glyph data

  • glyph_id (Integer)

    Glyph ID for error reporting

Returns:

Raises:



126
127
128
129
130
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 126

def self.parse(data, glyph_id)
  glyph = new(glyph_id)
  glyph.parse_data(data)
  glyph
end

Instance Method Details

#bounding_boxArray<Integer>

Get bounding box as array

Returns:

  • (Array<Integer>)

    Bounding box [xMin, yMin, xMax, yMax]



179
180
181
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 179

def bounding_box
  [x_min, y_min, x_max, y_max]
end

#component_glyph_idsArray<Integer>

Get all component glyph IDs (for dependency tracking)

This method returns the glyph IDs of all components that make up this compound glyph. This is essential for subsetting operations, where all dependent glyphs must be included.

Examples:

Getting component dependencies

glyph = glyf.glyph_for(100, loca, head)
if glyph.compound?
  deps = glyph.component_glyph_ids
  puts "Glyph 100 depends on: #{deps.join(', ')}"
end

Returns:

  • (Array<Integer>)

    Array of component glyph IDs



197
198
199
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 197

def component_glyph_ids
  components.map(&:glyph_index)
end

#compound?Boolean

Check if this is a compound glyph

Returns:

  • (Boolean)

    Always true for CompoundGlyph



165
166
167
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 165

def compound?
  true
end

#empty?Boolean

Check if glyph has no components

Returns:

  • (Boolean)

    True if no components



172
173
174
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 172

def empty?
  components.empty?
end

#metrics_componentComponent?

Get the component that provides metrics (if any)

Returns:

  • (Component, nil)

    Component with USE_MY_METRICS flag, or nil



226
227
228
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 226

def metrics_component
  components.find(&:use_my_metrics?)
end

#num_componentsInteger

Get number of components

Returns:

  • (Integer)

    Component count



212
213
214
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 212

def num_components
  components.length
end

#parse_data(data) ⇒ Object

Parse glyph data

Parameters:

  • data (String)

    Binary glyph data

Raises:



144
145
146
147
148
149
150
151
152
153
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 144

def parse_data(data)
  io = StringIO.new(data)
  io.set_encoding(Encoding::BINARY)

  parse_header(io)
  parse_components(io)
  parse_instructions(io) if has_instructions?

  validate_parsed_data!
end

#simple?Boolean

Check if this is a simple glyph

Returns:

  • (Boolean)

    Always false for CompoundGlyph



158
159
160
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 158

def simple?
  false
end

#uses_component?(glyph_id) ⇒ Boolean

Check if glyph uses a specific component

Parameters:

  • glyph_id (Integer)

    Glyph ID to check

Returns:

  • (Boolean)

    True if glyph uses this component



205
206
207
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 205

def uses_component?(glyph_id)
  component_glyph_ids.include?(glyph_id)
end

#uses_component_metrics?Boolean

Check if any component uses metrics from referenced glyph

Returns:

  • (Boolean)

    True if any component has USE_MY_METRICS flag



219
220
221
# File 'lib/fontisan/tables/glyf/compound_glyph.rb', line 219

def uses_component_metrics?
  components.any?(&:use_my_metrics?)
end