[feaLib]Escape nameid strings when writing feature files
https://github.com/fonttools/fonttools/issues/780
This commit is contained in:
parent
7cf22d01ae
commit
b22df7ff48
@ -1,6 +1,8 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from __future__ import unicode_literals
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.feaLib.error import FeatureLibError
|
||||
from fontTools.misc.encodingTools import getEncoding
|
||||
from collections import OrderedDict
|
||||
import itertools
|
||||
|
||||
@ -1059,10 +1061,27 @@ class NameRecord(Statement):
|
||||
self.platEncID, self.langID, self.string)
|
||||
|
||||
def asFea(self, indent=""):
|
||||
plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
|
||||
def escape(c, escape_pattern):
|
||||
# Also escape U+0022 QUOTATION MARK and U+005C REVERSE SOLIDUS
|
||||
if c >= 0x20 and c <= 0x7E and c not in (0x22, 0x5C):
|
||||
return unichr(c)
|
||||
else:
|
||||
return escape_pattern % c
|
||||
encoding = getEncoding(self.platformID, self.platEncID, self.langID)
|
||||
if encoding is None:
|
||||
raise FeatureLibError("Unsupported encoding", self.location)
|
||||
s = tobytes(self.string, encoding=encoding)
|
||||
if encoding == "utf_16_be":
|
||||
escaped_string = "".join([
|
||||
escape(byteord(s[i]) * 256 + byteord(s[i + 1]), r"\%04x")
|
||||
for i in range(0, len(s), 2)])
|
||||
else:
|
||||
escaped_string = "".join([escape(byteord(b), r"\%02x") for b in s])
|
||||
plat = simplify_name_attributes(
|
||||
self.platformID, self.platEncID, self.langID)
|
||||
if plat != "":
|
||||
plat += " "
|
||||
return "nameid {} {}\"{}\";".format(self.nameID, plat, self.string)
|
||||
return "nameid {} {}\"{}\";".format(self.nameID, plat, escaped_string)
|
||||
|
||||
|
||||
class FeatureNameStatement(NameRecord):
|
||||
|
@ -1,6 +1,4 @@
|
||||
table name {
|
||||
#test-fea2fea: nameid 9 "Joachim Müller-Lancé";
|
||||
nameid 9 "Joachim M\00fcller-Lanc\00e9"; # Windows (Unicode)
|
||||
#test-fea2fea: nameid 9 1 "Joachim Müller-Lancé";
|
||||
nameid 9 1 "Joachim M\9fller-Lanc\8e"; # Macintosh (Mac Roman)
|
||||
} name;
|
||||
|
@ -87,7 +87,15 @@ class LexerTest(unittest.TestCase):
|
||||
[(Lexer.STRING, "foo"), (Lexer.STRING, "bar")])
|
||||
self.assertEqual(lex('"foo \nbar\r baz \r\nqux\n\n "'),
|
||||
[(Lexer.STRING, "foo bar baz qux ")])
|
||||
self.assertRaises(FeatureLibError, lambda: lex('"foo\n bar'))
|
||||
# The lexer should preserve escape sequences because they have
|
||||
# different interpretations depending on context. For better
|
||||
# or for worse, that is how the OpenType Feature File Syntax
|
||||
# has been specified; see section 9.e (name table) for examples.
|
||||
self.assertEqual(lex(r'"M\00fcller-Lanc\00e9"'), # 'nameid 9'
|
||||
[(Lexer.STRING, r"M\00fcller-Lanc\00e9")])
|
||||
self.assertEqual(lex(r'"M\9fller-Lanc\8e"'), # 'nameid 9 1'
|
||||
[(Lexer.STRING, r"M\9fller-Lanc\8e")])
|
||||
self.assertRaises(FeatureLibError, lex, '"foo\n bar')
|
||||
|
||||
def test_bad_character(self):
|
||||
self.assertRaises(FeatureLibError, lambda: lex("123 \u0001"))
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from __future__ import unicode_literals
|
||||
from fontTools.feaLib.error import FeatureLibError
|
||||
@ -901,6 +902,69 @@ class ParserTest(unittest.TestCase):
|
||||
self.assertEqual(mc.glyphSet(), ("acute", "grave"))
|
||||
self.assertEqual((mc.anchor.x, mc.anchor.y), (350, 3))
|
||||
|
||||
def test_nameid_windows_utf16(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 9 "M\00fcller-Lanc\00e9"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertIsInstance(name, ast.NameRecord)
|
||||
self.assertEquals(name.nameID, 9)
|
||||
self.assertEquals(name.platformID, 3)
|
||||
self.assertEquals(name.platEncID, 1)
|
||||
self.assertEquals(name.langID, 0x0409)
|
||||
self.assertEquals(name.string, "Müller-Lancé")
|
||||
self.assertEquals(name.asFea(), r'nameid 9 "M\00fcller-Lanc\00e9";')
|
||||
|
||||
def test_nameid_windows_utf16_backslash(self):
|
||||
doc = self.parse(r'table name { nameid 9 "Back\005cslash"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertEquals(name.string, r"Back\slash")
|
||||
self.assertEquals(name.asFea(), r'nameid 9 "Back\005cslash";')
|
||||
|
||||
def test_nameid_windows_utf16_quotation_mark(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 9 "Quotation \0022Mark\0022"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertEquals(name.string, 'Quotation "Mark"')
|
||||
self.assertEquals(name.asFea(), r'nameid 9 "Quotation \0022Mark\0022";')
|
||||
|
||||
def test_nameid_windows_utf16_surroates(self):
|
||||
pass
|
||||
# TODO: https://github.com/fonttools/fonttools/issues/842
|
||||
# doc = self.parse(r'table name { nameid 9 "Carrot \D83E\DD55"; } name;')
|
||||
# name = doc.statements[0].statements[0]
|
||||
# self.assertEquals(name.string, r"Carrot 🥕")
|
||||
# self.assertEquals(name.asFea(), r'nameid 9 "Carrot \d83e\dd55";')
|
||||
|
||||
def test_nameid_mac_roman(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 9 1 "Joachim M\9fller-Lanc\8e"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertIsInstance(name, ast.NameRecord)
|
||||
self.assertEquals(name.nameID, 9)
|
||||
self.assertEquals(name.platformID, 1)
|
||||
self.assertEquals(name.platEncID, 0)
|
||||
self.assertEquals(name.langID, 0)
|
||||
self.assertEquals(name.string, "Joachim Müller-Lancé")
|
||||
self.assertEquals(name.asFea(),
|
||||
r'nameid 9 1 "Joachim M\9fller-Lanc\8e";')
|
||||
|
||||
def test_nameid_mac_croatian(self):
|
||||
doc = self.parse(
|
||||
r'table name { nameid 9 1 0 18 "Jovica Veljovi\e6"; } name;')
|
||||
name = doc.statements[0].statements[0]
|
||||
self.assertEquals(name.nameID, 9)
|
||||
self.assertEquals(name.platformID, 1)
|
||||
self.assertEquals(name.platEncID, 0)
|
||||
self.assertEquals(name.langID, 18)
|
||||
# TODO: https://github.com/fonttools/fonttools/issues/842
|
||||
# self.assertEquals(name.string, "Jovica Veljović")
|
||||
# self.assertEquals(name.asFea(), r'nameid 9 1 0 18 "Jovica Veljovi\e6";')
|
||||
|
||||
def test_nameid_unsupported_platform(self):
|
||||
self.assertRaisesRegex(
|
||||
FeatureLibError, "Expected platform id 1 or 3",
|
||||
self.parse, 'table name { nameid 9 666 "Foo"; } name;')
|
||||
|
||||
def test_rsub_format_a(self):
|
||||
doc = self.parse("feature test {rsub a [b B] c' d [e E] by C;} test;")
|
||||
rsub = doc.statements[0].statements[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user