summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-dig.lua
blob: 9ee57a794b15aedbdbf03627c62aebff647fb519 (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
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
133
134
135
136
137
138
if not modules then modules = { } end modules ['typo-dig'] = {
    version   = 1.001,
    comment   = "companion to typo-dig.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- we might consider doing this after the otf pass because now osf do not work
-- out well in node mode.

local next, type = next, type
local format, insert = string.format, table.insert
local round, div = math.round, math.div

local trace_digits = false  trackers.register("typesetting.digits", function(v) trace_digits = v end)

local report_digits = logs.new("digits")

local has_attribute      = node.has_attribute
local unset_attribute    = node.unset_attribute
local set_attribute      = node.set_attribute
local hpack_node         = node.hpack
local traverse_id        = node.traverse_id
local insert_before      = node.insert_before
local insert_after       = node.insert_after

local glyph = node.id("glyph")
local kern  = node.id("kern")

local new_glue = nodes.glue

local fontdata = fonts.identifiers
local chardata = fonts.characters
local quaddata = fonts.quads
local charbase = characters.data

typesetting        = typesetting        or { }
typesetting.digits = typesetting.digits or { }

local digits = typesetting.digits

digits.actions   = { }
digits.attribute = attributes.private("digits")

local a_digits = digits.attribute

local actions  = digits.actions

-- at some point we can manipulate the glyph node so then i need
-- to rewrite this then

function nodes.aligned(head,start,stop,width,how)
    if how == "flushright" or how == "middle" then
        head, start = insert_before(head,start,new_glue(0,65536,65536))
    end
    if how == "flushleft" or how == "middle" then
        head, stop = insert_after(head,stop,new_glue(0,65536,65536))
    end
    local prv, nxt = start.prev, stop.next
    start.prev, stop.next = nil, nil
    local packed = hpack_node(start,width,"exactly") -- no directional mess here, just lr
    if prv then
        prv.next, packed.prev = packed, prv
    end
    if nxt then
        nxt.prev, packed.next = packed, nxt
    end
    if packed.prev then
        return head, packed
    else
        return packed, packed
    end
end

actions[1] = function(head,start,attribute,attr)
    local font = start.font
    local char = start.char
    local unic = chardata[font][char].tounicode
    local what = unic and tonumber(unic,16) or char
    if charbase[what].category == "nd" then
        local oldwidth, newwidth = start.width, fonts.get_digit_width(font)
        if newwidth ~= oldwidth then
            if trace_digits then
                report_digits("digit trigger %s, instance %s, char 0x%05X, unicode 0x%05X, delta %s",
                    attr%100,div(attr,100),char,what,newwidth-oldwidth)
            end
            head, start = nodes.aligned(head,start,start,newwidth,"middle")
            return head, start, true
        end
    end
    return head, start, false
end

local function process(namespace,attribute,head)
    local done, current, ok = false, head, false
    while current do
        if current.id == glyph then
            local attr = has_attribute(current,attribute)
            if attr and attr > 0 then
                unset_attribute(current,attribute)
                local action = actions[attr%100] -- map back to low number
                if action then
                    head, current, ok = action(head,current,attribute,attr)
                    done = done and ok
                elseif trace_digits then
                    report_digits("unknown digit trigger %s",attr)
                end
            end
        end
        current = current and current.next
    end
    return head, done
end

local m = 0 -- a trick to make neighbouring ranges work

function digits.set(n)
    if trace_digits then
        report_digits("enabling digit handler")
    end
    tasks.enableaction("processors","typesetting.digits.handler")
    function digits.set(n)
        if m == 100 then
            m = 1
        else
            m = m + 1
        end
        tex.attribute[a_digits] = m * 100 + n
    end
    digits.set(n)
end

digits.handler = nodes.install_attribute_handler {
    name      = "digits",
    namespace = digits,
    processor = process,
}