Better fallback
This commit is contained in:
parent
8a88cd29fa
commit
a8e1943556
2 changed files with 67 additions and 30 deletions
|
@ -112,51 +112,65 @@ proc hasGlyph*(typeface: Typeface, rune: Rune): bool {.inline.} =
|
||||||
else:
|
else:
|
||||||
typeface.svgFont.hasGlyph(rune)
|
typeface.svgFont.hasGlyph(rune)
|
||||||
|
|
||||||
|
proc fallbackTypeface*(typeface: Typeface, rune: Rune): Typeface =
|
||||||
|
## Looks through fallback typefaces to find one that has the glyph.
|
||||||
|
if typeface.hasGlyph(rune):
|
||||||
|
return typeface
|
||||||
|
for fallback in typeface.fallbacks:
|
||||||
|
let typeface = fallback.fallbackTypeface(rune)
|
||||||
|
if typeface != nil:
|
||||||
|
return typeface
|
||||||
|
|
||||||
proc getGlyphPath*(
|
proc getGlyphPath*(
|
||||||
typeface: Typeface, rune: Rune
|
typeface: Typeface, rune: Rune
|
||||||
): Path {.inline, raises: [PixieError].} =
|
): Path {.inline, raises: [PixieError].} =
|
||||||
## The glyph path for the rune.
|
## The glyph path for the rune.
|
||||||
result = newPath()
|
result = newPath()
|
||||||
if typeface.hasGlyph(rune):
|
|
||||||
if typeface.opentype != nil:
|
let typeface2 = typeface.fallbackTypeface(rune)
|
||||||
result.addPath(typeface.opentype.getGlyphPath(rune))
|
if typeface2 == nil:
|
||||||
else:
|
return
|
||||||
result.addPath(typeface.svgFont.getGlyphPath(rune))
|
|
||||||
|
if typeface2.opentype != nil:
|
||||||
|
result.addPath(typeface2.opentype.getGlyphPath(rune))
|
||||||
else:
|
else:
|
||||||
for fallback in typeface.fallbacks:
|
result.addPath(typeface2.svgFont.getGlyphPath(rune))
|
||||||
if fallback.hasGlyph(rune):
|
|
||||||
result = fallback.getGlyphPath(rune)
|
# Apply typeface ratio.
|
||||||
let ratio = typeface.scale / fallback.scale
|
let ratio = typeface.scale / typeface2.scale
|
||||||
result.transform(scale(vec2(ratio, ratio)))
|
if ratio != 1.0:
|
||||||
|
result.transform(scale(vec2(ratio, ratio)))
|
||||||
|
|
||||||
proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} =
|
proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} =
|
||||||
## The advance for the rune in pixels.
|
## The advance for the rune in pixels.
|
||||||
if typeface.hasGlyph(rune):
|
let typeface2 = typeface.fallbackTypeface(rune)
|
||||||
if typeface.opentype != nil:
|
if typeface2 == nil:
|
||||||
return typeface.opentype.getAdvance(rune)
|
return
|
||||||
else:
|
|
||||||
return typeface.svgFont.getAdvance(rune)
|
|
||||||
else:
|
|
||||||
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:
|
if typeface2.opentype != nil:
|
||||||
return typeface.opentype.getAdvance(rune)
|
result = typeface2.opentype.getAdvance(rune)
|
||||||
else:
|
else:
|
||||||
return typeface.svgFont.getAdvance(rune)
|
result = typeface2.svgFont.getAdvance(rune)
|
||||||
|
|
||||||
|
# Apply typeface ratio.
|
||||||
|
result *= typeface.scale / typeface2.scale
|
||||||
|
|
||||||
proc getKerningAdjustment*(
|
proc getKerningAdjustment*(
|
||||||
typeface: Typeface, left, right: Rune
|
typeface: Typeface, left, right: Rune
|
||||||
): float32 {.inline, raises: [].} =
|
): float32 {.inline, raises: [].} =
|
||||||
## The kerning adjustment for the rune pair, in pixels.
|
## The kerning adjustment for the rune pair, in pixels.
|
||||||
if typeface.opentype != nil:
|
let
|
||||||
typeface.opentype.getKerningAdjustment(left, right)
|
typefaceRight = typeface.fallbackTypeface(right)
|
||||||
else:
|
typefaceLeft = typeface.fallbackTypeface(left)
|
||||||
typeface.svgfont.getKerningAdjustment(left, right)
|
# Only do kerning if both typefaces are the same.
|
||||||
|
if typefaceRight == typefaceLeft:
|
||||||
|
if typefaceRight.opentype != nil:
|
||||||
|
result = typefaceRight.opentype.getKerningAdjustment(left, right)
|
||||||
|
else:
|
||||||
|
result = typefaceRight.svgfont.getKerningAdjustment(left, right)
|
||||||
|
|
||||||
|
# Apply typeface ratio.
|
||||||
|
result *= typeface.scale / typefaceRight.scale
|
||||||
|
|
||||||
proc scale*(font: Font): float32 {.inline, raises: [].} =
|
proc scale*(font: Font): float32 {.inline, raises: [].} =
|
||||||
## The scale factor to transform font units into pixels.
|
## The scale factor to transform font units into pixels.
|
||||||
|
|
|
@ -1068,3 +1068,26 @@ block:
|
||||||
image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.")
|
image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.")
|
||||||
|
|
||||||
doDiff(image, "fallback")
|
doDiff(image, "fallback")
|
||||||
|
|
||||||
|
block:
|
||||||
|
let
|
||||||
|
font = readFont("tests/fonts/Inter-Regular.ttf")
|
||||||
|
typeface1 = readTypeface("tests/fonts/Aclonica-Regular_1.ttf")
|
||||||
|
typeface2 = readTypeface("tests/fonts/Ubuntu-Regular_1.ttf")
|
||||||
|
typeface3 = readTypeface("tests/fonts/NotoSansJP-Regular.ttf")
|
||||||
|
|
||||||
|
# font
|
||||||
|
# |.... typeface1
|
||||||
|
# |.... typeface2
|
||||||
|
# |.... typeface3 (with JP)
|
||||||
|
|
||||||
|
font.typeface.fallbacks.add(typeface1)
|
||||||
|
typeface1.fallbacks.add(typeface2)
|
||||||
|
typeface1.fallbacks.add(typeface3)
|
||||||
|
|
||||||
|
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, "fallback2")
|
||||||
|
|
Loading…
Reference in a new issue