This commit is contained in:
treeform 2021-09-03 08:33:15 -07:00
parent 692c91283d
commit 7b5ef3c87a

View file

@ -1,4 +1,5 @@
import flatty/binny, math, pixie/common, pixie/paths, sets, tables, unicode, vmath import flatty/binny, math, pixie/common, pixie/paths, sets, tables, unicode,
vmath, strutils
## See https://docs.microsoft.com/en-us/typography/opentype/spec/ ## See https://docs.microsoft.com/en-us/typography/opentype/spec/
@ -809,8 +810,6 @@ proc parseKernTable(buf: string, offset: int): KernTable =
else: else:
failUnsupported("Kern version") failUnsupported("Kern version")
import print, strutils
proc parseCFFIndex(buf: string, start: var int, stripZero = false): CFFIndex = proc parseCFFIndex(buf: string, start: var int, stripZero = false): CFFIndex =
proc getOffset(buf: string, offset, offSize: int): int = proc getOffset(buf: string, offset, offSize: int): int =
@ -891,7 +890,7 @@ const cffStandardStrings = [
"Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall",
"Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall",
"Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
"001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"]; "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"]
let TOP_DICT_META = { let TOP_DICT_META = {
0: "version", 0: "version",
@ -939,25 +938,12 @@ proc shift[T](s: var seq[T]): T =
proc parseCFFCharstring(cff: CffTable, code: string): Path = proc parseCFFCharstring(cff: CffTable, code: string): Path =
#print code
var c1x: float32
var c1y: float32
var c2x: float32
var c2y: float32
var p = newPath() var p = newPath()
var stack: seq[float32]; var stack: seq[float32]
# var nStems = 0; # var nStems = 0
var haveWidth = false; var haveWidth = false
# var open = false;
var x = 0f var x = 0f
var y = 0f var y = 0f
# var subrs;
# var subrsBias;
# var defaultWidthX;
# var nominalWidthX;
# TODO: isCIDFon
let let
subrs = cff.topDict.subrs subrs = cff.topDict.subrs
@ -967,23 +953,8 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
var width = defaultWidthX.float32 var width = defaultWidthX.float32
var breakOneMe = false
#print subrs, subrsBias, defaultWidthX, nominalWidthX
proc parse(code: string) = proc parse(code: string) =
var b1: int
var b2: int
var b3: int
var b4: int
# var codeIndex;
# var subrCode;
# var jpx;
# var jpy;
# var c3x;
# var c3y;
# var c4x;
# var c4y;
var i = 0 var i = 0
while i < code.len: while i < code.len:
var v = code.readUint8(i).int var v = code.readUint8(i).int
@ -994,8 +965,8 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
if stack.len > 1 and not haveWidth: if stack.len > 1 and not haveWidth:
width = stack.shift() + nominalWidthX.float32 width = stack.shift() + nominalWidthX.float32
haveWidth = true haveWidth = true
y += stack.pop(); y += stack.pop()
p.moveTo(x, y); p.moveTo(x, y)
of 5: # rlineto of 5: # rlineto
while stack.len > 0: while stack.len > 0:
@ -1010,26 +981,27 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
if stack.len == 0: if stack.len == 0:
break break
y += stack.shift() y += stack.shift()
p.lineTo(x, y); p.lineTo(x, y)
of 7: # vlineto of 7: # vlineto
while stack.len > 0: while stack.len > 0:
y += stack.shift(); y += stack.shift()
p.lineTo(x, y); p.lineTo(x, y)
if stack.len == 0: if stack.len == 0:
break; break
x += stack.shift(); x += stack.shift()
p.lineTo(x, y); p.lineTo(x, y)
of 8: # rrcurveto of 8: # rrcurveto
while stack.len > 0: while stack.len > 0:
c1x = x + stack.shift(); let
c1y = y + stack.shift(); c1x = x + stack.shift()
c2x = c1x + stack.shift(); c1y = y + stack.shift()
c2y = c1y + stack.shift(); c2x = c1x + stack.shift()
x = c2x + stack.shift(); c2y = c1y + stack.shift()
y = c2y + stack.shift(); x = c2x + stack.shift()
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); y = c2y + stack.shift()
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
of 10: # callsubr of 10: # callsubr
let codeIndex = stack.pop().int + subrsBias let codeIndex = stack.pop().int + subrsBias
@ -1050,7 +1022,6 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
if stack.len > 2 and not haveWidth: if stack.len > 2 and not haveWidth:
width = stack.shift() + nominalWidthX.float32 width = stack.shift() + nominalWidthX.float32
haveWidth = true haveWidth = true
y += stack.pop() y += stack.pop()
x += stack.pop() x += stack.pop()
p.moveTo(x, y) p.moveTo(x, y)
@ -1059,63 +1030,61 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
if stack.len > 1 and not haveWidth: if stack.len > 1 and not haveWidth:
width = stack.shift() + nominalWidthX.float32 width = stack.shift() + nominalWidthX.float32
haveWidth = true haveWidth = true
x += stack.pop() x += stack.pop()
p.moveTo(x, y) p.moveTo(x, y)
of 24: # rcurveline of 24: # rcurveline
while stack.len > 2: while stack.len > 2:
c1x = x + stack.shift(); let
c1y = y + stack.shift(); c1x = x + stack.shift()
c2x = c1x + stack.shift(); c1y = y + stack.shift()
c2y = c1y + stack.shift(); c2x = c1x + stack.shift()
x = c2x + stack.shift(); c2y = c1y + stack.shift()
y = c2y + stack.shift(); x = c2x + stack.shift()
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); y = c2y + stack.shift()
x += stack.shift(); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
y += stack.shift(); x += stack.shift()
p.lineTo(x, y); y += stack.shift()
p.lineTo(x, y)
of 25: # rlinecurve of 25: # rlinecurve
while stack.len > 6: while stack.len > 6:
x += stack.shift(); x += stack.shift()
y += stack.shift(); y += stack.shift()
p.lineTo(x, y); p.lineTo(x, y)
let
c1x = x + stack.shift(); c1x = x + stack.shift()
c1y = y + stack.shift(); c1y = y + stack.shift()
c2x = c1x + stack.shift(); c2x = c1x + stack.shift()
c2y = c1y + stack.shift(); c2y = c1y + stack.shift()
x = c2x + stack.shift(); x = c2x + stack.shift()
y = c2y + stack.shift(); y = c2y + stack.shift()
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y) p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
of 26: # vvcurveto of 26: # vvcurveto
if stack.len mod 2 != 0: if stack.len mod 2 != 0:
x += stack.shift() x += stack.shift()
while stack.len > 0: while stack.len > 0:
if stack.len < 4: let
breakOneMe = true c1x = x
c1x = x; c1y = y + stack.shift()
c1y = y + stack.shift(); c2x = c1x + stack.shift()
c2x = c1x + stack.shift(); c2y = c1y + stack.shift()
c2y = c1y + stack.shift(); x = c2x
x = c2x; y = c2y + stack.shift()
y = c2y + stack.shift(); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);
of 27: # hhcurveto of 27: # hhcurveto
if stack.len mod 2 != 0: if stack.len mod 2 != 0:
y += stack.shift() y += stack.shift()
while stack.len > 0: while stack.len > 0:
let
c1x = x + stack.shift() c1x = x + stack.shift()
c1y = y; c1y = y
c2x = c1x + stack.shift() c2x = c1x + stack.shift()
c2y = c1y + stack.shift() c2y = c1y + stack.shift()
x = c2x + stack.shift() x = c2x + stack.shift()
y = c2y; y = c2y
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y) p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
of 28: # shortint of 28: # shortint
@ -1131,43 +1100,49 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
of 30: # vhcurveto of 30: # vhcurveto
while stack.len > 0: while stack.len > 0:
c1x = x; block:
c1y = y + stack.shift(); let
c2x = c1x + stack.shift(); c1x = x
c2y = c1y + stack.shift(); c1y = y + stack.shift()
x = c2x + stack.shift(); c2x = c1x + stack.shift()
c2y = c1y + stack.shift()
x = c2x + stack.shift()
y = c2y + (if stack.len == 1: stack.shift() else: 0) y = c2y + (if stack.len == 1: stack.shift() else: 0)
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
if stack.len == 0: if stack.len == 0:
break break
block:
c1x = x + stack.shift(); let
c1y = y; c1x = x + stack.shift()
c2x = c1x + stack.shift(); c1y = y
c2y = c1y + stack.shift(); c2x = c1x + stack.shift()
y = c2y + stack.shift(); c2y = c1y + stack.shift()
y = c2y + stack.shift()
x = c2x + (if stack.len == 1: stack.shift() else: 0) x = c2x + (if stack.len == 1: stack.shift() else: 0)
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
of 31: # hvcurveto of 31: # hvcurveto
while stack.len > 0: while stack.len > 0:
c1x = x + stack.shift(); block:
c1y = y; let
c2x = c1x + stack.shift(); c1x = x + stack.shift()
c2y = c1y + stack.shift(); c1y = y
y = c2y + stack.shift(); c2x = c1x + stack.shift()
c2y = c1y + stack.shift()
y = c2y + stack.shift()
x = c2x + (if stack.len == 1: stack.shift() else: 0) x = c2x + (if stack.len == 1: stack.shift() else: 0)
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
if stack.len == 0: if stack.len == 0:
break break
block:
c1x = x; let
c1y = y + stack.shift(); c1x = x
c2x = c1x + stack.shift(); c1y = y + stack.shift()
c2y = c1y + stack.shift(); c2x = c1x + stack.shift()
x = c2x + stack.shift(); c2y = c1y + stack.shift()
x = c2x + stack.shift()
y = c2y + (if stack.len == 1: stack.shift() else: 0) y = c2y + (if stack.len == 1: stack.shift() else: 0)
p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y); p.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
else: else:
if v < 32: if v < 32:
@ -1175,29 +1150,27 @@ proc parseCFFCharstring(cff: CffTable, code: string): Path =
elif v < 247: elif v < 247:
stack.add(float32(v - 139)) stack.add(float32(v - 139))
elif v < 251: elif v < 251:
b1 = code.readUint8(i).int; let b1 = code.readUint8(i).int
i += 1; i += 1
stack.add(float32((v - 247) * 256 + b1 + 108)) stack.add(float32((v - 247) * 256 + b1 + 108))
elif v < 255: elif v < 255:
b1 = code.readUint8(i).int; let b1 = code.readUint8(i).int
i += 1; i += 1
stack.add(float32(-(v - 251) * 256 - b1 - 108)) stack.add(float32(-(v - 251) * 256 - b1 - 108))
else: else:
failUnsupported("test me")
let
b1 = code.readUint8(i + 0).int b1 = code.readUint8(i + 0).int
b2 = code.readUint8(i + 1).int b2 = code.readUint8(i + 1).int
b3 = code.readUint8(i + 2).int b3 = code.readUint8(i + 2).int
b4 = code.readUint8(i + 3).int b4 = code.readUint8(i + 3).int
i += 4; i += 4
stack.add(((b1 shl 24) or (b2 shl 16) or (b3 shl 8) or b4).float32 / 65536f) stack.add(
((b1 shl 24) or (b2 shl 16) or (b3 shl 8) or b4).float32 / 65536f)
parse(code) parse(code)
if breakOneMe:
quit()
return p return p
proc parseCFFTable(buf: string, offset: int): CFFTable = proc parseCFFTable(buf: string, offset: int): CFFTable =
buf.eofCheck(offset + 32) buf.eofCheck(offset + 32)
@ -1245,18 +1218,21 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
entries.add((op, operands)) entries.add((op, operands))
operands.setLen(0) operands.setLen(0)
else: else:
# Since the operands (values) come before the operators (keys), we store all operands in a list # Since the operands (values) come before the operators (keys), we store
# until we encounter an operator. # all operands in a list until we encounter an operator.
proc parseFloatOperand(): float64 = proc parseFloatOperand(): float64 =
var s = "" var s = ""
var eof = 15 var eof = 15
var lookup = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "E", "E-", "null", "-"] var lookup = [
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
".", "E", "E-", "null", "-"
]
while true: while true:
var b = data.readUint8(relativeOffset).int var b = data.readUint8(relativeOffset).int
inc relativeOffset inc relativeOffset
var n1 = b shr 4; var n1 = b shr 4
var n2 = b and 15; var n2 = b and 15
if n1 == eof: if n1 == eof:
break break
s.add lookup[n1] s.add lookup[n1]
@ -1289,13 +1265,14 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
inc relativeOffset inc relativeOffset
b4 = data.readUint8(relativeOffset).int b4 = data.readUint8(relativeOffset).int
inc relativeOffset inc relativeOffset
return float64(cast[int32](b1 shl 24 or b2 shl 16 or b3 shl 8 or b4)) return float64(cast[int32](
b1 shl 24 or b2 shl 16 or b3 shl 8 or b4))
if b0 == 30: if b0 == 30:
return parseFloatOperand() return parseFloatOperand()
if b0 >= 32 and b0 <= 246: if b0 >= 32 and b0 <= 246:
return float64(b0 - 139); return float64(b0 - 139)
if b0 >= 247 and b0 <= 250: if b0 >= 247 and b0 <= 250:
b1 = data.readUint8(relativeOffset).int b1 = data.readUint8(relativeOffset).int
@ -1314,22 +1291,12 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
operands.add(operand) operands.add(operand)
return entries return entries
# # Convert the entries returned by `parseDict` to a proper dictionary.
# # If a value is a list of one, it is unpacked.
# proc entriesToObject(entries: seq[(int, seq[float64])]): Table[int, seq[float64]] =
# var o: Table[int, seq[float64]]
# for i in 0 ..< entries.len:
# var key = entries[i][0]
# var values = entries[i][1]
# if key in o:
# failUnsupported("CFF duplicate key error " & $key)
# o[key] = values
# return o
# var dict = entriesToObject(entries)
# return dict
proc interpretDict(
proc interpretDict(entries: seq[(int, seq[float64])], meta: Table[int, string], strings: seq[string]): Table[string, seq[float64]] = entries: seq[(int, seq[float64])],
meta: Table[int, string],
strings: seq[string]
): Table[string, seq[float64]] =
for e in entries: for e in entries:
if e[0] notin meta: if e[0] notin meta:
#failUnsupported("CFF unknown op: " & $e[0]) #failUnsupported("CFF unknown op: " & $e[0])
@ -1339,19 +1306,26 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
failUnsupported("CFF duplicate key: " & key) failUnsupported("CFF duplicate key: " & key)
result[key] = e[1] result[key] = e[1]
# Parse the CFF top dictionary. A CFF table can contain multiple fonts, each with their own top dictionary. # Parse the CFF top dictionary. A CFF table can contain multiple fonts, each
# The top dictionary contains the essential metadata for the font, together with the private dictionary. # with their own top dictionary. The top dictionary contains the essential
proc parseCFFTopDict(data: string, strings: seq[string]): Table[string, seq[float64]] = # metadata for the font, together with the private dictionary.
proc parseCFFTopDict(
data: string,
strings: seq[string]
): Table[string, seq[float64]] =
var entries = parseCFFDict(data, 0, data.len) var entries = parseCFFDict(data, 0, data.len)
return interpretDict(entries, TOP_DICT_META, strings) return interpretDict(entries, TOP_DICT_META, strings)
proc parseCFFPrivateDict(data: string, strings: seq[string]): Table[string, seq[float64]] = proc parseCFFPrivateDict(
data: string,
strings: seq[string]
): Table[string, seq[float64]] =
var entries = parseCFFDict(data, 0, data.len) var entries = parseCFFDict(data, 0, data.len)
return interpretDict(entries, PRIVATE_DICT_META, strings) return interpretDict(entries, PRIVATE_DICT_META, strings)
proc getCFFString(strings: seq[string], index: int): string = proc getCFFString(strings: seq[string], index: int): string =
if index <= 390: if index <= 390:
cffStandardStrings[index]; cffStandardStrings[index]
else: else:
if index - 391 < strings.len: if index - 391 < strings.len:
strings[index - 391] strings[index - 391]
@ -1359,7 +1333,13 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
"" ""
# "Top DICT"s found using an INDEX list. # "Top DICT"s found using an INDEX list.
proc gatherCFFTopDicts(cff: CFFTable, data: string, start: int, cffIndex, strings: seq[string]): seq[CFFTopDict] = proc gatherCFFTopDicts(
cff: CFFTable,
data: string,
start: int,
cffIndex,
strings: seq[string]
): seq[CFFTopDict] =
for iTopDict in 0 ..< cffIndex.len: for iTopDict in 0 ..< cffIndex.len:
let let
@ -1398,7 +1378,6 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
result[i] = topDict[key][i].float32 result[i] = topDict[key][i].float32
else: else:
return default return default
cffTopDict.charStrings = topDict.getInt("charStrings", 0) cffTopDict.charStrings = topDict.getInt("charStrings", 0)
cffTopDict.charset = topDict.getInt("charset", 0) cffTopDict.charset = topDict.getInt("charset", 0)
cffTopDict.charstringType = topDict.getInt("charstringType", 2) cffTopDict.charstringType = topDict.getInt("charstringType", 2)
@ -1430,7 +1409,6 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
cffTopDict.defaultWidthX = privateDict.getInt("defaultWidthX", 0) cffTopDict.defaultWidthX = privateDict.getInt("defaultWidthX", 0)
cffTopDict.nominalWidthX = privateDict.getInt("nominalWidthX", 0) cffTopDict.nominalWidthX = privateDict.getInt("nominalWidthX", 0)
cffTopDict.subrs = privateDict.getInt("subrs", 0) cffTopDict.subrs = privateDict.getInt("subrs", 0)
# cffTopDict.ros: array[3, float32] # cffTopDict.ros: array[3, float32]
cffTopDict.strokeWidth = topDict.getInt("strokeWidth", 0) cffTopDict.strokeWidth = topDict.getInt("strokeWidth", 0)
# cffTopDict.uidBase: pointer # cffTopDict.uidBase: pointer
@ -1451,22 +1429,18 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
# TODO: isCIDFont? # TODO: isCIDFont?
# print result.topDict.subrs
# print result.topDict.defaultWidthX
# print result.topDict.nominalWidthX
if result.topDict.subrs != 0: if result.topDict.subrs != 0:
var subrOffset = offset + result.topDict.private[1].int + result.topDict.subrs var subrOffset =
offset + result.topDict.private[1].int + result.topDict.subrs
result.subrIndex = buf.parseCFFIndex(subrOffset) result.subrIndex = buf.parseCFFIndex(subrOffset)
proc parseCFFIndexLowMemory(buf: string, offset: int): seq[int] = proc parseCFFIndexLowMemory(buf: string, offset: int): seq[int] =
proc getOffset(dataView: string, offset, offSize: int): int = proc getOffset(dataView: string, offset, offSize: int): int =
var v = 0 var v = 0
for i in 0 ..< offSize: for i in 0 ..< offSize:
v = v shl 8 v = v shl 8
v += dataView.readUint8(offset + i).int v += dataView.readUint8(offset + i).int
return v return v
let count = buf.readUint16(offset).swap().int let count = buf.readUint16(offset).swap().int
var objectOffset = 0 var objectOffset = 0
if count != 0: if count != 0:
@ -1478,11 +1452,16 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
result.add offsetValue result.add offsetValue
pos += offsetSize pos += offsetSize
let charStringsIndex = parseCFFIndexLowMemory(buf, offset + result.topDict.charStrings); let charStringsIndex = parseCFFIndexLowMemory(
buf, offset + result.topDict.charStrings)
let nGlyphs = charStringsIndex.len let nGlyphs = charStringsIndex.len
proc parseCFFCharset(buf: string, offset: int, nGlyphs: int, stringIndex: seq[string]): seq[string] = proc parseCFFCharset(
buf: string,
offset: int,
nGlyphs: int,
stringIndex: seq[string]
): seq[string] =
# The .notdef glyph is implied # The .notdef glyph is implied
var charset = @[".notdef"] var charset = @[".notdef"]
var nGlyphs = nGlyphs - 1 var nGlyphs = nGlyphs - 1
@ -1506,31 +1485,18 @@ proc parseCFFTable(buf: string, offset: int): CFFTable =
failUnsupported("CFF charset format") failUnsupported("CFF charset format")
# Why do we need this anyways? # Why do we need this anyways?
var charset = parseCFFCharset(buf, offset + result.topDict.charset, nGlyphs, result.stringIndex.objects); var charset = parseCFFCharset(
# if topDict.encoding == 0: buf, offset + result.topDict.charset, nGlyphs, result.stringIndex.objects)
# discard
# else:
# failUnsupported("CFF top dict encoding")
var start = offset + result.topDict.charStrings var start = offset + result.topDict.charStrings
#print start
# for i in 0 ..< nGlyphs:
# print i
# var charString = parseCFFIndex(buf, start);
result.charIndex = buf.parseCFFIndex(start) result.charIndex = buf.parseCFFIndex(start)
#print charIndex
# let glyphIndex = 2539 # let glyphIndex = 2539
# let charstring = charIndex.objects[glyphIndex] # let charstring = charIndex.objects[glyphIndex]
# var path = parseCFFCharstring(result, charstring) # var path = parseCFFCharstring(result, charstring)
# for glyphIndex in 0 ..< result.charIndex.objects.len:
for glyphIndex in 0 ..< result.charIndex.objects.len: # let charstring = result.charIndex.objects[glyphIndex]
let charstring = result.charIndex.objects[glyphIndex] # var path = parseCFFCharstring(result, charstring)
var path = parseCFFCharstring(result, charstring)
# proc parseLangSys(buf: string, offset: int): LangSys = # proc parseLangSys(buf: string, offset: int): LangSys =
@ -2028,7 +1994,7 @@ proc parsePostTable(buf: string, offset: int): PostTable =
proc getGlyphId(opentype: OpenType, rune: Rune): uint16 = proc getGlyphId(opentype: OpenType, rune: Rune): uint16 =
result = opentype.cmap.runeToGlyphId.getOrDefault(rune, 0) result = opentype.cmap.runeToGlyphId.getOrDefault(rune, 0)
proc parseGlyph(opentype: OpenType, glyphId: uint16): Path {.raises: [PixieError].} proc parseGlyfGlyph(opentype: OpenType, glyphId: uint16): Path {.raises: [PixieError].}
proc parseGlyphPath( proc parseGlyphPath(
buf: string, offset, numberOfContours: int buf: string, offset, numberOfContours: int
@ -2249,7 +2215,7 @@ proc parseCompositeGlyph(opentype: OpenType, offset: int): Path =
# elif (flags and 0b1000000000000) != 0: # UNSCALED_COMPONENT_OFFSET # elif (flags and 0b1000000000000) != 0: # UNSCALED_COMPONENT_OFFSET
# discard # discard
var subPath = opentype.parseGlyph(component.glyphId) var subPath = opentype.parseGlyfGlyph(component.glyphId)
subPath.transform(mat3( subPath.transform(mat3(
component.xScale, component.scale10, 0.0, component.xScale, component.scale10, 0.0,
component.scale01, component.yScale, 0.0, component.scale01, component.yScale, 0.0,
@ -2260,7 +2226,7 @@ proc parseCompositeGlyph(opentype: OpenType, offset: int): Path =
moreComponents = (flags and 0b100000) != 0 moreComponents = (flags and 0b100000) != 0
proc parseGlyph(opentype: OpenType, glyphId: uint16): Path = proc parseGlyfGlyph(opentype: OpenType, glyphId: uint16): Path =
if glyphId.int >= opentype.glyf.offsets.len: if glyphId.int >= opentype.glyf.offsets.len:
raise newException(PixieError, "Invalid glyph ID " & $glyphId) raise newException(PixieError, "Invalid glyph ID " & $glyphId)
@ -2277,10 +2243,6 @@ proc parseGlyph(opentype: OpenType, glyphId: uint16): Path =
let let
numberOfContours = opentype.buf.readInt16(i + 0).swap().int numberOfContours = opentype.buf.readInt16(i + 0).swap().int
# xMin = opentype.buf.readInt16(i + 2).swap()
# yMin = opentype.buf.readInt16(i + 4).swap()
# xMax = opentype.buf.readInt16(i + 6).swap()
# yMax = opentype.buf.readInt16(i + 8).swap()
i += 10 i += 10
@ -2297,7 +2259,7 @@ proc parseCffGlyph(opentype: OpenType, glyphId: uint16): Path =
proc parseGlyph(opentype: OpenType, rune: Rune): Path {.inline.} = proc parseGlyph(opentype: OpenType, rune: Rune): Path {.inline.} =
if opentype.glyf != nil: if opentype.glyf != nil:
opentype.parseGlyph(opentype.getGlyphId(rune)) opentype.parseGlyfGlyph(opentype.getGlyphId(rune))
elif opentype.cff != nil: elif opentype.cff != nil:
opentype.parseCffGlyph(opentype.getGlyphId(rune)) opentype.parseCffGlyph(opentype.getGlyphId(rune))
else: else: