From c0f31b276fa6a99bd3a7de8c1c82b6a8704315be Mon Sep 17 00:00:00 2001 From: Andre von Houck Date: Fri, 17 Sep 2021 06:25:13 -0700 Subject: [PATCH 1/5] Add font fallback. --- src/pixie/fonts.nim | 62 +++++++++++++++++++++--------- tests/fonts/diffs/fallback.png | Bin 0 -> 16027 bytes tests/fonts/masters/fallback.png | Bin 0 -> 8000 bytes tests/fonts/rendered/fallback.png | Bin 0 -> 16304 bytes tests/test_fonts.nim | 11 ++++++ 5 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 tests/fonts/diffs/fallback.png create mode 100644 tests/fonts/masters/fallback.png create mode 100644 tests/fonts/rendered/fallback.png diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index f2d019a..ec7d585 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -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. diff --git a/tests/fonts/diffs/fallback.png b/tests/fonts/diffs/fallback.png new file mode 100644 index 0000000000000000000000000000000000000000..80016e6835db274b2312b6c844f1ce7f1d828ebf GIT binary patch literal 16027 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
u3(1D@m-GRlwLyk%$Ov> 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 NnVVP{*BU;K{XejuqM85z literal 0 HcmV?d00001 diff --git a/tests/fonts/rendered/fallback.png b/tests/fonts/rendered/fallback.png new file mode 100644 index 0000000000000000000000000000000000000000..a200ca0c7aadcc354eb60d391caa15218d016789 GIT binary patch literal 16304 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 literal 0 HcmV?d00001 diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index b4a34e3..b583d59 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -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") From 8a88cd29fab11dc5418e362bb0b6a36d98f0a030 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 1 Oct 2021 10:18:12 -0700 Subject: [PATCH 2/5] No need to check for rune.uint32 > SP.uint32 because typeset alreayd does. --- src/pixie/fonts.nim | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index ec7d585..d409434 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -107,31 +107,27 @@ proc isCCW(typeface: Typeface): bool {.inline.} = 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) - if typeface.opentype != nil: - typeface.opentype.hasGlyph(rune) - else: - typeface.svgFont.hasGlyph(rune) + if typeface.opentype != nil: + typeface.opentype.hasGlyph(rune) else: - false + typeface.svgFont.hasGlyph(rune) 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)) + if typeface.hasGlyph(rune): + if typeface.opentype != nil: + result.addPath(typeface.opentype.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))) + 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. @@ -153,7 +149,6 @@ proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} else: return typeface.svgFont.getAdvance(rune) - proc getKerningAdjustment*( typeface: Typeface, left, right: Rune ): float32 {.inline, raises: [].} = From a8e1943556e9f5c497e391f67b41c48b131b7166 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 1 Oct 2021 10:43:10 -0700 Subject: [PATCH 3/5] Better fallback --- src/pixie/fonts.nim | 74 ++++++++++++++++++++++++++------------------ tests/test_fonts.nim | 23 ++++++++++++++ 2 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index d409434..648f964 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -112,51 +112,65 @@ proc hasGlyph*(typeface: Typeface, rune: Rune): bool {.inline.} = else: 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*( typeface: Typeface, rune: Rune ): Path {.inline, raises: [PixieError].} = ## The glyph path for the rune. result = newPath() - if typeface.hasGlyph(rune): - if typeface.opentype != nil: - result.addPath(typeface.opentype.getGlyphPath(rune)) - else: - result.addPath(typeface.svgFont.getGlyphPath(rune)) + + let typeface2 = typeface.fallbackTypeface(rune) + if typeface2 == nil: + return + + if typeface2.opentype != nil: + result.addPath(typeface2.opentype.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))) + result.addPath(typeface2.svgFont.getGlyphPath(rune)) + + # Apply typeface ratio. + let ratio = typeface.scale / typeface2.scale + if ratio != 1.0: + result.transform(scale(vec2(ratio, ratio))) proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} = ## The advance for the rune in pixels. - if typeface.hasGlyph(rune): - if typeface.opentype != nil: - return typeface.opentype.getAdvance(rune) - 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 + let typeface2 = typeface.fallbackTypeface(rune) + if typeface2 == nil: + return - if typeface.opentype != nil: - return typeface.opentype.getAdvance(rune) - else: - return typeface.svgFont.getAdvance(rune) + if typeface2.opentype != nil: + result = typeface2.opentype.getAdvance(rune) + else: + result = typeface2.svgFont.getAdvance(rune) + + # Apply typeface ratio. + result *= typeface.scale / typeface2.scale proc getKerningAdjustment*( typeface: Typeface, left, right: Rune ): float32 {.inline, raises: [].} = ## The kerning adjustment for the rune pair, in pixels. - if typeface.opentype != nil: - typeface.opentype.getKerningAdjustment(left, right) - else: - typeface.svgfont.getKerningAdjustment(left, right) + let + typefaceRight = typeface.fallbackTypeface(right) + typefaceLeft = typeface.fallbackTypeface(left) + # 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: [].} = ## The scale factor to transform font units into pixels. diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index b583d59..c54150d 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -1068,3 +1068,26 @@ block: image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.") 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") From a1659198e37cac0a1a7f349256c26d7a35f5decf Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 1 Oct 2021 10:43:43 -0700 Subject: [PATCH 4/5] Add files. --- tests/fonts/diffs/fallback2.png | Bin 0 -> 15564 bytes tests/fonts/masters/fallback2.png | Bin 0 -> 7366 bytes tests/fonts/rendered/fallback2.png | Bin 0 -> 16304 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fonts/diffs/fallback2.png create mode 100644 tests/fonts/masters/fallback2.png create mode 100644 tests/fonts/rendered/fallback2.png diff --git a/tests/fonts/diffs/fallback2.png b/tests/fonts/diffs/fallback2.png new file mode 100644 index 0000000000000000000000000000000000000000..35a9e3a29e896237bae974438897594703c61098 GIT binary patch literal 15564 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 F{{!QO`N9AI literal 0 HcmV?d00001 diff --git a/tests/fonts/masters/fallback2.png b/tests/fonts/masters/fallback2.png new file mode 100644 index 0000000000000000000000000000000000000000..11351fcc584aeb0e08f8818d223e199ed245b0c3 GIT binary patch literal 7366 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 literal 0 HcmV?d00001 From 052eeb5a18e2bc1043d27dbfb1cd29e8f5d39fb5 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 1 Oct 2021 10:53:56 -0700 Subject: [PATCH 5/5] Fix tofu advance. --- src/pixie/fonts.nim | 5 +++-- tests/fonts/diffs/tofu_advance.png | Bin 0 -> 4790 bytes tests/fonts/masters/tofu_advance.png | Bin 0 -> 2805 bytes tests/fonts/rendered/tofu_advance.png | Bin 0 -> 5728 bytes tests/test_fonts.nim | 10 ++++++++++ 5 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/fonts/diffs/tofu_advance.png create mode 100644 tests/fonts/masters/tofu_advance.png create mode 100644 tests/fonts/rendered/tofu_advance.png diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index 648f964..0b42065 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -143,9 +143,10 @@ proc getGlyphPath*( proc getAdvance*(typeface: Typeface, rune: Rune): float32 {.inline, raises: [].} = ## The advance for the rune in pixels. - let typeface2 = typeface.fallbackTypeface(rune) + var typeface2 = typeface.fallbackTypeface(rune) if typeface2 == nil: - return + # Get tofu advance, see tofu_advance test. + typeface2 = typeface if typeface2.opentype != nil: result = typeface2.opentype.getAdvance(rune) diff --git a/tests/fonts/diffs/tofu_advance.png b/tests/fonts/diffs/tofu_advance.png new file mode 100644 index 0000000000000000000000000000000000000000..2b30fd23ec3e855a8213c2a59d46a6e66f67d590 GIT binary patch literal 4790 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 YWNoWg;)~pM%6Sw3aa&)rOx-5xU;Yp4&j0`b literal 0 HcmV?d00001 diff --git a/tests/fonts/masters/tofu_advance.png b/tests/fonts/masters/tofu_advance.png new file mode 100644 index 0000000000000000000000000000000000000000..adee2e33fd9fcaa460a16cff92659a2918d81864 GIT binary patch literal 2805 zcmeHJ`!^fd7CtFzs$*(8*UV6_KHOH(R$EmfUQ>!HLlQ>3rbV?Pv`GmfYF_Q!*0UW! z6>XQw5JZa*iO|ke2u<1|@yMfwG$q6%Lqt4odhZ``f4S?defB=zUhAB_&syKw-@m>M zJZorRY5)K*^z%Iv0)UQ{HjevbyLQhGMigk>j;p@mH~@Bj@zEgQ{)4ZzAOsh3)(bRp z&8D>n-2~6`o&Y>8*tvc|4*-MPerG%p>5w_mT+u&}d$zv|mv2ygfX_pp9IaVtqmMqv zC+7^%t|lXh(Q_8gY1!^p4TFp?b5__1kdBIDgO&*$<8?Td`oq2E215Wm^s6x1w_HB= z03auMvu)y`g?sk;^8}|9u~{?#3$@M;+ozfW0|VVwXE!%A<>PHBDFD2Kz#nvX|BawhRCL`~U6^=3+MKWlfK`Mcx{6-*37jjRY#+l?XRzK zmn1}$Xu(aI+_vn1&3@L||G-wv$>>w}Eq4{jjkP5?=oTXQF{~^){r7qSi+8G~!))#? zEuER6ywn_28&_3XnVcW|!n2~JYjX|#NxJ5;`R)EnTe1IYuY*vvYyhr`3?bDW?s-p; z`|z{#Li!0rHhTqW!WB*F@3Q!`*d=zq*zdz3XZIZkV2lC?=w@mA@w|9AAZt@CD_`4u z-F&L{yDsWn67eNY3eMy!r7sj**8-AuS`Lp=OfmSgK zwF(vLdD$Z&dgL+vWA1-W#L*H*+t6u`@XQ zJ&k~ihr(d6nD=!fw75^>IZwx|rO73t&=2k__ec_LV zjFr~72xm(YgQ!^{RLM$%D#&ADEK7kZTgJ^v{N>%a8Nk_-_MOJ#JS*Az)s)d3lYwd z!UV-yfvU~hl>QQ8QE1Y21pgQ(b89dv;#c04gyFYjm7=0liuWPe_d--5 zt}wQ>Iv-bj!7esRWO6{Ou{IYe8h>Q2nNZdm9%(xAw>7%6#SN(rd zX#+c~9NMDi+Fsl_IHCh)*&qo{KAi;-A4k53qJ5t_u*C3xbikWG|$bcfPmi zmE}=*@l@0#nxrMQlCuIQr7`_ri%?IjU@_>}<(OgYv#G}d?wADX7$H!~cs$8bm?6v1 z3eC2MfMfFy2Nx9IbnvIH4A!pKctsljZJNZqF4!2UejFXeUHX)?*3hudN8E%zveYk3 zGZk4g@&&>i)#35TbKd+uwZC+8UqfUGQqw-5rly{-dErgc2k#~$)nK;?uQ2(W+Cnn6 z{B|;Ies7ia&ylyno5rAvj2`o9N@#xn-X2!<6R9BP25~;zVpw#gkr0-DBahv?WNefo zY`-SP7M9hoT(Nv))!>ZIpGd`A(*Ymm4sG+T-W?H@v(NZ1#9R31K`+}nJ~MBw>lU1B z!6iQEZNG!iSan%5SX9WoqcP^i%Md}6?!ChV&OMLQjYCIMaUJz*opbGlt#xQ5C$p>( zx#LI-ak)4-9DuK`pM=EKZ)2ClWM_!aZk6izLc5_S2=;n~*LnV{rud>d&O+nC8fw`u zcE-via!1s#q!uze_fADm$TfSs6TTsSA|w4d^o6)NnNtyat<31DJlqa|0BG+?rsnSL z*bdFWt2*P1ktj2Q$Y z8UjV{QoY5gQvPk4aZN>Vl47i{WAyC#oY$tjUOmw566TUqjV^Pq?Zt~nl+{s2(j_MS zArrNR&uri@OegV2LM@ppV;-n(nW(Frsrq^`8 z2>Kq}<^MpJp$EzcO)&(!5OrfLiMQltthm02iWM%M45R558rY5|kouiDwweIF>{?@a z>;d0^sQr#U``M=i!7xMeB1ONd!l&Q<)i6~poYC}k;?G}8}KA+g_3P2>k^)oBDC^j=q-@x8nt2(%? zb3bY&Pb4fX(^RWM-evw*p6D6@@Nf@A7l02w+Ur2a|Ka5S!JlmI65hXL8)2>?Yn3DL N^A0@I==J@N{{{^?Gn4=T literal 0 HcmV?d00001 diff --git a/tests/fonts/rendered/tofu_advance.png b/tests/fonts/rendered/tofu_advance.png new file mode 100644 index 0000000000000000000000000000000000000000..a1deb57338b997cba10a5f5e60e4ec9500829731 GIT binary patch literal 5728 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 K%B6}{q5lPrM80PL literal 0 HcmV?d00001 diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index c54150d..6b78f7c 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -1091,3 +1091,13 @@ block: image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.") doDiff(image, "fallback2") + +block: + var font = readFont("tests/fonts/Inter-Regular.ttf") + + font.size = 26 + let image = newImage(800, 100) + image.fill(rgba(255, 255, 255, 255)) + image.fillText(font, "This[]Advance!") + + doDiff(image, "tofu_advance")