Skip to content

Commit

Permalink
Optimum fit line breaking and hyphenation
Browse files Browse the repository at this point in the history
This updates to the newest version of boxes and glue and has some
documentation.

Now implemented the optimum line breaking algorithm from
Donald E. Knuth and Michael F. Plass and the hyphenation algorithm
by Frank Liang.
  • Loading branch information
pgundlach committed Nov 30, 2021
1 parent 14499af commit 44c78a6
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 66 deletions.
8 changes: 6 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,9 @@ task :build do
sh "go build -ldflags \"-X main.version=#{@ets_version}\" -o bin/ets github.com/speedata/ets/ets/ets"
end



desc "Create documentation"
task :doc do
Dir.chdir("doc") do
sh "asciidoctor ets.adoc -a revnumber=#{@ets_version}"
end
end
77 changes: 48 additions & 29 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ETS Experimental typesetting system
# ets Experimental typesetting system

This software repository contains a Lua frontend for the typesetting library [“Boxes and Glue”](https://github.com/speedata/boxesandglue) which is an algorithmic typesetting machine in the spirits of TeX.

Expand Down Expand Up @@ -36,62 +36,64 @@ Contact: Patrick Gundlach <[email protected]>
## Sample code

```lua
-- The document d is the central point for all
function CreateFontVlist(d)
local face, msg = d.loadFace("fonts/CrimsonPro-Regular.ttf")
if not face then
print(msg)
os.exit(-1)
end
local fnt = d.createFont(face,document.sp("12pt"))
-- This is still a very vey early preview and will probably not work when
-- you experiment with the code.
--
-- Two functions for fonts and for images just to show how to
-- create objects and output them.

local lang_en, msg = d.loadpattern("hyphenationpatterns/hyph-en-us.pat.txt")
if not lang_en then
print(msg)
os.exit(-1)
end
document.info("Reading myfile.lua")

lang_en.name = "en"
local ok, face, msg, fnt, lang_en, imgfile, image

function CreateFontVlist(d)
local lang = node.new("lang")
lang.lang = lang_en

local tbl = fnt.shape("the quick brown fox jumps over the lazy dog")
local tbl = fnt.shape([[In olden times when wishing still helped one, there lived a king whose daughters
were all beautiful; and the youngest was so beautiful that the sun itself, which
has seen so much, was astonished whenever it shone in her face.
Close by the king's castle lay a great dark forest, and under an old lime-tree in the forest
was a well, and when the day was very warm, the king's child went out into the
forest and sat down by the side of the cool fountain; and when she was bored she
took a golden ball, and threw it up on high and caught it; and this ball was her
favorite plaything.]])


local head, cur = lang, lang
for _, glyph in ipairs(tbl) do
if glyph.glyph == 32 then
local glu = node.new("glue")
glu.width = fnt.space
glu.stretch = fnt.stretch
glu.shrink = fnt.shrink
head = node.insertafter(head,cur,glu)
cur = glu
else
local g = node.new("glyph")
g.width = glyph.advance
g.codepoint = glyph.codepoint
g.components = glyph.components
g.font = glyph.font
g.hyphenate = glyph.hyphenate
head = node.insertafter(head,cur,g)
cur = g
end
end

local hlist = node.hpack(head)
d.hyphenate(head)
node.append_lineend(cur)

local param = {
hsize = document.sp("200pt"),
hsize = document.sp("134pt"),
lineheight = document.sp("12pt"),
}

local vl = node.simplelinebreak(hlist,param)
local vl = node.linebreak(head,param)
return vl
end

local function CreateImageVlist(d)
local imgfile = d.loadimagefile("img/ocean.pdf")
local image = d.createimage(imgfile)


image = d.createimage(imgfile)
local imagenode = node.new("image")
imagenode.img = image
imagenode.width = document.sp("4cm")
Expand All @@ -101,21 +103,38 @@ local function CreateImageVlist(d)
return vlist
end


-- The document d is the most important item here.
local d = document.new("out.pdf")

face, msg = d.loadFace("fonts/CrimsonPro-Regular.ttf")
if not face then
print(msg)
os.exit(-1)
end

fnt = d.createFont(face,document.sp("12pt"))

lang_en, msg = d.loadpattern("hyphenationpatterns/hyph-en-us.pat.txt")
if not lang_en then
print(msg)
os.exit(-1)
end

lang_en.name = "en"
imgfile = d.loadimagefile("img/ocean.pdf")

local fontVL = CreateFontVlist(d)
local imageVL = CreateImageVlist(d)

d.outputat(document.sp("4cm"),document.sp("27cm"),fontVL)
d.outputat(document.sp("4cm"),document.sp("26cm"),imageVL)
d.outputat(document.sp("12cm"),document.sp("27cm"),imageVL)
d.currentpage().shipout()


local ok, msg = d.finish()
ok, msg = d.finish()
if not ok then
print(msg)
os.exit(-1)
end

document.info("Reading myfile.lua...done")
```

49 changes: 43 additions & 6 deletions core/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func registerDocumentType(l *lua.LState) {
l.SetField(mt, "new", l.NewFunction(newDocument))
l.SetField(mt, "sp", l.NewFunction(documentSP))
l.SetField(mt, "__index", l.NewFunction(indexDoc))
l.SetField(mt, "__newindex", l.NewFunction(newindexDoc))
}

// Constructor
Expand Down Expand Up @@ -87,6 +88,9 @@ func indexDoc(l *lua.LState) int {
case "finish":
l.Push(l.NewFunction(documentFinish(doc)))
return 1
case "hyphenate":
l.Push(l.NewFunction(documentHyphenate(doc.d)))
return 1
case "loadimagefile":
l.Push(l.NewFunction(documentLoadImageFile(doc.d)))
return 1
Expand All @@ -99,12 +103,27 @@ func indexDoc(l *lua.LState) int {
case "outputat":
l.Push(l.NewFunction(documentOutputAt(doc.d)))
return 1
case "defaultlanguage":
ud := newUserDataFromType(l, doc.d.DefaultLanguage)
l.Push(ud)
return 1
default:
fmt.Println("default in indexDoc", arg)
}
return 0
}

func newindexDoc(l *lua.LState) int {
doc := checkDocument(l, 1)
switch arg := l.CheckString(2); arg {
case "defaultlanguage":
ud := checkPatternFile(l, 3)
doc.d.SetDefaultLanguage(ud)
return 0
}
return 0
}

func checkDocument(l *lua.LState, argpos int) *doc {
ud := l.CheckUserData(argpos)
if v, ok := ud.Value.(*doc); ok {
Expand All @@ -128,19 +147,22 @@ func documentFinish(d *doc) lua.LGFunction {
}
}

func documentHyphenate(doc *document.Document) lua.LGFunction {
return func(l *lua.LState) int {
n := checkNode(l, 1)
doc.Hyphenate(n)
return 0
}
}

func documentLoadPatternFile(doc *document.Document) lua.LGFunction {
return func(l *lua.LState) int {
fn := l.CheckString(1)
pat, err := doc.LoadPatternFile(fn)
if err != nil {
return lerr(l, err.Error())
}
mt := l.NewTypeMetatable(luaLangTypeName)
l.SetField(mt, "__index", l.NewFunction(indexLang))
l.SetField(mt, "__newindex", l.NewFunction(newIndexLang))
ud := l.NewUserData()
ud.Value = pat
l.SetMetatable(ud, mt)
ud := newUserDataFromType(l, pat)
l.Push(ud)
return 1
}
Expand Down Expand Up @@ -183,3 +205,18 @@ func newIndexLang(l *lua.LState) int {
func indexLang(l *lua.LState) int {
return 0
}

func newUserDataFromType(l *lua.LState, n interface{}) *lua.LUserData {
var mt *lua.LTable
switch t := n.(type) {
case *lang.Lang:
mt = l.NewTypeMetatable(luaLangTypeName)
l.SetField(mt, "__index", l.NewFunction(indexLang))
l.SetField(mt, "__newindex", l.NewFunction(newIndexLang))
ud := l.NewUserData()
ud.Value = t
l.SetMetatable(ud, mt)
return ud
}
return nil
}
11 changes: 6 additions & 5 deletions core/font.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ func documentLoadFace(doc *document.Document) lua.LGFunction {
}
}

func getFontFromFace(l *lua.LState) int {
stackDump(l)
return 1
}

func checkFace(l *lua.LState, argpos int) *pdf.Face {
ud := l.CheckUserData(argpos)
if v, ok := ud.Value.(*pdf.Face); ok {
Expand Down Expand Up @@ -108,6 +103,12 @@ func indexFont(l *lua.LState) int {
case "space":
l.Push(lua.LNumber(f.Space))
return 1
case "stretch":
l.Push(lua.LNumber(f.SpaceStretch))
return 1
case "shrink":
l.Push(lua.LNumber(f.SpaceShrink))
return 1
case "shape":
l.Push(l.NewFunction(fontShape(f, fontObj)))
return 1
Expand Down
Loading

0 comments on commit 44c78a6

Please sign in to comment.