summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/typo-wrp.lmt
blob: b77e27532218198d9aea1130b0efc0d1a08fb30f (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
if not modules then modules = { } end modules ['typo-wrp'] = {
    version   = 1.001,
    comment   = "companion to typo-wrp.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- begin/end par wrapping stuff ... more to come

local boundary_code     = nodes.nodecodes.boundary
local glyph_code        = nodes.nodecodes.glyph
local wordboundary_code = nodes.boundarycodes.word
local userboundary_code = nodes.boundarycodes.user

local nuts              = nodes.nuts

local findtail          = nuts.tail
local getprev           = nuts.getprev
local setnext           = nuts.setnext
local getid             = nuts.getid
local getdata           = nuts.getdata
local isglyph           = nuts.isglyph
local getsubtype        = nuts.getsubtype
local getattr           = nuts.getattr
local flushnodelist     = nuts.flushlist
local traverse_boundary = nuts.traversers.boundary
local insertnodebefore  = nuts.insertbefore
local newkern           = nuts.pool.kern

local fontdata          = fonts.hashes.identifiers

local enableaction      = nodes.tasks.enableaction

local implement         = interfaces.implement

local wrappers          = { }
typesetters.wrappers    = wrappers

local trace_wrappers      trackers.register("typesetters.wrappers",function(v) trace_wrappers = v end)
local report            = logs.reporter("paragraphs","wrappers")

-- In luametatex we don't have the parfilskip attached yet but we can have final glue
-- anyway. This check is very bound to the \crlf definition where we get:
--
-- ... boundary [strut: hlist] [break: glue penalty] boundary

local a_crlf = attributes.private("crlf")

local function remove_dangling_crlf(head,tail)
    if head and tail then
        if getid(tail) == boundary_code and getsubtype(tail) == wordboundary_code then
            -- findnode could run backwards
            if getattr(tail,a_crlf) then
                local t = tail
                while t do
                    t = getprev(t)
                    if not t then
                        break
                    elseif getid(t) == boundary_code and getsubtype(t) == wordboundary_code then
                        if t ~= head then
                            if trace_wrappers then
                                report("removing a probably unwanted end-of-par break in line %s (guess)",tex.inputlineno)
                            end
                            tail = getprev(t)
                            setnext(tail)
                            flushnodelist(t)
                        end
                        break
                    end
                end
            end
        end
    end
    return head, tail
end

implement {
    name     = "enablecrlf",
    onlyonce = true,
    actions  = function()
        enableaction("processors","typesetters.wrappers.handler")
    end
}

-- Here's a solution for a trivial challenge by MS who got it from the internet
-- (SE). If needed we can make it a bit more granular.

local tighten       = { }
typesetters.tighten = tighten

local trace_tighten   trackers.register("typesetters.tighten",function(v) trace_tighten = v end)
local report        = logs.reporter("typesetters","tighten")

local a_tightfit_boundary = tex.boundaries.system("c_tightfit_boundary") -- private, not defined with \defineboundary

local function bbcompensation(font,char)
    local tfmdata   = fontdata[font]
    local character = tfmdata.characters[char]
    if character then
        local compensation = character.compensation
        if not compensation then
            local description = tfmdata.descriptions[char]
            if description then
                local boundingbox  = description.boundingbox
                return boundingbox and (boundingbox[3] - (description.width or 0)) * tfmdata.parameters.hfactor
            end
            character.compensation = compensation
        end
    end
    return 0
end

function tighten.handler(head)
    for n, subtype in traverse_boundary, head do
        if subtype == userboundary_code and getdata(n) == a_tightfit_boundary then
            local prev = getprev(n)
            if prev then
                local char, font = isglyph(prev)
                if char then
                    local compensation = bbcompensation(font,char)
                    if compensation > 0 then
                        if trace_tighten then
                            report("compensating %p after %C",compensation,char)
                        end
                        insertnodebefore(head,n,newkern(compensation))
                    end
                end
            end
        end
    end
    return head
end

implement {
    name     = "enabletighten",
    onlyonce = true,
    actions  = function()
        enableaction("processors","typesetters.tighten.handler")
    end
}

local dimension_value = tokens.values.dimension
local texgetnest      = tex.getnest

implement {
    name      = "tightfitcompensation",
    public    = true,
    protected = true,
    usage     = "value",
    actions   = function()
        local list = texgetnest()
        if list then
            list = list.tail
        end
        return
            dimension_value,
            list and list.id == glyph_code and bbcompensation(list.font,list.char) or 0
    end,
}