summaryrefslogtreecommitdiff
path: root/lib/lettering/font_variant.py
blob: d826dca60eaffab131f785f4816ec334f7909622 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -*- coding: UTF-8 -*-

import os
import inkex
import simplestyle

from ..svg.tags import INKSCAPE_GROUPMODE, INKSCAPE_LABEL
from .glyph import Glyph


class FontVariant(object):
    """Represents a single variant of a font.

    Each font may have multiple variants for left-to-right, right-to-left,
    etc.  Each variant has a set of Glyphs, one per character.

    A FontVariant instance can be accessed as a dict by using a unicode
    character as a key.

    Properties:
      path    -- the path to the directory containing this font
      variant -- the font variant, specified using one of the constants below
      glyphs  -- a dict of Glyphs, with the glyphs' unicode characters as keys.
    """

    # We use unicode characters rather than English strings for font file names
    # in order to be more approachable for languages other than English.
    LEFT_TO_RIGHT = u"→"
    RIGHT_TO_LEFT = u"←"
    TOP_TO_BOTTOM = u"↓"
    BOTTOM_TO_TOP = u"↑"
    VARIANT_TYPES = (LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP)

    @classmethod
    def reversed_variant(cls, variant):
        if variant == cls.LEFT_TO_RIGHT:
            return cls.RIGHT_TO_LEFT
        elif variant == cls.RIGHT_TO_LEFT:
            return cls.LEFT_TO_RIGHT
        elif variant == cls.TOP_TO_BOTTOM:
            return cls.BOTTOM_TO_TOP
        elif variant == cls.BOTTOM_TO_TOP:
            return cls.TOP_TO_BOTTOM
        else:
            return None

    def __init__(self, font_path, variant, default_glyph=None):
        self.path = font_path
        self.variant = variant
        self.default_glyph = default_glyph
        self.glyphs = {}
        self._load_glyphs()

    def _load_glyphs(self):
        svg_path = os.path.join(self.path, u"%s.svg" % self.variant)
        with open(svg_path) as svg_file:
            svg = inkex.etree.parse(svg_file)

        glyph_layers = svg.xpath(".//svg:g[starts-with(@inkscape:label, 'GlyphLayer-')]", namespaces=inkex.NSS)
        for layer in glyph_layers:
            self._clean_group(layer)
            layer.attrib[INKSCAPE_LABEL] = layer.attrib[INKSCAPE_LABEL].replace("GlyphLayer-", "", 1)
            glyph_name = layer.attrib[INKSCAPE_LABEL]
            self.glyphs[glyph_name] = Glyph(layer)

    def _clean_group(self, group):
        # We'll repurpose the layer as a container group labelled with the
        # glyph.
        del group.attrib[INKSCAPE_GROUPMODE]

        style_text = group.get('style')

        if style_text:
            # The layer may be marked invisible, so we'll clear the 'display'
            # style.
            style = simplestyle.parseStyle(group.get('style'))
            style.pop('display')
            group.set('style', simplestyle.formatStyle(style))

    def __getitem__(self, character):
        if character in self.glyphs:
            return self.glyphs[character]
        else:
            return self.glyphs.get(self.default_glyph, None)

    def __contains__(self, character):
        return character in self.glyphs