mirror of
https://git.fifo-f.eu/tex-projects/books/The-Invisible-Man-LaTeX.git
synced 2025-04-11 21:08:18 +02:00
116 lines
No EOL
4.3 KiB
Lua
116 lines
No EOL
4.3 KiB
Lua
-- Use method aliases for better performance
|
|
local nodecopy = node.copy
|
|
local nodecopylist = node.copy_list
|
|
local nodetail = node.tail
|
|
local nodeinsertbefore = node.insert_before
|
|
local nodeinsertafter = node.insert_after
|
|
local nodetraverseid = node.traverse_id
|
|
|
|
-- Get node ids from their names
|
|
local HLIST = node.id("hlist")
|
|
local WHAT = node.id("whatsit")
|
|
local COL = node.subtype("pdf_colorstack")
|
|
|
|
-- Make nodes for beginning and end of colored regions
|
|
local color_p1 = node.new(WHAT,COL)
|
|
local color_p1s = node.new(WHAT,COL)
|
|
local color_m1 = node.new(WHAT,COL)
|
|
local color_pm1 = node.new(WHAT,COL)
|
|
local color_pm1s = node.new(WHAT,COL)
|
|
local color_pop = node.new(WHAT,COL)
|
|
color_p1.stack = 0
|
|
color_p1.command = 1
|
|
color_p1.data = "0 0 1 rg" -- PDF code for RGB blue
|
|
color_p1s.stack = 0
|
|
color_p1s.command = 1
|
|
color_p1s.data = "0 0.7 0.7 rg" -- PDF code for RGB dark cyan
|
|
color_m1.stack = 0
|
|
color_m1.command = 1
|
|
color_m1.data = "1 0 0 rg" -- PDF code for RGB red
|
|
color_pm1.stack = 0
|
|
color_pm1.command = 1
|
|
color_pm1.data = "1 0 1 rg" -- PDF code for RGB magenta
|
|
color_pm1s.stack = 0
|
|
color_pm1s.command = 1
|
|
color_pm1s.data = "1 .5 .5 rg" -- PDF code for RGB pink
|
|
color_pop.stack = 0
|
|
color_pop.command = 2
|
|
|
|
-- Color to use for last line in the next post-linebreak filter call (nil = no color)
|
|
local LastLineColor = nil
|
|
|
|
-- Function to color the last line in the given list
|
|
local color_last_line = function (n)
|
|
-- Get the last hlist in the given list
|
|
local lastLine
|
|
for line in nodetraverseid(HLIST, n) do
|
|
lastLine = line
|
|
end
|
|
|
|
-- Surround it with color start/stop
|
|
lastLine.head = nodeinsertbefore(lastLine.head, lastLine.head, nodecopy(LastLineColor))
|
|
nodeinsertafter(lastLine.head, nodetail(lastLine.head), nodecopy(color_pop))
|
|
end
|
|
|
|
-- Callback to check if changing the looseness by +-1 would affect the line count
|
|
local pre_linebreak_test_looseness = function (head, groupeCode)
|
|
-- Disable underfull and overfull boxes reporting
|
|
luatexbase.add_to_callback("hpack_quality", function() end, "hpqfilter")
|
|
luatexbase.add_to_callback("vpack_quality", function() end, "vpqfilter")
|
|
|
|
-- Build a copy of the paragraph normally
|
|
local n, i = tex.linebreak(nodecopylist(head))
|
|
|
|
-- Build a copy of the paragraph with increased looseness and default emergency stretch
|
|
local nP1s, iP1s = tex.linebreak(nodecopylist(head), {looseness=tex.looseness+1})
|
|
|
|
local nP1, iP1
|
|
if iP1s.prevgraf > i.prevgraf then
|
|
-- It worked with the default emergency stretch, let's try without
|
|
nP1, iP1 = tex.linebreak(nodecopylist(head), {looseness=tex.looseness+1, emergencystretch=0})
|
|
else
|
|
-- Didn't work with emergency stretch, no point to try without
|
|
nP1, iP1 = n, i
|
|
end
|
|
|
|
-- Build a copy of the paragraph with decreased looseness
|
|
local nM1, iM1 = tex.linebreak(nodecopylist(head), {looseness=tex.looseness-1})
|
|
|
|
-- Reenable underfull and overfull boxes reporting
|
|
luatexbase.remove_from_callback("hpack_quality", "hpqfilter")
|
|
luatexbase.remove_from_callback("vpack_quality", "vpqfilter")
|
|
|
|
-- Set color to use in the post-linebreak callback
|
|
if iP1.prevgraf > i.prevgraf and iM1.prevgraf < i.prevgraf then
|
|
-- Both +1 and -1 looseness would work
|
|
LastLineColor = color_pm1
|
|
elseif iP1s.prevgraf > i.prevgraf and iM1.prevgraf < i.prevgraf then
|
|
-- Both +1 and -1 looseness would work, but +1 only with emergency stretch
|
|
LastLineColor = color_pm1s
|
|
elseif iP1.prevgraf > i.prevgraf then
|
|
-- Only +1 looseness would work
|
|
LastLineColor = color_p1
|
|
elseif iP1s.prevgraf > i.prevgraf then
|
|
-- Only +1 looseness would work and only thanks to the emergency stretch
|
|
LastLineColor = color_p1s
|
|
elseif iM1.prevgraf < i.prevgraf then
|
|
-- Only -1 looseness would work
|
|
LastLineColor = color_m1
|
|
else
|
|
LastLineColor = nil
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-- Callback to colorize the last line of the paragraph when ColorLastLine is true
|
|
local post_linebreak_color_last_line = function (head, groupcode)
|
|
if LastLineColor then
|
|
color_last_line(head)
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- Register callbacks
|
|
luatexbase.add_to_callback("pre_linebreak_filter", pre_linebreak_test_looseness, "pre_linebreak_test_looseness")
|
|
luatexbase.add_to_callback("post_linebreak_filter", post_linebreak_color_last_line, "post_linebreak_color_last_line") |