summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-par.lua
blob: 0449becbf5e51cd0480a1ada9780253408b9b3d6 (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
if not modules then modules = { } end modules ['typo-par'] = {
    version   = 1.001,
    comment   = "companion to typo-par.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- A playground for experiments.

local utfbyte = utf.byte
local utfchar = utf.char

local trace_paragraphs  = false  trackers.register("typesetters.paragraphs",        function(v) trace_paragraphs = v end)
local trace_dropper     = false  trackers.register("typesetters.paragraphs.dropper",function(v) trace_dropper    = v end)

local report_paragraphs = logs.reporter("nodes","paragraphs")
local report_dropper    = logs.reporter("nodes","dropped")

typesetters.paragraphs  = typesetters.paragraphs or { }
local paragraphs        = typesetters.paragraphs

local nodecodes         = nodes.nodecodes
local whatsitcodes      = nodes.whatsitcodes
local tasks             = nodes.tasks

local variables         = interfaces.variables

local texattribute      = tex.attribute
local unsetvalue        = attributes.unsetvalue

local glyph_code        = nodecodes.glyph
local hlist_code        = nodecodes.hlist
local kern_node         = nodecodes.kern
local whatsit_code      = nodecodes.whatsit
local localpar_code     = whatsitcodes.localpar

local a_paragraph       = attributes.private("paragraphspecial")
local a_color           = attributes.private('color')
local a_transparency    = attributes.private('transparency')
local a_colorspace      = attributes.private('colormodel')

local dropper = {
    enabled  = false,
 -- font     = 0,
 -- n        = 0,
 -- distance = 0,
 -- hoffset  = 0,
 -- voffset  = 0,
}

local droppers = { }

typesetters.paragraphs.droppers = droppers

function droppers.set(specification)
    dropper = specification or { }
end

function droppers.freeze()
    if dropper.enabled then
        dropper.font = font.current()
    end
end

-- dropped caps experiment (will be done properly when luatex
-- stores the state in the local par node) .. btw, search still
-- works with dropped caps, as does an export

-- we need a 'par' attribute and in fact for dropped caps we don't need
-- need an attribute ... dropit will become s state counter (or end up
-- in the localpar user data

-- for the moment, each paragraph gets a number as id (attribute) ..problem
-- with nesting .. or anyhow, needed for tagging anyway

-- todo: prevent linebreak .. but normally a dropper ends up atthe top of
-- a page so this has a low priority

local function process(namespace,attribute,head)
    local done = false
    if head.id == whatsit_code and head.subtype == localpar_code then
        -- begin of par
        local a = head[attribute]
        if a and a > 0 then
            if dropper.enabled then
                dropper.enabled = false -- dangerous for e.g. nested || in tufte
                local first = head.next
                if first and first.id == hlist_code then
                    -- parbox .. needs to be set at 0
                    first = first.next
                end
                if first and first.id == glyph_code then
-- if texattribute[a_paragraph] >= 0 then
--     texattribute[a_paragraph] = unsetvalue
-- end
                    local char = first.char
                    local prev = first.prev
                    local next = first.next
                 -- if prev.id == hlist_code then
                 --     -- set the width to 0
                 -- end
                    if next and next.id == kern_node then
                        next.kern = 0
                    end
                    first.font = dropper.font or first.font
                    -- can be a helper
                    local ma = dropper.ma or 0
                    local ca = dropper.ca
                    local ta = dropper.ta
                    if ca and ca > 0 then
                        first[a_colorspace] = ma == 0 and 1 or ma
                        first[a_color] = ca
                    end
                    if ta and ta > 0 then
                        first[a_transparency] = ta
                    end
                    --
                    local width  = first.width
                    local height = first.height
                    local depth  = first.depth
                    local distance = dropper.distance or 0
                    local voffset = dropper.voffset or 0
                    local hoffset = dropper.hoffset or 0
                    first.xoffset = - width  - hoffset - distance
                    first.yoffset = - height - voffset
                    if true then
                        -- needed till we can store parindent with localpar
                        first.prev = nil
                        first.next = nil
                        local h = node.hpack(first)
                        h.width = 0
                        h.height = 0
                        h.depth = 0
                        prev.next = h
                        next.prev = h
                        h.next = next
                        h.prev = prev
                    end
                    if dropper.location == variables.margin then
                        -- okay
                    else
                        local lines = tonumber(dropper.n) or 0
                        if lines == 0 then -- safeguard, not too precise
                            lines = math.ceil((height+voffset) / tex.baselineskip.width)
                        end
                        tex.hangafter  = - lines
                        tex.hangindent = width + distance
                    end
                    done = true
                end
            end
        end
    end
    return head, done
end

local enabled = false

function paragraphs.set(n)
    if n == variables.reset or not tonumber(n) or n == 0 then
        texattribute[a_paragraph] = unsetvalue
    else
        if not enabled then
            tasks.enableaction("processors","typesetters.paragraphs.handler")
            if trace_paragraphs then
                report_paragraphs("enabling paragraphs")
            end
            enabled = true
        end
        texattribute[a_paragraph] = n
    end
end

paragraphs.attribute = a_paragraph

paragraphs.handler = nodes.installattributehandler {
    name      = "paragraphs",
    namespace = paragraphs,
    processor = process,
}