megatest start + improvements

This commit is contained in:
Ryan Oldenburg 2021-04-26 22:45:32 -05:00
parent 4bdcc67baa
commit 7ae3d5c418
4 changed files with 55 additions and 30 deletions

View file

@ -543,6 +543,8 @@ proc parseKernTable(buf: string, offset: int): KernTable =
failUnsupported() failUnsupported()
subTable.length = buf.readUint16(i + 2).swap() subTable.length = buf.readUint16(i + 2).swap()
subTable.coverage = buf.readUint16(i + 4).swap() subTable.coverage = buf.readUint16(i + 4).swap()
if subTable.coverage shr 8 != 0:
failUnsupported()
subTable.nPairs = buf.readUint16(i + 6).swap() subTable.nPairs = buf.readUint16(i + 6).swap()
subTable.searchRange = buf.readUint16(i + 8).swap() subTable.searchRange = buf.readUint16(i + 8).swap()
subTable.entrySelector = buf.readUint16(i + 10).swap() subTable.entrySelector = buf.readUint16(i + 10).swap()

View file

@ -40,24 +40,6 @@ proc lineGap*(font: Font): float32 {.inline.} =
## The font line gap value in font units. ## The font line gap value in font units.
font.opentype.hhea.lineGap.float32 font.opentype.hhea.lineGap.float32
proc getGlyphPath*(font: Font, rune: Rune): Path =
if rune notin font.glyphPaths:
font.glyphPaths[rune] = font.opentype.parseGlyph(rune)
font.glyphPaths[rune].transform(scale(vec2(1, -1)))
font.glyphPaths[rune]
proc getGlyphAdvance*(font: Font, rune: Rune): float32 =
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 = proc scale*(font: Font): float32 =
## The scale factor to transform font units into pixels. ## The scale factor to transform font units into pixels.
font.size / font.opentype.head.unitsPerEm.float32 font.size / font.opentype.head.unitsPerEm.float32
@ -66,6 +48,29 @@ proc defaultLineHeight*(font: Font): float32 =
## The default line height in pixels for the current font size. ## The default line height in pixels for the current font size.
round((font.ascent + abs(font.descent) + font.lineGap) * font.scale) round((font.ascent + abs(font.descent) + font.lineGap) * font.scale)
proc getGlyphPath*(font: Font, rune: Rune): Path =
## The glyph path for the parameter rune.
if rune notin font.glyphPaths:
font.glyphPaths[rune] = font.opentype.parseGlyph(rune)
font.glyphPaths[rune].transform(scale(vec2(1, -1)))
font.glyphPaths[rune]
proc getGlyphAdvance*(font: Font, rune: Rune): float32 =
## The advance for the parameter rune in pixels.
let glyphId = font.opentype.getGlyphId(rune).int
if glyphId < font.opentype.hmtx.hMetrics.len:
result = font.opentype.hmtx.hMetrics[glyphId].advanceWidth.float32
else:
result = font.opentype.hmtx.hMetrics[^1].advanceWidth.float32
result *= font.scale
proc getKerningAdjustment*(font: Font, left, right: Rune): float32 =
## The kerning adjustment for the parameter rune pair, in pixels.
let pair = (left, right)
if pair in font.kerningPairs:
result = font.kerningPairs[pair]
result *= font.scale
proc convertTextCase(runes: var seq[Rune], textCase: TextCase) = proc convertTextCase(runes: var seq[Rune], textCase: TextCase) =
case textCase: case textCase:
of tcNormal: of tcNormal:
@ -111,9 +116,9 @@ proc typeset*(
prevCanWrap = i prevCanWrap = i
if i > 0: if i > 0:
at.x += font.getKerningAdjustment(runes[i - 1], rune) * font.scale at.x += font.getKerningAdjustment(runes[i - 1], rune)
let advance = font.getGlyphAdvance(rune) * font.scale let advance = font.getGlyphAdvance(rune)
if bounds.x > 0 and at.x + advance > bounds.x: # Wrap to new line if bounds.x > 0 and at.x + advance > bounds.x: # Wrap to new line
at.x = 0 at.x = 0
at.y += lineHeight at.y += lineHeight
@ -122,9 +127,9 @@ proc typeset*(
if prevCanWrap > 0 and prevCanWrap != i: if prevCanWrap > 0 and prevCanWrap != i:
for j in prevCanWrap + 1 ..< i: for j in prevCanWrap + 1 ..< i:
if j > 0: if j > 0:
at.x += font.getKerningAdjustment(runes[j - 1], runes[j]) * font.scale at.x += font.getKerningAdjustment(runes[j - 1], runes[j])
positions[j] = at positions[j] = at
at.x += font.getGlyphAdvance(runes[j]) * font.scale at.x += font.getGlyphAdvance(runes[j])
positions[i] = at positions[i] = at
at.x += advance at.x += advance
@ -142,14 +147,22 @@ proc parseOtf*(buf: string): Font =
if result.opentype.kern != nil: if result.opentype.kern != nil:
for table in result.opentype.kern.subTables: for table in result.opentype.kern.subTables:
for pair in table.kernPairs: if (table.coverage and 1) != 0: # Horizontal data
if pair.value != 0 and for pair in table.kernPairs:
pair.left in result.opentype.cmap.glyphIdToRune and if pair.value != 0 and
pair.right in result.opentype.cmap.glyphIdToRune: pair.left in result.opentype.cmap.glyphIdToRune and
result.kerningPairs[( pair.right in result.opentype.cmap.glyphIdToRune:
result.opentype.cmap.glyphIdToRune[pair.left], let key = (
result.opentype.cmap.glyphIdToRune[pair.right] result.opentype.cmap.glyphIdToRune[pair.left],
)] = pair.value.float32 result.opentype.cmap.glyphIdToRune[pair.right]
)
var value = pair.value.float32
if key in result.kerningPairs:
if (table.coverage and 0b1000) != 0: # Override
discard
else: # Accumulate
value += result.kerningPairs[key]
result.kerningPairs[key] = value
proc parseTtf*(buf: string): Font = proc parseTtf*(buf: string): Font =
parseOtf(buf) parseOtf(buf)

10
tests/fonts_megatest.nim Normal file
View file

@ -0,0 +1,10 @@
import common, pixie
# Clone https://github.com/google/fonts
# Check out commit ebaa6a7aab9b700da4e30a4682687acdf427eae7
let fontPaths = findAllFonts("../fonts")
for fontPath in fontPaths:
echo fontPath
let font = readFont(fontPath)