Skip to content

Commit 16ed156

Browse files
authored
Merge pull request #897 from googlefonts/fix-info-compiler-codepage-ranges
fix InfoCompiler overwriting the default master's codepage range bits
2 parents 5a606b7 + 7e9c7b3 commit 16ed156

File tree

3 files changed

+30
-104
lines changed

3 files changed

+30
-104
lines changed

Lib/ufo2ft/outlineCompiler.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
from ufo2ft.util import (
5252
_copyGlyph,
5353
_getNewGlyphFactory,
54-
calcCodePageRanges,
5554
colrClipBoxQuantization,
5655
getMaxComponentDepth,
5756
makeOfficialGlyphOrder,
@@ -665,11 +664,11 @@ def adjustOffset(offset, angle):
665664

666665
# codepage ranges
667666
codepageRanges = getAttrWithFallback(font.info, "openTypeOS2CodePageRanges")
668-
if codepageRanges is None:
669-
unicodes = self.unicodeToGlyphNameMapping.keys()
670-
codepageRanges = calcCodePageRanges(unicodes)
671-
os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32)
672-
os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32)
667+
if codepageRanges is not None:
668+
os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32)
669+
os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32)
670+
elif "cmap" in self.otf:
671+
os2.recalcCodePageRanges(self.otf)
673672

674673
# vendor id, padded with spaces if < 4 bytes
675674
os2.achVendID = getAttrWithFallback(font.info, "openTypeOS2VendorID").ljust(4)
@@ -1066,8 +1065,7 @@ def setupTable_meta(self):
10661065
isinstance(string, str) for string in value
10671066
):
10681067
raise TypeError(
1069-
f"public.openTypeMeta '{key}' value should "
1070-
"be a list of strings"
1068+
f"public.openTypeMeta '{key}' value should be a list of strings"
10711069
)
10721070
meta.data[key] = ",".join(value)
10731071
elif key in ["appl", "bild"]:

Lib/ufo2ft/util.py

+4-95
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
from fontTools.pens.reverseContourPen import ReverseContourPen
1919
from fontTools.pens.transformPen import TransformPen
2020

21+
# we keep this unused import in case some external code relied on the
22+
# old location of this function, which now lives in fontTools
23+
from fontTools.ttLib.tables.O_S_2f_2 import calcCodePageRanges # noqa: F401
24+
2125
from ufo2ft.constants import OPENTYPE_CATEGORIES_KEY, UNICODE_SCRIPT_ALIASES
2226
from ufo2ft.errors import InvalidDesignSpaceData, InvalidFontData
2327
from ufo2ft.fontInfoData import getAttrWithFallback
@@ -373,101 +377,6 @@ def unicodeScriptDirection(uv):
373377
return unicodedata.script_horizontal_direction(sc, "LTR")
374378

375379

