1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
# frozen_string_literal: true
require_relative '../../reader'
module TTFunk
class Table
class Glyf
# Composite TrueType glyph.
class Compound
include Reader
# Flags bit 0: arg1 and arg2 are words.
ARG_1_AND_2_ARE_WORDS = 0x0001
# Flags bit 3: there is a simple scale for the component.
WE_HAVE_A_SCALE = 0x0008
# Flags bit 5: at least one more glyph after this one.
MORE_COMPONENTS = 0x0020
# Flags bit 6: the x direction will use a different scale from the
# y direction.
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040
# Flags bit 7: there is a 2 by 2 transformation that will be used to
# scale the component.
WE_HAVE_A_TWO_BY_TWO = 0x0080
# Flags bit 8: following the last component are instructions for the
# composite character.
WE_HAVE_INSTRUCTIONS = 0x0100
# Glyph ID.
# @return [Integer]
attr_reader :id
# Binary serialization of this glyph.
# @return [String]
attr_reader :raw
# Number of contours in this glyph.
# @return [Integer]
attr_reader :number_of_contours
# Minimum x for coordinate.
# @return [Integer]
attr_reader :x_min
# Minimum y for coordinate.
# @return [Integer]
attr_reader :y_min
# Maximum x for coordinate.
# @return [Integer]
attr_reader :x_max
# Maximum y for coordinate.
# @return [Integer]
attr_reader :y_max
# IDs of compound glyphs.
attr_reader :glyph_ids
# 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 []
Component = Struct.new(:flags, :glyph_index, :arg1, :arg2, :transform)
# @param id [Integer] glyph ID.
# @param raw [String]
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
# Is this a composite glyph?
# @return [true]
def compound?
true
end
# Recode glyph.
#
# @param mapping [Hash{Integer => Integer}] a hash mapping old glyph IDs
# to new glyph IDs.
# @return [String]
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
end
end
end
end
|