diff --git a/font_collector/font/abc_font_face.py b/font_collector/font/abc_font_face.py index fd05588..f215fcb 100644 --- a/font_collector/font/abc_font_face.py +++ b/font_collector/font/abc_font_face.py @@ -27,7 +27,7 @@ from .cmap import CMap from .font_parser import FontParser from .font_type import FontType -from .name import Name +from .name import MacintoshEncodingID, MicrosoftEncodingID, Name, PlatformID if TYPE_CHECKING: from .font_file import FontFile @@ -298,44 +298,37 @@ def get_missing_glyphs( platform_id = charmap.contents.platform_id encoding_id = charmap.contents.encoding_id - cmap_encoding = FontParser.get_cmap_encoding(platform_id, encoding_id) - - # cmap not supported - if cmap_encoding is None: - continue - - if cmap_encoding == "unicode": - codepoint = ord(char) + if platform_id == PlatformID.MICROSOFT: + match encoding_id: + case MicrosoftEncodingID.SYMBOL: + codepoint = FontParser.get_glyph_id_for_symbol_cmap(ttFont, face, char, support_only_ascii_char_for_symbol_font) + case MicrosoftEncodingID.UNICODE_BMP: + is_legacy, legacy_codepoint = FontParser.get_glyph_id_for_legacy_cmap(ttFont, char) + codepoint = legacy_codepoint if is_legacy else ord(char) + case MicrosoftEncodingID.UNICODE_FULL: + codepoint = ord(char) + case _: + cmap_encoding = FontParser.MICROSOFT_CMAP_ENCODING_MAP.get(encoding_id) + if cmap_encoding is None: + raise ValueError(f"The encodingID {encoding_id} doesn't exist for microsoft platform. This should never happen.") + try: + codepoint = int.from_bytes(char.encode(cmap_encoding), "big") + except UnicodeEncodeError: + codepoint = None + elif platform_id == PlatformID.MACINTOSH: + match encoding_id: + case MacintoshEncodingID.ROMAN: + try: + codepoint = int.from_bytes(char.encode("mac_roman"), "big") + except UnicodeEncodeError: + codepoint = None + case _: + raise ValueError(f"The encodingID {encoding_id} doesn't exist for mac platform. This should never happen.") else: - symbol_cmap = False - if cmap_encoding == "unknown": - if platform_id == 3 and encoding_id == 0: - symbol_cmap = True - if support_only_ascii_char_for_symbol_font and not char.isascii(): - continue - cmap_encoding = FontParser.get_symbol_cmap_encoding(face) + raise ValueError(f"The platformID {platform_id} isn't supported by GDI. This should never happen.") - if cmap_encoding is None: - # Fallback if guess fails - cmap_encoding = "cp1252" - else: - # cmap not supported - continue - - if symbol_cmap and (0xF020 <= ord(char) and ord(char) <= 0xF0FF): - # If the character is already a "symbol" character (a.k.a is between 0xF020 and 0xF0FF), - # GDI directly use it's codepoint. - codepoint = ord(char) - else: - try: - codepoint = int.from_bytes(char.encode(cmap_encoding), "big") - except UnicodeEncodeError: - continue - - # GDI/Libass modify the codepoint for microsoft symbol cmap. - # See: https://github.com/libass/libass/blob/04a208d5d200360d2ac75f8f6cfc43dd58dd9225/libass/ass_font.c#L249-L250 - if platform_id == 3 and encoding_id == 0: - codepoint = 0xF000 | codepoint + if codepoint is None: + continue index = FT_Get_Char_Index(face, codepoint) diff --git a/font_collector/font/font_parser.py b/font_collector/font/font_parser.py index b48d017..8d47c93 100644 --- a/font_collector/font/font_parser.py +++ b/font_collector/font/font_parser.py @@ -10,13 +10,14 @@ from fontTools.ttLib.tables._n_a_m_e import NameRecord from fontTools.ttLib.ttFont import TTFont from fontTools.varLib.instancer.names import ELIDABLE_AXIS_VALUE_NAME -from freetype import Face, FT_Face, FT_Get_Glyph_Name +from freetype import FT_Get_First_Char, FT_UInt, Face, FT_Face, FT_Get_Glyph_Name from freetype.ft_enums.ft_style_flags import FT_STYLE_FLAGS from langcodes import Language from ..exceptions import InvalidNameRecord, InvalidVariableFontFaceException from .cmap import CMap -from .name import Name, NameID, PlatformID +from .legacy_cmap_mapping import arabic_simplified_cmap_mapping, arabic_traditional_cmap_mapping +from .name import MacintoshEncodingID, MicrosoftEncodingID, Name, NameID, PlatformID class FontParser: @@ -26,20 +27,16 @@ class FontParser: DEFAULT_WEIGHT = 400 DEFAULT_ITALIC = False - CMAP_ENCODING_MAP: dict[PlatformID, dict[int, str]] = { - PlatformID.MACINTOSH: { - 0: "mac_roman", - }, - PlatformID.MICROSOFT: { - 0: "unknown", - 1: "unicode", - 2: "cp932", - 3: "cp936", - 4: "cp950", - 5: "cp949", - 6: "cp1361", - 10: "unicode", - }, + MICROSOFT_CMAP_ENCODING_MAP: dict[int, str] = { + MicrosoftEncodingID.SHIFT_JIS: "cp932", + MicrosoftEncodingID.PRC: "cp936", + MicrosoftEncodingID.BIG5: "cp950", + MicrosoftEncodingID.WANSUNG: "cp949", + MicrosoftEncodingID.JOHAB: "cp1361", + } + LEGACY_CHARSET_CMAPS: dict[int, dict[int, int]] = { + 178: arabic_simplified_cmap_mapping, + 179: arabic_traditional_cmap_mapping, } @@ -522,8 +519,7 @@ def get_supported_cmaps( cmap_tables: list[CmapSubtable] = font["cmap"].tables for table in cmap_tables: - encoding = FontParser.get_cmap_encoding(table.platformID, table.platEncID) - if encoding is not None: + if FontParser.is_cmap_supported(table.platformID, table.platEncID): cmap = CMap(table.platformID, table.platEncID) if table.platformID == PlatformID.MICROSOFT: microsoft_cmaps.append(cmap) @@ -534,8 +530,7 @@ def get_supported_cmaps( face = Face(f, font_index) for charmap in face.charmaps: - encoding = FontParser.get_cmap_encoding(charmap.platform_id, charmap.encoding_id) - if encoding is not None: + if FontParser.is_cmap_supported(charmap.platform_id, charmap.encoding_id): cmap = CMap(charmap.platform_id, charmap.encoding_id) if charmap.platform_id == PlatformID.MICROSOFT: microsoft_cmaps.append(cmap) @@ -545,22 +540,103 @@ def get_supported_cmaps( @staticmethod - def get_cmap_encoding(platform_id: int, encoding_id: int) -> str | None: + def is_cmap_supported(platform_id: int, encoding_id: int) -> bool: """ Args: platform_id: CMap platform id encoding_id: CMap encoding id Returns: - The cmap encoding. - If GDI does not support the platform_id and/or platform_encoding_id, return None. - Warning, if it return "unknown", it means that the cmap is from a symbol font. - Call get_symbol_cmap_encoding() to know what is the encoding. - Notes: - - GDI only supports all encodings for the Microsoft CMap. - - For the Macintosh platform, it only supports the platform encoding 1. + True if the cmap is supported by GDI. + Otherwhise, False. + """ + if platform_id == PlatformID.MICROSOFT: + return encoding_id in ( + MicrosoftEncodingID.SYMBOL, + MicrosoftEncodingID.UNICODE_BMP, + MicrosoftEncodingID.SHIFT_JIS, + MicrosoftEncodingID.PRC, + MicrosoftEncodingID.BIG5, + MicrosoftEncodingID.WANSUNG, + MicrosoftEncodingID.JOHAB, + MicrosoftEncodingID.UNICODE_FULL, + ) + elif platform_id == PlatformID.MACINTOSH: + return encoding_id == MacintoshEncodingID.ROMAN + return False + + @staticmethod + def get_glyph_id_for_legacy_cmap(font: TTFont, character: str) -> tuple[bool, int | None]: + """ + Args: + font: A fontTools object representing the font. + character: A single character. + Returns: + A tuple (is_legacy, glyph_id). + is_legacy is True if the font is a legacy font. + glyph_id is the character's remapped PUA codepoint if the charset's mapping contains it. + It is None if is_legacy is False, and also None if is_legacy is True but the character + isn't in that charset's mapping. + Note: + This method is identical to https://github.com/libass/libass/blob/b2fe9d8770678a7b5271387d38c20657ebf3429a/libass/ass_font.c#L250-L270 + """ + if "OS/2" not in font: + return False, None + + charset = (font["OS/2"].fsSelection >> 8) & 0xFF + mapping = FontParser.LEGACY_CHARSET_CMAPS.get(charset) + if mapping is None: + return False, None + + glyph_id = mapping.get(ord(character)) + return True, glyph_id + + + @staticmethod + def get_glyph_id_for_symbol_cmap(font: TTFont, face: FT_Face, character: str, support_only_ascii_char_for_symbol_font: bool) -> int | None: + """ + Args: + font: A fontTools object representing the font. + face: An Font face. + character: A single character. + support_only_ascii_char_for_symbol_font: See ABCFontFace.get_missing_glyphs. + Returns: + The glyph_id GDI would look up for this character in a microsoft symbol cmap. + Note: + This method is identical to https://github.com/libass/libass/blob/b2fe9d8770678a7b5271387d38c20657ebf3429a/libass/ass_font.c#L272-L320 """ - if platform_id in FontParser.CMAP_ENCODING_MAP: - return FontParser.CMAP_ENCODING_MAP[PlatformID(platform_id)].get(encoding_id, None) + is_legacy, legacy_codepoint = FontParser.get_glyph_id_for_legacy_cmap(font, character) + if is_legacy: + return legacy_codepoint + + gindex = FT_UInt() + first_char = FT_Get_First_Char(face, byref(gindex)) + + match first_char & 0xFF00: + case 0xF000: + offset = 0xF000 + case 0xE000 | 0x0000: + offset = 0 + case _: + offset = first_char - 0x20 + + is_symbol_glyph_set = bool(offset) or ( + "OS/2" in font and font["OS/2"].panose.bFamilyType == 5 and (font["OS/2"].fsSelection & 0xFF) == 0 + ) + if not is_symbol_glyph_set: + return ord(character) + + cmap_encoding = FontParser.get_symbol_cmap_encoding(face) or "cp1252" + try: + codepoint = int.from_bytes(character.encode(cmap_encoding), "big") + except UnicodeEncodeError: + codepoint = None + + if codepoint is not None and codepoint <= 0xFF: + if not support_only_ascii_char_for_symbol_font or character.isascii(): + return offset + codepoint + elif 0xF020 <= ord(character) <= 0xF0FF: + return offset + (ord(character) & 0xFF) + return None diff --git a/font_collector/font/legacy_cmap_mapping.py b/font_collector/font/legacy_cmap_mapping.py new file mode 100644 index 0000000..84c03c2 --- /dev/null +++ b/font_collector/font/legacy_cmap_mapping.py @@ -0,0 +1,533 @@ +# WARNING - THIS FILE IS AUTO-GENERATED. DO NOT EDIT IT MANUALLY. +# Regenerate with: python legacy_cmap/gen_cmap.py + +arabic_simplified_cmap_mapping : dict[int, int] = { + 0x20: 0xf120, + 0x21: 0xf121, + 0x22: 0xf122, + 0x25: 0xf125, + 0x28: 0xf128, + 0x29: 0xf129, + 0x2a: 0xf12a, + 0x2b: 0xf12b, + 0x2c: 0xf15e, + 0x2d: 0xf12d, + 0x2e: 0xf12e, + 0x2f: 0xf12f, + 0x30: 0xf1b0, + 0x31: 0xf1b1, + 0x32: 0xf1b2, + 0x33: 0xf1b3, + 0x34: 0xf1b4, + 0x35: 0xf1b5, + 0x36: 0xf1b6, + 0x37: 0xf1b7, + 0x38: 0xf1b8, + 0x39: 0xf1b9, + 0x3a: 0xf13a, + 0x3b: 0xf13b, + 0x3d: 0xf13d, + 0x3f: 0xf13f, + 0x5b: 0xf15b, + 0x5c: 0xf15c, + 0x5d: 0xf15d, + 0xab: 0xf123, + 0xbb: 0xf124, + 0xd7: 0xf126, + 0xf7: 0xf127, + 0x60c: 0xf12c, + 0x61b: 0xf13b, + 0x61f: 0xf13f, + 0x621: 0xf1ad, + 0x622: 0xf145, + 0x623: 0xf143, + 0x624: 0xf1bb, + 0x625: 0xf147, + 0x626: 0xf1ba, + 0x627: 0xf141, + 0x628: 0xf14a, + 0x629: 0xf1a9, + 0x62a: 0xf14c, + 0x62b: 0xf14e, + 0x62c: 0xf151, + 0x62d: 0xf154, + 0x62e: 0xf157, + 0x62f: 0xf158, + 0x630: 0xf159, + 0x631: 0xf15a, + 0x632: 0xf160, + 0x633: 0xf162, + 0x634: 0xf164, + 0x635: 0xf166, + 0x636: 0xf168, + 0x637: 0xf169, + 0x638: 0xf16a, + 0x639: 0xf16e, + 0x63a: 0xf172, + 0x63b: 0xf100, + 0x63c: 0xf100, + 0x63d: 0xf100, + 0x63e: 0xf100, + 0x63f: 0xf100, + 0x640: 0xf15f, + 0x641: 0xf175, + 0x642: 0xf178, + 0x643: 0xf17a, + 0x644: 0xf17c, + 0x645: 0xf17e, + 0x646: 0xf1e1, + 0x647: 0xf1a4, + 0x648: 0xf1a5, + 0x649: 0xf1ac, + 0x64a: 0xf1a8, + 0x64b: 0xf1c7, + 0x64c: 0xf1c8, + 0x64d: 0xf1cb, + 0x64e: 0xf1c4, + 0x64f: 0xf1c5, + 0x650: 0xf1ca, + 0x651: 0xf1c9, + 0x652: 0xf1c6, + 0x653: 0xf100, + 0x654: 0xf100, + 0x655: 0xf100, + 0x656: 0xf100, + 0x657: 0xf100, + 0x658: 0xf100, + 0x659: 0xf100, + 0x65a: 0xf100, + 0x65b: 0xf100, + 0x65c: 0xf100, + 0x65d: 0xf100, + 0x65e: 0xf100, + 0x660: 0xf130, + 0x661: 0xf131, + 0x662: 0xf132, + 0x663: 0xf133, + 0x664: 0xf134, + 0x665: 0xf135, + 0x666: 0xf136, + 0x667: 0xf137, + 0x668: 0xf138, + 0x669: 0xf139, + 0x66b: 0xf15e, + 0x66c: 0xf15e, + 0x200c: 0xf10c, + 0x200d: 0xf10d, + 0x200e: 0xf10e, + 0x200f: 0xf10f, + 0x2018: 0xf13c, + 0x2019: 0xf13e, + 0xfe81: 0xf145, + 0xfe82: 0xf146, + 0xfe83: 0xf143, + 0xfe84: 0xf144, + 0xfe85: 0xf1bb, + 0xfe86: 0xf1bb, + 0xfe87: 0xf147, + 0xfe88: 0xf148, + 0xfe89: 0xf1ba, + 0xfe8a: 0xf1af, + 0xfe8b: 0xf1ae, + 0xfe8c: 0xf1ae, + 0xfe8d: 0xf141, + 0xfe8e: 0xf142, + 0xfe8f: 0xf14a, + 0xfe90: 0xf14a, + 0xfe91: 0xf149, + 0xfe92: 0xf149, + 0xfe93: 0xf1a9, + 0xfe94: 0xf1aa, + 0xfe95: 0xf14c, + 0xfe96: 0xf14c, + 0xfe97: 0xf14b, + 0xfe98: 0xf14b, + 0xfe99: 0xf14e, + 0xfe9a: 0xf14e, + 0xfe9b: 0xf14d, + 0xfe9c: 0xf14d, + 0xfe9d: 0xf151, + 0xfe9e: 0xf150, + 0xfe9f: 0xf14f, + 0xfea0: 0xf14f, + 0xfea1: 0xf154, + 0xfea2: 0xf153, + 0xfea3: 0xf152, + 0xfea4: 0xf152, + 0xfea5: 0xf157, + 0xfea6: 0xf156, + 0xfea7: 0xf155, + 0xfea8: 0xf155, + 0xfea9: 0xf158, + 0xfeaa: 0xf158, + 0xfeab: 0xf159, + 0xfeac: 0xf159, + 0xfead: 0xf15a, + 0xfeae: 0xf15a, + 0xfeaf: 0xf160, + 0xfeb0: 0xf160, + 0xfeb1: 0xf162, + 0xfeb2: 0xf162, + 0xfeb3: 0xf161, + 0xfeb4: 0xf161, + 0xfeb5: 0xf164, + 0xfeb6: 0xf164, + 0xfeb7: 0xf163, + 0xfeb8: 0xf163, + 0xfeb9: 0xf166, + 0xfeba: 0xf166, + 0xfebb: 0xf165, + 0xfebc: 0xf165, + 0xfebd: 0xf168, + 0xfebe: 0xf168, + 0xfebf: 0xf167, + 0xfec0: 0xf167, + 0xfec1: 0xf169, + 0xfec2: 0xf169, + 0xfec3: 0xf169, + 0xfec4: 0xf169, + 0xfec5: 0xf16a, + 0xfec6: 0xf16a, + 0xfec7: 0xf16a, + 0xfec8: 0xf16a, + 0xfec9: 0xf16e, + 0xfeca: 0xf16d, + 0xfecb: 0xf16b, + 0xfecc: 0xf16c, + 0xfecd: 0xf172, + 0xfece: 0xf171, + 0xfecf: 0xf16f, + 0xfed0: 0xf170, + 0xfed1: 0xf175, + 0xfed2: 0xf175, + 0xfed3: 0xf173, + 0xfed4: 0xf174, + 0xfed5: 0xf178, + 0xfed6: 0xf178, + 0xfed7: 0xf176, + 0xfed8: 0xf177, + 0xfed9: 0xf17a, + 0xfeda: 0xf17a, + 0xfedb: 0xf179, + 0xfedc: 0xf179, + 0xfedd: 0xf17c, + 0xfede: 0xf17c, + 0xfedf: 0xf17b, + 0xfee0: 0xf17b, + 0xfee1: 0xf17e, + 0xfee2: 0xf17e, + 0xfee3: 0xf17d, + 0xfee4: 0xf17d, + 0xfee5: 0xf1e1, + 0xfee6: 0xf1e1, + 0xfee7: 0xf17f, + 0xfee8: 0xf17f, + 0xfee9: 0xf1a4, + 0xfeea: 0xf1a3, + 0xfeeb: 0xf1a1, + 0xfeec: 0xf1a2, + 0xfeed: 0xf1a5, + 0xfeee: 0xf1a5, + 0xfeef: 0xf1ac, + 0xfef0: 0xf1ab, + 0xfef1: 0xf1a8, + 0xfef2: 0xf1a7, + 0xfef3: 0xf1a6, + 0xfef4: 0xf1a6, + 0xfef5: 0xf1c0, + 0xfef6: 0xf1c1, + 0xfef7: 0xf1be, + 0xfef8: 0xf1bf, + 0xfef9: 0xf1c2, + 0xfefa: 0xf1c3, + 0xfefb: 0xf1bd, + 0xfefc: 0xf1bc, +} + +arabic_traditional_cmap_mapping : dict[int, int] = { + 0x20: 0xf220, + 0x21: 0xf221, + 0x22: 0xf222, + 0x25: 0xf225, + 0x28: 0xf228, + 0x29: 0xf229, + 0x2a: 0xf22a, + 0x2b: 0xf22b, + 0x2c: 0xf25e, + 0x2d: 0xf22d, + 0x2e: 0xf22e, + 0x2f: 0xf22f, + 0x3a: 0xf23a, + 0x3b: 0xf23b, + 0x3d: 0xf23d, + 0x3f: 0xf23f, + 0x5b: 0xf25b, + 0x5d: 0xf25d, + 0xab: 0xf223, + 0xbb: 0xf224, + 0xd7: 0xf226, + 0xf7: 0xf227, + 0x60c: 0xf22c, + 0x61b: 0xf23b, + 0x61f: 0xf23f, + 0x621: 0xf2d5, + 0x622: 0xf245, + 0x623: 0xf243, + 0x624: 0xf2da, + 0x625: 0xf247, + 0x626: 0xf2d9, + 0x627: 0xf241, + 0x628: 0xf24c, + 0x629: 0xf2d1, + 0x62a: 0xf250, + 0x62b: 0xf254, + 0x62c: 0xf258, + 0x62d: 0xf260, + 0x62e: 0xf264, + 0x62f: 0xf265, + 0x630: 0xf267, + 0x631: 0xf269, + 0x632: 0xf26b, + 0x633: 0xf270, + 0x634: 0xf274, + 0x635: 0xf278, + 0x636: 0xf27e, + 0x637: 0xf2a2, + 0x638: 0xf2a3, + 0x639: 0xf2aa, + 0x63a: 0xf2ae, + 0x63b: 0xf200, + 0x63c: 0xf200, + 0x63d: 0xf200, + 0x63e: 0xf200, + 0x63f: 0xf200, + 0x640: 0xf25f, + 0x641: 0xf2b2, + 0x642: 0xf2b6, + 0x643: 0xf2ba, + 0x644: 0xf2be, + 0x645: 0xf2c2, + 0x646: 0xf2c6, + 0x647: 0xf2ca, + 0x648: 0xf2cb, + 0x649: 0xf2d4, + 0x64a: 0xf2d0, + 0x64b: 0xf2e7, + 0x64c: 0xf2e8, + 0x64d: 0xf2eb, + 0x64e: 0xf2e4, + 0x64f: 0xf2e5, + 0x650: 0xf2ea, + 0x651: 0xf2e9, + 0x652: 0xf2e6, + 0x653: 0xf200, + 0x654: 0xf200, + 0x655: 0xf200, + 0x656: 0xf200, + 0x657: 0xf200, + 0x658: 0xf200, + 0x659: 0xf200, + 0x65a: 0xf200, + 0x65b: 0xf200, + 0x65c: 0xf200, + 0x65d: 0xf200, + 0x65e: 0xf200, + 0x660: 0xf230, + 0x661: 0xf231, + 0x662: 0xf232, + 0x663: 0xf233, + 0x664: 0xf234, + 0x665: 0xf235, + 0x666: 0xf236, + 0x667: 0xf237, + 0x668: 0xf238, + 0x669: 0xf239, + 0x66b: 0xf25e, + 0x66c: 0xf25e, + 0x200c: 0xf20c, + 0x200d: 0xf20d, + 0x200e: 0xf20e, + 0x200f: 0xf20f, + 0x201c: 0xf23c, + 0x201d: 0xf23e, + 0xfc08: 0xf202, + 0xfc0a: 0xf21d, + 0xfc0e: 0xf203, + 0xfc10: 0xf21e, + 0xfc12: 0xf204, + 0xfc32: 0xf29f, + 0xfc3f: 0xf212, + 0xfc40: 0xf213, + 0xfc41: 0xf214, + 0xfc42: 0xf205, + 0xfc43: 0xf295, + 0xfc44: 0xf21c, + 0xfc4e: 0xf206, + 0xfc50: 0xf21f, + 0xfc5e: 0xf2ef, + 0xfc60: 0xf2ec, + 0xfc61: 0xf2ed, + 0xfc62: 0xf2f0, + 0xfc6a: 0xf215, + 0xfc6d: 0xf292, + 0xfc70: 0xf216, + 0xfc73: 0xf293, + 0xfc91: 0xf217, + 0xfc94: 0xf294, + 0xfc9c: 0xf280, + 0xfc9d: 0xf281, + 0xfc9e: 0xf282, + 0xfc9f: 0xf296, + 0xfca1: 0xf283, + 0xfca2: 0xf284, + 0xfca3: 0xf285, + 0xfca4: 0xf297, + 0xfca8: 0xf29a, + 0xfcaa: 0xf29b, + 0xfcac: 0xf29c, + 0xfcb0: 0xf218, + 0xfcc9: 0xf286, + 0xfcca: 0xf287, + 0xfccb: 0xf288, + 0xfccc: 0xf29d, + 0xfccd: 0xf21a, + 0xfcce: 0xf289, + 0xfccf: 0xf28a, + 0xfcd0: 0xf28b, + 0xfcd1: 0xf29e, + 0xfcd2: 0xf28d, + 0xfcd3: 0xf28e, + 0xfcd5: 0xf298, + 0xfcda: 0xf28f, + 0xfcdb: 0xf290, + 0xfcdc: 0xf291, + 0xfcdd: 0xf299, + 0xfd30: 0xf219, + 0xfd3e: 0xf27b, + 0xfd3f: 0xf27d, + 0xfd88: 0xf210, + 0xfe81: 0xf245, + 0xfe82: 0xf246, + 0xfe83: 0xf243, + 0xfe84: 0xf244, + 0xfe85: 0xf2da, + 0xfe86: 0xf2db, + 0xfe87: 0xf247, + 0xfe88: 0xf248, + 0xfe89: 0xf2d9, + 0xfe8a: 0xf2d8, + 0xfe8b: 0xf2d6, + 0xfe8c: 0xf2d7, + 0xfe8d: 0xf241, + 0xfe8e: 0xf242, + 0xfe8f: 0xf24c, + 0xfe90: 0xf24b, + 0xfe91: 0xf249, + 0xfe92: 0xf24a, + 0xfe93: 0xf2d1, + 0xfe94: 0xf2d2, + 0xfe95: 0xf250, + 0xfe96: 0xf24f, + 0xfe97: 0xf24d, + 0xfe98: 0xf24e, + 0xfe99: 0xf254, + 0xfe9a: 0xf253, + 0xfe9b: 0xf251, + 0xfe9c: 0xf252, + 0xfe9d: 0xf258, + 0xfe9e: 0xf257, + 0xfe9f: 0xf255, + 0xfea0: 0xf256, + 0xfea1: 0xf260, + 0xfea2: 0xf25c, + 0xfea3: 0xf259, + 0xfea4: 0xf25a, + 0xfea5: 0xf264, + 0xfea6: 0xf263, + 0xfea7: 0xf261, + 0xfea8: 0xf262, + 0xfea9: 0xf265, + 0xfeaa: 0xf266, + 0xfeab: 0xf267, + 0xfeac: 0xf268, + 0xfead: 0xf269, + 0xfeae: 0xf26a, + 0xfeaf: 0xf26b, + 0xfeb0: 0xf26c, + 0xfeb1: 0xf270, + 0xfeb2: 0xf26f, + 0xfeb3: 0xf26d, + 0xfeb4: 0xf26e, + 0xfeb5: 0xf274, + 0xfeb6: 0xf273, + 0xfeb7: 0xf271, + 0xfeb8: 0xf272, + 0xfeb9: 0xf278, + 0xfeba: 0xf277, + 0xfebb: 0xf275, + 0xfebc: 0xf276, + 0xfebd: 0xf27e, + 0xfebe: 0xf27c, + 0xfebf: 0xf279, + 0xfec0: 0xf27a, + 0xfec1: 0xf2a2, + 0xfec2: 0xf2a1, + 0xfec3: 0xf27f, + 0xfec4: 0xf2f1, + 0xfec5: 0xf2a6, + 0xfec6: 0xf2a5, + 0xfec7: 0xf2a3, + 0xfec8: 0xf2a4, + 0xfec9: 0xf2aa, + 0xfeca: 0xf2a9, + 0xfecb: 0xf2a7, + 0xfecc: 0xf2a8, + 0xfecd: 0xf2ae, + 0xfece: 0xf2ad, + 0xfecf: 0xf2ab, + 0xfed0: 0xf2ac, + 0xfed1: 0xf2b2, + 0xfed2: 0xf2b1, + 0xfed3: 0xf2af, + 0xfed4: 0xf2b0, + 0xfed5: 0xf2b6, + 0xfed6: 0xf2b5, + 0xfed7: 0xf2b3, + 0xfed8: 0xf2b4, + 0xfed9: 0xf2ba, + 0xfeda: 0xf2b9, + 0xfedb: 0xf2b7, + 0xfedc: 0xf2b8, + 0xfedd: 0xf2be, + 0xfede: 0xf2bd, + 0xfedf: 0xf2bb, + 0xfee0: 0xf2bc, + 0xfee1: 0xf2c2, + 0xfee2: 0xf2c1, + 0xfee3: 0xf2bf, + 0xfee4: 0xf2c0, + 0xfee5: 0xf2c6, + 0xfee6: 0xf2c5, + 0xfee7: 0xf2c3, + 0xfee8: 0xf2c4, + 0xfee9: 0xf2ca, + 0xfeea: 0xf2c9, + 0xfeeb: 0xf2c7, + 0xfeec: 0xf2c8, + 0xfeed: 0xf2cb, + 0xfeee: 0xf2cc, + 0xfeef: 0xf2d4, + 0xfef0: 0xf2d3, + 0xfef1: 0xf2d0, + 0xfef2: 0xf2cf, + 0xfef3: 0xf2cd, + 0xfef4: 0xf2ce, + 0xfef5: 0xf2e0, + 0xfef6: 0xf2e1, + 0xfef7: 0xf2de, + 0xfef8: 0xf2df, + 0xfef9: 0xf2e2, + 0xfefa: 0xf2e3, + 0xfefb: 0xf2dc, + 0xfefc: 0xf2dd, +} diff --git a/font_collector/font/name.py b/font_collector/font/name.py index 49b1b0a..952c168 100644 --- a/font_collector/font/name.py +++ b/font_collector/font/name.py @@ -19,7 +19,7 @@ MAC_LANGUAGES_TO_LCID_CODE: dict[str, int] = _MAC_LANGUAGE_CODES -__all__ = ["Name", "NameID", "PlatformID"] +__all__ = ["MacintoshEncodingID", "MicrosoftEncodingID", "Name", "NameID", "PlatformID"] class PlatformID(IntEnum): # From https://learn.microsoft.com/en-us/typography/opentype/spec/name#platform-ids @@ -28,6 +28,23 @@ class PlatformID(IntEnum): MICROSOFT = 3 +class MacintoshEncodingID(IntEnum): + # From https://learn.microsoft.com/en-us/typography/opentype/spec/name#macintosh-encoding-ids-script-manager-codes + ROMAN = 0 + + +class MicrosoftEncodingID(IntEnum): + # From https://learn.microsoft.com/en-us/typography/opentype/spec/name#windows-encoding-ids + SYMBOL = 0 + UNICODE_BMP = 1 + SHIFT_JIS = 2 + PRC = 3 + BIG5 = 4 + WANSUNG = 5 + JOHAB = 6 + UNICODE_FULL = 10 + + class NameID(IntEnum): # From: https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids COPYRIGHT = 0 @@ -100,21 +117,21 @@ def get_name_record_encoding(name: NameRecord) -> str | None: """ # From: https://github.com/MicrosoftDocs/typography-issues/issues/956#issuecomment-1205678068 if name.platformID == PlatformID.MICROSOFT: - if name.platEncID == 3: + if name.platEncID == MicrosoftEncodingID.PRC: return "cp936" - elif name.platEncID == 4: + elif name.platEncID == MicrosoftEncodingID.BIG5: if name.nameID == NameID.SUBFAMILY_NAME: return "utf_16_be" else: return "cp950" - elif name.platEncID == 5: + elif name.platEncID == MicrosoftEncodingID.WANSUNG: if name.nameID == NameID.SUBFAMILY_NAME: return "utf_16_be" else: return "cp949" else: return "utf_16_be" - elif name.platformID == PlatformID.MACINTOSH and name.platEncID == 0: + elif name.platformID == PlatformID.MACINTOSH and name.platEncID == MacintoshEncodingID.ROMAN: # From: https://github.com/libass/libass/issues/679#issuecomment-1442262479 return "iso-8859-1" diff --git a/legacy_cmap/ArabicPUASimplified.txt b/legacy_cmap/ArabicPUASimplified.txt new file mode 100644 index 0000000..a74ef26 --- /dev/null +++ b/legacy_cmap/ArabicPUASimplified.txt @@ -0,0 +1,250 @@ +# +# Name: Legacy Simplified Arabic encoding +# +# Format: Three tab-separated columns +# Column #1 is the PUA code (in hex as 0xXXXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in PUA order +# +0xF100 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE +0xF100 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW +0xF100 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V +0xF100 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE +0xF100 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0xF100 0x0653 # ARABIC MADDAH ABOVE +0xF100 0x0654 # ARABIC HAMZA ABOVE +0xF100 0x0655 # ARABIC HAMZA BELOW +0xF100 0x0656 # ARABIC SUBSCRIPT ALEF +0xF100 0x0657 # ARABIC INVERTED DAMMA +0xF100 0x0658 # ARABIC MARK NOON GHUNNA +0xF100 0x0659 # ARABIC ZWARAKAY +0xF100 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE +0xF100 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE +0xF100 0x065C # ARABIC VOWEL SIGN DOT BELOW +0xF100 0x065D # ARABIC REVERSED DAMMA +0xF100 0x065E # ARABIC FATHA WITH TWO DOTS +0xF10C 0x200C # ZERO WIDTH NON-JOINER +0xF10D 0x200D # ZERO WIDTH JOINER +0xF10E 0x200E # LEFT-TO-RIGHT MARK +0xF10F 0x200F # RIGHT-TO-LEFT MARK +0xF120 0x0020 # SPACE +0xF121 0x0021 # EXCLAMATION MARK +0xF122 0x0022 # QUOTATION MARK +0xF123 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xF124 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xF125 0x0025 # PERCENT SIGN +0xF126 0x00D7 # MULTIPLICATION SIGN +0xF127 0x00F7 # DIVISION SIGN +0xF128 0x0028 # LEFT PARENTHESIS +0xF129 0x0029 # RIGHT PARENTHESIS +0xF12A 0x002A # ASTERISK +0xF12B 0x002B # PLUS SIGN +0xF12C 0x060C # ARABIC COMMA +0xF12D 0x002D # HYPHEN-MINUS +0xF12E 0x002E # FULL STOP +0xF12F 0x002F # SOLIDUS +0xF130 0x0660 # ARABIC-INDIC DIGIT ZERO +0xF131 0x0661 # ARABIC-INDIC DIGIT ONE +0xF132 0x0662 # ARABIC-INDIC DIGIT TWO +0xF133 0x0663 # ARABIC-INDIC DIGIT THREE +0xF134 0x0664 # ARABIC-INDIC DIGIT FOUR +0xF135 0x0665 # ARABIC-INDIC DIGIT FIVE +0xF136 0x0666 # ARABIC-INDIC DIGIT SIX +0xF137 0x0667 # ARABIC-INDIC DIGIT SEVEN +0xF138 0x0668 # ARABIC-INDIC DIGIT EIGHT +0xF139 0x0669 # ARABIC-INDIC DIGIT NINE +0xF13A 0x003A # COLON +0xF13B 0x003B # SEMICOLON +0xF13B 0x061B # ARABIC SEMICOLON +0xF13C 0x2018 # LEFT SINGLE QUOTATION MARK +0xF13D 0x003D # EQUALS SIGN +0xF13E 0x2019 # RIGHT SINGLE QUOTATION MARK +0xF13F 0x003F # QUESTION MARK +0xF13F 0x061F # ARABIC QUESTION MARK +0xF141 0x0627 # ARABIC LETTER ALEF +0xF141 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM +0xF142 0xFE8E # ARABIC LETTER ALEF FINAL FORM +0xF143 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE +0xF143 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM +0xF144 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +0xF145 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE +0xF145 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM +0xF146 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +0xF147 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW +0xF147 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM +0xF148 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +0xF149 0xFE91 # ARABIC LETTER BEH INITIAL FORM +0xF149 0xFE92 # ARABIC LETTER BEH MEDIAL FORM +0xF14A 0x0628 # ARABIC LETTER BEH +0xF14A 0xFE8F # ARABIC LETTER BEH ISOLATED FORM +0xF14A 0xFE90 # ARABIC LETTER BEH FINAL FORM +0xF14B 0xFE97 # ARABIC LETTER TEH INITIAL FORM +0xF14B 0xFE98 # ARABIC LETTER TEH MEDIAL FORM +0xF14C 0x062A # ARABIC LETTER TEH +0xF14C 0xFE95 # ARABIC LETTER TEH ISOLATED FORM +0xF14C 0xFE96 # ARABIC LETTER TEH FINAL FORM +0xF14D 0xFE9B # ARABIC LETTER THEH INITIAL FORM +0xF14D 0xFE9C # ARABIC LETTER THEH MEDIAL FORM +0xF14E 0x062B # ARABIC LETTER THEH +0xF14E 0xFE99 # ARABIC LETTER THEH ISOLATED FORM +0xF14E 0xFE9A # ARABIC LETTER THEH FINAL FORM +0xF14F 0xFE9F # ARABIC LETTER JEEM INITIAL FORM +0xF14F 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM +0xF150 0xFE9E # ARABIC LETTER JEEM FINAL FORM +0xF151 0x062C # ARABIC LETTER JEEM +0xF151 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM +0xF152 0xFEA3 # ARABIC LETTER HAH INITIAL FORM +0xF152 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM +0xF153 0xFEA2 # ARABIC LETTER HAH FINAL FORM +0xF154 0x062D # ARABIC LETTER HAH +0xF154 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM +0xF155 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM +0xF155 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM +0xF156 0xFEA6 # ARABIC LETTER KHAH FINAL FORM +0xF157 0x062E # ARABIC LETTER KHAH +0xF157 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM +0xF158 0x062F # ARABIC LETTER DAL +0xF158 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM +0xF158 0xFEAA # ARABIC LETTER DAL FINAL FORM +0xF159 0x0630 # ARABIC LETTER THAL +0xF159 0xFEAB # ARABIC LETTER THAL ISOLATED FORM +0xF159 0xFEAC # ARABIC LETTER THAL FINAL FORM +0xF15A 0x0631 # ARABIC LETTER REH +0xF15A 0xFEAD # ARABIC LETTER REH ISOLATED FORM +0xF15A 0xFEAE # ARABIC LETTER REH FINAL FORM +0xF15B 0x005B # LEFT SQUARE BRACKET +0xF15C 0x005C # REVERSE SOLIDUS +0xF15D 0x005D # RIGHT SQUARE BRACKET +0xF15E 0x002C # COMMA +0xF15E 0x066B # ARABIC DECIMAL SEPARATOR +0xF15E 0x066C # ARABIC THOUSANDS SEPARATOR +0xF15F 0x0640 # ARABIC TATWEEL +0xF160 0x0632 # ARABIC LETTER ZAIN +0xF160 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM +0xF160 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM +0xF161 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM +0xF161 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM +0xF162 0x0633 # ARABIC LETTER SEEN +0xF162 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM +0xF162 0xFEB2 # ARABIC LETTER SEEN FINAL FORM +0xF163 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM +0xF163 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM +0xF164 0x0634 # ARABIC LETTER SHEEN +0xF164 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM +0xF164 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM +0xF165 0xFEBB # ARABIC LETTER SAD INITIAL FORM +0xF165 0xFEBC # ARABIC LETTER SAD MEDIAL FORM +0xF166 0x0635 # ARABIC LETTER SAD +0xF166 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM +0xF166 0xFEBA # ARABIC LETTER SAD FINAL FORM +0xF167 0xFEBF # ARABIC LETTER DAD INITIAL FORM +0xF167 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM +0xF168 0x0636 # ARABIC LETTER DAD +0xF168 0xFEBD # ARABIC LETTER DAD ISOLATED FORM +0xF168 0xFEBE # ARABIC LETTER DAD FINAL FORM +0xF169 0x0637 # ARABIC LETTER TAH +0xF169 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM +0xF169 0xFEC2 # ARABIC LETTER TAH FINAL FORM +0xF169 0xFEC3 # ARABIC LETTER TAH INITIAL FORM +0xF169 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM +0xF16A 0x0638 # ARABIC LETTER ZAH +0xF16A 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM +0xF16A 0xFEC6 # ARABIC LETTER ZAH FINAL FORM +0xF16A 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM +0xF16A 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM +0xF16B 0xFECB # ARABIC LETTER AIN INITIAL FORM +0xF16C 0xFECC # ARABIC LETTER AIN MEDIAL FORM +0xF16D 0xFECA # ARABIC LETTER AIN FINAL FORM +0xF16E 0x0639 # ARABIC LETTER AIN +0xF16E 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM +0xF16F 0xFECF # ARABIC LETTER GHAIN INITIAL FORM +0xF170 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM +0xF171 0xFECE # ARABIC LETTER GHAIN FINAL FORM +0xF172 0x063A # ARABIC LETTER GHAIN +0xF172 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM +0xF173 0xFED3 # ARABIC LETTER FEH INITIAL FORM +0xF174 0xFED4 # ARABIC LETTER FEH MEDIAL FORM +0xF175 0x0641 # ARABIC LETTER FEH +0xF175 0xFED1 # ARABIC LETTER FEH ISOLATED FORM +0xF175 0xFED2 # ARABIC LETTER FEH FINAL FORM +0xF176 0xFED7 # ARABIC LETTER QAF INITIAL FORM +0xF177 0xFED8 # ARABIC LETTER QAF MEDIAL FORM +0xF178 0x0642 # ARABIC LETTER QAF +0xF178 0xFED5 # ARABIC LETTER QAF ISOLATED FORM +0xF178 0xFED6 # ARABIC LETTER QAF FINAL FORM +0xF179 0xFEDB # ARABIC LETTER KAF INITIAL FORM +0xF179 0xFEDC # ARABIC LETTER KAF MEDIAL FORM +0xF17A 0x0643 # ARABIC LETTER KAF +0xF17A 0xFED9 # ARABIC LETTER KAF ISOLATED FORM +0xF17A 0xFEDA # ARABIC LETTER KAF FINAL FORM +0xF17B 0xFEDF # ARABIC LETTER LAM INITIAL FORM +0xF17B 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM +0xF17C 0x0644 # ARABIC LETTER LAM +0xF17C 0xFEDD # ARABIC LETTER LAM ISOLATED FORM +0xF17C 0xFEDE # ARABIC LETTER LAM FINAL FORM +0xF17D 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM +0xF17D 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM +0xF17E 0x0645 # ARABIC LETTER MEEM +0xF17E 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM +0xF17E 0xFEE2 # ARABIC LETTER MEEM FINAL FORM +0xF17F 0xFEE7 # ARABIC LETTER NOON INITIAL FORM +0xF17F 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM +0xF1A1 0xFEEB # ARABIC LETTER HEH INITIAL FORM +0xF1A2 0xFEEC # ARABIC LETTER HEH MEDIAL FORM +0xF1A3 0xFEEA # ARABIC LETTER HEH FINAL FORM +0xF1A4 0x0647 # ARABIC LETTER HEH +0xF1A4 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM +0xF1A5 0x0648 # ARABIC LETTER WAW +0xF1A5 0xFEED # ARABIC LETTER WAW ISOLATED FORM +0xF1A5 0xFEEE # ARABIC LETTER WAW FINAL FORM +0xF1A6 0xFEF3 # ARABIC LETTER YEH INITIAL FORM +0xF1A6 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM +0xF1A7 0xFEF2 # ARABIC LETTER YEH FINAL FORM +0xF1A8 0x064A # ARABIC LETTER YEH +0xF1A8 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM +0xF1A9 0x0629 # ARABIC LETTER TEH MARBUTA +0xF1A9 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM +0xF1AA 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM +0xF1AB 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM +0xF1AC 0x0649 # ARABIC LETTER ALEF MAKSURA +0xF1AC 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM +0xF1AD 0x0621 # ARABIC LETTER HAMZA +0xF1AE 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM +0xF1AE 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +0xF1AF 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM +0xF1B0 0x0030 # DIGIT ZERO +0xF1B1 0x0031 # DIGIT ONE +0xF1B2 0x0032 # DIGIT TWO +0xF1B3 0x0033 # DIGIT THREE +0xF1B4 0x0034 # DIGIT FOUR +0xF1B5 0x0035 # DIGIT FIVE +0xF1B6 0x0036 # DIGIT SIX +0xF1B7 0x0037 # DIGIT SEVEN +0xF1B8 0x0038 # DIGIT EIGHT +0xF1B9 0x0039 # DIGIT NINE +0xF1BA 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE +0xF1BA 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM +0xF1BB 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE +0xF1BB 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM +0xF1BB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +0xF1BC 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM +0xF1BD 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM +0xF1BE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM +0xF1BF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +0xF1C0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM +0xF1C1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +0xF1C2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM +0xF1C3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +0xF1C4 0x064E # ARABIC FATHA +0xF1C5 0x064F # ARABIC DAMMA +0xF1C6 0x0652 # ARABIC SUKUN +0xF1C7 0x064B # ARABIC FATHATAN +0xF1C8 0x064C # ARABIC DAMMATAN +0xF1C9 0x0651 # ARABIC SHADDA +0xF1CA 0x0650 # ARABIC KASRA +0xF1CB 0x064D # ARABIC KASRATAN +0xF1E1 0x0646 # ARABIC LETTER NOON +0xF1E1 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM +0xF1E1 0xFEE6 # ARABIC LETTER NOON FINAL FORM diff --git a/legacy_cmap/ArabicPUATraditional.txt b/legacy_cmap/ArabicPUATraditional.txt new file mode 100644 index 0000000..5683b87 --- /dev/null +++ b/legacy_cmap/ArabicPUATraditional.txt @@ -0,0 +1,295 @@ +# +# Name: Legacy Traditional Arabic encoding +# +# Format: Three tab-separated columns +# Column #1 is the PUA code (in hex as 0xXXXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in PUA order +# +0xF200 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE +0xF200 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW +0xF200 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V +0xF200 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE +0xF200 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0xF200 0x0653 # ARABIC MADDAH ABOVE +0xF200 0x0654 # ARABIC HAMZA ABOVE +0xF200 0x0655 # ARABIC HAMZA BELOW +0xF200 0x0656 # ARABIC SUBSCRIPT ALEF +0xF200 0x0657 # ARABIC INVERTED DAMMA +0xF200 0x0658 # ARABIC MARK NOON GHUNNA +0xF200 0x0659 # ARABIC ZWARAKAY +0xF200 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE +0xF200 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE +0xF200 0x065C # ARABIC VOWEL SIGN DOT BELOW +0xF200 0x065D # ARABIC REVERSED DAMMA +0xF200 0x065E # ARABIC FATHA WITH TWO DOTS +0xF202 0xFC08 # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM +0xF203 0xFC0E # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM +0xF204 0xFC12 # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM +0xF205 0xFC42 # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM +0xF206 0xFC4E # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM +0xF20C 0x200C # ZERO WIDTH NON-JOINER +0xF20D 0x200D # ZERO WIDTH JOINER +0xF20E 0x200E # LEFT-TO-RIGHT MARK +0xF20F 0x200F # RIGHT-TO-LEFT MARK +0xF210 0xFD88 # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM +0xF212 0xFC3F # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM +0xF213 0xFC40 # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM +0xF214 0xFC41 # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM +0xF215 0xFC6A # ARABIC LIGATURE BEH WITH REH FINAL FORM +0xF216 0xFC70 # ARABIC LIGATURE TEH WITH REH FINAL FORM +0xF217 0xFC91 # ARABIC LIGATURE YEH WITH REH FINAL FORM +0xF218 0xFCB0 # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM +0xF219 0xFD30 # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM +0xF21A 0xFCCD # ARABIC LIGATURE LAM WITH HEH INITIAL FORM +0xF21C 0xFC44 # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM +0xF21D 0xFC0A # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM +0xF21E 0xFC10 # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM +0xF21F 0xFC50 # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM +0xF220 0x0020 # SPACE +0xF221 0x0021 # EXCLAMATION MARK +0xF222 0x0022 # QUOTATION MARK +0xF223 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xF224 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xF225 0x0025 # PERCENT SIGN +0xF226 0x00D7 # MULTIPLICATION SIGN +0xF227 0x00F7 # DIVISION SIGN +0xF228 0x0028 # LEFT PARENTHESIS +0xF229 0x0029 # RIGHT PARENTHESIS +0xF22A 0x002A # ASTERISK +0xF22B 0x002B # PLUS SIGN +0xF22C 0x060C # ARABIC COMMA +0xF22D 0x002D # HYPHEN-MINUS +0xF22E 0x002E # FULL STOP +0xF22F 0x002F # SOLIDUS +0xF230 0x0660 # ARABIC-INDIC DIGIT ZERO +0xF231 0x0661 # ARABIC-INDIC DIGIT ONE +0xF232 0x0662 # ARABIC-INDIC DIGIT TWO +0xF233 0x0663 # ARABIC-INDIC DIGIT THREE +0xF234 0x0664 # ARABIC-INDIC DIGIT FOUR +0xF235 0x0665 # ARABIC-INDIC DIGIT FIVE +0xF236 0x0666 # ARABIC-INDIC DIGIT SIX +0xF237 0x0667 # ARABIC-INDIC DIGIT SEVEN +0xF238 0x0668 # ARABIC-INDIC DIGIT EIGHT +0xF239 0x0669 # ARABIC-INDIC DIGIT NINE +0xF23A 0x003A # COLON +0xF23B 0x003B # SEMICOLON +0xF23B 0x061B # ARABIC SEMICOLON +0xF23C 0x201C # LEFT DOUBLE QUOTATION MARK +0xF23D 0x003D # EQUALS SIGN +0xF23E 0x201D # RIGHT DOUBLE QUOTATION MARK +0xF23F 0x003F # QUESTION MARK +0xF23F 0x061F # ARABIC QUESTION MARK +0xF241 0x0627 # ARABIC LETTER ALEF +0xF241 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM +0xF242 0xFE8E # ARABIC LETTER ALEF FINAL FORM +0xF243 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE +0xF243 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM +0xF244 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +0xF245 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE +0xF245 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM +0xF246 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +0xF247 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW +0xF247 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM +0xF248 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +0xF249 0xFE91 # ARABIC LETTER BEH INITIAL FORM +0xF24A 0xFE92 # ARABIC LETTER BEH MEDIAL FORM +0xF24B 0xFE90 # ARABIC LETTER BEH FINAL FORM +0xF24C 0x0628 # ARABIC LETTER BEH +0xF24C 0xFE8F # ARABIC LETTER BEH ISOLATED FORM +0xF24D 0xFE97 # ARABIC LETTER TEH INITIAL FORM +0xF24E 0xFE98 # ARABIC LETTER TEH MEDIAL FORM +0xF24F 0xFE96 # ARABIC LETTER TEH FINAL FORM +0xF250 0x062A # ARABIC LETTER TEH +0xF250 0xFE95 # ARABIC LETTER TEH ISOLATED FORM +0xF251 0xFE9B # ARABIC LETTER THEH INITIAL FORM +0xF252 0xFE9C # ARABIC LETTER THEH MEDIAL FORM +0xF253 0xFE9A # ARABIC LETTER THEH FINAL FORM +0xF254 0x062B # ARABIC LETTER THEH +0xF254 0xFE99 # ARABIC LETTER THEH ISOLATED FORM +0xF255 0xFE9F # ARABIC LETTER JEEM INITIAL FORM +0xF256 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM +0xF257 0xFE9E # ARABIC LETTER JEEM FINAL FORM +0xF258 0x062C # ARABIC LETTER JEEM +0xF258 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM +0xF259 0xFEA3 # ARABIC LETTER HAH INITIAL FORM +0xF25A 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM +0xF25B 0x005B # LEFT SQUARE BRACKET +0xF25C 0xFEA2 # ARABIC LETTER HAH FINAL FORM +0xF25D 0x005D # RIGHT SQUARE BRACKET +0xF25E 0x002C # COMMA +0xF25E 0x066B # ARABIC DECIMAL SEPARATOR +0xF25E 0x066C # ARABIC THOUSANDS SEPARATOR +0xF25F 0x0640 # ARABIC TATWEEL +0xF260 0x062D # ARABIC LETTER HAH +0xF260 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM +0xF261 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM +0xF262 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM +0xF263 0xFEA6 # ARABIC LETTER KHAH FINAL FORM +0xF264 0x062E # ARABIC LETTER KHAH +0xF264 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM +0xF265 0x062F # ARABIC LETTER DAL +0xF265 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM +0xF266 0xFEAA # ARABIC LETTER DAL FINAL FORM +0xF267 0x0630 # ARABIC LETTER THAL +0xF267 0xFEAB # ARABIC LETTER THAL ISOLATED FORM +0xF268 0xFEAC # ARABIC LETTER THAL FINAL FORM +0xF269 0x0631 # ARABIC LETTER REH +0xF269 0xFEAD # ARABIC LETTER REH ISOLATED FORM +0xF26A 0xFEAE # ARABIC LETTER REH FINAL FORM +0xF26B 0x0632 # ARABIC LETTER ZAIN +0xF26B 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM +0xF26C 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM +0xF26D 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM +0xF26E 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM +0xF26F 0xFEB2 # ARABIC LETTER SEEN FINAL FORM +0xF270 0x0633 # ARABIC LETTER SEEN +0xF270 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM +0xF271 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM +0xF272 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM +0xF273 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM +0xF274 0x0634 # ARABIC LETTER SHEEN +0xF274 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM +0xF275 0xFEBB # ARABIC LETTER SAD INITIAL FORM +0xF276 0xFEBC # ARABIC LETTER SAD MEDIAL FORM +0xF277 0xFEBA # ARABIC LETTER SAD FINAL FORM +0xF278 0x0635 # ARABIC LETTER SAD +0xF278 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM +0xF279 0xFEBF # ARABIC LETTER DAD INITIAL FORM +0xF27A 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM +0xF27B 0xFD3E # ORNATE LEFT PARENTHESIS +0xF27C 0xFEBE # ARABIC LETTER DAD FINAL FORM +0xF27D 0xFD3F # ORNATE RIGHT PARENTHESIS +0xF27E 0x0636 # ARABIC LETTER DAD +0xF27E 0xFEBD # ARABIC LETTER DAD ISOLATED FORM +0xF27F 0xFEC3 # ARABIC LETTER TAH INITIAL FORM +0xF280 0xFC9C # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM +0xF281 0xFC9D # ARABIC LIGATURE BEH WITH HAH INITIAL FORM +0xF282 0xFC9E # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM +0xF283 0xFCA1 # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM +0xF284 0xFCA2 # ARABIC LIGATURE TEH WITH HAH INITIAL FORM +0xF285 0xFCA3 # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM +0xF286 0xFCC9 # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM +0xF287 0xFCCA # ARABIC LIGATURE LAM WITH HAH INITIAL FORM +0xF288 0xFCCB # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM +0xF289 0xFCCE # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM +0xF28A 0xFCCF # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM +0xF28B 0xFCD0 # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM +0xF28D 0xFCD2 # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM +0xF28E 0xFCD3 # ARABIC LIGATURE NOON WITH HAH INITIAL FORM +0xF28F 0xFCDA # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM +0xF290 0xFCDB # ARABIC LIGATURE YEH WITH HAH INITIAL FORM +0xF291 0xFCDC # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM +0xF292 0xFC6D # ARABIC LIGATURE BEH WITH NOON FINAL FORM +0xF293 0xFC73 # ARABIC LIGATURE TEH WITH NOON FINAL FORM +0xF294 0xFC94 # ARABIC LIGATURE YEH WITH NOON FINAL FORM +0xF295 0xFC43 # ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM +0xF296 0xFC9F # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM +0xF297 0xFCA4 # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM +0xF298 0xFCD5 # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM +0xF299 0xFCDD # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM +0xF29A 0xFCA8 # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM +0xF29B 0xFCAA # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM +0xF29C 0xFCAC # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM +0xF29D 0xFCCC # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM +0xF29E 0xFCD1 # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM +0xF29F 0xFC32 # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM +0xF2A1 0xFEC2 # ARABIC LETTER TAH FINAL FORM +0xF2A2 0x0637 # ARABIC LETTER TAH +0xF2A2 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM +0xF2A3 0x0638 # ARABIC LETTER ZAH +0xF2A3 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM +0xF2A4 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM +0xF2A5 0xFEC6 # ARABIC LETTER ZAH FINAL FORM +0xF2A6 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM +0xF2A7 0xFECB # ARABIC LETTER AIN INITIAL FORM +0xF2A8 0xFECC # ARABIC LETTER AIN MEDIAL FORM +0xF2A9 0xFECA # ARABIC LETTER AIN FINAL FORM +0xF2AA 0x0639 # ARABIC LETTER AIN +0xF2AA 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM +0xF2AB 0xFECF # ARABIC LETTER GHAIN INITIAL FORM +0xF2AC 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM +0xF2AD 0xFECE # ARABIC LETTER GHAIN FINAL FORM +0xF2AE 0x063A # ARABIC LETTER GHAIN +0xF2AE 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM +0xF2AF 0xFED3 # ARABIC LETTER FEH INITIAL FORM +0xF2B0 0xFED4 # ARABIC LETTER FEH MEDIAL FORM +0xF2B1 0xFED2 # ARABIC LETTER FEH FINAL FORM +0xF2B2 0x0641 # ARABIC LETTER FEH +0xF2B2 0xFED1 # ARABIC LETTER FEH ISOLATED FORM +0xF2B3 0xFED7 # ARABIC LETTER QAF INITIAL FORM +0xF2B4 0xFED8 # ARABIC LETTER QAF MEDIAL FORM +0xF2B5 0xFED6 # ARABIC LETTER QAF FINAL FORM +0xF2B6 0x0642 # ARABIC LETTER QAF +0xF2B6 0xFED5 # ARABIC LETTER QAF ISOLATED FORM +0xF2B7 0xFEDB # ARABIC LETTER KAF INITIAL FORM +0xF2B8 0xFEDC # ARABIC LETTER KAF MEDIAL FORM +0xF2B9 0xFEDA # ARABIC LETTER KAF FINAL FORM +0xF2BA 0x0643 # ARABIC LETTER KAF +0xF2BA 0xFED9 # ARABIC LETTER KAF ISOLATED FORM +0xF2BB 0xFEDF # ARABIC LETTER LAM INITIAL FORM +0xF2BC 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM +0xF2BD 0xFEDE # ARABIC LETTER LAM FINAL FORM +0xF2BE 0x0644 # ARABIC LETTER LAM +0xF2BE 0xFEDD # ARABIC LETTER LAM ISOLATED FORM +0xF2BF 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM +0xF2C0 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM +0xF2C1 0xFEE2 # ARABIC LETTER MEEM FINAL FORM +0xF2C2 0x0645 # ARABIC LETTER MEEM +0xF2C2 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM +0xF2C3 0xFEE7 # ARABIC LETTER NOON INITIAL FORM +0xF2C4 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM +0xF2C5 0xFEE6 # ARABIC LETTER NOON FINAL FORM +0xF2C6 0x0646 # ARABIC LETTER NOON +0xF2C6 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM +0xF2C7 0xFEEB # ARABIC LETTER HEH INITIAL FORM +0xF2C8 0xFEEC # ARABIC LETTER HEH MEDIAL FORM +0xF2C9 0xFEEA # ARABIC LETTER HEH FINAL FORM +0xF2CA 0x0647 # ARABIC LETTER HEH +0xF2CA 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM +0xF2CB 0x0648 # ARABIC LETTER WAW +0xF2CB 0xFEED # ARABIC LETTER WAW ISOLATED FORM +0xF2CC 0xFEEE # ARABIC LETTER WAW FINAL FORM +0xF2CD 0xFEF3 # ARABIC LETTER YEH INITIAL FORM +0xF2CE 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM +0xF2CF 0xFEF2 # ARABIC LETTER YEH FINAL FORM +0xF2D0 0x064A # ARABIC LETTER YEH +0xF2D0 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM +0xF2D1 0x0629 # ARABIC LETTER TEH MARBUTA +0xF2D1 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM +0xF2D2 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM +0xF2D3 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM +0xF2D4 0x0649 # ARABIC LETTER ALEF MAKSURA +0xF2D4 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM +0xF2D5 0x0621 # ARABIC LETTER HAMZA +0xF2D6 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM +0xF2D7 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +0xF2D8 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM +0xF2D9 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE +0xF2D9 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM +0xF2DA 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE +0xF2DA 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM +0xF2DB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +0xF2DC 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM +0xF2DD 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM +0xF2DE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM +0xF2DF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +0xF2E0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM +0xF2E1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +0xF2E2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM +0xF2E3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +0xF2E4 0x064E # ARABIC FATHA +0xF2E5 0x064F # ARABIC DAMMA +0xF2E6 0x0652 # ARABIC SUKUN +0xF2E7 0x064B # ARABIC FATHATAN +0xF2E8 0x064C # ARABIC DAMMATAN +0xF2E9 0x0651 # ARABIC SHADDA +0xF2EA 0x0650 # ARABIC KASRA +0xF2EB 0x064D # ARABIC KASRATAN +0xF2EC 0xFC60 # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM +0xF2ED 0xFC61 # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM +0xF2EF 0xFC5E # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM +0xF2F0 0xFC62 # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM +0xF2F1 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM diff --git a/legacy_cmap/gen_cmap.py b/legacy_cmap/gen_cmap.py new file mode 100644 index 0000000..c5c4433 --- /dev/null +++ b/legacy_cmap/gen_cmap.py @@ -0,0 +1,52 @@ +from pathlib import Path +import textwrap + + +def render_function(file_content: list[str], dict_name: str, unicode_mapping_file: Path): + mapping: dict[int, int] = {} + with open(unicode_mapping_file, encoding="utf-8") as f: + lines = f.readlines() + for line in lines: + if line.startswith("#"): + continue + pua_code_str, unicode_str, _ = line.split("\t") + unicode = int(unicode_str, 16) + pua_code = int(pua_code_str, 16) + mapping[unicode] = pua_code + + file_content.append(f"{dict_name} : dict[int, int] = {{") + for unicode, pua_code in sorted(mapping.items()): + file_content.append(f" {hex(unicode)}: {hex(pua_code)},") + file_content.append("}") + file_content.append("") + + +def main(): + SOURCES = [ + { + "file": Path(__file__).parent.joinpath("ArabicPUASimplified.txt"), + "function": "arabic_simplified_cmap_mapping", + }, + { + "file": Path(__file__).parent.joinpath("ArabicPUATraditional.txt"), + "function": "arabic_traditional_cmap_mapping", + }, + ] + + c_file_content = [] + + c_file_content.append(textwrap.dedent("""\ + # WARNING - THIS FILE IS AUTO-GENERATED. DO NOT EDIT IT MANUALLY. + # Regenerate with: python legacy_cmap/gen_cmap.py + """)) + + for source in SOURCES: + render_function(c_file_content, source["function"], source["file"]) + + c_file_path = Path(__file__).parent.parent.joinpath("font_collector", "font", "legacy_cmap_mapping.py") + c_file_path.write_text("\n".join(c_file_content), encoding="utf-8") + + + +if __name__ == "__main__": + main() diff --git a/tests/file/fonts/legacy-arabic-simplified-SimplifiedArabic.ttf b/tests/file/fonts/legacy-arabic-simplified-SimplifiedArabic.ttf new file mode 100644 index 0000000..ac53c00 Binary files /dev/null and b/tests/file/fonts/legacy-arabic-simplified-SimplifiedArabic.ttf differ diff --git a/tests/file/fonts/legacy-arabic-traditional-AGACairoRegular.ttf b/tests/file/fonts/legacy-arabic-traditional-AGACairoRegular.ttf new file mode 100644 index 0000000..4347075 Binary files /dev/null and b/tests/file/fonts/legacy-arabic-traditional-AGACairoRegular.ttf differ diff --git a/tests/file/fonts/symbol-first-char-0x0000-Baoloc.ttf b/tests/file/fonts/symbol-first-char-0x0000-Baoloc.ttf new file mode 100644 index 0000000..a5577ba Binary files /dev/null and b/tests/file/fonts/symbol-first-char-0x0000-Baoloc.ttf differ diff --git "a/tests/file/fonts/\345\276\256\350\275\257\347\256\200\346\240\207\345\256\213 - PlatEncID 3.TTF" "b/tests/file/fonts/\345\276\256\350\275\257\347\256\200\346\240\207\345\256\213 - PlatEncID 3.TTF" new file mode 100644 index 0000000..bc64300 Binary files /dev/null and "b/tests/file/fonts/\345\276\256\350\275\257\347\256\200\346\240\207\345\256\213 - PlatEncID 3.TTF" differ diff --git "a/tests/file/fonts/\346\226\207\351\274\216\344\270\255\347\211\271\345\273\243\345\221\212\351\253\224 - PlatEncID 4.ttf" "b/tests/file/fonts/\346\226\207\351\274\216\344\270\255\347\211\271\345\273\243\345\221\212\351\253\224 - PlatEncID 4.ttf" new file mode 100644 index 0000000..99f8caf Binary files /dev/null and "b/tests/file/fonts/\346\226\207\351\274\216\344\270\255\347\211\271\345\273\243\345\221\212\351\253\224 - PlatEncID 4.ttf" differ diff --git a/tests/font/test_font_loader.py b/tests/font/test_font_loader.py index b7c86ce..4ca82d8 100644 --- a/tests/font/test_font_loader.py +++ b/tests/font/test_font_loader.py @@ -32,11 +32,16 @@ def test_load_additional_fonts(): Path(os.path.join(font_directory, "font_without axis_value.ttf")), Path(os.path.join(font_directory, "fvar_with_0_instance.ttf")), Path(os.path.join(font_directory, "invalid_cmap.ttf")), + Path(os.path.join(font_directory, "legacy-arabic-simplified-SimplifiedArabic.ttf")), + Path(os.path.join(font_directory, "legacy-arabic-traditional-AGACairoRegular.ttf")), Path(os.path.join(font_directory, "opentype_font_collection.ttc")), Path(os.path.join(font_directory, "PENBOX.otf")), Path(os.path.join(font_directory, "SFProDisplay-Bold.ttf")), Path(os.path.join(font_directory, "SFProDisplay-BoldItalic.ttf")), + Path(os.path.join(font_directory, "symbol-first-char-0x0000-Baoloc.ttf")), Path(os.path.join(font_directory, "truetype_font_collection.ttc")), + Path(os.path.join(font_directory, "微软简标宋 - PlatEncID 3.TTF")), + Path(os.path.join(font_directory, "文鼎中特廣告體 - PlatEncID 4.ttf")), ] assert sorted(result) == sorted(expected_result) diff --git a/tests/font/test_font_parser.py b/tests/font/test_font_parser.py index b31eaae..42b2c8c 100644 --- a/tests/font/test_font_parser.py +++ b/tests/font/test_font_parser.py @@ -229,52 +229,52 @@ def test_get_supported_cmaps(): assert cmaps == [CMap(3, 1)] -def test_get_cmap_encoding(): +def test_is_cmap_supported(): # It could be any format cmap_format = 0 cmap = CmapSubtable.newSubtable(cmap_format) # Non-supported platform cmap.platformID = PlatformID.UNICODE - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == None + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == False cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 0 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "unknown" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 1 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "unicode" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 2 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "cp932" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 3 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "cp936" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 4 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "cp950" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 5 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "cp949" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 6 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "cp1361" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MICROSOFT cmap.platEncID = 10 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "unicode" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True cmap.platformID = PlatformID.MACINTOSH cmap.platEncID = 0 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == "mac_roman" + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == True # Non-supported platEncID cmap.platformID = PlatformID.MACINTOSH cmap.platEncID = 1 - assert FontParser.get_cmap_encoding(cmap.platformID, cmap.platEncID) == None + assert FontParser.is_cmap_supported(cmap.platformID, cmap.platEncID) == False diff --git a/tests/font/test_name.py b/tests/font/test_name.py index 40b396c..049229a 100644 --- a/tests/font/test_name.py +++ b/tests/font/test_name.py @@ -105,9 +105,7 @@ def test_get_name_encoding(): def test_get_decoded_name(): - # The string are from the font in this pack: https://github.com/libass/libass/issues/643#issuecomment-1476459274 - - # 微软简标宋 - PlatEncID 3.TTF + # tests\fonts\微软简标宋 - PlatEncID 3.TTF name_record = NameRecord() name_record.nameID = 1 name_record.string = b"\x00\xce\x00\xa2\x00\xc8\x00\xed\x00\xbc\x00\xf2\x00\xb1\x00\xea\x00\xcb\x00\xce" @@ -116,7 +114,7 @@ def test_get_decoded_name(): name_record.langID = 0 Name.get_decoded_name_record(name_record) == "微软简标宋" - # 文鼎中特廣告體 - PlatEncID 4.ttf + # tests\fonts\文鼎中特廣告體 - PlatEncID 4.ttf name_record = NameRecord() name_record.nameID = 1 name_record.string = b"\x00\xa4\x00\xe5\x00\xb9\x00\xa9\x00\xa4\x00\xa4\x00\xaf\x00S\x00\xbc\x00s\x00\xa7\x00i\x00\xc5\x00\xe9" diff --git a/tests/font/test_normal_font_face.py b/tests/font/test_normal_font_face.py index 17d7e21..b49b8af 100644 --- a/tests/font/test_normal_font_face.py +++ b/tests/font/test_normal_font_face.py @@ -119,7 +119,7 @@ def test_link_face_to_a_font_file(): assert font_face_2.font_file == font_file -def test_font_get_missing_glyphs_cmap_encoding_0(): +def test_font_get_missing_glyphs_cmap_encoding_0_offset_0xf000(): font_cmap_encoding_0 = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "font_cmap_encoding_0.ttf")) font_file = FontFile.from_font_path(font_cmap_encoding_0) @@ -145,6 +145,19 @@ def test_font_get_missing_glyphs_cmap_encoding_0(): missing_glyphs = font_face.get_missing_glyphs(chr(0xF0FF)) assert missing_glyphs == set() + +def test_font_get_missing_glyphs_cmap_encoding_0_offset_0x0000(): + font_path = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "symbol-first-char-0x0000-Baoloc.ttf")) + font_file = FontFile.from_font_path(font_path) + + assert len(font_file.font_faces) == 1 + font_face = font_file.font_faces[0] + assert isinstance(font_face, NormalFontFace) + + missing_glyphs = font_face.get_missing_glyphs("AÉ}@\\«»°:え") + assert missing_glyphs == set("え") + + def test_font_get_missing_glyphs_cmap_encoding_1(): font_cmap_encoding_1 = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "font_cmap_encoding_1.ttf")) font_file = FontFile.from_font_path(font_cmap_encoding_1) @@ -172,6 +185,56 @@ def test_font_get_missing_glyphs_cmap_encoding_2(): assert missing_glyphs == {"é"} +def test_font_get_missing_glyphs_cmap_encoding_3(): + font_cmap_encoding_3 = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "微软简标宋 - PlatEncID 3.TTF")) + font_file = FontFile.from_font_path(font_cmap_encoding_3) + + assert len(font_file.font_faces) == 1 + font_face = font_file.font_faces[0] + assert isinstance(font_face, NormalFontFace) + + # Try "ヲ" since cp936 doesn't support this char + missing_glyphs = font_face.get_missing_glyphs("AÉé㈤ヲ") + assert missing_glyphs == {"É", "ヲ"} + + +def test_font_get_missing_glyphs_cmap_encoding_4(): + font_cmap_encoding_4 = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "文鼎中特廣告體 - PlatEncID 4.ttf")) + font_file = FontFile.from_font_path(font_cmap_encoding_4) + + assert len(font_file.font_faces) == 1 + font_face = font_file.font_faces[0] + assert isinstance(font_face, NormalFontFace) + + # Try "ヲ" since cp950 doesn't support this char + missing_glyphs = font_face.get_missing_glyphs("é¥卷ヲ") + assert missing_glyphs == {"é", "ヲ"} + + +def test_font_get_missing_glyphs_cmap_legacy_arabic_simplified(): + font_path = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "legacy-arabic-simplified-SimplifiedArabic.ttf")) + font_file = FontFile.from_font_path(font_path) + + assert len(font_file.font_faces) == 1 + font_face = font_file.font_faces[0] + assert isinstance(font_face, NormalFontFace) + + missing_glyphs = font_face.get_missing_glyphs("جa") + assert missing_glyphs == set("a") + + +def test_font_get_missing_glyphs_cmap_legacy_arabic_traditional(): + font_path = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "legacy-arabic-traditional-AGACairoRegular.ttf")) + font_file = FontFile.from_font_path(font_path) + + assert len(font_file.font_faces) == 1 + font_face = font_file.font_faces[0] + assert isinstance(font_face, NormalFontFace) + + missing_glyphs = font_face.get_missing_glyphs("جa") + assert missing_glyphs == set("a") + + def test_font_get_missing_glyphs_cmap_encoding_mac_platform(): font_mac_platform = Path(os.path.join(os.path.dirname(dir_path), "file", "fonts", "font_mac.TTF")) font_file = FontFile.from_font_path(font_mac_platform)