376-
def calcCodePageRanges(unicodes):
377-
"""Given a set of Unicode codepoints (integers), calculate the
378-
corresponding OS/2 CodePage range bits.
379-
This is a direct translation of FontForge implementation:
380-
https://github.com/fontforge/fontforge/blob/7b2c074/fontforge/tottf.c#L3158
381-
"""
382-
codepageRanges = set()
383-
384-
chars = [chr(u) for u in unicodes]
385-
386-
hasAscii = set(range(0x20, 0x7E)).issubset(unicodes)
387-
hasLineart = "┤" in chars
388-
389-
for char in chars:
390-
if char == "Þ" and hasAscii:
391-
codepageRanges.add(0) # Latin 1
392-
elif char == "Ľ" and hasAscii:
393-
codepageRanges.add(1) # Latin 2: Eastern Europe
394-
if hasLineart:
395-
codepageRanges.add(58) # Latin 2
396-
elif char == "Б":
397-
codepageRanges.add(2) # Cyrillic
398-
if "Ѕ" in chars and hasLineart:
399-
codepageRanges.add(57) # IBM Cyrillic
400-
if "╜" in chars and hasLineart:
401-
codepageRanges.add(49) # MS-DOS Russian
402-
elif char == "Ά":
403-
codepageRanges.add(3) # Greek
404-
if hasLineart and "½" in chars:
405-
codepageRanges.add(48) # IBM Greek
406-
if hasLineart and "√" in chars:
407-
codepageRanges.add(60) # Greek, former 437 G
408-
elif char == "İ" and hasAscii:
409-
codepageRanges.add(4) # Turkish
410-
if hasLineart:
411-
codepageRanges.add(56) # IBM turkish
412-
elif char == "א":
413-
codepageRanges.add(5) # Hebrew
414-
if hasLineart and "√" in chars:
415-
codepageRanges.add(53) # Hebrew
416-
elif char == "ر":
417-
codepageRanges.add(6) # Arabic
418-
if "√" in chars:
419-
codepageRanges.add(51) # Arabic
420-
if hasLineart:
421-
codepageRanges.add(61) # Arabic; ASMO 708
422-
elif char == "ŗ" and hasAscii:
423-
codepageRanges.add(7) # Windows Baltic
424-
if hasLineart:
425-
codepageRanges.add(59) # MS-DOS Baltic
426-
elif char == "₫" and hasAscii:
427-
codepageRanges.add(8) # Vietnamese
428-
elif char == "ๅ":
429-
codepageRanges.add(16) # Thai
430-
elif char == "エ":
431-
codepageRanges.add(17) # JIS/Japan
432-
elif char == "ㄅ":
433-
codepageRanges.add(18) # Chinese: Simplified chars
434-
elif char == "ㄱ":
435-
codepageRanges.add(19) # Korean wansung
436-
elif char == "央":
437-
codepageRanges.add(20) # Chinese: Traditional chars
438-
elif char == "곴":
439-
codepageRanges.add(21) # Korean Johab
440-
elif char == "♥" and hasAscii:
441-
codepageRanges.add(30) # OEM Character Set
442-
# TODO: Symbol bit has a special meaning (check the spec), we need
443-
# to confirm if this is wanted by default.
444-
# elif chr(0xF000) <= char <= chr(0xF0FF):
445-
# codepageRanges.add(31) # Symbol Character Set
446-
elif char == "þ" and hasAscii and hasLineart:
447-
codepageRanges.add(54) # MS-DOS Icelandic
448-
elif char == "╚" and hasAscii:
449-
codepageRanges.add(62) # WE/Latin 1
450-
codepageRanges.add(63) # US
451-
elif hasAscii and hasLineart and "√" in chars:
452-
if char == "Å":
453-
codepageRanges.add(50) # MS-DOS Nordic
454-
elif char == "é":
455-
codepageRanges.add(52) # MS-DOS Canadian French
456-
elif char == "õ":
457-
codepageRanges.add(55) # MS-DOS Portuguese
458-
459-
if hasAscii and "‰" in chars and "∑" in chars:
460-
codepageRanges.add(29) # Macintosh Character Set (US Roman)
461-
462-
# when no codepage ranges can be enabled, fall back to enabling bit 0
463-
# (Latin 1) so that the font works in MS Word:
464-
# https://github.com/googlei18n/fontmake/issues/468
465-
if not codepageRanges:
466-
codepageRanges.add(0)
467-
468-
return codepageRanges
469-
470-
471380
class _LazyFontName:
472381
def __init__(self, font):
473382
self.font = font

tests/infoCompiler_test.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,30 @@ def test_name(self, testttf, testufo):
5050
assert ttf["name"].getDebugName(6) == "TestFontOverride-Italic"
5151

5252
def test_OS2(self, testttf, testufo):
53-
info = {"openTypeOS2TypoAscender": 100, "openTypeOS2TypoDescender": -200}
53+
info = {
54+
"openTypeOS2TypoAscender": 100,
55+
"openTypeOS2TypoDescender": -200,
56+
"openTypeOS2CodePageRanges": [0, 1, 2, 3, 32, 32 + 1, 32 + 2, 32 + 3],
57+
}
5458
compiler = InfoCompiler(testttf, testufo, info)
5559
ttf = compiler.compile()
5660
assert ttf["OS/2"].sTypoAscender == 100
5761
assert ttf["OS/2"].sTypoDescender == -200
62+
assert ttf["OS/2"].ulCodePageRange1 == 0b1111
63+
assert ttf["OS/2"].ulCodePageRange2 == 0b1111
64+
65+
def test_OS2_dont_overwrite_codePageRanges(self, testttf, testufo):
66+
# if the variable-font's 'public.fontInfo' lib key does not override the
67+
# openTypeOS2CodePageRanges, we should keep the original values as defined
68+
# or computed for the default master TTF.
69+
ulCodePageRange1 = testttf["OS/2"].ulCodePageRange1
70+
ulCodePageRange2 = testttf["OS/2"].ulCodePageRange2
71+
testufo.info.openTypeOS2CodePageRanges = None
72+
info = {}
73+
compiler = InfoCompiler(testttf, testufo, info)
74+
ttf = compiler.compile()
75+
assert ttf["OS/2"].ulCodePageRange1 == ulCodePageRange1
76+
assert ttf["OS/2"].ulCodePageRange2 == ulCodePageRange2
5877

5978
def test_post(self, testttf, testufo):
6079
info = {"italicAngle": 30.6}

0 commit comments

Comments
 (0)