From d47088e6cf3a95ddb33808b373b2320013ae6741 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 16:50:36 +0300 Subject: [PATCH 1/8] refactor(backends): Move current font tracking from module to class This is work towards being able to instantiate multiple outputters at the same time. Tracking this in a module-local variable means only one could be run without interference. --- core/libtexpdf-output.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index 35003732d..39ecb340a 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -5,7 +5,6 @@ if (not SILE.outputters) then SILE.outputters = {} end local cursorX = 0 local cursorY = 0 -local font = 0 local started = false local lastkey @@ -120,7 +119,7 @@ SILE.outputters.libtexpdf = { for i = 1, #(value.items) do local glyph = value.items[i].gid local buf = string.char(math.floor(glyph % 2^32 / 2^8)) .. string.char(glyph % 0x100) - pdf.setstring(cursorX + (value.items[i].x_offset or 0), cursorY + (value.items[i].y_offset or 0), buf, string.len(buf), font, value.items[i].glyphAdvance) + pdf.setstring(cursorX + (value.items[i].x_offset or 0), cursorY + (value.items[i].y_offset or 0), buf, string.len(buf), self._font, value.items[i].glyphAdvance) cursorX = cursorX + value.items[i].width end return @@ -132,15 +131,17 @@ SILE.outputters.libtexpdf = { buf[#buf+1] = string.char(glyph % 0x100) end buf = table.concat(buf, "") - pdf.setstring(cursorX, cursorY, buf, string.len(buf), font, width) + pdf.setstring(cursorX, cursorY, buf, string.len(buf), self._font, width) end, + _font = nil, + setFont = function (self, options) _deprecationCheck(self) ensureInit() if SILE.font._key(options) == lastkey then return end lastkey = SILE.font._key(options) - font = SILE.font.cache(options, SILE.shaper.getFace) + local font = SILE.font.cache(options, SILE.shaper.getFace) if options.direction == "TTB" then font.layout_dir = 1 end @@ -149,9 +150,9 @@ SILE.outputters.libtexpdf = { else pdf.setdirmode(0) end - local pdffont = pdf.loadfont(font) - if pdffont < 0 then SU.error("Font loading error for "..options) end - font = pdffont + self._font = pdf.loadfont(font) + if self._font < 0 then SU.error("Font loading error for "..options) end + return self._font end, drawImage = function (self, src, x, y, width, height) @@ -228,12 +229,12 @@ SILE.outputters.libtexpdf = { buf[#buf+1] = string.char(glyph % 0x100) end buf = table.concat(buf, "") - local oldfont = font + local oldfont = self._font self:setFont(gentium) - pdf.setstring(frame:left():tonumber() - _dl/2, (SILE.documentState.paperSize[2] - frame:top()):tonumber() + _dl/2, buf, string.len(buf), font, 0) + pdf.setstring(frame:left():tonumber() - _dl/2, (SILE.documentState.paperSize[2] - frame:top()):tonumber() + _dl/2, buf, string.len(buf), self._font, 0) if oldfont then pdf.loadfont(oldfont) - font = oldfont + self._font = oldfont end self:popColor() end, From 1ffe51acd1870c0860df9a8b6ced6e1bd878d262 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 16:58:26 +0300 Subject: [PATCH 2/8] refactor(backends): Use function for repeated crazy math --- core/libtexpdf-output.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index 39ecb340a..14ddf3ca7 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -22,6 +22,10 @@ local _deprecationCheck = function (caller) end end +local glyph2string = function (glyph) + return string.char(math.floor(glyph % 2^32 / 2^8)) .. string.char(glyph % 0x100) +end + local _dl = 0.5 SILE.outputters.libtexpdf = { @@ -117,8 +121,7 @@ SILE.outputters.libtexpdf = { -- is actually the shaped x_advance). if value.complex then for i = 1, #(value.items) do - local glyph = value.items[i].gid - local buf = string.char(math.floor(glyph % 2^32 / 2^8)) .. string.char(glyph % 0x100) + local buf = glyph2string(value.items[i].gid) pdf.setstring(cursorX + (value.items[i].x_offset or 0), cursorY + (value.items[i].y_offset or 0), buf, string.len(buf), self._font, value.items[i].glyphAdvance) cursorX = cursorX + value.items[i].width end @@ -126,9 +129,7 @@ SILE.outputters.libtexpdf = { end local buf = {} for i = 1, #(value.glyphString) do - local glyph = value.glyphString[i] - buf[#buf+1] = string.char(math.floor(glyph % 2^32 / 2^8)) - buf[#buf+1] = string.char(glyph % 0x100) + buf[i] = glyph2string(value.glyphString[i]) end buf = table.concat(buf, "") pdf.setstring(cursorX, cursorY, buf, string.len(buf), self._font, width) @@ -224,9 +225,7 @@ SILE.outputters.libtexpdf = { stuff = stuff[1].nodes[1].value.glyphString -- Horrible hack local buf = {} for i = 1, #stuff do - local glyph = stuff[i] - buf[#buf+1] = string.char(math.floor(glyph % 2^32 / 2^8)) - buf[#buf+1] = string.char(glyph % 0x100) + buf[i] = glyph2string(stuff[i]) end buf = table.concat(buf, "") local oldfont = self._font From 02cce408c209fd59fbd531d2e8bdd4625964c4ee Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 17:11:28 +0300 Subject: [PATCH 3/8] perf(backends): Reuse variables instead of recalculating values --- core/libtexpdf-output.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index 14ddf3ca7..3442ad4b6 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -120,19 +120,19 @@ SILE.outputters.libtexpdf = { -- position (cursorX + width - remember that the box's "width" -- is actually the shaped x_advance). if value.complex then - for i = 1, #(value.items) do + for i = 1, #value.items do local buf = glyph2string(value.items[i].gid) pdf.setstring(cursorX + (value.items[i].x_offset or 0), cursorY + (value.items[i].y_offset or 0), buf, string.len(buf), self._font, value.items[i].glyphAdvance) cursorX = cursorX + value.items[i].width end - return - end - local buf = {} - for i = 1, #(value.glyphString) do - buf[i] = glyph2string(value.glyphString[i]) + else + local buf = {} + for i = 1, #value.glyphString do + buf[i] = glyph2string(value.glyphString[i]) + end + buf = table.concat(buf, "") + pdf.setstring(cursorX, cursorY, buf, string.len(buf), self._font, width) end - buf = table.concat(buf, "") - pdf.setstring(cursorX, cursorY, buf, string.len(buf), self._font, width) end, _font = nil, @@ -140,8 +140,8 @@ SILE.outputters.libtexpdf = { setFont = function (self, options) _deprecationCheck(self) ensureInit() - if SILE.font._key(options) == lastkey then return end - lastkey = SILE.font._key(options) + local key = SILE.font._key(options) + if key == lastkey then return end local font = SILE.font.cache(options, SILE.shaper.getFace) if options.direction == "TTB" then font.layout_dir = 1 @@ -153,6 +153,7 @@ SILE.outputters.libtexpdf = { end self._font = pdf.loadfont(font) if self._font < 0 then SU.error("Font loading error for "..options) end + lastkey = key return self._font end, From 7caa9c82bbf0bd021e316893ffb2b2693ceeac55 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 17:22:22 +0300 Subject: [PATCH 4/8] feat(backends): Modify setCursor() to handle relative movements --- core/cairo-output.lua | 7 +++++-- core/debug-output.lua | 10 +++++++--- core/libtexpdf-output.lua | 7 ++++--- core/podofo-output.lua | 7 ++++--- core/text-output.lua | 18 ++++++++++-------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/core/cairo-output.lua b/core/cairo-output.lua index c54c570f1..7401373ee 100644 --- a/core/cairo-output.lua +++ b/core/cairo-output.lua @@ -59,9 +59,12 @@ SILE.outputters.cairo = { return self:setCursor(x, y) end, - setCursor = function (self, x, y) + setCursor = function (self, x, y, relative) _deprecationCheck(self) - move(cr, x, y) + local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 } + cursorX = offset.x + x + cursorY = offset.y - y + move(cr, cursorX, cursorY) end, setColor = function (self, color) diff --git a/core/debug-output.lua b/core/debug-output.lua index 1e4b6275b..39b7f4775 100644 --- a/core/debug-output.lua +++ b/core/debug-output.lua @@ -60,12 +60,16 @@ SILE.outputters.debug = { return self:setCursor(x, y) end, - setCursor = function (self, x, y) + setCursor = function (self, x, y, relative) _deprecationCheck(self) x = SU.cast("number", x) y = SU.cast("number", y) - if string.format("%.4f", x) ~= string.format("%.4f", cursorX) then writeline("Mx ", string.format("%.4f", x)); cursorX = x end - if string.format("%.4f", y) ~= string.format("%.4f", cursorY) then writeline("My ", string.format("%.4f", y)); cursorY = y end + local oldx, oldy = self:getCursor() + local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 } + cursorX = offset.x + x + cursorY = offset.y - y + if string.format("%.4f", oldx) ~= string.format("%.4f", cursorX) then writeline("Mx ", string.format("%.4f", x)) end + if string.format("%.4f", oldy) ~= string.format("%.4f", cursorY) then writeline("My ", string.format("%.4f", y)) end end, setColor = function (self, color) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index 3442ad4b6..4eb76fe6f 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -70,12 +70,13 @@ SILE.outputters.libtexpdf = { return self:setCursor(x, y) end, - setCursor = function (self, x, y) + setCursor = function (self, x, y, relative) _deprecationCheck(self) x = SU.cast("number", x) y = SU.cast("number", y) - cursorX = x - cursorY = SILE.documentState.paperSize[2] - y + local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 } + cursorX = offset.x + x + cursorY = offset.y + (relative and 0 or SILE.documentState.paperSize[2]) - y end, setColor = function (self, color) diff --git a/core/podofo-output.lua b/core/podofo-output.lua index be1764b26..51b178d6e 100644 --- a/core/podofo-output.lua +++ b/core/podofo-output.lua @@ -65,10 +65,11 @@ SILE.outputters.podofo = { return self:setCursor(x, y) end, - setCursor = function (self, x, y) + setCursor = function (self, x, y, relative) _deprecationCheck(self) - cursorX = x - cursorY = SILE.documentState.paperSize[2] - y + local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 } + cursorX = offset.x + x + cursorY = offset.y + SILE.documentState.paperSize[2] - y end, setColor = function (self, color) diff --git a/core/text-output.lua b/core/text-output.lua index 6255fd9d7..d95902a7e 100644 --- a/core/text-output.lua +++ b/core/text-output.lua @@ -53,29 +53,31 @@ cursor = function (self) return self:setCursor(x, y) end, - setCursor = function (self, x, y) + setCursor = function (self, x, y, relative) _deprecationCheck(self) local bs = SILE.measurement("0.8bs"):tonumber() local spc = SILE.measurement("0.8spc"):tonumber() + local offset = relative and { x = cursorX, y = cursorY } or { x = 0, y = 0 } + local newx, newy = offset.x + x, offset.y - y if started then - if x < cursorX then + if newx < cursorX then outfile:write("\n") - elseif y > cursorY then - if y - cursorY > bs then + elseif newy > cursorY then + if newy - cursorY > bs then outfile:write("\n") else outfile:write("‫") end - elseif x > cursorX then - if x - cursorX > spc then + elseif newx > cursorX then + if newx - cursorX > spc then outfile:write(" ") else outfile:write("‫") end end end - cursorY = y - cursorX = x + cursorY = newy + cursorX = newx end, setColor = function(self) From 095e4ac5a35a3d94f6b3c3a23bf79ee079dbd5ed Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 17:26:55 +0300 Subject: [PATCH 5/8] refactor(backends): Re-use methods for easier extension and debugging --- core/libtexpdf-output.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index 4eb76fe6f..fbe21af92 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -107,6 +107,11 @@ SILE.outputters.libtexpdf = { return self:drawHbox(value, width) end, + _drawString = function(self, str, width) + local x, y = self:getCursor() + pdf.setstring(x, y, str, string.len(str), self._font, width) + end, + drawHbox = function (self, value, width) _deprecationCheck(self) width = SU.cast("number", width) @@ -123,8 +128,9 @@ SILE.outputters.libtexpdf = { if value.complex then for i = 1, #value.items do local buf = glyph2string(value.items[i].gid) - pdf.setstring(cursorX + (value.items[i].x_offset or 0), cursorY + (value.items[i].y_offset or 0), buf, string.len(buf), self._font, value.items[i].glyphAdvance) - cursorX = cursorX + value.items[i].width + self:setCursor(value.items[i].x_offset or 0, value.items[i].y_offset or 0, true) + self:_drawString(buf, value.items[i].glyphAdvance) + self:setCursor(value.items[i].width, 0, true) end else local buf = {} @@ -132,7 +138,7 @@ SILE.outputters.libtexpdf = { buf[i] = glyph2string(value.glyphString[i]) end buf = table.concat(buf, "") - pdf.setstring(cursorX, cursorY, buf, string.len(buf), self._font, width) + self:_drawString(buf, width) end end, @@ -232,7 +238,8 @@ SILE.outputters.libtexpdf = { buf = table.concat(buf, "") local oldfont = self._font self:setFont(gentium) - pdf.setstring(frame:left():tonumber() - _dl/2, (SILE.documentState.paperSize[2] - frame:top()):tonumber() + _dl/2, buf, string.len(buf), self._font, 0) + self:setCursor(frame:left():tonumber() - _dl/2, frame:top():tonumber() + _dl/2) + self:_drawString(buf, 0) if oldfont then pdf.loadfont(oldfont) self._font = oldfont From b53896e1fea42f639074f0bba40504ba85eda19c Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 20 Aug 2020 17:30:11 +0300 Subject: [PATCH 6/8] fix(backends): Properly switch between normal and debug fonts --- core/libtexpdf-output.lua | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/core/libtexpdf-output.lua b/core/libtexpdf-output.lua index fbe21af92..32cb98797 100644 --- a/core/libtexpdf-output.lua +++ b/core/libtexpdf-output.lua @@ -8,6 +8,8 @@ local cursorY = 0 local started = false local lastkey +local debugfont = SILE.font.loadDefaults({ family = "Gentium Plus", language = "en", size = 10 }) + local function ensureInit () if not started then pdf.init(SILE.outputFilename, SILE.documentState.paperSize[1], SILE.documentState.paperSize[2], SILE.full_version) @@ -142,6 +144,18 @@ SILE.outputters.libtexpdf = { end end, + _debugfont = nil, + + _withDebugFont = function (self, callback) + if not self._debugfont then + self._debugfont = self:setFont(debugfont) + end + local oldfont = self._font + self._font = self._debugfont + callback() + self._font = oldfont + end, + _font = nil, setFont = function (self, options) @@ -228,22 +242,17 @@ SILE.outputters.libtexpdf = { self:drawRule(frame:right()-_dl/2, frame:top()-_dl/2, _dl, frame:height()+_dl) self:drawRule(frame:left()-_dl/2, frame:bottom()-_dl/2, frame:width()+_dl, _dl) -- self:drawRule(frame:left() + frame:width()/2 - 5, (frame:top() + frame:bottom())/2+5, 10, 10) - local gentium = SILE.font.loadDefaults({family="Gentium Plus", language="en"}) - local stuff = SILE.shaper:createNnodes(frame.id, gentium) + local stuff = SILE.shaper:createNnodes(frame.id, debugfont) stuff = stuff[1].nodes[1].value.glyphString -- Horrible hack local buf = {} for i = 1, #stuff do buf[i] = glyph2string(stuff[i]) end buf = table.concat(buf, "") - local oldfont = self._font - self:setFont(gentium) - self:setCursor(frame:left():tonumber() - _dl/2, frame:top():tonumber() + _dl/2) - self:_drawString(buf, 0) - if oldfont then - pdf.loadfont(oldfont) - self._font = oldfont - end + self:_withDebugFont(function () + self:setCursor(frame:left():tonumber() - _dl/2, frame:top():tonumber() + _dl/2) + self:_drawString(buf, 0) + end) self:popColor() end, From 774b0447d8bd0f954444f332dcbfac9018b8321d Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Tue, 25 Aug 2020 14:05:25 +0300 Subject: [PATCH 7/8] test(backends): Check output of complex hboxes in libtexpdf --- tests/bug-1044.expected | 10 ++++++++++ tests/bug-1044.sil | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/bug-1044.expected create mode 100644 tests/bug-1044.sil diff --git a/tests/bug-1044.expected b/tests/bug-1044.expected new file mode 100644 index 000000000..93f3b363e --- /dev/null +++ b/tests/bug-1044.expected @@ -0,0 +1,10 @@ +Set paper size 297.6377985 419.5275636 +Begin page +Mx 14.8819 +My 27.9564 +Set font Libertinus Serif;10;400;;normal;;LTR +T 53 66 (Ta) +Mx 27.9627 +T 80 71 (of) +End page +Finish diff --git a/tests/bug-1044.sil b/tests/bug-1044.sil new file mode 100644 index 000000000..26d156816 --- /dev/null +++ b/tests/bug-1044.sil @@ -0,0 +1,8 @@ +\begin[papersize=a6]{document} +\nofolios +\neverindent +\font[family=Libertinus Serif]{Ta of} +% If complex shaping is skipped and glyphAdvance ignored when outputting +% a series of hboxes, the "Ta" kerning above will cause "of" to be positioned +% too far forward. +\end{document} From 88ac88805c138397d7cf94f8b7864d65956a7e13 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Tue, 25 Aug 2020 14:18:49 +0300 Subject: [PATCH 8/8] fix(tooling): Expand variables so fonts are known dependencies of tests --- Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index f563ac877..0e1c5278c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -184,9 +184,9 @@ define runsile = endef _FORCED = $(and $(SILE_COVERAGE)$(CLEAN),force) -_TEST_DEPS = $(and $(filter tests/%,$@),$(addprefix .fonts/,$(TESTFONTFILES))) -_DOCS_DEPS = $(and $(filter documentation/%,$@),$(addprefix .fonts/,$(DOCSFONTFILES))) -_EXAM_DEPS = $(and $(filter examples/%,$@),$(addprefix .fonts/,$(EXAMFONTFILES))) +_TEST_DEPS = $(and $$(filter tests/%,$@),$(addprefix .fonts/,$(TESTFONTFILES))) +_DOCS_DEPS = $(and $$(filter documentation/%,$@),$(addprefix .fonts/,$(DOCSFONTFILES))) +_EXAM_DEPS = $(and $$(filter examples/%,$@),$(addprefix .fonts/,$(EXAMFONTFILES))) # TODO: remove _BUILT_SUBDIRS hack and replace it with something sensible when # these subdirs don't do crazy things like copying files outside of their own trees!