summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/plain/pitex/output.ptx
blob: 20a0dc677f28b6395d34f9f8d1566b9d09a04288 (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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
\defactiveparameter page {%
  \settovalue\pdfpagewidth  #1 : width
  \settovalue\pdfpageheight #1 : height
  \settovalue\baselineskip  #1 : baselineskip
  \settovalueor\topskip     #1 : topskip {\topskip=\baselineskip}%
  \settovalue\pdfhorigin    #1 : left
  \ifattribute #1 : right
              {\hsize = \dimexpr(\pdfpagewidth-\pdfhorigin-\usevalue #1 : right )\relax}
              {\settovalue\hsize #1 : hsize }%
  \settovalue\pdfvorigin    #1 : top
  \settovalue\parindent     #1 : parindent
  \settovalue\parskip       #1 : parskip
  \ifattribute #1 : lines {\vsize=\usevalue #1 : lines \baselineskip}{}%
  }

\restrictparameter page : 
  width
  height
  hsize
  baselineskip
  topskip
  left
  right
  top
  lines
  parindent
  parskip
\par

% Defaults... they don't produce anything beautiful.
% I redefine them on every job.
\setparameter page:
  height       = 28cm
  width        = 21cm
  hsize        = 15cm
  baselineskip = 12pt
  lines        = 42
  left         = 1in
  top          = 1in
  parskip      = 0pt

\widowpenalty151
\clubpenalty0
\holdinginserts1
\newdimen\outputsize
\newif\ifheader

\gates new \OutputRoutine {OutputRoutine}%

\OutputRoutine list {output}
  [precheck]
    {%
    \global\holdinginserts0
    \OutputRoutine skip {precheck, shipout}{output}%
    \ifnum\outputpenalty<\widowpenalty
      \global\outputsize=\vsize
    \else
      \ifnum\outputpenalty=10000
        \global\outputsize=\vsize
      \else
        \ifdim\pagegoal<\vsize
          \global\advance\vsize-\baselineskip
          \global\outputsize=\dimexpr\vsize+\baselineskip\relax
        \else
          \global\advance\vsize\baselineskip
          \global\outputsize=\dimexpr\vsize-\baselineskip\relax
        \fi
      \fi
    \fi
    \unvbox\outputbox
    \ifnum\outputpenalty=10000
      \penalty0
    \else
      \penalty\outputpenalty
    \fi}
%
  (shipout)
  . (inserts)
  . . [inserts_figures]   ?{conditional = \unless\ifvoid\ptx@insert_figures} {%
        \setbox\outputbox=\vbox to \outputsize{%
        \box\ptx@insert_figures
        \unvbox\outputbox}}
  . . [inserts_footnotes] ?{conditional = \unless\ifvoid\ptx@insert_footnotes} {%
        \setbox\outputbox=\vbox to \outputsize{%
          \unvbox\outputbox
          \vfil
          \vskip.5\skip\ptx@insert_footnotes
          \vbox to0pt{\vss\hrule width .3\hsize}%
          \vskip.5\skip\ptx@insert_footnotes
          \unvbox\ptx@insert_footnotes}}
  %
  . [headers] {%
      \setbox\outputbox=\vbox{%
      \kern-3\baselineskip
      \vbox to3\baselineskip{%
        \hbox to\hsize{\strut\baselineskip {0pt}%
          \normalsize\rm\sc
          \ifodd\pageno
            \hfill\usevalue chapter : inner_title \rlap{\kern1em \the\pageno}\kern-3em
          \else
            \kern-3em\llap{\the\pageno\kern1em }\usevalue chapter : inner_title \hfill
          \fi}
          \vfill}
      \nointerlineskip
      \box\outputbox}}
    %
  . [ship] {%
      \settovalue\pdfhorigin page : left
      \shipout\box\outputbox}
    %
  . [postship] {%
      \global\holdinginserts1
      \global\vsize\outputsize
      \global\advance\count0 1
      \ifnum\insertpenalties>0
        \ifnum\outputpenalty=\clearpagepenalty
          \hbox{}\vfil\penalty\outputpenalty
        \fi
      \fi}


\output{%
  \OutputRoutine execute {output}%
  }



% MARGIN NOTES
\setparameter marginnote :
  hsize     = 3cm
  hpos      = fr
  font      = \it
  parindent = 0pt
  side      = right
  gap       = 1em

\newcount\notecount
\newattribute\ptx@marginnote_attribute
\def\marginnote{%
  \ifnext[
    {\ptx@marginnote}
    {\ptx@marginnote[]}%
  }

\long\def\ptx@marginnote[#1]#2{%
  \setparameterlist{marginnote@temp}{meta = marginnote, #1}%
  \global\advance\notecount 1
  \global\expandafter\newbox\csname marginnote_\the\notecount\endcsname
  \global\expandafter\setbox\csname marginnote_\the\notecount\endcsname=
    \vtop{%
      \settovalue\hsize marginnote@temp : hsize
      \settovalue{\advance\hsize} marginnote@temp : gap
      \leftskip=0pt \rightskip=0pt plus 1 fil \parfillskip=0pt\relax
      \ifcasevalue marginnote@temp : hpos
        \val ff \rightskip=0pt \parfillskip=0pt plus 1 fil
        \val rf \leftskip=0pt plus 1 fil \rightskip=1pt
        \val rr \leftskip=0pt plus 1 fil
      \endval
      \ifvalue marginnote@temp : side = left
        {\settovalue{\advance\rightskip} marginnote@temp : gap }
        {\settovalue{\advance\leftskip} marginnote@temp : gap }%
      \settovalue\baselineskip marginnote@temp : baselineskip
      \settovalue\parindent marginnote@temp : parindent
      \usevalue marginnote@temp : font
      #2}%
  \quitvmode % Must be outside the attribute's scope, otherwise the
             %  paragraphs DIR whatsit might get in the way.
  \bgroup
  \ifvalue marginnote@temp : side = left
    {\ptx@marginnote_attribute=-\expandafter\the\csname marginnote_\the\notecount\endcsname}
    {\ptx@marginnote_attribute=\expandafter\the\csname marginnote_\the\notecount\endcsname}\relax
  \pdfliteral{}%
  \egroup
  \deleteparameter marginnote@temp:%
  }

\luacode
local WHAT, HLIST, KERN = node.id("whatsit"), node.id("hlist"), node.id("kern")
local GLUE, SPEC = node.id("glue"), node.id("glue_spec")
local marginnote_table = {}
function pitex.misc.mark_lines (head)
  for line in node.traverse_id(HLIST, head) do
    local t = {left = {}, right = {}}
    local item = line.head
    while item do
      local next = item.next
      if item.id == WHAT then
        local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
        if attr then
          if attr < 0 then
            table.insert(t.left, -attr)
          else
            table.insert(t.right, attr)
          end
          line.head = node.remove(line.head, item)
        end
      end
      item = next
    end
    if #t.left > 0 or #t.right > 0 then
      table.insert(marginnote_table, t)
      node.set_attribute(line, \attributenumber\ptx@marginnote_attribute, #marginnote_table)
    end
  end
  return head
end

pitex.callback.register("post_linebreak_filter", "pitex.misc:mark_lines")

local lheight, rheight = 0, 0
local function update_height (h)
  lheight = lheight + h
  rheight = rheight + h
end

local function first_dim (n, t)
  while n do
    if node.has_field(n, "kern") then
      return n.kern
    elseif node.has_field(n, "spec") then
      return n.spec.width
    elseif node.has_field(n, "height") then
      return t == "height" and n.height or n.depth
    else
      n = t == "height" and n.next or n.prev
    end
  end
  return 0
end

function process_marginalia (head)
  lheight, rheight = 0, 0
  local item, first = node.slide(head), true
  while item do
    if node.has_field(item, "kern") then
      if not first then
        update_height(item.kern)
      end
    elseif node.has_field(item, "spec") then
      if not first then
        update_height(item.spec.width)
      end
    elseif node.has_field(item, "height") then
      if first then
        first = false
      else
        update_height(item.depth)
      end
      local attr = node.has_attribute(item, \attributenumber\ptx@marginnote_attribute)
      if attr then
        for side, notes in pairs (marginnote_table[attr]) do
          if #notes > 0 then
            local note
            for _, n in ipairs(notes) do
              if note then
                local n, g, s = tex.box[n], node.new(GLUE), node.new(SPEC)
                local d = first_dim(node.tail(note.head), "depth")
                local h = first_dim(n.head, "height")
                s.width = tex.baselineskip.width - (d + h)
                g.spec = s
                note.depth = note.depth + s.width + n.height + n.depth
                node.insert_after(note.head, node.tail(note.head), g)
                g.next, n.head.prev = n.head, g
              else
                note = tex.box[n]
              end
            end
            first = true
            local upward = note.depth - first_dim(node.tail(note.head), "depth")
            local remainingheight = side == "left" and lheight or rheight
            if upward > remainingheight then
              upward = remainingheight - upward
            else
              upward = 0
            end
            local kern = node.new(KERN, 1)
            kern.kern = upward - note.height - item.depth
            node.insert_before(note.list, note.list, kern)
            note.list = kern
            if side == "left" then
              note.shift = -note.width
              lheight = upward
            else
              note.shift = item.width
              rheight = upward
            end
            note.height, note.depth = 0, 0
            node.insert_after(head, item, note)
          else
            if side == "left" then
              lheight = lheight + item.height
            else
              rheight = rheight + item.height
            end
          end
        end
      else
        update_height(item.height)
      end
    end
    item = item.prev
  end
end
\luacode/

\OutputRoutine def {processmarginalia}{%
  \ptx@lua{process_marginalia(tex.box[255].list)}%
  }

\OutputRoutine add {processmarginalia}[first]{shipout}