def __init__(self, font, decompositions): self.font = font self.decompositions = decompositions self.missing_chars = Tally("Missing combinable characters", "char") self.unknown_classes = Tally("Unknown combining classes")
class FontFiller(object): """ Utility class for filling out a font based on combining characters. """ def __init__(self, font, decompositions): self.font = font self.decompositions = decompositions self.missing_chars = Tally("Missing combinable characters", "char") self.unknown_classes = Tally("Unknown combining classes") def add_glyph_to_font(self, char): """ Add the glyph representing char to the given font, if it can be built. """ if ord(char) in self.font: # It's already there! return True if char not in self.decompositions: # We don't know how to build it. return False components = self.decompositions[char] for component_char, combining_class in components: if combining_class not in SUPPORTED_COMBINING_CLASSES: # We don't know how to combine this with other characters. self.unknown_classes.record(combining_class) return False if not self.add_glyph_to_font(component_char): # We don't know how to build one of the required components. self.missing_chars.record(component_char) return False # Now we have all the components, let's put them together! glyph = self.font.new_glyph_from_data("char%d" % ord(char), codepoint=ord(char)) # Draw on the base char. base_char = components[0][0] base_combining_class = components[0][1] assert (base_combining_class == CC_SPACING, "base char should be a spacing char") base_glyph = self.font[ord(base_char)] glyph.merge_glyph(base_glyph, 0,0) glyph.advance = base_glyph.advance for component_char, combining_class in components[1:]: other_glyph = self.font[ord(component_char)] if combining_class == CC_SPACING: # Draw other_glyph beside the current glyph glyph.merge_glyph(other_glyph, glyph.advance,0) glyph.advance += other_glyph.advance elif combining_class == CC_A: # Draw other_glyph centred above the current glyph y_offset = 0 x_offset = 0 if "CAP_HEIGHT" in self.font and glyph.bbH > 0: # We assume combining glyphs are drawn above the # CAP_HEIGHT. y_offset = glyph.get_ascent() - self.font["CAP_HEIGHT"] if glyph.bbW > 0: x_offset = int( float(glyph.advance)/2 - float(other_glyph.advance)/2 ) glyph.merge_glyph(other_glyph, x_offset,y_offset) elif combining_class in (CC_B, CC_B_ATTACHED): # Draw other_glyph centred below the current glyph y_offset = -glyph.get_descent() x_offset = 0 if glyph.bbW > 0: x_offset = int( float(glyph.advance)/2 - float(other_glyph.advance)/2 ) glyph.merge_glyph(other_glyph, x_offset,y_offset) else: raise RuntimeError("Unsupported combining class %d" % (combining_class,)) return True def add_decomposable_glyphs_to_font(self): """ Adds all the glyphs that can be built to the given font. """ for char in self.decompositions: self.add_glyph_to_font(char)