This commit is contained in:
Ryan Oldenburg 2021-04-26 22:14:08 -05:00
parent 9dc96f45ce
commit 4bdcc67baa
4 changed files with 31 additions and 7 deletions

View file

@ -15,6 +15,7 @@ type
numTables*: uint16
encodingRecords*: seq[EncodingRecord]
runeToGlyphId*: Table[Rune, uint16]
glyphIdToRune*: Table[uint16, Rune]
HeadTable* = ref object
majorVersion*: uint16
@ -295,6 +296,7 @@ proc parseCmapTable(buf: string, offset: int): CmapTable =
if c != 65535:
result.runeToGlyphId[Rune(c)] = glyphId.uint16
result.glyphIdToRune[glyphId.uint16] = Rune(c)
else:
# TODO implement other Windows encodingIDs
discard
@ -563,13 +565,13 @@ proc parseKernTable(buf: string, offset: int): KernTable =
else:
failUnsupported()
proc getGlyphId*(opentype: OpenType, rune: Rune): int =
proc getGlyphId*(opentype: OpenType, rune: Rune): uint16 =
if rune in opentype.cmap.runeToGlyphId:
result = opentype.cmap.runeToGlyphId[rune].int
result = opentype.cmap.runeToGlyphId[rune]
else:
discard # Index 0 is the "missing character" glyph
proc parseGlyph(opentype: OpenType, glyphId: int): Path
proc parseGlyph(opentype: OpenType, glyphId: uint16): Path
proc parseGlyphPath(buf: string, offset, numberOfContours: int): Path =
if numberOfContours < 0:
@ -781,7 +783,7 @@ proc parseCompositeGlyph(opentype: OpenType, offset: int): Path =
# elif (flags and 0b1000000000000) != 0: # UNSCALED_COMPONENT_OFFSET
# discard
var subPath = opentype.parseGlyph(component.glyphId.int)
var subPath = opentype.parseGlyph(component.glyphId)
subPath.transform(mat3(
component.xScale, component.scale10, 0.0,
component.scale01, component.yScale, 0.0,
@ -792,8 +794,8 @@ proc parseCompositeGlyph(opentype: OpenType, offset: int): Path =
moreComponents = (flags and 0b100000) != 0
proc parseGlyph(opentype: OpenType, glyphId: int): Path =
if glyphId < 0 or glyphId >= opentype.glyf.offsets.len:
proc parseGlyph(opentype: OpenType, glyphId: uint16): Path =
if glyphId.int >= opentype.glyf.offsets.len:
raise newException(PixieError, "Invalid glyph ID " & $glyphId)
let glyphOffset = opentype.glyf.offsets[glyphId]

View file

@ -6,6 +6,7 @@ type
Font* = ref object
opentype: OpenType
glyphPaths: Table[Rune, Path]
kerningPairs: Table[(Rune, Rune), float32]
size*: float32 ## Font size in pixels.
lineHeight*: float32 ## The line height in pixels or AutoLineHeight for the font's default line height.
@ -46,12 +47,17 @@ proc getGlyphPath*(font: Font, rune: Rune): Path =
font.glyphPaths[rune]
proc getGlyphAdvance*(font: Font, rune: Rune): float32 =
let glyphId = font.opentype.getGlyphId(rune)
let glyphId = font.opentype.getGlyphId(rune).int
if glyphId < font.opentype.hmtx.hMetrics.len:
font.opentype.hmtx.hMetrics[glyphId].advanceWidth.float32
else:
font.opentype.hmtx.hMetrics[^1].advanceWidth.float32
proc getKerningAdjustment*(font: Font, left, right: Rune): float32 =
let pair = (left, right)
if pair in font.kerningPairs:
result = font.kerningPairs[pair]
proc scale*(font: Font): float32 =
## The scale factor to transform font units into pixels.
font.size / font.opentype.head.unitsPerEm.float32
@ -104,6 +110,9 @@ proc typeset*(
if rune.canWrap():
prevCanWrap = i
if i > 0:
at.x += font.getKerningAdjustment(runes[i - 1], rune) * font.scale
let advance = font.getGlyphAdvance(rune) * font.scale
if bounds.x > 0 and at.x + advance > bounds.x: # Wrap to new line
at.x = 0
@ -112,6 +121,8 @@ proc typeset*(
# Go back and wrap glyphs after the wrap index down to the next line
if prevCanWrap > 0 and prevCanWrap != i:
for j in prevCanWrap + 1 ..< i:
if j > 0:
at.x += font.getKerningAdjustment(runes[j - 1], runes[j]) * font.scale
positions[j] = at
at.x += font.getGlyphAdvance(runes[j]) * font.scale
@ -129,5 +140,16 @@ proc parseOtf*(buf: string): Font =
result.size = 12
result.lineHeight = AutoLineHeight
if result.opentype.kern != nil:
for table in result.opentype.kern.subTables:
for pair in table.kernPairs:
if pair.value != 0 and
pair.left in result.opentype.cmap.glyphIdToRune and
pair.right in result.opentype.cmap.glyphIdToRune:
result.kerningPairs[(
result.opentype.cmap.glyphIdToRune[pair.left],
result.opentype.cmap.glyphIdToRune[pair.right]
)] = pair.value.float32
proc parseTtf*(buf: string): Font =
parseOtf(buf)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB