Add font fallback.
This commit is contained in:
parent
ce05442e2e
commit
c0f31b276f
5 changed files with 55 additions and 18 deletions
|
@ -12,6 +12,7 @@ type
|
|||
opentype: OpenType
|
||||
svgFont: SvgFont
|
||||
filePath*: string
|
||||
fallbacks*: seq[Typeface]
|
||||
|
||||
Font* = ref object
|
||||
typeface*: Typeface
|
||||
|
@ -53,6 +54,13 @@ type
|
|||
# tcSmallCaps
|
||||
# tcSmallCapsForced
|
||||
|
||||
proc scale*(typeface: Typeface): float32 {.inline, raises: [].} =
|
||||
## The scale factor to transform font units into pixels.
|
||||
if typeface.opentype != nil:
|
||||
typeface.opentype.head.unitsPerEm.float32
|
||||
else:
|
||||
typeface.svgFont.unitsPerEm
|
||||
|
||||
proc ascent*(typeface: Typeface): float32 {.raises: [].} =
|
||||
## The font ascender value in font units.
|
||||
if typeface.opentype != nil:
|
||||
|
@ -97,17 +105,6 @@ proc isCCW(typeface: Typeface): bool {.inline.} =
|
|||
if typeface.opentype != nil:
|
||||
return typeface.opentype.isCCW()
|
||||
|
||||
proc getGlyphPath*(
|
||||
typeface: Typeface, rune: Rune
|
||||
): Path {.inline, raises: [PixieError].} =
|
||||
## The glyph path for the rune.
|
||||
result = newPath()
|
||||
if rune.uint32 > SP.uint32: # Empty paths for control runes (not tofu)
|
||||
if typeface.opentype != nil:
|
||||
result.addPath(typeface.opentype.getGlyphPath(rune))
|
||||
else:
|
||||
result.addPath(typeface.svgFont.getGlyphPath(rune))
|
||||
|
||||
proc hasGlyph*(typeface: Typeface, rune: Rune): bool {.inline.} =
|
||||
## Returns if there is a glyph for this rune.
|
||||
if rune.uint32 > SP.uint32: # Empty paths for control runes (not tofu)
|
||||
|
@ -118,12 +115,44 @@ proc hasGlyph*(typeface: Typeface, rune: Rune): bool {.inline.} =
|
|||
else:
|
||||
false
|
||||
|
||||
proc getGlyphPath*(
|
||||
typeface: Typeface, rune: Rune
|
||||
): Path {.inline, raises: [PixieError].} =
|
||||
## The glyph path for the rune.
|
||||
result = newPath()
|
||||
if rune.uint32 > SP.uint32: # Empty paths for control runes (not tofu)
|
||||
if typeface.hasGlyph(rune):
|
||||
if typeface.opentype != nil:
|
||||
result.addPath(typeface.opentype.getGlyphPath(rune))
|
||||
else:
|
||||
result.addPath(typeface.svgFont.getGlyphPath(rune))
|
||||
else:
|
||||
for fallback in typeface.fallbacks:
|
||||
if fallback.hasGlyph(rune):
|
||||
result = fallback.getGlyphPath(rune)
|
||||
let ratio = typeface.scale / fallback.scale
|
||||
result.transform(scale(vec2(ratio, ratio)))
|
||||
|
||||
proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} =
|
||||
## The advance for the rune in pixels.
|
||||
if typeface.opentype != nil:
|
||||
typeface.opentype.getAdvance(rune)
|
||||
if typeface.hasGlyph(rune):
|
||||
if typeface.opentype != nil:
|
||||
return typeface.opentype.getAdvance(rune)
|
||||
else:
|
||||
return typeface.svgFont.getAdvance(rune)
|
||||
else:
|
||||
typeface.svgFont.getAdvance(rune)
|
||||
for fallback in typeface.fallbacks:
|
||||
if fallback.hasGlyph(rune):
|
||||
result = fallback.getAdvance(rune)
|
||||
let ratio = typeface.scale / fallback.scale
|
||||
result *= ratio
|
||||
return
|
||||
|
||||
if typeface.opentype != nil:
|
||||
return typeface.opentype.getAdvance(rune)
|
||||
else:
|
||||
return typeface.svgFont.getAdvance(rune)
|
||||
|
||||
|
||||
proc getKerningAdjustment*(
|
||||
typeface: Typeface, left, right: Rune
|
||||
|
@ -136,10 +165,7 @@ proc getKerningAdjustment*(
|
|||
|
||||
proc scale*(font: Font): float32 {.inline, raises: [].} =
|
||||
## The scale factor to transform font units into pixels.
|
||||
if font.typeface.opentype != nil:
|
||||
font.size / font.typeface.opentype.head.unitsPerEm.float32
|
||||
else:
|
||||
font.size / font.typeface.svgFont.unitsPerEm
|
||||
font.size / font.typeface.scale
|
||||
|
||||
proc defaultLineHeight*(font: Font): float32 {.inline, raises: [].} =
|
||||
## The default line height in pixels for the current font size.
|
||||
|
|
BIN
tests/fonts/diffs/fallback.png
Normal file
BIN
tests/fonts/diffs/fallback.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
tests/fonts/masters/fallback.png
Normal file
BIN
tests/fonts/masters/fallback.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
BIN
tests/fonts/rendered/fallback.png
Normal file
BIN
tests/fonts/rendered/fallback.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -1057,3 +1057,14 @@ block:
|
|||
image.fillText(font, "Grumpy wizards make toxic brew for the evil Queen and Jack.")
|
||||
|
||||
doDiff(image, "cff_strikethrough")
|
||||
|
||||
block:
|
||||
var font = readFont("tests/fonts/Inter-Regular.ttf")
|
||||
var typeface = readTypeface("tests/fonts/NotoSansJP-Regular.ttf")
|
||||
font.typeface.fallbacks.add(typeface)
|
||||
font.size = 26
|
||||
let image = newImage(800, 100)
|
||||
image.fill(rgba(255, 255, 255, 255))
|
||||
image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.")
|
||||
|
||||
doDiff(image, "fallback")
|
||||
|
|
Loading…
Reference in a new issue