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)



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

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



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

def blend_data
  @blend_data
end

#dataString (readonly)

Returns Binary CharString data.

Returns:

  • (String)

    Binary CharString data



39
40
41
# File 'lib/fontisan/tables/cff2/charstring_parser.rb', line 39

def data
  @data
end

#num_axesInteger (readonly)

Returns Number of variation axes.

Returns:

  • (Integer)

    Number of variation axes



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

def num_axes
  @num_axes
end

#pathArray<Hash> (readonly)

Returns Parsed path commands.

Returns:

  • (Array<Hash>)

    Parsed path commands



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

def path
  @path
end

#widthInteger? (readonly)

Returns Glyph width.

Returns:

  • (Integer, nil)

    Glyph width



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

def width
  @width
end

#xFloat (readonly)

Returns Current X coordinate.

Returns:

  • (Float)

    Current X coordinate



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

def x
  @x
end

#yFloat (readonly)

Returns Current Y coordinate.

Returns:

  • (Float)

    Current Y coordinate



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

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



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

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)


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

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



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

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