summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-phb-imp-binary.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-phb-imp-binary.lua')
-rw-r--r--tex/context/base/mkiv/font-phb-imp-binary.lua119
1 files changed, 119 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-phb-imp-binary.lua b/tex/context/base/mkiv/font-phb-imp-binary.lua
new file mode 100644
index 000000000..39ac6ec04
--- /dev/null
+++ b/tex/context/base/mkiv/font-phb-imp-binary.lua
@@ -0,0 +1,119 @@
+if not modules then modules = { } end modules ['font-phb-imp-binary'] = {
+ version = 1.000, -- 2016.10.10,
+ comment = "companion to font-txt.mkiv",
+ author = "Hans Hagen",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- The hb library comes in versions and the one I tested in 2016 was part of the inkscape
+-- suite. In principle one can have incompatibilities due to updates but that is the nature
+-- of a library. When a library ie expected one has better use the system version, if only
+-- to make sure that different programs behave the same.
+--
+-- The main reason for testing this approach was that when Idris was working on his fonts,
+-- we wanted to know how different shapers deal with it and the hb command line program
+-- could provide uniscribe output. For the context shaper uniscribe is the reference, also
+-- because Idris started out with Volt a decade ago.
+--
+-- This file uses the indirect approach by calling the executable. This file uses context
+-- features and is not generic.
+
+local next, tonumber, pcall = next, tonumber, pcall
+
+local concat = table.concat
+local reverse = table.reverse
+local formatters = string.formatters
+local removefile = os.remove
+local resultof = os.resultof
+local savedata = io.savedata
+
+local report = utilities.hb.report or print
+local packtoutf8 = utilities.hb.helpers.packtoutf8
+
+if not context then
+ report("the binary runner is only supported in context")
+ return
+end
+
+-- output : [index=cluster@x_offset,y_offset+x_advance,y_advance|...]
+-- result : { index, cluster, x_offset, y_offset, x_advance, y_advance }
+
+local P, Ct, Cc = lpeg.P, lpeg.Ct, lpeg.Cc
+local lpegmatch = lpeg.match
+
+local zero = Cc(0)
+local number = lpeg.patterns.integer / tonumber + zero
+local index = lpeg.patterns.cardinal / tonumber
+local cluster = index
+local offset = (P("@") * number * (P(",") * number + zero)) + zero * zero
+local advance = (P("+") * number * (P(",") * number + zero)) + zero * zero
+local glyph = Ct(index * P("=") * cluster * offset * advance)
+local pattern = Ct(P("[") * (glyph * P("|")^-1)^0 * P("]"))
+
+local shapers = {
+ native = "ot,uniscribe,fallback",
+ uniscribe = "uniscribe,ot,fallback",
+ fallback = "fallback"
+}
+
+local runner = sandbox.registerrunner {
+ method = "resultof",
+ name = "harfbuzz",
+ -- program = {
+ -- windows = "hb-shape.exe",
+ -- unix = "hb-shape"
+ -- },
+ program = "hb-shape",
+ checkers = {
+ shaper = "string",
+ features = "string",
+ script = "string",
+ language = "string",
+ direction = "string",
+ textfile = "writable",
+ fontfile = "readable",
+ },
+ template = string.longtostring [[
+ --shaper=%shaper%
+ --output-format=text
+ --no-glyph-names
+ --features="%features%"
+ --script=%script%
+ --language=%language%
+ --direction=%direction%
+ --text-file=%textfile%
+ --font-file=%fontfile%
+ ]],
+}
+
+local tempfile = "font-phb.tmp"
+local reported = false
+
+function utilities.hb.methods.binary(font,data,rlmode,text,leading,trailing)
+ if runner then
+ savedata(tempfile,packtoutf8(text,leading,trailing))
+ local result = runner {
+ shaper = shapers[data.shaper] or shapers.native,
+ features = data.features,
+ script = data.script or "dflt",
+ language = data.language or "dflt",
+ direction = rlmode < 0 and "rtl" or "ltr",
+ textfile = tempfile,
+ fontfile = data.filename,
+ }
+ removefile(tempfile)
+ if result then
+ -- return jsontolua(result)
+ result = lpegmatch(pattern,result) -- { index cluster xo yo xa ya }
+ if rlmode < 0 then
+ return reverse(result) -- we can avoid this
+ else
+ return result
+ end
+ end
+ elseif reported then
+ report("no runner available")
+ reported = true
+ end
+end