%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/utils/fonts/sfnt/ |
Current File : //usr/lib/calibre/calibre/utils/fonts/sfnt/gsub.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>' __docformat__ = 'restructuredtext en' from struct import unpack_from from functools import partial from calibre.utils.fonts.sfnt import UnknownTable, FixedProperty from calibre.utils.fonts.sfnt.errors import UnsupportedFont from calibre.utils.fonts.sfnt.common import (ScriptListTable, FeatureListTable, SimpleListTable, LookupTable, ExtensionSubstitution, UnknownLookupSubTable) from polyglot.builtins import iteritems, itervalues class SingleSubstitution(UnknownLookupSubTable): formats = {1, 2} def initialize(self, data): if self.format == 1: self.delta = data.unpack('h') else: count = data.unpack('H') self.substitutes = data.unpack('%dH'%count, single_special=False) def all_substitutions(self, glyph_ids): gid_index_map = self.coverage.coverage_indices(glyph_ids) if self.format == 1: return {gid + self.delta for gid in gid_index_map} return {self.substitutes[i] for i in itervalues(gid_index_map)} class MultipleSubstitution(UnknownLookupSubTable): formats = {1} def initialize(self, data): self.coverage_to_subs_map = self.read_sets(data, set_is_index=True) def all_substitutions(self, glyph_ids): gid_index_map = self.coverage.coverage_indices(glyph_ids) ans = set() for index in itervalues(gid_index_map): glyphs = set(self.coverage_to_subs_map[index]) ans |= glyphs return ans class AlternateSubstitution(MultipleSubstitution): pass class LigatureSubstitution(UnknownLookupSubTable): formats = {1} def initialize(self, data): self.coverage_to_lig_map = self.read_sets(data, self.read_ligature) def read_ligature(self, data): lig_glyph, count = data.unpack('HH') components = data.unpack('%dH'%(count-1), single_special=False) return (lig_glyph, components) def all_substitutions(self, glyph_ids): gid_index_map = self.coverage.coverage_indices(glyph_ids) ans = set() for start_glyph_id, index in iteritems(gid_index_map): for glyph_id, components in self.coverage_to_lig_map[index]: components = (start_glyph_id,) + components if set(components).issubset(glyph_ids): ans.add(glyph_id) return ans class ContexttualSubstitution(UnknownLookupSubTable): formats = {1, 2, 3} @property def has_initial_coverage(self): return self.format != 3 def initialize(self, data): pass # TODO def all_substitutions(self, glyph_ids): # This table only defined substitution in terms of other tables return set() class ChainingContextualSubstitution(UnknownLookupSubTable): formats = {1, 2, 3} @property def has_initial_coverage(self): return self.format != 3 def initialize(self, data): pass # TODO def all_substitutions(self, glyph_ids): # This table only defined substitution in terms of other tables return set() class ReverseChainSingleSubstitution(UnknownLookupSubTable): formats = {1} def initialize(self, data): backtrack_count = data.unpack('H') backtrack_offsets = data.unpack('%dH'%backtrack_count, single_special=False) lookahead_count = data.unpack('H') lookahead_offsets = data.unpack('%dH'%lookahead_count, single_special=False) backtrack_offsets = [data.start_pos + x for x in backtrack_offsets] lookahead_offsets = [data.start_pos + x for x in lookahead_offsets] backtrack_offsets, lookahead_offsets # TODO: Use these count = data.unpack('H') self.substitutes = data.unpack('%dH'%count) def all_substitutions(self, glyph_ids): gid_index_map = self.coverage.coverage_indices(glyph_ids) return {self.substitutes[i] for i in itervalues(gid_index_map)} subtable_map = { 1: SingleSubstitution, 2: MultipleSubstitution, 3: AlternateSubstitution, 4: LigatureSubstitution, 5: ContexttualSubstitution, 6: ChainingContextualSubstitution, 8: ReverseChainSingleSubstitution, } class GSUBLookupTable(LookupTable): def set_child_class(self): if self.lookup_type == 7: self.child_class = partial(ExtensionSubstitution, subtable_map=subtable_map) else: self.child_class = subtable_map[self.lookup_type] class LookupListTable(SimpleListTable): child_class = GSUBLookupTable class GSUBTable(UnknownTable): version = FixedProperty('_version') def decompile(self): (self._version, self.scriptlist_offset, self.featurelist_offset, self.lookuplist_offset) = unpack_from(b'>L3H', self.raw) if self._version != 0x10000: raise UnsupportedFont('The GSUB table has unknown version: 0x%x'% self._version) self.script_list_table = ScriptListTable(self.raw, self.scriptlist_offset) # self.script_list_table.dump() self.feature_list_table = FeatureListTable(self.raw, self.featurelist_offset) # self.feature_list_table.dump() self.lookup_list_table = LookupListTable(self.raw, self.lookuplist_offset) def all_substitutions(self, glyph_ids): glyph_ids = frozenset(glyph_ids) ans = set(glyph_ids) for lookup_table in self.lookup_list_table: for subtable in lookup_table: glyphs = subtable.all_substitutions(ans) if glyphs: ans |= glyphs return ans - {glyph_ids}