class TTFunk::Table::Glyf::Compound

Composite TrueType glyph.

Constants

ARG_1_AND_2_ARE_WORDS

Flags bit 0: arg1 and arg2 are words.

Component

Component glyph.

@!attribute [rw] flags

Component flag.
@return [Integer]

@!attribute [rw] glyph_index

Glyph index of component.
@return [Integer]

@!attribute [rw] arg1

x-offset for component or point number.
@return [Integer]

@!attribute [rw] arg2

y-offset for component or point number.
@return [Integer]

@!attribute [rw] transform

Transformation.
@return []
MORE_COMPONENTS

Flags bit 5: at least one more glyph after this one.

WE_HAVE_AN_X_AND_Y_SCALE

Flags bit 6: the x direction will use a different scale from the y direction.

WE_HAVE_A_SCALE

Flags bit 3: there is a simple scale for the component.

WE_HAVE_A_TWO_BY_TWO

Flags bit 7: there is a 2 by 2 transformation that will be used to scale the component.

WE_HAVE_INSTRUCTIONS

Flags bit 8: following the last component are instructions for the composite character.

Attributes

glyph_ids[R]

IDs of compound glyphs.

id[R]

Glyph ID. @return [Integer]

number_of_contours[R]

Number of contours in this glyph. @return [Integer]

raw[R]

Binary serialization of this glyph. @return [String]

x_max[R]

Maximum x for coordinate. @return [Integer]

x_min[R]

Minimum x for coordinate. @return [Integer]

y_max[R]

Maximum y for coordinate. @return [Integer]

y_min[R]

Minimum y for coordinate. @return [Integer]

Public Class Methods

new(id, raw) click to toggle source

@param id [Integer] glyph ID. @param raw [String]

# File lib/ttfunk/table/glyf/compound.rb, line 85
def initialize(id, raw)
  @id = id
  @raw = raw
  io = StringIO.new(raw)

  @number_of_contours, @x_min, @y_min, @x_max, @y_max =
    io.read(10).unpack('n*').map { |i|
      BinUtils.twos_comp_to_int(i, bit_width: 16)
    }

  # Because TTFunk only cares about glyphs insofar as they (1) provide
  # a bounding box for each glyph, and (2) can be rewritten into a
  # font subset, we don't really care about the rest of the glyph data
  # except as a whole. Thus, we don't actually decompose the glyph
  # into it's parts--all we really care about are the locations within
  # the raw string where the component glyph ids are stored, so that
  # when we rewrite this glyph into a subset we can rewrite the
  # component glyph-ids so they are correct for the subset.

  @glyph_ids = []
  @glyph_id_offsets = []
  offset = 10 # 2 bytes for each of num-contours, min x/y, max x/y

  loop do
    flags, glyph_id = @raw[offset, 4].unpack('n*')
    @glyph_ids << glyph_id
    @glyph_id_offsets << (offset + 2)

    break if (flags & MORE_COMPONENTS).zero?

    offset += 4

    offset +=
      if (flags & ARG_1_AND_2_ARE_WORDS).zero?
        2
      else
        4
      end

    if flags & WE_HAVE_A_TWO_BY_TWO != 0
      offset += 8
    elsif flags & WE_HAVE_AN_X_AND_Y_SCALE != 0
      offset += 4
    elsif flags & WE_HAVE_A_SCALE != 0
      offset += 2
    end
  end
end

Public Instance Methods

compound?() click to toggle source

Is this a composite glyph? @return [true]

# File lib/ttfunk/table/glyf/compound.rb, line 136
def compound?
  true
end
recode(mapping) click to toggle source

Recode glyph.

@param mapping [Hash{Integer => Integer}] a hash mapping old glyph IDs

to new glyph IDs.

@return [String]

# File lib/ttfunk/table/glyf/compound.rb, line 145
def recode(mapping)
  result = raw.dup
  new_ids = glyph_ids.map { |id| mapping[id] }

  new_ids.zip(@glyph_id_offsets).each do |new_id, offset|
    result[offset, 2] = [new_id].pack('n')
  end

  result
end