Skip to content

Commit

Permalink
fix(packages): Refactor grid with new measurements
Browse files Browse the repository at this point in the history
Includes extensive refactoring but does a bit more than push code
around, also fixes some outstanding bugs in the grid package.

* Grid debug lines start and stop with the correct frame.
* Grid cursor is not reset by pushing some box types or switching
  frames.
* More line height scenarios are also taken into account.
* Turning off the grid returns control to the superseded typesetter
  functions, not always the default one.
  • Loading branch information
alerque committed Jan 4, 2020
1 parent 8c8f3cc commit c9a862a
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 81 deletions.
4 changes: 2 additions & 2 deletions core/typesetter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -581,10 +581,10 @@ SILE.defaultTypesetter = std.object {
SU.debug("typesetter", " 2) "..vbox)
if not previous then return SILE.nodefactory.vglue() end
local prevDepth = previous.depth
SU.debug("typesetter", " Depth of previous line was "..tostring(prevDepth))
SU.debug("typesetter", " Depth of previous line was " .. prevDepth)
local bls = SILE.settings.get("document.baselineskip")
local depth = bls.height:absolute() - vbox.height:absolute() - prevDepth:absolute()
SU.debug("typesetter", " Leading height = " .. tostring(bls.height) .. " - " .. tostring(vbox.height) .. " - " .. tostring(prevDepth) .. " = "..depth)
SU.debug("typesetter", " Leading height = " .. bls.height .. " - " .. vbox.height .. " - " .. prevDepth .. " = "..depth)

-- the lineskip setting is a vglue, but we need a version absolutized at this point, see #526
local lead = SILE.settings.get("document.lineskip").height:absolute()
Expand Down
2 changes: 1 addition & 1 deletion core/utilities.lua
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ end

utilities.rateBadness = function(inf_bad, shortfall, spring)
if spring:tonumber() == 0 then return inf_bad end
local bad = math.floor(100 * math.abs((shortfall:tonumber() / spring:tonumber())) ^ 3)
local bad = math.floor(100 * math.abs(shortfall:tonumber() / spring:tonumber()) ^ 3)
return math.min(inf_bad, bad)
end

Expand Down
162 changes: 95 additions & 67 deletions packages/grid.lua
Original file line number Diff line number Diff line change
@@ -1,91 +1,129 @@
local gridSpacing -- Should be a setting
-- TODO: Should be registered as a setting not hidden as a package variable
local gridSpacing = SILE.measurement()

local makeUp = function ()
if not SILE.typesetter.frame.state.totals.gridCursor then SILE.typesetter.frame.state.totals.gridCursor = 0 end
local toadd = gridSpacing - (SILE.typesetter.frame.state.totals.gridCursor % gridSpacing)
SILE.typesetter.frame.state.totals.gridCursor = SILE.typesetter.frame.state.totals.gridCursor + toadd
return SILE.nodefactory.newVglue({ height = SILE.length.new({ length = toadd }) })
local function makeUp (totals)
local toadd = gridSpacing - totals.gridCursor % gridSpacing
totals.gridCursor = totals.gridCursor + toadd
SU.debug("typesetter", "Makeup height = " .. toadd)
return SILE.nodefactory.vglue(toadd)
end

local leadingFor = function (self, vbox, previous)
if not self.frame.state.totals.gridCursor then self.frame.state.totals.gridCursor = 0 end
if not previous then return SILE.nodefactory.newVglue({height=SILE.length.new({})}) end
if type(vbox.height) == "table" then
self.frame.state.totals.gridCursor = self.frame.state.totals.gridCursor + vbox.height.length + previous.depth
else
self.frame.state.totals.gridCursor = self.frame.state.totals.gridCursor + vbox.height + previous.depth
end
return makeUp()
local function leadingFor (typesetter, vbox, previous)
SU.debug("typesetter", " Considering leading between two lines (grid mode):")
SU.debug("typesetter", " 1) "..previous)
SU.debug("typesetter", " 2) "..vbox)
if not previous then return SILE.nodefactory.vglue() end
SU.debug("typesetter", " Depth of previous line was " .. previous.depth)
local totals = typesetter.frame.state.totals
local oldCursor = totals.gridCursor
totals.gridCursor = totals.gridCursor + vbox.height:absolute() + previous.depth
SU.debug("typesetter", " Cursor change = " .. totals.gridCursor - oldCursor)
return makeUp(typesetter.frame.state.totals)
end

local pushVglue = function (self, spec)
if not self.frame.state.totals.gridCursor then
self.frame.state.totals.gridCursor = 0
end
spec.height.stretch = 0
spec.height.shrink = 0
self.frame.state.totals.gridCursor = self.frame.state.totals.gridCursor + SILE.measurement(spec.height):absolute()
SILE.defaultTypesetter.pushVglue(self, spec)
SILE.defaultTypesetter.pushVglue(self, makeUp())
local function pushVglue (typesetter, spec)
-- if SU.type(spec) ~= "table" then SU.warn("Please use pushVertical() to pass a premade node instead of a spec") end
local node = SU.type(spec) == "vglue" and spec or SILE.nodefactory.vglue(spec)
node.height.stretch = SILE.measurement()
node.height.shrink = SILE.measurement()
local totals = typesetter.frame.state.totals
totals.gridCursor = totals.gridCursor + SILE.measurement(node.height):absolute()
typesetter:pushVertical(node)
typesetter:pushVertical(makeUp(typesetter.frame.state.totals))
return node
end

local function pushExplicitVglue (typesetter, spec)
-- if SU.type(spec) ~= "table" then SU.warn("Please use pushVertical() to pass a premade node instead of a spec") end
local node = SU.type(spec) == "vglue" and spec or SILE.nodefactory.vglue(spec)
node.explicit = true
node.discardable = false
node.height.stretch = SILE.measurement()
node.height.shrink = SILE.measurement()
local totals = typesetter.frame.state.totals
totals.gridCursor = totals.gridCursor + SILE.measurement(node.height):absolute()
typesetter:pushVertical(node)
typesetter:pushVertical(makeUp(typesetter.frame.state.totals))
return node
end

local debugGrid = function ()
local t = SILE.typesetter
if not t.frame.state.totals.gridCursor then t.frame.state.totals.gridCursor = 0 end
local g = t.frame.state.totals.gridCursor
while g < t.frame:bottom() do
SILE.outputter.rule(t.frame:left(), t.frame:top() + g, t.frame:width(), 0.1)
g = g + gridSpacing
local function startGridInFrame (typesetter)
local queue = typesetter.state.outputQueue
typesetter.frame.state.totals.gridCursor = SILE.measurement(0)
if #queue == 0 then
typesetter.state.previousVbox = typesetter:pushVbox()
return
end
while queue[1] and queue[1].discardable do
table.remove(queue, 1)
end
if queue[1] then
table.insert(queue, 1, SILE.nodefactory.vbox())
table.insert(queue, 2, SILE.typesetter:leadingFor(queue[2], queue[1]))
end
end

local defaultPagebuilder = require("core/pagebuilder")
local function debugGrid ()
local frame = SILE.typesetter.frame
local gridCursor = gridSpacing
while gridCursor < frame:height() do
SILE.outputter.rule(frame:left(), frame:top() + gridCursor, frame:width(), 0.1)
gridCursor = gridCursor + gridSpacing
end
end

local gridPagebuilder = pl.class({
_base = defaultPagebuilder,
_base = require("core/pagebuilder"),

findBestBreak = function (_, options)
local vboxlist = SU.required(options, "vboxlist", "in findBestBreak")
local target = SU.required(options, "target", "in findBestBreak")
local i = 0
local totalHeight = SILE.length.new()
local totalHeight = SILE.length()
local bestBreak = 0
SU.debug("pagebuilder", "Page builder for frame "..SILE.typesetter.frame.id.." called with "..#vboxlist.." nodes, "..target)
if SU.debugging("vboxes") then
for j, box in ipairs(vboxlist) do
SU.debug("vboxes", (j == i and " >" or " ") .. j .. ": " .. box)
end
end
while i < #vboxlist do
i = i + 1
if not vboxlist[i]:isVglue() then
i = i - 1
break
end
end
SU.debug("pagebuilder", "Page builder for frame "..SILE.typesetter.frame.id.." called with "..#vboxlist.." nodes, "..target)
while i < #vboxlist do
i = i + 1
local vbox = vboxlist[i]
SU.debug("pagebuilder", "Dealing with VBox " .. vbox)
if (vbox:isVbox()) then
totalHeight = totalHeight + vbox.height + vbox.depth
if vbox:isVbox() then
totalHeight = totalHeight + vbox.height:absolute() + vbox.depth:absolute()
elseif vbox:isVglue() then
totalHeight = totalHeight + vbox.height
end
if vbox.type == "insertionVbox" then
totalHeight = totalHeight + vbox.height:absolute()
elseif vbox:isInsertion() then
target = SILE.insertions.processInsertion(vboxlist, i, totalHeight, target)
vbox = vboxlist[i]
end
local left = target - totalHeight.length
SU.debug("pagebuilder", "I have " .. tostring(left) .. "pts left")
local left = target - totalHeight
SU.debug("pagebuilder", "I have " .. left .. "left")
SU.debug("pagebuilder", "totalHeight " .. totalHeight .. " with target " .. target)
local badness = 0
if left < 0 then badness = 1000000 end
if vbox:isPenalty() then
if vbox.penalty < -3000 then badness = 100000
else badness = -(left * left) - vbox.penalty end
end
else badness = -left * left - vbox.penalty
end
end
if badness > 0 then
local onepage = {}
for j=1, bestBreak do
for j = 1, bestBreak do
onepage[j] = table.remove(vboxlist, 1)
end
while(#onepage > 1 and onepage[#onepage].discardable) do onepage[#onepage] = nil end
while #onepage > 1 and onepage[#onepage].discardable do
onepage[#onepage] = nil
end
return onepage, 1000
end
bestBreak = i
Expand All @@ -94,7 +132,8 @@ local gridPagebuilder = pl.class({
end
})

local oldPageBuilder
local oldPageBuilder, oldLeadingFor, oldPushVglue, oldPushExplicitVglue

SILE.registerCommand("grid:debug", function (_, _)
debugGrid()
SILE.typesetter:registerNewFrameHook(debugGrid)
Expand All @@ -104,35 +143,24 @@ SILE.registerCommand("grid", function (options, _)
SILE.typesetter.state.grid = true
SU.required(options, "spacing", "grid package")
gridSpacing = SILE.parseComplexFrameDimension(options.spacing)
-- SILE.typesetter:leaveHmode()

oldPageBuilder = SILE.pagebuilder
SILE.pagebuilder = gridPagebuilder()

oldLeadingFor = SILE.typesetter.leadingFor
SILE.typesetter.leadingFor = leadingFor
oldPushVglue = SILE.typesetter.pushVglue
SILE.typesetter.pushVglue = pushVglue
oldPushExplicitVglue = SILE.typesetter.pushExplicitVglue
SILE.typesetter.pushExplicitVglue = pushExplicitVglue
if SILE.typesetter.frame then
SILE.typesetter.frame.state.totals.gridCursor = 0
SILE.typesetter.state.previousVbox = SILE.defaultTypesetter.pushVbox(SILE.typesetter, {})
startGridInFrame(SILE.typesetter)
end
SILE.typesetter:registerNewFrameHook(function (self)
self.frame.state.totals.gridCursor = 0
while self.state.outputQueue[1] and self.state.outputQueue[1].discardable do
table.remove(self.state.outputQueue, 1)
end
if self.state.outputQueue[1] then
table.insert(self.state.outputQueue, 1, SILE.nodefactory.newVbox({}))
table.insert(self.state.outputQueue, 2, leadingFor(self, self.state.outputQueue[2], self.state.outputQueue[1]))
end
end)

SILE.typesetter:registerNewFrameHook(startGridInFrame)
end, "Begins typesetting on a grid spaced at <spacing> intervals.")

SILE.registerCommand("no-grid", function (_, _)
SILE.typesetter.state.grid = false
SILE.typesetter.leadingFor = SILE.defaultTypesetter.leadingFor
SILE.typesetter.pushVglue = SILE.defaultTypesetter.pushVglue
SILE.typesetter.setVerticalGlue = SILE.defaultTypesetter.setVerticalGlue
SILE.typesetter.leadingFor = oldLeadingFor
SILE.typesetter.pushVglue = oldPushVglue
SILE.typesetter.pushExplicitVglue = oldPushExplicitVglue
SILE.pagebuilder = oldPageBuilder
-- SILE.typesetter.state = t.state
end, "Stops grid typesetting.")
11 changes: 0 additions & 11 deletions tests/grid.expected
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Set paper size 419.5275636 595.275597
Begin page
Draw line 34.8208 69.0520 325.9729 0.1000
Draw line 34.8208 89.0520 325.9729 0.1000
Draw line 34.8208 109.0520 325.9729 0.1000
Draw line 34.8208 129.0520 325.9729 0.1000
Expand All @@ -22,9 +21,6 @@ Draw line 34.8208 429.0520 325.9729 0.1000
Draw line 34.8208 449.0520 325.9729 0.1000
Draw line 34.8208 469.0520 325.9729 0.1000
Draw line 34.8208 489.0520 325.9729 0.1000
Draw line 34.8208 509.0520 325.9729 0.1000
Draw line 34.8208 529.0520 325.9729 0.1000
Draw line 34.8208 549.0520 325.9729 0.1000
Mx 54.8208
My 89.0520
Set font Gentium Plus;10;400;;normal;;LTR
Expand Down Expand Up @@ -423,9 +419,6 @@ Draw line 58.7339 429.0520 325.9729 0.1000
Draw line 58.7339 449.0520 325.9729 0.1000
Draw line 58.7339 469.0520 325.9729 0.1000
Draw line 58.7339 489.0520 325.9729 0.1000
Draw line 58.7339 509.0520 325.9729 0.1000
Draw line 58.7339 529.0520 325.9729 0.1000
Draw line 58.7339 549.0520 325.9729 0.1000
Mx 58.7339
My 89.0520
Set font Gentium Plus;8;400;;normal;;LTR
Expand Down Expand Up @@ -621,7 +614,6 @@ My 519.7531
Set font Gentium Plus;10;400;;normal;;LTR
T 21 (2)
New page
Draw line 34.8208 69.0520 325.9729 0.1000
Draw line 34.8208 89.0520 325.9729 0.1000
Draw line 34.8208 109.0520 325.9729 0.1000
Draw line 34.8208 129.0520 325.9729 0.1000
Expand All @@ -643,9 +635,6 @@ Draw line 34.8208 429.0520 325.9729 0.1000
Draw line 34.8208 449.0520 325.9729 0.1000
Draw line 34.8208 469.0520 325.9729 0.1000
Draw line 34.8208 489.0520 325.9729 0.1000
Draw line 34.8208 509.0520 325.9729 0.1000
Draw line 34.8208 529.0520 325.9729 0.1000
Draw line 34.8208 549.0520 325.9729 0.1000
Mx 195.4611
T 22 (3)
End page
Expand Down

0 comments on commit c9a862a

Please sign in to comment.