File: Attachment.py

package info (click to toggle)
python-fontfeatures 1.9.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,096 kB
  • sloc: python: 9,112; makefile: 22
file content (132 lines) | stat: -rw-r--r-- 4,642 bytes parent folder | download
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import logging


def shaper_inputs(self):
    """Returns a list of potential glyphs to determine whether to test if this
    rule applies at a given point."""
    return [self.bases.keys(), self.marks.keys()]


def find_base_backwards(self, buf, ix):
    """Looks backwards in a buffer from index ``ix`` to find the nearest base."""
    start_ix = ix
    ix = ix - 1
    while ix >= 0:
        if buf[ix].glyph in self.bases.keys():
            # Check for unhelpful stuff in between
            my_category = buf[ix].category[0]
            for i in range(ix + 1, start_ix):
                if buf[i].category[0] == my_category or buf[i].category[0] == "unknown":
                    # Oops, we skipped over another %s to get here
                    return None
            return ix
        ix = ix - 1
    return None


def would_apply_at_position(self, buf, ix, namedclasses={}):
    """Tests to see if this rule would apply at position ``ix`` of the buffer."""
    from fontFeatures.shaperLib.Rule import _expand_slot

    logging.getLogger("fontFeatures.shaperLib").debug(
        "Testing if rule would apply at position %i" % (ix)
    )
    if namedclasses:
        marks = _expand_slot(self.marks.keys(), namedclasses)
        bases = _expand_slot(self.bases.keys(), namedclasses)
    else:
        marks = self.marks.keys()
        bases = self.bases.keys()

    if self.is_cursive:
        if ix == 0:
            logging.getLogger("fontFeatures.shaperLib").debug(
                " * No, it has no adjacent glyph"
            )
            return False
        # We will sort it out later
        # logging.getLogger("fontFeatures.shaperLib").debug(" * Yes, %s/%s is a pair" % (buf[ix].glyph, buf[ix-1].glyph))
        return True

    # Mark to base is a bit different, as multiple marks can attach to a base
    # so we search backwards for the preceding base glyph
    # XXX mark to mark
    if buf[ix].glyph not in marks:
        logging.getLogger("fontFeatures.shaperLib").debug(
            " * No, %s is not in our mark list" % (buf[ix].glyph)
        )
        return False
    base_ix = find_base_backwards(self, buf, ix)
    if base_ix is None:
        logging.getLogger("fontFeatures.shaperLib").debug(
            " * No, I couldn't find a base glyph"
        )
        return False
    if buf[base_ix].glyph not in bases:
        logging.getLogger("fontFeatures.shaperLib").debug(
            " * No, %s is not in our base list" % buf[base_ix].glyph
        )
        return False
    logging.getLogger("fontFeatures.shaperLib").debug(
        " * Yes, attaching mark %s/%i to %s/%i"
        % (buf[ix].glyph, ix, buf[base_ix].glyph, base_ix)
    )
    return True


def _do_apply_cursive(self, buf, ix):
    this_record = buf[ix]
    prev_record = buf[ix - 1]

    mark = prev_record.glyph
    base = this_record.glyph

    if mark not in self.marks or base not in self.bases:
        return
    exit_x, exit_y = self.marks.get(mark, (0, 0))
    entry_x, entry_y = self.bases.get(base, (0, 0))

    i = ix - 1
    j = ix

    if buf.direction == "LTR":
        buf[i].position.xAdvance = exit_x + (buf[i].position.xPlacement or 0)
        d = entry_x + (buf[j].position.xPlacement or 0)
        buf[j].position.xAdvance = (buf[j].position.xAdvance or 0) - d
        buf[j].position.xPlacement = (buf[j].position.xPlacement or 0) - d
    elif buf.direction == "RTL":
        d = exit_x + (buf[i].position.xPlacement or 0)
        logging.getLogger("fontFeatures.shaperLib").debug(
            "Adjusting advance of %s by %i" % (buf[i].glyph, -d)
        )
        buf[i].position.xAdvance = (buf[i].position.xAdvance or 0) - d
        buf[i].position.xPlacement = (buf[i].position.xPlacement or 0) - d

        buf[j].position.xAdvance = entry_x + (buf[j].position.xPlacement or 0)

    child = i
    parent = j
    x_offset = entry_x - exit_x
    y_offset = entry_y - exit_y
    if not (self.flags & 1):
        parent, child = child, parent
        x_offset = -x_offset
        y_offset = -y_offset
    buf[child].position.yPlacement = y_offset
    this_record.attach_type = "cursive"
    this_record.attach_chain = parent - child


def _do_apply(self, buf, ix, namedclasses={}):
    if self.is_cursive:
        return _do_apply_cursive(self, buf, ix)

    base_ix = find_base_backwards(self, buf, ix)
    mark = buf[ix].glyph
    base = buf[base_ix].glyph
    xpos = self.bases[base][0] - self.marks[mark][0]
    ypos = self.bases[base][1] - self.marks[mark][1]
    buf[ix].position.xPlacement = xpos
    buf[ix].position.yPlacement = ypos
    buf[ix].attach_type = "mark"
    buf[ix].attach_chain = base_ix - ix