Class: Fontisan::Tables::Cff2::CharstringParser

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/tables/cff2/charstring_parser.rb

Overview

Type 2 CharString parser for CFF2 (variable fonts)

CFF2 CharStrings extend Type 2 CharStrings with the blend operator for variation support. The blend operator applies variation deltas to base values based on design space coordinates.

Blend Operator (operator 16):

  • Takes N*K+1 operands where:

    • N = number of design variation axes

    • K = number of values to blend

  • Format: [v1, Δv1_axis1, Δv1_axis2, …, v2, Δv2_axis1, …, K, N, blend]

  • Produces K blended values on the stack

Example for 2 axes (wght, wdth) blending 3 values:

Input: [100, 10, 5, 200, 20, 10, 50, 5, 2, 3, 2, blend]
- v1=100 with deltas [10, 5]
- v2=200 with deltas [20, 10]
- v3=50 with deltas [5, 2]
- K=3 (number of values), N=2 (number of axes)

Reference: Adobe Technical Note #5177 (CFF2 specification)

Examples:

Parsing a CFF2 CharString with blend

parser = Fontisan::Tables::Cff2::CharstringParser.new(
  data, num_axes, variation_store
)
charstring = parser.parse
puts charstring.path
puts charstring.blend_data

Constant Summary collapse

BLEND_OPERATOR =

CFF2-specific operators

16

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, num_axes = 0, global_subrs = nil, local_subrs = nil, vsindex = 0) ⇒ CharstringParser

Initialize parser

Parameters:

  • data (String)

    Binary CharString data

  • num_axes (Integer) (defaults to: 0)

    Number of variation axes (from fvar)

  • global_subrs (Cff::Index, nil) (defaults to: nil)

    Global subroutines INDEX

  • local_subrs (Cff::Index, nil) (defaults to: nil)

    Local subroutines INDEX

  • vsindex (Integer) (defaults to: 0)

    Variation store index (default 0)



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 71

def initialize(data, num_axes = 0, global_subrs = nil, local_subrs = nil, vsindex = 0)
  @data = data
  @num_axes = num_axes
  @global_subrs = global_subrs
  @local_subrs = local_subrs
  @vsindex = vsindex

  @path = []
  @blend_data = []
  @x = 0.0
  @y = 0.0
  @width = nil
  @stems = 0
end

Instance Attribute Details

#blend_dataArray<Hash> (readonly)

Returns Blend operator data.

Returns:

  • (Array<Hash>)

    Blend operator data



50
51
52
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 50

def blend_data
  @blend_data
end

#dataString (readonly)

Returns Binary CharString data.

Returns:

  • (String)

    Binary CharString data



41
42
43
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 41

def data
  @data
end

#num_axesInteger (readonly)

Returns Number of variation axes.

Returns:

  • (Integer)

    Number of variation axes



44
45
46
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 44

def num_axes
  @num_axes
end

#pathArray<Hash> (readonly)

Returns Parsed path commands.

Returns:

  • (Array<Hash>)

    Parsed path commands



47
48
49
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 47

def path
  @path
end

#widthInteger? (readonly)

Returns Glyph width.

Returns:

  • (Integer, nil)

    Glyph width



59
60
61
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 59

def width
  @width
end

#xFloat (readonly)

Returns Current X coordinate.

Returns:

  • (Float)

    Current X coordinate



53
54
55
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 53

def x
  @x
end

#yFloat (readonly)

Returns Current Y coordinate.

Returns:

  • (Float)

    Current Y coordinate



56
57
58
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 56

def y
  @y
end

Instance Method Details

#blend_values(coordinates) ⇒ Array<Float>

Get blended values for a specific set of coordinates

Parameters:

  • coordinates (Hash<String, Float>)

    Axis coordinates

Returns:

  • (Array<Float>)

    Blended values



106
107
108
109
110
111
112
113
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 106

def blend_values(coordinates)
  return [] if @blend_data.empty?

  # Apply blend operations with coordinates
  @blend_data.map do |blend_op|
    apply_blend(blend_op, coordinates)
  end.flatten
end

#parseself

Parse the CharString

Returns:

  • (self)


89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 89

def parse
  return self if @parsed

  @stack = []
  @io = StringIO.new(@data)
  @io.set_encoding(Encoding::BINARY)

  parse_charstring_program

  @parsed = true
  self
end

#to_commandsArray<Array>

Convert path to drawing commands

Returns:

  • (Array<Array>)

    Array of command arrays



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 118

def to_commands
  @path.map do |cmd|
    case cmd[:type]
    when :move_to
      [:move_to, cmd[:x], cmd[:y]]
    when :line_to
      [:line_to, cmd[:x], cmd[:y]]
    when :curve_to
      [:curve_to, cmd[:x1], cmd[:y1], cmd[:x2], cmd[:y2], cmd[:x], cmd[:y]]
    end
  end
end