summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/anch-pos.lua72
-rw-r--r--tex/context/base/back-exp.lua92
-rw-r--r--tex/context/base/cont-new.mkiv2
-rw-r--r--tex/context/base/context-version.pdfbin4112 -> 4091 bytes
-rw-r--r--tex/context/base/context.mkiv2
-rw-r--r--tex/context/base/font-chk.lua28
-rw-r--r--tex/context/base/font-col.lua21
-rw-r--r--tex/context/base/font-ctx.lua38
-rw-r--r--tex/context/base/font-gds.lua33
-rw-r--r--tex/context/base/font-nod.lua437
-rw-r--r--tex/context/base/font-odv.lua1010
-rw-r--r--tex/context/base/font-otn.lua642
-rw-r--r--tex/context/base/font-otx.lua130
-rw-r--r--tex/context/base/font-sol.lua174
-rw-r--r--tex/context/base/lang-rep.lua189
-rw-r--r--tex/context/base/lang-wrd.lua28
-rw-r--r--tex/context/base/lpdf-nod.lua81
-rw-r--r--tex/context/base/lpdf-tag.lua65
-rw-r--r--tex/context/base/math-dir.lua35
-rw-r--r--tex/context/base/math-noa.lua411
-rw-r--r--tex/context/base/math-tag.lua129
-rw-r--r--tex/context/base/node-acc.lua114
-rw-r--r--tex/context/base/node-aux.lua354
-rw-r--r--tex/context/base/node-bck.lua109
-rw-r--r--tex/context/base/node-fin.lua313
-rw-r--r--tex/context/base/node-fnt.lua41
-rw-r--r--tex/context/base/node-inj.lua200
-rw-r--r--tex/context/base/node-ltp.lua3192
-rw-r--r--tex/context/base/node-mig.lua93
-rw-r--r--tex/context/base/node-pro.lua113
-rw-r--r--tex/context/base/node-ref.lua220
-rw-r--r--tex/context/base/node-res.lua531
-rw-r--r--tex/context/base/node-rul.lua125
-rw-r--r--tex/context/base/node-tra.lua341
-rw-r--r--tex/context/base/node-tst.lua69
-rw-r--r--tex/context/base/node-typ.lua57
-rw-r--r--tex/context/base/pack-rul.lua71
-rw-r--r--tex/context/base/page-lin.lua112
-rw-r--r--tex/context/base/page-mix.lua220
-rw-r--r--tex/context/base/scrp-cjk.lua131
-rw-r--r--tex/context/base/scrp-eth.lua22
-rw-r--r--tex/context/base/scrp-ini.lua85
-rw-r--r--tex/context/base/spac-ali.lua44
-rw-r--r--tex/context/base/spac-chr.lua95
-rw-r--r--tex/context/base/spac-ver.lua407
-rw-r--r--tex/context/base/status-files.pdfbin24576 -> 24546 bytes
-rw-r--r--tex/context/base/status-lua.pdfbin228159 -> 228232 bytes
-rw-r--r--tex/context/base/strc-mar.lua29
-rw-r--r--tex/context/base/supp-box.lua147
-rw-r--r--tex/context/base/tabl-xtb.lua131
-rw-r--r--tex/context/base/trac-jus.lua58
-rw-r--r--tex/context/base/trac-par.lua125
-rw-r--r--tex/context/base/trac-vis.lua294
-rw-r--r--tex/context/base/typo-bld.lua6
-rw-r--r--tex/context/base/typo-brk.lua122
-rw-r--r--tex/context/base/typo-cap.lua103
-rw-r--r--tex/context/base/typo-cln.lua17
-rw-r--r--tex/context/base/typo-dha.lua75
-rw-r--r--tex/context/base/typo-dig.lua58
-rw-r--r--tex/context/base/typo-dir.lua32
-rw-r--r--tex/context/base/typo-drp.lua101
-rw-r--r--tex/context/base/typo-dua.lua78
-rw-r--r--tex/context/base/typo-dub.lua79
-rw-r--r--tex/context/base/typo-fln.lua91
-rw-r--r--tex/context/base/typo-itc.lua36
-rw-r--r--tex/context/base/typo-krn.lua192
-rw-r--r--tex/context/base/typo-mar.lua145
-rw-r--r--tex/context/base/typo-pag.lua64
-rw-r--r--tex/context/base/typo-rep.lua50
-rw-r--r--tex/context/base/typo-spa.lua56
-rw-r--r--tex/context/base/typo-tal.lua78
-rw-r--r--tex/generic/context/luatex/luatex-fonts-inj.lua526
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua770
-rw-r--r--tex/generic/context/luatex/luatex-fonts-otn.lua2848
-rw-r--r--tex/generic/context/luatex/luatex-fonts.lua4
75 files changed, 8855 insertions, 8138 deletions
diff --git a/tex/context/base/anch-pos.lua b/tex/context/base/anch-pos.lua
index 9cc9fb128..0bd945c8a 100644
--- a/tex/context/base/anch-pos.lua
+++ b/tex/context/base/anch-pos.lua
@@ -30,15 +30,25 @@ local texsp = tex.sp
----- texsp = string.todimen -- because we cache this is much faster but no rounding
local texgetcount = tex.getcount
-local texgetbox = tex.getbox
local texsetcount = tex.setcount
local texget = tex.get
local pdf = pdf -- h and v are variables
local setmetatableindex = table.setmetatableindex
-local new_latelua = nodes.pool.latelua
-local find_tail = node.slide
+
+local nuts = nodes.nuts
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getlist = nuts.getlist
+local getbox = nuts.getbox
+local getskip = nuts.getskip
+
+local find_tail = nuts.tail
+
+local new_latelua = nuts.pool.latelua
+local new_latelua_node = nodes.pool.latelua
local variables = interfaces.variables
local v_text = variables.text
@@ -302,13 +312,13 @@ function commands.bcolumn(tag,register) -- name will change
insert(columns,tag)
column = tag
if register then
- context(new_latelua(f_b_column(tag)))
+ context(new_latelua_node(f_b_column(tag)))
end
end
function commands.ecolumn(register) -- name will change
if register then
- context(new_latelua(f_e_column()))
+ context(new_latelua_node(f_e_column()))
end
remove(columns)
column = columns[#columns]
@@ -340,10 +350,10 @@ function jobpositions.markregionbox(n,tag,correct)
nofregions = nofregions + 1
tag = f_region(nofregions)
end
- local box = texgetbox(n)
- local w = box.width
- local h = box.height
- local d = box.depth
+ local box = getbox(n)
+ local w = getfield(box,"width")
+ local h = getfield(box,"height")
+ local d = getfield(box,"depth")
tobesaved[tag] = {
p = true,
x = true,
@@ -355,18 +365,18 @@ function jobpositions.markregionbox(n,tag,correct)
local push = new_latelua(f_b_region(tag))
local pop = new_latelua(f_e_region(tostring(correct))) -- todo: check if tostring is needed with formatter
-- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end
- local head = box.list
+ local head = getlist(box)
if head then
local tail = find_tail(head)
- head.prev = push
- push.next = head
- pop .prev = tail
- tail.next = pop
+ setfield(head,"prev",push)
+ setfield(push,"next",head)
+ setfield(pop,"prev",tail)
+ setfield(tail,"next",pop)
else -- we can have a simple push/pop
- push.next = pop
- pop.prev = push
+ setfield(push,"next",pop)
+ setfield(pop,"prev",push)
end
- box.list = push
+ setfield(box,"list",push)
end
function jobpositions.enhance(name)
@@ -375,7 +385,7 @@ end
function commands.pos(name,t)
tobesaved[name] = t
- context(new_latelua(f_enhance(name)))
+ context(new_latelua_node(f_enhance(name)))
end
local nofparagraphs = 0
@@ -383,19 +393,19 @@ local nofparagraphs = 0
function commands.parpos() -- todo: relate to localpar (so this is an intermediate variant)
nofparagraphs = nofparagraphs + 1
texsetcount("global","c_anch_positions_paragraph",nofparagraphs)
- local strutbox = texgetbox("strutbox")
+ local strutbox = getbox("strutbox")
local t = {
p = true,
c = true,
r = true,
x = true,
y = true,
- h = strutbox.height,
- d = strutbox.depth,
+ h = getfield(strutbox,"height"),
+ d = getfield(strutbox,"depth"),
hs = texget("hsize"),
}
- local leftskip = texget("leftskip").width
- local rightskip = texget("rightskip").width
+ local leftskip = getfield(getskip("leftskip"),"width")
+ local rightskip = getfield(getskip("rightskip"),"width")
local hangindent = texget("hangindent")
local hangafter = texget("hangafter")
local parindent = texget("parindent")
@@ -420,7 +430,7 @@ function commands.parpos() -- todo: relate to localpar (so this is an intermedia
end
local tag = f_p_tag(nofparagraphs)
tobesaved[tag] = t
- context(new_latelua(f_enhance(tag)))
+ context(new_latelua_node(f_enhance(tag)))
end
function commands.posxy(name) -- can node.write be used here?
@@ -432,7 +442,7 @@ function commands.posxy(name) -- can node.write be used here?
y = true,
n = nofparagraphs > 0 and nofparagraphs or nil,
}
- context(new_latelua(f_enhance(name)))
+ context(new_latelua_node(f_enhance(name)))
end
function commands.poswhd(name,w,h,d)
@@ -447,7 +457,7 @@ function commands.poswhd(name,w,h,d)
d = d,
n = nofparagraphs > 0 and nofparagraphs or nil,
}
- context(new_latelua(f_enhance(name)))
+ context(new_latelua_node(f_enhance(name)))
end
function commands.posplus(name,w,h,d,extra)
@@ -463,22 +473,22 @@ function commands.posplus(name,w,h,d,extra)
n = nofparagraphs > 0 and nofparagraphs or nil,
e = extra,
}
- context(new_latelua(f_enhance(name)))
+ context(new_latelua_node(f_enhance(name)))
end
function commands.posstrut(name,w,h,d)
- local strutbox = texgetbox("strutbox")
+ local strutbox = getbox("strutbox")
tobesaved[name] = {
p = true,
c = column,
r = true,
x = true,
y = true,
- h = strutbox.height,
- d = strutbox.depth,
+ h = getfield(strutbox,"height"),
+ d = getfield(strutbox,"depth"),
n = nofparagraphs > 0 and nofparagraphs or nil,
}
- context(new_latelua(f_enhance(name)))
+ context(new_latelua_node(f_enhance(name)))
end
function jobpositions.getreserved(tag,n)
diff --git a/tex/context/base/back-exp.lua b/tex/context/base/back-exp.lua
index 18a339247..dedfc22c0 100644
--- a/tex/context/base/back-exp.lua
+++ b/tex/context/base/back-exp.lua
@@ -95,10 +95,22 @@ local a_reference = attributes.private('reference')
local a_textblock = attributes.private("textblock")
-local traverse_id = node.traverse_id
-local traverse_nodes = node.traverse
-local slide_nodelist = node.slide
-local locate_node = nodes.locate
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getsubtype = nuts.getsubtype
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getlist = nuts.getlist
+local getid = nuts.getid
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+
+local setattr = nuts.setattr
+
+local traverse_id = nuts.traverse_id
+local traverse_nodes = nuts.traverse
local references = structures.references
local structurestags = structures.tags
@@ -1826,25 +1838,25 @@ end
local function collectresults(head,list) -- is last used (we also have currentattribute)
local p
for n in traverse_nodes(head) do
- local id = n.id -- 14: image, 8: literal (mp)
+ local id = getid(n) -- 14: image, 8: literal (mp)
if id == glyph_code then
- local at = n[a_tagged]
+ local at = getattr(n,a_tagged)
if not at then
-- we need to tag the pagebody stuff as being valid skippable
--
-- report_export("skipping character: %C (no attribute)",n.char)
else
-- we could add tonunicodes for ligatures (todo)
- local components = n.components
+ local components = getfield(n,"components")
if components then -- we loose data
collectresults(components,nil)
else
- local c = n.char
+ local c = getchar(n)
if last ~= at then
local tl = taglist[at]
pushcontent()
currentnesting = tl
- currentparagraph = n[a_taggedpar]
+ currentparagraph = getattr(n,a_taggedpar)
currentattribute = at
last = at
pushentry(currentnesting)
@@ -1853,13 +1865,13 @@ local function collectresults(head,list) -- is last used (we also have currentat
end
-- We need to intercept this here; maybe I will also move this
-- to a regular setter at the tex end.
- local r = n[a_reference]
+ local r = getattr(n,a_reference)
if r then
referencehash[tl[#tl]] = r -- fulltag
end
--
elseif last then
- local ap = n[a_taggedpar]
+ local ap = getattr(n,a_taggedpar)
if ap ~= currentparagraph then
pushcontent(currentparagraph,ap)
pushentry(currentnesting)
@@ -1874,7 +1886,7 @@ local function collectresults(head,list) -- is last used (we also have currentat
report_export("%w<!-- processing glyph %C tagged %a) -->",currentdepth,c,at)
end
end
- local s = n[a_exportstatus]
+ local s = getattr(n,a_exportstatus)
if s then
c = s
end
@@ -1883,7 +1895,7 @@ local function collectresults(head,list) -- is last used (we also have currentat
report_export("%w<!-- skipping last glyph -->",currentdepth)
end
elseif c == 0x20 then
- local a = n[a_characters]
+ local a = getattr(n,a_characters)
nofcurrentcontent = nofcurrentcontent + 1
if a then
if trace_export then
@@ -1894,7 +1906,7 @@ local function collectresults(head,list) -- is last used (we also have currentat
currentcontent[nofcurrentcontent] = " "
end
else
- local fc = fontchar[n.font]
+ local fc = fontchar[getfont(n)]
if fc then
fc = fc and fc[c]
if fc then
@@ -1919,20 +1931,23 @@ local function collectresults(head,list) -- is last used (we also have currentat
end
elseif id == disc_code then -- probably too late
if keephyphens then
- local pre = n.pre
- if pre and not pre.next and pre.id == glyph_code and pre.char == hyphencode then
+ local pre = getfield(n,"pre")
+ if pre and not getnext(pre) and getid(pre) == glyph_code and getchar(pre) == hyphencode then
nofcurrentcontent = nofcurrentcontent + 1
currentcontent[nofcurrentcontent] = hyphen
end
end
- collectresults(n.replace,nil)
+ local replace = getfield(n,"replace")
+ if replace then
+ collectresults(replace,nil)
+ end
elseif id == glue_code then
-- we need to distinguish between hskips and vskips
- local ca = n[a_characters]
+ local ca = getattr(n,a_characters)
if ca == 0 then
-- skip this one ... already converted special character (node-acc)
elseif ca then
- local a = n[a_tagged]
+ local a = getattr(n,a_tagged)
if a then
local c = specialspaces[ca]
if last ~= a then
@@ -1942,13 +1957,13 @@ local function collectresults(head,list) -- is last used (we also have currentat
end
pushcontent()
currentnesting = tl
- currentparagraph = n[a_taggedpar]
+ currentparagraph = getattr(n,a_taggedpar)
currentattribute = a
last = a
pushentry(currentnesting)
-- no reference check (see above)
elseif last then
- local ap = n[a_taggedpar]
+ local ap = getattr(n,a_taggedpar)
if ap ~= currentparagraph then
pushcontent(currentparagraph,ap)
pushentry(currentnesting)
@@ -1969,11 +1984,11 @@ local function collectresults(head,list) -- is last used (we also have currentat
currentcontent[nofcurrentcontent] = c
end
else
- local subtype = n.subtype
+ local subtype = getsubtype(n)
if subtype == userskip_code then
- if n.spec.width > threshold then
+ if getfield(getfield(n,"spec"),"width") > threshold then
if last and not somespace[currentcontent[nofcurrentcontent]] then
- local a = n[a_tagged]
+ local a = getattr(n,a_tagged)
if a == last then
if trace_export then
report_export("%w<!-- injecting spacing 5a -->",currentdepth)
@@ -2000,7 +2015,7 @@ local function collectresults(head,list) -- is last used (we also have currentat
end
elseif subtype == spaceskip_code or subtype == xspaceskip_code then
if not somespace[currentcontent[nofcurrentcontent]] then
- local a = n[a_tagged]
+ local a = getattr(n,a_tagged)
if a == last then
if trace_export then
report_export("%w<!-- injecting spacing 7 (stay in element) -->",currentdepth)
@@ -2029,7 +2044,7 @@ local function collectresults(head,list) -- is last used (we also have currentat
nofcurrentcontent = nofcurrentcontent - 1
end
elseif not somespace[r] then
- local a = n[a_tagged]
+ local a = getattr(n,a_tagged)
if a == last then
if trace_export then
report_export("%w<!-- injecting spacing 1 (end of line, stay in element) -->",currentdepth)
@@ -2057,9 +2072,9 @@ local function collectresults(head,list) -- is last used (we also have currentat
end
end
elseif id == hlist_code or id == vlist_code then
- local ai = n[a_image]
+ local ai = getattr(n,a_image)
if ai then
- local at = n[a_tagged]
+ local at = getattr(n,a_tagged)
if nofcurrentcontent > 0 then
pushcontent()
pushentry(currentnesting) -- ??
@@ -2072,18 +2087,21 @@ local function collectresults(head,list) -- is last used (we also have currentat
currentparagraph = nil
else
-- we need to determine an end-of-line
- collectresults(n.list,n)
+ local list = getlist(n)
+ if list then
+ collectresults(list,n)
+ end
end
elseif id == kern_code then
- local kern = n.kern
+ local kern = getfield(n,"kern")
if kern > 0 then
local limit = threshold
- if p and p.id == glyph_code then
+ if p and getid(p) == glyph_code then
limit = fontquads[p.font] / 4
end
if kern > limit then
if last and not somespace[currentcontent[nofcurrentcontent]] then
- local a = n[a_tagged]
+ local a = getattr(n,a_tagged)
if a == last then
if not somespace[currentcontent[nofcurrentcontent]] then
if trace_export then
@@ -2123,7 +2141,7 @@ function nodes.handlers.export(head) -- hooks into the page builder
end
-- continueexport()
restart = true
- collectresults(head)
+ collectresults(tonut(head))
if trace_export then
report_export("%w<!-- stop flushing page -->",currentdepth)
end
@@ -2133,12 +2151,12 @@ end
function builders.paragraphs.tag(head)
noftextblocks = noftextblocks + 1
- for n in traverse_id(hlist_code,head) do
- local subtype = n.subtype
+ for n in traverse_id(hlist_code,tonut(head)) do
+ local subtype = getsubtype(n)
if subtype == line_code then
- n[a_textblock] = noftextblocks
+ setattr(n,a_textblock,noftextblocks)
elseif subtype == glue_code or subtype == kern_code then
- n[a_textblock] = 0
+ setattr(n,a_textblock,0)
end
end
return false
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 2bbd9ea9b..0918a2119 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2014.01.07 01:06}
+\newcontextversion{2014.01.07 14:00}
%D This file is loaded at runtime, thereby providing an excellent place for
%D hacks, patches, extensions and new features.
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf
index db893977e..7a76449f0 100644
--- a/tex/context/base/context-version.pdf
+++ b/tex/context/base/context-version.pdf
Binary files differ
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 7934f5a26..579d8ea75 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -28,7 +28,7 @@
%D up and the dependencies are more consistent.
\edef\contextformat {\jobname}
-\edef\contextversion{2014.01.07 01:06}
+\edef\contextversion{2014.01.07 14:00}
\edef\contextkind {beta}
%D For those who want to use this:
diff --git a/tex/context/base/font-chk.lua b/tex/context/base/font-chk.lua
index 6dc1667bb..5d4f6059b 100644
--- a/tex/context/base/font-chk.lua
+++ b/tex/context/base/font-chk.lua
@@ -41,9 +41,18 @@ local enableaction = tasks.enableaction
local disableaction = tasks.disableaction
local glyph_code = nodes.nodecodes.glyph
-local traverse_id = node.traverse_id
-local remove_node = nodes.remove
-local insert_node_after = node.insert_after
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local setfield = nuts.setfield
+
+local traverse_id = nuts.traverse_id
+local remove_node = nuts.remove
+local insert_node_after = nuts.insert_after
-- maybe in fonts namespace
-- deletion can be option
@@ -205,9 +214,10 @@ end
function checkers.missing(head)
local lastfont, characters, found = nil, nil, nil
+ head = tonut(head)
for n in traverse_id(glyph_code,head) do -- faster than while loop so we delay removal
- local font = n.font
- local char = n.char
+ local font = getfont(n)
+ local char = getchar(n)
if font ~= lastfont then
characters = fontcharacters[font]
lastfont = font
@@ -236,8 +246,8 @@ function checkers.missing(head)
elseif action == "replace" then
for i=1,#found do
local n = found[i]
- local font = n.font
- local char = n.char
+ local font = getfont(n)
+ local char = getchar(n)
local tfmdata = fontdata[font]
local properties = tfmdata.properties
local privates = properties.privates
@@ -255,13 +265,13 @@ function checkers.missing(head)
head = remove_node(head,n,true)
else
-- good, we have \definefontfeature[default][default][missing=yes]
- n.char = p
+ setfield(n,"char",p)
end
end
else
-- maye write a report to the log
end
- return head, false
+ return tonode(head), false
end
local relevant = { "missing (will be deleted)", "missing (will be flagged)", "missing" }
diff --git a/tex/context/base/font-col.lua b/tex/context/base/font-col.lua
index f5e17f1da..187e33311 100644
--- a/tex/context/base/font-col.lua
+++ b/tex/context/base/font-col.lua
@@ -17,7 +17,12 @@ local type, next, toboolean = type, next, toboolean
local gmatch = string.gmatch
local fastcopy = table.fastcopy
-local traverse_id = nodes.traverse_id
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local setfield = nuts.setfield
+local traverse_id = nuts.traverse_id
local settings_to_hash = utilities.parsers.settings_to_hash
@@ -199,7 +204,7 @@ end
--
-- if lpegmatch(okay,name) then
-function collections.prepare(name) -- we can do this in lua now
+function collections.prepare(name) -- we can do this in lua now .. todo
current = currentfont()
if vectors[current] then
return
@@ -244,23 +249,23 @@ end
function collections.process(head) -- this way we keep feature processing
local done = false
- for n in traverse_id(glyph_code,head) do
- local v = vectors[n.font]
+ for n in traverse_id(glyph_code,tonut(head)) do
+ local v = vectors[getfont(n)]
if v then
- local id = v[n.char]
+ local id = v[getchar(n)]
if id then
if type(id) == "table" then
local newid, newchar = id[1], id[2]
if trace_collecting then
report_fonts("remapping character %C in font %a to character %C in font %a",getchar(n),getfont(n),newchar,newid)
end
- n.font = newid
- n.char = newchar
+ setfield(n,"font",newid)
+ setfield(n,"char",newchar)
else
if trace_collecting then
report_fonts("remapping font %a to %a for character %C",getfont(n),id,getchar(n))
end
- n.font = id
+ setfield(n,"font",id)
end
end
end
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index b08a6aed2..8c4992d0c 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -57,6 +57,16 @@ local helpers = fonts.helpers
local hashes = fonts.hashes
local currentfont = font.current
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
local texgetattribute = tex.getattribute
local texsetattribute = tex.setattribute
local texgetdimen = tex.getdimen
@@ -1901,24 +1911,25 @@ end
-- a fontkern plug:
-local copy_node = node.copy
-local kern = nodes.pool.register(nodes.pool.kern())
-node.set_attribute(kern,attributes.private('fontkern'),1) -- we can have several, attributes are shared
+local copy_node = nuts.copy
+local kern = nuts.pool.register(nuts.pool.kern())
+
+setattr(kern,attributes.private('fontkern'),1) -- we can have several, attributes are shared
nodes.injections.installnewkern(function(k)
local c = copy_node(kern)
- c.kern = k
+ setfield(c,"kern",k)
return c
end)
-directives.register("nodes.injections.fontkern", function(v) kern.subtype = v and 0 or 1 end)
+directives.register("nodes.injections.fontkern", function(v) setfield(kern,"subtype",v and 0 or 1) end)
-- here
local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
local analyzers = fonts.analyzers
@@ -1926,7 +1937,7 @@ local methods = analyzers.methods
local unsetvalue = attributes.unsetvalue
-local traverse_by_id = node.traverse_id
+local traverse_by_id = nuts.traverse_id
local a_color = attributes.private('color')
local a_colormodel = attributes.private('colormodel')
@@ -1953,16 +1964,17 @@ local names = {
local function markstates(head)
if head then
- local model = head[a_colormodel] or 1
+ head = tonut(head)
+ local model = getattr(head,a_colormodel) or 1
for glyph in traverse_by_id(glyph_code,head) do
- local a = glyph[a_state]
+ local a = getattr(glyph,a_state)
if a then
local name = names[a]
if name then
local color = m_color[name]
if color then
- glyph[a_colormodel] = model
- glyph[a_color] = color
+ setattr(glyph,a_colormodel,model)
+ setattr(glyph,a_color,color)
end
end
end
@@ -2005,8 +2017,8 @@ registerotffeature { -- adapts
function methods.nocolor(head,font,attr)
for n in traverse_by_id(glyph_code,head) do
- if not font or n.font == font then
- n[a_color] = unsetvalue
+ if not font or getfont(n) == font then
+ setattr(n,a_color,unsetvalue)
end
end
return head, true
diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua
index 7131ecad5..e57f784a0 100644
--- a/tex/context/base/font-gds.lua
+++ b/tex/context/base/font-gds.lua
@@ -46,7 +46,12 @@ local findfile = resolvers.findfile
local glyph_code = nodes.nodecodes.glyph
-local traverse_id = nodes.traverse_id
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getattr = nuts.getattr
+local traverse_id = nuts.traverse_id
function fontgoodies.report(what,trace,goodies)
if trace_goodies or trace then
@@ -311,16 +316,16 @@ local setnodecolor = nodes.tracers.colors.set
-- function colorschemes.coloring(head)
-- local lastfont, lastscheme
-- local done = false
--- for n in traverse_id(glyph_code,head) do
--- local a = n[a_colorscheme]
+-- for n in traverse_id(glyph_code,tonut(head)) do
+-- local a = getattr(n,a_colorscheme)
-- if a then
--- local f = n.font
+-- local f = getfont(n)
-- if f ~= lastfont then
-- lastscheme = fontproperties[f].colorscheme
-- lastfont = f
-- end
-- if lastscheme then
--- local sc = lastscheme[n.char]
+-- local sc = lastscheme[getchar(n)]
-- if sc then
-- done = true
-- setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow
@@ -338,21 +343,21 @@ local setnodecolor = nodes.tracers.colors.set
-- local lastattr = nil
-- local lastscheme = nil
-- local lastprefix = nil
--- local done = nil
--- for n in traverse_id(glyph_code,head) do
--- local a = n[a_colorscheme]
+-- local done = nil
+-- for n in traverse_id(glyph_code,tonut(head)) do
+-- local a = getattr(n,a_colorscheme)
-- if a then
-- if a ~= lastattr then
-- lastattr = a
-- lastprefix = "colorscheme:" .. a .. ":"
-- end
--- local f = n.font
+-- local f = getfont(n)
-- if f ~= lastfont then
-- lastfont = f
-- lastscheme = fontproperties[f].colorscheme
-- end
-- if lastscheme then
--- local sc = lastscheme[n.char]
+-- local sc = lastscheme[getchar(n)]
-- if sc then
-- setnodecolor(n,lastprefix .. sc) -- slow
-- done = true
@@ -384,10 +389,10 @@ function colorschemes.coloring(head)
local lastcache = nil
local lastscheme = nil
local done = nil
- for n in traverse_id(glyph_code,head) do
- local a = n[a_colorscheme]
+ for n in traverse_id(glyph_code,tonut(head)) do
+ local a = getattr(n,a_colorscheme)
if a then
- local f = n.font
+ local f = getfont(n)
if f ~= lastfont then
lastfont = f
lastscheme = fontproperties[f].colorscheme
@@ -397,7 +402,7 @@ function colorschemes.coloring(head)
lastcache = cache[a]
end
if lastscheme then
- local sc = lastscheme[n.char]
+ local sc = lastscheme[getchar(n)]
if sc then
setnodecolor(n,lastcache[sc]) -- we could inline this one
done = true
diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua
deleted file mode 100644
index 7fa3297d4..000000000
--- a/tex/context/base/font-nod.lua
+++ /dev/null
@@ -1,437 +0,0 @@
-if not modules then modules = { } end modules ['font-nod'] = {
- version = 1.001,
- comment = "companion to font-ini.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This is rather experimental. We need more control and some of this
-might become a runtime module instead. This module will be cleaned up!</p>
---ldx]]--
-
-local tonumber, tostring = tonumber, tostring
-local utfchar = utf.char
-local concat = table.concat
-local match, gmatch, concat, rep = string.match, string.gmatch, table.concat, string.rep
-
-local report_nodes = logs.reporter("fonts","tracing")
-
-fonts = fonts or { }
-nodes = nodes or { }
-
-local fonts, nodes, node, context = fonts, nodes, node, context
-
-local tracers = nodes.tracers or { }
-nodes.tracers = tracers
-
-local tasks = nodes.tasks or { }
-nodes.tasks = tasks
-
-local handlers = nodes.handlers or { }
-nodes.handlers = handlers
-
-local injections = nodes.injections or { }
-nodes.injections = injections
-
-local char_tracers = tracers.characters or { }
-tracers.characters = char_tracers
-
-local step_tracers = tracers.steppers or { }
-tracers.steppers = step_tracers
-
-local texsetbox = tex.setbox
-
-local copy_node_list = nodes.copy_list
-local hpack_node_list = nodes.hpack
-local free_node_list = nodes.flush_list
-local traverse_nodes = nodes.traverse
-
-local nodecodes = nodes.nodecodes
-local whatcodes = nodes.whatcodes
-
-local glyph_code = nodecodes.glyph
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local disc_code = nodecodes.disc
-local glue_code = nodecodes.glue
-local kern_code = nodecodes.kern
-local rule_code = nodecodes.rule
-local whatsit_code = nodecodes.whatsit
-local spec_code = nodecodes.glue_spec
-
-local localpar_code = whatcodes.localpar
-local dir_code = whatcodes.dir
-
-local nodepool = nodes.pool
-local new_glyph = nodepool.glyph
-
-local formatters = string.formatters
-local formatter = string.formatter
-
-local hashes = fonts.hashes
-
-local fontidentifiers = hashes.identifiers
-local fontdescriptions = hashes.descriptions
-local fontcharacters = hashes.characters
-local fontproperties = hashes.properties
-local fontparameters = hashes.parameters
-
-function char_tracers.collect(head,list,tag,n)
- n = n or 0
- local ok, fn = false, nil
- while head do
- local id = head.id
- if id == glyph_code then
- local f = head.font
- if f ~= fn then
- ok, fn = false, f
- end
- local c = head.char
- local i = fontidentifiers[f].indices[c] or 0
- if not ok then
- ok = true
- n = n + 1
- list[n] = list[n] or { }
- list[n][tag] = { }
- end
- local l = list[n][tag]
- l[#l+1] = { c, f, i }
- elseif id == disc_code then
- -- skip
- else
- ok = false
- end
- head = head.next
- end
-end
-
-function char_tracers.equal(ta, tb)
- if #ta ~= #tb then
- return false
- else
- for i=1,#ta do
- local a, b = ta[i], tb[i]
- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then
- return false
- end
- end
- end
- return true
-end
-
-function char_tracers.string(t)
- local tt = { }
- for i=1,#t do
- tt[i] = utfchar(t[i][1])
- end
- return concat(tt,"")
-end
-
-local f_unicode = formatters["%U"]
-
-function char_tracers.unicodes(t,decimal)
- local tt = { }
- for i=1,#t do
- local n = t[i][1]
- if n == 0 then
- tt[i] = "-"
- elseif decimal then
- tt[i] = n
- else
- tt[i] = f_unicode(n)
- end
- end
- return concat(tt," ")
-end
-
-function char_tracers.indices(t,decimal)
- local tt = { }
- for i=1,#t do
- local n = t[i][3]
- if n == 0 then
- tt[i] = "-"
- elseif decimal then
- tt[i] = n
- else
- tt[i] = f_unicode(n)
- end
- end
- return concat(tt," ")
-end
-
-function char_tracers.start()
- local npc = handlers.characters
- local list = { }
- function handlers.characters(head)
- local n = #list
- char_tracers.collect(head,list,'before',n)
- local h, d = npc(head)
- char_tracers.collect(head,list,'after',n)
- if #list > n then
- list[#list+1] = { }
- end
- return h, d
- end
- function char_tracers.stop()
- tracers.list['characters'] = list
- local variables = {
- ['title'] = 'ConTeXt Character Processing Information',
- ['color-background-one'] = lmx.get('color-background-yellow'),
- ['color-background-two'] = lmx.get('color-background-purple'),
- }
- lmx.show('context-characters.lmx',variables)
- handlers.characters = npc
- tasks.restart("processors", "characters")
- end
- tasks.restart("processors", "characters")
-end
-
-local stack = { }
-
-function tracers.start(tag)
- stack[#stack+1] = tag
- local tracer = tracers[tag]
- if tracer and tracer.start then
- tracer.start()
- end
-end
-function tracers.stop()
- local tracer = stack[#stack]
- if tracer and tracer.stop then
- tracer.stop()
- end
- stack[#stack] = nil
-end
-
--- experimental
-
-local collection, collecting, messages = { }, false, { }
-
-function step_tracers.start()
- collecting = true
-end
-
-function step_tracers.stop()
- collecting = false
-end
-
-function step_tracers.reset()
- for i=1,#collection do
- local c = collection[i]
- if c then
- free_node_list(c)
- end
- end
- collection, messages = { }, { }
-end
-
-function step_tracers.nofsteps()
- return context(#collection)
-end
-
-function step_tracers.glyphs(n,i)
- local c = collection[i]
- if c then
- local b = hpack_node_list(copy_node_list(c)) -- multiple arguments
- texsetbox(n,b)
- end
-end
-
-function step_tracers.features()
- -- we cannot use first_glyph here as it only finds characters with subtype < 256
- local f = collection[1]
- while f do
- if f.id == glyph_code then
- local tfmdata, t = fontidentifiers[f.font], { }
- for feature, value in table.sortedhash(tfmdata.shared.features) do
- if feature == "number" or feature == "features" then
- -- private
- elseif type(value) == "boolean" then
- if value then
- t[#t+1] = formatters["%s=yes"](feature)
- else
- -- skip
- end
- else
- t[#t+1] = formatters["%s=%s"](feature,value)
- end
- end
- if #t > 0 then
- context(concat(t,", "))
- else
- context("no features")
- end
- return
- end
- f = f.next
- end
-end
-
-function tracers.fontchar(font,char)
- local n = new_glyph()
- n.font, n.char, n.subtype = font, char, 256
- context(n)
-end
-
-function step_tracers.font(command)
- local c = collection[1]
- while c do
- local id = c.id
- if id == glyph_code then
- local font = c.font
- local name = file.basename(fontproperties[font].filename or "unknown")
- local size = fontparameters[font].size or 0
- if command then
- context[command](font,name,size) -- size in sp
- else
- context("[%s: %s @ %p]",font,name,size)
- end
- return
- else
- c = c.next
- end
- end
-end
-
-function step_tracers.codes(i,command)
- local c = collection[i]
- while c do
- local id = c.id
- if id == glyph_code then
- if command then
- local f, c = c.font,c.char
- local d = fontdescriptions[f]
- local d = d and d[c]
- context[command](f,c,d and d.class or "")
- else
- context("[%s:U+%04X]",c.font,c.char)
- end
- elseif id == whatsit_code and (c.subtype == localpar_code or c.subtype == dir_code) then
- context("[%s]",c.dir)
- else
- context("[%s]",nodecodes[id])
- end
- c = c.next
- end
-end
-
-function step_tracers.messages(i,command,split)
- local list = messages[i] -- or { "no messages" }
- if list then
- for i=1,#list do
- local l = list[i]
- if not command then
- context("(%s)",l)
- elseif split then
- local a, b = match(l,"^(.-)%s*:%s*(.*)$")
- context[command](a or l or "",b or "")
- else
- context[command](l)
- end
- end
- end
-end
-
--- hooks into the node list processor (see otf)
-
-function step_tracers.check(head)
- if collecting then
- step_tracers.reset()
- local n = copy_node_list(head)
- injections.handler(n,nil,"trace",true)
- handlers.protectglyphs(n) -- can be option
- collection[1] = n
- end
-end
-
-function step_tracers.register(head)
- if collecting then
- local nc = #collection+1
- if messages[nc] then
- local n = copy_node_list(head)
- injections.handler(n,nil,"trace",true)
- handlers.protectglyphs(n) -- can be option
- collection[nc] = n
- end
- end
-end
-
-function step_tracers.message(str,...)
- str = formatter(str,...)
- if collecting then
- local n = #collection + 1
- local m = messages[n]
- if not m then m = { } messages[n] = m end
- m[#m+1] = str
- end
- return str -- saves an intermediate var in the caller
-end
-
---
-
-local threshold = 65536
-
-local function toutf(list,result,nofresult,stopcriterium)
- if list then
- for n in traverse_nodes(list) do
- local id = n.id
- if id == glyph_code then
- local components = n.components
- if components then
- result, nofresult = toutf(components,result,nofresult)
- else
- local c = n.char
- local fc = fontcharacters[n.font]
- if fc then
- local u = fc[c].tounicode
- if u then
- for s in gmatch(u,"....") do
- nofresult = nofresult + 1
- result[nofresult] = utfchar(tonumber(s,16))
- end
- else
- nofresult = nofresult + 1
- result[nofresult] = utfchar(c)
- end
- else
- nofresult = nofresult + 1
- result[nofresult] = utfchar(c)
- end
- end
- elseif id == disc_code then
- result, nofresult = toutf(n.replace,result,nofresult) -- needed?
- elseif id == hlist_code or id == vlist_code then
- -- if nofresult > 0 and result[nofresult] ~= " " then
- -- nofresult = nofresult + 1
- -- result[nofresult] = " "
- -- end
- result, nofresult = toutf(n.list,result,nofresult)
- elseif id == glue_code then
- if nofresult > 0 and result[nofresult] ~= " " then
- nofresult = nofresult + 1
- result[nofresult] = " "
- end
- elseif id == kern_code and n.kern > threshold then
- if nofresult > 0 and result[nofresult] ~= " " then
- nofresult = nofresult + 1
- result[nofresult] = " "
- end
- end
- if n == stopcriterium then
- break
- end
- end
- end
- if nofresult > 0 and result[nofresult] == " " then
- result[nofresult] = nil
- nofresult = nofresult - 1
- end
- return result, nofresult
-end
-
-function nodes.toutf(list,stopcriterium)
- local result, nofresult = toutf(list,{},0,stopcriterium)
- return concat(result)
-end
diff --git a/tex/context/base/font-odv.lua b/tex/context/base/font-odv.lua
index 7255c5be5..198acd6f9 100644
--- a/tex/context/base/font-odv.lua
+++ b/tex/context/base/font-odv.lua
@@ -63,9 +63,9 @@ if not modules then modules = { } end modules ['font-odv'] = {
--
-- local function ms_matra(c)
-- local prebase, abovebase, belowbase, postbase = true, true, true, true
--- local n = c.next
--- while n and n.id == glyph_code and n.subtype < 256 and n.font == font do
--- local char = n.char
+-- local n = getnext(c)
+-- while n and getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font do
+-- local char = getchar(n)
-- if not dependent_vowel[char] then
-- break
-- elseif pre_mark[char] and prebase then
@@ -79,7 +79,7 @@ if not modules then modules = { } end modules ['font-odv'] = {
-- else
-- return c
-- end
--- c = c.next
+-- c = getnext(c)
-- end
-- return c
-- end
@@ -106,11 +106,26 @@ local methods = fonts.analyzers.methods
local otffeatures = fonts.constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
-local insert_node_after = nodes.insert_after
-local copy_node = nodes.copy
-local free_node = nodes.free
-local remove_node = nodes.remove
-local flush_list = nodes.flush_list
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getchar = nuts.getchar
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local insert_node_after = nuts.insert_after
+local copy_node = nuts.copy
+local free_node = nuts.free
+local remove_node = nuts.remove
+local flush_list = nuts.flush_list
local unsetvalue = attributes.unsetvalue
@@ -147,7 +162,7 @@ xprocesscharacters = function(head,font)
end
local function processcharacters(head,font)
- return xprocesscharacters(head)
+ return tonut(xprocesscharacters(tonode(head)))
end
-- function processcharacters(head,font)
@@ -402,6 +417,7 @@ local reorder_class = {
[0x0CC4] = "after subscript",
[0x0CD5] = "after subscript",
[0x0CD6] = "after subscript",
+ -- malayalam
}
-- We use some pseudo features as we need to manipulate the nodelist based
@@ -615,30 +631,30 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
local lookuphash, reph, vattu, blwfcache = deva_initialize(font,attr) -- could be inlines but ugly
local current = start
- local n = start.next
+ local n = getnext(start)
local base = nil
local firstcons = nil
local lastcons = nil
local basefound = false
- if ra[start.char] and halant[n.char] and reph then
+ if ra[getchar(start)] and halant[getchar(n)] and reph then
-- if syllable starts with Ra + H and script has 'Reph' then exclude Reph
-- from candidates for base consonants
if n == stop then
return head, stop, nbspaces
end
- if n.next.char == c_zwj then
+ if getchar(getnext(n)) == c_zwj then
current = start
else
- current = n.next
- start[a_state] = s_rphf
+ current = getnext(n)
+ setattr(start,a_state,s_rphf)
end
end
- if current.char == c_nbsp then
+ if getchar(current) == c_nbsp then
-- Stand Alone cluster
if current == stop then
- stop = stop.prev
+ stop = getprev(stop)
head = remove_node(head,current)
free_node(current)
return head, stop, nbspaces
@@ -647,37 +663,37 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
base = current
firstcons = current
lastcons = current
- current = current.next
+ current = getnext(current)
if current ~= stop then
- if nukta[current.char] then
- current = current.next
+ if nukta[getchar(current)] then
+ current = getnext(current)
end
- if current.char == c_zwj then
+ if getchar(current) == c_zwj then
if current ~= stop then
- local next = current.next
- if next ~= stop and halant[next.char] then
+ local next = getnext(current)
+ if next ~= stop and halant[getchar(next)] then
current = next
- next = current.next
- local tmp = next and next.next or nil -- needs checking
+ next = getnext(current)
+ local tmp = next and getnext(next) or nil -- needs checking
local changestop = next == stop
local tempcurrent = copy_node(next)
local nextcurrent = copy_node(current)
- tempcurrent.next = nextcurrent
- nextcurrent.prev = tempcurrent
- tempcurrent[a_state] = s_blwf
+ setfield(tempcurrent,"next",nextcurrent)
+ setfield(nextcurrent,"prev",tempcurrent)
+ setattr(tempcurrent,a_state,s_blwf)
tempcurrent = processcharacters(tempcurrent,font)
- tempcurrent[a_state] = unsetvalue
- if next.char == tempcurrent.char then
+ setattr(tempcurrent,a_state,unsetvalue)
+ if getchar(next) == getchar(tempcurrent) then
flush_list(tempcurrent)
local n = copy_node(current)
- current.char = dotted_circle
+ setfield(current,"char",dotted_circle)
head = insert_node_after(head, current, n)
else
- current.char = tempcurrent.char -- (assumes that result of blwf consists of one node)
- local freenode = current.next
- current.next = tmp
+ setfield(current,"char",getchar(tempcurrent)) -- (assumes that result of blwf consists of one node)
+ local freenode = getnext(current)
+ setfield(current,"next",tmp)
if tmp then
- tmp.prev = current
+ setfield(tmp,"prev",current)
end
free_node(freenode)
flush_list(tempcurrent)
@@ -694,82 +710,82 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
while not basefound do
-- find base consonant
- if consonant[current.char] then
- current[a_state] = s_half
+ if consonant[getchar(current)] then
+ setattr(current,a_state,s_half)
if not firstcons then
firstcons = current
end
lastcons = current
if not base then
base = current
- elseif blwfcache[current.char] then
+ elseif blwfcache[getchar(current)] then
-- consonant has below-base (or post-base) form
- current[a_state] = s_blwf
+ setattr(current,a_state,s_blwf)
else
base = current
end
end
basefound = current == stop
- current = current.next
+ current = getnext(current)
end
if base ~= lastcons then
-- if base consonant is not last one then move halant from base consonant to last one
local np = base
- local n = base.next
- if nukta[n.char] then
+ local n = getnext(base)
+ if nukta[getchar(n)] then
np = n
- n = n.next
+ n = getnext(n)
end
- if halant[n.char] then
+ if halant[getchar(n)] then
if lastcons ~= stop then
- local ln = lastcons.next
- if nukta[ln.char] then
+ local ln = getnext(lastcons)
+ if nukta[getchar(ln)] then
lastcons = ln
end
end
- -- local np = n.prev
- local nn = n.next
- local ln = lastcons.next -- what if lastcons is nn ?
- np.next = nn
- nn.prev = np
- lastcons.next = n
+ -- local np = getprev(n)
+ local nn = getnext(n)
+ local ln = getnext(lastcons) -- what if lastcons is nn ?
+ setfield(np,"next",nn)
+ setfield(nn,"prev",np)
+ setfield(lastcons,"next",n)
if ln then
- ln.prev = n
+ setfield(ln,"prev",n)
end
- n.next = ln
- n.prev = lastcons
+ setfield(n,"next",ln)
+ setfield(n,"prev",lastcons)
if lastcons == stop then
stop = n
end
end
end
- n = start.next
- if n ~= stop and ra[start.char] and halant[n.char] and not zw_char[n.next.char] then
+ n = getnext(start)
+ if n ~= stop and ra[getchar(start)] and halant[getchar(n)] and not zw_char[getchar(getnext(n))] then
-- if syllable starts with Ra + H then move this combination so that it follows either:
-- the post-base 'matra' (if any) or the base consonant
local matra = base
if base ~= stop then
- local next = base.next
- if dependent_vowel[next.char] then
+ local next = getnext(base)
+ if dependent_vowel[getchar(next)] then
matra = next
end
end
-- [sp][start][n][nn] [matra|base][?]
-- [matra|base][start] [n][?] [sp][nn]
- local sp = start.prev
- local nn = n.next
- local mn = matra.next
+ local sp = getprev(start)
+ local nn = getnext(n)
+ local mn = getnext(matra)
if sp then
- sp.next = nn
+ setfield(sp,"next",nn)
end
- nn.prev = sp
- matra.next = start
- start.prev = matra
- n.next = mn
+ setfield(nn,"prev",sp)
+ setfield(matra,"next",start)
+ setfield(start,"prev",matra)
+ setfield(n,"next",mn)
if mn then
- mn.prev = n
+ setfield(mn,"prev",n)
end
if head == start then
head = nn
@@ -782,17 +798,17 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
local current = start
while current ~= stop do
- local next = current.next
- if next ~= stop and halant[next.char] and next.next.char == c_zwnj then
- current[a_state] = unsetvalue
+ local next = getnext(current)
+ if next ~= stop and halant[getchar(next)] and getchar(getnext(next)) == c_zwnj then
+ setattr(current,a_state,unsetvalue)
end
current = next
end
- if base ~= stop and base[a_state] then
- local next = base.next
- if halant[next.char] and not (next ~= stop and next.next.char == c_zwj) then
- base[a_state] = unsetvalue
+ if base ~= stop and getattr(base,a_state) then
+ local next = getnext(base)
+ if halant[getchar(next)] and not (next ~= stop and getchar(getnext(next)) == c_zwj) then
+ setattr(base,a_state,unsetvalue)
end
end
@@ -802,62 +818,62 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
-- classify consonants and 'matra' parts as pre-base, above-base (Reph), below-base or post-base, and group elements of the syllable (consonants and 'matras') according to this classification
local current, allreordered, moved = start, false, { [base] = true }
- local a, b, p, bn = base, base, base, base.next
- if base ~= stop and nukta[bn.char] then
+ local a, b, p, bn = base, base, base, getnext(base)
+ if base ~= stop and nukta[getchar(bn)] then
a, b, p = bn, bn, bn
end
while not allreordered do
-- current is always consonant
local c = current
- local n = current.next
+ local n = getnext(current)
local l = nil -- used ?
if c ~= stop then
- if nukta[n.char] then
+ if nukta[getchar(n)] then
c = n
- n = n.next
+ n = getnext(n)
end
if c ~= stop then
- if halant[n.char] then
+ if halant[getchar(n)] then
c = n
- n = n.next
+ n = getnext(n)
end
- while c ~= stop and dependent_vowel[n.char] do
+ while c ~= stop and dependent_vowel[getchar(n)] do
c = n
- n = n.next
+ n = getnext(n)
end
if c ~= stop then
- if vowel_modifier[n.char] then
+ if vowel_modifier[getchar(n)] then
c = n
- n = n.next
+ n = getnext(n)
end
- if c ~= stop and stress_tone_mark[n.char] then
+ if c ~= stop and stress_tone_mark[getchar(n)] then
c = n
- n = n.next
+ n = getnext(n)
end
end
end
end
- local bp = firstcons.prev
- local cn = current.next
- local last = c.next
+ local bp = getprev(firstcons)
+ local cn = getnext(current)
+ local last = getnext(c)
while cn ~= last do
-- move pre-base matras...
- if pre_mark[cn.char] then
+ if pre_mark[getchar(cn)] then
if bp then
- bp.next = cn
+ setfield(bp,"next",cn)
end
- local next = cn.next
- local prev = cn.prev
+ local next = getnext(cn)
+ local prev = getprev(cn)
if next then
- next.prev = prev
+ setfield(next,"prev",prev)
end
- prev.next = next
+ setfield(prev,"next",next)
if cn == stop then
stop = prev
end
- cn.prev = bp
- cn.next = firstcons
- firstcons.prev = cn
+ setfield(cn,"prev",bp)
+ setfield(cn,"next",firstcons)
+ setfield(firstcons,"prev",cn)
if firstcons == start then
if head == start then
head = cn
@@ -866,29 +882,29 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
end
break
end
- cn = cn.next
+ cn = getnext(cn)
end
allreordered = c == stop
- current = c.next
+ current = getnext(c)
end
if reph or vattu then
local current, cns = start, nil
while current ~= stop do
local c = current
- local n = current.next
- if ra[current.char] and halant[n.char] then
+ local n = getnext(current)
+ if ra[getchar(current)] and halant[getchar(n)] then
c = n
- n = n.next
+ n = getnext(n)
local b, bn = base, base
while bn ~= stop do
- local next = bn.next
- if dependent_vowel[next.char] then
+ local next = getnext(bn)
+ if dependent_vowel[getchar(next)] then
b = next
end
bn = next
end
- if current[a_state] == s_rphf then
+ if getattr(current,a_state) == s_rphf then
-- position Reph (Ra + H) after post-base 'matra' (if any) since these
-- become marks on the 'matra', not on the base glyph
if b ~= current then
@@ -901,65 +917,65 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
if b == stop then
stop = c
end
- local prev = current.prev
+ local prev = getprev(current)
if prev then
- prev.next = n
+ setfield(prev,"next",n)
end
if n then
- n.prev = prev
+ setfield(n,"prev",prev)
end
- local next = b.next
- c.next = next
+ local next = getnext(b)
+ setfield(c,"next",next)
if next then
- next.prev = c
+ setfield(next,"prev",c)
end
- c.next = next
- b.next = current
- current.prev = b
+ setfield(c,"next",next)
+ setfield(b,"next",current)
+ setfield(current,"prev",b)
end
- elseif cns and cns.next ~= current then
+ elseif cns and getnext(cns) ~= current then -- todo: optimize next
-- position below-base Ra (vattu) following the consonants on which it is placed (either the base consonant or one of the pre-base consonants)
- local cp, cnsn = current.prev, cns.next
+ local cp, cnsn = getprev(current), getnext(cns)
if cp then
- cp.next = n
+ setfield(cp,"next",n)
end
if n then
- n.prev = cp
+ setfield(n,"prev",cp)
end
- cns.next = current
- current.prev = cns
- c.next = cnsn
+ setfield(cns,"next",current)
+ setfield(current,"prev",cns)
+ setfield(c,"next",cnsn)
if cnsn then
- cnsn.prev = c
+ setfield(cnsn,"prev",c)
end
if c == stop then
stop = cp
break
end
- current = n.prev
+ current = getprev(n)
end
else
- local char = current.char
+ local char = getchar(current)
if consonant[char] then
cns = current
- local next = cns.next
- if halant[next.char] then
+ local next = getnext(cns)
+ if halant[getchar(next)] then
cns = next
end
elseif char == c_nbsp then
nbspaces = nbspaces + 1
cns = current
- local next = cns.next
- if halant[next.char] then
+ local next = getnext(cns)
+ if halant[getchar(next)] then
cns = next
end
end
end
- current = current.next
+ current = getnext(current)
end
end
- if base.char == c_nbsp then
+ if getchar(base) == c_nbsp then
nbspaces = nbspaces - 1
head = remove_node(head,base)
free_node(base)
@@ -979,24 +995,24 @@ end
function handlers.devanagari_reorder_matras(head,start,kind,lookupname,replacement) -- no leak
local current = start -- we could cache attributes here
- local startfont = start.font
- local startattr = start[a_syllabe]
+ local startfont = getfont(start)
+ local startattr = getattr(start,a_syllabe)
-- can be fast loop
- while current and current.id == glyph_code and current.subtype<256 and current.font == font and current[a_syllabe] == startattr do
- local next = current.next
- if halant[current.char] and not current[a_state] then
- if next and next.id == glyph_code and next.subtype<256 and next.font == font and next[a_syllabe] == startattr and zw_char[next.char] then
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font and getattr(current,a_syllabe) == startattr do
+ local next = getnext(current)
+ if halant[getchar(current)] and not getattr(current,a_state) then
+ if next and getid(next) == glyph_code and getsubtype(next) < 256 and getfont(next) == font and getattr(next,a_syllabe) == startattr and zw_char[getchar(next)] then
current = next
end
- local startnext = start.next
+ local startnext = getnext(start)
head = remove_node(head,start)
- local next = current.next
+ local next = getnext(current)
if next then
- next.prev = start
+ setfield(next,"prev",start)
end
- start.next = next
- current.next = start
- start.prev = current
+ setfield(start,"next",next)
+ setfield(current,"next",start)
+ setfield(start,"prev",current)
start = startnext
break
end
@@ -1032,98 +1048,98 @@ end
function handlers.devanagari_reorder_reph(head,start,kind,lookupname,replacement)
-- since in Devanagari reph has reordering position 'before postscript' dev2 only follows step 2, 4, and 6,
-- the other steps are still ToDo (required for scripts other than dev2)
- local current = start.next
+ local current = getnext(start)
local startnext = nil
local startprev = nil
- local startfont = start.font
- local startattr = start[a_syllabe]
- while current and current.id == glyph_code and current.subtype<256 and current.font == startfont and current[a_syllabe] == startattr do --step 2
- if halant[current.char] and not current[a_state] then
- local next = current.next
- if next and next.id == glyph_code and next.subtype<256 and next.font == startfont and next[a_syllabe] == startattr and zw_char[next.char] then
+ local startfont = getfont(start)
+ local startattr = getattr(start,a_syllabe)
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == startfont and getattr(current,a_syllabe) == startattr do --step 2
+ if halant[getchar(current)] and not getattr(current,a_state) then
+ local next = getnext(current)
+ if next and getid(next) == glyph_code and getsubtype(next) < 256 and getfont(next) == startfont and getattr(next,a_syllabe) == startattr and zw_char[getchar(next)] then
current = next
end
- startnext = start.next
+ startnext = getnext(start)
head = remove_node(head,start)
- local next = current.next
+ local next = getnext(current)
if next then
- next.prev = start
+ setfield(next,"prev",start)
end
- start.next = next
- current.next = start
- start.prev = current
+ setfield(start,"next",next)
+ setfield(current,"next",start)
+ setfield(start,"prev",current)
start = startnext
- startattr = start[a_syllabe]
+ startattr = getattr(start,a_syllabe)
break
end
- current = current.next
+ current = getnext(current)
end
if not startnext then
- current = start.next
- while current and current.id == glyph_code and current.subtype<256 and current.font == startfont and current[a_syllabe] == startattr do --step 4
- if current[a_state] == s_pstf then --post-base
- startnext = start.next
+ current = getnext(start)
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == startfont and getattr(current,a_syllabe) == startattr do --step 4
+ if getattr(current,a_state) == s_pstf then --post-base
+ startnext = getnext(start)
head = remove_node(head,start)
- local prev = current.prev
- start.prev = prev
- prev.next = start
- start.next = current
- current.prev = start
+ local prev = getprev(current)
+ setfield(start,"prev",prev)
+ setfield(prev,"next",start)
+ setfield(start,"next",current)
+ setfield(current,"prev",start)
start = startnext
- startattr = start[a_syllabe]
+ startattr = getattr(start,a_syllabe)
break
end
- current = current.next
+ current = getnext(current)
end
end
-- ToDo: determine position for reph with reordering position other than 'before postscript'
-- (required for scripts other than dev2)
-- leaks
if not startnext then
- current = start.next
+ current = getnext(start)
local c = nil
- while current and current.id == glyph_code and current.subtype<256 and current.font == startfont and current[a_syllabe] == startattr do --step 5
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == startfont and getattr(current,a_syllabe) == startattr do --step 5
if not c then
- local char = current.char
+ local char = getchar(current)
-- todo: combine in one
if mark_above_below_post[char] and reorder_class[char] ~= "after subscript" then
c = current
end
end
- current = current.next
+ current = getnext(current)
end
-- here we can loose the old start node: maybe best split cases
if c then
- startnext = start.next
+ startnext = getnext(start)
head = remove_node(head,start)
- local prev = c.prev
- start.prev = prev
- prev.next = start
- start.next = c
- c.prev = start
+ local prev = getprev(c)
+ setfield(start,"prev",prev)
+ setfield(prev,"next",start)
+ setfield(start,"next",c)
+ setfield(c,"prev",start)
-- end
start = startnext
- startattr = start[a_syllabe]
+ startattr = getattr(start,a_syllabe)
end
end
-- leaks
if not startnext then
current = start
- local next = current.next
- while next and next.id == glyph_code and next.subtype<256 and next.font == startfont and next[a_syllabe] == startattr do --step 6
+ local next = getnext(current)
+ while next and getid(next) == glyph_code and getsubtype(next) < 256 and getfont(next) == startfont and getattr(next,a_syllabe) == startattr do --step 6
current = next
- next = current.next
+ next = getnext(current)
end
if start ~= current then
- startnext = start.next
+ startnext = getnext(start)
head = remove_node(head,start)
- local next = current.next
+ local next = getnext(current)
if next then
- next.prev = start
+ setfield(next,"prev",start)
end
- start.next = next
- current.next = start
- start.prev = current
+ setfield(start,"next",next)
+ setfield(current,"next",start)
+ setfield(start,"prev",current)
start = startnext
end
end
@@ -1146,71 +1162,71 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start,k
local current = start
local startnext = nil
local startprev = nil
- local startfont = start.font
- local startattr = start[a_syllabe]
+ local startfont = getfont(start)
+ local startattr = getattr(start,a_syllabe)
-- can be fast for loop + caching state
- while current and current.id == glyph_code and current.subtype<256 and current.font == startfont and current[a_syllabe] == startattr do
- local next = current.next
- if halant[current.char] and not current[a_state] then
- if next and next.id == glyph_code and next.subtype<256 and next.font == font and next[a_syllabe] == startattr then
- local char = next.char
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == startfont and getattr(current,a_syllabe) == startattr do
+ local next = getnext(current)
+ if halant[getchar(current)] and not getattr(current,a_state) then
+ if next and getid(next) == glyph_code and getsubtype(next) < 256 and getfont(next) == font and getattr(next,a_syllabe) == startattr then
+ local char = getchar(next)
if char == c_zwnj or char == c_zwj then
current = next
end
end
- startnext = start.next
+ startnext = getnext(start)
removenode(start,start)
- local next = current.next
+ local next = getnext(current)
if next then
- next.prev = start
+ setfield(next,"prev",start)
end
- start.next = next
- current.next = start
- start.prev = current
+ setfield(start,"next",next)
+ setfield(current,"next",start)
+ setfield(start,"prev",current)
start = startnext
break
end
current = next
end
if not startnext then
- current = start.next
- startattr = start[a_syllabe]
- while current and current.id == glyph_code and current.subtype<256 and current.font == startfont and current[a_syllabe] == startattr do
- if not consonant[current.char] and current[a_state] then --main
- startnext = start.next
+ current = getnext(start)
+ startattr = getattr(start,a_syllabe)
+ while current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == startfont and getattr(current,a_syllabe) == startattr do
+ if not consonant[getchar(current)] and getattr(current,a_state) then --main
+ startnext = getnext(start)
removenode(start,start)
- local prev = current.prev
- start.prev = prev
- prev.next = start
- start.next = current
- current.prev = start
+ local prev = getprev(current)
+ setfield(start,"prev",prev)
+ setfield(prev,"next",start)
+ setfield(start,"next",current)
+ setfield(current,"prev",start)
start = startnext
break
end
- current = current.next
+ current = getnext(current)
end
end
return head, start, true
end
function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
- local stop = start.next
- local startfont = start.font
- while stop and stop.id == glyph_code and stop.subtype<256 and stop.font == startfont do
- local char = stop.char
+ local stop = getnext(start)
+ local startfont = getfont(start)
+ while stop and getid(stop) == glyph_code and getsubtype(stop) < 256 and getfont(stop) == startfont do
+ local char = getchar(stop)
if char == c_zwnj or char == c_zwj then
- stop = stop.next
+ stop = getnext(stop)
else
break
end
end
if stop then
- stop.prev.next = nil
- stop.prev = start.prev
+ setfield(getfield(stop,"prev"),"next",nil)
+ setfield(stop,"prev",getprev(start))
end
- local prev = start.prev
+ local prev = getprev(start)
if prev then
- prev.next = stop
+ setfield(prev,"next",stop)
end
if head == start then
head = stop
@@ -1276,6 +1292,7 @@ local function dev2_initialize(font,attr)
for k, v in next, ra do
local r = lookupcache[k]
if r then
+ local h = false
for k, v in next, halant do
local h = r[k]
if h then
@@ -1331,7 +1348,6 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
for k, v in next, ra do
local r = lookupcache[k]
if r then
- local h = false
for k, v in next, halant do
local h = r[k]
if h then
@@ -1345,21 +1361,21 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
end
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or current.char
+ local c = locl[current] or getchar(current)
local found = lookupcache[c]
if found then
- local next = current.next
- local n = locl[next] or next.char
+ local next = getnext(current)
+ local n = locl[next] or getchar(next)
if found[n] then --above-base: rphf Consonant + Halant
- local afternext = next ~= stop and next.next
- if afternext and zw_char[afternext.char] then -- ZWJ and ZWNJ prevent creation of reph
+ local afternext = next ~= stop and getnext(next)
+ if afternext and zw_char[getchar(afternext)] then -- ZWJ and ZWNJ prevent creation of reph
current = next
- current = current.next
+ current = getnext(current)
elseif current == start then
- current[a_state] = s_rphf
+ setattr(current,a_state,s_rphf)
current = next
else
current = next
@@ -1367,7 +1383,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
end
end
- current = current.next
+ current = getnext(current)
end
elseif kind == "pref" then
-- why not global? pretty ineffient this way
@@ -1391,87 +1407,87 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
--
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or current.char
+ local c = locl[current] or getchar(current)
local found = lookupcache[c]
if found then
- local next = current.next
- local n = locl[next] or next.char
+ local next = getnext(current)
+ local n = locl[next] or getchar(next)
if found[n] then
- current[a_state] = s_pref
- next[a_state] = s_pref
+ setattr(current,a_state,s_pref)
+ setattr(next,a_state,s_pref)
current = next
end
end
end
- current = current.next
+ current = getnext(current)
end
elseif kind == "half" then -- half forms: half / Consonant + Halant
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or current.char
+ local c = locl[current] or getchar(current)
local found = lookupcache[c]
if found then
- local next = current.next
- local n = locl[next] or next.char
+ local next = getnext(current)
+ local n = locl[next] or getchar(next)
if found[n] then
- if next ~= stop and next.next.char == c_zwnj then -- zwnj prevent creation of half
+ if next ~= stop and getchar(getnext(next)) == c_zwnj then -- zwnj prevent creation of half
current = next
else
- current[a_state] = s_half
+ setattr(current,a_state,s_half)
if not halfpos then
halfpos = current
end
end
- current = current.next
+ current = getnext(current)
end
end
end
- current = current.next
+ current = getnext(current)
end
elseif kind == "blwf" then -- below-base: blwf / Halant + Consonant
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or current.char
+ local c = locl[current] or getchar(current)
local found = lookupcache[c]
if found then
- local next = current.next
- local n = locl[next] or next.char
+ local next = getnext(current)
+ local n = locl[next] or getchar(next)
if found[n] then
- current[a_state] = s_blwf
- next[a_state] = s_blwf
+ setattr(current,a_state,s_blwf)
+ setattr(next,a_state,s_blwf)
current = next
subpos = current
end
end
end
- current = current.next
+ current = getnext(current)
end
elseif kind == "pstf" then -- post-base: pstf / Halant + Consonant
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or current.char
+ local c = locl[current] or getchar(current)
local found = lookupcache[c]
if found then
- local next = current.next
- local n = locl[next] or next.char
+ local next = getnext(current)
+ local n = locl[next] or getchar(next)
if found[n] then
- current[a_state] = s_pstf
- next[a_state] = s_pstf
+ setattr(current,a_state,s_pstf)
+ setattr(next,a_state,s_pstf)
current = next
postpos = current
end
end
end
- current = current.next
+ current = getnext(current)
end
end
end
@@ -1483,14 +1499,14 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
local current, base, firstcons = start, nil, nil
- if start[a_state] == s_rphf then
+ if getattr(start,a_state) == s_rphf then
-- if syllable starts with Ra + H and script has 'Reph' then exclude Reph from candidates for base consonants
- current = start.next.next
+ current = getnext(getnext(start))
end
local function stand_alone(is_nbsp)
if current == stop then
- stop = stop.prev
+ stop = getprev(stop)
head = remove_node(head,current)
free_node(current)
return head, stop, nbspaces
@@ -1498,36 +1514,36 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
if is_nbsp then
nbspaces = nbspaces + 1
end
- base = current
- current = current.next
+ base = current
+ current = getnext(current)
if current ~= stop then
- local char = current.char
+ local char = getchar(current)
if nukta[char] then
- current = current.next
- char = current.char
+ current = getnext(current)
+ char = getchar(current)
end
if char == c_zwj then
- local next = current.next
- if current ~= stop and next ~= stop and halant[next.char] then
+ local next = getnext(current)
+ if current ~= stop and next ~= stop and halant[getchar(next)] then
current = next
- next = current.next
- local tmp = next.next
+ next = getnext(current)
+ local tmp = getnext(next)
local changestop = next == stop
- next.next = nil
- current[a_state] = s_pref
+ setfield(next,"next",nil)
+ setattr(current,a_state,s_pref)
current = processcharacters(current,font)
- current[a_state] = s_blwf
+ setattr(current,a_state,s_blwf)
current = processcharacters(current,font)
- current[a_state] = s_pstf
+ setattr(current,a_state,s_pstf)
current = processcharacters(current,font)
- current[a_state] = unsetvalue
- if halant[current.char] then
- current.next.next = tmp
+ setattr(current,a_state,unsetvalue)
+ if halant[getchar(current)] then
+ setfield(getnext(current),"next",tmp)
local nc = copy_node(current)
- current.char = dotted_circle
+ setfield(current,"char",dotted_circle)
head = insert_node_after(head,current,nc)
else
- current.next = tmp -- assumes that result of pref, blwf, or pstf consists of one node
+ setfield(current,"next",tmp) -- assumes that result of pref, blwf, or pstf consists of one node
if changestop then
stop = current
end
@@ -1538,23 +1554,23 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
end
- if current ~= stop.next then
+ if current ~= getnext(stop) then
-- Stand Alone cluster
stand_alone()
- elseif current.char == c_nbsp then
+ elseif getchar(current) == c_nbsp then
-- Stand Alone cluster
stand_alone(true)
else -- not Stand Alone cluster
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do -- find base consonant
- local next = current.next
- if consonant[current.char] then
- if not (current ~= stop and next ~= stop and halant[next.char] and next.next.char == c_zwj) then
+ local next = getnext(current)
+ if consonant[getchar(current)] then
+ if not (current ~= stop and next ~= stop and halant[getchar(next)] and getchar(getnext(next)) == c_zwj) then
if not firstcons then
firstcons = current
end
-- check whether consonant has below-base or post-base form or is pre-base reordering Ra
- local a = current[a_state]
+ local a = getattr(current,a_state)
if not (a == s_pref or a == s_blwf or a == s_pstf) then
base = current
end
@@ -1568,13 +1584,13 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
if not base then
- if start[a_state] == s_rphf then
- start[a_state] = unsetvalue
+ if getattr(start,a_state) == s_rphf then
+ setattr(start,a_state,unsetvalue)
end
return head, stop, nbspaces
else
- if base[a_state] then
- base[a_state] = unsetvalue
+ if getattr(base,a_state) then
+ setattr(base,a_state,unsetvalue)
end
basepos = base
end
@@ -1592,32 +1608,32 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
local moved = { }
local current = start
- local last = stop.next
+ local last = getnext(stop)
while current ~= last do
- local char, target, cn = locl[current] or current.char, nil, current.next
+ local char, target, cn = locl[current] or getchar(current), nil, getnext(current)
-- not so efficient (needed for malayalam)
local tpm = twopart_mark[char]
if tpm then
local extra = copy_node(current)
char = tpm[1]
- current.char = char
- extra.char = tpm[2]
- head = insert_after(head,current,extra)
+ setfield(current,"char",char)
+ setfield(extra,"char",tpm[2])
+ head = insert_node_after(head,current,extra)
end
--
if not moved[current] and dependent_vowel[char] then
if pre_mark[char] then -- Before first half form in the syllable
moved[current] = true
- local prev = current.prev
- local next = current.next
+ local prev = getprev(current)
+ local next = getnext(current)
if prev then
- prev.next = next
+ setfield(prev,"next",next)
end
if next then
- next.prev = prev
+ setfield(next,"prev",prev)
end
if current == stop then
- stop = current.prev
+ stop = getprev(current)
end
if halfpos == start then
if head == start then
@@ -1625,13 +1641,13 @@ end
end
start = current
end
- local prev = halfpos.prev
+ local prev = getprev(halfpos)
if prev then
- prev.next = current
+ setfield(prev,"next",current)
end
- current.prev = prev
- halfpos.prev = current
- current.next = halfpos
+ setfield(current,"prev",prev)
+ setfield(halfpos,"prev",current)
+ setfield(current,"next",halfpos)
halfpos = current
elseif above_mark[char] then -- After main consonant
target = basepos
@@ -1653,25 +1669,25 @@ end
postpos = current
end
if mark_above_below_post[char] then
- local prev = current.prev
+ local prev = getprev(current)
if prev ~= target then
- local next = current.next
+ local next = getnext(current)
if prev then -- not needed, already tested with target
- prev.next = next
+ setfield(prev,"next",next)
end
if next then
- next.prev = prev
+ setfield(next,"prev",prev)
end
if current == stop then
stop = prev
end
- local next = target.next
+ local next = getnext(target)
if next then
- next.prev = current
+ setfield(next,"prev",current)
end
- current.next = next
- target.next = current
- current.prev = target
+ setfield(current,"next",next)
+ setfield(target,"next",current)
+ setfield(current,"prev",target)
end
end
end
@@ -1682,7 +1698,7 @@ end
local current, c = start, nil
while current ~= stop do
- local char = current.char
+ local char = getchar(current)
if halant[char] or stress_tone_mark[char] then
if not c then
c = current
@@ -1690,33 +1706,33 @@ end
else
c = nil
end
- local next = current.next
- if c and nukta[next.char] then
+ local next = getnext(current)
+ if c and nukta[getchar(next)] then
if head == c then
head = next
end
if stop == next then
stop = current
end
- local prev = c.prev
+ local prev = getprev(c)
if prev then
- prev.next = next
+ setfield(prev,"next",next)
end
- next.prev = prev
- local nextnext = next.next
- current.next = nextnext
- local nextnextnext = nextnext.next
+ setfield(next,"prev",prev)
+ local nextnext = getnext(next)
+ setfield(current,"next",nextnext)
+ local nextnextnext = getnext(nextnext)
if nextnextnext then
- nextnextnext.prev = current
+ setfield(nextnextnext,"prev",current)
end
- c.prev = nextnext
- nextnext.next = c
+ setfield(c,"prev",nextnext)
+ setfield(nextnext,"next",c)
end
if stop == current then break end
- current = current.next
+ current = getnext(current)
end
- if base.char == c_nbsp then
+ if getchar(base) == c_nbsp then
nbspaces = nbspaces - 1
head = remove_node(head, base)
free_node(base)
@@ -1740,30 +1756,30 @@ for k, v in next, halant do separator[k] = true end
local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowel
-- why two variants ... the comment suggests that it's the same ruleset
- local n = c.next
+ local n = getnext(c)
if not n then
return c
end
if variant == 1 then
- local v = n.id == glyph_code and n.subtype<256 and n.font == font
- if v and nukta[n.char] then
- n = n.next
+ local v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
+ if v and nukta[getchar(n)] then
+ n = getnext(n)
if n then
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
end
end
if n and v then
- local nn = n.next
- if nn and nn.id == glyph_code and nn.subtype<256 and nn.font == font then
- local nnn = nn.next
- if nnn and nnn.id == glyph_code and nnn.subtype<256 and nnn.font == font then
- local nnc = nn.char
- local nnnc = nnn.char
+ local nn = getnext(n)
+ if nn and getid(nn) == glyph_code and getsubtype(nn) < 256 and getfont(nn) == font then
+ local nnn = getnext(nn)
+ if nnn and getid(nnn) == glyph_code and getsubtype(nnn) < 256 and getfont(nnn) == font then
+ local nnc = getchar(nn)
+ local nnnc = getchar(nnn)
if nnc == c_zwj and consonant[nnnc] then
c = nnn
elseif (nnc == c_zwnj or nnc == c_zwj) and halant[nnnc] then
- local nnnn = nnn.next
- if nnnn and nnnn.id == glyph_code and consonant[nnnn.char] and nnnn.subtype<256 and nnnn.font == font then
+ local nnnn = getnext(nnn)
+ if nnnn and getid(nnnn) == glyph_code and consonant[getchar(nnnn)] and getsubtype(nnnn) < 256 and getfont(nnnn) == font then
c = nnnn
end
end
@@ -1771,94 +1787,94 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
end
elseif variant == 2 then
- if n.id == glyph_code and nukta[n.char] and n.subtype<256 and n.font == font then
+ if getid(n) == glyph_code and nukta[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
c = n
end
- n = c.next
- if n and n.id == glyph_code and n.subtype<256 and n.font == font then
- local nn = n.next
+ n = getnext(c)
+ if n and getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font then
+ local nn = getnext(n)
if nn then
- local nv = nn.id == glyph_code and nn.subtype<256 and nn.font == font
- if nv and zw_char[n.char] then
+ local nv = getid(nn) == glyph_code and getsubtype(nn) < 256 and getfont(nn) == font
+ if nv and zw_char[getchar(n)] then
n = nn
- nn = nn.next
- nv = nn and nn.id == glyph_code and nn.subtype<256 and nn.font == font
+ nn = getnext(nn)
+ nv = nn and getid(nn) == glyph_code and getsubtype(nn) < 256 and getfont(nn) == font
end
- if nv and halant[n.char] and consonant[nn.char] then
+ if nv and halant[getchar(n)] and consonant[getchar(nn)] then
c = nn
end
end
end
end
-- c = ms_matra(c)
- local n = c.next
+ local n = getnext(c)
if not n then
return c
end
- local v = n.id == glyph_code and n.subtype<256 and n.font == font
+ local v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- local char = n.char
+ local char = getchar(n)
if dependent_vowel[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if nukta[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if halant[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if vowel_modifier[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if stress_tone_mark[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if stress_tone_mark[char] then
return n
@@ -1868,38 +1884,38 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
end
local function analyze_next_chars_two(c,font)
- local n = c.next
+ local n = getnext(c)
if not n then
return c
end
- if n.id == glyph_code and nukta[n.char] and n.subtype<256 and n.font == font then
+ if getid(n) == glyph_code and nukta[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
c = n
end
n = c
while true do
- local nn = n.next
- if nn and nn.id == glyph_code and nn.subtype<256 and nn.font == font then
- local char = nn.char
+ local nn = getnext(n)
+ if nn and getid(nn) == glyph_code and getsubtype(nn) < 256 and getfont(nn) == font then
+ local char = getchar(nn)
if halant[char] then
n = nn
- local nnn = nn.next
- if nnn and nnn.id == glyph_code and zw_char[nnn.char] and nnn.subtype<256 and nnn.font == font then
+ local nnn = getnext(nn)
+ if nnn and getid(nnn) == glyph_code and zw_char[getchar(nnn)] and getsubtype(nnn) < 256 and getfont(nnn) == font then
n = nnn
end
elseif char == c_zwnj or char == c_zwj then
-- n = nn -- not here (?)
- local nnn = nn.next
- if nnn and nnn.id == glyph_code and halant[nnn.char] and nnn.subtype<256 and nnn.font == font then
+ local nnn = getnext(nn)
+ if nnn and getid(nnn) == glyph_code and halant[getchar(nnn)] and getsubtype(nnn) < 256 and getfont(nnn) == font then
n = nnn
end
else
break
end
- local nn = n.next
- if nn and nn.id == glyph_code and consonant[nn.char] and nn.subtype<256 and nn.font == font then
+ local nn = getnext(n)
+ if nn and getid(nn) == glyph_code and consonant[getchar(nn)] and getsubtype(nn) < 256 and getfont(nn) == font then
n = nn
- local nnn = nn.next
- if nnn and nnn.id == glyph_code and nukta[nnn.char] and nnn.subtype<256 and nnn.font == font then
+ local nnn = getnext(nn)
+ if nnn and getid(nnn) == glyph_code and nukta[getchar(nnn)] and getsubtype(nnn) < 256 and getfont(nnn) == font then
n = nnn
end
c = n
@@ -1915,114 +1931,114 @@ local function analyze_next_chars_two(c,font)
-- This shouldn't happen I guess.
return
end
- local n = c.next
+ local n = getnext(c)
if not n then
return c
end
- local v = n.id == glyph_code and n.subtype<256 and n.font == font
+ local v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- local char = n.char
+ local char = getchar(n)
if char == c_anudatta then
c = n
- n = c.next
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if halant[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
if char == c_zwnj or char == c_zwj then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
else
-- c = ms_matra(c)
-- same as one
if dependent_vowel[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if nukta[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if halant[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
end
-- same as one
if vowel_modifier[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if stress_tone_mark[char] then
- c = c.next
- n = c.next
+ c = getnext(c)
+ n = getnext(c)
if not n then
return c
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
return c
end
- char = n.char
+ char = getchar(n)
end
if stress_tone_mark[char] then
return n
@@ -2034,9 +2050,9 @@ end
local function inject_syntax_error(head,current,mark)
local signal = copy_node(current)
if mark == pre_mark then
- signal.char = dotted_circle
+ setfield(signal,"char",dotted_circle)
else
- current.char = dotted_circle
+ setfield(current,"char",dotted_circle)
end
return insert_node_after(head,current,signal)
end
@@ -2045,31 +2061,32 @@ end
-- a lot. Common code has been synced.
function methods.deva(head,font,attr)
+ head = tonut(head)
local current = head
local start = true
local done = false
local nbspaces = 0
while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font then
+ if getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font then
done = true
local syllablestart = current
local syllableend = nil
local c = current
- local n = c.next
- if n and ra[c.char] and n.id == glyph_code and halant[n.char] and n.subtype<256 and n.font == font then
- local n = n.next
- if n and n.id == glyph_code and n.subtype<256 and n.font == font then
+ local n = getnext(c)
+ if n and ra[getchar(c)] and getid(n) == glyph_code and halant[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
+ local n = getnext(n)
+ if n and getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font then
c = n
end
end
- local standalone = c.char == c_nbsp
+ local standalone = getchar(c) == c_nbsp
if standalone then
- local prev = current.prev
+ local prev = getprev(current)
if not prev then
-- begin of paragraph or box
- elseif prev.id ~= glyph_code or prev.subtype>=256 or prev.font ~= font then
+ elseif getid(prev) ~= glyph_code or getsubtype(prev) >= 256 or getfont(prev) ~= font then
-- different font or language so quite certainly a different word
- elseif not separator[prev.char] then
+ elseif not separator[getchar(prev)] then
-- something that separates words
else
standalone = false
@@ -2078,61 +2095,61 @@ function methods.deva(head,font,attr)
if standalone then
-- stand alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
local syllableend = analyze_next_chars_one(c,font,2)
- current = syllableend.next
+ current = getnext(syllableend)
if syllablestart ~= syllableend then
head, current, nbspaces = deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
- current = current.next
+ current = getnext(current)
end
else
- -- we can delay the n.subtype and n.font and test for say halant first
+ -- we can delay the getsubtype(n) and getfont(n) and test for say halant first
-- as an table access is faster than two function calls (subtype and font are
-- pseudo fields) but the code becomes messy (unless we make it a function)
- local char = current.char
+ local char = getchar(current)
if consonant[char] then
-- syllable containing consonant
local prevc = true
while prevc do
prevc = false
- local n = current.next
+ local n = getnext(current)
if not n then
break
end
- local v = n.id == glyph_code and n.subtype<256 and n.font == font
+ local v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
break
end
- local c = n.char
+ local c = getchar(n)
if nukta[c] then
- n = n.next
+ n = getnext(n)
if not n then
break
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
break
end
- c = n.char
+ c = getchar(n)
end
if halant[c] then
- n = n.next
+ n = getnext(n)
if not n then
break
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
break
end
- c = n.char
+ c = getchar(n)
if c == c_zwnj or c == c_zwj then
- n = n.next
+ n = getnext(n)
if not n then
break
end
- v = n.id == glyph_code and n.subtype<256 and n.font == font
+ v = getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font
if not v then
break
end
- c = n.char
+ c = getchar(n)
end
if consonant[c] then
prevc = true
@@ -2140,77 +2157,77 @@ function methods.deva(head,font,attr)
end
end
end
- local n = current.next
- if n and n.id == glyph_code and nukta[n.char] and n.subtype<256 and n.font == font then
+ local n = getnext(current)
+ if n and getid(n) == glyph_code and nukta[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
-- nukta (not specified in Microsft Devanagari OpenType specification)
current = n
- n = current.next
+ n = getnext(current)
end
syllableend = current
current = n
if current then
- local v = current.id == glyph_code and current.subtype<256 and current.font == font
+ local v = getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font
if v then
- if halant[current.char] then
+ if halant[getchar(current)] then
-- syllable containing consonant without vowels: {C + [Nukta] + H} + C + H
- local n = current.next
- if n and n.id == glyph_code and zw_char[n.char] and n.subtype<256 and n.font == font then
+ local n = getnext(current)
+ if n and getid(n) == glyph_code and zw_char[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
-- code collapsed, probably needs checking with intention
syllableend = n
- current = n.next
+ current = getnext(n)
else
syllableend = current
current = n
end
else
-- syllable containing consonant with vowels: {C + [Nukta] + H} + C + [M] + [VM] + [SM]
- local c = current.char
+ local c = getchar(current)
if dependent_vowel[c] then
syllableend = current
- current = current.next
- v = current and current.id == glyph_code and current.subtype<256 and current.font == font
+ current = getnext(current)
+ v = current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font
if v then
- c = current.char
+ c = getchar(current)
end
end
if v and vowel_modifier[c] then
syllableend = current
- current = current.next
- v = current and current.id == glyph_code and current.subtype<256 and current.font == font
+ current = getnext(current)
+ v = current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font
if v then
- c = current.char
+ c = getchar(current)
end
end
if v and stress_tone_mark[c] then
syllableend = current
- current = current.next
+ current = getnext(current)
end
end
end
end
if syllablestart ~= syllableend then
head, current, nbspaces = deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
- current = current.next
+ current = getnext(current)
end
elseif independent_vowel[char] then
-- syllable without consonants: VO + [VM] + [SM]
syllableend = current
- current = current.next
+ current = getnext(current)
if current then
- local v = current.id == glyph_code and current.subtype<256 and current.font == font
+ local v = getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font
if v then
- local c = current.char
+ local c = getchar(current)
if vowel_modifier[c] then
syllableend = current
- current = current.next
- v = current and current.id == glyph_code and current.subtype<256 and current.font == font
+ current = getnext(current)
+ v = current and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font
if v then
- c = current.char
+ c = getchar(current)
end
end
if v and stress_tone_mark[c] then
syllableend = current
- current = current.next
+ current = getnext(current)
end
end
end
@@ -2219,11 +2236,11 @@ function methods.deva(head,font,attr)
if mark then
head, current = inject_syntax_error(head,current,mark)
end
- current = current.next
+ current = getnext(current)
end
end
else
- current = current.next
+ current = getnext(current)
end
start = false
end
@@ -2232,7 +2249,7 @@ function methods.deva(head,font,attr)
head = replace_all_nbsp(head)
end
- head = typesetters.characters.handler(head)
+ head = tonode(head)
return head, done
end
@@ -2243,6 +2260,7 @@ end
-- handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1)
function methods.dev2(head,font,attr)
+ head = tonut(head)
local current = head
local start = true
local done = false
@@ -2250,18 +2268,18 @@ function methods.dev2(head,font,attr)
local nbspaces = 0
while current do
local syllablestart, syllableend = nil, nil
- if current.id == glyph_code and current.subtype<256 and current.font == font then
+ if getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font then
done = true
syllablestart = current
local c = current
- local n = current.next
- if n and ra[c.char] and n.id == glyph_code and halant[n.char] and n.subtype<256 and n.font == font then
- local n = n.next
- if n and n.id == glyph_code and n.subtype<256 and n.font == font then
+ local n = getnext(current)
+ if n and ra[getchar(c)] and getid(n) == glyph_code and halant[getchar(n)] and getsubtype(n) < 256 and getfont(n) == font then
+ local n = getnext(n)
+ if n and getid(n) == glyph_code and getsubtype(n) < 256 and getfont(n) == font then
c = n
end
end
- local char = c.char
+ local char = getchar(c)
if independent_vowel[char] then
-- vowel-based syllable: [Ra+H]+V+[N]+[<[<ZWJ|ZWNJ>]+H+C|ZWJ+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
current = analyze_next_chars_one(c,font,1)
@@ -2270,12 +2288,12 @@ function methods.dev2(head,font,attr)
local standalone = char == c_nbsp
if standalone then
nbspaces = nbspaces + 1
- local p = current.prev
+ local p = getprev(current)
if not p then
-- begin of paragraph or box
- elseif p.id ~= glyph_code or p.subtype>=256 or p.font ~= font then
+ elseif getid(p) ~= glyph_code or getsubtype(p) >= 256 or getfont(p) ~= font then
-- different font or language so quite certainly a different word
- elseif not separator[p.char] then
+ elseif not separator[getchar(p)] then
-- something that separates words
else
standalone = false
@@ -2285,7 +2303,7 @@ function methods.dev2(head,font,attr)
-- Stand Alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
current = analyze_next_chars_one(c,font,2)
syllableend = current
- elseif consonant[current.char] then
+ elseif consonant[getchar(current)] then
-- WHY current INSTEAD OF c ?
-- Consonant syllable: {C+[N]+<H+[<ZWNJ|ZWJ>]|<ZWNJ|ZWJ>+H>} + C+[N]+[A] + [< H+[<ZWNJ|ZWJ>] | {M}+[N]+[H]>]+[SM]+[(VD)]
@@ -2297,29 +2315,31 @@ function methods.dev2(head,font,attr)
if syllableend then
syllabe = syllabe + 1
local c = syllablestart
- local n = syllableend.next
+ local n = getnext(syllableend)
while c ~= n do
- c[a_syllabe] = syllabe
- c = c.next
+ setattr(c,a_syllabe,syllabe)
+ c = getnext(c)
end
end
if syllableend and syllablestart ~= syllableend then
head, current, nbspaces = dev2_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
end
- if not syllableend and current.id == glyph_code and current.subtype<256 and current.font == font and not current[a_state] then
- local mark = mark_four[current.char]
+ if not syllableend and getid(current) == glyph_code and getsubtype(current) < 256 and getfont(current) == font and not getattr(current,a_state) then
+ local mark = mark_four[getchar(current)]
if mark then
head, current = inject_syntax_error(head,current,mark)
end
end
start = false
- current = current.next
+ current = getnext(current)
end
if nbspaces > 0 then
head = replace_all_nbsp(head)
end
+ head = tonode(head)
+
return head, done
end
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index c57be5f02..7a5ae1758 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -171,12 +171,28 @@ registertracker("otf.injections","nodes.injections")
registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local insert_node_after = node.insert_after
-local delete_node = nodes.delete
-local copy_node = node.copy
-local find_node_tail = node.tail or node.slide
-local flush_node_list = node.flush_list
-local end_of_math = node.end_of_math
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local insert_node_after = nuts.insert_after
+local delete_node = nuts.delete
+local copy_node = nuts.copy
+local find_node_tail = nuts.tail
+local flush_node_list = nuts.flush_list
+local end_of_math = nuts.end_of_math
local setmetatableindex = table.setmetatableindex
@@ -332,11 +348,11 @@ end
-- and indices.
local function copy_glyph(g) -- next and prev are untouched !
- local components = g.components
+ local components = getfield(g,"components")
if components then
- g.components = nil
+ setfield(g,"components",nil)
local n = copy_node(g)
- g.components = components
+ setfield(g,"components",components)
return n
else
return copy_node(g)
@@ -346,28 +362,28 @@ end
-- start is a mark and we need to keep that one
local function markstoligature(kind,lookupname,head,start,stop,char)
- if start == stop and start.char == char then
+ if start == stop and getchar(start) == char then
return head, start
else
- local prev = start.prev
- local next = stop.next
- start.prev = nil
- stop.next = nil
+ local prev = getprev(start)
+ local next = getnext(stop)
+ setfield(start,"prev",nil)
+ setfield(stop,"next",nil)
local base = copy_glyph(start)
if head == start then
head = base
end
- base.char = char
- base.subtype = ligature_code
- base.components = start
+ setfield(base,"char",char)
+ setfield(base,"subtype",ligature_code)
+ setfield(base,"components",start)
if prev then
- prev.next = base
+ setfield(prev,"next",base)
end
if next then
- next.prev = base
+ setfield(next,"prev",base)
end
- base.next = next
- base.prev = prev
+ setfield(base,"next",next)
+ setfield(base,"prev",prev)
return head, base
end
end
@@ -380,17 +396,17 @@ end
-- third component.
local function getcomponentindex(start)
- if start.id ~= glyph_code then
+ if getid(start) ~= glyph_code then
return 0
- elseif start.subtype == ligature_code then
+ elseif getsubtype(start) == ligature_code then
local i = 0
- local components = start.components
+ local components = getfield(start,"components")
while components do
i = i + getcomponentindex(components)
- components = components.next
+ components = getnext(components)
end
return i
- elseif not marks[start.char] then
+ elseif not marks[getchar(start)] then
return 1
else
return 0
@@ -400,29 +416,29 @@ end
-- eventually we will do positioning in an other way (needs addional w/h/d fields)
local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head
- if start == stop and start.char == char then
- start.char = char
+ if start == stop and getchar(start) == char then
+ setfield(start,"char",char)
return head, start
end
- local prev = start.prev
- local next = stop.next
- start.prev = nil
- stop.next = nil
+ local prev = getprev(start)
+ local next = getnext(stop)
+ setfield(start,"prev",nil)
+ setfield(stop,"next",nil)
local base = copy_glyph(start)
if start == head then
head = base
end
- base.char = char
- base.subtype = ligature_code
- base.components = start -- start can have components
+ setfield(base,"char",char)
+ setfield(base,"subtype",ligature_code)
+ setfield(base,"components",start) -- start can have components
if prev then
- prev.next = base
+ setfield(prev,"next",base)
end
if next then
- next.prev = base
+ setfield(next,"prev",base)
end
- base.next = next
- base.prev = prev
+ setfield(base,"next",next)
+ setfield(base,"prev",prev)
if not discfound then
local deletemarks = markflag ~= "mark"
local components = start
@@ -432,35 +448,35 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
local current = base
-- first we loop over the glyphs in start .. stop
while start do
- local char = start.char
+ local char = getchar(start)
if not marks[char] then
baseindex = baseindex + componentindex
componentindex = getcomponentindex(start)
elseif not deletemarks then -- quite fishy
- start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
+ setattr(start,a_ligacomp,baseindex + (getattr(start,a_ligacomp) or componentindex))
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
end
head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components
elseif trace_marks then
logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
end
- start = start.next
+ start = getnext(start)
end
-- we can have one accent as part of a lookup and another following
-- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added)
- local start = current.next
- while start and start.id == glyph_code do
- local char = start.char
+ local start = getnext(current)
+ while start and getid(start) == glyph_code do
+ local char = getchar(start)
if marks[char] then
- start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
+ setattr(start,a_ligacomp,baseindex + (getattr(start,a_ligacomp) or componentindex))
if trace_marks then
- logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
+ logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
end
else
break
end
- start = start.next
+ start = getnext(start)
end
end
return head, base
@@ -468,9 +484,9 @@ end
function handlers.gsub_single(head,start,kind,lookupname,replacement)
if trace_singles then
- logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement))
end
- start.char = replacement
+ setfield(start,"char",replacement)
return head, start, true
end
@@ -497,7 +513,7 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives
return false, trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
end
elseif value == 0 then
- return start.char, trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
+ return getchar(start), trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
elseif value < 1 then
return alternatives[1], trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
else
@@ -509,30 +525,30 @@ end
local function multiple_glyphs(head,start,multiple,ignoremarks)
local nofmultiples = #multiple
if nofmultiples > 0 then
- start.char = multiple[1]
+ setfield(start,"char",multiple[1])
if nofmultiples > 1 then
- local sn = start.next
+ local sn = getnext(start)
for k=2,nofmultiples do -- todo: use insert_node
-- untested:
--
--- while ignoremarks and marks[sn.char] then
--- local sn = sn.next
+-- while ignoremarks and marks[getchar(sn)] then
+-- local sn = getnext(sn)
-- end
local n = copy_node(start) -- ignore components
- n.char = multiple[k]
- n.next = sn
- n.prev = start
+ setfield(n,"char",multiple[k])
+ setfield(n,"next",sn)
+ setfield(n,"prev",start)
if sn then
- sn.prev = n
+ setfield(sn,"prev",n)
end
- start.next = n
+ setfield(start,"next",n)
start = n
end
end
return head, start, true
else
if trace_multiples then
- logprocess("no multiple for %s",gref(start.char))
+ logprocess("no multiple for %s",gref(getchar(start)))
end
return head, start, false
end
@@ -543,12 +559,12 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence
local choice, comment = get_alternative_glyph(start,alternative,value,trace_alternatives)
if choice then
if trace_alternatives then
- logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
+ logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment)
end
- start.char = choice
+ setfield(start,"char",choice)
else
if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
+ logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment)
end
end
return head, start, true
@@ -556,23 +572,23 @@ end
function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
if trace_multiples then
- logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(getchar(start)),gref(multiple))
end
return multiple_glyphs(head,start,multiple,sequence.flags[1])
end
function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
- local s, stop, discfound = start.next, nil, false
- local startchar = start.char
+ local s, stop, discfound = getnext(start), nil, false
+ local startchar = getchar(start)
if marks[startchar] then
while s do
- local id = s.id
- if id == glyph_code and s.font == currentfont and s.subtype<256 then
- local lg = ligature[s.char]
+ local id = getid(s)
+ if id == glyph_code and getfont(s) == currentfont and getsubtype(s)<256 then
+ local lg = ligature[getchar(s)]
if lg then
stop = s
ligature = lg
- s = s.next
+ s = getnext(s)
else
break
end
@@ -584,9 +600,9 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
local lig = ligature.ligature
if lig then
if trace_ligatures then
- local stopchar = stop.char
+ local stopchar = getchar(stop)
head, start = markstoligature(kind,lookupname,head,start,stop,lig)
- logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
else
head, start = markstoligature(kind,lookupname,head,start,stop,lig)
end
@@ -598,18 +614,18 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
else
local skipmark = sequence.flags[1]
while s do
- local id = s.id
- if id == glyph_code and s.subtype<256 then
- if s.font == currentfont then
- local char = s.char
+ local id = getid(s)
+ if id == glyph_code and getsubtype(s)<256 then
+ if getfont(s) == currentfont then
+ local char = getchar(s)
if skipmark and marks[char] then
- s = s.next
+ s = getnext(s)
else
local lg = ligature[char]
if lg then
stop = s
ligature = lg
- s = s.next
+ s = getnext(s)
else
break
end
@@ -619,7 +635,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
end
elseif id == disc_code then
discfound = true
- s = s.next
+ s = getnext(s)
else
break
end
@@ -628,21 +644,20 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
if lig then
if stop then
if trace_ligatures then
- local stopchar = stop.char
+ local stopchar = getchar(stop)
head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
- logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
else
head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
end
- return head, start, true
else
-- weird but happens (in some arabic font)
- start.char = lig
+ setfield(start,"char",lig)
if trace_ligatures then
logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
end
- return head, start, true
end
+ return head, start, true
else
-- weird but happens
end
@@ -656,16 +671,16 @@ we need to explicitly test for basechar, baselig and basemark entries.</p>
--ldx]]--
function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
- local base = start.prev -- [glyph] [start=mark]
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- local basechar = base.char
+ local base = getprev(start) -- [glyph] [start=mark]
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ local basechar = getchar(base)
if marks[basechar] then
while true do
- base = base.prev
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- basechar = base.char
+ base = getprev(base)
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ basechar = getchar(base)
if not marks[basechar] then
break
end
@@ -717,16 +732,16 @@ end
function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
-- check chainpos variant
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
- local base = start.prev -- [glyph] [optional marks] [start=mark]
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- local basechar = base.char
+ local base = getprev(start) -- [glyph] [optional marks] [start=mark]
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ local basechar = getchar(base)
if marks[basechar] then
while true do
- base = base.prev
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- basechar = base.char
+ base = getprev(base)
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ basechar = getchar(base)
if not marks[basechar] then
break
end
@@ -738,7 +753,7 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
end
end
end
- local index = start[a_ligacomp]
+ local index = getattr(start,a_ligacomp)
local baseanchors = descriptions[basechar]
if baseanchors then
baseanchors = baseanchors.anchors
@@ -785,22 +800,22 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
end
function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
- local base = start.prev -- [glyph] [basemark] [start=mark]
- local slc = start[a_ligacomp]
+ local base = getprev(start) -- [glyph] [basemark] [start=mark]
+ local slc = getattr(start,a_ligacomp)
if slc then -- a rather messy loop ... needs checking with husayni
while base do
- local blc = base[a_ligacomp]
+ local blc = getattr(base,a_ligacomp)
if blc and blc ~= slc then
- base = base.prev
+ base = getprev(base)
else
break
end
end
end
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
- local basechar = base.char
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then -- subtype test can go
+ local basechar = getchar(base)
local baseanchors = descriptions[basechar]
if baseanchors then
baseanchors = baseanchors.anchors
@@ -840,21 +855,21 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
end
function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) -- to be checked
- local alreadydone = cursonce and start[a_cursbase]
+ local alreadydone = cursonce and getattr(start,a_cursbase)
if not alreadydone then
local done = false
- local startchar = start.char
+ local startchar = getchar(start)
if marks[startchar] then
if trace_cursive then
logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
end
else
- local nxt = start.next
- while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
- local nextchar = nxt.char
+ local nxt = getnext(start)
+ while not done and nxt and getid(nxt) == glyph_code and getfont(nxt) == currentfont and getsubtype(nxt)<256 do
+ local nextchar = getchar(nxt)
if marks[nextchar] then
-- should not happen (maybe warning)
- nxt = nxt.next
+ nxt = getnext(nxt)
else
local entryanchors = descriptions[nextchar]
if entryanchors then
@@ -889,14 +904,14 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
return head, start, done
else
if trace_cursive and trace_details then
- logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
end
return head, start, false
end
end
function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
- local startchar = start.char
+ local startchar = getchar(start)
local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
@@ -907,19 +922,19 @@ end
function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
-- todo: kerns in components of ligatures
- local snext = start.next
+ local snext = getnext(start)
if not snext then
return head, start, false
else
local prev, done = start, false
local factor = tfmdata.parameters.factor
local lookuptype = lookuptypes[lookupname]
- while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
- local nextchar = snext.char
+ while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
+ local nextchar = getchar(snext)
local krn = kerns[nextchar]
if not krn and marks[nextchar] then
prev = snext
- snext = snext.next
+ snext = getnext(snext)
else
if not krn then
-- skip
@@ -927,14 +942,14 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
if lookuptype == "pair" then -- probably not needed
local a, b = krn[2], krn[3]
if a and #a > 0 then
- local startchar = start.char
+ local startchar = getchar(start)
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
- local startchar = start.char
+ local startchar = getchar(start)
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -946,7 +961,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-- if a and a ~= 0 then
-- local k = setkern(snext,factor,rlmode,a)
-- if trace_kerns then
- -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
-- end
-- end
-- if b and b ~= 0 then
@@ -957,7 +972,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
elseif krn ~= 0 then
local k = setkern(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
end
done = true
end
@@ -1012,13 +1027,13 @@ end
-- itself. It is meant mostly for dealing with Urdu.
function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
- local char = start.char
+ local char = getchar(start)
local replacement = replacements[char]
if replacement then
if trace_singles then
logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
end
- start.char = replacement
+ setfield(start,"char",replacement)
return head, start, true
else
return head, start, false
@@ -1047,9 +1062,9 @@ as less as needed but that would also make the code even more messy.</p>
-- -- done
-- elseif ignoremarks then
-- repeat -- start x x m x x stop => start m
--- local next = start.next
--- if not marks[next.char] then
--- local components = next.components
+-- local next = getnext(start)
+-- if not marks[getchar(next)] then
+-- local components = getfield(next,"components")
-- if components then -- probably not needed
-- flush_node_list(components)
-- end
@@ -1059,8 +1074,8 @@ as less as needed but that would also make the code even more messy.</p>
-- until next == stop
-- else -- start x x x stop => start
-- repeat
--- local next = start.next
--- local components = next.components
+-- local next = getnext(start)
+-- local components = getfield(next,"components")
-- if components then -- probably not needed
-- flush_node_list(components)
-- end
@@ -1084,8 +1099,8 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
end
while current do
- if current.id == glyph_code then
- local currentchar = current.char
+ if getid(current) == glyph_code then
+ local currentchar = getchar(current)
local lookupname = subtables[1] -- only 1
local replacement = lookuphash[lookupname]
if not replacement then
@@ -1102,14 +1117,14 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
if trace_singles then
logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
end
- current.char = replacement
+ setfield(current,"char",replacement)
end
end
return head, start, true
elseif current == stop then
break
else
- current = current.next
+ current = getnext(current)
end
end
return head, start, false
@@ -1124,7 +1139,7 @@ the match.</p>
function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-- local head, n = delete_till_stop(head,start,stop)
- local startchar = start.char
+ local startchar = getchar(start)
local subtables = currentlookup.subtables
local lookupname = subtables[1]
local replacements = lookuphash[lookupname]
@@ -1167,8 +1182,8 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
local subtables = currentlookup.subtables
local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
while current do
- if current.id == glyph_code then -- is this check needed?
- local currentchar = current.char
+ if getid(current) == glyph_code then -- is this check needed?
+ local currentchar = getchar(current)
local lookupname = subtables[1]
local alternatives = lookuphash[lookupname]
if not alternatives then
@@ -1183,7 +1198,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
if trace_alternatives then
logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
end
- start.char = choice
+ setfield(start,"char",choice)
else
if trace_alternatives then
logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
@@ -1197,7 +1212,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
elseif current == stop then
break
else
- current = current.next
+ current = getnext(current)
end
end
return head, start, false
@@ -1212,7 +1227,7 @@ assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
- local startchar = start.char
+ local startchar = getchar(start)
local subtables = currentlookup.subtables
local lookupname = subtables[1]
local ligatures = lookuphash[lookupname]
@@ -1227,20 +1242,20 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
end
else
- local s = start.next
+ local s = getnext(start)
local discfound = false
local last = stop
local nofreplacements = 0
local skipmark = currentlookup.flags[1]
while s do
- local id = s.id
+ local id = getid(s)
if id == disc_code then
- s = s.next
+ s = getnext(s)
discfound = true
else
- local schar = s.char
+ local schar = getchar(s)
if skipmark and marks[schar] then -- marks
- s = s.next
+ s = getnext(s)
else
local lg = ligatures[schar]
if lg then
@@ -1248,7 +1263,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if s == stop then
break
else
- s = s.next
+ s = getnext(s)
end
else
break
@@ -1265,7 +1280,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if start == stop then
logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
else
- logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)),gref(l2))
end
end
head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
@@ -1274,7 +1289,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if start == stop then
logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
else
- logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)))
end
end
end
@@ -1285,7 +1300,7 @@ end
chainmores.gsub_ligature = chainprocs.gsub_ligature
function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
@@ -1294,14 +1309,14 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
markanchors = markanchors[markchar]
end
if markanchors then
- local base = start.prev -- [glyph] [start=mark]
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- local basechar = base.char
+ local base = getprev(start) -- [glyph] [start=mark]
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ local basechar = getchar(base)
if marks[basechar] then
while true do
- base = base.prev
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- basechar = base.char
+ base = getprev(base)
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ basechar = getchar(base)
if not marks[basechar] then
break
end
@@ -1349,7 +1364,7 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
end
function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
@@ -1358,14 +1373,14 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
markanchors = markanchors[markchar]
end
if markanchors then
- local base = start.prev -- [glyph] [optional marks] [start=mark]
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- local basechar = base.char
+ local base = getprev(start) -- [glyph] [optional marks] [start=mark]
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ local basechar = getchar(base)
if marks[basechar] then
while true do
- base = base.prev
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
- basechar = base.char
+ base = getprev(base)
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then
+ basechar = getchar(base)
if not marks[basechar] then
break
end
@@ -1378,7 +1393,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
end
end
-- todo: like marks a ligatures hash
- local index = start[a_ligacomp]
+ local index = getattr(start,a_ligacomp)
local baseanchors = descriptions[basechar].anchors
if baseanchors then
local baseanchors = baseanchors['baselig']
@@ -1418,9 +1433,9 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
end
function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar = start.char
+ local markchar = getchar(start)
if marks[markchar] then
- -- local alreadydone = markonce and start[a_markmark]
+ -- local alreadydone = markonce and getattr(start,a_markmark)
-- if not alreadydone then
-- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
local subtables = currentlookup.subtables
@@ -1430,20 +1445,20 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
markanchors = markanchors[markchar]
end
if markanchors then
- local base = start.prev -- [glyph] [basemark] [start=mark]
- local slc = start[a_ligacomp]
+ local base = getprev(start) -- [glyph] [basemark] [start=mark]
+ local slc = getattr(start,a_ligacomp)
if slc then -- a rather messy loop ... needs checking with husayni
while base do
- local blc = base[a_ligacomp]
+ local blc = getattr(base,a_ligacomp)
if blc and blc ~= slc then
- base = base.prev
+ base = getprev(base)
else
break
end
end
end
- if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
- local basechar = base.char
+ if base and getid(base) == glyph_code and getfont(base) == currentfont and getsubtype(base)<256 then -- subtype test can go
+ local basechar = getchar(base)
local baseanchors = descriptions[basechar].anchors
if baseanchors then
baseanchors = baseanchors['basemark']
@@ -1483,9 +1498,9 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
end
function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local alreadydone = cursonce and start[a_cursbase]
+ local alreadydone = cursonce and getattr(start,a_cursbase)
if not alreadydone then
- local startchar = start.char
+ local startchar = getchar(start)
local subtables = currentlookup.subtables
local lookupname = subtables[1]
local exitanchors = lookuphash[lookupname]
@@ -1499,12 +1514,12 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
end
else
- local nxt = start.next
- while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
- local nextchar = nxt.char
+ local nxt = getnext(start)
+ while not done and nxt and getid(nxt) == glyph_code and getfont(nxt) == currentfont and getsubtype(nxt)<256 do
+ local nextchar = getchar(nxt)
if marks[nextchar] then
-- should not happen (maybe warning)
- nxt = nxt.next
+ nxt = getnext(nxt)
else
local entryanchors = descriptions[nextchar]
if entryanchors then
@@ -1539,7 +1554,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
return head, start, done
else
if trace_cursive and trace_details then
- logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
end
return head, start, false
end
@@ -1549,7 +1564,7 @@ end
function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-- untested .. needs checking for the new model
- local startchar = start.char
+ local startchar = getchar(start)
local subtables = currentlookup.subtables
local lookupname = subtables[1]
local kerns = lookuphash[lookupname]
@@ -1570,9 +1585,9 @@ chainmores.gpos_single = chainprocs.gpos_single -- okay?
-- when machines become faster i will make a shared function
function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
- local snext = start.next
+ local snext = getnext(start)
if snext then
- local startchar = start.char
+ local startchar = getchar(start)
local subtables = currentlookup.subtables
local lookupname = subtables[1]
local kerns = lookuphash[lookupname]
@@ -1582,12 +1597,12 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
local lookuptype = lookuptypes[lookupname]
local prev, done = start, false
local factor = tfmdata.parameters.factor
- while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
- local nextchar = snext.char
+ while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
+ local nextchar = getchar(snext)
local krn = kerns[nextchar]
if not krn and marks[nextchar] then
prev = snext
- snext = snext.next
+ snext = getnext(snext)
else
if not krn then
-- skip
@@ -1595,14 +1610,14 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
if lookuptype == "pair" then
local a, b = krn[2], krn[3]
if a and #a > 0 then
- local startchar = start.char
+ local startchar = getchar(start)
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
- local startchar = start.char
+ local startchar = getchar(start)
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -1614,7 +1629,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
if a and a ~= 0 then
local k = setkern(snext,factor,rlmode,a)
if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
end
end
if b and b ~= 0 then
@@ -1625,7 +1640,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
elseif krn ~= 0 then
local k = setkern(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
end
done = true
end
@@ -1657,6 +1672,12 @@ local function show_skip(kind,chainname,char,ck,class)
end
end
+local quit_on_no_replacement = true
+
+directives.register("otf.chain.quitonnoreplacement",function(value) -- maybe per font
+ quit_on_no_replacement = value
+end)
+
local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
local flags = sequence.flags
@@ -1677,7 +1698,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
-- f..l = mid string
if s == 1 then
-- never happens
- match = current.id == glyph_code and current.font == currentfont and current.subtype<256 and seq[1][current.char]
+ match = getid(current) == glyph_code and getfont(current) == currentfont and getsubtype(current)<256 and seq[1][getchar(current)]
else
-- maybe we need a better space check (maybe check for glue or category or combination)
-- we cannot optimize for n=2 because there can be disc nodes
@@ -1692,13 +1713,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
-- match = true
else
local n = f + 1
- last = last.next
+ last = getnext(last)
while n <= l do
if last then
- local id = last.id
+ local id = getid(last)
if id == glyph_code then
- if last.font == currentfont and last.subtype<256 then
- local char = last.char
+ if getfont(last) == currentfont and getsubtype(last)<256 then
+ local char = getchar(last)
local ccd = descriptions[char]
if ccd then
local class = ccd.class
@@ -1707,10 +1728,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if trace_skips then
show_skip(kind,chainname,char,ck,class)
end
- last = last.next
+ last = getnext(last)
elseif seq[n][char] then
if n < l then
- last = last.next
+ last = getnext(last)
end
n = n + 1
else
@@ -1726,7 +1747,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- last = last.next
+ last = getnext(last)
else
match = false
break
@@ -1740,15 +1761,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
-- before
if match and f > 1 then
- local prev = start.prev
+ local prev = getprev(start)
if prev then
local n = f-1
while n >= 1 do
if prev then
- local id = prev.id
+ local id = getid(prev)
if id == glyph_code then
- if prev.font == currentfont and prev.subtype<256 then -- normal char
- local char = prev.char
+ if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char
+ local char = getchar(prev)
local ccd = descriptions[char]
if ccd then
local class = ccd.class
@@ -1779,7 +1800,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
match = false
break
end
- prev = prev.prev
+ prev = getprev(prev)
elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
n = n -1
else
@@ -1800,16 +1821,16 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
-- after
if match and s > l then
- local current = last and last.next
+ local current = last and getnext(last)
if current then
-- removed optimization for s-l == 1, we have to deal with marks anyway
local n = l + 1
while n <= s do
if current then
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- if current.font == currentfont and current.subtype<256 then -- normal char
- local char = current.char
+ if getfont(current) == currentfont and getsubtype(current)<256 then -- normal char
+ local char = getchar(current)
local ccd = descriptions[char]
if ccd then
local class = ccd.class
@@ -1840,7 +1861,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
match = false
break
end
- current = current.next
+ current = getnext(current)
elseif seq[n][32] then
n = n + 1
else
@@ -1864,7 +1885,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
-- ck == currentcontext
if trace_contexts then
local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5]
- local char = start.char
+ local char = getchar(start)
if ck[9] then
logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
@@ -1899,12 +1920,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
repeat
if skipped then
while true do
- local char = start.char
+ local char = getchar(start)
local ccd = descriptions[char]
if ccd then
local class = ccd.class
if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- start = start.next
+ start = getnext(start)
else
break
end
@@ -1938,7 +1959,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
if start then
- start = start.next
+ start = getnext(start)
else
-- weird
end
@@ -1949,7 +1970,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if replacements then
head, start, done = chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
else
- done = true -- can be meant to be skipped
+ done = quit_on_no_replacement -- can be meant to be skipped / quite inconsistent in fonts
if trace_contexts then
logprocess("%s: skipping match",cref(kind,chainname))
end
@@ -2099,12 +2120,12 @@ end
-- if ok then
-- done = true
-- end
--- if start then start = start.next end
+-- if start then start = getnext(start) end
-- else
--- start = start.next
+-- start = getnext(start)
-- end
-- else
--- start = start.next
+-- start = getnext(start)
-- end
-- there will be a new direction parser (pre-parsed etc)
@@ -2126,6 +2147,8 @@ local function featuresprocessor(head,font,attr)
return head, false
end
+ head = tonut(head)
+
if trace_steps then
checkstep(head)
end
@@ -2157,6 +2180,8 @@ local function featuresprocessor(head,font,attr)
-- Keeping track of the headnode is needed for devanagari (I generalized it a bit
-- so that multiple cases are also covered.)
+ -- todo: retain prev
+
for s=1,#datasets do
local dataset = datasets[s]
featurevalue = dataset[1] -- todo: pass to function instead of using a global
@@ -2175,10 +2200,10 @@ local function featuresprocessor(head,font,attr)
-- we need to get rid of this slide! probably no longer needed in latest luatex
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- if start.font == font and start.subtype<256 then
- local a = start[0]
+ if getfont(start) == font and getsubtype(start) < 256 then
+ local a = getattr(start,0)
if a then
a = a == attr
else
@@ -2189,7 +2214,7 @@ local function featuresprocessor(head,font,attr)
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[start.char]
+ local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
@@ -2200,15 +2225,15 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(typ,lookupname)
end
end
- if start then start = start.prev end
+ if start then start = getprev(start) end
else
- start = start.prev
+ start = getprev(start)
end
else
- start = start.prev
+ start = getprev(start)
end
else
- start = start.prev
+ start = getprev(start)
end
end
else
@@ -2228,16 +2253,16 @@ local function featuresprocessor(head,font,attr)
local head = start
local done = false
while start do
- local id = start.id
- if id == glyph_code and start.font == font and start.subtype <256 then
- local a = start[0]
+ local id = getid(start)
+ if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ local a = getattr(start,0)
if a then
- a = (a == attr) and (not attribute or start[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(start,a_state) == attribute)
else
- a = not attribute or start[a_state] == attribute
+ a = not attribute or getattr(start,a_state) == attribute
end
if a then
- local lookupmatch = lookupcache[start.char]
+ local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
-- sequence kan weg
local ok
@@ -2246,12 +2271,12 @@ local function featuresprocessor(head,font,attr)
done = true
end
end
- if start then start = start.next end
+ if start then start = getnext(start) end
else
- start = start.next
+ start = getnext(start)
end
else
- start = start.next
+ start = getnext(start)
end
end
if done then
@@ -2261,19 +2286,19 @@ local function featuresprocessor(head,font,attr)
end
local function kerndisc(disc) -- we can assume that prev and next are glyphs
- local prev = disc.prev
- local next = disc.next
+ local prev = getprev(disc)
+ local next = getnext(disc)
if prev and next then
- prev.next = next
- -- next.prev = prev
- local a = prev[0]
+ setfield(prev,"next",next)
+ -- setfield(next,"prev",prev)
+ local a = getattr(prev,0)
if a then
- a = (a == attr) and (not attribute or prev[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(prev,a_state) == attribute)
else
- a = not attribute or prev[a_state] == attribute
+ a = not attribute or getattr(prev,a_state) == attribute
end
if a then
- local lookupmatch = lookupcache[prev.char]
+ local lookupmatch = lookupcache[getchar(prev)]
if lookupmatch then
-- sequence kan weg
local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
@@ -2283,24 +2308,24 @@ local function featuresprocessor(head,font,attr)
end
end
end
- prev.next = disc
- -- next.prev = disc
+ setfield(prev,"next",disc)
+ -- setfield(next,"prev",disc)
end
return next
end
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- if start.font == font and start.subtype<256 then
- local a = start[0]
+ if getfont(start) == font and getsubtype(start) < 256 then
+ local a = getattr(start,0)
if a then
- a = (a == attr) and (not attribute or start[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(start,a_state) == attribute)
else
- a = not attribute or start[a_state] == attribute
+ a = not attribute or getattr(start,a_state) == attribute
end
if a then
- local lookupmatch = lookupcache[start.char]
+ local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
-- sequence kan weg
local ok
@@ -2309,39 +2334,39 @@ local function featuresprocessor(head,font,attr)
success = true
end
end
- if start then start = start.next end
+ if start then start = getnext(start) end
else
- start = start.next
+ start = getnext(start)
end
else
- start = start.next
+ start = getnext(start)
end
elseif id == disc_code then
-- mostly for gsub
- if start.subtype == discretionary_code then
- local pre = start.pre
+ if getsubtype(start) == discretionary_code then
+ local pre = getfield(start,"pre")
if pre then
local new = subrun(pre)
- if new then start.pre = new end
+ if new then setfield(start,"pre",new) end
end
- local post = start.post
+ local post = getfield(start,"post")
if post then
local new = subrun(post)
- if new then start.post = new end
+ if new then setfield(start,"post",new) end
end
- local replace = start.replace
+ local replace = getfield(start,"replace")
if replace then
local new = subrun(replace)
- if new then start.replace = new end
+ if new then setfield(start,"replace",new) end
end
elseif typ == "gpos_single" or typ == "gpos_pair" then
kerndisc(start)
end
- start = start.next
+ start = getnext(start)
elseif id == whatsit_code then -- will be function
- local subtype = start.subtype
+ local subtype = getsubtype(start)
if subtype == dir_code then
- local dir = start.dir
+ local dir = getfield(start,"dir")
if dir == "+TRT" or dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
@@ -2360,7 +2385,7 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype == localpar_code then
- local dir = start.dir
+ local dir = getfield(start,"dir")
if dir == "TRT" then
rlparmode = -1
elseif dir == "TLT" then
@@ -2374,11 +2399,11 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
- start = start.next
+ start = getnext(start)
elseif id == math_code then
- start = end_of_math(start).next
+ start = getnext(end_of_math(start))
else
- start = start.next
+ start = getnext(start)
end
end
end
@@ -2389,20 +2414,20 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
local head = start
local done = false
while start do
- local id = start.id
- if id == glyph_code and start.id == font and start.subtype <256 then
- local a = start[0]
+ local id = getid(start)
+ if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ local a = getattr(start,0)
if a then
- a = (a == attr) and (not attribute or start[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(start,a_state) == attribute)
else
- a = not attribute or start[a_state] == attribute
+ a = not attribute or getattr(start,a_state) == attribute
end
if a then
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[start.char]
+ local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
@@ -2419,12 +2444,12 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_missing_cache(typ,lookupname)
end
end
- if start then start = start.next end
+ if start then start = getnext(start) end
else
- start = start.next
+ start = getnext(start)
end
else
- start = start.next
+ start = getnext(start)
end
end
if done then
@@ -2434,23 +2459,23 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
end
local function kerndisc(disc) -- we can assume that prev and next are glyphs
- local prev = disc.prev
- local next = disc.next
+ local prev = getprev(disc)
+ local next = getnext(disc)
if prev and next then
- prev.next = next
- -- next.prev = prev
- local a = prev[0]
+ setfield(prev,"next",next)
+ -- setfield(next,"prev",prev)
+ local a = getattr(prev,0)
if a then
- a = (a == attr) and (not attribute or prev[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(prev,a_state) == attribute)
else
- a = not attribute or prev[a_state] == attribute
+ a = not attribute or getattr(prev,a_state) == attribute
end
if a then
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[prev.char]
+ local lookupmatch = lookupcache[getchar(prev)]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
@@ -2464,28 +2489,28 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
end
end
end
- prev.next = disc
- -- next.prev = disc
+ setfield(prev,"next",disc)
+ -- setfield(next,"prev",disc)
end
return next
end
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- if start.font == font and start.subtype<256 then
- local a = start[0]
+ if getfont(start) == font and getsubtype(start) < 256 then
+ local a = getattr(start,0)
if a then
- a = (a == attr) and (not attribute or start[a_state] == attribute)
+ a = (a == attr) and (not attribute or getattr(start,a_state) == attribute)
else
- a = not attribute or start[a_state] == attribute
+ a = not attribute or getattr(start,a_state) == attribute
end
if a then
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[start.char]
+ local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
@@ -2502,39 +2527,39 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_missing_cache(typ,lookupname)
end
end
- if start then start = start.next end
+ if start then start = getnext(start) end
else
- start = start.next
+ start = getnext(start)
end
else
- start = start.next
+ start = getnext(start)
end
elseif id == disc_code then
-- mostly for gsub
- if start.subtype == discretionary_code then
- local pre = start.pre
+ if getsubtype(start) == discretionary_code then
+ local pre = getfield(start,"pre")
if pre then
local new = subrun(pre)
- if new then start.pre = new end
+ if new then setfield(start,"pre",new) end
end
- local post = start.post
+ local post = getfield(start,"post")
if post then
local new = subrun(post)
- if new then start.post = new end
+ if new then setfield(start,"post",new) end
end
- local replace = start.replace
+ local replace = getfield(start,"replace")
if replace then
local new = subrun(replace)
- if new then start.replace = new end
+ if new then setfield(start,"replace",new) end
end
elseif typ == "gpos_single" or typ == "gpos_pair" then
kerndisc(start)
end
- start = start.next
+ start = getnext(start)
elseif id == whatsit_code then
- local subtype = start.subtype
+ local subtype = getsubtype(start)
if subtype == dir_code then
- local dir = start.dir
+ local dir = getfield(start,"dir")
if dir == "+TRT" or dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
@@ -2553,7 +2578,7 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype == localpar_code then
- local dir = start.dir
+ local dir = getfield(start,"dir")
if dir == "TRT" then
rlparmode = -1
elseif dir == "TLT" then
@@ -2566,11 +2591,11 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
- start = start.next
+ start = getnext(start)
elseif id == math_code then
- start = end_of_math(start).next
+ start = getnext(end_of_math(start))
else
- start = start.next
+ start = getnext(start)
end
end
end
@@ -2582,6 +2607,9 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
registerstep(head)
end
end
+
+ head = tonode(head)
+
return head, done
end
diff --git a/tex/context/base/font-otx.lua b/tex/context/base/font-otx.lua
index f39045223..b7d2ae0bc 100644
--- a/tex/context/base/font-otx.lua
+++ b/tex/context/base/font-otx.lua
@@ -30,15 +30,29 @@ analyzers.methods = methods
local a_state = attributes.private('state')
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local setattr = nuts.setattr
+
+local traverse_id = nuts.traverse_id
+local traverse_node_list = nuts.traverse
+local end_of_math = nuts.end_of_math
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
local math_code = nodecodes.math
-local traverse_id = node.traverse_id
-local traverse_node_list = node.traverse
-local end_of_math = node.end_of_math
-
local fontdata = fonts.hashes.identifiers
local categories = characters and characters.categories or { } -- sorry, only in context
local chardata = characters and characters.data
@@ -95,60 +109,61 @@ analyzers.useunicodemarks = false
-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
-function analyzers.setstate(head,font)
+function analyzers.setstate(head,font) -- we can skip math
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
local descriptions = tfmdata.descriptions
local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ current = tonut(current)
while current do
- local id = current.id
- if id == glyph_code and current.font == font then
+ local id = getid(current)
+ if id == glyph_code and getfont(current) == font then
done = true
- local char = current.char
+ local char = getchar(current)
local d = descriptions[char]
if d then
if d.class == "mark" then
done = true
- current[a_state] = s_mark
+ setattr(current,a_state,s_mark)
elseif useunicodemarks and categories[char] == "mn" then
done = true
- current[a_state] = s_mark
+ setattr(current,a_state,s_mark)
elseif n == 0 then
first, last, n = current, current, 1
- current[a_state] = s_init
+ setattr(current,a_state,s_init)
else
last, n = current, n+1
- current[a_state] = s_medi
+ setattr(current,a_state,s_medi)
end
else -- finish
if first and first == last then
- last[a_state] = s_isol
+ setattr(last,a_state,s_isol)
elseif last then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
end
first, last, n = nil, nil, 0
end
elseif id == disc_code then
-- always in the middle
- current[a_state] = s_medi
+ setattr(current,a_state,s_medi)
last = current
else -- finish
if first and first == last then
- last[a_state] = s_isol
+ setattr(last,a_state,s_isol)
elseif last then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
end
first, last, n = nil, nil, 0
if id == math_code then
current = end_of_math(current)
end
end
- current = current.next
+ current = getnext(current)
end
if first and first == last then
- last[a_state] = s_isol
+ setattr(last,a_state,s_isol)
elseif last then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
end
return head, done
end
@@ -209,7 +224,7 @@ methods.latn = analyzers.setstate
local arab_warned = { }
local function warning(current,what)
- local char = current.char
+ local char = getchar(current)
if not arab_warned[char] then
log.report("analyze","arab: character %C has no %a class",char,what)
arab_warned[char] = true
@@ -261,94 +276,95 @@ function methods.arab(head,font,attr)
local first, last = nil, nil
local c_first, c_last = nil, nil
local current, done = head, false
+ current = tonut(current)
while current do
- local id = current.id
- if id == glyph_code and current.font == font and current.subtype<256 and not current[a_state] then
+ local id = getid(current)
+ if id == glyph_code and getfont(current) == font and getsubtype(current)<256 and not getattr(current,a_state) then
done = true
- local char = current.char
+ local char = getchar(current)
local classifier = classifiers[char]
if not classifier then
if last then
if c_last == s_medi or c_last == s_fina then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
else
warning(last,"fina")
- last[a_state] = s_error
+ setattr(last,a_state,s_error)
end
first, last = nil, nil
elseif first then
if c_first == s_medi or c_first == s_fina then
- first[a_state] = s_isol
+ setattr(first,a_state,s_isol)
else
warning(first,"isol")
- first[a_state] = s_error
+ setattr(first,a_state,s_error)
end
first = nil
end
elseif classifier == s_mark then
- current[a_state] = s_mark
+ setattr(current,a_state,s_mark)
elseif classifier == s_isol then
if last then
if c_last == s_medi or c_last == s_fina then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
else
warning(last,"fina")
- last[a_state] = s_error
+ setattr(last,a_state,s_error)
end
first, last = nil, nil
elseif first then
if c_first == s_medi or c_first == s_fina then
- first[a_state] = s_isol
+ setattr(first,a_state,s_isol)
else
warning(first,"isol")
- first[a_state] = s_error
+ setattr(first,a_state,s_error)
end
first = nil
end
- current[a_state] = s_isol
+ setattr(current,a_state,s_isol)
elseif classifier == s_medi then
if first then
last = current
c_last = classifier
- current[a_state] = s_medi
+ setattr(current,a_state,s_medi)
else
- current[a_state] = s_init
+ setattr(current,a_state,s_init)
first = current
c_first = classifier
end
elseif classifier == s_fina then
if last then
- if last[a_state] ~= s_init then
- last[a_state] = s_medi
+ if getattr(last,a_state) ~= s_init then
+ setattr(last,a_state,s_medi)
end
- current[a_state] = s_fina
+ setattr(current,a_state,s_fina)
first, last = nil, nil
elseif first then
- -- if first[a_state] ~= s_init then
+ -- if getattr(first,a_state) ~= s_init then
-- -- needs checking
- -- first[a_state] = s_medi
+ -- setattr(first,a_state,s_medi)
-- end
- current[a_state] = s_fina
+ setattr(current,a_state,s_fina)
first = nil
else
- current[a_state] = s_isol
+ setattr(current,a_state,s_isol)
end
else -- classifier == s_rest
- current[a_state] = s_rest
+ setattr(current,a_state,s_rest)
if last then
if c_last == s_medi or c_last == s_fina then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
else
warning(last,"fina")
- last[a_state] = s_error
+ setattr(last,a_state,s_error)
end
first, last = nil, nil
elseif first then
if c_first == s_medi or c_first == s_fina then
- first[a_state] = s_isol
+ setattr(first,a_state,s_isol)
else
warning(first,"isol")
- first[a_state] = s_error
+ setattr(first,a_state,s_error)
end
first = nil
end
@@ -356,18 +372,18 @@ function methods.arab(head,font,attr)
else
if last then
if c_last == s_medi or c_last == s_fina then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
else
warning(last,"fina")
- last[a_state] = s_error
+ setattr(last,a_state,s_error)
end
first, last = nil, nil
elseif first then
if c_first == s_medi or c_first == s_fina then
- first[a_state] = s_isol
+ setattr(first,a_state,s_isol)
else
warning(first,"isol")
- first[a_state] = s_error
+ setattr(first,a_state,s_error)
end
first = nil
end
@@ -375,21 +391,21 @@ function methods.arab(head,font,attr)
current = end_of_math(current)
end
end
- current = current.next
+ current = getnext(current)
end
if last then
if c_last == s_medi or c_last == s_fina then
- last[a_state] = s_fina
+ setattr(last,a_state,s_fina)
else
warning(last,"fina")
- last[a_state] = s_error
+ setattr(last,a_state,s_error)
end
elseif first then
if c_first == s_medi or c_first == s_fina then
- first[a_state] = s_isol
+ setattr(first,a_state,s_isol)
else
warning(first,"isol")
- first[a_state] = s_error
+ setattr(first,a_state,s_error)
end
end
return head, done
diff --git a/tex/context/base/font-sol.lua b/tex/context/base/font-sol.lua
index 9ccfd0588..a41e4a679 100644
--- a/tex/context/base/font-sol.lua
+++ b/tex/context/base/font-sol.lua
@@ -48,19 +48,41 @@ local v_split = variables.split
local settings_to_array = utilities.parsers.settings_to_array
local settings_to_hash = utilities.parsers.settings_to_hash
-local find_node_tail = node.tail or node.slide
-local free_node = node.free
-local free_nodelist = node.flush_list
-local copy_nodelist = node.copy_list
-local traverse_nodes = node.traverse
-local traverse_ids = node.traverse_id
-local protect_glyphs = nodes.handlers.protectglyphs or node.protect_glyphs
-local hpack_nodes = node.hpack
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local repack_hlist = nodes.repackhlist
+local tasks = nodes.tasks
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getlist = nuts.getlist
+
+local find_node_tail = nuts.tail
+local free_node = nuts.free
+local free_nodelist = nuts.flush_list
+local copy_nodelist = nuts.copy_list
+local traverse_nodes = nuts.traverse
+local traverse_ids = nuts.traverse_id
+local hpack_nodes = nuts.hpack
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local protect_glyphs = nuts.protect_glyphs
+
+local repack_hlist = nuts.repackhlist
+
local nodes_to_utf = nodes.listtoutf
+----- protect_glyphs = nodes.handlers.protectglyphs
+
local setnodecolor = nodes.tracers.colors.set
local nodecodes = nodes.nodecodes
@@ -79,8 +101,7 @@ local localpar_code = whatsitcodes.localpar
local dir_code = whatsitcodes.dir
local userdefined_code = whatsitcodes.userdefined
-local nodepool = nodes.pool
-local tasks = nodes.tasks
+local nodepool = nuts.pool
local usernodeids = nodepool.userids
local new_textdir = nodepool.textdir
@@ -90,7 +111,7 @@ local new_leftskip = nodepool.leftskip
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
-local process_characters = nodes.handlers.characters
+----- process_characters = nodes.handlers.characters
local inject_kerns = nodes.injections.handler
local fonthashes = fonts.hashes
@@ -317,11 +338,12 @@ end)
function splitters.split(head)
-- quite fast
+ head = tonut(head)
local current, done, rlmode, start, stop, attribute = head, false, false, nil, nil, 0
cache, max_less, max_more = { }, 0, 0
local function flush() -- we can move this
- local font = start.font
- local last = stop.next
+ local font = getfont(start)
+ local last = getnext(stop)
local list = last and copy_nodelist(start,last) or copy_nodelist(start)
local n = #cache + 1
if encapsulate then
@@ -332,18 +354,18 @@ function splitters.split(head)
else
local current = start
while true do
- current[a_word] = n
+ setattr(current,a_word,n)
if current == stop then
break
else
- current = current.next
+ current = getnext(current)
end
end
end
if rlmode == "TRT" or rlmode == "+TRT" then
local dirnode = new_textdir("+TRT")
- list.prev = dirnode
- dirnode.next = list
+ setfield(list,"prev",dirnode)
+ setfield(dirnode,"next",list)
list = dirnode
end
local c = {
@@ -364,11 +386,11 @@ function splitters.split(head)
start, stop, done = nil, nil, true
end
while current do -- also nextid
- local next = current.next
- local id = current.id
+ local next = getnext(current)
+ local id = getid(current)
if id == glyph_code then
- if current.subtype < 256 then
- local a = current[a_split]
+ if getsubtype(current) < 256 then
+ local a = getattr(current,a_split)
if not a then
start, stop = nil, nil
elseif not start then
@@ -384,7 +406,7 @@ function splitters.split(head)
if start then
flush()
end
- elseif start and next and next.id == glyph_code and next.subtype < 256 then
+ elseif start and next and getid(next) == glyph_code and getsubtype(next) < 256 then
-- beware: we can cross future lines
stop = next
else
@@ -394,9 +416,9 @@ function splitters.split(head)
if start then
flush()
end
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == dir_code or subtype == localpar_code then
- rlmode = current.dir
+ rlmode = getfield(current,"dir")
end
else
if start then
@@ -410,17 +432,17 @@ function splitters.split(head)
end
nofparagraphs = nofparagraphs + 1
nofwords = nofwords + #cache
- return head, done
+ return tonode(head), done
end
local function collect_words(list) -- can be made faster for attributes
local words, w, word = { }, 0, nil
if encapsulate then
for current in traverse_ids(whatsit_code,list) do
- if current.subtype == userdefined_code then -- hm
- local user_id = current.user_id
+ if getsubtype(current) == userdefined_code then -- hm
+ local user_id = getfield(current,"user_id")
if user_id == splitter_one then
- word = { current.value, current, current }
+ word = { getfield(current,"value"), current, current }
w = w + 1
words[w] = word
elseif user_id == splitter_two then
@@ -436,9 +458,9 @@ local function collect_words(list) -- can be made faster for attributes
local current, first, last, index = list, nil, nil, nil
while current do
-- todo: disc and kern
- local id = current.id
+ local id = getid(current)
if id == glyph_code or id == disc_code then
- local a = current[a_word]
+ local a = getattr(current,a_word)
if a then
if a == index then
-- same word
@@ -471,7 +493,7 @@ local function collect_words(list) -- can be made faster for attributes
report_splitters("skipped: %C",current.char)
end
end
- elseif id == kern_code and (current.subtype == fontkern_code or current[a_fontkern]) then
+ elseif id == kern_code and (getsubtype(current) == fontkern_code or getattr(current,a_fontkern)) then
if first then
last = current
else
@@ -489,7 +511,7 @@ local function collect_words(list) -- can be made faster for attributes
end
end
end
- current = current.next
+ current = getnext(current)
end
if index then
w = w + 1
@@ -520,8 +542,8 @@ local function doit(word,list,best,width,badness,line,set,listdir)
if found then
local h, t
if encapsulate then
- h = word[2].next -- head of current word
- t = word[3].prev -- tail of current word
+ h = getnext(word[2]) -- head of current word
+ t = getprev(word[3]) -- tail of current word
else
h = word[2]
t = word[3]
@@ -536,7 +558,7 @@ local function doit(word,list,best,width,badness,line,set,listdir)
ok = true
break
else
- c = c.next
+ c = getnext(c)
end
end
if not ok then
@@ -555,19 +577,20 @@ local function doit(word,list,best,width,badness,line,set,listdir)
local first = copy_nodelist(original)
if not trace_colors then
for n in traverse_nodes(first) do -- maybe fast force so no attr needed
- n[0] = featurenumber -- this forces dynamics
+ setattr(n,0,featurenumber) -- this forces dynamics
end
elseif set == "less" then
for n in traverse_nodes(first) do
setnodecolor(n,"font:isol") -- yellow
- n[0] = featurenumber
+ setattr(n,0,featurenumber)
end
else
for n in traverse_nodes(first) do
setnodecolor(n,"font:medi") -- green
- n[0] = featurenumber
+ setattr(n,0,featurenumber)
end
end
+first = tonode(first)
local font = found.font
local setdynamics = setfontdynamics[font]
if setdynamics then
@@ -579,20 +602,21 @@ local function doit(word,list,best,width,badness,line,set,listdir)
report_solutions("fatal error, no dynamics for font %a",font)
end
first = inject_kerns(first)
- if first.id == whatsit_code then
+first = tonut(first)
+ if getid(first) == whatsit_code then
local temp = first
- first = first.next
+ first = getnext(first)
free_node(temp)
end
local last = find_node_tail(first)
-- replace [u]h->t by [u]first->last
- local prev = h.prev
- local next = t.next
- prev.next = first
- first.prev = prev
+ local prev = getprev(h)
+ local next = getnext(t)
+ setfield(prev,"next",first)
+ setfield(first,"prev",prev)
if next then
- last.next = next
- next.prev = last
+ setfield(last,"next",next)
+ setfield(next,"prev",last)
end
-- check new pack
local temp, b = repack_hlist(list,width,'exactly',listdir)
@@ -601,22 +625,22 @@ local function doit(word,list,best,width,badness,line,set,listdir)
report_optimizers("line %a, badness before %a, after %a, criterium %a, verdict %a",line,badness,b,criterium,"quit")
end
-- remove last insert
- prev.next = h
- h.prev = prev
+ setfield(prev,"next",h)
+ setfield(h,"prev",prev)
if next then
- t.next = next
- next.prev = t
+ setfield(t,"next",next)
+ setfield(next,"prev",t)
else
- t.next = nil
+ setfield(t,"next",nil)
end
- last.next = nil
+ setfield(last,"next",nil)
free_nodelist(first)
else
if trace_optimize then
report_optimizers("line %a, badness before: %a, after %a, criterium %a, verdict %a",line,badness,b,criterium,"continue")
end
-- free old h->t
- t.next = nil
+ setfield(t,"next",nil)
free_nodelist(h) -- somhow fails
if not encapsulate then
word[2] = first
@@ -697,9 +721,9 @@ variants[v_random] = function(words,list,best,width,badness,line,set,listdir)
end
local function show_quality(current,what,line)
- local set = current.glue_set
- local sign = current.glue_sign
- local order = current.glue_order
+ local set = getfield(current,"glue_set")
+ local sign = getfield(current,"glue_sign")
+ local order = getfield(current,"glue_order")
local amount = set * ((sign == 2 and -1) or 1)
report_optimizers("line %a, category %a, amount %a, set %a, sign %a, how %a, order %a",line,what,amount,set,sign,how,order)
end
@@ -719,20 +743,25 @@ function splitters.optimize(head)
math.setrandomseedi(randomseed)
randomseed = nil
end
- local line = 0
- local tex_hbadness, tex_hfuzz = tex.hbadness, tex.hfuzz
- tex.hbadness, tex.hfuzz = 10000, number.maxdimen
+ local line = 0
+ local tex_hbadness = tex.hbadness
+ local tex_hfuzz = tex.hfuzz
+ tex.hbadness = 10000
+ tex.hfuzz = number.maxdimen
if trace_optimize then
report_optimizers("preroll %a, variant %a, criterium %a, cache size %a",preroll,variant,criterium,nc)
end
- for current in traverse_ids(hlist_code,head) do
- -- report_splitters("before: [%s] => %s",current.dir,nodes.tosequence(current.list,nil))
+ for current in traverse_ids(hlist_code,tonut(head)) do
line = line + 1
- local sign, dir, list, width = current.glue_sign, current.dir, current.list, current.width
- if not encapsulate and list.id == glyph_code then
+ local sign = getfield(current,"glue_sign")
+ local dir = getfield(current,"dir")
+ local width = getfield(current,"width")
+ local list = getlist(current)
+ if not encapsulate and getid(list) == glyph_code then
-- nasty .. we always assume a prev being there .. future luatex will always have a leftskip set
- -- current.list, list = insert_node_before(list,list,new_glue(0))
- current.list, list = insert_node_before(list,list,new_leftskip(0))
+ -- is this assignment ok ? .. needs checking
+ list = insert_node_before(list,list,new_leftskip(0)) -- new_glue(0)
+ setfield(current,"list",list)
end
local temp, badness = repack_hlist(list,width,'exactly',dir) -- it would be nice if the badness was stored in the node
if badness > 0 then
@@ -792,7 +821,7 @@ function splitters.optimize(head)
local words = collect_words(list)
for best=lastbest or 1,max do
local temp, done, changes, b = optimize(words,list,best,width,badness,line,set,dir)
- current.list = temp
+ setfield(current,"list",temp)
if trace_optimize then
report_optimizers("line %a, alternative %a, changes %a, badness %a",line,best,changes,b)
end
@@ -810,15 +839,16 @@ function splitters.optimize(head)
end
end
-- we pack inside the outer hpack and that way keep the original wd/ht/dp as bonus
- current.list = hpack_nodes(current.list,width,'exactly',listdir)
- -- report_splitters("after: [%s] => %s",temp.dir,nodes.tosequence(temp.list,nil))
+ local list = hpack_nodes(getlist(current),width,'exactly',listdir)
+ setfield(current,"list",list)
end
for i=1,nc do
local ci = cache[i]
free_nodelist(ci.original)
end
cache = { }
- tex.hbadness, tex.hfuzz = tex_hbadness, tex_hfuzz
+ tex.hbadness = tex_hbadness
+ tex.hfuzz = tex_hfuzz
stoptiming(splitters)
end
diff --git a/tex/context/base/lang-rep.lua b/tex/context/base/lang-rep.lua
deleted file mode 100644
index 31ae36e6d..000000000
--- a/tex/context/base/lang-rep.lua
+++ /dev/null
@@ -1,189 +0,0 @@
-if not modules then modules = { } end modules ['lang-rep'] = {
- version = 1.001,
- comment = "companion to lang-rep.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- A BachoTeX 2013 experiment, probably not that useful. Eventually I used a simpler
--- more generic example.
-
-local utfbyte, utfsplit = utf.byte, utf.split
-
-local trace_replacements = false trackers.register("languages.replacements", function(v) trace_replacements = v end)
-local trace_detail = false trackers.register("languages.replacements.detail", function(v) trace_detail = v end)
-
-local report_replacement = logs.reporter("languages","replacements")
-
-local glyph_code = nodes.nodecodes.glyph
-
-local insert_node_before = nodes.insert_before
-local remove_node = nodes.remove
-local copy_node = nodes.copy
-
-local texsetattribute = tex.setattribute
-local unsetvalue = attributes.unsetvalue
-
-local v_reset = interfaces.variables.reset
-
-local replacements = languages.replacements or { }
-languages.replacements = replacements
-
-local a_replacements = attributes.private("replacements")
-
-local lists = { }
-local last = 0
-local trees = { }
-
-table.setmetatableindex(lists,function(lists,name)
- last = last + 1
- local list = { }
- local data = { name = name, list = list, attribute = last }
- lists[last] = data
- lists[name] = data
- trees[last] = list
- return data
-end)
-
-local function add(root,word,replacement)
- local list = utfsplit(word,true)
- for i=1,#list do
- local l = utfbyte(list[i])
- if not root[l] then
- root[l] = { }
- end
- if i == #list then
- local newlist = utfsplit(replacement,true)
- for i=1,#newlist do
- newlist[i] = utfbyte(newlist[i])
- end
- root[l].final = {
- word = word,
- replacement = replacement,
- oldlength = #list,
- newcodes = newlist,
- }
- end
- root = root[l]
- end
-end
-
-function replacements.add(category,word,replacement)
- local root = lists[category].list
- if type(word) == "table" then
- for word, replacement in next, word do
- add(root,word,replacement)
- end
- else
- add(root,word,replacement or "")
- end
-end
-
-local function hit(a,head)
- local tree = trees[a]
- if tree then
- local root = tree[head.char]
- if root then
- local current = head.next
- local lastrun = false
- local lastfinal = false
- while current and current.id == glyph_code do
- local newroot = root[current.char]
- if not newroot then
- return lastrun, lastfinal
- else
- local final = newroot.final
- if final then
- if trace_detail then
- report_replacement("hitting word %a, replacement %a",final.word,final.replacement)
- end
- lastrun = current
- lastfinal = final
- else
- root = newroot
- end
- end
- current = current.next
- end
- if lastrun then
- return lastrun, lastfinal
- end
- end
- end
-end
-
-function replacements.handler(head)
- local current = head
- local done = false
- while current do
- if current.id == glyph_code then
- local a = getattr(current,a_replacements)
- if a then
- local last, final = hit(a,current)
- if last then
- local oldlength = final.oldlength
- local newcodes = final.newcodes
- local newlength = #newcodes
- if report_replacement then
- report_replacement("replacing word %a by %a",final.word,final.replacement)
- end
- if oldlength == newlength then -- #old == #new
- for i=1,newlength do
- current.char = newcodes[i]
- current = current.next
- end
- elseif oldlength < newlength then -- #old < #new
- for i=1,newlength-oldlength do
- local n = copy_node(current)
- n.char = newcodes[i]
- head, current = insert_node_before(head,current,n)
- current = current.next
- end
- for i=newlength-oldlength+1,newlength do
- current.char = newcodes[i]
- current = current.next
- end
- else -- #old > #new
- for i=1,oldlength-newlength do
- head, current = remove_node(head,current,true)
- end
- for i=1,newlength do
- current.char = newcodes[i]
- current = current.next
- end
- end
- done = true
- end
- end
- end
- current = current.next
- end
- return head, done
-end
-
-local enabled = false
-
-function replacements.set(n) -- number or 'reset'
- if n == v_reset then
- n = unsetvalue
- else
- n = lists[n].attribute
- if not enabled then
- nodes.tasks.enableaction("processors","languages.replacements.handler")
- if trace_replacements then
- report_replacement("enabling replacement handler")
- end
- enabled = true
- end
- end
- texsetattribute(a_replacements,n)
-end
-
--- interface
-
-commands.setreplacements = replacements.set
-commands.addreplacements = replacements.add
-
-nodes.tasks.prependaction("processors","words","languages.replacements.handler")
-nodes.tasks.disableaction("processors","languages.replacements.handler")
diff --git a/tex/context/base/lang-wrd.lua b/tex/context/base/lang-wrd.lua
index bf066fc09..11d99976e 100644
--- a/tex/context/base/lang-wrd.lua
+++ b/tex/context/base/lang-wrd.lua
@@ -26,7 +26,17 @@ words.threshold = 4
local numbers = languages.numbers
local registered = languages.registered
-local traverse_nodes = node.traverse
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local traverse_nodes = nuts.traverse
+
local wordsdata = words.data
local chardata = characters.data
local tasks = nodes.tasks
@@ -96,7 +106,7 @@ end
-- there is an n=1 problem somewhere in nested boxes
local function mark_words(head,whenfound) -- can be optimized and shared
- local current, language, done = head, nil, nil, 0, false
+ local current, language, done = tonut(head), nil, nil, 0, false
local str, s, nds, n = { }, 0, { }, 0 -- n could also be a table, saves calls
local function action()
if s > 0 then
@@ -112,9 +122,9 @@ local function mark_words(head,whenfound) -- can be optimized and shared
n, s = 0, 0
end
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local a = current.lang
+ local a = getfield(current,"lang")
if a then
if a ~= language then
if s > 0 then
@@ -126,16 +136,16 @@ local function mark_words(head,whenfound) -- can be optimized and shared
action()
language = a
end
- local components = current.components
+ local components = getfield(current,"components")
if components then
n = n + 1
nds[n] = current
for g in traverse_nodes(components) do
s = s + 1
- str[s] = utfchar(g.char)
+ str[s] = utfchar(getchar(g))
end
else
- local code = current.char
+ local code = getchar(current)
local data = chardata[code]
if is_letter[data.category] then
n = n + 1
@@ -151,12 +161,12 @@ local function mark_words(head,whenfound) -- can be optimized and shared
n = n + 1
nds[n] = current
end
- elseif id == kern_code and current.subtype == kerning_code and s > 0 then
+ elseif id == kern_code and getsubtype(current) == kerning_code and s > 0 then
-- ok
elseif s > 0 then
action()
end
- current = current.next
+ current = getnext(current)
end
if s > 0 then
action()
diff --git a/tex/context/base/lpdf-nod.lua b/tex/context/base/lpdf-nod.lua
index 6b104d2fa..68d7fca90 100644
--- a/tex/context/base/lpdf-nod.lua
+++ b/tex/context/base/lpdf-nod.lua
@@ -6,21 +6,29 @@ if not modules then modules = { } end modules ['lpdf-nod'] = {
license = "see context related readme files"
}
-local formatters = string.formatters
+local type = type
-local copy_node = node.copy
-local new_node = node.new
+local formatters = string.formatters
-local nodepool = nodes.pool
-local register = nodepool.register
local whatsitcodes = nodes.whatsitcodes
local nodeinjections = backends.nodeinjections
-local pdfliteral = register(new_node("whatsit", whatsitcodes.pdfliteral)) pdfliteral.mode = 1
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local setfield = nuts.setfield
+
+local copy_node = nuts.copy
+local new_node = nuts.new
+
+local nodepool = nuts.pool
+local register = nodepool.register
+
+local pdfliteral = register(new_node("whatsit", whatsitcodes.pdfliteral)) setfield(pdfliteral,"mode",1)
local pdfsave = register(new_node("whatsit", whatsitcodes.pdfsave))
local pdfrestore = register(new_node("whatsit", whatsitcodes.pdfrestore))
local pdfsetmatrix = register(new_node("whatsit", whatsitcodes.pdfsetmatrix))
-local pdfdest = register(new_node("whatsit", whatsitcodes.pdfdest)) pdfdest.named_id = 1 -- xyz_zoom untouched
+local pdfdest = register(new_node("whatsit", whatsitcodes.pdfdest)) setfield(pdfdest,"named_id",1) -- xyz_zoom untouched
local pdfannot = register(new_node("whatsit", whatsitcodes.pdfannot))
local variables = interfaces.variables
@@ -38,14 +46,14 @@ local views = { -- beware, we do support the pdf keys but this is *not* official
function nodepool.pdfliteral(str)
local t = copy_node(pdfliteral)
- t.data = str
+ setfield(t,"data",str)
return t
end
function nodepool.pdfdirect(str)
local t = copy_node(pdfliteral)
- t.data = str
- t.mode = 1
+ setfield(t,"data",str)
+ setfield(t,"mode",1)
return t
end
@@ -57,16 +65,10 @@ function nodepool.pdfrestore()
return copy_node(pdfrestore)
end
-function nodepool.pdfsetmatrix(rx,sx,sy,ry,tx,ty)
- local t = copy_node(pdfsetmatrix)
- t.data = formatters["%s %s %s %s"](rx or 0,sx or 0,sy or 0,ry or 0) -- todo: tx ty
- return t
-end
-
-function nodepool.pdfsetmatrix(rx,sx,sy,ry,tx,ty)
+function nodepool.pdfsetmatrix(rx,sx,sy,ry,tx,ty) -- todo: tx ty
local t = copy_node(pdfsetmatrix)
if type(rx) == "string" then
- t.data = rx
+ setfield(t,"data",rx)
else
if not rx then
rx = 1
@@ -86,12 +88,12 @@ function nodepool.pdfsetmatrix(rx,sx,sy,ry,tx,ty)
end
if sx == 0 and sy == 0 then
if rx == 1 and ry == 1 then
- t.data = "1 0 0 1"
+ setfield(t,"data","1 0 0 1")
else
- t.data = formatters["%0.6f 0 0 %0.6f"](rx,ry)
+ setfield(t,"data",formatters["%0.6f 0 0 %0.6f"](rx,ry))
end
else
- t.data = formatters["%0.6f %0.6f %0.6f %0.6f"](rx,sx,sy,ry)
+ setfield(t,"data",formatters["%0.6f %0.6f %0.6f %0.6f"](rx,sx,sy,ry))
end
end
return t
@@ -104,19 +106,19 @@ nodeinjections.transform = nodepool.pdfsetmatrix
function nodepool.pdfannotation(w,h,d,data,n)
local t = copy_node(pdfannot)
if w and w ~= 0 then
- t.width = w
+ setfield(t,"width",w)
end
if h and h ~= 0 then
- t.height = h
+ setfield(t,"height",h)
end
if d and d ~= 0 then
- t.depth = d
+ setfield(t,"depth",d)
end
if n then
- t.objnum = n
+ setfield(t,"objnum",n)
end
if data and data ~= "" then
- t.data = data
+ setfield(t,"data",data)
end
return t
end
@@ -138,35 +140,36 @@ function nodepool.pdfdestination(w,h,d,name,view,n)
local t = copy_node(pdfdest)
local hasdimensions = false
if w and w ~= 0 then
- t.width = w
+ setfield(t,"width",w)
hasdimensions = true
end
if h and h ~= 0 then
- t.height = h
+ setfield(t,"height",h)
hasdimensions = true
end
if d and d ~= 0 then
- t.depth = d
+ setfield(t,"depth",d)
hasdimensions = true
end
if n then
- t.objnum = n
+ setfield(t,"objnum",n)
end
view = views[view] or view or 1 -- fit is default
- t.dest_id = name
- t.dest_type = view
+ setfield(t,"dest_id",name)
+ setfield(t,"dest_type",view)
if hasdimensions and view == 0 then -- xyz
-- see (!) s -> m -> t -> r
+ -- linked
local s = copy_node(pdfsave)
local m = copy_node(pdfsetmatrix)
local r = copy_node(pdfrestore)
- m.data = "1 0 0 1"
- s.next = m
- m.next = t
- t.next = r
- m.prev = s
- t.prev = m
- r.prev = t
+ setfield(m,"data","1 0 0 1")
+ setfield(s,"next",m)
+ setfield(m,"next",t)
+ setfield(t,"next",r)
+ setfield(m,"prev",s)
+ setfield(t,"prev",m)
+ setfield(r,"prev",t)
return s -- a list
else
return t
diff --git a/tex/context/base/lpdf-tag.lua b/tex/context/base/lpdf-tag.lua
index 29ffcd207..83315da07 100644
--- a/tex/context/base/lpdf-tag.lua
+++ b/tex/context/base/lpdf-tag.lua
@@ -14,7 +14,9 @@ local trace_tags = false trackers.register("structures.tags", function(v) trace
local report_tags = logs.reporter("backend","tags")
-local backends, lpdf, nodes = backends, lpdf, nodes
+local backends = backends
+local lpdf = lpdf
+local nodes = nodes
local nodeinjections = backends.pdf.nodeinjections
local codeinjections = backends.pdf.codeinjections
@@ -47,11 +49,22 @@ local glyph_code = nodecodes.glyph
local a_tagged = attributes.private('tagged')
local a_image = attributes.private('image')
-local traverse_nodes = node.traverse
-local traverse_id = node.traverse_id
-local tosequence = nodes.tosequence
-local copy_node = node.copy
-local slide_nodelist = node.slide
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getprev = nuts.getprev
+local getlist = nuts.getlist
+local setfield = nuts.setfield
+
+local traverse_nodes = nuts.traverse
+local tosequence = nuts.tosequence
+local copy_node = nuts.copy
+local slide_nodelist = nuts.slide
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
local structure_stack = { }
local structure_kids = pdfarray()
@@ -175,7 +188,8 @@ local function makeelement(fulltag,parent)
end
local function makecontent(parent,start,stop,slist,id)
- local tag, kids = parent.tag, parent.kids
+ local tag = parent.tag
+ local kids = parent.kids
local last = index
if id == "image" then
local d = pdfdictionary {
@@ -198,23 +212,16 @@ local function makecontent(parent,start,stop,slist,id)
end
--
local bliteral = pdfliteral(format("/%s <</MCID %s>>BDC",tag,last))
- local prev = start.prev
- if prev then
- prev.next, bliteral.prev = bliteral, prev
- end
- start.prev, bliteral.next = bliteral, start
- if slist and slist.list == start then
- slist.list = bliteral
- elseif not prev then
+ local eliteral = pdfliteral("EMC")
+ --
+ if slist and getlist(slist) == start then
+ setfield(slist,"list",bliteral)
+ elseif not getprev(start) then
report_tags("this can't happen: injection in front of nothing")
end
--
- local eliteral = pdfliteral("EMC")
- local next = stop.next
- if next then
- next.prev, eliteral.next = eliteral, next
- end
- stop.next, eliteral.prev = eliteral, stop
+ insert_before(start,start,bliteral)
+ insert_after(stop,stop,eliteral)
--
index = index + 1
list[index] = parent.pref
@@ -227,9 +234,9 @@ local level, last, ranges, range = 0, nil, { }, nil
local function collectranges(head,list)
for n in traverse_nodes(head) do
- local id = n.id -- 14: image, 8: literal (mp)
+ local id = getid(n) -- 14: image, 8: literal (mp)
if id == glyph_code then
- local at = n[a_tagged]
+ local at = getattr(n,a_tagged)
if not at then
range = nil
elseif last ~= at then
@@ -240,9 +247,9 @@ local function collectranges(head,list)
range[4] = n -- stop
end
elseif id == hlist_code or id == vlist_code then
- local at = n[a_image]
+ local at = getattr(n,a_image)
if at then
- local at = n[a_tagged]
+ local at = getattr(n,a_tagged)
if not at then
range = nil
else
@@ -250,7 +257,7 @@ local function collectranges(head,list)
end
last = nil
else
- local nl = n.list
+ local nl = getlist(n)
slide_nodelist(nl) -- temporary hack till math gets slided (tracker item)
collectranges(nl,n)
end
@@ -262,7 +269,7 @@ function nodeinjections.addtags(head)
-- no need to adapt head, as we always operate on lists
level, last, ranges, range = 0, nil, { }, nil
initializepage()
- collectranges(head)
+ collectranges(tonut(head))
if trace_tags then
for i=1,#ranges do
local range = ranges[i]
@@ -289,13 +296,13 @@ function nodeinjections.addtags(head)
local b, e = makecontent(prev,start,stop,list,id)
if start == head then
report_tags("this can't happen: parent list gets tagged")
- head = b
+ head = tonode(b)
end
end
finishpage()
-- can be separate feature
--
- -- injectspans(head) -- does to work yet
+ -- injectspans(tonut(head)) -- does to work yet
--
return head, true
end
diff --git a/tex/context/base/math-dir.lua b/tex/context/base/math-dir.lua
index 507a24e41..ec64e6787 100644
--- a/tex/context/base/math-dir.lua
+++ b/tex/context/base/math-dir.lua
@@ -23,8 +23,19 @@ local trace_directions = false trackers.register("typesetters.directions.math
local report_directions = logs.reporter("typesetting","math directions")
-local insert_node_before = nodes.insert_before
-local insert_node_after = nodes.insert_after
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getlist = nuts.getlist
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
local nodecodes = nodes.nodecodes
local tasks = nodes.tasks
@@ -33,7 +44,7 @@ local glyph_code = nodecodes.glyph
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_textdir = nodepool.textdir
@@ -61,9 +72,9 @@ local function processmath(head)
stop = nil
end
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local char = current.char
+ local char = getchar(current)
local cdir = chardirections[char]
if cdir == "en" or cdir == "an" then -- we could check for mathclass punctuation
if not start then
@@ -83,7 +94,7 @@ local function processmath(head)
if mirror then
local class = charclasses[char]
if class == "open" or class == "close" then
- current.char = mirror
+ setfield(current,"char",mirror)
if trace_directions then
report_directions("mirrored: %C to %C",char,mirror)
end
@@ -101,14 +112,14 @@ local function processmath(head)
-- math can pack things into hlists .. we need to make sure we don't process
-- too often: needs checking
if id == hlist_code or id == vlist_code then
- local list, d = processmath(current.list)
- current.list = list
+ local list, d = processmath(getlist(current))
+ setfield(current,"list",list)
if d then
done = true
end
end
end
- current = current.next
+ current = getnext(current)
end
if not start then
-- nothing
@@ -124,9 +135,11 @@ local enabled = false
function directions.processmath(head) -- style, penalties
if enabled then
- local a = head[a_mathbidi]
+ local h = tonut(head)
+ local a = getattr(h,a_mathbidi)
if a and a > 0 then
- return processmath(head)
+ local head, done = processmath(h)
+ return tonode(head), done
end
end
return head, false
diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua
index f3987c12f..4e25fe206 100644
--- a/tex/context/base/math-noa.lua
+++ b/tex/context/base/math-noa.lua
@@ -54,16 +54,35 @@ local report_families = logs.reporter("mathematics","families")
local a_mathrendering = attributes.private("mathrendering")
local a_exportstatus = attributes.private("exportstatus")
-local mlist_to_hlist = node.mlist_to_hlist
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+local tonut = nuts.tonut
+local nutstring = nuts.tostring
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local free_node = nuts.free
+local new_node = nuts.new -- todo: pool: math_noad math_sub
+local copy_node = nuts.copy
+
+local mlist_to_hlist = nodes.mlist_to_hlist
+
local font_of_family = node.family_font
-local insert_node_after = node.insert_after
-local insert_node_before = node.insert_before
-local free_node = node.free
-local new_node = node.new -- todo: pool: math_noad math_sub
-local copy_node = node.copy
-local new_kern = nodes.pool.kern
-local new_rule = nodes.pool.rule
+local new_kern = nodepool.kern
+local new_rule = nodepool.rule
local topoints = number.points
@@ -126,23 +145,23 @@ local function process(start,what,n,parent)
if n then n = n + 1 else n = 0 end
local prev = nil
while start do
- local id = start.id
+ local id = getid(start)
if trace_processing then
if id == math_noad then
- report_processing("%w%S, class %a",n*2,start,noadcodes[start.subtype])
+ report_processing("%w%S, class %a",n*2,nutstring(start),noadcodes[getsubtype(start)])
elseif id == math_char then
- local char = start.char
- local fam = start.fam
+ local char = getchar(start)
+ local fam = getfield(start,"fam")
local font = font_of_family(fam)
- report_processing("%w%S, family %a, font %a, char %a, shape %c",n*2,start,fam,font,char,char)
+ report_processing("%w%S, family %a, font %a, char %a, shape %c",n*2,nutstring(start),fam,font,char,char)
else
- report_processing("%w%S",n*2,start)
+ report_processing("%w%S",n*2,nutstring(start))
end
end
local proc = what[id]
if proc then
-- report_processing("start processing")
- local done, newstart = proc(start,what,n,parent) -- prev is bugged: or start.prev
+ local done, newstart = proc(start,what,n,parent) -- prev is bugged: or getprev(start)
if newstart then
start = newstart
-- report_processing("stop processing (new start)")
@@ -154,55 +173,55 @@ local function process(start,what,n,parent)
elseif id == math_noad then
if prev then
-- we have no proper prev in math nodes yet
- start.prev = prev
+ setfield(start,"prev",prev)
end
- local noad = start.nucleus if noad then process(noad,what,n,start) end -- list
- noad = start.sup if noad then process(noad,what,n,start) end -- list
- noad = start.sub if noad then process(noad,what,n,start) end -- list
+
+ local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list
elseif id == math_box or id == math_sub then
- -- local noad = start.list if noad then process(noad,what,n,start) end -- list
- local noad = start.head if noad then process(noad,what,n,start) end -- list
+ local noad = getfield(start,"list") if noad then process(noad,what,n,start) end -- list (not getlist !)
elseif id == math_fraction then
- local noad = start.num if noad then process(noad,what,n,start) end -- list
- noad = start.denom if noad then process(noad,what,n,start) end -- list
- noad = start.left if noad then process(noad,what,n,start) end -- delimiter
- noad = start.right if noad then process(noad,what,n,start) end -- delimiter
+ local noad = getfield(start,"num") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"denom") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter
+ noad = getfield(start,"right") if noad then process(noad,what,n,start) end -- delimiter
elseif id == math_choice then
- local noad = start.display if noad then process(noad,what,n,start) end -- list
- noad = start.text if noad then process(noad,what,n,start) end -- list
- noad = start.script if noad then process(noad,what,n,start) end -- list
- noad = start.scriptscript if noad then process(noad,what,n,start) end -- list
+ local noad = getfield(start,"display") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"text") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"script") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"scriptscript") if noad then process(noad,what,n,start) end -- list
elseif id == math_fence then
- local noad = start.delim if noad then process(noad,what,n,start) end -- delimiter
+ local noad = getfield(start,"delim") if noad then process(noad,what,n,start) end -- delimiter
elseif id == math_radical then
- local noad = start.nucleus if noad then process(noad,what,n,start) end -- list
- noad = start.sup if noad then process(noad,what,n,start) end -- list
- noad = start.sub if noad then process(noad,what,n,start) end -- list
- noad = start.left if noad then process(noad,what,n,start) end -- delimiter
- noad = start.degree if noad then process(noad,what,n,start) end -- list
+ local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter
+ noad = getfield(start,"degree") if noad then process(noad,what,n,start) end -- list
elseif id == math_accent then
- local noad = start.nucleus if noad then process(noad,what,n,start) end -- list
- noad = start.sup if noad then process(noad,what,n,start) end -- list
- noad = start.sub if noad then process(noad,what,n,start) end -- list
- noad = start.accent if noad then process(noad,what,n,start) end -- list
- noad = start.bot_accent if noad then process(noad,what,n,start) end -- list
+ local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"accent") if noad then process(noad,what,n,start) end -- list
+ noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list
elseif id == math_style then
-- has a next
else
-- glue, penalty, etc
end
prev = start
- start = start.next
+ start = getnext(start)
end
end
local function processnoads(head,actions,banner)
if trace_processing then
report_processing("start %a",banner)
- process(head,actions)
+ process(tonut(head),actions)
report_processing("stop %a",banner)
else
- process(head,actions)
+ process(tonut(head),actions)
end
end
@@ -233,37 +252,71 @@ local familymap = { [0] =
"pseudobold",
}
+-- families[math_char] = function(pointer)
+-- if getfield(pointer,"fam") == 0 then
+-- local a = getattr(pointer,a_mathfamily)
+-- if a and a > 0 then
+-- setattr(pointer,a_mathfamily,0)
+-- if a > 5 then
+-- local char = getchar(pointer)
+-- local bold = boldmap[char]
+-- local newa = a - 3
+-- if bold then
+-- setattr(pointer,a_exportstatus,char)
+-- setfield(pointer,"char",bold)
+-- if trace_families then
+-- report_families("replacing %C by bold %C, family %s with remap %s becomes %s with remap %s",char,bold,a,familymap[a],newa,familymap[newa])
+-- end
+-- else
+-- if trace_families then
+-- report_families("no bold replacement for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa])
+-- end
+-- end
+-- setfield(pointer,"fam",newa)
+-- else
+-- if trace_families then
+-- local char = getchar(pointer)
+-- report_families("family of %C becomes %s with remap %s",char,a,familymap[a])
+-- end
+-- setfield(pointer,"fam",a)
+-- end
+-- else
+-- -- pointer.fam = 0
+-- end
+-- end
+-- end
+
families[math_char] = function(pointer)
- if pointer.fam == 0 then
- local a = pointer[a_mathfamily]
+ if getfield(pointer,"fam") == 0 then
+ local a = getattr(pointer,a_mathfamily)
if a and a > 0 then
- pointer[a_mathfamily] = 0
+ setattr(pointer,a_mathfamily,0)
if a > 5 then
- local char = pointer.char
+ local char = getchar(pointer)
local bold = boldmap[char]
local newa = a - 3
if not bold then
if trace_families then
report_families("no bold replacement for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa])
end
- pointer.fam = newa
- elseif not fontcharacters[font_of_family(newa)][bold] then
+ setfield(pointer,"fam",newa)
+ elseif not fontcharacters[font_of_family(newa)][bold] then
if trace_families then
report_families("no bold character for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa])
end
if newa > 3 then
- pointer.fam = newa - 3
+ setfield(pointer,"fam",newa-3)
end
else
- pointer[a_exportstatus] = char
- pointer.char = bold
+ setattr(pointer,a_exportstatus,char)
+ setfield(pointer,"char",bold)
if trace_families then
report_families("replacing %C by bold %C, family %s with remap %s becomes %s with remap %s",char,bold,a,familymap[a],newa,familymap[newa])
end
- pointer.fam = newa
+ setfield(pointer,"fam",newa)
end
else
- local char = pointer.char
+ local char = getchar(pointer)
if not fontcharacters[font_of_family(a)][char] then
if trace_families then
report_families("no bold replacement for %C",char)
@@ -272,7 +325,7 @@ families[math_char] = function(pointer)
if trace_families then
report_families("family of %C becomes %s with remap %s",char,a,familymap[a])
end
- pointer.fam = a
+ setfield(pointer,"fam",a)
end
end
end
@@ -280,31 +333,31 @@ families[math_char] = function(pointer)
end
families[math_delim] = function(pointer)
- if pointer.small_fam == 0 then
- local a = pointer[a_mathfamily]
+ if getfield(pointer,"small_fam") == 0 then
+ local a = getattr(pointer,a_mathfamily)
if a and a > 0 then
- pointer[a_mathfamily] = 0
+ setattr(pointer,a_mathfamily,0)
if a > 5 then
-- no bold delimiters in unicode
a = a - 3
end
- local char = pointer.small_char
+ local char = getfield(pointer,"small_char")
local okay = fontcharacters[font_of_family(a)][char]
if okay then
- pointer.small_fam = a
+ setfield(pointer,"small_fam",a)
elseif a > 2 then
- pointer.small_fam = a - 3
+ setfield(pointer,"small_fam",a-3)
end
- local char = pointer.large_char
+ local char = getfield(pointer,"large_char")
local okay = fontcharacters[font_of_family(a)][char]
if okay then
- pointer.large_fam = a
+ setfield(pointer,"large_fam",a)
elseif a > 2 then
- pointer.large_fam = a - 3
+ setfield(pointer,"large_fam",a-3)
end
else
- pointer.small_fam = 0
- pointer.large_fam = 0
+ setfield(pointer,"small_fam",0)
+ setfield(pointer,"large_fam",0)
end
end
end
@@ -332,8 +385,8 @@ local fallbackstyleattr = mathematics.fallbackstyleattr
local setnodecolor = nodes.tracers.colors.set
local function checked(pointer)
- local char = pointer.char
- local fam = pointer.fam
+ local char = getchar(pointer)
+ local fam = getfield(pointer,"fam")
local id = font_of_family(fam)
local tc = fontcharacters[id]
if not tc[char] then
@@ -346,27 +399,27 @@ local function checked(pointer)
if trace_analyzing then
setnodecolor(pointer,"font:isol")
end
- pointer[a_exportstatus] = char -- testcase: exponentiale
- pointer.char = newchar
+ setattr(pointer,a_exportstatus,char) -- testcase: exponentiale
+ setfield(pointer,"char",newchar)
return true
end
end
end
processors.relocate[math_char] = function(pointer)
- local g = pointer[a_mathgreek] or 0
- local a = pointer[a_mathalphabet] or 0
+ local g = getattr(pointer,a_mathgreek) or 0
+ local a = getattr(pointer,a_mathalphabet) or 0
if a > 0 or g > 0 then
if a > 0 then
- pointer[a_mathgreek] = 0
+ setattr(pointer,a_mathgreek,0)
end
if g > 0 then
- pointer[a_mathalphabet] = 0
+ setattr(pointer,a_mathalphabet,0)
end
- local char = pointer.char
+ local char = getchar(pointer)
local newchar = remapalphabets(char,a,g)
if newchar then
- local fam = pointer.fam
+ local fam = getfield(pointer,"fam")
local id = font_of_family(fam)
local characters = fontcharacters[id]
if characters[newchar] then
@@ -376,7 +429,7 @@ processors.relocate[math_char] = function(pointer)
if trace_analyzing then
setnodecolor(pointer,"font:isol")
end
- pointer.char = newchar
+ setfield(pointer,"char",newchar)
return true
else
local fallback = fallbackstyleattr(a)
@@ -390,7 +443,7 @@ processors.relocate[math_char] = function(pointer)
if trace_analyzing then
setnodecolor(pointer,"font:isol")
end
- pointer.char = newchar
+ setfield(pointer,"char",newchar)
return true
elseif trace_remapping then
report_remap("char",id,char,newchar," fails (no fallback character)")
@@ -436,19 +489,19 @@ processors.render = { }
local rendersets = mathematics.renderings.numbers or { } -- store
processors.render[math_char] = function(pointer)
- local attr = pointer[a_mathrendering]
+ local attr = getattr(pointer,a_mathrendering)
if attr and attr > 0 then
- local char = pointer.char
+ local char = getchar(pointer)
local renderset = rendersets[attr]
if renderset then
local newchar = renderset[char]
if newchar then
- local fam = pointer.fam
+ local fam = getfield(pointer,"fam")
local id = font_of_family(fam)
local characters = fontcharacters[id]
if characters and characters[newchar] then
- pointer.char = newchar
- pointer[a_exportstatus] = char
+ setfield(pointer,"char",newchar)
+ setattr(pointer,a_exportstatus,char)
end
end
end
@@ -475,19 +528,19 @@ local mathsize = attributes.private("mathsize")
local resize = { } processors.resize = resize
resize[math_fence] = function(pointer)
- local subtype = pointer.subtype
+ local subtype = getsubtype(pointer)
if subtype == left_fence_code or subtype == right_fence_code then
- local a = pointer[mathsize]
+ local a = getattr(pointer,mathsize)
if a and a > 0 then
local method, size = div(a,100), a % 100
- pointer[mathsize] = 0
- local delimiter = pointer.delim
- local chr = delimiter.small_char
+ setattr(pointer,mathsize,0)
+ local delimiter = getfield(pointer,"delim")
+ local chr = getfield(delimiter,"small_char")
if chr > 0 then
- local fam = delimiter.small_fam
+ local fam = getfield(delimiter,"small_fam")
local id = font_of_family(fam)
if id > 0 then
- delimiter.small_char = mathematics.big(fontdata[id],chr,size,method)
+ setfield(delimiter,"small_char",mathematics.big(fontdata[id],chr,size,method))
end
end
end
@@ -499,7 +552,6 @@ function handlers.resize(head,style,penalties)
return true
end
-
local collapse = { } processors.collapse = collapse
local mathpairs = characters.mathpairs
@@ -538,20 +590,20 @@ local validpair = {
}
local function movesubscript(parent,current_nucleus,current_char)
- local prev = parent.prev
- if prev and prev.id == math_noad then
- if not prev.sup and not prev.sub then
- current_nucleus.char = movesub[current_char or current_nucleus.char]
+ local prev = getfield(parent,"prev")
+ if prev and getid(prev) == math_noad then
+ if not getfield(prev,"sup") and not getfield(prev,"sub") then
+ setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)])
-- {f} {'}_n => f_n^'
- local nucleus = parent.nucleus
- local sub = parent.sub
- local sup = parent.sup
- prev.sup = nucleus
- prev.sub = sub
+ local nucleus = getfield(parent,"nucleus")
+ local sub = getfield(parent,"sub")
+ local sup = getfield(parent,"sup")
+ setfield(prev,"sup",nucleus)
+ setfield(prev,"sub",sub)
local dummy = copy_node(nucleus)
- dummy.char = 0
- parent.nucleus = dummy
- parent.sub = nil
+ setfield(dummy,"char",0)
+ setfield(parent,"nucleus",dummy)
+ setfield(parent,"sub",nil)
if trace_collapsing then
report_collapsing("fixing subscript")
end
@@ -561,40 +613,40 @@ end
local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off
if parent then
- if validpair[parent.subtype] then
- local current_nucleus = parent.nucleus
- if current_nucleus.id == math_char then
- local current_char = current_nucleus.char
- if not parent.sub and not parent.sup then
+ if validpair[getsubtype(parent)] then
+ local current_nucleus = getfield(parent,"nucleus")
+ if getid(current_nucleus) == math_char then
+ local current_char = getchar(current_nucleus)
+ if not getfield(parent,"sub") and not getfield(parent,"sup") then
local mathpair = mathpairs[current_char]
if mathpair then
- local next_noad = parent.next
- if next_noad and next_noad.id == math_noad then
- if validpair[next_noad.subtype] then
- local next_nucleus = next_noad.nucleus
- if next_nucleus.id == math_char then
- local next_char = next_nucleus.char
+ local next_noad = getnext(parent)
+ if next_noad and getid(next_noad) == math_noad then
+ if validpair[getsubtype(next_noad)] then
+ local next_nucleus = getfield(next_noad,"nucleus")
+ if getid(next_nucleus) == math_char then
+ local next_char = getchar(next_nucleus)
local newchar = mathpair[next_char]
if newchar then
- local fam = current_nucleus.fam
+ local fam = getfield(current_nucleus,"fam")
local id = font_of_family(fam)
local characters = fontcharacters[id]
if characters and characters[newchar] then
if trace_collapsing then
report_collapsing("%U + %U => %U",current_char,next_char,newchar)
end
- current_nucleus.char = newchar
- local next_next_noad = next_noad.next
+ setfield(current_nucleus,"char",newchar)
+ local next_next_noad = getnext(next_noad)
if next_next_noad then
- parent.next = next_next_noad
- next_next_noad.prev = parent
+ setfield(parent,"next",next_next_noad)
+ setfield(next_next_noad,"prev",parent)
else
- parent.next = nil
+ setfield(parent,"next",nil)
end
- parent.sup = next_noad.sup
- parent.sub = next_noad.sub
- next_noad.sup = nil
- next_noad.sub = nil
+ setfield(parent,"sup",getfield(next_noad,"sup"))
+ setfield(parent,"sub",getfield(next_noad,"sub"))
+ setfield(next_noad,"sup",nil)
+ setfield(next_noad,"sub",nil)
free_node(next_noad)
collapsepair(pointer,what,n,parent,true)
if not nested and movesub[current_char] then
@@ -634,13 +686,13 @@ local replaced = { }
local function replace(pointer,what,n,parent)
pointer = parent -- we're following the parent list (chars trigger this)
- local next = pointer.next
+ local next = getnext(pointer)
local start_super, stop_super, start_sub, stop_sub
local mode = "unset"
- while next and next.id == math_noad do
- local nextnucleus = next.nucleus
- if nextnucleus and nextnucleus.id == math_char and not next.sub and not next.sup then
- local char = nextnucleus.char
+ while next and getid(next) == math_noad do
+ local nextnucleus = getfield(next,"nucleus")
+ if nextnucleus and getid(nextnucleus) == math_char and not getfield(next,"sub") and not getfield(next,"sup") then
+ local char = getchar(nextnucleus)
local s = superscripts[char]
if s then
if not start_super then
@@ -650,8 +702,8 @@ local function replace(pointer,what,n,parent)
break
end
stop_super = next
- next = next.next
- nextnucleus.char = s
+ next = getnext(next)
+ setfield(nextnucleus,"char",s)
replaced[char] = (replaced[char] or 0) + 1
if trace_normalizing then
report_normalizing("superscript %C becomes %C",char,s)
@@ -666,8 +718,8 @@ local function replace(pointer,what,n,parent)
break
end
stop_sub = next
- next = next.next
- nextnucleus.char = s
+ next = getnext(next)
+ setfield(nextnucleus,"char",s)
replaced[char] = (replaced[char] or 0) + 1
if trace_normalizing then
report_normalizing("subscript %C becomes %C",char,s)
@@ -682,29 +734,29 @@ local function replace(pointer,what,n,parent)
end
if start_super then
if start_super == stop_super then
- pointer.sup = start_super.nucleus
+ setfield(pointer,"sup",getfield(start_super,"nucleus"))
else
local list = new_node(math_sub) -- todo attr
- list.head = start_super
- pointer.sup = list
+ setfield(list,"list",start_super)
+ setfield(pointer,"sup",list)
end
if mode == "super" then
- pointer.next = stop_super.next
+ setfield(pointer,"next",getnext(stop_super))
end
- stop_super.next = nil
+ setfield(stop_super,"next",nil)
end
if start_sub then
if start_sub == stop_sub then
- pointer.sub = start_sub.nucleus
+ setfield(pointer,"sub",getfield(start_sub,"nucleus"))
else
local list = new_node(math_sub) -- todo attr
- list.head = start_sub
- pointer.sub = list
+ setfield(list,"list",start_sub)
+ setfield(pointer,"sub",list)
end
if mode == "sub" then
- pointer.next = stop_sub.next
+ setfield(pointer,"next",getnext(stop_sub))
end
- stop_sub.next = nil
+ setfield(stop_sub,"next",nil)
end
-- we could return stop
end
@@ -785,20 +837,20 @@ function mathematics.setalternate(fam,tag)
end
alternate[math_char] = function(pointer)
- local a = pointer[a_mathalternate]
+ local a = getattr(pointer,a_mathalternate)
if a and a > 0 then
- pointer[a_mathalternate] = 0
- local tfmdata = fontdata[font_of_family(pointer.fam)] -- we can also have a famdata
+ setattr(pointer,a_mathalternate,0)
+ local tfmdata = fontdata[font_of_family(getfield(pointer,"fam"))] -- we can also have a famdata
local mathalternatesattributes = tfmdata.shared.mathalternatesattributes
if mathalternatesattributes then
local what = mathalternatesattributes[a]
- local alt = getalternate(tfmdata,pointer.char,what.feature,what.value)
+ local alt = getalternate(tfmdata,getchar(pointer),what.feature,what.value)
if alt then
if trace_alternates then
report_alternates("alternate %a, value %a, replacing glyph %U by glyph %U",
- tostring(what.feature),tostring(what.value),pointer.char,alt)
+ tostring(what.feature),tostring(what.value),getchar(pointer),alt)
end
- pointer.char = alt
+ setfield(pointer,"char",alt)
end
end
end
@@ -885,13 +937,14 @@ end
local function insert_kern(current,kern)
local sub = new_node(math_sub) -- todo: pool
local noad = new_node(math_noad) -- todo: pool
- sub.head = kern
- kern.next = noad
- noad.nucleus = current
+ setfield(sub,"list",kern)
+ setfield(kern,"next",noad)
+ setfield(noad,"nucleus",current)
return sub
end
local setcolor = nodes.tracers.colors.set
+local resetcolor = nodes.tracers.colors.reset
local italic_kern = new_kern
local c_positive_d = "trace:db"
local c_negative_d = "trace:dr"
@@ -913,44 +966,44 @@ trackers.register("math.italics", function(v)
end)
italics[math_char] = function(pointer,what,n,parent)
- local method = pointer[a_mathitalics]
+ local method = getattr(pointer,a_mathitalics)
if method and method > 0 then
- local char = pointer.char
- local font = font_of_family(pointer.fam) -- todo: table
+ local char = getchar(pointer)
+ local font = font_of_family(getfield(pointer,"fam")) -- todo: table
local correction, visual = getcorrection(method,font,char)
if correction then
- local pid = parent.id
+ local pid = getid(parent)
local sub, sup
if pid == math_noad then
- sup = parent.sup
- sub = parent.sub
+ sup = getfield(parent,"sup")
+ sub = getfield(parent,"sub")
end
if sup or sub then
- local subtype = parent.subtype
+ local subtype = getsubtype(parent)
if subtype == noad_oplimits then
if sup then
- parent.sup = insert_kern(sup,italic_kern(correction,font))
+ setfield(parent,"sup",insert_kern(sup,italic_kern(correction,font)))
if trace_italics then
report_italics("method %a, adding %p italic correction for upper limit of %C",method,correction,char)
end
end
if sub then
local correction = - correction
- parent.sub = insert_kern(sub,italic_kern(correction,font))
+ setfield(parent,"sub",insert_kern(sub,italic_kern(correction,font)))
if trace_italics then
report_italics("method %a, adding %p italic correction for lower limit of %C",method,correction,char)
end
end
else
if sup then
- parent.sup = insert_kern(sup,italic_kern(correction,font))
+ setfield(parent,"sup",insert_kern(sup,italic_kern(correction,font)))
if trace_italics then
report_italics("method %a, adding %p italic correction before superscript after %C",method,correction,char)
end
end
end
else
- local next_noad = parent.next
+ local next_noad = getnext(parent)
if not next_noad then
if n== 1 then -- only at the outer level .. will become an option (always,endonly,none)
if trace_italics then
@@ -958,12 +1011,12 @@ italics[math_char] = function(pointer,what,n,parent)
end
insert_node_after(parent,parent,italic_kern(correction,font))
end
- elseif next_noad.id == math_noad then
- local next_subtype = next_noad.subtype
+ elseif getid(next_noad) == math_noad then
+ local next_subtype = getsubtype(next_noad)
if next_subtype == noad_punct or next_subtype == noad_ord then
- local next_nucleus = next_noad.nucleus
- if next_nucleus.id == math_char then
- local next_char = next_nucleus.char
+ local next_nucleus = getfield(next_noad,"nucleus")
+ if getid(next_nucleus) == math_char then
+ local next_char = getchar(next_nucleus)
local next_data = chardata[next_char]
local visual = next_data.visual
if visual == "it" or visual == "bi" then
@@ -1047,15 +1100,15 @@ local validvariants = { -- fast check on valid
}
variants[math_char] = function(pointer,what,n,parent) -- also set export value
- local char = pointer.char
+ local char = getchar(pointer)
local selector = validvariants[char]
if selector then
- local next = parent.next
- if next and next.id == math_noad then
- local nucleus = next.nucleus
- if nucleus and nucleus.id == math_char and nucleus.char == selector then
+ local next = getnext(parent)
+ if next and getid(next) == math_noad then
+ local nucleus = getfield(next,"nucleus")
+ if nucleus and getid(nucleus) == math_char and getchar(nucleus) == selector then
local variant
- local tfmdata = fontdata[font_of_family(pointer.fam)] -- we can also have a famdata
+ local tfmdata = fontdata[font_of_family(getfield(pointer,"fam"))] -- we can also have a famdata
local mathvariants = tfmdata.resources.variants -- and variantdata
if mathvariants then
mathvariants = mathvariants[selector]
@@ -1064,8 +1117,8 @@ variants[math_char] = function(pointer,what,n,parent) -- also set export value
end
end
if variant then
- pointer.char = variant
- pointer[a_exportstatus] = char -- we don't export the variant as it's visual markup
+ setfield(pointer,"char",variant)
+ setattr(pointer,a_exportstatus,char) -- we don't export the variant as it's visual markup
if trace_variants then
report_variants("variant (%U,%U) replaced by %U",char,selector,variant)
end
@@ -1074,8 +1127,8 @@ variants[math_char] = function(pointer,what,n,parent) -- also set export value
report_variants("no variant (%U,%U)",char,selector)
end
end
- next.prev = pointer
- parent.next = next.next
+ setfield(next,"prev",pointer)
+ setfield(parent,"next",getnext(next))
free_node(next)
end
end
@@ -1108,7 +1161,7 @@ local colors = {
}
classes[math_char] = function(pointer,what,n,parent)
- local color = colors[parent.subtype]
+ local color = colors[getsubtype(parent)]
if color then
setcolor(pointer,color)
else
diff --git a/tex/context/base/math-tag.lua b/tex/context/base/math-tag.lua
index ab5902dd4..3cd4cae16 100644
--- a/tex/context/base/math-tag.lua
+++ b/tex/context/base/math-tag.lua
@@ -11,10 +11,22 @@ if not modules then modules = { } end modules ['math-tag'] = {
local find, match = string.find, string.match
local insert, remove = table.insert, table.remove
-local attributes, nodes = attributes, nodes
+local attributes = attributes
+local nodes = nodes
-local set_attributes = nodes.setattributes
-local traverse_nodes = node.traverse
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getchar = nuts.getchar
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local set_attributes = nuts.setattributes
+local traverse_nodes = nuts.traverse
local nodecodes = nodes.nodecodes
@@ -61,22 +73,24 @@ local function processsubsup(start)
-- At some point we might need to add an attribute signaling the
-- super- and subscripts because TeX and MathML use a different
-- order.
- local nucleus, sup, sub = start.nucleus, start.sup, start.sub
+ local nucleus = getfield(start,"nucleus")
+ local sup = getfield(start,"sup")
+ local sub = getfield(start,"sub")
if sub then
if sup then
- start[a_tagged] = start_tagged("msubsup")
+ setattr(start,a_tagged,start_tagged("msubsup"))
process(nucleus)
process(sub)
process(sup)
stop_tagged()
else
- start[a_tagged] = start_tagged("msub")
+ setattr(start,a_tagged,start_tagged("msub"))
process(nucleus)
process(sub)
stop_tagged()
end
elseif sup then
- start[a_tagged] = start_tagged("msup")
+ setattr(start,a_tagged,start_tagged("msup"))
process(nucleus)
process(sup)
stop_tagged()
@@ -93,11 +107,11 @@ local actionstack = { }
process = function(start) -- we cannot use the processor as we have no finalizers (yet)
while start do
- local id = start.id
+ local id = getid(start)
if id == math_char_code then
- local char = start.char
+ local char = getchar(start)
-- check for code
- local a = start[a_mathcategory]
+ local a = getattr(start,a_mathcategory)
if a then
a = { detail = a }
end
@@ -119,22 +133,22 @@ process = function(start) -- we cannot use the processor as we have no finalizer
else
tag = "mo"
end
- start[a_tagged] = start_tagged(tag,a)
+ setattr(start,a_tagged,start_tagged(tag,a))
stop_tagged()
break -- okay?
elseif id == math_textchar_code then
-- check for code
- local a = start[a_mathcategory]
+ local a = getattr(start,a_mathcategory)
if a then
- start[a_tagged] = start_tagged("ms",{ detail = a })
+ setattr(start,a_tagged,start_tagged("ms",{ detail = a }))
else
- start[a_tagged] = start_tagged("ms")
+ setattr(start,a_tagged,start_tagged("ms"))
end
stop_tagged()
break
elseif id == math_delim_code then
-- check for code
- start[a_tagged] = start_tagged("mo")
+ setattr(start,a_tagged,start_tagged("mo"))
stop_tagged()
break
elseif id == math_style_code then
@@ -143,14 +157,14 @@ process = function(start) -- we cannot use the processor as we have no finalizer
processsubsup(start)
elseif id == math_box_code or id == hlist_code or id == vlist_code then
-- keep an eye on math_box_code and see what ends up in there
- local attr = start[a_tagged]
+ local attr = getattr(start,a_tagged)
local last = attr and taglist[attr]
if last and find(last[#last],"formulacaption[:%-]") then
-- leave alone, will nicely move to the outer level
else
local text = start_tagged("mtext")
- start[a_tagged] = text
- local list = start.list
+ setattr(start,a_tagged,text)
+ local list = getfield(start,"list")
if not list then
-- empty list
elseif not attr then
@@ -166,8 +180,8 @@ process = function(start) -- we cannot use the processor as we have no finalizer
local function runner(list) -- quite inefficient
local cache = { } -- we can have nested unboxed mess so best local to runner
for n in traverse_nodes(list) do
- local id = n.id
- local aa = n[a_tagged]
+ local id = getid(n)
+ local aa = getattr(n,a_tagged)
if aa then
local ac = cache[aa]
if not ac then
@@ -185,12 +199,12 @@ process = function(start) -- we cannot use the processor as we have no finalizer
end
cache[aa] = ac
end
- n[a_tagged] = ac
+ setattr(n,a_tagged,ac)
else
- n[a_tagged] = text
+ setattr(n,a_tagged,text)
end
if id == hlist_code or id == vlist_code then
- runner(n.list)
+ runner(getlist(n))
end
end
end
@@ -199,47 +213,53 @@ process = function(start) -- we cannot use the processor as we have no finalizer
stop_tagged()
end
elseif id == math_sub_code then
- local list = start.list
+ local list = getfield(start,"list")
if list then
- local attr = start[a_tagged]
+ local attr = getattr(start,a_tagged)
local last = attr and taglist[attr]
local action = last and match(last[#last],"maction:(.-)%-")
if action and action ~= "" then
if actionstack[#actionstack] == action then
- start[a_tagged] = start_tagged("mrow")
+ setattr(start,a_tagged,start_tagged("mrow"))
process(list)
stop_tagged()
else
insert(actionstack,action)
- start[a_tagged] = start_tagged("mrow",{ detail = action })
+ setattr(start,a_tagged,start_tagged("mrow",{ detail = action }))
process(list)
stop_tagged()
remove(actionstack)
end
else
- start[a_tagged] = start_tagged("mrow")
+ setattr(start,a_tagged,start_tagged("mrow"))
process(list)
stop_tagged()
end
end
elseif id == math_fraction_code then
- local num, denom, left, right = start.num, start.denom, start.left, start.right
+ local num = getfield(start,"num")
+ local denom = getfield(start,"denom")
+ local left = getfield(start,"left")
+ local right = getfield(start,"right")
if left then
- left[a_tagged] = start_tagged("mo")
+ setattr(left,a_tagged,start_tagged("mo"))
process(left)
stop_tagged()
end
- start[a_tagged] = start_tagged("mfrac")
+ setattr(start,a_tagged,start_tagged("mfrac"))
process(num)
process(denom)
stop_tagged()
if right then
- right[a_tagged] = start_tagged("mo")
+ setattr(right,a_tagged,start_tagged("mo"))
process(right)
stop_tagged()
end
elseif id == math_choice_code then
- local display, text, script, scriptscript = start.display, start.text, start.script, start.scriptscript
+ local display = getfield(start,"display")
+ local text = getfield(start,"text")
+ local script = getfield(start,"script")
+ local scriptscript = getfield(start,"scriptscript")
if display then
process(display)
end
@@ -253,67 +273,69 @@ process = function(start) -- we cannot use the processor as we have no finalizer
process(scriptscript)
end
elseif id == math_fence_code then
- local delim = start.delim
- local subtype = start.subtype
+ local delim = getfield(start,"delim")
+ local subtype = getfield(start,"subtype")
+ -- setattr(start,a_tagged,start_tagged("mfenced")) -- needs checking
if subtype == 1 then
-- left
- start[a_tagged] = start_tagged("mfenced")
if delim then
- start[a_tagged] = start_tagged("mleft")
+ setattr(start,a_tagged,start_tagged("mleft"))
process(delim)
stop_tagged()
end
elseif subtype == 2 then
-- middle
if delim then
- start[a_tagged] = start_tagged("mmiddle")
+ setattr(start,a_tagged,start_tagged("mmiddle"))
process(delim)
stop_tagged()
end
elseif subtype == 3 then
if delim then
- start[a_tagged] = start_tagged("mright")
+ setattr(start,a_tagged,start_tagged("mright"))
process(delim)
stop_tagged()
end
- stop_tagged()
else
-- can't happen
end
+ -- stop_tagged()
elseif id == math_radical_code then
- local left, degree = start.left, start.degree
+ local left = getfield(start,"left")
+ local degree = getfield(start,"degree")
if left then
start_tagged("")
process(left) -- root symbol, ignored
stop_tagged()
end
if degree then -- not good enough, can be empty mlist
- start[a_tagged] = start_tagged("mroot")
+ setattr(start,a_tagged,start_tagged("mroot"))
processsubsup(start)
process(degree)
stop_tagged()
else
- start[a_tagged] = start_tagged("msqrt")
+ setattr(start,a_tagged,start_tagged("msqrt"))
processsubsup(start)
stop_tagged()
end
elseif id == math_accent_code then
- local accent, bot_accent = start.accent, start.bot_accent
+ local accent = getfield(start,"accent")
+ local bot_accent = getfield(start,"bot_accent")
if bot_accent then
if accent then
- start[a_tagged] = start_tagged("munderover",{ detail = "accent" })
+ setattr(start,a_tagged,start_tagged("munderover",{ detail = "accent" }))
processsubsup(start)
process(bot_accent)
process(accent)
stop_tagged()
else
- start[a_tagged] = start_tagged("munder",{ detail = "accent" })
+ setattr(start,a_tagged,start_tagged("munder",{ detail = "accent" }))
processsubsup(start)
process(bot_accent)
stop_tagged()
end
elseif accent then
- start[a_tagged] = start_tagged("mover",{ detail = "accent" })
+ setattr(start,a_tagged,start_tagged("mover",{ detail = "accent" }))
processsubsup(start)
process(accent)
stop_tagged()
@@ -321,22 +343,23 @@ process = function(start) -- we cannot use the processor as we have no finalizer
processsubsup(start)
end
elseif id == glue_code then
- start[a_tagged] = start_tagged("mspace")
+ setattr(start,a_tagged,start_tagged("mspace"))
stop_tagged()
else
- start[a_tagged] = start_tagged("merror", { detail = nodecodes[i] })
+ setattr(start,a_tagged,start_tagged("merror", { detail = nodecodes[i] }))
stop_tagged()
end
- start = start.next
+ start = getnext(start)
end
end
function noads.handlers.tags(head,style,penalties)
+ head = tonut(head)
local v_math = start_tagged("math")
local v_mrow = start_tagged("mrow")
- local v_mode = head[a_mathmode]
- head[a_tagged] = v_math
- head[a_tagged] = v_mrow
+ local v_mode = getattr(head,a_mathmode)
+ -- setattr(head,a_tagged,v_math)
+ setattr(head,a_tagged,v_mrow)
tags.setattributehash(v_math,"mode",v_mode == 1 and "display" or "inline")
process(head)
stop_tagged()
diff --git a/tex/context/base/node-acc.lua b/tex/context/base/node-acc.lua
index 81ae496b2..6a1b986bc 100644
--- a/tex/context/base/node-acc.lua
+++ b/tex/context/base/node-acc.lua
@@ -11,10 +11,25 @@ local nodes, node = nodes, node
local nodecodes = nodes.nodecodes
local tasks = nodes.tasks
-local traverse_nodes = node.traverse
-local traverse_id = node.traverse_id
-local copy_node = node.copy
-local free_nodelist = node.flush_list
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local getid = nuts.getid
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+local getlist = nuts.getlist
+local getchar = nuts.getchar
+local getnext = nuts.getnext
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local traverse_nodes = nuts.traverse
+local traverse_id = nuts.traverse_id
+local copy_node = nuts.copy
+local free_nodelist = nuts.flush_list
+local insert_after = nuts.insert_after
local glue_code = nodecodes.glue
local kern_code = nodecodes.kern
@@ -29,57 +44,68 @@ local threshold = 65536
-- todo: nbsp etc
-- todo: collapse kerns
+-- p_id
+
local function injectspaces(head)
- local p
+ local p, p_id
local n = head
while n do
- local id = n.id
+ local id = getid(n)
if id == glue_code then -- todo: check for subtype related to spacing (13/14 but most seems to be 0)
- -- if n.spec.width > 0 then -- threshold
- if p and p.id == glyph_code then
+ -- if getfield(getfield(n,"spec"),"width") > 0 then -- threshold
+ if p and p_id == glyph_code then
local g = copy_node(p)
- local c = g.components
+ local c = getfield(g,"components")
if c then -- it happens that we copied a ligature
free_nodelist(c)
- g.components = nil
- g.subtype = 256
+ setfield(g,"components",nil)
+ setfield(g,"subtype",256)
end
- local a = n[a_characters]
- local s = copy_node(n.spec)
- g.char, n.spec = 32, s
- p.next, g.prev = g, p
- g.next, n.prev = n, g
- s.width = s.width - g.width
+ -- p .. g
+ local a = getattr(n,a_characters)
+ local s = copy_node(getfield(n,"spec"))
+ setfield(g,"char",32)
+ insert_after(p,p,g)
+ -- setfield(p,"next",g)
+ -- setfield(g,"prev",p)
+ -- setfield(g,"next",n)
+ -- setfield(n,"prev",g)
+ setfield(n,"spec",s)
+ setfield(s,"width",getfield(s,"width") - getfield(g,"width"))
if a then
- g[a_characters] = a
+ setattr(g,a_characters,a)
end
- s[a_characters] = 0
- n[a_characters] = 0
+ setattr(s,a_characters,0)
+ setattr(n,a_characters,0)
end
-- end
elseif id == hlist_code or id == vlist_code then
- injectspaces(n.list,attribute)
+ injectspaces(getlist(n),attribute)
-- elseif id == kern_code then -- the backend already collapses
-- local first = n
-- while true do
- -- local nn = n.next
- -- if nn and nn.id == kern_code then
+ -- local nn = getnext(n)
+ -- if nn and getid(nn) == kern_code then
-- -- maybe we should delete kerns but who cares at this stage
- -- first.kern = first.kern + nn.kern
- -- nn.kern = 0
+ -- setfield(first,"kern",getfield(first,"kern") + getfield(nn,"kern")
+ -- setfield(nn,"kern",0)
-- n = nn
-- else
-- break
-- end
-- end
end
+ p_id = id
p = n
- n = n.next
+ n = getnext(n)
end
- return head, true
+ return head, true -- always done anyway
end
-nodes.handlers.accessibility = injectspaces
+nodes.handlers.accessibility = function(head)
+ local head, done = injectspaces(tonut(head))
+ return tonode(head), done
+end
-- todo:
@@ -90,16 +116,18 @@ nodes.handlers.accessibility = injectspaces
-- local function compact(n)
-- local t = { }
-- for n in traverse_id(glyph_code,n) do
--- t[#t+1] = utfchar(n.char) -- check for unicode
+-- t[#t+1] = utfchar(getchar(n)) -- check for unicode
-- end
-- return concat(t,"")
-- end
--
-- local function injectspans(head)
--- for n in traverse_nodes(head) do
--- local id = n.id
+-- local done = false
+-- for n in traverse_nodes(tonuts(head)) do
+-- local id = getid(n)
-- if id == disc then
--- local r, p = n.replace, n.pre
+-- local r = getfield(n,"replace")
+-- local p = getfield(n,"pre")
-- if r and p then
-- local str = compact(r)
-- local hsh = hyphenated[str]
@@ -108,13 +136,14 @@ nodes.handlers.accessibility = injectspaces
-- hyphenated[str] = hsh
-- codes[hsh] = str
-- end
--- n[a_hyphenated] = hsh
+-- setattr(n,a_hyphenated,hsh)
+-- done = true
-- end
-- elseif id == hlist_code or id == vlist_code then
--- injectspans(n.list)
+-- injectspans(getlist(n))
-- end
-- end
--- return head, true
+-- return tonodes(head), done
-- end
--
-- nodes.injectspans = injectspans
@@ -122,19 +151,22 @@ nodes.handlers.accessibility = injectspaces
-- tasks.appendaction("processors", "words", "nodes.injectspans")
--
-- local function injectspans(head)
--- for n in traverse_nodes(head) do
--- local id = n.id
+-- local done = false
+-- for n in traverse_nodes(tonut(head)) do
+-- local id = getid(n)
-- if id == disc then
--- local a = n[a_hyphenated]
+-- local a = getattr(n,a_hyphenated)
-- if a then
-- local str = codes[a]
-- local b = new_pdfliteral(format("/Span << /ActualText %s >> BDC", lpdf.tosixteen(str)))
-- local e = new_pdfliteral("EMC")
--- node.insert_before(head,n,b)
--- node.insert_after(head,n,e)
+-- insert_before(head,n,b)
+-- insert_after(head,n,e)
+-- done = true
-- end
-- elseif id == hlist_code or id == vlist_code then
--- injectspans(n.list)
+-- injectspans(getlist(n))
-- end
-- end
+-- return tonodes(head), done
-- end
diff --git a/tex/context/base/node-aux.lua b/tex/context/base/node-aux.lua
index 443c78547..7eb51e5b4 100644
--- a/tex/context/base/node-aux.lua
+++ b/tex/context/base/node-aux.lua
@@ -22,82 +22,105 @@ local vlist_code = nodecodes.vlist
local attributelist_code = nodecodes.attributelist -- temporary
local math_code = nodecodes.math
-local nodepool = nodes.pool
-
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local vianuts = nuts.vianuts
+
+local getbox = nuts.getbox
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getattr = nuts.getattr
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local traverse_nodes = nuts.traverse
+local traverse_id = nuts.traverse_id
+local free_node = nuts.free
+local hpack_nodes = nuts.hpack
+local unset_attribute = nuts.unset_attribute
+local first_glyph = nuts.first_glyph
+local copy_node = nuts.copy
+local copy_node_list = nuts.copy_list
+local slide_nodes = nuts.slide
+local insert_node_after = nuts.insert_after
+local isnode = nuts.is_node
+
+local nodepool = nuts.pool
local new_glue = nodepool.glue
local new_glyph = nodepool.glyph
-local traverse_nodes = node.traverse
-local traverse_id = node.traverse_id
-local free_node = node.free
-local hpack_nodes = node.hpack
-local unset_attribute = node.unset_attribute
-local first_glyph = node.first_glyph or node.first_character
-local copy_node = node.copy
-local copy_node_list = node.copy_list
-local slide_nodes = node.slide
-local insert_node_after = node.insert_after
-local isnode = node.is_node
-
local unsetvalue = attributes.unsetvalue
local current_font = font.current
-local texgetbox = tex.getbox
-
local report_error = logs.reporter("node-aux:error")
-function nodes.repackhlist(list,...)
---~ nodes.showsimplelist(list)
+local function repackhlist(list,...)
local temp, b = hpack_nodes(list,...)
- list = temp.list
- temp.list = nil
+ list = getlist(temp)
+ setfield(temp,"list",nil)
free_node(temp)
return list, b
end
+nuts.repackhlist = repackhlist
+
+function nodes.repackhlist(list,...)
+ local list, b = repackhlist(tonut(list),...)
+ return tonode(list), b
+end
+
local function set_attributes(head,attr,value)
for n in traverse_nodes(head) do
- n[attr] = value
- local id = n.id
+ setattr(n,attr,value)
+ local id = getid(n)
if id == hlist_node or id == vlist_node then
- set_attributes(n.list,attr,value)
+ set_attributes(getlist(n),attr,value)
end
end
end
local function set_unset_attributes(head,attr,value)
for n in traverse_nodes(head) do
- if not n[attr] then
- n[attr] = value
+ if not getattr(n,attr) then
+ setattr(n,attr,value)
end
- local id = n.id
+ local id = getid(n)
if id == hlist_code or id == vlist_code then
- set_unset_attributes(n.list,attr,value)
+ set_unset_attributes(getlist(n),attr,value)
end
end
end
local function unset_attributes(head,attr)
for n in traverse_nodes(head) do
- n[attr] = unsetvalue
- local id = n.id
+ setattr(n,attr,unsetvalue)
+ local id = getid(n)
if id == hlist_code or id == vlist_code then
- unset_attributes(n.list,attr)
+ unset_attributes(getlist(n),attr)
end
end
end
-nodes.setattribute = node.set_attribute
-nodes.getattribute = node.has_attribute
-nodes.unsetattribute = node.unset_attribute
-nodes.has_attribute = node.has_attribute
+-- for old times sake
+
+nuts.setattribute = nuts.setattr nodes.setattribute = nodes.setattr
+nuts.getattribute = nuts.getattr nodes.getattribute = nodes.getattr
+nuts.unsetattribute = nuts.unset_attribute nodes.unsetattribute = nodes.unset_attribute
+nuts.has_attribute = nuts.has_attribute nodes.has_attribute = nodes.has_attribute
+nuts.firstglyph = nuts.first_glyph nodes.firstglyph = nodes.first_glyph
-nodes.firstglyph = first_glyph
-nodes.setattributes = set_attributes
-nodes.setunsetattributes = set_unset_attributes
-nodes.unsetattributes = unset_attributes
+nuts.setattributes = set_attributes nodes.setattributes = vianuts(set_attributes)
+nuts.setunsetattributes = set_unset_attributes nodes.setunsetattributes = vianuts(set_unset_attributes)
+nuts.unsetattributes = unset_attributes nodes.unsetattributes = vianuts(unset_attributes)
+-- history:
+--
-- function nodes.is_skipable(a,id) -- skipable nodes at the margins during character protrusion
-- return (
-- id ~= glyph_node
@@ -106,29 +129,26 @@ nodes.unsetattributes = unset_attributes
-- or id == adjust_node
-- or id == penalty_node
-- or (id == glue_node and a.spec.writable)
--- or (id == disc_node and a.pre == nil and a.post == nil and a.replace == nil)
--- or (id == math_node and a.surround == 0)
--- or (id == kern_node and (a.kern == 0 or a.subtype == NORMAL))
--- or (id == hlist_node and a.width == 0 and a.height == 0 and a.depth == 0 and a.list == nil)
--- or (id == whatsit_node and a.subtype ~= pdf_refximage_node and a.subtype ~= pdf_refxform_node)
+-- or (id == disc_node and getfield(a,"pre") == nil and getfield(a,"post") == nil and getfield(a,"replace") == nil)
+-- or (id == math_node and getfield(a,"surround") == 0)
+-- or (id == kern_node and (getfield(a,"kern") == 0 or getsubtype(subtype) == NORMAL))
+-- or (id == hlist_node and getfield(a,"width") == 0 and getfield(a,"height") == 0 and getfield(a,"depth") == 0 and getlist(a) == nil)
+-- or (id == whatsit_node and getsubtype(a) ~= pdf_refximage_node and getsubtype(a) ~= pdf_refxform_node)
-- )
-- end
-
--- history:
---
--
-- local function glyph_width(a)
--- local ch = chardata[a.font][a.char]
+-- local ch = chardata[getfont(a)][getchar(a)]
-- return (ch and ch.width) or 0
-- end
--
-- local function glyph_total(a)
--- local ch = chardata[a.font][a.char]
+-- local ch = chardata[getfont(a)][getchar(a)]
-- return (ch and (ch.height+ch.depth)) or 0
-- end
--
-- local function non_discardable(a) -- inline
--- return a.id < math_node -- brrrr
+-- return getid(id) < math_node -- brrrr
-- end
--
-- local function calculate_badness(t,s)
@@ -183,8 +203,36 @@ nodes.unsetattributes = unset_attributes
-- return -u
-- end
-- end
+--
+-- if not node.end_of_math then
+-- function node.end_of_math(n)
+-- for n in traverse_id(math_code,getnext(next)) do
+-- return n
+-- end
+-- end
+-- end
+--
+-- nodes.endofmath = node.end_of_math
+--
+-- local function firstline(n)
+-- while n do
+-- local id = getid(n)
+-- if id == hlist_code then
+-- if getsubtype(n) == line_code then
+-- return n
+-- else
+-- return firstline(getlist(n))
+-- end
+-- elseif id == vlist_code then
+-- return firstline(getlist(n))
+-- end
+-- n = getnext(n)
+-- end
+-- end
+--
+-- nodes.firstline = firstline
-function nodes.firstcharacter(n,untagged) -- tagged == subtype > 255
+local function firstcharacter(n,untagged) -- tagged == subtype > 255
if untagged then
return first_glyph(n)
else
@@ -194,43 +242,18 @@ function nodes.firstcharacter(n,untagged) -- tagged == subtype > 255
end
end
-function nodes.firstcharinbox(n)
- local l = texgetbox(n).list
+local function firstcharinbox(n)
+ local l = getlist(getbox(n))
if l then
for g in traverse_id(glyph_code,l) do
- return g.char
+ return getchar(g)
end
end
return 0
end
-if not node.end_of_math then
- function node.end_of_math(n)
- for n in traverse_id(math_code,n.next) do
- return n
- end
- end
-end
-
-nodes.endofmath = node.end_of_math
-
--- local function firstline(n)
--- while n do
--- local id = n.id
--- if id == hlist_code then
--- if n.subtype == line_code then
--- return n
--- else
--- return firstline(n.list)
--- end
--- elseif id == vlist_code then
--- return firstline(n.list)
--- end
--- n = n.next
--- end
--- end
-
--- nodes.firstline = firstline
+nuts.firstcharacter = firstcharacter nodes.firstcharacter = vianuts(firstcharacter)
+nuts.firstcharinbox = firstcharinbox nodes.firstcharinbox = vianuts(firstcharinbox)
-- this depends on fonts, so we have a funny dependency ... will be
-- sorted out .. we could make tonodes a plugin into this
@@ -242,10 +265,8 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob-
local head, tail, space, fnt, template = nil, nil, nil, nil, nil
if not fnt then
fnt = current_font()
- elseif type(fnt) ~= "number" and fnt.id == "glyph" then
- fnt, template = nil, fnt
- -- else
- -- already a number
+ elseif type(fnt) ~= "number" and getid(fnt) == glyph_code then -- so it has to be a real node
+ fnt, template = nil, tonut(fnt)
end
for s in utfvalues(str) do
local n
@@ -259,12 +280,12 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob-
end
elseif template then
n = copy_node(template)
- n.char = s
+ setvalue(n,"char",s)
else
n = new_glyph(fnt,s)
end
if attr then -- normally false when template
- n.attr = copy_node_list(attr)
+ setfield(n,"attr",copy_node_list(attr))
end
if head then
insert_node_after(head,tail,n)
@@ -276,68 +297,129 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob-
return head, tail
end
-nodes.tonodes = tonodes
+nuts.tonodes = tonodes
+
+nodes.tonodes = function(str,fnt,attr)
+ local head, tail = tonodes(str,fnt,attr)
+ return tonode(head), tonode(tail)
+end
+
+-- local function link(list,currentfont,currentattr,head,tail)
+-- for i=1,#list do
+-- local n = list[i]
+-- if n then
+-- local tn = isnode(n)
+-- if not tn then
+-- local tn = type(n)
+-- if tn == "number" then
+-- if not currentfont then
+-- currentfont = current_font()
+-- end
+-- local h, t = tonodes(tostring(n),currentfont,currentattr)
+-- if not h then
+-- -- skip
+-- elseif not head then
+-- head = h
+-- tail = t
+-- else
+-- setfield(tail,"next",h)
+-- setfield(h,"prev",t)
+-- tail = t
+-- end
+-- elseif tn == "string" then
+-- if #tn > 0 then
+-- if not currentfont then
+-- currentfont = current_font()
+-- end
+-- local h, t = tonodes(n,currentfont,currentattr)
+-- if not h then
+-- -- skip
+-- elseif not head then
+-- head, tail = h, t
+-- else
+-- setfield(tail,"next",h)
+-- setfield(h,"prev",t)
+-- tail = t
+-- end
+-- end
+-- elseif tn == "table" then
+-- if #tn > 0 then
+-- if not currentfont then
+-- currentfont = current_font()
+-- end
+-- head, tail = link(n,currentfont,currentattr,head,tail)
+-- end
+-- end
+-- elseif not head then
+-- head = n
+-- tail = slide_nodes(n)
+-- elseif getid(n) == attributelist_code then
+-- -- weird case
+-- report_error("weird node type in list at index %s:",i)
+-- for i=1,#list do
+-- local l = list[i]
+-- report_error("%3i: %s %S",i,getid(l) == attributelist_code and "!" or ">",l)
+-- end
+-- os.exit()
+-- else
+-- setfield(tail,"next",n)
+-- setfield(n,"prev",tail)
+-- if getnext(n) then
+-- tail = slide_nodes(n)
+-- else
+-- tail = n
+-- end
+-- end
+-- else
+-- -- permitting nil is convenient
+-- end
+-- end
+-- return head, tail
+-- end
-local function link(list,currentfont,currentattr,head,tail)
+local function link(list,currentfont,currentattr,head,tail) -- an oldie, might be replaced
for i=1,#list do
local n = list[i]
if n then
- local tn = isnode(n)
- if not tn then
- local tn = type(n)
- if tn == "number" then
+ local tn = type(n)
+ if tn == "string" then
+ if #tn > 0 then
if not currentfont then
currentfont = current_font()
end
- local h, t = tonodes(tostring(n),currentfont,currentattr)
+ local h, t = tonodes(n,currentfont,currentattr)
if not h then
-- skip
elseif not head then
head, tail = h, t
else
- tail.next, h.prev, tail = h, t, t
- end
- elseif tn == "string" then
- if #tn > 0 then
- if not currentfont then
- currentfont = current_font()
- end
- local h, t = tonodes(n,currentfont,currentattr)
- if not h then
- -- skip
- elseif not head then
- head, tail = h, t
- else
- tail.next, h.prev, tail = h, t, t
- end
+ setfield(tail,"next",h)
+ setfield(h,"prev",t)
+ tail = t
end
- elseif tn == "table" then
- if #tn > 0 then
- if not currentfont then
- currentfont = current_font()
- end
- head, tail = link(n,currentfont,currentattr,head,tail)
+ end
+ elseif tn == "table" then
+ if #tn > 0 then
+ if not currentfont then
+ currentfont = current_font()
end
+ head, tail = link(n,currentfont,currentattr,head,tail)
end
elseif not head then
head = n
- if n.next then
- tail = slide_nodes(n)
- else
- tail = n
- end
- elseif n.id == attributelist_code then
+ tail = slide_nodes(n)
+ elseif getid(n) == attributelist_code then
-- weird case
report_error("weird node type in list at index %s:",i)
for i=1,#list do
local l = list[i]
- report_error("%3i: %s %S",i,l.id == attributelist_code and "!" or ">",l)
+ report_error("%3i: %s %S",i,getid(l) == attributelist_code and "!" or ">",l)
end
os.exit()
else
- tail.next = n
- n.prev = tail
- if n.next then
+ setfield(tail,"next",n)
+ setfield(n,"prev",tail)
+ if getnext(n) then
tail = slide_nodes(n)
else
tail = n
@@ -350,17 +432,22 @@ local function link(list,currentfont,currentattr,head,tail)
return head, tail
end
-nodes.link = link
+nuts.link = link
+
+nodes.link = function(list,currentfont,currentattr,head,tail)
+ local head, tail = link(list,currentfont,currentattr,tonut(head),tonut(tail))
+ return tonode(head), tonode(tail)
+end
local function locate(start,wantedid,wantedsubtype)
for n in traverse_nodes(start) do
- local id = n.id
+ local id = getid(n)
if id == wantedid then
- if not wantedsubtype or n.subtype == wantedsubtype then
+ if not wantedsubtype or getsubtype(n) == wantedsubtype then
return n
end
elseif id == hlist_code or id == vlist_code then
- local found = locate(n.list,wantedid,wantedsubtype)
+ local found = locate(getlist(n),wantedid,wantedsubtype)
if found then
return found
end
@@ -368,7 +455,12 @@ local function locate(start,wantedid,wantedsubtype)
end
end
-nodes.locate = locate
+nuts.locate = locate
+
+nodes.locate = function(start,wantedid,wantedsubtype)
+ local found = locate(tonut(start),wantedid,wantedsubtype)
+ return found and tonode(found)
+end
-- I have no use for this yet:
--
@@ -381,10 +473,12 @@ nodes.locate = locate
-- return (badness/100)^(1/3)
-- end
--
--- function tex.stretch_amount(skip,badness)
+-- function tex.stretch_amount(skip,badness) -- node no nut
-- if skip.id == gluespec_code then
-- return skip.width + (badness and (badness/100)^(1/3) or 1) * skip.stretch
-- else
-- return 0
-- end
-- end
+
+
diff --git a/tex/context/base/node-bck.lua b/tex/context/base/node-bck.lua
index feaa2c684..d756d43d6 100644
--- a/tex/context/base/node-bck.lua
+++ b/tex/context/base/node-bck.lua
@@ -11,6 +11,8 @@ if not modules then modules = { } end modules ['node-bck'] = {
local attributes, nodes, node = attributes, nodes, node
+local tasks = nodes.tasks
+
local nodecodes = nodes.nodecodes
local listcodes = nodes.listcodes
@@ -19,11 +21,25 @@ local vlist_code = nodecodes.vlist
local glyph_code = nodecodes.glyph
local cell_code = listcodes.cell
-local traverse = node.traverse
-local traverse_id = node.traverse_id
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+
+local traverse = nuts.traverse
+local traverse_id = nuts.traverse_id
-local nodepool = nodes.pool
-local tasks = nodes.tasks
local new_rule = nodepool.rule
local new_glue = nodepool.glue
@@ -37,50 +53,50 @@ local a_alignbackground = attributes.private('alignbackground')
local function add_backgrounds(head) -- rather old code .. to be redone
local current = head
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code or id == vlist_code then
- local list = current.list
+ local list = getlist(current)
if list then
local head = add_backgrounds(list)
if head then
- current.list = head
+ setfield(current,"list",head)
list = head
end
end
- local width = current.width
+ local width = getfield(current,"width")
if width > 0 then
- local background = current[a_background]
+ local background = getattr(current,a_background)
if background then
-- direct to hbox
-- colorspace is already set so we can omit that and stick to color
- local mode = current[a_colorspace]
+ local mode = getattr(current,a_colorspace)
if mode then
- local height = current.height
- local depth = current.depth
+ local height = getfield(current,"height")
+ local depth = getfield(current,"depth")
local skip = id == hlist_code and width or (height + depth)
local glue = new_glue(-skip)
local rule = new_rule(width,height,depth)
- local color = current[a_color]
- local transparency = current[a_transparency]
- rule[a_colorspace] = mode
+ local color = getattr(current,a_color)
+ local transparency = getattr(current,a_transparency)
+ setattr(rule,a_colorspace,mode)
if color then
- rule[a_color] = color
+ setattr(rule,a_color,color)
end
if transparency then
- rule[a_transparency] = transparency
+ setattr(rule,a_transparency,transparency)
end
- rule.next = glue
- glue.prev = rule
+ setfield(rule,"next",glue)
+ setfield(glue,"prev",rule)
if list then
- glue.next = list
- list.prev = glue
+ setfield(glue,"next",list)
+ setfield(list,"prev",glue)
end
- current.list = rule
+ setfield(current,"list",rule)
end
end
end
end
- current = current.next
+ current = getnext(current)
end
return head, true
end
@@ -88,16 +104,16 @@ end
local function add_alignbackgrounds(head)
local current = head
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code then
- local list = current.list
+ local list = getlist(current)
if not list then
-- no need to look
- elseif current.subtype == cell_code then
+ elseif getsubtype(current) == cell_code then
local background = nil
local found = nil
-- for l in traverse(list) do
- -- background = l[a_alignbackground]
+ -- background = getattr(l,a_alignbackground)
-- if background then
-- found = l
-- break
@@ -106,7 +122,7 @@ local function add_alignbackgrounds(head)
-- we know that it's a fake hlist (could be user node)
-- but we cannot store tables in user nodes yet
for l in traverse_id(hpack_code,list) do
- background = l[a_alignbackground]
+ background = getattr(l,a_alignbackground)
if background then
found = l
end
@@ -115,28 +131,28 @@ local function add_alignbackgrounds(head)
--
if background then
-- current has subtype 5 (cell)
- local width = current.width
+ local width = getfield(current,"width")
if width > 0 then
- local mode = found[a_colorspace]
+ local mode = getattr(found,a_colorspace)
if mode then
local glue = new_glue(-width)
- local rule = new_rule(width,current.height,current.depth)
- local color = found[a_color]
- local transparency = found[a_transparency]
- rule[a_colorspace] = mode
+ local rule = new_rule(width,getfield(current,"height"),getfield(current,"depth"))
+ local color = getattr(found,a_color)
+ local transparency = getattr(found,a_transparency)
+ setattr(rule,a_colorspace,mode)
if color then
- rule[a_color] = color
+ setattr(rule,a_color,color)
end
if transparency then
- rule[a_transparency] = transparency
+ setattr(rule,a_transparency,transparency)
end
- rule.next = glue
- glue.prev = rule
+ setfield(rule,"next",glue)
+ setfield(glue,"prev",rule)
if list then
- glue.next = list
- list.prev = glue
+ setfield(glue,"next",list)
+ setfield(list,"prev",glue)
end
- current.list = rule
+ setfield(current,"list",rule)
end
end
end
@@ -144,18 +160,21 @@ local function add_alignbackgrounds(head)
add_alignbackgrounds(list)
end
elseif id == vlist_code then
- local list = current.list
+ local list = getlist(current)
if list then
add_alignbackgrounds(list)
end
end
- current = current.next
+ current = getnext(current)
end
return head, true
end
-nodes.handlers.backgrounds = add_backgrounds
-nodes.handlers.alignbackgrounds = add_alignbackgrounds
+-- nodes.handlers.backgrounds = add_backgrounds
+-- nodes.handlers.alignbackgrounds = add_alignbackgrounds
+
+nodes.handlers.backgrounds = function(head) local head, done = add_backgrounds (tonut(head)) return tonode(head), done end
+nodes.handlers.alignbackgrounds = function(head) local head, done = add_alignbackgrounds(tonut(head)) return tonode(head), done end
tasks.appendaction("shipouts","normalizers","nodes.handlers.backgrounds")
tasks.appendaction("shipouts","normalizers","nodes.handlers.alignbackgrounds")
diff --git a/tex/context/base/node-fin.lua b/tex/context/base/node-fin.lua
index 63a5ef83e..0d095cbde 100644
--- a/tex/context/base/node-fin.lua
+++ b/tex/context/base/node-fin.lua
@@ -8,36 +8,55 @@ if not modules then modules = { } end modules ['node-fin'] = {
-- this module is being reconstructed
-- local functions, only slightly slower
+--
+-- leaders are also triggers
local next, type, format = next, type, string.format
local attributes, nodes, node = attributes, nodes, node
-local copy_node = node.copy
-local find_tail = node.slide
-
-local nodecodes = nodes.nodecodes
-local whatcodes = nodes.whatcodes
-
-local glyph_code = nodecodes.glyph
-local disc_code = nodecodes.disc
-local glue_code = nodecodes.glue
-local rule_code = nodecodes.rule
-local whatsit_code = nodecodes.whatsit
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-
-local pdfliteral_code = whatcodes.pdfliteral
-
-local states = attributes.states
-local numbers = attributes.numbers
-local a_trigger = attributes.private('trigger')
-local triggering = false
-
-local starttiming = statistics.starttiming
-local stoptiming = statistics.stoptiming
-local loadstripped = utilities.lua.loadstripped
-local unsetvalue = attributes.unsetvalue
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getleader = nuts.getleader
+local getattr = nuts.getattr
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local copy_node = nuts.copy
+local find_tail = nuts.slide
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+
+local nodecodes = nodes.nodecodes
+local whatcodes = nodes.whatcodes
+
+local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
+local glue_code = nodecodes.glue
+local rule_code = nodecodes.rule
+local whatsit_code = nodecodes.whatsit
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+
+local pdfliteral_code = whatcodes.pdfliteral
+
+local states = attributes.states
+local numbers = attributes.numbers
+local a_trigger = attributes.private('trigger')
+local triggering = false
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+local loadstripped = utilities.lua.loadstripped
+local unsetvalue = attributes.unsetvalue
-- these two will be like trackers
@@ -102,10 +121,13 @@ function nodes.installattributehandler(plugin)
return loadstripped(template)()
end
--- the injectors
+-- for the moment:
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
+local function copied(n)
+ return copy_node(tonut(n))
+end
+
+-- the injectors
local nsdata, nsnone, nslistwise, nsforced, nsselector, nstrigger
local current, current_selector, done = 0, 0, false -- nb, stack has a local current !
@@ -132,23 +154,25 @@ end
function states.finalize(namespace,attribute,head) -- is this one ok?
if current > 0 and nsnone then
- local id = head.id
+ head = tonut(head)
+ local id = getid(head)
if id == hlist_code or id == vlist_code then
- local list = head.list
+ local list = getlist(head)
if list then
- head.list = insert_node_before(list,list,copy_node(nsnone))
+ list = insert_node_before(list,list,copied(nsnone)) -- two return values
+ setfield(head,"list",list)
end
else
- head = insert_node_before(head,head,copy_node(nsnone))
+ head = insert_node_before(head,head,copied(nsnone))
end
- return head, true, true
+ return tonode(head), true, true
end
return head, false, false
end
-- disc nodes can be ignored
-- we need to deal with literals too (reset as well as oval)
--- if id == glyph_code or (id == whatsit_code and stack.subtype == pdfliteral_code) or (id == rule_code and stack.width ~= 0) or (id == glue_code and stack.leader) then
+-- if id == glyph_code or (id == whatsit_code and getsubtype(stack) == pdfliteral_code) or (id == rule_code and stack.width ~= 0) or (id == glue_code and stack.leader) then
local function process(namespace,attribute,head,inheritance,default) -- one attribute
local stack = head
@@ -156,53 +180,57 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr
local check = false
local leader = nil
while stack do
- local id = stack.id
+ local id = getid(stack)
if id == glyph_code then
check = true
elseif id == glue_code then
- leader = stack.leader
+ leader = getleader(stack)
if leader then
check = true
end
elseif id == hlist_code or id == vlist_code then
- local content = stack.list
+ local content = getlist(stack)
if content then
-- begin nested --
- local ok
- if nstrigger and stack[nstrigger] then
- local outer = stack[attribute]
+ if nstrigger and getattr(stack,nstrigger) then
+ local outer = getattr(stack,attribute)
if outer ~= inheritance then
- stack.list, ok = process(namespace,attribute,content,inheritance,outer)
+ local list, ok = process(namespace,attribute,content,inheritance,outer)
+ setfield(stack,"list",list)
+ done = done or ok
else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
+ local list, ok = process(namespace,attribute,content,inheritance,default)
+ setfield(stack,"list",list)
+ done = done or ok
end
else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
+ local list, ok = process(namespace,attribute,content,inheritance,default)
+ setfield(stack,"list",list)
+ done = done or ok
end
-- end nested --
- done = done or ok
end
elseif id == rule_code then
- check = stack.width ~= 0
+ check = getfield(stack,"width") ~= 0
end
-- much faster this way than using a check() and nested() function
if check then
- local c = stack[attribute]
+ local c = getattr(stack,attribute)
if c then
if default and c == inheritance then
if current ~= default then
- head = insert_node_before(head,stack,copy_node(nsdata[default]))
+ head = insert_node_before(head,stack,copied(nsdata[default]))
current = default
done = true
end
elseif current ~= c then
- head = insert_node_before(head,stack,copy_node(nsdata[c]))
+ head = insert_node_before(head,stack,copied(nsdata[c]))
current = c
done = true
end
if leader then
local savedcurrent = current
- local ci = leader.id
+ local ci = getid(leader)
if ci == hlist_code or ci == vlist_code then
-- else we reset inside a box unneeded, okay, the downside is
-- that we trigger color in each repeated box, so there is room
@@ -210,41 +238,48 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr
current = 0
end
-- begin nested --
- local ok = false
- if nstrigger and stack[nstrigger] then
- local outer = stack[attribute]
+ if nstrigger and getattr(stack,nstrigger) then
+ local outer = getattr(stack,attribute)
if outer ~= inheritance then
- stack.leader, ok = process(namespace,attribute,leader,inheritance,outer)
+ local list, ok = process(namespace,attribute,leader,inheritance,outer)
+ setfield(stack,"leader",list)
+ done = done or ok
else
- stack.leader, ok = process(namespace,attribute,leader,inheritance,default)
+ local list, ok = process(namespace,attribute,leader,inheritance,default)
+ setfield(stack,"leader",list)
+ done = done or ok
end
else
- stack.leader, ok = process(namespace,attribute,leader,inheritance,default)
+ local list, ok = process(namespace,attribute,leader,inheritance,default)
+ setfield(stack,"leader",list)
+ done = done or ok
end
-- end nested --
- done = done or ok
current = savedcurrent
leader = false
end
elseif default and inheritance then
if current ~= default then
- head = insert_node_before(head,stack,copy_node(nsdata[default]))
+ head = insert_node_before(head,stack,copied(nsdata[default]))
current = default
done = true
end
elseif current > 0 then
- head = insert_node_before(head,stack,copy_node(nsnone))
+ head = insert_node_before(head,stack,copied(nsnone))
current = 0
done = true
end
check = false
end
- stack = stack.next
+ stack = getnext(stack)
end
return head, done
end
-states.process = process
+states.process = function(namespace,attribute,head,default)
+ local head, done = process(namespace,attribute,tonut(head),default)
+ return tonode(head), done
+end
-- we can force a selector, e.g. document wide color spaces, saves a little
-- watch out, we need to check both the selector state (like colorspace) and
@@ -258,93 +293,103 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at
local check = false
local leader = nil
while stack do
- local id = stack.id
+ local id = getid(stack)
if id == glyph_code then
check = true
elseif id == glue_code then
- leader = stack.leader
+ leader = getleader(stack)
if leader then
check = true
end
elseif id == hlist_code or id == vlist_code then
- local content = stack.list
+ local content = getlist(stack)
if content then
- local ok = false
-- begin nested
- if nstrigger and stack[nstrigger] then
- local outer = stack[attribute]
+ if nstrigger and getattr(stack,nstrigger) then
+ local outer = getattr(stack,attribute)
if outer ~= inheritance then
- stack.list, ok = selective(namespace,attribute,content,inheritance,outer)
+ local list, ok = selective(namespace,attribute,content,inheritance,outer)
+ setfield(stack,"list",list)
+ done = done or ok
else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
+ local list, ok = selective(namespace,attribute,content,inheritance,default)
+ setfield(stack,"list",list)
+ done = done or ok
end
else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
+ local list, ok = selective(namespace,attribute,content,inheritance,default)
+ setfield(stack,"list",list)
+ done = done or ok
end
-- end nested
- done = done or ok
end
elseif id == rule_code then
- check = stack.width ~= 0
+ check = getfield(stack,"width") ~= 0
end
if check then
- local c = stack[attribute]
+ local c = getattr(stack,attribute)
if c then
if default and c == inheritance then
if current ~= default then
local data = nsdata[default]
- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector]))
+ head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector]))
current = default
done = true
end
else
- local s = stack[nsselector]
+ local s = getattr(stack,nsselector)
if current ~= c or current_selector ~= s then
local data = nsdata[c]
- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector]))
+ head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector]))
current = c
current_selector = s
done = true
end
end
if leader then
- local ok = false
-- begin nested
- if nstrigger and stack[nstrigger] then
- local outer = stack[attribute]
+ if nstrigger and getattr(stack,nstrigger) then
+ local outer = getatribute(stack,attribute)
if outer ~= inheritance then
- stack.leader, ok = selective(namespace,attribute,leader,inheritance,outer)
+ local list, ok = selective(namespace,attribute,leader,inheritance,outer)
+ setfield(stack,"leader",list)
+ done = done or ok
else
- stack.leader, ok = selective(namespace,attribute,leader,inheritance,default)
+ local list, ok = selective(namespace,attribute,leader,inheritance,default)
+ setfield(stack,"leader",list)
+ done = done or ok
end
else
- stack.leader, ok = selective(namespace,attribute,leader,inheritance,default)
+ local list, ok = selective(namespace,attribute,leader,inheritance,default)
+ setfield(stack,"leader",list)
+ done = done or ok
end
-- end nested
- done = done or ok
- leader = false
+ leader = false
end
elseif default and inheritance then
if current ~= default then
local data = nsdata[default]
- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector]))
+ head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector]))
current = default
done = true
end
elseif current > 0 then
- head = insert_node_before(head,stack,copy_node(nsnone))
+ head = insert_node_before(head,stack,copied(nsnone))
current, current_selector, done = 0, 0, true
end
check = false
end
-
- stack = stack.next
+ stack = getnext(stack)
end
return head, done
end
-states.selective = selective
+states.selective = function(namespace,attribute,head,default)
+ local head, done = selective(namespace,attribute,tonut(head),default)
+ return tonode(head), done
+end
-- Ideally the next one should be merged with the previous but keeping it separate is
-- safer. We deal with two situations: efficient boxwise (layoutareas) and mixed layers
@@ -363,76 +408,80 @@ local function stacked(namespace,attribute,head,default) -- no triggering, no in
local check = false
local leader = false
while stack do
- local id = stack.id
+ local id = getid(stack)
if id == glyph_code then
check = true
elseif id == glue_code then
- leader = stack.leader
+ leader = getleader(stack)
if leader then
check = true
end
elseif id == hlist_code or id == vlist_code then
- local content = stack.list
+ local content = getlist(stack)
if content then
-- the problem is that broken lines gets the attribute which can be a later one
if nslistwise then
- local a = stack[attribute]
+ local a = getattr(stack,attribute)
if a and current ~= a and nslistwise[a] then -- viewerlayer / needs checking, see below
local p = current
- current, done = a, true
- head = insert_node_before(head,stack,copy_node(nsdata[a]))
- stack.list = stacked(namespace,attribute,content,current)
- head, stack = insert_node_after(head,stack,copy_node(nsnone))
+ current = a
+ head = insert_node_before(head,stack,copied(nsdata[a]))
+ local list = stacked(namespace,attribute,content,current) -- two return values
+ setfield(stack,"list",list)
+ done = true
+ head, stack = insert_node_after(head,stack,copied(nsnone))
current = p
else
- local ok = false
- stack.list, ok = stacked(namespace,attribute,content,current)
+ local list, ok = stacked(namespace,attribute,content,current)
+ setfield(stack,"list",list) -- only if ok
done = done or ok
end
else
- local ok = false
- stack.list, ok = stacked(namespace,attribute,content,current)
+ local list, ok = stacked(namespace,attribute,content,current)
+ setfield(stack,"list",list) -- only if ok
done = done or ok
end
end
elseif id == rule_code then
- check = stack.width ~= 0
+ check = getfield(stack,"width") ~= 0
end
if check then
- local a = stack[attribute]
+ local a = getattr(stack,attribute)
if a then
if current ~= a then
- head = insert_node_before(head,stack,copy_node(nsdata[a]))
+ head = insert_node_before(head,stack,copied(nsdata[a]))
depth = depth + 1
current, done = a, true
end
if leader then
- local ok = false
- stack.leader, ok = stacked(namespace,attribute,content,current)
+ local list, ok = stacked(namespace,attribute,content,current)
+ setfield(stack,"leader",list) -- only if ok
done = done or ok
leader = false
end
elseif default > 0 then
--
elseif current > 0 then
- head = insert_node_before(head,stack,copy_node(nsnone))
+ head = insert_node_before(head,stack,copied(nsnone))
depth = depth - 1
current, done = 0, true
end
check = false
end
-
- stack = stack.next
+ stack = getnext(stack)
end
while depth > 0 do
- head = insert_node_after(head,stack,copy_node(nsnone))
+ head = insert_node_after(head,stack,copied(nsnone))
depth = depth - 1
end
return head, done
end
-states.stacked = stacked
+states.stacked = function(namespace,attribute,head,default)
+ local head, done = stacked(namespace,attribute,tonut(head),default)
+ return tonode(head), done
+end
-- experimental
@@ -446,52 +495,53 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in
local check = false
local leader = false
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
check = true
elseif id == glue_code then
- leader = current.leader
+ leader = getleader(current)
if leader then
check = true
end
elseif id == hlist_code or id == vlist_code then
- local content = current.list
+ local content = getlist(current)
if not content then
-- skip
elseif nslistwise then
- local a = current[attribute]
+ local a = getattr(current,attribute)
if a and attrib ~= a and nslistwise[a] then -- viewerlayer
+ head = insert_node_before(head,current,copied(nsdata[a]))
+ local list = stacker(namespace,attribute,content,a)
+ setfield(current,"list",list)
done = true
- head = insert_node_before(head,current,copy_node(nsdata[a]))
- current.list = stacker(namespace,attribute,content,a)
- head, current = insert_node_after(head,current,copy_node(nsnone))
+ head, current = insert_node_after(head,current,copied(nsnone))
else
- local ok = false
- current.list, ok = stacker(namespace,attribute,content,attrib)
+ local list, ok = stacker(namespace,attribute,content,attrib)
+ setfield(current,"list",list)
done = done or ok
end
else
- local ok = false
- current.list, ok = stacker(namespace,attribute,content,default)
+ local list, ok = stacker(namespace,attribute,content,default)
+ setfield(current,"list",list)
done = done or ok
end
elseif id == rule_code then
- check = current.width ~= 0
+ check = getfield(current,"width") ~= 0
end
if check then
- local a = current[attribute] or unsetvalue
+ local a = getattr(current,attribute) or unsetvalue
if a ~= attrib then
local n = nsstep(a)
if n then
-- !!!! TEST CODE !!!!
- -- head = insert_node_before(head,current,copy_node(nsdata[tonumber(n)])) -- a
- head = insert_node_before(head,current,n) -- a
+ -- head = insert_node_before(head,current,copied(nsdata[tonumber(n)])) -- a
+ head = insert_node_before(head,current,tonut(n)) -- a
end
attrib, done, okay = a, true, true
if leader then
-- tricky as a leader has to be a list so we cannot inject before
- local _, ok = stacker(namespace,attribute,leader,attrib)
+ local list, ok = stacker(namespace,attribute,leader,attrib)
done = done or ok
leader = false
end
@@ -500,20 +550,23 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in
end
previous = current
- current = current.next
+ current = getnext(current)
end
if okay then
local n = nsend()
if n then
-- !!!! TEST CODE !!!!
- -- head = insert_node_after(head,previous,copy_node(nsdata[tostring(n)]))
- head = insert_node_after(head,previous,n)
+ -- head = insert_node_after(head,previous,copied(nsdata[tostring(n)]))
+ head = insert_node_after(head,previous,tonut(n))
end
end
return head, done
end
-states.stacker = stacker
+states.stacker = function(namespace,attribute,head,default)
+ local head, done = stacker(namespace,attribute,tonut(head),default)
+ return tonode(head), done
+end
-- -- --
diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua
index 2f59d513c..7000c4fd7 100644
--- a/tex/context/base/node-fnt.lua
+++ b/tex/context/base/node-fnt.lua
@@ -23,12 +23,24 @@ local fontdata = fonthashes.identifiers
local otf = fonts.handlers.otf
-local traverse_id = node.traverse_id
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
+
local nodecodes = nodes.nodecodes
local handlers = nodes.handlers
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getattr = nuts.getattr
+local getid = nuts.getid
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getnext = nuts.getnext
+
+local traverse_id = nuts.traverse_id
+
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
@@ -109,25 +121,25 @@ function handlers.characters(head)
report_fonts()
report_fonts("checking node list, run %s",run)
report_fonts()
- local n = head
+ local n = tonut(head)
while n do
- local id = n.id
+ local id = getid(n)
if id == glyph_code then
- local font = n.font
- local attr = n[0] or 0
- report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,n.char)
+ local font = getfont(n)
+ local attr = getattr(n,0) or 0
+ report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,getchar(n))
elseif id == disc_code then
report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n))
else
report_fonts("[%s]",nodecodes[id])
end
- n = n.next
+ n = getnext(n)
end
end
- for n in traverse_id(glyph_code,head) do
- -- if n.subtype<256 then -- all are 1
- local font = n.font
- local attr = n[0] or 0 -- zero attribute is reserved for fonts in context
+ for n in traverse_id(glyph_code,tonut(head)) do
+ -- if getsubtype(n) <256 then -- all are 1
+ local font = getfont(n)
+ local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
if font ~= prevfont or attr ~= prevattr then
if attr > 0 then
local used = attrfonts[font]
@@ -391,5 +403,8 @@ end
-- return head, true
-- end
-handlers.protectglyphs = node.protect_glyphs
-handlers.unprotectglyphs = node.unprotect_glyphs
+local d_protect_glyphs = nuts.protect_glyphs
+local d_unprotect_glyphs = nuts.unprotect_glyphs
+
+handlers.protectglyphs = function(n) return d_protect_glyphs (tonut(n)) end
+handlers.unprotectglyphs = function(n) return d_unprotect_glyphs(tonut(n)) end
diff --git a/tex/context/base/node-inj.lua b/tex/context/base/node-inj.lua
index ae48150a6..f30070e9e 100644
--- a/tex/context/base/node-inj.lua
+++ b/tex/context/base/node-inj.lua
@@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['node-inj'] = {
-- test fonts. Btw, future versions of luatex will have extended glyph properties
-- that can be of help. Some optimizations can go away when we have faster machines.
--- todo: make a special one for context
+-- todo: ignore kerns between disc and glyph
local next = next
local utfchar = utf.char
@@ -30,13 +30,32 @@ local injections = nodes.injections
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
-local nodepool = nodes.pool
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
local newkern = nodepool.kern
-local traverse_id = node.traverse_id
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local traverse_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
local a_kernpair = attributes.private('kernpair')
local a_ligacomp = attributes.private('ligacomp')
@@ -71,8 +90,8 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
local ws, wn = tfmstart.width, tfmnext.width
local bound = #cursives + 1
- start[a_cursbase] = bound
- nxt[a_curscurs] = bound
+ setattr(start,a_cursbase,bound)
+ setattr(nxt,a_curscurs,bound)
cursives[bound] = { rlmode, dx, dy, ws, wn }
return dx, dy, bound
end
@@ -81,14 +100,14 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
-- dy = y - h
if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
- local bound = current[a_kernpair]
+ local bound = getattr(current,a_kernpair)
if bound then
local kb = kerns[bound]
-- inefficient but singles have less, but weird anyway, needs checking
kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
else
bound = #kerns + 1
- current[a_kernpair] = bound
+ setattr(current,a_kernpair,bound)
kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
end
return x, y, w, h, bound
@@ -100,7 +119,7 @@ function injections.setkern(current,factor,rlmode,x,tfmchr)
local dx = factor*x
if dx ~= 0 then
local bound = #kerns + 1
- current[a_kernpair] = bound
+ setattr(current,a_kernpair,bound)
kerns[bound] = { rlmode, dx }
return dx, bound
else
@@ -110,7 +129,7 @@ end
function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) -- ba=baseanchor, ma=markanchor
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) -- the index argument is no longer used but when this
- local bound = base[a_markbase] -- fails again we should pass it
+ local bound = getattr(base,a_markbase) -- fails again we should pass it
local index = 1
if bound then
local mb = marks[bound]
@@ -118,19 +137,19 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) --
-- if not index then index = #mb + 1 end
index = #mb + 1
mb[index] = { dx, dy, rlmode }
- start[a_markmark] = bound
- start[a_markdone] = index
+ setattr(start,a_markmark,bound)
+ setattr(start,a_markdone,index)
return dx, dy, bound
else
- report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
+ report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
end
end
-- index = index or 1
index = index or 1
bound = #marks + 1
- base[a_markbase] = bound
- start[a_markmark] = bound
- start[a_markdone] = index
+ setattr(base,a_markbase,bound)
+ setattr(start,a_markmark,bound)
+ setattr(start,a_markdone,index)
marks[bound] = { [index] = { dx, dy, rlmode, baseismark } }
return dx, dy, bound
end
@@ -142,15 +161,15 @@ end
local function trace(head)
report_injections("begin run")
for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- local kp = n[a_kernpair]
- local mb = n[a_markbase]
- local mm = n[a_markmark]
- local md = n[a_markdone]
- local cb = n[a_cursbase]
- local cc = n[a_curscurs]
- local char = n.char
- report_injections("font %s, char %U, glyph %c",n.font,char,char)
+ if getsubtype(n) < 256 then
+ local kp = getattr(n,a_kernpair)
+ local mb = getattr(n,a_markbase)
+ local mm = getattr(n,a_markmark)
+ local md = getattr(n,a_markdone)
+ local cb = getattr(n,a_cursbase)
+ local cc = getattr(n,a_curscurs)
+ local char = getchar(n)
+ report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
if kp then
local k = kerns[kp]
if k[3] then
@@ -198,22 +217,24 @@ local function show_result(head)
local current = head
local skipping = false
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",
+ getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
skipping = false
elseif id == kern_code then
- report_injections("kern: %p",current.kern)
+ report_injections("kern: %p",getfield(current,"kern"))
skipping = false
elseif not skipping then
report_injections()
skipping = true
end
- current = current.next
+ current = getnext(current)
end
end
function injections.handler(head,where,keep)
+ head = tonut(head)
local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
if has_marks or has_cursives then
if trace_injections then
@@ -224,17 +245,18 @@ function injections.handler(head,where,keep)
if has_kerns then -- move outside loop
local nf, tm = nil, nil
for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
- if n.subtype < 256 then
+ if getsubtype(n) < 256 then
nofvalid = nofvalid + 1
valid[nofvalid] = n
- if n.font ~= nf then
- nf = n.font
- tm = fontdata[nf].resources.marks
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
end
if tm then
- mk[n] = tm[n.char]
+ mk[n] = tm[getchar(n)]
end
- local k = n[a_kernpair]
+ local k = getattr(n,a_kernpair)
if k then
local kk = kerns[k]
if kk then
@@ -254,15 +276,16 @@ function injections.handler(head,where,keep)
else
local nf, tm = nil, nil
for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
+ if getsubtype(n) < 256 then
nofvalid = nofvalid + 1
valid[nofvalid] = n
- if n.font ~= nf then
- nf = n.font
- tm = fontdata[nf].resources.marks
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
end
if tm then
- mk[n] = tm[n.char]
+ mk[n] = tm[getchar(n)]
end
end
end
@@ -272,7 +295,7 @@ function injections.handler(head,where,keep)
local cx = { }
if has_kerns and next(ky) then
for n, k in next, ky do
- n.yoffset = k
+ setfield(n,"yoffset",k)
end
end
-- todo: reuse t and use maxt
@@ -283,9 +306,9 @@ function injections.handler(head,where,keep)
for i=1,nofvalid do -- valid == glyphs
local n = valid[i]
if not mk[n] then
- local n_cursbase = n[a_cursbase]
+ local n_cursbase = getattr(n,a_cursbase)
if p_cursbase then
- local n_curscurs = n[a_curscurs]
+ local n_curscurs = getattr(n,a_curscurs)
if p_cursbase == n_curscurs then
local c = cursives[n_curscurs]
if c then
@@ -310,20 +333,20 @@ function injections.handler(head,where,keep)
end
end
elseif maxt > 0 then
- local ny = n.yoffset
+ local ny = getfield(n,"yoffset")
for i=maxt,1,-1 do
ny = ny + d[i]
local ti = t[i]
- ti.yoffset = ti.yoffset + ny
+ setfield(ti,"yoffset",getfield(ti,"yoffset") + ny)
end
maxt = 0
end
if not n_cursbase and maxt > 0 then
- local ny = n.yoffset
+ local ny = getfield(n,"yoffset")
for i=maxt,1,-1 do
ny = ny + d[i]
local ti = t[i]
- ti.yoffset = ny
+ setfield(ti,"yoffset",ny)
end
maxt = 0
end
@@ -331,11 +354,11 @@ function injections.handler(head,where,keep)
end
end
if maxt > 0 then
- local ny = n.yoffset
+ local ny = getfield(n,"yoffset")
for i=maxt,1,-1 do
ny = ny + d[i]
local ti = t[i]
- ti.yoffset = ny
+ setfield(ti,"yoffset",ny)
end
maxt = 0
end
@@ -346,57 +369,83 @@ function injections.handler(head,where,keep)
if has_marks then
for i=1,nofvalid do
local p = valid[i]
- local p_markbase = p[a_markbase]
+ local p_markbase = getattr(p,a_markbase)
if p_markbase then
- local mrks = marks[p_markbase]
- local nofmarks = #mrks
- for n in traverse_id(glyph_code,p.next) do
- local n_markmark = n[a_markmark]
+ local mrks = marks[p_markbase]
+ local nofmarks = #mrks
+ for n in traverse_id(glyph_code,getnext(p)) do
+ local n_markmark = getattr(n,a_markmark)
if p_markbase == n_markmark then
- local index = n[a_markdone] or 1
+ local index = getattr(n,a_markdone) or 1
local d = mrks[index]
if d then
local rlmode = d[3]
--
local k = wx[p]
+ local px = getfield(p,"xoffset")
+ local ox = 0
if k then
local x = k[2]
local w = k[4]
if w then
if rlmode and rlmode >= 0 then
-- kern(x) glyph(p) kern(w-x) mark(n)
- n.xoffset = p.xoffset - p.width + d[1] - (w-x)
+ ox = px - getfield(p,"width") + d[1] - (w-x)
+ -- report_injections("l2r case 1: %p",ox)
else
-- kern(w-x) glyph(p) kern(x) mark(n)
- n.xoffset = p.xoffset - d[1] - x
+ ox = px - d[1] - x
+ -- report_injections("r2l case 1: %p",ox)
end
else
if rlmode and rlmode >= 0 then
-- okay for husayni
- n.xoffset = p.xoffset - p.width + d[1]
+ ox = px - getfield(p,"width") + d[1]
+ -- report_injections("r2l case 2: %p",ox)
else
-- needs checking: is x ok here?
- n.xoffset = p.xoffset - d[1] - x
+ ox = px - d[1] - x
+ -- report_injections("r2l case 2: %p",ox)
end
end
else
+ -- if rlmode and rlmode >= 0 then
+ -- ox = px - getfield(p,"width") + d[1]
+ -- -- report_injections("l2r case 3: %p",ox)
+ -- else
+ -- ox = px - d[1]
+ -- -- report_injections("r2l case 3: %p",ox)
+ -- end
+ --
+ -- we need to deal with fonts that have marks with width
+ --
+ local wp = getfield(p,"width")
+ local wn = getfield(n,"width") -- in arial marks have widths
if rlmode and rlmode >= 0 then
- n.xoffset = p.xoffset - p.width + d[1]
+ ox = px - wp + d[1]
+ -- report_injections("l2r case 3: %p",ox)
else
- n.xoffset = p.xoffset - d[1]
+ ox = px - d[1]
+ -- report_injections("r2l case 3: %p",ox)
end
- local w = n.width
- if w ~= 0 then
- insert_node_before(head,n,newkern(-w/2))
- insert_node_after(head,n,newkern(-w/2))
+ if wn ~= 0 then
+ -- bad: we should center
+ insert_node_before(head,n,newkern(-wn/2))
+ insert_node_after(head,n,newkern(-wn/2))
+ -- wx[n] = { 0, -wn/2, 0, -wn }
end
+ -- so far
end
- -- --
+ setfield(n,"xoffset",ox)
+ --
+ local py = getfield(p,"yoffset")
+ local oy = 0
if mk[p] then
- n.yoffset = p.yoffset + d[2]
+ oy = py + d[2]
else
- n.yoffset = n.yoffset + p.yoffset + d[2]
+ oy = getfield(n,"yoffset") + py + d[2]
end
+ setfield(n,"yoffset",oy)
--
if nofmarks == 1 then
break
@@ -404,6 +453,8 @@ function injections.handler(head,where,keep)
nofmarks = nofmarks - 1
end
end
+ elseif not n_markmark then
+ break -- HH: added 2013-09-12: no need to deal with non marks
else
-- KE: there can be <mark> <mkmk> <mark> sequences in ligatures
end
@@ -465,6 +516,7 @@ function injections.handler(head,where,keep)
-- if trace_injections then
-- show_result(head)
-- end
+head = tonode(head)
return head, true
elseif not keep then
kerns, cursives, marks = { }, { }, { }
@@ -474,14 +526,14 @@ function injections.handler(head,where,keep)
trace(head)
end
for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- local k = n[a_kernpair]
+ if getsubtype(n) < 256 then
+ local k = getattr(n,a_kernpair)
if k then
local kk = kerns[k]
if kk then
local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
if y and y ~= 0 then
- n.yoffset = y -- todo: h ?
+ setfield(n,"yoffset",y) -- todo: h ?
end
if w then
-- copied from above
@@ -518,9 +570,9 @@ function injections.handler(head,where,keep)
-- if trace_injections then
-- show_result(head)
-- end
- return head, true
+ return tonode(head), true
else
-- no tracing needed
end
- return head, false
+ return tonode(head), false
end
diff --git a/tex/context/base/node-ltp.lua b/tex/context/base/node-ltp.lua
deleted file mode 100644
index c52e001df..000000000
--- a/tex/context/base/node-ltp.lua
+++ /dev/null
@@ -1,3192 +0,0 @@
-if not modules then modules = { } end modules ['node-par'] = {
- version = 1.001,
- comment = "companion to node-par.mkiv",
- author = "Hans Hagen",
- copyright = "ConTeXt Development Team",
- license = "see context related readme files",
- comment = "a translation of the built in parbuilder, initial convertsin by Taco Hoekwater",
-}
-
--- todo: remove nest_stack from linebreak.w
--- todo: use ex field as signal (index in ?)
--- todo: attr driven unknown/on/off
--- todo: permit global steps i.e. using an attribute that sets min/max/step and overloads the font parameters
--- todo: split the three passes into three functions
--- todo: simplify the direction stack, no copy needed
--- todo: see if we can do without delta nodes (needs thinking)
--- todo: add more mkiv like tracing
--- todo: add a couple of plugin hooks
--- todo: maybe split expansion code paths
--- todo: fix line numbers (cur_list.pg_field needed)
--- todo: make kerns stretch an option and disable it by default (definitely not shrink)
--- todo: check and improve protrusion
--- todo: arabic etc (we could use pretty large scales there) .. marks and cursive
-
---[[
-
- This code is derived from traditional TeX and has bits of pdfTeX, Aleph (Omega), and of course LuaTeX. So,
- the basic algorithm for sure is not our work. On the other hand, the directional model in LuaTeX is cleaned
- up as is other code. And of course there are hooks for callbacks.
-
- The first version of the code below was a conversion of the C code that in turn was a conversion from the
- original Pascal code. Around September 2008 we experimented with cq. discussed possible approaches to improved
- typesetting of Arabic and as our policy is that extensions happen in Lua this means that we need a parbuilder
- in Lua. Taco's first conversion still looked quite C-ish and in the process of cleaning up we uncovered some odd
- bits and pieces in the original code as well. I did some first cleanup to get rid of C-artefacts, and Taco and I
- spent the usual amount of Skyping to sort out problems. At that point we diverted to other LuaTeX issues.
-
- A while later I decided to pick up this thread and decided to look into better ways to deal with font expansion
- (aka hz). I got it running using a simpler method. One reason why the built-in mechanims is slow is that there is
- lots of redudancy in calculations. Expanded widths are recalculated each time and because the hpakc routine does
- it again that gives some overhead. In the process extra fonts are created with different dimensions so that the
- backend can deal with it. The alternative method doesn't create fonts but passes an expansion factor to the
- pdf generator. The small patch needed for the backend code worked more or less okay but was never intergated into
- LuaTeX due to lack of time.
-
- This all happened in 2010 while listening to Peter Gabriels "Scratch My Back" and Camels "Rayaz" so it was a
- rather relaxed job.
-
- In 2012 I picked up this thread. Because both languages are similar but also quite different it took some time
- to get compatible output. Because the C code uses macros, careful checking was needed. Of course Lua's table model
- and local variables brought some work as well. And still the code looks a bit C-ish. We could not divert too much
- from the original model simply because it's well documented but future versions (or variants) might as well look
- different.
-
- Eventually I'll split this code into passes so that we can better see what happens, but first we need to reach
- a decent level of stability. The current expansion results are not the same as the built-in but that was never
- the objective. It all has to do with slightly different calculations.
-
- The original C-code related to protrusion and expansion is not that efficient as many (redundant) function
- calls take place in the linebreaker and packer. As most work related to fonts is done in the backend, we
- can simply stick to width calculations here. Also, it is no problem at all that we use floating point
- calculations (as Lua has only floats). The final result will look ok as the hpack will nicely compensate
- for rounding errors as it will normally distribute the content well enough. And let's admit: most texies
- won't see it anyway. As long as we're cross platform compatible it's fine.
-
- We use the table checked_expansion to keep track of font related parameters (per paragraph). The table is
- also the signal that we have adjustments > 1. In retrospect one might wonder if adjusting kerns is such a
- good idea because other spacing is also not treated. If we would stick to the regular hpack routine
- we do have to follow the same logic, but I decided to use a Lua hpacker so that constraint went away. And
- anyway, instead of doing a lookup in the kern table (that we don't have in node mode) the set kern value
- is used. Disabling kern scaling will become an option in Luatex some day. You can blame me for all errors
- that crept in and I know that there are some.
-
- To be honest, I slowly start to grasp the magic here as normally I start from scratch when implementing
- something (as it's the only way I can understand things). This time I had a recently acquired stack of
- Porcupine Tree disks to get me through.
-
- Picking up this effort was inspired by discussions between Luigi Scarso and me about efficiency of Lua
- code and we needed some stress tests to compare regular LuaTeX and LuajitTeX. One of the tests was
- processing tufte.tex as that one has lots of hyphenations and is a tough one to get right.
-
- tufte: boxed 1000 times, no flushing in backend:
-
- \testfeatureonce{1000}{\setbox0\hbox{\tufte}}
- \testfeatureonce{1000}{\setbox0\vbox{\tufte}}
- \startparbuilder[basic]\testfeatureonce{1000}{\setbox0\vbox{\tufte}}\stopparbuilder
-
- method normal hz comment
-
- luatex tex hbox 9.64 9.64 baseline font feature processing, hyphenation etc: 9.74
- tex vbox 9.84 10.16 0.20 linebreak / 0.52 with hz -> 0.32 hz overhead (150pct more)
- lua vbox 17.28 18.43 7.64 linebreak / 8.79 with hz -> 1.33 hz overhead ( 20pct more)
-
- new laptop | no nuts
- 3.42 baseline
- 3.63 0.21 linebreak
- 7.38 3.96 linebreak
-
- new laptop | most nuts
- 2.45 baseline
- 2.53 0.08 linebreak
- 6.16 3.71 linebreak
- ltp nuts 5.45 3.00 linebreak
-
- luajittex tex hbox 6.33 6.33 baseline font feature processing, hyphenation etc: 6.33
- tex vbox 6.53 6.81 0.20 linebreak / 0.48 with hz -> 0.28 hz overhead (expected 0.32)
- lua vbox 11.06 11.81 4.53 linebreak / 5.28 with hz -> 0.75 hz overhead
-
- new laptop | no nuts
- 2.06 baseline
- 2.27 0.21 linebreak
- 3.95 1.89 linebreak
-
- new laptop | most nuts
- 1.25 baseline
- 1.30 0.05 linebreak
- 3.03 1.78 linebreak
- ltp nuts 2.47 1.22 linebreak
-
- Interesting is that the runtime for the built-in parbuilder indeed increases much when expansion
- is enabled, but in the Lua variant the extra overhead is way less significant. This means that when we
- retrofit the same approach into the core, the overhead of expansion can be sort of nilled.
-
-]]--
-
-local utfchar = utf.char
-local write, write_nl = texio.write, texio.write_nl
-local sub, format = string.sub, string.format
-local round, floor = math.round, math.floor
-local insert, remove = table.insert, table.remove
-
-local fonts, nodes, node = fonts, nodes, node
-
-local trace_basic = false trackers.register("builders.paragraphs.basic", function(v) trace_basic = v end)
-local trace_lastlinefit = false trackers.register("builders.paragraphs.lastlinefit", function(v) trace_lastlinefit = v end)
-local trace_adjusting = false trackers.register("builders.paragraphs.adjusting", function(v) trace_adjusting = v end)
-local trace_protruding = false trackers.register("builders.paragraphs.protruding", function(v) trace_protruding = v end)
-local trace_expansion = false trackers.register("builders.paragraphs.expansion", function(v) trace_expansion = v end)
-local trace_quality = false trackers.register("builders.paragraphs.quality", function(v) trace_quality = v end)
-
-local report_parbuilders = logs.reporter("nodes","parbuilders")
-local report_hpackers = logs.reporter("nodes","hpackers")
-
-local calculate_badness = tex.badness
-local texnest = tex.nest
-local texlists = tex.lists
-
--- (t == 0 and 0) or (s <= 0 and 10000) or calculate_badness(t,s)
-
--- local function calculate_badness(t,s)
--- if t == 0 then
--- return 0
--- elseif s <= 0 then
--- return 10000 -- infinite_badness
--- else
--- local r
--- if t <= 7230584 then
--- r = (t * 297) / s
--- elseif s >= 1663497 then
--- r = t / (s / 297)
--- else
--- r = t
--- end
--- if r > 1290 then
--- return 10000 -- infinite_badness
--- else
--- return (r * r * r + 0x20000) / 0x40000
--- end
--- end
--- end
-
-local parbuilders = builders.paragraphs
-local constructors = parbuilders.constructors
-
-local setmetatableindex = table.setmetatableindex
-
-local fonthashes = fonts.hashes
-local fontdata = fonthashes.identifiers
-local chardata = fonthashes.characters
-local quaddata = fonthashes.quads
-local parameters = fonthashes.parameters
-
-local slide_nodes = node.slide
-local new_node = node.new
-local copy_node = node.copy
-local copy_node_list = node.copy_list
-local flush_node = node.free
-local flush_node_list = node.flush_list
-local hpack_nodes = node.hpack
-local xpack_nodes = node.hpack
-local replace_node = nodes.replace
-local insert_node_after = node.insert_after
-local insert_node_before = node.insert_before
-local traverse_by_id = node.traverse_id
-
-local setnodecolor = nodes.tracers.colors.set
-
-local nodepool = nodes.pool
-
-local nodecodes = nodes.nodecodes
-local whatcodes = nodes.whatcodes
-local kerncodes = nodes.kerncodes
-local glyphcodes = nodes.glyphcodes
-local gluecodes = nodes.gluecodes
-local margincodes = nodes.margincodes
-local disccodes = nodes.disccodes
-local mathcodes = nodes.mathcodes
-local fillcodes = nodes.fillcodes
-
-local temp_code = nodecodes.temp
-local glyph_code = nodecodes.glyph
-local ins_code = nodecodes.ins
-local mark_code = nodecodes.mark
-local adjust_code = nodecodes.adjust
-local penalty_code = nodecodes.penalty
-local whatsit_code = nodecodes.whatsit
-local disc_code = nodecodes.disc
-local math_code = nodecodes.math
-local kern_code = nodecodes.kern
-local glue_code = nodecodes.glue
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local unset_code = nodecodes.unset
-local marginkern_code = nodecodes.marginkern
-
-local leaders_code = gluecodes.leaders
-
-local localpar_code = whatcodes.localpar
-local dir_code = whatcodes.dir
-local pdfrefximage_code = whatcodes.pdfrefximage
-local pdfrefxform_code = whatcodes.pdfrefxform
-
-local kerning_code = kerncodes.kerning -- font kern
-local userkern_code = kerncodes.userkern
-
-local ligature_code = glyphcodes.ligature
-
-local stretch_orders = nodes.fillcodes
-
-local leftmargin_code = margincodes.left
-local rightmargin_code = margincodes.right
-
-local automatic_disc_code = disccodes.automatic
-local regular_disc_code = disccodes.regular
-local first_disc_code = disccodes.first
-local second_disc_code = disccodes.second
-
-local endmath_code = mathcodes.endmath
-
-local nosubtype_code = 0
-
-local unhyphenated_code = nodecodes.unhyphenated or 1
-local hyphenated_code = nodecodes.hyphenated or 2
-local delta_code = nodecodes.delta or 3
-local passive_code = nodecodes.passive or 4
-
-local maxdimen = number.maxdimen
-
-local max_halfword = 0x7FFFFFFF
-local infinite_penalty = 10000
-local eject_penalty = -10000
-local infinite_badness = 10000
-local awful_badness = 0x3FFFFFFF
-
-local fit_very_loose_class = 0 -- fitness for lines stretching more than their stretchability
-local fit_loose_class = 1 -- fitness for lines stretching 0.5 to 1.0 of their stretchability
-local fit_decent_class = 2 -- fitness for all other lines
-local fit_tight_class = 3 -- fitness for lines shrinking 0.5 to 1.0 of their shrinkability
-
-local new_penalty = nodepool.penalty
-local new_dir = nodepool.textdir
-local new_leftmarginkern = nodepool.leftmarginkern
-local new_rightmarginkern = nodepool.rightmarginkern
-local new_leftskip = nodepool.leftskip
-local new_rightskip = nodepool.rightskip
-local new_lineskip = nodepool.lineskip
-local new_baselineskip = nodepool.baselineskip
-local new_temp = nodepool.temp
-local new_rule = nodepool.rule
-
-local is_rotated = nodes.is_rotated
-local is_parallel = nodes.textdir_is_parallel
-local is_opposite = nodes.textdir_is_opposite
-local textdir_is_equal = nodes.textdir_is_equal
-local pardir_is_equal = nodes.pardir_is_equal
-local glyphdir_is_equal = nodes.glyphdir_is_equal
-
-local dir_pops = nodes.dir_is_pop
-local dir_negations = nodes.dir_negation
-local is_skipable = node.protrusion_skippable
-local a_fontkern = attributes.private('fontkern')
-
--- helpers --
-
--- It makes more sense to move the somewhat messy dir state tracking
--- out of the main functions. First we create a stack allocator.
-
-local function new_dir_stack(dir) -- also use elsewhere
- return { n = 0, dir }
-end
-
--- The next function checks a dir node and returns the new dir state. By
--- using s static table we are quite efficient. This function is used
--- in the parbuilder.
-
-local function checked_line_dir(stack,current)
- if not dir_pops[current] then
- local n = stack.n + 1
- stack.n = n
- stack[n] = current
- return current.dir
- elseif n > 0 then
- local n = stack.n
- local dirnode = stack[n]
- dirstack.n = n - 1
- return dirnode.dir
- else
- report_parbuilders("warning: missing pop node (%a)",1) -- in line ...
- end
-end
-
--- The next function checks a dir nodes in a list and appends the negations
--- that are currently needed (some day LuaTeX will be more tolerant). We use
--- the negations for the next line.
-
-local function inject_dirs_at_end_of_line(stack,current,start,stop)
- local e = start
- local n = stack.n
- local h = nil
- while start and start ~= stop do
- if start.id == whatsit_code and start.subtype == dir_code then
- if not dir_pops[start.dir] then
- n = n + 1
- stack[n] = start
- elseif n > 0 then
- n = n - 1
- else
- report_parbuilders("warning: missing pop node (%a)",2) -- in line ...
- end
- end
- start = start.next
- end
- for i=n,1,-1 do
- h, current = insert_node_after(current,current,new_dir(dir_negations[stack[i].dir]))
- end
- stack.n = n
- return current
-end
-
-local function inject_dirs_at_begin_of_line(stack,current)
- local h = nil
- for i=stack.n,1,-1 do
- h, current = insert_node_after(current,current,new_dir(stack[i]))
- end
- stack.n = 0
- return current
-end
-
--- diagnostics --
-
-local dummy = function() end
-
-local diagnostics = {
- start = dummy,
- stop = dummy,
- current_pass = dummy,
- break_node = dummy,
- feasible_break = dummy,
-}
-
--- statistics --
-
-local nofpars, noflines, nofprotrudedlines, nofadjustedlines = 0, 0, 0, 0
-
-local function register_statistics(par)
- local statistics = par.statistics
- nofpars = nofpars + 1
- noflines = noflines + statistics.noflines
- nofprotrudedlines = nofprotrudedlines + statistics.nofprotrudedlines
- nofadjustedlines = nofadjustedlines + statistics.nofadjustedlines
-end
-
--- resolvers --
-
-local whatsiters = {
- get_width = { },
- get_dimensions = { },
-}
-
-local get_whatsit_width = whatsiters.get_width
-local get_whatsit_dimensions = whatsiters.get_dimensions
-
-local function get_width (n) return n.width end
-local function get_dimensions(n) return n.width, n.height, n.depth end
-
-get_whatsit_width[pdfrefximage_code] = get_width
-get_whatsit_width[pdfrefxform_code ] = get_width
-
-get_whatsit_dimensions[pdfrefximage_code] = get_dimensions
-get_whatsit_dimensions[pdfrefxform_code ] = get_dimensions
-
--- expansion etc --
-
-local function calculate_fraction(x,n,d,max_answer)
- local the_answer = x * n/d + 1/2 -- round ?
- if the_answer > max_answer then
- return max_answer
- elseif the_answer < -max_answer then
- return -max_answer
- else
- return the_answer
- end
-end
-
-local function check_shrinkage(par,n)
- -- called often, so maybe move inline -- use NORMAL
- if n.shrink_order ~= 0 and n.shrink ~= 0 then
- if par.no_shrink_error_yet then
- par.no_shrink_error_yet = false
- report_parbuilders("infinite glue shrinkage found in a paragraph and removed")
- end
- n = copy_node(n)
- n.shrink_order = 0
- end
- return n
-end
-
--- It doesn't really speed up much but the additional memory usage is
--- rather small so it doesn't hurt too much.
-
-local expansions = { }
-local nothing = { stretch = 0, shrink = 0 }
-
-setmetatableindex(expansions,function(t,font) -- we can store this in tfmdata if needed
- local expansion = parameters[font].expansion -- can be an extra hash
- if expansion and expansion.auto then
- local factors = { }
- local c = chardata[font]
- setmetatableindex(factors,function(t,char)
- local fc = c[char]
- local ef = fc.expansion_factor
- if ef and ef > 0 then
- local stretch = expansion.stretch
- local shrink = expansion.shrink
- if stretch ~= 0 or shrink ~= 0 then
- local factor = ef / 1000
- local ef_quad = factor * quaddata[font] / 1000
- local v = {
- glyphstretch = stretch * ef_quad,
- glyphshrink = shrink * ef_quad,
- factor = factor,
- stretch = stretch,
- shrink = shrink,
- }
- t[char] = v
- return v
- end
- end
- t[char] = nothing
- return nothing
- end)
- t[font] = factors
- return factors
- else
- t[font] = false
- return false
- end
-end)
-
--- local function char_stretch_shrink(p)
--- local data = expansions[p.font][p.char]
--- if data then
--- return data.glyphstretch, data.glyphshrink
--- else
--- return 0, 0
--- end
--- end
---
--- local cal_margin_kern_var = char_stretch_shrink
-
--- local function kern_stretch_shrink(p,d)
--- local l = p.prev
--- if l and l.id == glyph_code then -- how about disc nodes?
--- local r = p.next
--- if r and r.id == glyph_code then
--- local lf, rf = l.font, r.font
--- if lf == rf then
--- local data = expansions[lf][l.char]
--- if data then
--- local stretch = data.stretch
--- local shrink = data.shrink
--- if stretch ~= 0 then
--- -- stretch = data.factor * (d * stretch - d)
--- stretch = data.factor * d * (stretch - 1)
--- end
--- if shrink ~= 0 then
--- -- shrink = data.factor * (d * shrink - d)
--- shrink = data.factor * d * (shrink - 1)
--- end
--- return stretch, shrink
--- end
--- end
--- end
--- end
--- return 0, 0
--- end
-
-local function kern_stretch_shrink(p,d)
- local left = p.prev
- if left and left.id == glyph_code then -- how about disc nodes?
- local data = expansions[left.font][left.char]
- if data then
- local stretch = data.stretch
- local shrink = data.shrink
- if stretch ~= 0 then
- -- stretch = data.factor * (d * stretch - d)
- stretch = data.factor * d * (stretch - 1)
- end
- if shrink ~= 0 then
- -- shrink = data.factor * (d * shrink - d)
- shrink = data.factor * d * (shrink - 1)
- end
- return stretch, shrink
- end
- end
- return 0, 0
-end
-
--- local function kern_stretch_shrink(p,d)
--- -- maybe make it an option in luatex where we also need to check for attribute fontkern but in general
--- -- it makes no sense to scale kerns
--- return 0, 0
--- end
-
-local expand_kerns = false
--- local expand_kerns = "both"
-
-directives.register("builders.paragraphs.adjusting.kerns",function(v)
- if not v then
- expand_kerns = false
- elseif v == "stretch" or v == "shrink" then
- expand_kerns = v
- elseif v == "both" then
- expand_kerns = true
- else
- expand_kerns = toboolean(v,true) or false
- end
-end)
-
--- state:
-
-local function check_expand_pars(checked_expansion,f)
- local expansion = parameters[f].expansion
- if not expansion then
- checked_expansion[f] = false
- return false
- end
--- expansion.step = 1
- local step = expansion.step or 0
- local stretch = expansion.stretch or 0
- local shrink = expansion.shrink or 0
- if step == 0 or (stretch == 0 and schrink == 0) then
- checked_expansion[f] = false
- return false
- end
- local par = checked_expansion.par
- if par.cur_font_step < 0 then
- par.cur_font_step = step
- elseif par.cur_font_step ~= step then
- report_parbuilders("using fonts with different step of expansion in one paragraph is not allowed")
- checked_expansion[f] = false
- return false
- end
- if stretch == 0 then
- -- okay
- elseif par.max_stretch_ratio < 0 then
- par.max_stretch_ratio = stretch -- expansion_factor
- elseif par.max_stretch_ratio ~= stretch then
- report_parbuilders("using fonts with different stretch limit of expansion in one paragraph is not allowed")
- checked_expansion[f] = false
- return false
- end
- if shrink == 0 then
- -- okay
- elseif par.max_shrink_ratio < 0 then
- par.max_shrink_ratio = shrink -- - expansion_factor
- elseif par.max_shrink_ratio ~= shrink then
- report_parbuilders("using fonts with different shrink limit of expansion in one paragraph is not allowed")
- checked_expansion[f] = false
- return false
- end
- if trace_adjusting then
- report_parbuilders("expanding font %a using step %a, shrink %a and stretch %a",f,step,stretch,shrink)
- end
- local e = expansions[f]
- checked_expansion[f] = e
- return e
-end
-
-local function check_expand_lines(checked_expansion,f)
- local expansion = parameters[f].expansion
- if not expansion then
- checked_expansion[f] = false
- return false
- end
--- expansion.step = 1
- local step = expansion.step or 0
- local stretch = expansion.stretch or 0
- local shrink = expansion.shrink or 0
- if step == 0 or (stretch == 0 and schrink == 0) then
- checked_expansion[f] = false
- return false
- end
- if trace_adjusting then
- report_parbuilders("expanding font %a using step %a, shrink %a and stretch %a",f,step,stretch,shrink)
- end
- local e = expansions[f]
- checked_expansion[f] = e
- return e
-end
-
--- protrusion
-
-local function find(head) -- do we really want to recurse into an hlist?
- while head do
- local id = head.id
- if id == glyph_code then
- return head
- elseif id == hlist_code then
- local found = find(head.list)
- if found then
- return found
- else
- head = head.next
- end
- elseif is_skipable(head) then
- head = head.next
- else
- return head
- end
- end
- return nil
-end
-
-local function find_protchar_left(l) -- weird function
- local ln = l.next
- if ln and ln.id == hlist_code and not ln.list and ln.width == 0 and ln.height == 0 and ln.depth == 0 then
- l = l.next
- else -- if d then -- was always true
- local id = l.id
- while ln and not (id == glyph_code or id < math_code) do -- is there always a glyph?
- l = ln
- ln = l.next
- id = ln.id
- end
- end
- -- if l.id == glyph_code then
- -- return l
- -- end
- return find(l) or l
-end
-
-local function find(head,tail)
- local tail = tail or slide_nodes(head)
- while tail do
- local id = tail.id
- if id == glyph_code then
- return tail
- elseif id == hlist_code then
- local found = find(tail.list)
- if found then
- return found
- else
- tail = tail.prev
- end
- elseif is_skipable(tail) then
- tail = tail.prev
- else
- return tail
- end
- end
- return nil
-end
-
-local function find_protchar_right(l,r)
- return r and find(l,r) or r
-end
-
-local function left_pw(p)
- local font = p.font
- local prot = chardata[font][p.char].left_protruding
- if not prot or prot == 0 then
- return 0
- end
- return prot * quaddata[font] / 1000, p
-end
-
-local function right_pw(p)
- local font = p.font
- local prot = chardata[font][p.char].right_protruding
- if not prot or prot == 0 then
- return 0
- end
- return prot * quaddata[font] / 1000, p
-end
-
--- par parameters
-
-local function reset_meta(par)
- local active = {
- id = hyphenated_code,
- line_number = max_halfword,
- }
- active.next = par.active -- head of metalist
- par.active = active
- par.passive = nil
-end
-
-local function add_to_width(line_break_dir,checked_expansion,s) -- split into two loops (normal and expansion)
- local size = 0
- local adjust_stretch = 0
- local adjust_shrink = 0
- while s do
- local id = s.id
- if id == glyph_code then
- if is_rotated[line_break_dir] then -- can be shared
- size = size + s.height + s.depth
- else
- size = size + s.width
- end
- if checked_expansion then
- local data = checked_expansion[s.font]
- if data then
- data = data[s.char]
- if data then
- adjust_stretch = adjust_stretch + data.glyphstretch
- adjust_shrink = adjust_shrink + data.glyphshrink
- end
- end
- end
- elseif id == hlist_code or id == vlist_code then
- if is_parallel[s.dir][line_break_dir] then
- size = size + s.width
- else
- size = size + s.depth + s.height
- end
- elseif id == kern_code then
- local d = s.kern
- if d ~= 0 then
- if checked_expansion and expand_kerns and (s.subtype == kerning_code or s[a_fontkern]) then
- local stretch, shrink = kern_stretch_shrink(s,d)
- if expand_kerns == "stretch" then
- adjust_stretch = adjust_stretch + stretch
- elseif expand_kerns == "shrink" then
- adjust_shrink = adjust_shrink + shrink
- else
- adjust_stretch = adjust_stretch + stretch
- adjust_shrink = adjust_shrink + shrink
- end
- end
- size = size + d
- end
- elseif id == rule_code then
- size = size + s.width
- else
- report_parbuilders("unsupported node at location %a",6)
- end
- s = s.next
- end
- return size, adjust_stretch, adjust_shrink
-end
-
-local function compute_break_width(par,break_type,p) -- split in two
- local break_width = par.break_width
- if break_type > unhyphenated_code then
- local disc_width = par.disc_width
- local checked_expansion = par.checked_expansion
- local line_break_dir = par.line_break_dir
- local break_size = break_width.size + disc_width.size
- local break_adjust_stretch = break_width.adjust_stretch + disc_width.adjust_stretch
- local break_adjust_shrink = break_width.adjust_shrink + disc_width.adjust_shrink
- local replace = p.replace
- if replace then
- local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,replace)
- break_size = break_size - size
- break_adjust_stretch = break_adjust_stretch - adjust_stretch
- break_adjust_shrink = break_adjust_shrink - adjust_shrink
- end
- local post = p.post
- if post then
- local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,post)
- break_size = break_size + size
- break_adjust_stretch = break_adjust_stretch + adjust_stretch
- break_adjust_shrink = break_adjust_shrink + adjust_shrink
- end
- break_width.size = break_size
- break_width.adjust_stretch = break_adjust_stretch
- break_width.adjust_shrink = break_adjust_shrink
- if not post then
- p = p.next
- else
- return
- end
- end
- while p do -- skip spacing etc
- local id = p.id
- if id == glyph_code then
- return -- happens often
- elseif id == glue_code then
- local spec = p.spec
- local order = stretch_orders[spec.stretch_order]
- break_width.size = break_width.size - spec.width
- break_width[order] = break_width[order] - spec.stretch
- break_width.shrink = break_width.shrink - spec.shrink
- elseif id == penalty_code then
- -- do nothing
- elseif id == kern_code then
- if p.subtype == userkern_code then
- break_width.size = break_width.size - p.kern
- else
- return
- end
- elseif id == math_code then
- break_width.size = break_width.size - p.surround
- else
- return
- end
- p = p.next
- end
-end
-
-local function append_to_vlist(par, b)
- local prev_depth = par.prev_depth
- if prev_depth > par.ignored_dimen then
- if b.id == hlist_code then
- local d = par.baseline_skip.width - prev_depth - b.height -- deficiency of space between baselines
- local s = d < par.line_skip_limit and new_lineskip(tex.lineskip) or new_baselineskip(d)
- -- local s = d < par.line_skip_limit
- -- if s then
- -- s = new_lineskip()
- -- s.spec = tex.lineskip
- -- else
- -- s = new_baselineskip(d)
- -- end
- local head_field = par.head_field
- if head_field then
- local n = slide_nodes(head_field)
- n.next = s
- s.prev = n
- else
- par.head_field = s
- end
- end
- end
- local head_field = par.head_field
- if head_field then
- local n = slide_nodes(head_field)
- n.next = b
- b.prev = n
- else
- par.head_field = b
- end
- if b.id == hlist_code then
- local pd = b.depth
- par.prev_depth = pd
- texnest[texnest.ptr].prevdepth = pd
- end
-end
-
-local function append_list(par, b)
- local head_field = par.head_field
- if head_field then
- local n = slide_nodes(head_field)
- n.next = b
- b.prev = n
- else
- par.head_field = b
- end
-end
-
--- We can actually make par local to this module as we never break inside a break call and that way the
--- array is reused. At some point the information will be part of the paragraph spec as passed.
-
-local hztolerance = 2500
-local hzwarned = false
-
-local function initialize_line_break(head,display)
-
- local hang_indent = tex.hangindent or 0
- local hsize = tex.hsize or 0
- local hang_after = tex.hangafter or 0
- local par_shape_ptr = tex.parshape
- local left_skip = tex.leftskip -- nodes
- local right_skip = tex.rightskip -- nodes
- local pretolerance = tex.pretolerance
- local tolerance = tex.tolerance
- local adjust_spacing = tex.pdfadjustspacing
- local protrude_chars = tex.pdfprotrudechars
- local last_line_fit = tex.lastlinefit
-
- local newhead = new_temp()
- newhead.next = head
-
- local adjust_spacing_status = adjust_spacing > 1 and -1 or 0
-
- -- metatables
-
- local par = {
- head = newhead,
- head_field = nil,
- display = display,
- font_in_short_display = 0,
- no_shrink_error_yet = true, -- have we complained about infinite shrinkage?
- second_pass = false, -- is this our second attempt to break this paragraph?
- final_pass = false, -- is this our final attempt to break this paragraph?
- threshold = 0, -- maximum badness on feasible lines
-
- passive = nil, -- most recent node on passive list
- printed_node = head, -- most recent node that has been printed
- pass_number = 0, -- the number of passive nodes allocated on this pass
- auto_breaking = 0, -- make auto_breaking accessible out of line_break
-
- active_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
- break_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
- disc_width = { size = 0, adjust_stretch = 0, adjust_shrink = 0 },
- fill_width = { stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
- background = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
-
- hang_indent = hang_indent,
- hsize = hsize,
- hang_after = hang_after,
- par_shape_ptr = par_shape_ptr,
- left_skip = left_skip,
- right_skip = right_skip,
- pretolerance = pretolerance,
- tolerance = tolerance,
-
- protrude_chars = protrude_chars,
- adjust_spacing = adjust_spacing,
- max_stretch_ratio = adjust_spacing_status,
- max_shrink_ratio = adjust_spacing_status,
- cur_font_step = adjust_spacing_status,
- checked_expansion = false,
- tracing_paragraphs = tex.tracingparagraphs > 0,
-
- emergency_stretch = tex.emergencystretch or 0,
- looseness = tex.looseness or 0,
- line_penalty = tex.linepenalty or 0,
- hyphen_penalty = tex.hyphenpenalty or 0,
- broken_penalty = tex.brokenpenalty or 0,
- inter_line_penalty = tex.interlinepenalty or 0,
- club_penalty = tex.clubpenalty or 0,
- widow_penalty = tex.widowpenalty or 0,
- display_widow_penalty = tex.displaywidowpenalty or 0,
- ex_hyphen_penalty = tex.exhyphenpenalty or 0,
-
- adj_demerits = tex.adjdemerits or 0,
- double_hyphen_demerits = tex.doublehyphendemerits or 0,
- final_hyphen_demerits = tex.finalhyphendemerits or 0,
-
- first_line = 0, -- tex.nest[tex.nest.ptr].modeline, -- 0, -- cur_list.pg_field
-
- each_line_height = tex.pdfeachlineheight or 0, -- this will go away
- each_line_depth = tex.pdfeachlinedepth or 0, -- this will go away
- first_line_height = tex.pdffirstlineheight or 0, -- this will go away
- last_line_depth = tex.pdflastlinedepth or 0, -- this will go away
- ignored_dimen = tex.pdfignoreddimen or 0, -- this will go away
-
- baseline_skip = tex.baselineskip or 0,
- lineskip = tex.lineskip or 0,
- line_skip_limit = tex.lineskiplimit or 0,
-
- prev_depth = texnest[texnest.ptr].prevdepth,
-
- final_par_glue = slide_nodes(head), -- todo: we know tail already, slow
-
- par_break_dir = tex.pardir,
- line_break_dir = tex.pardir,
-
- internal_pen_inter = 0, -- running localinterlinepenalty
- internal_pen_broken = 0, -- running localbrokenpenalty
- internal_left_box = nil, -- running localleftbox
- internal_left_box_width = 0, -- running localleftbox width
- init_internal_left_box = nil, -- running localleftbox
- init_internal_left_box_width = 0, -- running localleftbox width
- internal_right_box = nil, -- running localrightbox
- internal_right_box_width = 0, -- running localrightbox width
-
- best_place = { }, -- how to achieve minimal_demerits
- best_pl_line = { }, -- corresponding line number
- easy_line = 0, -- line numbers easy_line are equivalent in break nodes
- last_special_line = 0, -- line numbers last_special_line all have the same width
- first_width = 0, -- the width of all lines last_special_line, if no parshape has been specified
- second_width = 0, -- the width of all lines last_special_line
- first_indent = 0, -- left margin to go with first_width
- second_indent = 0, -- left margin to go with second_width
-
- best_bet = nil, -- use this passive node and its predecessors
- fewest_demerits = 0, -- the demerits associated with best_bet
- best_line = 0, -- line number following the last line of the new paragraph
- line_diff = 0, -- the difference between the current line number and the optimum best_line
-
- -- not yet used
-
- best_pl_short = { }, -- shortfall corresponding to minimal_demerits
- best_pl_glue = { }, -- corresponding glue stretch or shrink
- do_last_line_fit = false,
- last_line_fit = last_line_fit,
-
- minimum_demerits = awful_badness,
-
- minimal_demerits = {
-
- [fit_very_loose_class] = awful_badness,
- [fit_loose_class] = awful_badness,
- [fit_decent_class] = awful_badness,
- [fit_tight_class] = awful_badness,
-
- },
-
- prev_char_p = nil,
-
- statistics = {
-
- noflines = 0,
- nofprotrudedlines = 0,
- nofadjustedlines = 0,
-
- },
-
- -- -- just a thought ... parshape functions ... it would be nice to
- -- -- also store the height so far (probably not too hard) although
- -- -- in most cases we work on grids in such cases
- --
- -- adapt_width = function(par,line)
- -- -- carry attribute, so that we can accumulate
- -- local left = 655360 * (line - 1)
- -- local right = 655360 * (line - 1)
- -- return left, right
- -- end
-
- }
-
- if adjust_spacing > 1 then
- local checked_expansion = { par = par }
- setmetatableindex(checked_expansion,check_expand_pars)
- par.checked_expansion = checked_expansion
-
- if par.tolerance < hztolerance then
- if not hzwarned then
- report_parbuilders("setting tolerance to %a for hz",hztolerance)
- hzwarned = true
- end
- par.tolerance = hztolerance
- end
-
- end
-
- -- we need par for the error message
-
- local background = par.background
-
- local l = check_shrinkage(par,left_skip)
- local r = check_shrinkage(par,right_skip)
- local l_order = stretch_orders[l.stretch_order]
- local r_order = stretch_orders[r.stretch_order]
-
- background.size = l.width + r.width
- background.shrink = l.shrink + r.shrink
- background[l_order] = l.stretch
- background[r_order] = r.stretch + background[r_order]
-
- -- this will move up so that we can assign the whole par table
-
- if not par_shape_ptr then
- if hang_indent == 0 then
- par.second_width = hsize
- par.second_indent = 0
- else
- local abs_hang_after = hang_after >0 and hang_after or -hang_after
- local abs_hang_indent = hang_indent>0 and hang_indent or -hang_indent
- par.last_special_line = abs_hang_after
- if hang_after < 0 then
- par.first_width = hsize - abs_hang_indent
- if hang_indent >= 0 then
- par.first_indent = hang_indent
- else
- par.first_indent = 0
- end
- par.second_width = hsize
- par.second_indent = 0
- else
- par.first_width = hsize
- par.first_indent = 0
- par.second_width = hsize - abs_hang_indent
- if hang_indent >= 0 then
- par.second_indent = hang_indent
- else
- par.second_indent = 0
- end
- end
- end
- else
- local last_special_line = #par_shape_ptr
- par.last_special_line = last_special_line
- local parshape = par_shape_ptr[last_special_line]
- par.second_width = parshape[2]
- par.second_indent = parshape[1]
- end
-
- if par.looseness == 0 then
- par.easy_line = par.last_special_line
- else
- par.easy_line = max_halfword
- end
-
- if pretolerance >= 0 then
- par.threshold = pretolerance
- par.second_pass = false
- par.final_pass = false
- else
- par.threshold = tolerance
- par.second_pass = true
- par.final_pass = par.emergency_stretch <= 0
- if trace_basic then
- if par.final_pass then
- report_parbuilders("enabling second and final pass")
- else
- report_parbuilders("enabling second pass")
- end
- end
- end
-
- if last_line_fit > 0 then
- local spec = par.final_par_glue.spec
- local stretch = spec.stretch
- local stretch_order = spec.stretch_order
- if stretch > 0 and stretch_order > 0 and background.fi == 0 and background.fil == 0 and background.fill == 0 and background.filll == 0 then
- par.do_last_line_fit = true
- local si = stretch_orders[stretch_order]
- if trace_lastlinefit or trace_basic then
- report_parbuilders("enabling last line fit, stretch order %a set to %a, linefit is %a",si,stretch,last_line_fit)
- end
- par.fill_width[si] = stretch
- end
- end
-
- return par
-end
-
-local function post_line_break(par)
-
- local prevgraf = texnest[texnest.ptr].prevgraf
- local cur_line = prevgraf + 1 -- the current line number being justified
- local cur_p = nil
-
- local adjust_spacing = par.adjust_spacing
- local protrude_chars = par.protrude_chars
- local statistics = par.statistics
-
- local p, s, k, w -- check when local
-
- local q = par.best_bet.break_node
- repeat -- goto first breakpoint
- local r = q
- q = q.prev_break
- r.prev_break = cur_p
- cur_p = r
- until not q
-
- local stack = new_dir_stack()
-
- repeat
-
- inject_dirs_at_begin_of_line(stack,par.head)
-
- local q = nil
- local r = cur_p.cur_break
-
- local disc_break = false
- local post_disc_break = false
- local glue_break = false
-
- if not r then
- r = slide_nodes(par.head)
- if r == par.final_par_glue then
- q = r -- q refers to the last node of the line (and paragraph)
- r = r.prev -- r refers to the node after which the dir nodes should be closed
- end
- else
- local id = r.id
- if id == glue_code then
- -- r is normal skip
- r = replace_node(r,new_rightskip(par.right_skip))
- glue_break = true
- q = r -- q refers to the last node of the line
- r = r.prev -- r refers to the node after which the dir nodes should be closed
- elseif id == disc_code then
- -- todo: use insert_before/after
- local prev_r = r.prev
- local next_r = r.next
- local subtype = r.subtype
- local pre = r.pre
- local post = r.post
- local replace = r.replace
- if subtype == second_disc_code then
- if not (prev_r.id == disc_code and prev_r.subtype == first_disc_code) then
- report_parbuilders('unsupported disc at location %a',3)
- end
- if pre then
- flush_node_list(pre)
- r.pre = nil
- pre = nil -- signal
- end
- if replace then
- local n = slide_nodes(replace)
- prev_r.next = replace
- replace.prev = prev_r
- n.next = r
- r.prev = n
- r.replace = nil
- replace = nil -- signal
- end
- local pre = prev_r.pre
- local post = prev_r.post
- local replace = prev_r.replace
- if pre then
- flush_node_list(pre)
- prev_r.pre = nil
- end
- if replace then
- flush_node_list(replace)
- prev_r.replace = nil
- end
- if post then
- flush_node_list(post)
- prev_r.post = nil
- end
- elseif subtype == first_disc_code then
- if not (v.id == disc_code and v.subtype == second_disc_code) then
- report_parbuilders('unsupported disc at location %a',4)
- end
- next_r.subtype = regular_disc_code
- next_r.replace = post
- r.post = nil
- end
- if replace then
- r.replace = nil -- free
- flush_node_list(replace)
- end
- if pre then
- local n = slide_nodes(pre)
- prev_r.next = pre
- pre.prev = prev_r
- n.next = r
- r.prev = n
- r.pre = nil
- end
- if post then
- local n = slide_nodes(post)
- r.next = post
- post.prev = r
- n.next = next_r
- next_r.prev = n
- r.post = nil
- post_disc_break = true
- end
- disc_break = true
- elseif id == kern_code then
- r.kern = 0
- elseif r.id == math_code then
- r.surround = 0
- end
- end
- r = inject_dirs_at_end_of_line(stack,r,par.head.next,cur_p.cur_break)
- local crb = cur_p.passive_right_box
- if crb then
- local s = copy_node(crb)
- local e = r.next
- r.next = s
- s.prev = r
- s.next = e
- if e then
- e.prev = s
- end
- r = s
- end
- if not q then
- q = r
- end
- if q and q ~= par.head and protrude_chars > 0 then
- local id = q.id
- local c = (disc_break and (id == glyph_code or id ~= disc_code) and q) or q.prev
- local p = find_protchar_right(par.head.next,c)
- if p and p.id == glyph_code then
- local w, last_rightmost_char = right_pw(p)
- if last_rightmost_char and w ~= 0 then
- -- so we inherit attributes, q is new pseudo head
- q, c = insert_node_after(q,c,new_rightmarginkern(copy_node(last_rightmost_char),-w))
- end
- end
- end
- if not glue_break then
- local h
- h, q = insert_node_after(q,q,new_rightskip(par.right_skip)) -- q moves on as pseudo head
- end
- r = q.next
- q.next = nil
- local phead = par.head
- q = phead.next
- phead.next = r
- if r then
- r.prev = phead
- end
- local clb = cur_p.passive_left_box
- if clb then -- here we miss some prev links
- local s = copy_node(cb)
- s = q.next
- r.next = q
- q = r
- if s and cur_line == (par.first_line + 1) and s.id == hlist_code and not s.list then
- q = q.next
- r.next = s.next
- s.next = r
- end
- end
- if protrude_chars > 0 then
- local p = find_protchar_left(q)
- if p and p.id == glyph_code then
- local w, last_leftmost_char = left_pw(p)
- if last_leftmost_char and w ~= 0 then
- -- so we inherit attributes, q is pseudo head and moves back
- q = insert_node_before(q,q,new_leftmarginkern(copy_node(last_leftmost_char),-w))
- end
- end
- end
- local ls = par.left_skip
- if ls and (ls.width ~= 0 or ls.stretch ~= 0 or ls.shrink ~= 0) then
- q = insert_node_before(q,q,new_leftskip(ls))
- end
- local curwidth, cur_indent
- if cur_line > par.last_special_line then
- cur_indent = par.second_indent
- cur_width = par.second_width
- else
- local psp = par.par_shape_ptr
- if psp then
- cur_indent = psp[cur_line][1]
- cur_width = psp[cur_line][2]
- else
- cur_indent = par.first_indent
- cur_width = par.first_width
- end
- end
- statistics.noflines = statistics.noflines + 1
- if adjust_spacing > 0 then
- statistics.nofadjustedlines = statistics.nofadjustedlines + 1
- -- in the built-in hpack cal_expand_ratio will later on call subst_ext_font
- -- in the alternative approach we can do both in one run
- just_box = xpack_nodes(q,cur_width,"cal_expand_ratio",par.par_break_dir) -- ,cur_p.analysis)
- else
- just_box = xpack_nodes(q,cur_width,"exactly",par.par_break_dir) -- ,cur_p.analysis)
- end
- if protrude_chars > 0 then
- statistics.nofprotrudedlines = statistics.nofprotrudedlines + 1
- end
- -- wrong:
- local adjust_head = texlists.adjust_head
- local pre_adjust_head = texlists.pre_adjust_head
- --
- just_box.shift = cur_indent
- if par.each_line_height ~= par.ignored_dimen then
- just_box.height = par.each_line_height
- end
- if par.each_line_depth ~= par.ignored_dimen then
- just_box.depth = par.each_line_depth
- end
- if par.first_line_height ~= par.ignored_dimen and (cur_line == par.first_line + 1) then
- just_box.height = par.first_line_height
- end
- if par.last_line_depth ~= par.ignored_dimen and cur_line + 1 == par.best_line then
- just_box.depth = par.last_line_depth
- end
- if texlists.pre_adjust_head ~= pre_adjust_head then
- append_list(par, texlists.pre_adjust_head)
- texlists.pre_adjust_head = pre_adjust_head
- end
- append_to_vlist(par, just_box)
- if texlists.adjust_head ~= adjust_head then
- append_list(par, texlists.adjust_head)
- texlists.adjust_head = adjust_head
- end
- local pen
- if cur_line + 1 ~= par.best_line then
- if cur_p.passive_pen_inter then
- pen = cur_p.passive_pen_inter
- else
- pen = par.inter_line_penalty
- end
- if cur_line == prevgraf + 1 then
- pen = pen + par.club_penalty
- end
- if cur_line + 2 == par.best_line then
- if par.display then
- pen = pen + par.display_widow_penalty
- else
- pen = pen + par.widow_penalty
- end
- end
- if disc_break then
- if cur_p.passive_pen_broken ~= 0 then
- pen = pen + cur_p.passive_pen_broken
- else
- pen = pen + par.broken_penalty
- end
- end
- if pen ~= 0 then
- append_to_vlist(par,new_penalty(pen))
- end
- end
- cur_line = cur_line + 1
- cur_p = cur_p.prev_break
- if cur_p and not post_disc_break then
- local phead = par.head
- local r = phead
- while true do
- q = r.next
- if q == cur_p.cur_break or q.id == glyph_code then
- break
- end
- local id = q.id
- if not (id == whatsit_code and q.subtype == localpar_code) then
- if id < math_code or (id == kern_code and q.subtype ~= userkern_code) then
- break
- end
- end
- r = q
- end
- if r ~= phead then
- r.next = nil
- flush_node_list(phead.next)
- phead.next = q
- if q then
- q.prev = phead
- end
- end
- end
- until not cur_p
- if cur_line ~= par.best_line then -- or not par.head.next then
- report_parbuilders("line breaking")
- end
- if par.head then -- added
--- flush_node(par.head) -- the localpar_code whatsit
- par.head = nil
- end
- cur_line = cur_line - 1
- if trace_basic then
- report_parbuilders("paragraph broken into %a lines",cur_line)
- end
- texnest[texnest.ptr].prevgraf = cur_line
-end
-
-local function wrap_up(par)
- if par.tracing_paragraphs then
- diagnostics.stop()
- end
- if par.do_last_line_fit then
- local best_bet = par.best_bet
- local active_short = best_bet.active_short
- local active_glue = best_bet.active_glue
- if active_short == 0 then
- if trace_lastlinefit then
- report_parbuilders("disabling last line fit, no active_short")
- end
- par.do_last_line_fit = false
- else
- local glue = par.final_par_glue
- local spec = copy_node(glue.spec)
- spec.width = spec.width + active_short - active_glue
- spec.stretch = 0
- -- flush_node(glue.spec) -- brrr, when we do this we can get an "invalid id stretch message", maybe dec refcount
- glue.spec = spec
- if trace_lastlinefit then
- report_parbuilders("applying last line fit, short %a, glue %p",active_short,active_glue)
- end
- end
- end
- -- we have a bunch of glue and and temp nodes not freed
- local head = par.head
- if head.id == temp_code then
- par.head = head.next
- flush_node(head)
- end
- post_line_break(par)
- reset_meta(par)
- register_statistics(par)
- return par.head_field
-end
-
--- we could do active nodes differently ... table instead of linked list or a list
--- with prev nodes
-
-local function deactivate_node(par,prev_prev_r,prev_r,r,cur_active_width,checked_expansion) -- no need for adjust if disabled
- local active = par.active
- local active_width = par.active_width
- prev_r.next = r.next
- -- removes r
- -- r = nil
- if prev_r == active then
- r = active.next
- if r.id == delta_code then
- local aw = active_width.size + r.size active_width.size = aw cur_active_width.size = aw
- local aw = active_width.stretch + r.stretch active_width.stretch = aw cur_active_width.stretch = aw
- local aw = active_width.fi + r.fi active_width.fi = aw cur_active_width.fi = aw
- local aw = active_width.fil + r.fil active_width.fil = aw cur_active_width.fil = aw
- local aw = active_width.fill + r.fill active_width.fill = aw cur_active_width.fill = aw
- local aw = active_width.filll + r.filll active_width.filll = aw cur_active_width.filll = aw
- local aw = active_width.shrink + r.shrink active_width.shrink = aw cur_active_width.shrink = aw
- if checked_expansion then
- local aw = active_width.adjust_stretch + r.adjust_stretch active_width.adjust_stretch = aw cur_active_width.adjust_stretch = aw
- local aw = active_width.adjust_shrink + r.adjust_shrink active_width.adjust_shrink = aw cur_active_width.adjust_shrink = aw
- end
- active.next = r.next
- -- removes r
- -- r = nil
- end
- elseif prev_r.id == delta_code then
- r = prev_r.next
- if r == active then
- cur_active_width.size = cur_active_width.size - prev_r.size
- cur_active_width.stretch = cur_active_width.stretch - prev_r.stretch
- cur_active_width.fi = cur_active_width.fi - prev_r.fi
- cur_active_width.fil = cur_active_width.fil - prev_r.fil
- cur_active_width.fill = cur_active_width.fill - prev_r.fill
- cur_active_width.filll = cur_active_width.filll - prev_r.filll
- cur_active_width.shrink = cur_active_width.shrink - prev_r.shrink
- if checked_expansion then
- cur_active_width.adjust_stretch = cur_active_width.adjust_stretch - prev_r.adjust_stretch
- cur_active_width.adjust_shrink = cur_active_width.adjust_shrink - prev_r.adjust_shrink
- end
- prev_prev_r.next = active
- -- removes prev_r
- -- prev_r = nil
- prev_r = prev_prev_r
- elseif r.id == delta_code then
- local rn = r.size cur_active_width.size = cur_active_width.size + rn prev_r.size = prev_r.size + rn
- local rn = r.stretch cur_active_width.stretch = cur_active_width.stretch + rn prev_r.stretch = prev_r.stretch + rn
- local rn = r.fi cur_active_width.fi = cur_active_width.fi + rn prev_r.fi = prev_r.fi + rn
- local rn = r.fil cur_active_width.fil = cur_active_width.fil + rn prev_r.fil = prev_r.fil + rn
- local rn = r.fill cur_active_width.fill = cur_active_width.fill + rn prev_r.fill = prev_r.fill + rn
- local rn = r.filll cur_active_width.filll = cur_active_width.filll + rn prev_r.filll = prev_r.fill + rn
- local rn = r.shrink cur_active_width.shrink = cur_active_width.shrink + rn prev_r.shrink = prev_r.shrink + rn
- if checked_expansion then
- local rn = r.adjust_stretch cur_active_width.adjust_stretch = cur_active_width.adjust_stretch + rn prev_r.adjust_stretch = prev_r.adjust_stretch + rn
- local rn = r.adjust_shrink cur_active_width.adjust_shrink = cur_active_width.adjust_shrink + rn prev_r.adjust_shrink = prev_r.adjust_shrink + rn
- end
- prev_r.next = r.next
- -- removes r
- -- r = nil
- end
- end
- return prev_r, r
-end
-
-local function lastlinecrap(shortfall,active_short,active_glue,cur_active_width,fill_width,last_line_fit)
- if active_short == 0 or active_glue <= 0 then
- return false, 0, fit_decent_class, 0, 0
- end
- if cur_active_width.fi ~= fill_width.fi or cur_active_width.fil ~= fill_width.fil or cur_active_width.fill ~= fill_width.fill or cur_active_width.filll ~= fill_width.filll then
- return false, 0, fit_decent_class, 0, 0
- end
- local adjustment = active_short > 0 and cur_active_width.stretch or cur_active_width.shrink
- if adjustment <= 0 then
- return false, 0, fit_decent_class, adjustment, 0
- end
- adjustment = calculate_fraction(adjustment,active_short,active_glue,maxdimen)
- if last_line_fit < 1000 then
- adjustment = calculate_fraction(adjustment,last_line_fit,1000,maxdimen) -- uses previous adjustment
- end
- local fit_class = fit_decent_class
- if adjustment > 0 then
- local stretch = cur_active_width.stretch
- if adjustment > shortfall then
- adjustment = shortfall
- end
- if adjustment > 7230584 and stretch < 1663497 then
- return true, fit_very_loose_class, shortfall, adjustment, infinite_badness
- end
- -- if adjustment == 0 then -- badness = 0
- -- return true, shortfall, fit_decent_class, 0, 0
- -- elseif stretch <= 0 then -- badness = 10000
- -- return true, shortfall, fit_very_loose_class, adjustment, 10000
- -- end
- -- local badness = (adjustment == 0 and 0) or (stretch <= 0 and 10000) or calculate_badness(adjustment,stretch)
- local badness = calculate_badness(adjustment,stretch)
- if badness > 99 then
- return true, shortfall, fit_very_loose_class, adjustment, badness
- elseif badness > 12 then
- return true, shortfall, fit_loose_class, adjustment, badness
- else
- return true, shortfall, fit_decent_class, adjustment, badness
- end
- elseif adjustment < 0 then
- local shrink = cur_active_width.shrink
- if -adjustment > shrink then
- adjustment = -shrink
- end
- local badness = calculate_badness(-adjustment,shrink)
- if badness > 12 then
- return true, shortfall, fit_tight_class, adjustment, badness
- else
- return true, shortfall, fit_decent_class, adjustment, badness
- end
- else
- return false, 0, fit_decent_class, 0, 0
- end
-end
-
-local function try_break(pi, break_type, par, first_p, cur_p, checked_expansion)
-
- if pi >= infinite_penalty then
- return -- this breakpoint is inhibited by infinite penalty
- elseif pi <= -infinite_penalty then
- pi = eject_penalty -- this breakpoint will be forced
- end
-
- local prev_prev_r = nil -- a step behind prev_r, if type(prev_r)=delta_code
- local prev_r = par.active -- stays a step behind r
- local r = nil -- runs through the active list
- local no_break_yet = true -- have we found a feasible break at cur_p?
- local node_r_stays_active = false -- should node r remain in the active list?
- local line_width = 0 -- the current line will be justified to this width
- local line_number = 0 -- line number of current active node
- local old_line_number = 0 -- maximum line number in current equivalence class of lines
-
- local protrude_chars = par.protrude_chars
- local checked_expansion = par.checked_expansion
- local break_width = par.break_width
- local active_width = par.active_width
- local background = par.background
- local minimal_demerits = par.minimal_demerits
- local best_place = par.best_place
- local best_pl_line = par.best_pl_line
- local best_pl_short = par.best_pl_short
- local best_pl_glue = par.best_pl_glue
- local do_last_line_fit = par.do_last_line_fit
- local final_pass = par.final_pass
- local tracing_paragraphs = par.tracing_paragraphs
- -- local par_active = par.active
-
- local cur_active_width = checked_expansion and { -- distance from current active node
- size = active_width.size,
- stretch = active_width.stretch,
- fi = active_width.fi,
- fil = active_width.fil,
- fill = active_width.fill,
- filll = active_width.filll,
- shrink = active_width.shrink,
- adjust_stretch = active_width.adjust_stretch,
- adjust_shrink = active_width.adjust_shrink,
- } or {
- size = active_width.size,
- stretch = active_width.stretch,
- fi = active_width.fi,
- fil = active_width.fil,
- fill = active_width.fill,
- filll = active_width.filll,
- shrink = active_width.shrink,
- }
-
- while true do
- r = prev_r.next
- if r.id == delta_code then
- cur_active_width.size = cur_active_width.size + r.size
- cur_active_width.stretch = cur_active_width.stretch + r.stretch
- cur_active_width.fi = cur_active_width.fi + r.fi
- cur_active_width.fil = cur_active_width.fil + r.fil
- cur_active_width.fill = cur_active_width.fill + r.fill
- cur_active_width.filll = cur_active_width.filll + r.filll
- cur_active_width.shrink = cur_active_width.shrink + r.shrink
- if checked_expansion then
- cur_active_width.adjust_stretch = cur_active_width.adjust_stretch + r.adjust_stretch
- cur_active_width.adjust_shrink = cur_active_width.adjust_shrink + r.adjust_shrink
- end
- prev_prev_r = prev_r
- prev_r = r
- else
- line_number = r.line_number
- if line_number > old_line_number then
- local minimum_demerits = par.minimum_demerits
- if minimum_demerits < awful_badness and (old_line_number ~= par.easy_line or r == par.active) then
- if no_break_yet then
- no_break_yet = false
- break_width.size = background.size
- break_width.stretch = background.stretch
- break_width.fi = background.fi
- break_width.fil = background.fil
- break_width.fill = background.fill
- break_width.filll = background.filll
- break_width.shrink = background.shrink
- if checked_expansion then
- break_width.adjust_stretch = 0
- break_width.adjust_shrink = 0
- end
- if cur_p then
- compute_break_width(par,break_type,cur_p)
- end
- end
- if prev_r.id == delta_code then
- prev_r.size = prev_r.size - cur_active_width.size + break_width.size
- prev_r.stretch = prev_r.stretch - cur_active_width.stretc + break_width.stretch
- prev_r.fi = prev_r.fi - cur_active_width.fi + break_width.fi
- prev_r.fil = prev_r.fil - cur_active_width.fil + break_width.fil
- prev_r.fill = prev_r.fill - cur_active_width.fill + break_width.fill
- prev_r.filll = prev_r.filll - cur_active_width.filll + break_width.filll
- prev_r.shrink = prev_r.shrink - cur_active_width.shrink + break_width.shrink
- if checked_expansion then
- prev_r.adjust_stretch = prev_r.adjust_stretch - cur_active_width.adjust_stretch + break_width.adjust_stretch
- prev_r.adjust_shrink = prev_r.adjust_shrink - cur_active_width.adjust_shrink + break_width.adjust_shrink
- end
- elseif prev_r == par.active then
- active_width.size = break_width.size
- active_width.stretch = break_width.stretch
- active_width.fi = break_width.fi
- active_width.fil = break_width.fil
- active_width.fill = break_width.fill
- active_width.filll = break_width.filll
- active_width.shrink = break_width.shrink
- if checked_expansion then
- active_width.adjust_stretch = break_width.adjust_stretch
- active_width.adjust_shrink = break_width.adjust_shrink
- end
- else
- local q = checked_expansion and {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = break_width.size - cur_active_width.size,
- stretch = break_width.stretch - cur_active_width.stretch,
- fi = break_width.fi - cur_active_width.fi,
- fil = break_width.fil - cur_active_width.fil,
- fill = break_width.fill - cur_active_width.fill,
- filll = break_width.filll - cur_active_width.filll,
- shrink = break_width.shrink - cur_active_width.shrink,
- adjust_stretch = break_width.adjust_stretch - cur_active_width.adjust_stretch,
- adjust_shrink = break_width.adjust_shrink - cur_active_width.adjust_shrink,
- } or {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = break_width.size - cur_active_width.size,
- stretch = break_width.stretch - cur_active_width.stretch,
- fi = break_width.fi - cur_active_width.fi,
- fil = break_width.fil - cur_active_width.fil,
- fill = break_width.fill - cur_active_width.fill,
- filll = break_width.filll - cur_active_width.filll,
- shrink = break_width.shrink - cur_active_width.shrink,
- }
- prev_r.next = q
- prev_prev_r = prev_r
- prev_r = q
- end
- local adj_demerits = par.adj_demerits
- local abs_adj_demerits = adj_demerits > 0 and adj_demerits or -adj_demerits
- if abs_adj_demerits >= awful_badness - minimum_demerits then
- minimum_demerits = awful_badness - 1
- else
- minimum_demerits = minimum_demerits + abs_adj_demerits
- end
- for fit_class = fit_very_loose_class, fit_tight_class do
- if minimal_demerits[fit_class] <= minimum_demerits then
- -- insert a new active node from best_place[fit_class] to cur_p
- par.pass_number = par.pass_number + 1
- local prev_break = best_place[fit_class]
- local passive = {
- id = passive_code,
- subtype = nosubtype_code,
- next = par.passive,
- cur_break = cur_p,
- serial = par.pass_number,
- prev_break = prev_break,
- passive_pen_inter = par.internal_pen_inter,
- passive_pen_broken = par.internal_pen_broken,
- passive_last_left_box = par.internal_left_box,
- passive_last_left_box_width = par.internal_left_box_width,
- passive_left_box = prev_break and prev_break.passive_last_left_box or par.init_internal_left_box,
- passive_left_box_width = prev_break and prev_break.passive_last_left_box_width or par.init_internal_left_box_width,
- passive_right_box = par.internal_right_box,
- passive_right_box_width = par.internal_right_box_width,
--- analysis = table.fastcopy(cur_active_width),
- }
- par.passive = passive
- local q = {
- id = break_type,
- subtype = fit_class,
- break_node = passive,
- line_number = best_pl_line[fit_class] + 1,
- total_demerits = minimal_demerits[fit_class], -- or 0,
- next = r,
- }
- if do_last_line_fit then
- local active_short = best_pl_short[fit_class]
- local active_glue = best_pl_glue[fit_class]
- q.active_short = active_short
- q.active_glue = active_glue
- if trace_lastlinefit then
- report_parbuilders("setting short to %i and glue to %p using class %a",active_short,active_glue,fit_class)
- end
- end
- -- q.next = r -- already done
- prev_r.next = q
- prev_r = q
- if tracing_paragraphs then
- diagnostics.break_node(par,q,fit_class,break_type,cur_p)
- end
- end
- minimal_demerits[fit_class] = awful_badness
- end
- par.minimum_demerits = awful_badness
- if r ~= par.active then
- local q = checked_expansion and {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = cur_active_width.size - break_width.size,
- stretch = cur_active_width.stretch - break_width.stretch,
- fi = cur_active_width.fi - break_width.fi,
- fil = cur_active_width.fil - break_width.fil,
- fill = cur_active_width.fill - break_width.fill,
- filll = cur_active_width.filll - break_width.filll,
- shrink = cur_active_width.shrink - break_width.shrink,
- adjust_stretch = cur_active_width.adjust_stretch - break_width.adjust_stretch,
- adjust_shrink = cur_active_width.adjust_shrink - break_width.adjust_shrink,
- } or {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = cur_active_width.size - break_width.size,
- stretch = cur_active_width.stretch - break_width.stretch,
- fi = cur_active_width.fi - break_width.fi,
- fil = cur_active_width.fil - break_width.fil,
- fill = cur_active_width.fill - break_width.fill,
- filll = cur_active_width.filll - break_width.filll,
- shrink = cur_active_width.shrink - break_width.shrink,
- }
- -- q.next = r -- already done
- prev_r.next = q
- prev_prev_r = prev_r
- prev_r = q
- end
- end
- if r == par.active then
- return
- end
- if line_number > par.easy_line then
- old_line_number = max_halfword - 1
- line_width = par.second_width
- else
- old_line_number = line_number
- if line_number > par.last_special_line then
- line_width = par.second_width
- elseif par.par_shape_ptr then
- line_width = par.par_shape_ptr[line_number][2]
- else
- line_width = par.first_width
- end
- end
- end
- local artificial_demerits = false -- has d been forced to zero
- local shortfall = line_width - cur_active_width.size - par.internal_right_box_width -- used in badness calculations
- if not r.break_node then
- shortfall = shortfall - par.init_internal_left_box_width
- else
- shortfall = shortfall - (r.break_node.passive_last_left_box_width or 0)
- end
- local pw, lp, rp -- used later on
- if protrude_chars > 1 then
- -- this is quite time consuming
- local b = r.break_node
- local l = b and b.cur_break or first_p
- local o = cur_p and cur_p.prev
- if cur_p and cur_p.id == disc_code and cur_p.pre then
- o = slide_nodes(cur_p.pre)
- else
- o = find_protchar_right(l,o)
- end
- if o and o.id == glyph_code then
- pw, rp = right_pw(o)
- shortfall = shortfall + pw
- end
- local id = l.id
- if id == glyph_code then
- -- ok ?
- elseif id == disc_code and l.post then
- l = l.post -- TODO: first char could be a disc
- else
- l = find_protchar_left(l)
- end
- if l and l.id == glyph_code then
- pw, lp = left_pw(l)
- shortfall = shortfall + pw
- end
- end
- if checked_expansion and shortfall ~= 0 then
- local margin_kern_stretch = 0
- local margin_kern_shrink = 0
- if protrude_chars > 1 then
- if lp then
--- margin_kern_stretch, margin_kern_shrink = cal_margin_kern_var(lp)
-local data = expansions[lp.font][lp.char]
-if data then
- margin_kern_stretch, margin_kern_shrink = data.glyphstretch, data.glyphshrink
-end
- end
- if rp then
--- local mka, mkb = cal_margin_kern_var(rp)
--- margin_kern_stretch = margin_kern_stretch + mka
--- margin_kern_shrink = margin_kern_shrink + mkb
-local data = expansions[lp.font][lp.char]
-if data then
- margin_kern_stretch = margin_kern_stretch + data.glyphstretch
- margin_kern_shrink = margin_kern_shrink + data.glyphshrink
-end
- end
- end
- local total = cur_active_width.adjust_stretch + margin_kern_stretch
- if shortfall > 0 and total > 0 then
- if total > shortfall then
- shortfall = total / (par.max_stretch_ratio / par.cur_font_step) / 2 -- to be adapted
- else
- shortfall = shortfall - total
- end
- else
- total = cur_active_width.adjust_shrink + margin_kern_shrink
- if shortfall < 0 and total > 0 then
- if total > - shortfall then
- shortfall = - total / (par.max_shrink_ratio / par.cur_font_step) / 2 -- to be adapted
- else
- shortfall = shortfall + total
- end
- end
- end
- end
- local b = 0
- local g = 0
- local fit_class = fit_decent_class
- local found = false
- if shortfall > 0 then
- if cur_active_width.fi ~= 0 or cur_active_width.fil ~= 0 or cur_active_width.fill ~= 0 or cur_active_width.filll ~= 0 then
- if not do_last_line_fit then
- -- okay
- elseif not cur_p then
- found, shortfall, fit_class, g, b = lastlinecrap(shortfall,r.active_short,r.active_glue,cur_active_width,par.fill_width,par.last_line_fit)
- else
- shortfall = 0
- end
- else
- local stretch = cur_active_width.stretch
- if shortfall > 7230584 and stretch < 1663497 then
- b = infinite_badness
- fit_class = fit_very_loose_class
- else
- b = calculate_badness(shortfall,stretch)
- if b > 99 then
- fit_class = fit_very_loose_class
- elseif b > 12 then
- fit_class = fit_loose_class
- else
- fit_class = fit_decent_class
- end
- end
- end
- else
- local shrink = cur_active_width.shrink
- if -shortfall > shrink then
- b = infinite_badness + 1
- else
- b = calculate_badness(-shortfall,shrink)
- end
- if b > 12 then
- fit_class = fit_tight_class
- else
- fit_class = fit_decent_class
- end
- end
- if do_last_line_fit and not found then
- if not cur_p then
- -- g = 0
- shortfall = 0
- elseif shortfall > 0 then
- g = cur_active_width.stretch
- elseif shortfall < 0 then
- g = cur_active_width.shrink
- else
- g = 0
- end
- end
- -- ::FOUND::
- local continue_only = false -- brrr
- if b > infinite_badness or pi == eject_penalty then
- if final_pass and par.minimum_demerits == awful_badness and r.next == par.active and prev_r == par.active then
- artificial_demerits = true -- set demerits zero, this break is forced
- node_r_stays_active = false
- elseif b > par.threshold then
- prev_r, r = deactivate_node(par,prev_prev_r,prev_r,r,cur_active_width,checked_expansion)
- continue_only = true
- else
- node_r_stays_active = false
- end
- else
- prev_r = r
- if b > par.threshold then
- continue_only = true
- else
- node_r_stays_active = true
- end
- end
- if not continue_only then
- local d = 0
- if not artificial_demerits then
- d = par.line_penalty + b
- if (d >= 0 and d or -d) >= 10000 then -- abs(d)
- d = 100000000
- else
- d = d * d
- end
- if pi == 0 then
- -- nothing
- elseif pi > 0 then
- d = d + pi * pi
- elseif pi > eject_penalty then
- d = d - pi * pi
- end
- if break_type == hyphenated_code and r.id == hyphenated_code then
- if cur_p then
- d = d + par.double_hyphen_demerits
- else
- d = d + par.final_hyphen_demerits
- end
- end
- local delta = fit_class - r.subtype
- if (delta >= 0 and delta or -delta) > 1 then -- abs(delta)
- d = d + par.adj_demerits
- end
- end
- if tracing_paragraphs then
- diagnostics.feasible_break(par,cur_p,r,b,pi,d,artificial_demerits)
- end
- d = d + r.total_demerits -- this is the minimum total demerits from the beginning to cur_p via r
- if d <= minimal_demerits[fit_class] then
- minimal_demerits[fit_class] = d
- best_place [fit_class] = r.break_node
- best_pl_line [fit_class] = line_number
- if do_last_line_fit then
- best_pl_short[fit_class] = shortfall
- best_pl_glue [fit_class] = g
- if trace_lastlinefit then
- report_parbuilders("storing last line fit short %a and glue %p in class %a",shortfall,g,fit_class)
- end
- end
- if d < par.minimum_demerits then
- par.minimum_demerits = d
- end
- end
- if not node_r_stays_active then
- prev_r, r = deactivate_node(par,prev_prev_r,prev_r,r,cur_active_width,checked_expansion)
- end
- end
- end
- end
-end
-
-local function kern_break(par, cur_p, first_p, checked_expansion) -- move inline if needed
- local v = cur_p.next
- if par.auto_breaking and v.id == glue_code then
- try_break(0, unhyphenated_code, par, first_p, cur_p, checked_expansion)
- end
- local active_width = par.active_width
- if cur_p.id ~= math_code then
- active_width.size = active_width.size + cur_p.kern
- else
- active_width.size = active_width.size + cur_p.surround
- end
-end
-
--- we can call the normal one for simple box building in the otr so we need
--- frequent enabling/disabling
-
-local temp_head = new_temp()
-
-function constructors.methods.basic(head,d)
- if trace_basic then
- report_parbuilders("starting at %a",head)
- end
-
- local par = initialize_line_break(head,d)
-
- local checked_expansion = par.checked_expansion
- local active_width = par.active_width
- local disc_width = par.disc_width
- local background = par.background
- local tracing_paragraphs = par.tracing_paragraphs
-
- local dirstack = new_dir_stack()
-
- if tracing_paragraphs then
- diagnostics.start()
- if par.pretolerance >= 0 then
- diagnostics.current_pass(par,"firstpass")
- end
- end
-
- while true do
- reset_meta(par)
- if par.threshold > infinite_badness then
- par.threshold = infinite_badness
- end
- par.active.next = {
- id = unhyphenated_code,
- subtype = fit_decent_class,
- next = par.active,
- break_node = nil,
- line_number = par.first_line + 1,
- total_demerits = 0,
- active_short = 0,
- active_glue = 0,
- }
- active_width.size = background.size
- active_width.stretch = background.stretch
- active_width.fi = background.fi
- active_width.fil = background.fil
- active_width.fill = background.fill
- active_width.filll = background.filll
- active_width.shrink = background.shrink
-
- if checked_expansion then
- active_width.adjust_stretch = 0
- active_width.adjust_shrink = 0
- end
-
- par.passive = nil -- = 0
- par.printed_node = temp_head -- only when tracing, shared
- par.printed_node.next = head
- par.pass_number = 0
- par.auto_breaking = true
-
- local cur_p = head
- local first_p = cur_p
-
- par.font_in_short_display = 0
-
- if cur_p and cur_p.id == whatsit_code and cur_p.subtype == localpar_code then
- par.init_internal_left_box = cur_p.box_left
- par.init_internal_left_box_width = cur_p.box_left_width
- par.internal_pen_inter = cur_p.pen_inter
- par.internal_pen_broken = cur_p.pen_broken
- par.internal_left_box = par.init_internal_left_box
- par.internal_left_box_width = par.init_internal_left_box_width
- par.internal_right_box = cur_p.box_right
- par.internal_right_box_width = cur_p.box_right_width
- end
-
- -- all passes are combined in this loop so maybe we should split this into
- -- three function calls; we then also need to do the wrap_up elsewhere
-
- -- split into normal and expansion loop
-
- -- use an active local
-
- local fontexp, lastfont -- we can pass fontexp to calculate width if needed
-
- while cur_p and par.active.next ~= par.active do
- while cur_p and cur_p.id == glyph_code do
- if is_rotated[par.line_break_dir] then
- active_width.size = active_width.size + cur_p.height + cur_p.depth
- else
- active_width.size = active_width.size + cur_p.width
- end
- if checked_expansion then
- local data= checked_expansion[cur_p.font]
- if data then
- local currentfont = cur_p.font
- if currentfont ~= lastfont then
- fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer
- lastfont = currentfont
- end
- if fontexps then
- local expansion = fontexps[cur_p.char]
- if expansion then
- active_width.adjust_stretch = active_width.adjust_stretch + expansion.glyphstretch
- active_width.adjust_shrink = active_width.adjust_shrink + expansion.glyphshrink
- end
- end
- end
- end
- cur_p = cur_p.next
- end
- if not cur_p then -- TODO
- report_parbuilders("problems with linebreak_tail")
- os.exit()
- end
- local id = cur_p.id
- if id == hlist_code or id == vlist_code then
- if is_parallel[cur_p.dir][par.line_break_dir] then
- active_width.size = active_width.size + cur_p.width
- else
- active_width.size = active_width.size + cur_p.depth + cur_p.height
- end
- elseif id == glue_code then
- if par.auto_breaking then
- local prev_p = cur_p.prev
- if prev_p and prev_p ~= temp_head then
- local id = prev_p.id
- if id == glyph_code or
- (id < math_code and (id ~= whatsit_code or prev_p.subtype ~= dir_code)) or -- was: precedes_break(prev_p)
- (id == kern_code and prev_p.subtype ~= userkern_code) then
- try_break(0, unhyphenated_code, par, first_p, cur_p, checked_expansion)
- end
- end
- end
- local spec = check_shrinkage(par,cur_p.spec)
- local order = stretch_orders[spec.stretch_order]
- cur_p.spec = spec
- active_width.size = active_width.size + spec.width
- active_width[order] = active_width[order] + spec.stretch
- active_width.shrink = active_width.shrink + spec.shrink
- elseif id == disc_code then
- local subtype = cur_p.subtype
- if subtype ~= second_disc_code then -- are there still second_disc_code in luatex
- local line_break_dir = par.line_break_dir
- if par.second_pass then -- todo: make second pass local
- local actual_pen = subtype == automatic_disc_code and par.ex_hyphen_penalty or par.hyphen_penalty
- local pre = cur_p.pre
- if not pre then -- trivial pre-break
- disc_width.size = 0
- if checked_expansion then
- disc_width.adjust_stretch = 0
- disc_width.adjust_shrink = 0
- end
- try_break(actual_pen, hyphenated_code, par, first_p, cur_p, checked_expansion)
- else
- local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,pre)
- disc_width.size = size
- active_width.size = active_width.size + size
- if checked_expansion then
- disc_width.adjust_stretch = adjust_stretch
- disc_width.adjust_shrink = adjust_shrink
- active_width.adjust_stretch = active_width.adjust_stretch + adjust_stretch
- active_width.adjust_shrink = active_width.adjust_shrink + adjust_shrink
- else
- -- disc_width.adjust_stretch = 0
- -- disc_width.adjust_shrink = 0
- end
- try_break(actual_pen, hyphenated_code, par, first_p, cur_p, checked_expansion)
- if subtype == first_disc_code then
- local cur_p_next = cur_p.next
- if cur_p_next.id ~= disc_code or cur_p_next.subtype ~= second_disc_code then
- report_parbuilders("unsupported disc at location %a",1)
- else
- local pre = cur_p_next.pre
- if pre then
- local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,pre)
- disc_width.size = disc_width.size + size
- if checked_expansion then
- disc_width.adjust_stretch = disc_width.adjust_stretch + adjust_stretch
- disc_width.adjust_shrink = disc_width.adjust_shrink + adjust_shrink
- end
- try_break(actual_pen, hyphenated_code, par, first_p, cur_p_next, checked_expansion)
- --
- -- I will look into this some day ... comment in linebreak.w says that this fails,
- -- maybe this is what Taco means with his comment in the luatex manual.
- --
- -- do_one_seven_eight(sub_disc_width_from_active_width);
- -- do_one_seven_eight(reset_disc_width);
- -- s = vlink_no_break(vlink(cur_p));
- -- add_to_widths(s, line_break_dir, pdf_adjust_spacing,disc_width);
- -- ext_try_break(...,first_p,vlink(cur_p));
- --
- else
- report_parbuilders("unsupported disc at location %a",2)
- end
- end
- end
- -- beware, we cannot restore to a saved value as the try_break adapts active_width
- active_width.size = active_width.size - disc_width.size
- if checked_expansion then
- active_width.adjust_stretch = active_width.adjust_stretch - disc_width.adjust_stretch
- active_width.adjust_shrink = active_width.adjust_shrink - disc_width.adjust_shrink
- end
- end
- end
- local replace = cur_p.replace
- if replace then
- local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,replace)
- active_width.size = active_width.size + size
- if checked_expansion then
- active_width.adjust_stretch = active_width.adjust_stretch + adjust_stretch
- active_width.adjust_shrink = active_width.adjust_shrink + adjust_shrink
- end
- end
- end
- elseif id == kern_code then
- if cur_p.subtype == userkern_code then
- kern_break(par,cur_p,first_p, checked_expansion)
- else
- local d = cur_p.kern
- of d ~= 0 then
- active_width.size = active_width.size + d
- if checked_expansion and expand_kerns and (cur_p.subtype == kerning_code or cur_p[a_fontkern]) then
- local stretch, shrink = kern_stretch_shrink(cur_p,d)
- if expand_kerns == "stretch" then
- active_width.adjust_stretch = active_width.adjust_stretch + stretch
- elseif expand_kerns == "shrink" then
- active_width.adjust_shrink = active_width.adjust_shrink + shrink
- else
- active_width.adjust_stretch = active_width.adjust_stretch + stretch
- active_width.adjust_shrink = active_width.adjust_shrink + shrink
- end
- end
- end
- end
- elseif id == math_code then
- par.auto_breaking = cur_p.subtype == endmath_code
- kern_break(par,cur_p, first_p, checked_expansion)
- elseif id == rule_code then
- active_width.size = active_width.size + cur_p.width
- elseif id == penalty_code then
- try_break(cur_p.penalty, unhyphenated_code, par, first_p, cur_p, checked_expansion)
- elseif id == whatsit_code then
- local subtype = cur_p.subtype
- if subtype == localpar_code then
- par.internal_pen_inter = cur_p.pen_inter
- par.internal_pen_broken = cur_p.pen_broken
- par.internal_left_box = cur_p.box_left
- par.internal_left_box_width = cur_p.box_left_width
- par.internal_right_box = cur_p.box_right
- par.internal_right_box_width = cur_p.box_right_width
- elseif subtype == dir_code then
- par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir
- else
- local get_width = get_whatsit_width[subtype]
- if get_width then
- active_width.size = active_width.size + get_width(cur_p)
- end
- end
- elseif id == mark_code or id == ins_code or id == adjust_code then
- -- skip
- else
- report_parbuilders("node of type %a found in paragraph",type(id))
- end
- cur_p = cur_p.next
- end
- if not cur_p then
- try_break(eject_penalty, hyphenated_code, par, first_p, cur_p, checked_expansion)
- local p_active = par.active
- local n_active = p_active.next
- if n_active ~= p_active then
- local r = n_active
- par.fewest_demerits = awful_badness
- repeat -- use local d
- if r.id ~= delta_code and r.total_demerits < par.fewest_demerits then
- par.fewest_demerits = r.total_demerits
- par.best_bet = r
- end
- r = r.next
- until r == p_active
- par.best_line = par.best_bet.line_number
- local asked_looseness = par.looseness
- if asked_looseness == 0 then
- return wrap_up(par)
- end
- local r = n_active
- local actual_looseness = 0
- -- minimize assignments to par but happens seldom
- repeat
- if r.id ~= delta_code then
- local line_diff = r.line_number - par.best_line
- par.line_diff = line_diff
- if (line_diff < actual_looseness and asked_looseness <= line_diff) or
- (line_diff > actual_looseness and asked_looseness >= line_diff) then
- par.best_bet = r
- actual_looseness = line_diff
- par.fewest_demerits = r.total_demerits
- elseif line_diff == actual_looseness and r.total_demerits < par.fewest_demerits then
- par.best_bet = r
- par.fewest_demerits = r.total_demerits
- end
- end
- r = r.next
- until r == p_active -- weird, loop list?
- par.best_line = par.best_bet.line_number
- if actual_looseness == asked_looseness or par.final_pass then
- return wrap_up(par)
- end
- end
- end
- reset_meta(par) -- clean up the memory by removing the break nodes
- if not par.second_pass then
- if tracing_paragraphs then
- diagnostics.current_pass(par,"secondpass")
- end
- par.threshold = par.tolerance
- par.second_pass = true
- par.final_pass = par.emergency_stretch <= 0
- else
- if tracing_paragraphs then
- diagnostics.current_pass(par,"emergencypass")
- end
- par.background.stretch = par.background.stretch + par.emergency_stretch
- par.final_pass = true
- end
- end
- return wrap_up(par)
-end
-
--- standard tex logging .. will be adapted ..
-
-local function write_esc(cs)
- local esc = tex.escapechar
- if esc then
- write("log",utfchar(esc),cs)
- else
- write("log",cs)
- end
-end
-
-function diagnostics.start()
-end
-
-function diagnostics.stop()
- write_nl("log",'')
-end
-
-function diagnostics.current_pass(par,what)
- write_nl("log",format("@%s",what))
-end
-
-local function short_display(a,font_in_short_display)
- while a do
- local id = a.id
- if id == glyph_code then
- local font = a.font
- if font ~= font_in_short_display then
- write("log",tex.fontidentifier(font) .. ' ')
- font_in_short_display = font
- end
- if a.subtype == ligature_code then
- font_in_short_display = short_display(a.components,font_in_short_display)
- else
- write("log",utfchar(a.char))
- end
--- elseif id == rule_code then
--- write("log","|")
--- elseif id == glue_code then
--- if a.spec.writable then
--- write("log"," ")
--- end
--- elseif id == math_code then
--- write("log","$")
- elseif id == disc_code then
- font_in_short_display = short_display(a.pre,font_in_short_display)
- font_in_short_display = short_display(a.post,font_in_short_display)
- else -- no explicit checking
- write("log",format("[%s]",nodecodes[id]))
- end
- a = a.next
- end
- return font_in_short_display
-end
-
-diagnostics.short_display = short_display
-
-function diagnostics.break_node(par, q, fit_class, break_type, cur_p) -- %d ?
- local passive = par.passive
- local typ_ind = break_type == hyphenated_code and '-' or ""
- if par.do_last_line_fit then
- local s = number.toscaled(q.active_short)
- local g = number.toscaled(q.active_glue)
- if cur_p then
- write_nl("log",format("@@%d: line %d.%d%s t=%s s=%s g=%s",
- passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g))
- else
- write_nl("log",format("@@%d: line %d.%d%s t=%s s=%s a=%s",
- passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g))
- end
- else
- write_nl("log",format("@@%d: line %d.%d%s t=%s",
- passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits))
- end
- if not passive.prev_break then
- write("log"," -> @0")
- else
- write("log",format(" -> @%d", passive.prev_break.serial or 0))
- end
-end
-
-function diagnostics.feasible_break(par, cur_p, r, b, pi, d, artificial_demerits)
- local printed_node = par.printed_node
- if printed_node ~= cur_p then
- write_nl("log","")
- if not cur_p then
- par.font_in_short_display = short_display(printed_node.next,par.font_in_short_display)
- else
- local save_link = cur_p.next
- cur_p.next = nil
- write_nl("log","")
- par.font_in_short_display = short_display(printed_node.next,par.font_in_short_display)
- cur_p.next = save_link
- end
- par.printed_node = cur_p
- end
- write_nl("log","@")
- if not cur_p then
- write_esc("par")
- else
- local id = cur_p.id
- if id == glue_code then
- -- print nothing
- elseif id == penalty_code then
- write_esc("penalty")
- elseif id == disc_code then
- write_esc("discretionary")
- elseif id == kern_code then
- write_esc("kern")
- elseif id == math_code then
- write_esc("math")
- else
- write_esc("unknown")
- end
- end
- local via, badness, demerits = 0, '*', '*'
- if r.break_node then
- via = r.break_node.serial or 0
- end
- if b <= infinite_badness then
- badness = tonumber(d) -- format("%d", b)
- end
- if not artificial_demerits then
- demerits = tonumber(d) -- format("%d", d)
- end
- write("log",format(" via @%d b=%s p=%s d=%s", via, badness, pi, demerits))
-end
-
--- reporting --
-
-statistics.register("alternative parbuilders", function()
- if nofpars > 0 then
- return format("%s paragraphs, %s lines (%s protruded, %s adjusted)", nofpars, noflines, nofprotrudedlines, nofadjustedlines)
- end
-end)
-
--- actually scaling kerns is not such a good idea and it will become
--- configureable
-
--- This is no way a replacement for the built in (fast) packer
--- it's just an alternative for special (testing) purposes.
---
--- We could use two hpacks: one to be used in the par builder
--- and one to be used for other purposes. The one in the par
--- builder is much more simple as it does not need the expansion
--- code but only need to register the effective expansion factor
--- with the glyph.
-
-local function glyph_width_height_depth(curdir,pdir,p)
- if is_rotated[curdir] then
- if is_parallel[curdir][pdir] then
- local half = (p.height + p.depth) / 2
- return p.width, half, half
- else
- local half = p.width / 2
- return p.height + p.depth, half, half
- end
- elseif is_rotated[pdir] then
- if is_parallel[curdir][pdir] then
- local half = (p.height + p.depth) / 2
- return p.width, half, half
- else
- return p.height + p.depth, p.width, 0 -- weird
- end
- else
- if glyphdir_is_equal[curdir][pdir] then
- return p.width, p.height, p.depth
- elseif is_opposite[curdir][pdir] then
- return p.width, p.depth, p.height
- else -- can this happen?
- return p.height + p.depth, p.width, 0 -- weird
- end
- end
-end
-
-local function pack_width_height_depth(curdir,pdir,p)
- if is_rotated[curdir] then
- if is_parallel[curdir][pdir] then
- local half = (p.height + p.depth) / 2
- return p.width, half, half
- else -- can this happen?
- local half = p.width / 2
- return p.height + p.depth, half, half
- end
- else
- if pardir_is_equal[curdir][pdir] then
- return p.width, p.height, p.depth
- elseif is_opposite[curdir][pdir] then
- return p.width, p.depth, p.height
- else -- weird dimensions, can this happen?
- -- return p.width, p.depth, p.height
- return p.height + p.depth, p.width, 0
- end
- end
-end
-
--- local function xpack(head,width,method,direction,analysis)
---
--- -- inspect(analysis)
---
--- local expansion = method == "cal_expand_ratio"
--- local natural = analysis.size
--- local font_stretch = analysis.adjust_stretch
--- local font_shrink = analysis.adjust_shrink
--- local font_expand_ratio = 0
--- local delta = width - natural
---
--- local hlist = new_node("hlist")
---
--- hlist.list = head
--- hlist.dir = direction or tex.textdir
--- hlist.width = width
--- hlist.height = height
--- hlist.depth = depth
---
--- if delta == 0 then
---
--- hlist.glue_sign = 0
--- hlist.glue_order = 0
--- hlist.glue_set = 0
---
--- else
---
--- local order = analysis.filll ~= 0 and fillcodes.filll or
--- analysis.fill ~= 0 and fillcodes.fill or
--- analysis.fil ~= 0 and fillcodes.fil or
--- analysis.fi ~= 0 and fillcodes.fi or 0
---
--- if delta > 0 then
---
--- if expansion and order == 0 and font_stretch > 0 then
--- font_expand_ratio = (delta/font_stretch) * 1000
--- else
--- local stretch = analysis.stretch
--- if stretch ~= 0 then
--- hlist.glue_sign = 1 -- stretch
--- hlist.glue_order = order
--- hlist.glue_set = delta/stretch
--- else
--- hlist.glue_sign = 0 -- nothing
--- hlist.glue_order = order
--- hlist.glue_set = 0
--- end
--- end
--- print("stretch",hlist.glue_sign,hlist.glue_order,hlist.glue_set)
---
--- else
---
--- if expansion and order == 0 and font_shrink > 0 then
--- font_expand_ratio = (delta/font_shrink) * 1000
--- else
--- local shrink = analysis.shrink
--- if shrink ~= 0 then
--- hlist.glue_sign = 2 -- shrink
--- hlist.glue_order = order
--- hlist.glue_set = - delta/shrink
--- else
--- hlist.glue_sign = 0 -- nothing
--- hlist.glue_order = order
--- hlist.glue_set = 0
--- end
--- end
--- print("shrink",hlist.glue_sign,hlist.glue_order,hlist.glue_set)
---
--- end
---
--- end
---
--- if not expansion or font_expand_ratio == 0 then
--- -- nothing
--- elseif font_expand_ratio > 0 then
--- if font_expand_ratio > 1000 then
--- font_expand_ratio = 1000
--- end
--- local current = head
--- while current do
--- local id = current.id
--- if id == glyph_code then
--- local stretch, shrink = char_stretch_shrink(current) -- get only one
--- if stretch then
--- if trace_expansion then
--- setnodecolor(g,"hz:positive")
--- end
--- current.expansion_factor = font_expand_ratio * stretch
--- end
--- elseif id == kern_code then
--- local kern = current.kern
--- if kern ~= 0 and current.subtype == kerning_code then
--- current.kern = font_expand_ratio * current.kern
--- end
--- end
--- current = current.next
--- end
--- elseif font_expand_ratio < 0 then
--- if font_expand_ratio < -1000 then
--- font_expand_ratio = -1000
--- end
--- local current = head
--- while current do
--- local id = current.id
--- if id == glyph_code then
--- local stretch, shrink = char_stretch_shrink(current) -- get only one
--- if shrink then
--- if trace_expansion then
--- setnodecolor(g,"hz:negative")
--- end
--- current.expansion_factor = font_expand_ratio * shrink
--- end
--- elseif id == kern_code then
--- local kern = current.kern
--- if kern ~= 0 and current.subtype == kerning_code then
--- current.kern = font_expand_ratio * current.kern
--- end
--- end
--- current = current.next
--- end
--- end
--- return hlist, 0
--- end
-
-local function hpack(head,width,method,direction) -- fast version when head = nil
-
- -- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but
- -- with the glue mess it's less trivial as we lack detail
-
- local hlist = new_node("hlist")
-
- if head == nil then
- return hlist, 0
- end
-
- local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font"
-
- direction = direction or tex.textdir
-
- local line = 0
-
- local height = 0
- local depth = 0
- local natural = 0
- local font_stretch = 0
- local font_shrink = 0
- local font_expand_ratio = 0
- local last_badness = 0
- local disc_stack = { }
- local disc_level = 0
- local expansion_stack = cal_expand_ratio and { } -- todo: optionally pass this
- local expansion_index = 0
- local total_stretch = { [0] = 0, 0, 0, 0, 0 }
- local total_shrink = { [0] = 0, 0, 0, 0, 0 }
-
- local hpack_dir = direction
-
- local adjust_head = texlists.adjust_head
- local pre_adjust_head = texlists.pre_adjust_head
- local adjust_tail = adjust_head and slide_nodes(adjust_head)
- local pre_adjust_tail = pre_adjust_head and slide_nodes(pre_adjust_head)
-
- hlist.list = head
- hlist.dir = hpack_dir
-
- new_dir_stack(hpack_dir)
-
- local checked_expansion = false
-
- if cal_expand_ratio then
- checked_expansion = { }
- setmetatableindex(checked_expansion,check_expand_lines)
- end
-
- -- this one also needs to check the font, so in the end indeed we might end up with two variants
-
- local fontexps, lastfont
-
- local current = head
-
- while current do
- local id = current.id
- if id == glyph_code then
- if cal_expand_ratio then
- local currentfont = current.font
- if currentfont ~= lastfont then
- fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer
- lastfont = currentfont
- end
- if fontexps then
- local expansion = fontexps[current.char]
- if expansion then
- font_stretch = font_stretch + expansion.glyphstretch
- font_shrink = font_shrink + expansion.glyphshrink
- expansion_index = expansion_index + 1
- expansion_stack[expansion_index] = current
- end
- end
- end
- -- use inline if no expansion
- local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ?
- natural = natural + wd
- if ht > height then
- height = ht
- end
- if dp > depth then
- depth = dp
- end
- current = current.next
- elseif id == kern_code then
- local kern = current.kern
- if kern == 0 then
- -- no kern
- else
- if cal_expand_ratio and expand_kerns and current.subtype == kerning_code or current[a_fontkern] then -- check p.kern
- local stretch, shrink = kern_stretch_shrink(current,kern)
- if expand_kerns == "stretch" then
- font_stretch = font_stretch + stretch
- elseif expand_kerns == "shrink" then
- font_shrink = font_shrink + shrink
- else
- font_stretch = font_stretch + stretch
- font_shrink = font_shrink + shrink
- end
- expansion_index = expansion_index + 1
- expansion_stack[expansion_index] = current
- end
- natural = natural + kern
- end
- current = current.next
- elseif id == disc_code then
- if current.subtype ~= second_disc_code then
- -- we follow the end of line disc chain
- local replace = current.replace
- if replace then
- disc_level = disc_level + 1
- disc_stack[disc_level] = current.next
- current = replace
- else
- current = current.next
- end
- else
- current = current.next
- end
- elseif id == glue_code then
- local spec = current.spec
- natural = natural + spec.width
- local op = spec.stretch_order
- local om = spec.shrink_order
- total_stretch[op] = total_stretch[op] + spec.stretch
- total_shrink [om] = total_shrink [om] + spec.shrink
- if current.subtype >= leaders_code then
- local leader = current.leader
- local ht = leader.height
- local dp = leader.depth
- if ht > height then
- height = ht
- end
- if dp > depth then
- depth = dp
- end
- end
- current = current.next
- elseif id == hlist_code or id == vlist_code then
- local sh = current.shift
- local wd, ht, dp = pack_width_height_depth(hpack_dir,current.dir or hpack_dir,current) -- added: or pack_dir
- local hs, ds = ht - sh, dp + sh
- natural = natural + wd
- if hs > height then
- height = hs
- end
- if ds > depth then
- depth = ds
- end
- current = current.next
- elseif id == rule_code then
- local wd = current.width
- local ht = current.height
- local dp = current.depth
- natural = natural + wd
- if ht > height then
- height = ht
- end
- if dp > depth then
- depth = dp
- end
- current = current.next
- elseif id == math_code then
- natural = natural + current.surround
- current = current.next
- elseif id == unset_code then
- local wd = current.width
- local ht = current.height
- local dp = current.depth
- local sh = current.shift
- local hs = ht - sh
- local ds = dp + sh
- natural = natural + wd
- if hs > height then
- height = hs
- end
- if ds > depth then
- depth = ds
- end
- current = current.next
- elseif id == ins_code or id == mark_code then
- local prev = current.prev
- local next = current.next
- if adjust_tail then -- todo
- if next then
- next.prev = prev
- end
- if prev then
- prev.next = next
- end
- current.prev = adjust_tail
- current.next = nil
- adjust_tail.next = current
- adjust_tail = current
- else
- adjust_head = current
- adjust_tail = current
- current.prev = nil
- current.next = nil
- end
- current = next
- elseif id == adjust_code then
- local list = current.list
- if adjust_tail then
- adjust_tail.next = list
- adjust_tail = slide_nodes(list)
- else
- adjust_head = list
- adjust_tail = slide_nodes(list)
- end
- current = current.next
- elseif id == whatsit_code then
- local subtype = current.subtype
- if subtype == dir_code then
- hpack_dir = checked_line_dir(stack,current) or hpack_dir
- else
- local get_dimensions = get_whatsit_dimensions[subtype]
- if get_dimensions then
- local wd, ht, dp = get_dimensions(current)
- natural = natural + wd
- if ht > height then
- height = ht
- end
- if dp > depth then
- depth = dp
- end
- end
- end
- current = current.next
- elseif id == marginkern_code then
- if cal_expand_ratio then
- local glyph = current.glyph
- local char_pw = current.subtype == leftmargin_code and left_pw or right_pw
- font_stretch = font_stretch - current.width - char_pw(glyph)
- font_shrink = font_shrink - current.width - char_pw(glyph)
- expansion_index = expansion_index + 1
- expansion_stack[expansion_index] = glyph
- end
- natural = natural + current.width
- current = current.next
- else
- current = current.next
- end
- if not current and disc_level > 0 then
- current = disc_stack[disc_level]
- disc_level = disc_level - 1
- end
- end
- if adjust_tail then
- adjust_tail.next = nil -- todo
- end
- if pre_adjust_tail then
- pre_adjust_tail.next = nil -- todo
- end
- if mode == "additional" then
- width = width + natural
- end
-
- hlist.width = width
- hlist.height = height
- hlist.depth = depth
-
- local delta = width - natural
- if delta == 0 then
- hlist.glue_sign = 0
- hlist.glue_order = 0
- hlist.glue_set = 0
- elseif delta > 0 then
- -- natural width smaller than requested width
- local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or
- (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0
--- local correction = 0
- if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch
- font_expand_ratio = delta/font_stretch
-
- if font_expand_ratio > 1 then
- font_expand_ratio = 1
- end
-
- local fontexps, lastfont
- for i=1,expansion_index do
- local g = expansion_stack[i]
- local e
- if g.id == glyph_code then
- local currentfont = g.font
- if currentfont ~= lastfont then
- fontexps = expansions[currentfont]
- lastfont = currentfont
- end
- local data = fontexps[g.char]
- if trace_expansion then
- setnodecolor(g,"hz:positive")
- end
- e = font_expand_ratio * data.glyphstretch / 1000
--- correction = correction + (e / 1000) * g.width
- else
- local kern = g.kern
- local stretch, shrink = kern_stretch_shrink(g,kern)
- e = font_expand_ratio * stretch / 1000
--- correction = correction + (e / 1000) * kern
- end
- g.expansion_factor = e
- end
- end
--- delta = delta - correction
- local tso = total_stretch[order]
- if tso ~= 0 then
- hlist.glue_sign = 1
- hlist.glue_order = order
- hlist.glue_set = delta/tso
- else
- hlist.glue_sign = 0
- hlist.glue_order = order
- hlist.glue_set = 0
- end
- if font_expand_ratio ~= 0 then
- -- todo
- elseif order == 0 then -- and hlist.list then
- last_badness = calculate_badness(delta,total_stretch[0])
- if last_badness > tex.hbadness then
- if last_badness > 100 then
- diagnostics.underfull_hbox(hlist,line,last_badness)
- else
- diagnostics.loose_hbox(hlist,line,last_badness)
- end
- end
- end
- else
- -- natural width larger than requested width
- local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3
- or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0
--- local correction = 0
- if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink
- font_expand_ratio = delta/font_shrink
-
- if font_expand_ratio < 1 then
- font_expand_ratio = -1
- end
-
- local fontexps, lastfont
- for i=1,expansion_index do
- local g = expansion_stack[i]
- local e
- if g.id == glyph_code then
- local currentfont = g.font
- if currentfont ~= lastfont then
- fontexps = expansions[currentfont]
- lastfont = currentfont
- end
- local data = fontexps[g.char]
- if trace_expansion then
- setnodecolor(g,"hz:negative")
- end
- e = font_expand_ratio * data.glyphshrink / 1000
- -- local d = (e / 1000) * 1000
- -- local eps = g.width - (1 + d / 1000000) * g.width
- -- correction = correction + eps
- -- e = d
--- correction = correction + (e / 1000) * g.width
- else
- local kern = g.kern
- local stretch, shrink = kern_stretch_shrink(g,kern)
- e = font_expand_ratio * shrink / 1000
--- correction = correction + (e / 1000) * kern
- end
- g.expansion_factor = e
- end
- end
--- delta = delta - correction
- local tso = total_shrink[order]
- if tso ~= 0 then
- hlist.glue_sign = 2
- hlist.glue_order = order
- hlist.glue_set = -delta/tso
- else
- hlist.glue_sign = 0
- hlist.glue_order = order
- hlist.glue_set = 0
- end
- if font_expand_ratio ~= 0 then
- -- todo
- elseif tso < -delta and order == 0 then -- and hlist.list then
- last_badness = 1000000
- hlist.glue_set = 1
- local fuzz = - delta - total_shrink[0]
- local hfuzz = tex.hfuzz
- if fuzz > hfuzz or tex.hbadness < 100 then
- local overfullrule = tex.overfullrule
- if fuzz > hfuzz and overfullrule > 0 then
- -- weird, is always called and no rules shows up
- slide_nodes(list).next = new_rule(overfullrule,nil,nil,hlist.dir)
- end
- diagnostics.overfull_hbox(hlist,line,-delta)
- end
- elseif order == 0 and hlist.list and last_badness > tex.hbadness then
- diagnostics.bad_hbox(hlist,line,last_badness)
- end
- end
- return hlist, last_badness
-end
-
-xpack_nodes = hpack -- comment this for old fashioned expansion
-
-local function common_message(hlist,line,str)
- write_nl("")
- if status.output_active then -- unset
- write(str," has occurred while \\output is active")
- end
- local fileline = status.linenumber
- if line > 0 then
- write(str," in paragraph at lines ",fileline,"--",fileline+line-1)
- elseif line < 0 then
- write(str," in alignment at lines ",fileline,"--",fileline-line-1)
- else
- write(str," detected at line ",fileline)
- end
- write_nl("")
- diagnostics.short_display(hlist.list,false)
- write_nl("")
- -- diagnostics.start()
- -- show_box(hlist.list)
- -- diagnostics.stop()
-end
-
-function diagnostics.overfull_hbox(hlist,line,d)
- common_message(hlist,line,format("Overfull \\hbox (%spt too wide)",number.toscaled(d)))
-end
-
-function diagnostics.bad_hbox(hlist,line,b)
- common_message(hlist,line,format("Tight \\hbox (badness %i)",b))
-end
-
-function diagnostics.underfull_hbox(hlist,line,b)
- common_message(hlist,line,format("Underfull \\hbox (badness %i)",b))
-end
-
-function diagnostics.loose_hbox(hlist,line,b)
- common_message(hlist,line,format("Loose \\hbox (badness %i)",b))
-end
-
--- e = font_expand_ratio * data.glyphstretch / 1000
--- local stretch = data.stretch
--- if e >= stretch then
--- e = stretch
--- else
--- local step = 5
--- e = math.round(e/step) * step
--- end
-
--- local shrink = - data.shrink
--- if e <= shrink then
--- e = shrink
--- else
--- local step = 5
--- e = math.round(e/step) * step
--- end
diff --git a/tex/context/base/node-mig.lua b/tex/context/base/node-mig.lua
index 9fc35a048..2b35335c3 100644
--- a/tex/context/base/node-mig.lua
+++ b/tex/context/base/node-mig.lua
@@ -6,15 +6,32 @@ if not modules then modules = { } end modules ['node-mig'] = {
license = "see context related readme files"
}
+-- todo: insert_after
+
local format = string.format
-local attributes, nodes, node = attributes, nodes, node
+local trace_migrations = false trackers.register("nodes.migrations", function(v) trace_migrations = v end)
-local remove_nodes = nodes.remove
+local report_nodes = logs.reporter("nodes","migrations")
-local nodecodes = nodes.nodecodes
+local attributes = attributes
+local nodes = nodes
local tasks = nodes.tasks
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local remove_nodes = nuts.remove
+
+local nodecodes = nodes.nodecodes
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local insert_code = nodecodes.ins
@@ -22,10 +39,6 @@ local mark_code = nodecodes.mark
local a_migrated = attributes.private("migrated")
-local trace_migrations = false trackers.register("nodes.migrations", function(v) trace_migrations = v end)
-
-local report_nodes = logs.reporter("nodes","migrations")
-
local migrate_inserts, migrate_marks, inserts_too
local t_inserts, t_marks, t_sweeps = 0, 0, 0
@@ -33,32 +46,42 @@ local t_inserts, t_marks, t_sweeps = 0, 0, 0
local function locate(head,first,last,ni,nm)
local current = head
while current do
- local id = current.id
+ local id = getid(current)
if id == vlist_code or id == hlist_code then
- current.list, first, last, ni, nm = locate(current.list,first,last,ni,nm)
- current = current.next
+ local list = getlist(current)
+ if list then
+ list, first, last, ni, nm = locate(list,first,last,ni,nm)
+ setfield(current,"list",list)
+ end
+ current = getnext(current)
elseif migrate_inserts and id == insert_code then
local insert
head, current, insert = remove_nodes(head,current)
- insert.next = nil
+ setfield(insert,"next",nil)
if first then
- insert.prev, last.next = last, insert
+ setfield(insert,"prev",last)
+ setfield(last,"next",insert)
else
- insert.prev, first = nil, insert
+ setfield(insert,"prev",nil)
+ first = insert
end
- last, ni = insert, ni + 1
+ last = insert
+ ni = ni + 1
elseif migrate_marks and id == mark_code then
local mark
head, current, mark = remove_nodes(head,current)
- mark.next = nil
+ setfield(mark,"next",nil)
if first then
- mark.prev, last.next = last, mark
+ setfield(mark,"prev",last)
+ setfield(last,"next",mark)
else
- mark.prev, first = nil, mark
+ setfield(mark,"prev",nil)
+ first = mark
end
- last, nm = mark, nm + 1
+ last = mark
+ nm = nm + 1
else
- current= current.next
+ current = getnext(current)
end
end
return head, first, last, ni, nm
@@ -70,39 +93,43 @@ function nodes.handlers.migrate(head,where)
if trace_migrations then
report_nodes("migration sweep %a",where)
end
- local current = head
+ local current = tonut(head)
while current do
- local id = current.id
+ local id = getid(current)
-- inserts_too is a temp hack, we should only do them when it concerns
-- newly placed (flushed) inserts
- if id == vlist_code or id == hlist_code or (inserts_too and id == insert_code) and not current[a_migrated] then
- current[a_migrated] = 1
+ if id == vlist_code or id == hlist_code or (inserts_too and id == insert_code) and not getattr(current,a_migrated) then
+ setattr(current,a_migrated,1)
t_sweeps = t_sweeps + 1
- local h = current.list
+ local h = getlist(current)
local first, last, ni, nm
while h do
- local id = h.id
+ local id = getid(h)
if id == vlist_code or id == hlist_code then
h, first, last, ni, nm = locate(h,first,last,0,0)
end
- h = h.next
+ h = getnext(h)
end
if first then
- t_inserts, t_marks = t_inserts + ni, t_marks + nm
+ t_inserts = t_inserts + ni
+ t_marks = t_marks + nm
if trace_migrations and (ni > 0 or nm > 0) then
report_nodes("sweep %a, container %a, %s inserts and %s marks migrated outwards during %a",
t_sweeps,nodecodes[id],ni,nm,where)
end
- -- inserts after head
- local n = current.next
+ -- inserts after head, use insert_after
+ local n = getnext(current)
if n then
- last.next, n.prev = n, last
+ setfield(last,"next",n)
+ setfield(n,"prev",last)
end
- current.next, first.prev = first, current
- done, current = true, last
+ setfield(current,"next",first)
+ setfield(first,"prev",current)
+ done = true
+ current = last
end
end
- current = current.next
+ current = getnext(next)
end
return head, done
end
diff --git a/tex/context/base/node-pro.lua b/tex/context/base/node-pro.lua
index aa6692d7b..2cc00601c 100644
--- a/tex/context/base/node-pro.lua
+++ b/tex/context/base/node-pro.lua
@@ -13,15 +13,15 @@ local trace_callbacks = false trackers.register("nodes.callbacks", function(v)
local report_nodes = logs.reporter("nodes","processors")
-local nodes, node = nodes, node
+local nodes = nodes
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local tasks = nodes.tasks
+local nuts = nodes.nuts
-local free_node = node.free
-local first_glyph = node.first_glyph or node.first_character
-local has_attribute = node.has_attribute
+local first_glyph = nodes.first_glyph
+local has_glyph = nodes.has_glyph
nodes.processors = nodes.processors or { }
local processors = nodes.processors
@@ -31,43 +31,53 @@ local processors = nodes.processors
local actions = tasks.actions("processors")
-local n = 0
+do
-local function reconstruct(head) -- we probably have a better one
- local t, n, h = { }, 0, head
- while h do
+ local tonut = nuts.tonut
+ local getid = nuts.getid
+ local getchar = nuts.getchar
+ local getnext = nuts.getnext
+
+ local n = 0
+
+ local function reconstruct(head) -- we probably have a better one
+ local t, n, h = { }, 0, tonut(head)
+ while h do
+ n = n + 1
+ local id = getid(h)
+ if id == glyph_code then -- todo: disc etc
+ t[n] = utfchar(getchar(h))
+ else
+ t[n] = "[]"
+ end
+ h = getnext(h)
+ end
+ return concat(t)
+ end
+
+ local function tracer(what,state,head,groupcode,before,after,show)
+ if not groupcode then
+ groupcode = "unknown"
+ elseif groupcode == "" then
+ groupcode = "mvl"
+ end
n = n + 1
- local id = h.id
- if id == glyph_code then -- todo: disc etc
- t[n] = utfchar(h.char)
+ if show then
+ report_nodes("%s: location %a, state %a, group %a, # before %a, # after %s, stream: %s",what,n,state,groupcode,before,after,reconstruct(head))
else
- t[n] = "[]"
+ report_nodes("%s: location %a, state %a, group %a, # before %a, # after %s",what,n,state,groupcode,before,after)
end
- h = h.next
end
- return concat(t)
-end
-local function tracer(what,state,head,groupcode,before,after,show)
- if not groupcode then
- groupcode = "unknown"
- elseif groupcode == "" then
- groupcode = "mvl"
- end
- n = n + 1
- if show then
- report_nodes("%s: location %a, state %a, group %a, # before %a, # after %s, stream: %s",what,n,state,groupcode,before,after,reconstruct(head))
- else
- report_nodes("%s: location %a, state %a, group %a, # before %a, # after %s",what,n,state,groupcode,before,after)
- end
-end
+ processors.tracer = tracer
-processors.tracer = tracer
+end
processors.enabled = true -- this will become a proper state (like trackers)
function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction
- local first, found = first_glyph(head) -- they really need to be glyphs
+ -- local first, found = first_glyph(head) -- they really need to be glyphs
+ local found = has_glyph(head)
if found then
if trace_callbacks then
local before = nodes.count(head,true)
@@ -94,10 +104,8 @@ local enabled = true
function processors.hpack_filter(head,groupcode,size,packtype,direction)
if enabled then
- -- if not head.next and head.id ~= glyph_code then -- happens often but not faster
- -- return true
- -- end
- local first, found = first_glyph(head) -- they really need to be glyphs
+ -- local first, found = first_glyph(head) -- they really need to be glyphs
+ local found = has_glyph(head)
if found then
if trace_callbacks then
local before = nodes.count(head,true)
@@ -121,15 +129,36 @@ function processors.hpack_filter(head,groupcode,size,packtype,direction)
return true
end
-local hpack = node.hpack
+do
+
+ local setfield = nodes.setfield
+ local hpack = nodes.hpack
+
+ function nodes.fasthpack(...) -- todo: pass explicit arguments
+ enabled = false
+ local hp, b = hpack(...)
+ setfield(hp,"prev",nil)
+ setfield(hp,"next",nil)
+ enabled = true
+ return hp, b
+ end
+
+end
+
+do
+
+ local setfield = nuts.setfield
+ local hpack = nuts.hpack
+
+ function nuts.fasthpack(...) -- todo: pass explicit arguments
+ enabled = false
+ local hp, b = hpack(...)
+ setfield(hp,"prev",nil)
+ setfield(hp,"next",nil)
+ enabled = true
+ return hp, b
+ end
-function nodes.fasthpack(...) -- todo: pass explicit arguments
- enabled = false
- local hp, b = hpack(...)
- hp.prev = nil
- hp.next = nil
- enabled = true
- return hp, b
end
callbacks.register('pre_linebreak_filter', processors.pre_linebreak_filter, "all kind of horizontal manipulations (before par break)")
diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua
index aa864fb1c..7cfbde849 100644
--- a/tex/context/base/node-ref.lua
+++ b/tex/context/base/node-ref.lua
@@ -21,7 +21,6 @@ local attributes, nodes, node = attributes, nodes, node
local allocate = utilities.storage.allocate, utilities.storage.mark
local mark = utilities.storage.allocate, utilities.storage.mark
-
local nodeinjections = backends.nodeinjections
local codeinjections = backends.codeinjections
@@ -33,9 +32,6 @@ local colors = attributes.colors
local references = structures.references
local tasks = nodes.tasks
-local hpack_list = node.hpack
-local list_dimensions = node.dimensions
-
local trace_backend = false trackers.register("nodes.backend", function(v) trace_backend = v end)
local trace_references = false trackers.register("nodes.references", function(v) trace_references = v end)
local trace_destinations = false trackers.register("nodes.destinations", function(v) trace_destinations = v end)
@@ -44,6 +40,27 @@ local report_reference = logs.reporter("backend","references")
local report_destination = logs.reporter("backend","destinations")
local report_area = logs.reporter("backend","areas")
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+
+local hpack_list = nuts.hpack
+local list_dimensions = nuts.dimensions
+local traverse = nuts.traverse
+local find_node_tail = nuts.tail
+
local nodecodes = nodes.nodecodes
local skipcodes = nodes.skipcodes
local whatcodes = nodes.whatcodes
@@ -63,21 +80,18 @@ local dir_code = whatcodes.dir
local line_code = listcodes.line
-local nodepool = nodes.pool
-
+local new_rule = nodepool.rule
local new_kern = nodepool.kern
-local traverse = node.traverse
-local find_node_tail = node.tail or node.slide
local tosequence = nodes.tosequence
-- local function dimensions(parent,start,stop)
--- stop = stop and stop.next
+-- stop = stop and getnext(stop)
-- if parent then
-- if stop then
--- return list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,start,stop)
+-- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop)
-- else
--- return list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,start)
+-- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign",getfield(parent,"glue_order"),start)
-- end
-- else
-- if stop then
@@ -92,9 +106,9 @@ local tosequence = nodes.tosequence
local function dimensions(parent,start,stop)
if parent then
- return list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,start,stop and stop.next)
+ return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop and getnext(stop))
else
- return list_dimensions(start,stop and stop.next)
+ return list_dimensions(start,stop and getnext(stop))
end
end
@@ -111,25 +125,25 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t
if trace_backend then
report_area("head: %04i %s %s %s => w=%p, h=%p, d=%p, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved)
end
- result.next = first
- first.prev = result
+ setfield(result,"next",first)
+ setfield(first,"prev",result)
return result, last
else
if trace_backend then
report_area("middle: %04i %s %s => w=%p, h=%p, d=%p, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved)
end
- local prev = first.prev
+ local prev = getprev(first)
if prev then
- result.next = first
- result.prev = prev
- prev.next = result
- first.prev = result
+ setfield(result,"next",first)
+ setfield(result,"prev",prev)
+ setfield(prev,"next",result)
+ setfield(first,"prev",result)
else
- result.next = first
- first.prev = result
+ setfield(result,"next",first)
+ setfield(first,"prev",result)
end
- if first == head.next then
- head.next = result -- hm, weird
+ if first == getnext(head) then
+ setfield(head,"next",result) -- hm, weird
end
return head, last
end
@@ -139,9 +153,9 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t
end
local function inject_list(id,current,reference,make,stack,pardir,txtdir)
- local width, height, depth, correction = current.width, current.height, current.depth, 0
+ local width, height, depth, correction = getfield(current,"width"), getfield(current,"height"), getfield(current,"depth"), 0
local moveright = false
- local first = current.list
+ local first = getlist(current)
if id == hlist_code then -- box_code line_code
-- can be either an explicit hbox or a line and there is no way
-- to recognize this; anyway only if ht/dp (then inline)
@@ -149,17 +163,17 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir)
if first then
if sr and sr[2] then
local last = find_node_tail(first)
- if last.id == glue_code and last.subtype == rightskip_code then
- local prev = last.prev
- moveright = first.id == glue_code and first.subtype == leftskip_code
- if prev and prev.id == glue_code and prev.subtype == parfillskip_code then
- width = dimensions(current,first,prev.prev) -- maybe not current as we already take care of it
+ if getid(last) == glue_code and getsubtype(last) == rightskip_code then
+ local prev = getprev(last)
+ moveright = getid(first) == glue_code and getsubtype(first) == leftskip_code
+ if prev and getid(prev) == glue_code and getsubtype(prev) == parfillskip_code then
+ width = dimensions(current,first,getprev(prev)) -- maybe not current as we already take care of it
else
- if moveright and first.writable then
- width = width - first.spec.stretch*current.glue_set * current.glue_sign
+ if moveright and getfield(first,"writable") then
+ width = width - getfield(getfield(first,"spec"),"stretch") * getfield(current,"glue_set") * getfield(current,"glue_sign")
end
- if last.writable then
- width = width - last.spec.stretch*current.glue_set * current.glue_sign
+ if getfield(last,"writable") then
+ width = width - getfield(getfield(last,"spec"),"stretch") * getfield(current,"glue_set") * getfield(current,"glue_sign")
end
end
end
@@ -184,19 +198,21 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir)
report_area("box: %04i %s %s: w=%p, h=%p, d=%p, c=%s",reference,pardir or "---",txtdir or "----",width,height,depth,resolved)
end
if not first then
- current.list = result
+ setfield(current,"list",result)
elseif moveright then -- brr no prevs done
-- result after first
- local n = first.next
- result.next = n
- first.next = result
- result.prev = first
- if n then n.prev = result end
+ local n = getnext(first)
+ setfield(result,"next",n)
+ setfield(first,"next",result)
+ setfield(result,"prev",first)
+ if n then
+ setfield(n,"prev",result)
+ end
else
-- first after result
- result.next = first
- first.prev = result
- current.list = result
+ setfield(result,"next",first)
+ setfield(first,"prev",result)
+ setfield(current,"list",result)
end
end
end
@@ -209,9 +225,9 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
pardir = pardir or "==="
txtdir = txtdir or "==="
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code or id == vlist_code then
- local r = current[attribute]
+ local r = getattr(current,attribute)
-- somehow reference is true so the following fails (second one not done) in
-- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
-- so let's wait till this fails again
@@ -222,32 +238,33 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
if r then
done[r] = (done[r] or 0) + 1
end
- local list = current.list
+ local list = getlist(current)
if list then
- local _
- current.list, _, pardir, txtdir = inject_areas(list,attribute,make,stack,done,r or skip or 0,current,pardir,txtdir)
+ local h, ok
+ h, ok , pardir, txtdir = inject_areas(list,attribute,make,stack,done,r or skip or 0,current,pardir,txtdir)
+ setfield(current,"list",h)
end
if r then
done[r] = done[r] - 1
end
elseif id == whatsit_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == localpar_code then
- pardir = current.dir
+ pardir = getfield(current,"dir")
elseif subtype == dir_code then
- txtdir = current.dir
+ txtdir = getfield(current,"dir")
end
- elseif id == glue_code and current.subtype == leftskip_code then -- any glue at the left?
+ elseif id == glue_code and getsubtype(current) == leftskip_code then -- any glue at the left?
--
else
- local r = current[attribute]
+ local r = getattr(current,attribute)
if not r then
-- just go on, can be kerns
elseif not reference then
reference, first, last, firstdir = r, current, current, txtdir
elseif r == reference then
last = current
- elseif (done[reference] or 0) == 0 then -- or id == glue_code and current.subtype == right_skip_code
+ elseif (done[reference] or 0) == 0 then -- or id == glue_code and getsubtype(current) == right_skip_code
if not skip or r > skip then -- maybe no > test
head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
reference, first, last, firstdir = nil, nil, nil, nil
@@ -256,7 +273,7 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
reference, first, last, firstdir = r, current, current, txtdir
end
end
- current = current.next
+ current = getnext(current)
end
if reference and (done[reference] or 0) == 0 then
head = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
@@ -271,32 +288,32 @@ local function inject_area(head,attribute,make,stack,done,parent,pardir,txtdir)
txtdir = txtdir or "==="
local current = head
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code or id == vlist_code then
- local r = current[attribute]
+ local r = getattr(current,attribute)
if r and not done[r] then
done[r] = true
inject_list(id,current,r,make,stack,pardir,txtdir)
end
- local list = current.list
+ local list = getlist(current)
if list then
- current.list = inject_area(list,attribute,make,stack,done,current,pardir,txtdir)
+ setfield(current,"list",inject_area(list,attribute,make,stack,done,current,pardir,txtdir))
end
elseif id == whatsit_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == localpar_code then
- pardir = current.dir
+ pardir = getfield(current,"dir")
elseif subtype == dir_code then
- txtdir = current.dir
+ txtdir = getfield(current,"dir")
end
else
- local r = current[attribute]
+ local r = getattr(current,attribute)
if r and not done[r] then
done[r] = true
head, current = inject_range(head,current,current,r,make,stack,parent,pardir,txtdir)
end
end
- current = current.next
+ current = getnext(current)
end
end
return head, true
@@ -304,12 +321,6 @@ end
-- tracing
-local nodepool = nodes.pool
-
-local new_rule = nodepool.rule
-local new_kern = nodepool.kern
-
-local set_attribute = node.set_attribute
local register_color = colors.register
local a_color = attributes.private('color')
@@ -346,15 +357,15 @@ local function colorize(width,height,depth,n,reference,what)
height = 65536/2
depth = height
end
- local rule = new_rule(width,height,depth)
- rule[a_colormodel] = 1 -- gray color model
- rule[a_color] = u_color
- rule[a_transparency] = u_transparency
+ local rule = new_rule(width,height,depth) -- todo: use tracer rule
+ setattr(rule,a_colormodel,1) -- gray color model
+ setattr(rule,a_color,u_color)
+ setattr(rule,a_transparency,u_transparency)
if width < 0 then
local kern = new_kern(width)
- rule.width = -width
- kern.next = rule
- rule.prev = kern
+ setfield(rule,"width",-width)
+ setfield(kern,"next",rule)
+ setfield(rule,"prev",kern)
return kern
else
return rule
@@ -363,9 +374,6 @@ end
-- references:
-local nodepool = nodes.pool
-local new_kern = nodepool.kern
-
local texsetattribute = tex.setattribute
local texsetcount = tex.setcount
@@ -410,22 +418,25 @@ local function makereference(width,height,depth,reference)
end
local annot = nodeinjections.reference(width,height,depth,set)
if annot then
+annot = tonut(annot)
nofreferences = nofreferences + 1
local result, current
if trace_references then
local step = 65536
result = hpack_list(colorize(width,height-step,depth-step,2,reference,"reference")) -- step subtracted so that we can see seperate links
- result.width = 0
+ setfield(result,"width",0)
current = result
end
if current then
- current.next = annot
+ setfield(current,"next",annot)
else
result = annot
end
references.registerpage(n)
result = hpack_list(result,0)
- result.width, result.height, result.depth = 0, 0, 0
+ setfield(result,"width",0)
+ setfield(result,"height",0)
+ setfield(result,"depth",0)
if cleanupreferences then stack[reference] = nil end
return result, resolved
elseif trace_references then
@@ -436,9 +447,19 @@ local function makereference(width,height,depth,reference)
end
end
+-- function nodes.references.handler(head)
+-- if topofstack > 0 then
+-- return inject_areas(head,attribute,makereference,stack,done)
+-- else
+-- return head, false
+-- end
+-- end
+
function nodes.references.handler(head)
if topofstack > 0 then
- return inject_areas(head,attribute,makereference,stack,done)
+ head = tonut(head)
+ local head, done = inject_areas(head,attribute,makereference,stack,done)
+ return tonode(head), done
else
return head, false
end
@@ -484,12 +505,12 @@ local function makedestination(width,height,depth,reference)
end
for n=1,#name do
local rule = hpack_list(colorize(width,height,depth,3,reference,"destination"))
- rule.width = 0
+ setfield(rule,"width",0)
if not result then
result, current = rule, rule
else
- current.next = rule
- rule.prev = current
+ setfield(current,"next",rule)
+ setfield(rule,"prev",current)
current = rule
end
width, height = width - step, height - step
@@ -499,12 +520,12 @@ local function makedestination(width,height,depth,reference)
for n=1,#name do
local annot = nodeinjections.destination(width,height,depth,name[n],view)
if annot then
- -- probably duplicate
+annot = tonut(annot) -- obsolete soon
if not result then
result = annot
else
- current.next = annot
- annot.prev = current
+ setfield(current,"next",annot)
+ setfield(annot,"prev",current)
end
current = find_node_tail(annot)
end
@@ -512,7 +533,9 @@ local function makedestination(width,height,depth,reference)
if result then
-- some internal error
result = hpack_list(result,0)
- result.width, result.height, result.depth = 0, 0, 0
+ setfield(result,"width",0)
+ setfield(result,"height",0)
+ setfield(result,"depth",0)
end
if cleanupdestinations then stack[reference] = nil end
return result, resolved
@@ -521,14 +544,25 @@ local function makedestination(width,height,depth,reference)
end
end
+-- function nodes.destinations.handler(head)
+-- if topofstack > 0 then
+-- return inject_area(head,attribute,makedestination,stack,done) -- singular
+-- else
+-- return head, false
+-- end
+-- end
+
function nodes.destinations.handler(head)
if topofstack > 0 then
- return inject_area(head,attribute,makedestination,stack,done) -- singular
+ head = tonut(head)
+ local head, done = inject_areas(head,attribute,makedestination,stack,done)
+ return tonode(head), done
else
return head, false
end
end
+
-- will move
function references.mark(reference,h,d,view)
diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua
index ca9d67f91..709532d76 100644
--- a/tex/context/base/node-res.lua
+++ b/tex/context/base/node-res.lua
@@ -18,13 +18,8 @@ local report_nodes = logs.reporter("nodes","housekeeping")
local nodes, node = nodes, node
-local copy_node = node.copy
-local free_node = node.free
-local free_list = node.flush_list
-local new_node = node.new
-
nodes.pool = nodes.pool or { }
-local pool = nodes.pool
+local nodepool = nodes.pool
local whatsitcodes = nodes.whatsitcodes
local skipcodes = nodes.skipcodes
@@ -35,400 +30,454 @@ local glyph_code = nodecodes.glyph
local allocate = utilities.storage.allocate
-local texgetbox = tex.getbox
local texgetcount = tex.getcount
local reserved, nofreserved = { }, 0
-local function register_node(n)
- nofreserved = nofreserved + 1
- reserved[nofreserved] = n
- return n
-end
+-- user nodes
-pool.register = register_node
+local userids = allocate()
+local lastid = 0
-function pool.cleanup(nofboxes) -- todo
- if nodes.tracers.steppers then -- to be resolved
- nodes.tracers.steppers.reset() -- todo: make a registration subsystem
- end
- local nl, nr = 0, nofreserved
- for i=1,nofreserved do
- local ri = reserved[i]
- -- if not (ri.id == glue_spec and not ri.is_writable) then
- free_node(reserved[i])
- -- end
+setmetatable(userids, {
+ __index = function(t,k)
+ if type(k) == "string" then
+ lastid = lastid + 1
+ rawset(userids,lastid,k)
+ rawset(userids,k,lastid)
+ return lastid
+ else
+ rawset(userids,k,k)
+ return k
+ end
+ end,
+ __call = function(t,k)
+ return t[k]
end
- if nofboxes then
- for i=0,nofboxes do
- local l = texgetbox(i)
- if l then
- free_node(l) -- also list ?
- nl = nl + 1
- end
+} )
+
+-- nuts overload
+
+local nuts = nodes.nuts
+local nutpool = { }
+nuts.pool = nutpool
+
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getbox = nuts.getbox
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getid = nuts.getid
+
+local copy_nut = nuts.copy
+local new_nut = nuts.new
+local free_nut = nuts.free
+
+-- at some point we could have a dual set (the overhead of tonut is not much larger than
+-- metatable associations at the lua/c end esp if we also take assignments into account
+
+-- table.setmetatableindex(nodepool,function(t,k,v)
+-- -- report_nodes("defining nodepool[%s] instance",k)
+-- local f = nutpool[k]
+-- local v = function(...)
+-- return tonode(f(...))
+-- end
+-- t[k] = v
+-- return v
+-- end)
+--
+-- -- we delay one step because that permits us a forward reference
+-- -- e.g. in pdfsetmatrix
+
+table.setmetatableindex(nodepool,function(t,k,v)
+ -- report_nodes("defining nodepool[%s] instance",k)
+ local v = function(...)
+ local f = nutpool[k]
+ local v = function(...)
+ return tonode(f(...))
end
+ t[k] = v
+ return v(...)
end
- reserved = { }
- nofreserved = 0
- return nr, nl, nofboxes -- can be nil
+ t[k] = v
+ return v
+end)
+
+local function register_nut(n)
+ nofreserved = nofreserved + 1
+ reserved[nofreserved] = n
+ return n
end
-function pool.usage()
- local t = { }
- for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
- t[tag] = n
+local function register_node(n)
+ nofreserved = nofreserved + 1
+ if type(n) == "number" then -- isnut(n)
+ reserved[nofreserved] = n
+ else
+ reserved[nofreserved] = tonut(n)
end
- return t
+ return n
end
-local disc = register_node(new_node("disc"))
-local kern = register_node(new_node("kern",kerncodes.userkern))
-local fontkern = register_node(new_node("kern",kerncodes.fontkern))
-local penalty = register_node(new_node("penalty"))
-local glue = register_node(new_node("glue")) -- glue.spec = nil
-local glue_spec = register_node(new_node("glue_spec"))
-local glyph = register_node(new_node("glyph",0))
-local textdir = register_node(new_node("whatsit",whatsitcodes.dir))
-local latelua = register_node(new_node("whatsit",whatsitcodes.latelua))
-local special = register_node(new_node("whatsit",whatsitcodes.special))
-local user_n = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_n.type = 100 -- 44
-local user_l = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_l.type = 110 -- 44
-local user_s = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_s.type = 115 -- 44
-local user_t = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_t.type = 116 -- 44
-local left_margin_kern = register_node(new_node("margin_kern",0))
-local right_margin_kern = register_node(new_node("margin_kern",1))
-local lineskip = register_node(new_node("glue",skipcodes.lineskip))
-local baselineskip = register_node(new_node("glue",skipcodes.baselineskip))
-local leftskip = register_node(new_node("glue",skipcodes.leftskip))
-local rightskip = register_node(new_node("glue",skipcodes.rightskip))
-local temp = register_node(new_node("temp",0))
-local noad = register_node(new_node("noad"))
+nodepool.userids = userids
+nodepool.register = register_node
+
+nutpool.userids = userids
+nutpool.register = register_node -- could be register_nut
+
+-- so far
+
+local disc = register_nut(new_nut("disc"))
+local kern = register_nut(new_nut("kern",kerncodes.userkern))
+local fontkern = register_nut(new_nut("kern",kerncodes.fontkern))
+local penalty = register_nut(new_nut("penalty"))
+local glue = register_nut(new_nut("glue")) -- glue.spec = nil
+local glue_spec = register_nut(new_nut("glue_spec"))
+local glyph = register_nut(new_nut("glyph",0))
+local textdir = register_nut(new_nut("whatsit",whatsitcodes.dir))
+local latelua = register_nut(new_nut("whatsit",whatsitcodes.latelua))
+local special = register_nut(new_nut("whatsit",whatsitcodes.special))
+local user_n = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_n,"type",100) -- 44
+local user_l = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_l,"type",110) -- 44
+local user_s = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_s,"type",115) -- 44
+local user_t = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_t,"type",116) -- 44
+local left_margin_kern = register_nut(new_nut("margin_kern",0))
+local right_margin_kern = register_nut(new_nut("margin_kern",1))
+local lineskip = register_nut(new_nut("glue",skipcodes.lineskip))
+local baselineskip = register_nut(new_nut("glue",skipcodes.baselineskip))
+local leftskip = register_nut(new_nut("glue",skipcodes.leftskip))
+local rightskip = register_nut(new_nut("glue",skipcodes.rightskip))
+local temp = register_nut(new_nut("temp",0))
+local noad = register_nut(new_nut("noad"))
-- the dir field needs to be set otherwise crash:
-local rule = register_node(new_node("rule")) rule .dir = "TLT"
-local hlist = register_node(new_node("hlist")) hlist.dir = "TLT"
-local vlist = register_node(new_node("vlist")) vlist.dir = "TLT"
-
-function pool.zeroglue(n)
- local s = n.spec
- return not writable or (
- s.width == 0
- and s.stretch == 0
- and s.shrink == 0
- and s.stretch_order == 0
- and s.shrink_order == 0
- )
-end
-
-function pool.glyph(fnt,chr)
- local n = copy_node(glyph)
- if fnt then n.font = fnt end
- if chr then n.char = chr end
+local rule = register_nut(new_nut("rule")) setfield(rule, "dir","TLT")
+local hlist = register_nut(new_nut("hlist")) setfield(hlist,"dir","TLT")
+local vlist = register_nut(new_nut("vlist")) setfield(vlist,"dir","TLT")
+
+function nutpool.zeroglue(n)
+ local s = getfield(n,"spec")
+ return not writable or ( -- still valid? writable
+ getfield(s,"width") == 0
+ and getfield(s,"stretch") == 0
+ and getfield(s,"shrink") == 0
+ and getfield(s,"stretch_order") == 0
+ and getfield(s,"shrink_order") == 0
+ )
+end
+
+function nutpool.glyph(fnt,chr)
+ local n = copy_nut(glyph)
+ if fnt then setfield(n,"font",fnt) end
+ if chr then setfield(n,"char",chr) end
return n
end
-function pool.penalty(p)
- local n = copy_node(penalty)
- n.penalty = p
+function nutpool.penalty(p)
+ local n = copy_nut(penalty)
+ setfield(n,"penalty",p)
return n
end
-function pool.kern(k)
- local n = copy_node(kern)
- n.kern = k
+function nutpool.kern(k)
+ local n = copy_nut(kern)
+ setfield(n,"kern",k)
return n
end
-function pool.fontkern(k)
- local n = copy_node(fontkern)
- n.kern = k
+function nutpool.fontkern(k)
+ local n = copy_nut(fontkern)
+ setfield(n,"kern",k)
return n
end
-function pool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
- local s = copy_node(glue_spec)
- if width then s.width = width end
- if stretch then s.stretch = stretch end
- if shrink then s.shrink = shrink end
- if stretch_order then s.stretch_order = stretch_order end
- if shrink_order then s.shrink_order = shrink_order end
+function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
+ local s = copy_nut(glue_spec)
+ if width then setfield(s,"width",width) end
+ if stretch then setfield(s,"stretch",stretch) end
+ if shrink then setfield(s,"shrink",shrink) end
+ if stretch_order then setfield(s,"stretch_order",stretch_order) end
+ if shrink_order then setfield(s,"shrink_order",shrink_order) end
return s
end
local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order)
- local n = copy_node(skip)
+ local n = copy_nut(skip)
if not width then
-- no spec
elseif width == false or tonumber(width) then
- local s = copy_node(glue_spec)
- if width then s.width = width end
- if stretch then s.stretch = stretch end
- if shrink then s.shrink = shrink end
- if stretch_order then s.stretch_order = stretch_order end
- if shrink_order then s.shrink_order = shrink_order end
- n.spec = s
+ local s = copy_nut(glue_spec)
+ if width then setfield(s,"width",width) end
+ if stretch then setfield(s,"stretch",stretch) end
+ if shrink then setfield(s,"shrink",shrink) end
+ if stretch_order then setfield(s,"stretch_order",stretch_order) end
+ if shrink_order then setfield(s,"shrink_order",shrink_order) end
+ setfield(n,"spec",s)
else
-- shared
- n.spec = copy_node(width)
+ setfield(n,"spec",copy_nut(width))
end
return n
end
-function pool.stretch(a,b)
- local n = copy_node(glue)
- local s = copy_node(glue_spec)
+function nutpool.stretch(a,b)
+ local n = copy_nut(glue)
+ local s = copy_nut(glue_spec)
if b then
- s.stretch = a
- s.stretch_order = b
+ setfield(s,"stretch",a)
+ setfield(s,"stretch_order",b)
else
- s.stretch = 1
- s.stretch_order = a or 1
+ setfield(s,"stretch",1)
+ setfield(s,"stretch_order",a or 1)
end
- n.spec = s
+ setfield(n,"spec",s)
return n
end
-function pool.shrink(a,b)
- local n = copy_node(glue)
- local s = copy_node(glue_spec)
+function nutpool.shrink(a,b)
+ local n = copy_nut(glue)
+ local s = copy_nut(glue_spec)
if b then
- s.shrink = a
- s.shrink_order = b
+ setfield(s,"shrink",a)
+ setfield(s,"shrink_order",b)
else
- s.shrink = 1
- s.shrink_order = a or 1
+ setfield(s,"shrink",1)
+ setfield(s,"shrink_order",a or 1)
end
- n.spec = s
+ setfield(n,"spec",s)
return n
end
-
-function pool.glue(width,stretch,shrink,stretch_order,shrink_order)
+function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order)
return someskip(glue,width,stretch,shrink,stretch_order,shrink_order)
end
-function pool.leftskip(width,stretch,shrink,stretch_order,shrink_order)
+function nutpool.leftskip(width,stretch,shrink,stretch_order,shrink_order)
return someskip(leftskip,width,stretch,shrink,stretch_order,shrink_order)
end
-function pool.rightskip(width,stretch,shrink,stretch_order,shrink_order)
+function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order)
return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order)
end
-function pool.lineskip(width,stretch,shrink,stretch_order,shrink_order)
+function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order)
return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order)
end
-function pool.baselineskip(width,stretch,shrink)
+function nutpool.baselineskip(width,stretch,shrink)
return someskip(baselineskip,width,stretch,shrink)
end
-function pool.disc()
- return copy_node(disc)
+function nutpool.disc()
+ return copy_nut(disc)
end
-function pool.textdir(dir)
- local t = copy_node(textdir)
- t.dir = dir
+function nutpool.textdir(dir)
+ local t = copy_nut(textdir)
+ setfield(t,"dir",dir)
return t
end
-function pool.rule(width,height,depth,dir) -- w/h/d == nil will let them adapt
- local n = copy_node(rule)
- if width then n.width = width end
- if height then n.height = height end
- if depth then n.depth = depth end
- if dir then n.dir = dir end
+function nutpool.rule(width,height,depth,dir) -- w/h/d == nil will let them adapt
+ local n = copy_nut(rule)
+ if width then setfield(n,"width",width) end
+ if height then setfield(n,"height",height) end
+ if depth then setfield(n,"depth",depth) end
+ if dir then setfield(n,"dir",dir) end
return n
end
-if node.has_field(latelua,'string') then
- function pool.latelua(code)
- local n = copy_node(latelua)
- n.string = code
+-- if node.has_field(latelua,'string') then
+ function nutpool.latelua(code)
+ local n = copy_nut(latelua)
+ setfield(n,"string",code)
return n
end
-else
- function pool.latelua(code)
- local n = copy_node(latelua)
- n.data = code
- return n
- end
-end
-
-function pool.leftmarginkern(glyph,width)
- local n = copy_node(left_margin_kern)
+-- else
+-- function nutpool.latelua(code)
+-- local n = copy_nut(latelua)
+-- setfield(n,"data",code)
+-- return n
+-- end
+-- end
+
+function nutpool.leftmarginkern(glyph,width)
+ local n = copy_nut(left_margin_kern)
if not glyph then
report_nodes("invalid pointer to left margin glyph node")
- elseif glyph.id ~= glyph_code then
+ elseif getid(glyph) ~= glyph_code then
report_nodes("invalid node type %a for %s margin glyph node",nodecodes[glyph],"left")
else
- n.glyph = glyph
+ setfield(n,"glyph",glyph)
end
if width then
- n.width = width
+ setfield(n,"width",width)
end
return n
end
-function pool.rightmarginkern(glyph,width)
- local n = copy_node(right_margin_kern)
+function nutpool.rightmarginkern(glyph,width)
+ local n = copy_nut(right_margin_kern)
if not glyph then
report_nodes("invalid pointer to right margin glyph node")
- elseif glyph.id ~= glyph_code then
+ elseif getid(glyph) ~= glyph_code then
report_nodes("invalid node type %a for %s margin glyph node",nodecodes[p],"right")
else
- n.glyph = glyph
+ setfield(n,"glyph",glyph)
end
if width then
- n.width = width
+ setfield(n,"width",width)
end
return n
end
-function pool.temp()
- return copy_node(temp)
+function nutpool.temp()
+ return copy_nut(temp)
end
-function pool.noad()
- return copy_node(noad)
+function nutpool.noad()
+ return copy_nut(noad)
end
-function pool.hlist(list,width,height,depth)
- local n = copy_node(hlist)
+function nutpool.hlist(list,width,height,depth)
+ local n = copy_nut(hlist)
if list then
- n.list = list
+ setfield(n,"list",list)
end
if width then
- n.width = width
+ setfield(n,"width",width)
end
if height then
- n.height = height
+ setfield(n,"height",height)
end
if depth then
- n.depth = depth
+ setfield(n,"depth",depth)
end
return n
end
-function pool.vlist(list,width,height,depth)
- local n = copy_node(vlist)
+function nutpool.vlist(list,width,height,depth)
+ local n = copy_nut(vlist)
if list then
- n.list = list
+ setfield(n,"list",list)
end
if width then
- n.width = width
+ setfield(n,"width",width)
end
if height then
- n.height = height
+ setfield(n,"height",height)
end
if depth then
- n.depth = depth
+ setfield(n,"depth",depth)
end
return n
end
---[[
-<p>At some point we ran into a problem that the glue specification
-of the zeropoint dimension was overwritten when adapting a glue spec
-node. This is a side effect of glue specs being shared. After a
-couple of hours tracing and debugging Taco and I came to the
-conclusion that it made no sense to complicate the spec allocator
-and settled on a writable flag. This all is a side effect of the
-fact that some glues use reserved memory slots (with the zeropoint
-glue being a noticeable one). So, next we wrap this into a function
-and hide it for the user. And yes, LuaTeX now gives a warning as
-well.</p>
-]]--
-
-function nodes.writable_spec(n) -- not pool
- local spec = n.spec
- if not spec then
- spec = copy_node(glue_spec)
- n.spec = spec
- elseif not spec.writable then
- spec = copy_node(spec)
- n.spec = spec
- end
- return spec
-end
-
-- local num = userids["my id"]
-- local str = userids[num]
-local userids = allocate() pool.userids = userids
-local lastid = 0
-
-setmetatable(userids, {
- __index = function(t,k)
- if type(k) == "string" then
- lastid = lastid + 1
- rawset(userids,lastid,k)
- rawset(userids,k,lastid)
- return lastid
- else
- rawset(userids,k,k)
- return k
- end
- end,
- __call = function(t,k)
- return t[k]
- end
-} )
-
-function pool.usernumber(id,num)
- local n = copy_node(user_n)
+function nutpool.usernumber(id,num)
+ local n = copy_nut(user_n)
if num then
- n.user_id, n.value = id, num
+ setfield(n,"user_id",id)
+ setfield(n,"value",num)
elseif id then
- n.value = id
+ setfield(n,"value",id)
end
return n
end
-function pool.userlist(id,list)
- local n = copy_node(user_l)
+function nutpool.userlist(id,list)
+ local n = copy_nut(user_l)
if list then
- n.user_id, n.value = id, list
+ setfield(n,"user_id",id)
+ setfield(n,"value",list)
else
- n.value = id
+ setfield(n,"value",id)
end
return n
end
-function pool.userstring(id,str)
- local n = copy_node(user_s)
+function nutpool.userstring(id,str)
+ local n = copy_nut(user_s)
if str then
- n.user_id, n.value = id, str
+ setfield(n,"user_id",id)
+ setfield(n,"value",str)
else
- n.value = id
+ setfield(n,"value",id)
end
return n
end
-function pool.usertokens(id,tokens)
- local n = copy_node(user_t)
+function nutpool.usertokens(id,tokens)
+ local n = copy_nut(user_t)
if tokens then
- n.user_id, n.value = id, tokens
+ setfield(n,"user_id",id)
+ setfield(n,"value",tokens)
else
- n.value = id
+ setfield(n,"value",id)
end
return n
end
-function pool.special(str)
- local n = copy_node(special)
- n.data = str
+function nutpool.special(str)
+ local n = copy_nut(special)
+ setfield(n,"data",str)
return n
end
+-- housekeeping
+
+local function cleanup(nofboxes) -- todo
+ if nodes.tracers.steppers then -- to be resolved
+ nodes.tracers.steppers.reset() -- todo: make a registration subsystem
+ end
+ local nl, nr = 0, nofreserved
+ for i=1,nofreserved do
+ local ri = reserved[i]
+ -- if not (getid(ri) == glue_spec and not getfield(ri,"is_writable")) then
+ free_nut(reserved[i])
+ -- end
+ end
+ if nofboxes then
+ for i=0,nofboxes do
+ local l = getbox(i)
+ if l then
+ free_nut(l) -- also list ?
+ nl = nl + 1
+ end
+ end
+ end
+ reserved = { }
+ nofreserved = 0
+ return nr, nl, nofboxes -- can be nil
+end
+
+
+local function usage()
+ local t = { }
+ for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
+ t[tag] = n
+ end
+ return t
+end
+
+nutpool .cleanup = cleanup
+nodepool.cleanup = cleanup
+
+nutpool .usage = usage
+nodepool.usage = usage
+
+-- end
+
statistics.register("cleaned up reserved nodes", function()
- return format("%s nodes, %s lists of %s", pool.cleanup(texgetcount("c_syst_last_allocated_box")))
+ return format("%s nodes, %s lists of %s", cleanup(texgetcount("c_syst_last_allocated_box")))
end) -- \topofboxstack
statistics.register("node memory usage", function() -- comes after cleanup !
return status.node_mem_usage
end)
-lua.registerfinalizer(pool.cleanup, "cleanup reserved nodes")
+lua.registerfinalizer(cleanup, "cleanup reserved nodes")
diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua
index 96d6bdf41..6f3bc9df9 100644
--- a/tex/context/base/node-rul.lua
+++ b/tex/context/base/node-rul.lua
@@ -13,12 +13,28 @@ if not modules then modules = { } end modules ['node-rul'] = {
local attributes, nodes, node = attributes, nodes, node
-local nodecodes = nodes.nodecodes
-local tasks = nodes.tasks
-
-local glyph_code = nodecodes.glyph
-local disc_code = nodecodes.disc
-local rule_code = nodecodes.rule
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getlist = nuts.getlist
+
+local nodecodes = nodes.nodecodes
+local tasks = nodes.tasks
+
+local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
+local rule_code = nodecodes.rule
function nodes.striprange(first,last) -- todo: dir
if first and last then -- just to be sure
@@ -26,11 +42,11 @@ function nodes.striprange(first,last) -- todo: dir
return first, last
end
while first and first ~= last do
- local id = first.id
+ local id = getid(first)
if id == glyph_code or id == disc_code then -- or id == rule_code
break
else
- first = first.next
+ first = getnext(first)
end
end
if not first then
@@ -39,13 +55,13 @@ function nodes.striprange(first,last) -- todo: dir
return first, last
end
while last and last ~= first do
- local id = last.id
+ local id = getid(last)
if id == glyph_code or id == disc_code then -- or id == rule_code
break
else
- local prev = last.prev -- luatex < 0.70 has italic correction kern not prev'd
+ local prev = getprev(last) -- luatex < 0.70 has italic correction kern not prev'd
if prev then
- last = last.prev
+ last = prev
else
break
end
@@ -73,12 +89,12 @@ local a_color = attributes.private('color')
local a_transparency = attributes.private('transparency')
local a_colorspace = attributes.private('colormodel')
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local striprange = nodes.striprange
-local list_dimensions = node.dimensions
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local list_dimensions = nuts.dimensions
+local hpack_nodes = nuts.hpack
-local hpack_nodes = node.hpack
+local striprange = nodes.striprange
local fontdata = fonts.hashes.identifiers
local variables = interfaces.variables
@@ -111,7 +127,7 @@ local dir_code = whatcodes.dir
local kerning_code = kerncodes.kern
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_rule = nodepool.rule
local new_kern = nodepool.kern
@@ -141,9 +157,9 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
local f, l, a, d, i, class
local continue, done, strip, level = false, false, true, -1
while n do
- local id = n.id
+ local id = getid(n)
if id == glyph_code or id == rule_code then
- local aa = n[attribute]
+ local aa = getattr(n,attribute)
if aa then
if aa == a then
if not f then -- ?
@@ -172,13 +188,13 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
end
f, l, a = nil, nil, nil
end
--- elseif f and (id == disc_code or (id == kern_code and n.subtype == kerning_code)) then
+-- elseif f and (id == disc_code or (id == kern_code and getsubtype(n) == kerning_code)) then
-- l = n
elseif id == disc_code then
if f then
l = n
end
- elseif id == kern_code and n.subtype == kerning_code then
+ elseif id == kern_code and getsubtype(n) == kerning_code then
if f then
l = n
end
@@ -187,11 +203,11 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
head, done = flush(head,f,l,d,level,parent,strip), true
f, l, a = nil, nil, nil
end
- local list = n.list
+ local list = getlist(n)
if list then
- n.list = processwords(attribute,data,flush,list,n)
+ setfield(n,"list",(processwords(attribute,data,flush,list,n))) -- watch ()
end
- elseif checkdir and id == whatsit_code and n.subtype == dir_code then -- only changes in dir, we assume proper boundaries
+ elseif checkdir and id == whatsit_code and getsubtype(n) == dir_code then -- only changes in dir, we assume proper boundaries
if f and a then
l = n
end
@@ -203,8 +219,8 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
-- l = n
elseif id == glue_code then
-- catch \underbar{a} \underbar{a} (subtype test is needed)
- local subtype = n.subtype
- if n[attribute] and (subtype == userskip_code or subtype == spaceskip_code or subtype == xspaceskip_code) then
+ local subtype = getsubtype(n)
+ if getattr(n,attribute) and (subtype == userskip_code or subtype == spaceskip_code or subtype == xspaceskip_code) then
l = n
else
head, done = flush(head,f,l,d,level,parent,strip), true
@@ -216,7 +232,7 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
f, l, a = nil, nil, nil
end
end
- n = n.next
+ n = getnext(n)
end
if f then
head, done = flush(head,f,l,d,level,parent,strip), true
@@ -227,7 +243,16 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi
end
end
-nodes.processwords = processwords
+-- nodes.processwords = processwords
+
+nodes.processwords = function(attribute,data,flush,head,parent) -- we have hlistdir and local dir
+ head = tonut(head)
+ if parent then
+ parent = tonut(parent)
+ end
+ local head, done = processwords(attribute,data,flush,head,parent)
+ return tonode(head), done
+end
--
@@ -246,7 +271,7 @@ end
local a_viewerlayer = attributes.private("viewerlayer")
local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose
- if f.id ~= glyph_code then
+ if getid(f) ~= glyph_code then
-- saveguard ... we need to deal with rules and so (math)
return head
end
@@ -264,16 +289,16 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
if not f then
return head
end
- local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next)
+ local w = list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),f,getnext(l))
local method, offset, continue, dy, order, max = d.method, d.offset, d.continue, d.dy, d.order, d.max
local rulethickness, unit = d.rulethickness, d.unit
local ma, ca, ta = d.ma, d.ca, d.ta
- local colorspace = ma > 0 and ma or f[a_colorspace] or 1
- local color = ca > 0 and ca or f[a_color]
- local transparency = ta > 0 and ta or f[a_transparency]
+ local colorspace = ma > 0 and ma or getattr(f,a_colorspace) or 1
+ local color = ca > 0 and ca or getattr(f,a_color)
+ local transparency = ta > 0 and ta or getattr(f,a_transparency)
local foreground = order == v_foreground
- local e = dimenfactor(unit,f.font) -- what if no glyph node
+ local e = dimenfactor(unit,getfont(f)) -- what if no glyph node
local rt = tonumber(rulethickness)
if rt then
@@ -281,7 +306,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
else
local n, u = splitdimen(rulethickness)
if n and u then -- we need to intercept ex and em and % and ...
- rulethickness = n * dimenfactor(u,fontdata[f.font]) / 2
+ rulethickness = n * dimenfactor(u,fontdata[getfont(f)]) / 2
else
rulethickness = 1/5
end
@@ -300,18 +325,18 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
local ht = (offset+(i-1)*dy)*e + rulethickness - m
local dp = -(offset+(i-1)*dy)*e + rulethickness + m
local r = new_rule(w,ht,dp)
- local v = f[a_viewerlayer]
+ local v = getattr(f,a_viewerlayer)
-- quick hack
if v then
- r[a_viewerlayer] = v
+ setattr(r,a_viewerlayer,v)
end
--
if color then
- r[a_colorspace] = colorspace
- r[a_color] = color
+ setattr(r,a_colorspace,colorspace)
+ setattr(r,a_color,color)
end
if transparency then
- r[a_transparency] = transparency
+ setattr(r,a_transparency,transparency)
end
local k = new_kern(-w)
if foreground then
@@ -365,21 +390,27 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha
if true then
first, last = striprange(first,last)
end
- local prev, next = first.prev, last.next
- first.prev, last.next = nil, nil
- local width, height, depth = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,first,next)
+ local prev = getprev(first)
+ local next = getnext(last)
+ setfield(first,"prev",nil)
+ setfield(last,"next",nil)
+ local width, height, depth = list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),first,next)
local list = hpack_nodes(first,width,"exactly")
if first == head then
head = list
end
if prev then
- prev.next, list.prev = list, prev
+ setfield(prev,"next",list)
+ setfield(list,"prev",prev)
end
if next then
- next.prev, list.next = list, next
+ setfield(next,"prev",list)
+ setfield(list,"next",next)
end
- local raise = data.dy * dimenfactor(data.unit,fontdata[first.font])
- list.shift, list.height, list.depth = raise, height, depth
+ local raise = data.dy * dimenfactor(data.unit,fontdata[getfont(first)])
+ setfield(list,"shift",raise)
+ setfield(list,"height",height)
+ setfield(list,"depth",depth)
if trace_shifted then
report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true))
end
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
index 9617f7476..89c3e52f9 100644
--- a/tex/context/base/node-tra.lua
+++ b/tex/context/base/node-tra.lua
@@ -34,9 +34,30 @@ nodes.handlers = handlers
local injections = nodes.injections or { }
nodes.injections = injections
-local traverse_nodes = node.traverse
-local traverse_by_id = node.traverse_id
-local count_nodes = nodes.count
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getchar = nuts.getchar
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+
+local setattr = nuts.setattr
+
+local flush_list = nuts.flush_list
+local count_nodes = nuts.count
+local used_nodes = nuts.usedlist
+
+local traverse_by_id = nuts.traverse_id
+local traverse_nodes = nuts.traverse
+local d_tostring = nuts.tostring
+
+local nutpool = nuts.pool
+local new_rule = nutpool.rule
local nodecodes = nodes.nodecodes
local whatcodes = nodes.whatcodes
@@ -56,9 +77,6 @@ local gluespec_code = nodecodes.gluespec
local localpar_code = whatcodes.localpar
local dir_code = whatcodes.dir
-local nodepool = nodes.pool
-local new_rule = nodepool.rule
-
local dimenfactors = number.dimenfactors
local formatters = string.formatters
@@ -68,15 +86,16 @@ function nodes.showlist(head, message)
if message then
report_nodes(message)
end
- for n in traverse_nodes(head) do
- report_nodes(tostring(n))
+ for n in traverse_nodes(tonut(head)) do
+ report_nodes(d_tostring(n))
end
end
function nodes.handlers.checkglyphs(head,message)
+ local h = tonut(head)
local t = { }
- for g in traverse_by_id(glyph_code,head) do
- t[#t+1] = formatters["%U:%s"](g.char,g.subtype)
+ for g in traverse_by_id(glyph_code,h) do
+ t[#t+1] = formatters["%U:%s"](getchar(g),getsubtype(g))
end
if #t > 0 then
if message and message ~= "" then
@@ -90,12 +109,12 @@ end
function nodes.handlers.checkforleaks(sparse)
local l = { }
- local q = node.usedlist()
- for p in traverse(q) do
- local s = table.serialize(nodes.astable(p,sparse),nodecodes[p.id])
+ local q = used_nodes()
+ for p in traverse_nodes(q) do
+ local s = table.serialize(nodes.astable(p,sparse),nodecodes[getid(p)])
l[s] = (l[s] or 0) + 1
end
- node.flush_list(q)
+ flush_list(q)
for k, v in next, l do
report_nodes("%s * %s",v,k)
end
@@ -105,39 +124,40 @@ local f_sequence = formatters["U+%04X:%s"]
local function tosequence(start,stop,compact)
if start then
+ start = tonut(start)
+ stop = stop and tonut(stop)
local t = { }
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- local c = start.char
+ local c = getchar(start)
if compact then
- if start.components then
- t[#t+1] = tosequence(start.components,nil,compact)
+ local components = getfield(start,"components")
+ if components then
+ t[#t+1] = tosequence(components,nil,compact)
else
t[#t+1] = utfchar(c)
end
else
t[#t+1] = f_sequence(c,utfchar(c))
end
- elseif id == whatsit_code and start.subtype == localpar_code or start.subtype == dir_code then
- t[#t+1] = "[" .. start.dir .. "]"
elseif id == rule_code then
if compact then
t[#t+1] = "|"
else
t[#t+1] = nodecodes[id]
end
+ elseif id == whatsit_code and getsubtype(start) == localpar_code or getsubtype(start) == dir_code then
+ t[#t+1] = "[" .. getfield(start,"dir") .. "]"
+ elseif compact then
+ t[#t+1] = "[]"
else
- if compact then
- t[#t+1] = "[]"
- else
- t[#t+1] = nodecodes[id]
- end
+ t[#t+1] = nodecodes[id]
end
if start == stop then
break
else
- start = start.next
+ start = getnext(start)
end
end
if compact then
@@ -153,21 +173,23 @@ end
nodes.tosequence = tosequence
function nodes.report(t,done)
- report_nodes("output %a, %changed %a, %s nodes",status.output_active,done,count_nodes(t))
+ report_nodes("output %a, %changed %a, %s nodes",status.output_active,done,count_nodes(tonut(t)))
end
function nodes.packlist(head)
local t = { }
- for n in traverse(head) do
- t[#t+1] = tostring(n)
+ for n in traverse_nodes(tonut(head)) do
+ t[#t+1] = d_tostring(n)
end
return t
end
function nodes.idstostring(head,tail)
+ head = tonut(head)
+ tail = tail and tonut(tail)
local t, last_id, last_n = { }, nil, 0
for n in traverse_nodes(head,tail) do -- hm, does not stop at tail
- local id = n.id
+ local id = getid(n)
if not last_id then
last_id, last_n = id, 1
elseif last_id == id then
@@ -195,6 +217,8 @@ function nodes.idstostring(head,tail)
end
-- function nodes.xidstostring(head,tail) -- only for special tracing of backlinks
+-- head = tonut(head)
+-- tail = tonut(tail)
-- local n = head
-- while n.next do
-- n = n.next
@@ -217,7 +241,7 @@ end
-- if n == head then
-- break
-- end
--- n = n.prev
+-- n = getprev(n)
-- end
-- if not last_id then
-- t[#t+1] = "no nodes"
@@ -230,51 +254,56 @@ end
-- end
local function showsimplelist(h,depth,n)
+ h = h and tonut(h)
while h do
report_nodes("% w%s",n,d_tostring(h))
if not depth or n < depth then
- local id = h.id
+ local id = getid(h)
if id == hlist_code or id == vlist_code then
- showsimplelist(h.list,depth,n+1)
+ showsimplelist(getlist(h),depth,n+1)
end
end
- h = h.next
+ h = getnext(h)
end
end
---~ \startluacode
---~ callback.register('buildpage_filter',function() nodes.show_simple_list(tex.lists.contrib_head) end)
---~ \stopluacode
---~ \vbox{b\footnote{n}a}
---~ \startluacode
---~ callback.register('buildpage_filter',nil)
---~ \stopluacode
+-- \startluacode
+-- callback.register('buildpage_filter',function() nodes.show_simple_list(tex.lists.contrib_head) end)
+-- \stopluacode
+-- \vbox{b\footnote{n}a}
+-- \startluacode
+-- callback.register('buildpage_filter',nil)
+-- \stopluacode
nodes.showsimplelist = function(h,depth) showsimplelist(h,depth,0) end
local function listtoutf(h,joiner,textonly,last)
- local joiner = (joiner == true and utfchar(0x200C)) or joiner -- zwnj
local w = { }
while h do
- local id = h.id
+ local id = getid(h)
if id == glyph_code then -- always true
- local c = h.char
+ local c = getchar(h)
w[#w+1] = c >= 0 and utfchar(c) or formatters["<%i>"](c)
if joiner then
w[#w+1] = joiner
end
elseif id == disc_code then
- local pre = h.pre
- local pos = h.post
- local rep = h.replace
+ local pre = getfield(h,"pre")
+ local pos = getfield(h,"post")
+ local rep = getfield(h,"replace")
w[#w+1] = formatters["[%s|%s|%s]"] (
pre and listtoutf(pre,joiner,textonly) or "",
pos and listtoutf(pos,joiner,textonly) or "",
rep and listtoutf(rep,joiner,textonly) or ""
)
elseif textonly then
- if id == glue_code and h.spec and h.spec.width > 0 then
- w[#w+1] = " "
+ if id == glue_code then
+ local spec = getfield(h,"spec")
+ if spec and getfield(spec,"width") > 0 then
+ w[#w+1] = " "
+ end
+ elseif id == hlist_code or id == vlist_code then
+ w[#w+1] = "[]"
end
else
w[#w+1] = "[-]"
@@ -282,24 +311,28 @@ local function listtoutf(h,joiner,textonly,last)
if h == last then
break
else
- h = h.next
+ h = getnext(h)
end
end
return concat(w)
end
-nodes.listtoutf = listtoutf
+function nodes.listtoutf(h,joiner,textonly,last)
+ local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
+ return listtoutf(tonut(h),joiner,textonly,last and tonut(last))
+end
local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" }
local function showboxes(n,symbol,depth)
- depth, symbol = depth or 0, symbol or "."
- for n in traverse_nodes(n) do
- local id = n.id
+ depth = depth or 0
+ symbol = symbol or "."
+ for n in traverse_nodes(tonut(n)) do
+ local id = getid(n)
if id == hlist_code or id == vlist_code then
- local s = n.subtype
+ local s = getsubtype(n)
report_nodes(rep(symbol,depth) .. what[s] or s)
- showboxes(n.list,symbol,depth+1)
+ showboxes(getlist(n),symbol,depth+1)
end
end
end
@@ -322,15 +355,8 @@ local stripper = lpeg.patterns.stripzeros
local dimenfactors = number.dimenfactors
-local function numbertodimen(d,unit,fmt,strip)
- if not d then
- local str = formatters[fmt](0,unit)
- return strip and lpegmatch(stripper,str) or str
- end
- local t = type(d)
- if t == 'string' then
- return d
- end
+local function nodetodimen(d,unit,fmt,strip)
+ d = tonut(d) -- tricky: direct nuts are an issue
if unit == true then
unit = "pt"
fmt = "%0.5f%s"
@@ -342,27 +368,23 @@ local function numbertodimen(d,unit,fmt,strip)
fmt = "%0.5f%s"
end
end
- if t == "number" then
- local str = formatters[fmt](d*dimenfactors[unit],unit)
- return strip and lpegmatch(stripper,str) or str
- end
- local id = d.id
+ local id = getid(d)
if id == kern_code then
- local str = formatters[fmt](d.width*dimenfactors[unit],unit)
+ local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
return strip and lpegmatch(stripper,str) or str
end
if id == glue_code then
- d = d.spec
+ d = getfield(d,"spec")
end
- if not d or not d.id == gluespec_code then
+ if not d or not getid(d) == gluespec_code then
local str = formatters[fmt](0,unit)
return strip and lpegmatch(stripper,str) or str
end
- local width = d.width
- local plus = d.stretch_order
- local minus = d.shrink_order
- local stretch = d.stretch
- local shrink = d.shrink
+ local width = getfield(d,"width")
+ local plus = getfield(d,"stretch_order")
+ local minus = getfield(d,"shrink_order")
+ local stretch = getfield(d,"stretch")
+ local shrink = getfield(d,"shrink")
if plus ~= 0 then
plus = " plus " .. stretch/65536 .. fillcodes[plus]
elseif stretch ~= 0 then
@@ -379,11 +401,39 @@ local function numbertodimen(d,unit,fmt,strip)
else
minus = ""
end
- local str = formatters[fmt](d.width*dimenfactors[unit],unit)
+ local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
return (strip and lpegmatch(stripper,str) or str) .. plus .. minus
end
+local function numbertodimen(d,unit,fmt,strip)
+ if not d then
+ local str = formatters[fmt](0,unit)
+ return strip and lpegmatch(stripper,str) or str
+ end
+ local t = type(d)
+ if t == 'string' then
+ return d
+ elseif t == "number" then
+ if unit == true then
+ unit = "pt"
+ fmt = "%0.5f%s"
+ else
+ unit = unit or 'pt'
+ if not fmt then
+ fmt = "%s%s"
+ elseif fmt == true then
+ fmt = "%0.5f%s"
+ end
+ end
+ local str = formatters[fmt](d*dimenfactors[unit],unit)
+ return strip and lpegmatch(stripper,str) or str
+ else
+ return nodetodimen(d,unit,fmt,strip) -- real node
+ end
+end
+
number.todimen = numbertodimen
+nodes .todimen = nodetodimen
function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end
function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end
@@ -398,6 +448,19 @@ function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end
function number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end
function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end
+function nodes.topoints (n,fmt) return nodetodimen(n,"pt",fmt) end
+function nodes.toinches (n,fmt) return nodetodimen(n,"in",fmt) end
+function nodes.tocentimeters (n,fmt) return nodetodimen(n,"cm",fmt) end
+function nodes.tomillimeters (n,fmt) return nodetodimen(n,"mm",fmt) end
+function nodes.toscaledpoints(n,fmt) return nodetodimen(n,"sp",fmt) end
+function nodes.toscaledpoints(n) return n .. "sp" end
+function nodes.tobasepoints (n,fmt) return nodetodimen(n,"bp",fmt) end
+function nodes.topicas (n,fmt) return nodetodimen(n "pc",fmt) end
+function nodes.todidots (n,fmt) return nodetodimen(n,"dd",fmt) end
+function nodes.tociceros (n,fmt) return nodetodimen(n,"cc",fmt) end
+function nodes.tonewdidots (n,fmt) return nodetodimen(n,"nd",fmt) end
+function nodes.tonewciceros (n,fmt) return nodetodimen(n,"nc",fmt) end
+
-- stop redefinition
local points = function(n)
@@ -443,8 +506,13 @@ number.basepoints = basepoints
number.pts = pts
number.nopts = nopts
-local colors = { }
-tracers.colors = colors
+nodes.points = function(n) return numbertodimen(n,"pt",true,true) end
+nodes.basepoints = function(n) return numbertodimen(n,"bp",true,true) end
+nodes.pts = function(n) return numbertodimen(n,"pt",true) end
+nodes.nopts = function(n) return format("%.5f",n*ptfactor) end
+
+local colors = { }
+tracers.colors = colors
local unsetvalue = attributes.unsetvalue
@@ -454,36 +522,34 @@ local m_color = attributes.list[a_color] or { }
function colors.set(n,c,s)
local mc = m_color[c]
- if not mc then
- n[a_color] = unsetvalue
+ local nn = tonut(n)
+ if mc then
+ local mm = s or texgetattribute(a_colormodel)
+ setattr(nn,a_colormodel,mm <= 0 and mm or 1)
+ setattr(nn,a_color,mc)
else
- if not n[a_colormodel] then
- n[a_colormodel] = s or 1
- end
- n[a_color] = mc
+ setattr(nn,a_color,unsetvalue)
end
return n
end
function colors.setlist(n,c,s)
- local f = n
- while n do
- local mc = m_color[c]
- if not mc then
- n[a_color] = unsetvalue
- else
- if not n[a_colormodel] then
- n[a_colormodel] = s or 1
- end
- n[a_color] = mc
- end
- n = n.next
+ local nn = tonut(n)
+ local mc = m_color[c] or unsetvalue
+ local mm = s or texgetattribute(a_colormodel)
+ if mm <= 0 then
+ mm = 1
+ end
+ while nn do
+ setattr(nn,a_colormodel,mm)
+ setattr(nn,a_color,mc)
+ nn = getnext(nn)
end
- return f
+ return n
end
function colors.reset(n)
- n[a_color] = unsetvalue
+ setattr(tonut(n),a_color,unsetvalue)
return n
end
@@ -496,31 +562,22 @@ local a_transparency = attributes.private('transparency')
local m_transparency = attributes.list[a_transparency] or { }
function transparencies.set(n,t)
- local mt = m_transparency[t]
- if not mt then
- n[a_transparency] = unsetvalue
- else
- n[a_transparency] = mt
- end
+ setattr(tonut(n),a_transparency,m_transparency[t] or unsetvalue)
return n
end
function transparencies.setlist(n,c,s)
- local f = n
- while n do
- local mt = m_transparency[c]
- if not mt then
- n[a_transparency] = unsetvalue
- else
- n[a_transparency] = mt
- end
- n = n.next
+ local nn = tonut(n)
+ local mt = m_transparency[c] or unsetvalue
+ while nn do
+ setattr(nn,a_transparency,mt)
+ nn = getnext(nn)
end
- return f
+ return n
end
function transparencies.reset(n)
- n[a_transparency] = unsetvalue
+ setattr(n,a_transparency,unsetvalue)
return n
end
@@ -537,52 +594,62 @@ end
-- although tracers are used seldom
local function setproperties(n,c,s)
+ local nn = tonut(n)
local mm = texgetattribute(a_colormodel)
- n[a_colormodel] = mm > 0 and mm or 1
- n[a_color] = m_color[c]
- n[a_transparency] = m_transparency[c]
+ setattr(nn,a_colormodel,mm > 0 and mm or 1)
+ setattr(nn,a_color,m_color[c])
+ setattr(nn,a_transparency,m_transparency[c])
return n
end
tracers.setproperties = setproperties
-function tracers.setlistv(n,c,s)
- local f = n
+function tracers.setlist(n,c,s)
+ local nn = tonut(n)
local mc = m_color[c]
local mt = m_transparency[c]
local mm = texgetattribute(a_colormodel)
if mm <= 0 then
mm = 1
end
- while n do
- n[a_colormodel] = mm
- n[a_color] = mc
- n[a_transparency] = mt
- n = n.next
+ while nn do
+ setattr(nn,a_colormodel,mm)
+ setattr(nn,a_color,mc)
+ setattr(nn,a_transparency,mt)
+ nn = getnext(nn)
end
- return f
+ return n
end
function tracers.resetproperties(n)
- n[a_color] = unsetvalue
- n[a_transparency] = unsetvalue
+ local nn = tonut(n)
+ setattr(nn,a_color,unsetvalue)
+ setattr(nn,a_transparency,unsetvalue)
return n
end
-function tracers.rule(w,h,d,c,s) -- so some day we can consider using literals (speedup)
- return setproperties(new_rule(w,h,d),c,s)
-end
-
--- only nodes
+-- this one returns a nut
local nodestracerpool = { }
+local nutstracerpool = { }
tracers.pool = {
nodes = nodestracerpool,
+ nuts = nutstracerpool,
}
-function nodestracerpool.rule(w,h,d,c,s) -- so some day we can consider using literals (speedup)
+table.setmetatableindex(nodestracerpool,function(t,k,v)
+ local f = nutstracerpool[k]
+ local v = function(...)
+ return tonode(f(...))
+ end
+ t[k] = v
+ return v
+end)
+
+function nutstracerpool.rule(w,h,d,c,s) -- so some day we can consider using literals (speedup)
return setproperties(new_rule(w,h,d),c,s)
end
tracers.rule = nodestracerpool.rule -- for a while
+
diff --git a/tex/context/base/node-tst.lua b/tex/context/base/node-tst.lua
index bfe0051bd..7f5102d5f 100644
--- a/tex/context/base/node-tst.lua
+++ b/tex/context/base/node-tst.lua
@@ -24,17 +24,26 @@ local rightskip_code = skipcodes.rightskip
local abovedisplayshortskip_code = skipcodes.abovedisplayshortskip
local belowdisplayshortskip_code = skipcodes.belowdisplayshortskip
-local find_node_tail = node.tail or node.slide
+local nuts = nodes.nuts
-function nodes.leftmarginwidth(n) -- todo: three values
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getchar = nuts.getchar
+local getsubtype = nuts.getsubtype
+
+local find_node_tail = nuts.tail
+
+function nuts.leftmarginwidth(n) -- todo: three values
while n do
- local id = n.id
+ local id = getid(n)
if id == glue_code then
- return n.subtype == leftskip_code and n.spec.width or 0
+ return getsubtype(n) == leftskip_code and getfield(getfield(n,"spec"),"width") or 0
elseif id == whatsit_code then
- n = n.next
+ n = getnext(n)
elseif id == hlist_code then
- return n.width
+ return getfield(n,"width")
else
break
end
@@ -42,15 +51,15 @@ function nodes.leftmarginwidth(n) -- todo: three values
return 0
end
-function nodes.rightmarginwidth(n)
+function nuts.rightmarginwidth(n)
if n then
n = find_node_tail(n)
while n do
- local id = n.id
+ local id = getid(n)
if id == glue_code then
- return n.subtype == rightskip_code and n.spec.width or 0
+ return getsubtype(n) == rightskip_code and getfield(getfield(n,"spec"),"width") or 0
elseif id == whatsit_code then
- n = n.prev
+ n = getprev(n)
else
break
end
@@ -59,15 +68,15 @@ function nodes.rightmarginwidth(n)
return false
end
-function nodes.somespace(n,all)
+function nuts.somespace(n,all)
if n then
- local id = n.id
+ local id = getid(n)
if id == glue_code then
- return (all or (n.spec.width ~= 0)) and glue_code
+ return (all or (getfield(getfield(n,"spec"),"width") ~= 0)) and glue_code
elseif id == kern_code then
- return (all or (n.kern ~= 0)) and kern
+ return (all or (getfield(n,"kern") ~= 0)) and kern
elseif id == glyph_code then
- local category = chardata[n.char].category
+ local category = chardata[getchar(n)].category
-- maybe more category checks are needed
return (category == "zs") and glyph_code
end
@@ -75,12 +84,12 @@ function nodes.somespace(n,all)
return false
end
-function nodes.somepenalty(n,value)
+function nuts.somepenalty(n,value)
if n then
- local id = n.id
+ local id = getid(n)
if id == penalty_code then
if value then
- return n.penalty == value
+ return getfield(n,"penalty") == value
else
return true
end
@@ -89,32 +98,38 @@ function nodes.somepenalty(n,value)
return false
end
-function nodes.is_display_math(head)
- local n = head.prev
+function nuts.is_display_math(head)
+ local n = getprev(head)
while n do
- local id = n.id
+ local id = getid(n)
if id == penalty_code then
elseif id == glue_code then
- if n.subtype == abovedisplayshortskip_code then
+ if getsubtype(n) == abovedisplayshortskip_code then
return true
end
else
break
end
- n = n.prev
+ n = getprev(n)
end
- n = head.next
+ n = getnext(head)
while n do
- local id = n.id
+ local id = getid(n)
if id == penalty_code then
elseif id == glue_code then
- if n.subtype == belowdisplayshortskip_code then
+ if getsubtype(n) == belowdisplayshortskip_code then
return true
end
else
break
end
- n = n.next
+ n = getnext(n)
end
return false
end
+
+nodes.leftmarginwidth = nodes.vianuts(nuts.leftmarginwidth)
+nodes.rightmarginwidth = nodes.vianuts(nuts.rightmarginwidth)
+nodes.somespace = nodes.vianuts(nuts.somespace)
+nodes.somepenalty = nodes.vianuts(nuts.somepenalty)
+nodes.is_display_math = nodes.vianuts(nuts.is_display_math)
diff --git a/tex/context/base/node-typ.lua b/tex/context/base/node-typ.lua
index 4a2ef8d49..5a4dfe4be 100644
--- a/tex/context/base/node-typ.lua
+++ b/tex/context/base/node-typ.lua
@@ -8,21 +8,27 @@ if not modules then modules = { } end modules ['node-typ'] = {
-- code has been moved to blob-ini.lua
-local typesetters = nodes.typesetters or { }
-nodes.typesetters = typesetters
+local typesetters = nodes.typesetters or { }
+nodes.typesetters = typesetters
-local hpack_node_list = nodes.hpack
-local vpack_node_list = nodes.vpack
-local fast_hpack_list = nodes.fasthpack
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
-local nodepool = nodes.pool
+local setfield = nuts.setfield
+
+local hpack_node_list = nuts.hpack
+local vpack_node_list = nuts.vpack
+local fast_hpack_list = nuts.fasthpack
+
+local nodepool = nuts.pool
local new_glyph = nodepool.glyph
local new_glue = nodepool.glue
local utfvalues = utf.values
-local currentfont = font.current
-local fontparameters = fonts.hashes.parameters
+local currentfont = font.current
+local fontparameters = fonts.hashes.parameters
local function tonodes(str,fontid,spacing) -- quick and dirty
local head, prev = nil, nil
@@ -53,8 +59,8 @@ local function tonodes(str,fontid,spacing) -- quick and dirty
elseif not head then
head = next
else
- prev.next = next
- next.prev = prev
+ setfield(prev,"next",next)
+ setfield(next,"prev",prev)
end
prev = next
end
@@ -77,17 +83,30 @@ end
local tovpackfast = tovpack
-typesetters.tonodes = tonodes
-typesetters.tohpack = tohpack
-typesetters.tohpackfast = tohpackfast
-typesetters.tovpack = tovpack
-typesetters.tovpackfast = tovpackfast
+local tnuts = { }
+nuts.typesetters = tnuts
+
+tnuts.tonodes = tonodes
+tnuts.tohpack = tohpack
+tnuts.tohpackfast = tohpackfast
+tnuts.tovpack = tovpack
+tnuts.tovpackfast = tovpackfast
+
+tnuts.hpack = tohpack -- obsolete
+tnuts.fast_hpack = tohpackfast -- obsolete
+tnuts.vpack = tovpack -- obsolete
+
+typesetters.tonodes = function(...) local h, b = tonodes (...) return tonode(h), b end
+typesetters.tohpack = function(...) local h, b = tohpack (...) return tonode(h), b end
+typesetters.tohpackfast = function(...) local h, b = tohpackfast(...) return tonode(h), b end
+typesetters.tovpack = function(...) local h, b = tovpack (...) return tonode(h), b end
+typesetters.tovpackfast = function(...) local h, b = tovpackfast(...) return tonode(h), b end
-typesetters.hpack = tohpack
-typesetters.fast_hpack = tohpackfast
-typesetters.vpack = tovpack
+typesetters.hpack = typesetters.tohpack -- obsolete
+typesetters.fast_hpack = typesetters.tofasthpack -- obsolete
+typesetters.vpack = typesetters.tovpack -- obsolete
-- node.write(nodes.typestters.hpack("Hello World!"))
-- node.write(nodes.typestters.hpack("Hello World!",1,100*1024*10))
-string.tonodes = tonodes -- quite convenient
+string.tonodes = function(...) return tonode(tonodes(...)) end -- quite convenient
diff --git a/tex/context/base/pack-rul.lua b/tex/context/base/pack-rul.lua
index 329ea63b8..b9fa141fc 100644
--- a/tex/context/base/pack-rul.lua
+++ b/tex/context/base/pack-rul.lua
@@ -21,15 +21,25 @@ local line_code = nodes.listcodes.line
local texsetdimen = tex.setdimen
local texsetcount = tex.setcount
-local texgetbox = tex.getbox
-local hpack = nodes.hpack
-local free = nodes.free
-local copy = nodes.copy_list
-local traverse_id = nodes.traverse_id
-local node_dimensions = nodes.dimensions
+
+local nuts = nodes.nuts
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getlist = nuts.getlist
+local getsubtype = nuts.getsubtype
+local getbox = nuts.getbox
+
+local hpack = nuts.hpack
+local free = nuts.free
+local copy = nuts.copy_list
+local traverse_id = nuts.traverse_id
+local node_dimensions = nuts.dimensions
function commands.doreshapeframedbox(n)
- local box = texgetbox(n)
+ local box = getbox(n)
local noflines = 0
local firstheight = nil
local lastdepth = nil
@@ -38,27 +48,27 @@ function commands.doreshapeframedbox(n)
local maxwidth = 0
local totalwidth = 0
local averagewidth = 0
- local boxwidth = box.width
+ local boxwidth = getfield(box,"width")
if boxwidth ~= 0 then -- and h.subtype == vlist_code
- local list = box.list
+ local list = getlist(box)
if list then
local function check(n,repack)
if not firstheight then
- firstheight = n.height
+ firstheight = getfield(n,"height")
end
- lastdepth = n.depth
+ lastdepth = getfield(n,"depth")
noflines = noflines + 1
- local l = n.list
+ local l = getlist(n)
if l then
if repack then
- local subtype = n.subtype
+ local subtype = getsubtype(n)
if subtype == box_code or subtype == line_code then
- lastlinelength = node_dimensions(l,n.dir) -- used to be: hpack(copy(l)).width
+ lastlinelength = node_dimensions(l,getfield(n,"dir")) -- used to be: hpack(copy(l)).width
else
- lastlinelength = n.width
+ lastlinelength = getfield(n,"width")
end
else
- lastlinelength = n.width
+ lastlinelength = getfield(n,"width")
end
if lastlinelength > maxwidth then
maxwidth = lastlinelength
@@ -84,28 +94,27 @@ function commands.doreshapeframedbox(n)
elseif maxwidth ~= 0 then
if hdone then
for h in traverse_id(hlist_code,list) do
- local l = h.list
+ local l = getlist(h)
if l then
- local subtype = h.subtype
+ local subtype = getsubtype(n)
if subtype == box_code or subtype == line_code then
- h.list = hpack(l,maxwidth,'exactly',h.dir)
- h.shift = 0 -- needed for display math
+ l = hpack(l,maxwidth,'exactly',getfield(h,"dir")) -- multiple return values
+ setfield(h,"list",l)
+ setfield(h,"shift",0) -- needed for display math, so no width check possible
end
- h.width = maxwidth
+ setfield(h,"width",maxwidth)
end
end
- box.width = maxwidth -- moved
- averagewidth = noflines > 0 and totalwidth/noflines or 0
end
-- if vdone then
-- for v in traverse_id(vlist_code,list) do
- -- local width = n.width
+ -- local width = getfield(n,"width")
-- if width > maxwidth then
- -- v.width = maxwidth
+ -- setfield(v,"width",maxwidth)
-- end
-- end
-- end
- box.width = maxwidth
+ setfield(box,"width",maxwidth)
averagewidth = noflines > 0 and totalwidth/noflines or 0
end
end
@@ -119,18 +128,18 @@ function commands.doreshapeframedbox(n)
end
function commands.doanalyzeframedbox(n)
- local box = texgetbox(n)
+ local box = getbox(n)
local noflines = 0
local firstheight = nil
local lastdepth = nil
- if box.width ~= 0 then
- local list = box.list
+ if getfield(box,"width") ~= 0 then
+ local list = getlist(box)
if list then
local function check(n)
if not firstheight then
- firstheight = n.height
+ firstheight = getfield(n,"height")
end
- lastdepth = n.depth
+ lastdepth = getfield(n,"depth")
noflines = noflines + 1
end
for h in traverse_id(hlist_code,list) do
diff --git a/tex/context/base/page-lin.lua b/tex/context/base/page-lin.lua
index 7e8e9ad8a..66b7e4684 100644
--- a/tex/context/base/page-lin.lua
+++ b/tex/context/base/page-lin.lua
@@ -8,32 +8,36 @@ if not modules then modules = { } end modules ['page-lin'] = {
-- experimental -> will become builders
-local trace_numbers = false trackers.register("lines.numbers", function(v) trace_numbers = v end)
-
-local report_lines = logs.reporter("lines")
+-- if there is demand for it, we can support multiple numbering streams
+-- and use more than one attibute
-local attributes, nodes, node, context = attributes, nodes, node, context
+local next, tonumber = next, tonumber
-nodes.lines = nodes.lines or { }
-local lines = nodes.lines
+local trace_numbers = false trackers.register("lines.numbers", function(v) trace_numbers = v end)
-lines.data = lines.data or { } -- start step tag
-local data = lines.data
-local last = #data
+local report_lines = logs.reporter("lines")
-local texgetbox = tex.getbox
+local attributes = attributes
+local nodes = nodes
+local context = context
-lines.scratchbox = lines.scratchbox or 0
+nodes.lines = nodes.lines or { }
+local lines = nodes.lines
-local leftmarginwidth = nodes.leftmarginwidth
+lines.data = lines.data or { } -- start step tag
+local data = lines.data
+local last = #data
-storage.register("lines/data", lines.data, "nodes.lines.data")
+lines.scratchbox = lines.scratchbox or 0
--- if there is demand for it, we can support multiple numbering streams
--- and use more than one attibute
+storage.register("lines/data", data, "nodes.lines.data")
local variables = interfaces.variables
+local v_next = variables.next
+local v_page = variables.page
+local v_no = variables.no
+
local nodecodes = nodes.nodecodes
local hlist_code = nodecodes.hlist
@@ -49,12 +53,25 @@ local current_list = { }
local cross_references = { }
local chunksize = 250 -- not used in boxed
-local traverse_id = node.traverse_id
-local traverse = node.traverse
-local copy_node = node.copy
-local hpack_node = node.hpack
-local insert_node_after = node.insert_after
-local insert_node_before = node.insert_before
+local nuts = nodes.nuts
+
+local getid = nuts.getid
+local getnext = nuts.getnext
+local getattr = nuts.getattr
+local getlist = nuts.getlist
+local getbox = nuts.getbox
+local getfield = nuts.getfield
+
+local setfield = nuts.setfield
+
+local traverse_id = nuts.traverse_id
+local traverse = nuts.traverse
+local copy_node = nuts.copy
+local hpack_node = nuts.hpack
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local is_display_math = nuts.is_display_math
+local leftmarginwidth = nuts.leftmarginwidth
-- cross referencing
@@ -67,16 +84,16 @@ end
local function resolve(n,m) -- we can now check the 'line' flag (todo)
while n do
- local id = n.id
+ local id = getid(n)
if id == whatsit_code then -- why whatsit
- local a = n[a_linereference]
+ local a = getattr(n,a_linereference)
if a then
cross_references[a] = m
end
elseif id == hlist_code or id == vlist_code then
- resolve(n.list,m)
+ resolve(getlist(n),m)
end
- n = n.next
+ n = getnext(n)
end
end
@@ -165,20 +182,20 @@ local function check_number(n,a,skip,sameline)
if sameline then
skipflag = 0
if trace_numbers then
- report_lines("skipping broken line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or "no")
+ report_lines("skipping broken line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
end
elseif not skip and s % d.step == 0 then
skipflag, d.start = 1, s + 1 -- (d.step or 1)
if trace_numbers then
- report_lines("making number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or "no")
+ report_lines("making number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
end
else
skipflag, d.start = 0, s + 1 -- (d.step or 1)
if trace_numbers then
- report_lines("skipping line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or "no")
+ report_lines("skipping line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
end
end
- context.makelinenumber(tag,skipflag,s,n.shift,n.width,leftmarginwidth(n.list),n.dir)
+ context.makelinenumber(tag,skipflag,s,getfield(n,"shift"),getfield(n,"width"),leftmarginwidth(getlist(n)),getfield(n,"dir"))
end
end
@@ -189,26 +206,26 @@ end
local function identify(list)
if list then
for n in traverse_id(hlist_code,list) do
- if n[a_linenumber] then
+ if getattr(n,a_linenumber) then
return list
end
end
local n = list
while n do
- local id = n.id
+ local id = getid(n)
if id == hlist_code or id == vlist_code then
- local ok = identify(n.list)
+ local ok = identify(getlist(n))
if ok then
return ok
end
end
- n = n.next
+ n = getnext(n)
end
end
end
function boxed.stage_zero(n)
- return identify(texgetbox(n).list)
+ return identify(getlist(getbox(n)))
end
-- reset ranges per page
@@ -217,39 +234,39 @@ end
function boxed.stage_one(n,nested)
current_list = { }
- local box = texgetbox(n)
+ local box = getbox(n)
if box then
- local list = box.list
+ local list = getlist(box)
if nested then
list = identify(list)
end
local last_a, last_v, skip = nil, -1, false
for n in traverse_id(hlist_code,list) do -- attr test here and quit as soon as zero found
- if n.height == 0 and n.depth == 0 then
+ if getfield(n,"height") == 0 and getfield(n,"depth") == 0 then
-- skip funny hlists -- todo: check line subtype
else
- local list = n.list
- local a = list[a_linenumber]
+ local list = getlist(n)
+ local a = getattr(list,a_linenumber)
if a and a > 0 then
if last_a ~= a then
local da = data[a]
local ma = da.method
- if ma == variables.next then
+ if ma == v_next then
skip = true
- elseif ma == variables.page then
+ elseif ma == v_page then
da.start = 1 -- eventually we will have a normal counter
end
last_a = a
if trace_numbers then
- report_lines("starting line number range %s: start %s, continue",a,da.start,da.continue or "no")
+ report_lines("starting line number range %s: start %s, continue %s",a,da.start,da.continue or v_no)
end
end
- if n[a_displaymath] then
- if nodes.is_display_math(n) then
+ if getattr(n,a_displaymath) then
+ if is_display_math(n) then
check_number(n,a,skip)
end
else
- local v = list[a_verbatimline]
+ local v = getattr(list,a_verbatimline)
if not v or v ~= last_v then
last_v = v
check_number(n,a,skip)
@@ -268,7 +285,7 @@ function boxed.stage_two(n,m)
if #current_list > 0 then
m = m or lines.scratchbox
local t, tn = { }, 0
- for l in traverse_id(hlist_code,texgetbox(m).list) do
+ for l in traverse_id(hlist_code,getlist(getbox(m))) do
tn = tn + 1
t[tn] = copy_node(l)
end
@@ -276,7 +293,8 @@ function boxed.stage_two(n,m)
local li = current_list[i]
local n, m, ti = li[1], li[2], t[i]
if ti then
- ti.next, n.list = n.list, ti
+ setfield(ti,"next",getlist(n))
+ setfield(n,"list",ti)
resolve(n,m)
else
report_lines("error in linenumbering (1)")
diff --git a/tex/context/base/page-mix.lua b/tex/context/base/page-mix.lua
index 7d13d9e4e..a7db58f82 100644
--- a/tex/context/base/page-mix.lua
+++ b/tex/context/base/page-mix.lua
@@ -15,46 +15,71 @@ if not modules then modules = { } end modules ["page-mix"] = {
local concat = table.concat
-local nodecodes = nodes.nodecodes
-local gluecodes = nodes.gluecodes
-local nodepool = nodes.pool
-
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local kern_code = nodecodes.kern
-local glue_code = nodecodes.glue
-local penalty_code = nodecodes.penalty
-local insert_code = nodecodes.ins
-local mark_code = nodecodes.mark
-
-local new_hlist = nodepool.hlist
-local new_vlist = nodepool.vlist
-local new_glue = nodepool.glue
-
-local hpack = node.hpack
-local vpack = node.vpack
-local freenode = node.free
-local concatnodes = nodes.concat
-
-local texgetbox = tex.getbox
-local texsetbox = tex.setbox
-local texgetskip = tex.getskip
-
-local points = number.points
-
-local settings_to_hash = utilities.parsers.settings_to_hash
-
-local variables = interfaces.variables
-local v_yes = variables.yes
-local v_global = variables["global"]
-local v_local = variables["local"]
-local v_columns = variables.columns
-
local trace_state = false trackers.register("mixedcolumns.trace", function(v) trace_state = v end)
local trace_detail = false trackers.register("mixedcolumns.detail", function(v) trace_detail = v end)
local report_state = logs.reporter("mixed columns")
+local nodecodes = nodes.nodecodes
+local gluecodes = nodes.gluecodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local penalty_code = nodecodes.penalty
+local insert_code = nodecodes.ins
+local mark_code = nodecodes.mark
+local rule_code = nodecodes.rule
+
+local topskip_code = gluecodes.topskip
+local lineskip_code = gluecodes.lineskip
+local baselineskip_code = gluecodes.baselineskip
+local userskip_code = gluecodes.userskip
+
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local nodetostring = nuts.tostring
+local listtoutf = nodes.listtoutf
+
+local hpack = nuts.hpack
+local vpack = nuts.vpack
+local freenode = nuts.free
+local concatnodes = nuts.concat
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getsubtype = nuts.getsubtype
+local getbox = nuts.getbox
+local setbox = nuts.setbox
+local getskip = nuts.getskip
+local getattribute = nuts.getattribute
+
+local nodepool = nuts.pool
+
+local new_hlist = nodepool.hlist
+local new_vlist = nodepool.vlist
+local new_glue = nodepool.glue
+
+local points = number.points
+
+local settings_to_hash = utilities.parsers.settings_to_hash
+
+local variables = interfaces.variables
+local v_yes = variables.yes
+local v_global = variables["global"]
+local v_local = variables["local"]
+local v_columns = variables.columns
+local v_fixed = variables.fixed
+local v_auto = variables.auto
+local v_none = variables.none
+local v_more = variables.more
+local v_less = variables.less
+
pagebuilders = pagebuilders or { }
pagebuilders.mixedcolumns = pagebuilders.mixedcolumns or { }
local mixedcolumns = pagebuilders.mixedcolumns
@@ -77,13 +102,13 @@ local function collectinserts(result,nxt,nxtid)
local inserts, currentskips, nextskips, inserttotal = { }, 0, 0, 0
while nxt do
if nxtid == insert_code then
- inserttotal = inserttotal + nxt.height + nxt.depth
- local s = nxt.subtype
+ inserttotal = inserttotal + getfield(nxt,"height") + getfield(nxt,"depth")
+ local s = getsubtype(nxt)
local c = inserts[s]
if not c then
c = { }
inserts[s] = c
- local width = texgetskip(s).width
+ local width = getfield(getskip(s),"width")
if not result.inserts[s] then
currentskips = currentskips + width
end
@@ -100,9 +125,9 @@ local function collectinserts(result,nxt,nxtid)
else
break
end
- nxt = nxt.next
+ nxt = getnext(nxt)
if nxt then
- nxtid = nxt.id
+ nxtid = getid(nxt)
else
break
end
@@ -128,30 +153,30 @@ end
local function discardtopglue(current,discarded)
local size = 0
while current do
- local id = current.id
+ local id = getid(current)
if id == glue_code then
- size = size + current.spec.width
+ size = size + getfield(getfield(current,"spec"),"width")
discarded[#discarded+1] = current
- current = current.next
+ current = getnext(current)
elseif id == penalty_code then
- if current.penalty == forcedbreak then
+ if getfield(current,"penalty") == forcedbreak then
discarded[#discarded+1] = current
- current = current.next
- while current and current.id == glue_code do
- size = size + current.spec.width
+ current = getnext(current)
+ while current and getid(current) == glue_code do
+ size = size + getfield(getfield(current,"spec"),"width")
discarded[#discarded+1] = current
- current = current.next
+ current = getnext(current)
end
else
discarded[#discarded+1] = current
- current = current.next
+ current = getnext(current)
end
else
break
end
end
if current then
- current.prev = nil
+ setfield(current,"prev",nil) -- prevent look back
end
return current, size
end
@@ -162,13 +187,13 @@ local function stripbottomglue(results,discarded)
local r = results[i]
local t = r.tail
while t and t ~= r.head do
- local prev = t.prev
+ local prev = getprev(t)
if not prev then
break
end
- local id = t.id
+ local id = getid(t)
if id == penalty_code then
- if t.penalty == forcedbreak then
+ if getfield(t,"penalty") == forcedbreak then
break
else
discarded[#discarded+1] = t
@@ -177,7 +202,7 @@ local function stripbottomglue(results,discarded)
end
elseif id == glue_code then
discarded[#discarded+1] = t
- local width = t.spec.width
+ local width = getfield(getfield(t,"spec"),"width")
if trace_state then
report_state("columns %s, discarded bottom glue %p",i,width)
end
@@ -201,20 +226,20 @@ local function setsplit(specification) -- a rather large function
report_state("fatal error, no box")
return
end
- local list = texgetbox(box)
+ local list = getbox(box)
if not list then
report_state("fatal error, no list")
return
end
- local head = list.head or specification.originalhead
+ local head = getlist(list) or specification.originalhead
if not head then
report_state("fatal error, no head")
return
end
local discarded = { }
local originalhead = head
- local originalwidth = specification.originalwidth or list.width
- local originalheight = specification.originalheight or list.height
+ local originalwidth = specification.originalwidth or getfield(list,"width")
+ local originalheight = specification.originalheight or getfield(list,"height")
local current = head
local skipped = 0
local height = 0
@@ -277,20 +302,20 @@ local function setsplit(specification) -- a rather large function
local current = start
-- first skip over glue and penalty
while current do
- local id = current.id
+ local id = getid(current)
if id == glue_code or id == penalty_code then
- current = current.prev
+ current = getprev(current)
else
break
end
end
-- then skip over content
while current do
- local id = current.id
+ local id = getid(current)
if id == glue_code or id == penalty_code then
break
else
- current = current.prev
+ current = getprev(current)
end
end
if not current then
@@ -324,7 +349,7 @@ local function setsplit(specification) -- a rather large function
if current == head then
result.tail = head
else
- result.tail = current.prev
+ result.tail = getprev(current)
end
result.height = height
result.depth = depth
@@ -344,6 +369,9 @@ local function setsplit(specification) -- a rather large function
report_state("setting collector to column %s",column)
end
current, skipped = discardtopglue(current,discarded)
+ if trace_detail and skipped ~= 0 then
+ report_state("check > column 1, discarded %p",skipped)
+ end
head = current
return true, skipped
end
@@ -387,7 +415,7 @@ local function setsplit(specification) -- a rather large function
head = current
local function process_skip(current,nxt)
- local advance = current.spec.width
+ local advance = getfield(getfield(current,"spec"),"width")
if advance ~= 0 then
local state, skipped = checked(advance,"glue")
if trace_state then
@@ -411,7 +439,7 @@ local function setsplit(specification) -- a rather large function
end
local function process_kern(current,nxt)
- local advance = current.kern
+ local advance = getfield(current,"kern")
if advance ~= 0 then
local state, skipped = checked(advance,"kern")
if trace_state then
@@ -434,7 +462,7 @@ local function setsplit(specification) -- a rather large function
local function process_rule(current,nxt)
-- simple variant of h|vlist
- local advance = current.height -- + current.depth
+ local advance = getfield(current,"height") -- + getfield(current,"depth")
local state, skipped = checked(advance+currentskips,"rule")
if trace_state then
report_state("%-7s > column %s, state %a, rule, advance %p, height %p","line",column,state,advance,inserttotal,height)
@@ -451,7 +479,7 @@ local function setsplit(specification) -- a rather large function
else
height = height + currentskips
end
- depth = current.depth
+ depth = getfield(current,"depth")
skip = 0
end
@@ -462,12 +490,12 @@ local function setsplit(specification) -- a rather large function
-- [chapter] [penalty] [section] [penalty] [first line]
local function process_penalty(current,nxt)
- local penalty = current.penalty
+ local penalty = getfield(current,"penalty")
if penalty == 0 then
lastlocked = nil
lastcurrent = nil
elseif penalty == forcedbreak then
- local needed = current[a_checkedbreak]
+ local needed = getattribute(current,a_checkedbreak)
local proceed = not needed or needed == 0
if not proceed then
local available = target - height
@@ -515,12 +543,12 @@ local function setsplit(specification) -- a rather large function
end
local function process_list(current,nxt)
- local nxtid = nxt and nxt.id
+ local nxtid = nxt and getid(nxt)
line = line + 1
local inserts, currentskips, nextskips, inserttotal = nil, 0, 0, 0
- local advance = current.height -- + current.depth
+ local advance = getfield(current,"height") -- + getfield(current,"depth")
if trace_state then
- report_state("%-7s > column %s, content: %s","line",column,listtoutf(current.list,true,true))
+ report_state("%-7s > column %s, content: %s","line",column,listtoutf(getlist(current),true,true))
end
if nxt and (nxtid == insert_code or nxtid == mark_code) then
nxt, inserts, localskips, insertskips, inserttotal = collectinserts(result,nxt,nxtid)
@@ -541,7 +569,7 @@ local function setsplit(specification) -- a rather large function
else
height = height + currentskips
end
- depth = current.depth
+ depth = getfield(current,"depth")
skip = 0
if inserts then
-- so we already collect them ... makes backtracking tricky ... alternatively
@@ -555,8 +583,8 @@ local function setsplit(specification) -- a rather large function
while current do
- local id = current.id
- local nxt = current.next
+ local id = getid(current)
+ local nxt = getnext(current)
backtracked = false
@@ -629,7 +657,7 @@ local function setsplit(specification) -- a rather large function
specification.overflow = overflow
specification.discarded = discarded
- texgetbox(specification.box).list = nil
+ setfield(getbox(specification.box),"list",nil)
return specification
end
@@ -641,12 +669,12 @@ function mixedcolumns.finalize(result)
local r = results[i]
local h = r.head
if h then
- h.prev = nil
+ setfield(h,"prev",nil)
local t = r.tail
if t then
- t.next = nil
+ setfield(t,"next",nil)
else
- h.next = nil
+ setfield(h,"next",nil)
r.tail = h
end
for c, list in next, r.inserts do
@@ -655,13 +683,13 @@ function mixedcolumns.finalize(result)
local l = list[i]
local h = new_hlist()
t[i] = h
- h.head = l.head
- h.height = l.height
- h.depth = l.depth
+ setfield(h,"list",l.head)
+ setfield(h,"height",l.height)
+ setfield(h,"depth",l.depth)
l.head = nil
end
- t[1].prev = nil -- needs checking
- t[#t].next = nil -- needs checking
+ setfield(t[1],"prev",nil) -- needs checking
+ setfield(t[#t],"next",nil) -- needs checking
r.inserts[c] = t
end
end
@@ -733,13 +761,13 @@ function mixedcolumns.getsplit(result,n)
return new_glue(result.originalwidth)
end
- h.prev = nil -- move up
+ setfield(h,"prev",nil) -- move up
local strutht = result.strutht
local strutdp = result.strutdp
local lineheight = strutht + strutdp
local v = new_vlist()
- v.head = h
+ setfield(v,"list",h)
-- local v = vpack(h,"exactly",height)
@@ -761,14 +789,14 @@ function mixedcolumns.getsplit(result,n)
dp = result.depth
end
- v.width = wd
- v.height = ht
- v.depth = dp
+ setfield(v,"width",wd)
+ setfield(v,"height",ht)
+ setfield(v,"depth",dp)
if trace_state then
- local id = h.id
+ local id = getid(h)
if id == hlist_code then
- report_state("flush, column %s, grid %a, width %p, height %p, depth %p, %s: %s",n,grid,wd,ht,dp,"top line",nodes.toutf(h.list))
+ report_state("flush, column %s, grid %a, width %p, height %p, depth %p, %s: %s",n,grid,wd,ht,dp,"top line",listtoutf(getlist(h)))
else
report_state("flush, column %s, grid %a, width %p, height %p, depth %p, %s: %s",n,grid,wd,ht,dp,"head node",nodecodes[id])
end
@@ -777,8 +805,8 @@ function mixedcolumns.getsplit(result,n)
for c, list in next, r.inserts do
local l = concatnodes(list)
local b = vpack(l) -- multiple arguments, todo: fastvpack
- -- texsetbox("global",c,b)
- texsetbox(c,b)
+ -- setbox("global",c,b)
+ setbox(c,b)
r.inserts[c] = nil
end
@@ -822,7 +850,7 @@ end
function commands.mixgetsplit(n)
if result then
- context(mixedcolumns.getsplit(result,n))
+ context(tonode(mixedcolumns.getsplit(result,n)))
end
end
@@ -834,13 +862,13 @@ end
function commands.mixflushrest()
if result then
- context(mixedcolumns.getrest(result))
+ context(tonode(mixedcolumns.getrest(result)))
end
end
function commands.mixflushlist()
if result then
- context(mixedcolumns.getlist(result))
+ context(tonode(mixedcolumns.getlist(result)))
end
end
diff --git a/tex/context/base/scrp-cjk.lua b/tex/context/base/scrp-cjk.lua
index 681fc4c43..9050da6be 100644
--- a/tex/context/base/scrp-cjk.lua
+++ b/tex/context/base/scrp-cjk.lua
@@ -14,15 +14,29 @@ if not modules then modules = { } end modules ['scrp-cjk'] = {
-- sense either because otherwise a wanted space at the end of a
-- line would have to be a hard coded ones.
-local utfchar = utf.char
-
-local insert_node_after = nodes.insert_after
-local insert_node_before = nodes.insert_before
-local remove_node = nodes.remove
-local copy_node = nodes.copy
-local traverse_id = nodes.traverse_id
-
-local nodepool = nodes.pool
+local utfchar = utf.getchar
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local copy_node = nuts.copy
+local remove_node = nuts.remove
+local traverse_id = nuts.traverse_id
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getattr = nuts.getattr
+local getsubtype = nuts.getsubtype
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+
+local nodepool = nuts.pool
local new_glue = nodepool.glue
local new_kern = nodepool.kern
local new_penalty = nodepool.penalty
@@ -88,20 +102,20 @@ end
-- at font definition time and/or just assume a correct font
local function trace_detail(current,what)
- local prev = current.prev
- local c_id = current.id
- local p_id = prev and prev.id
+ local prev = getprev(current)
+ local c_id = getid(current)
+ local p_id = prev and getid(prev)
if c_id == glyph_code then
- local c_ch = current.char
+ local c_ch = getchar(current)
if p_id == glyph_code then
- local p_ch = p_id and prev.char
+ local p_ch = p_id and getchar(prev)
report_details("[%C %a] [%s] [%C %a]",p_ch,hash[p_ch],what,c_ch,hash[c_ch])
else
report_details("[%s] [%C %a]",what,c_ch,hash[c_ch])
end
else
if p_id == glyph_code then
- local p_ch = p_id and prev.char
+ local p_ch = p_id and getchar(prev)
report_details("[%C %a] [%s]",p_ch,hash[p_ch],what)
else
report_details("[%s]",what)
@@ -110,8 +124,8 @@ local function trace_detail(current,what)
end
local function trace_detail_between(p,n,what)
- local p_ch = p.char
- local n_ch = n.char
+ local p_ch = getchar(p)
+ local n_ch = getchar(n)
report_details("[%C %a] [%s] [%C %a]",p_ch,hash[p_ch],what,n_ch,hash[n_ch])
end
@@ -427,29 +441,29 @@ local function process(head,first,last)
if first ~= last then
local lastfont, previous, last = nil, "start", nil
while true do
- local upcoming, id = first.next, first.id
+ local upcoming, id = getnext(first), getid(first)
if id == glyph_code then
- local a = first[a_scriptstatus]
+ local a = getattr(first,a_scriptstatus)
local current = numbertocategory[a]
local action = injectors[previous]
if action then
action = action[current]
if action then
- local font = first.font
+ local font = getfont(first)
if font ~= lastfont then
lastfont = font
- set_parameters(font,numbertodataset[first[a_scriptinjection]])
+ set_parameters(font,numbertodataset[getattr(first,a_scriptinjection)])
end
action(head,first)
end
end
previous = current
else -- glue
- local p, n = first.prev, upcoming
+ local p, n = getprev(first), upcoming
if p and n then
- local pid, nid = p.id, n.id
+ local pid, nid = getid(p), getid(n)
if pid == glyph_code and nid == glyph_code then
- local pa, na = p[a_scriptstatus], n[a_scriptstatus]
+ local pa, na = getattr(p,a_scriptstatus), getattr(n,a_scriptstatus)
local pcjk, ncjk = pa and numbertocategory[pa], na and numbertocategory[na]
if not pcjk or not ncjk
or pcjk == "korean" or ncjk == "korean"
@@ -495,23 +509,24 @@ scripts.installmethod {
}
function scripts.decomposehangul(head)
+ local head = tonut(head)
local done = false
for current in traverse_id(glyph_code,head) do
- local lead_consonant, medial_vowel, tail_consonant = decomposed(current.char)
+ local lead_consonant, medial_vowel, tail_consonant = decomposed(getchar(current))
if lead_consonant then
- current.char = lead_consonant
+ setfield(current,"char",lead_consonant)
local m = copy_node(current)
- m.char = medial_vowel
+ setfield(m,"char",medial_vowel)
head, current = insert_node_after(head,current,m)
if tail_consonant then
local t = copy_node(current)
- t.char = tail_consonant
+ setfield(t,"char",tail_consonant)
head, current = insert_node_after(head,current,t)
end
done = true
end
end
- return head, done
+ return tonode(head), done
end
-- nodes.tasks.prependaction("processors","normalizers","scripts.decomposehangul")
@@ -682,29 +697,29 @@ local function process(head,first,last)
if first ~= last then
local lastfont, previous, last = nil, "start", nil
while true do
- local upcoming, id = first.next, first.id
+ local upcoming, id = getnext(first), getid(first)
if id == glyph_code then
- local a = first[a_scriptstatus]
+ local a = getattr(first,a_scriptstatus)
local current = numbertocategory[a]
local action = injectors[previous]
if action then
action = action[current]
if action then
- local font = first.font
+ local font = getfont(first)
if font ~= lastfont then
lastfont = font
- set_parameters(font,numbertodataset[first[a_scriptinjection]])
+ set_parameters(font,numbertodataset[getattr(first,a_scriptinjection)])
end
action(head,first)
end
end
previous = current
else -- glue
- local p, n = first.prev, upcoming
+ local p, n = getprev(first), upcoming
if p and n then
- local pid, nid = p.id, n.id
+ local pid, nid = getid(p), getid(n)
if pid == glyph_code and nid == glyph_code then
- local pa, na = p[a_scriptstatus], n[a_scriptstatus]
+ local pa, na = getattr(p,a_scriptstatus), getattr(n,a_scriptstatus)
local pcjk, ncjk = pa and numbertocategory[pa], na and numbertocategory[na]
if not pcjk or not ncjk
or pcjk == "korean" or ncjk == "korean"
@@ -904,34 +919,32 @@ local function process(head,first,last)
if first ~= last then
local lastfont, previous, last = nil, "start", nil
while true do
- local upcoming, id = first.next, first.id
+ local upcoming, id = getnext(first), getid(first)
if id == glyph_code then
- local a = first[a_scriptstatus]
+ local a = getattr(first,a_scriptstatus)
local current = numbertocategory[a]
local action = injectors[previous]
if action then
action = action[current]
if action then
- local font = first.font
+ local font = getfont(first)
if font ~= lastfont then
lastfont = font
- set_parameters(font,numbertodataset[first[a_scriptinjection]])
+ set_parameters(font,numbertodataset[getattr(first,a_scriptinjection)])
end
action(head,first)
end
end
previous = current
-
--- elseif id == math_code then
--- upcoming = end_of_math(current).next
--- previous = "start"
-
+ -- elseif id == math_code then
+ -- upcoming = getnext(end_of_math(current))
+ -- previous = "start"
else -- glue
- local p, n = first.prev, upcoming -- we should remember prev
+ local p, n = getprev(first), upcoming -- we should remember prev
if p and n then
- local pid, nid = p.id, n.id
+ local pid, nid = getid(p), getid(n)
if pid == glyph_code and nid == glyph_code then
- local pa, na = p[a_scriptstatus], n[a_scriptstatus]
+ local pa, na = getattr(p,a_scriptstatus), getattr(n,a_scriptstatus)
local pcjk, ncjk = pa and numbertocategory[pa], na and numbertocategory[na]
if not pcjk or not ncjk
or pcjk == "korean" or ncjk == "korean"
@@ -940,17 +953,17 @@ local function process(head,first,last)
or pcjk == "half_width_close" or ncjk == "half_width_open" then -- extra compared to korean
previous = "start"
else -- if head ~= first then
-if id == glue_code and first.subtype == userskip_code then -- also scriptstatus check?
- -- for the moment no distinction possible between space and userskip
- local w = first.spec.width
- local s = spacedata[p.font]
- if w == s then -- could be option
- if trace_details then
- trace_detail_between(p,n,"space removed")
- end
- remove_node(head,first,true)
- end
-end
+ if id == glue_code and getsubtype(first) == userskip_code then -- also scriptstatus check?
+ -- for the moment no distinction possible between space and userskip
+ local w = getfield(getfield(first,"spec"),"width")
+ local s = spacedata[getfont(p)]
+ if w == s then -- could be option
+ if trace_details then
+ trace_detail_between(p,n,"space removed")
+ end
+ remove_node(head,first,true)
+ end
+ end
previous = pcjk
-- else
-- previous = pcjk
diff --git a/tex/context/base/scrp-eth.lua b/tex/context/base/scrp-eth.lua
index 597afa1b5..8ecbce522 100644
--- a/tex/context/base/scrp-eth.lua
+++ b/tex/context/base/scrp-eth.lua
@@ -9,9 +9,17 @@ if not modules then modules = { } end modules ['scrp-eth'] = {
-- at some point I will review the script code but for the moment we
-- do it this way; so space settings like with cjk yet
-local insert_node_before = node.insert_before
+local nuts = nodes.nuts
-local nodepool = nodes.pool
+local getnext = nuts.getnext
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getattr = nuts.getattr
+
+local insert_node_before = nuts.insert_before
+
+local nodepool = nuts.pool
local new_glue = nodepool.glue
local new_penalty = nodepool.penalty
@@ -37,13 +45,13 @@ local inter_character_stretch_factor = 1
local inter_character_shrink_factor = 1
local function space_glue(current)
- local data = numbertodataset[current[a_scriptinjection]]
+ local data = numbertodataset[getattr(current,a_scriptinjection)]
if data then
inter_character_space_factor = data.inter_character_space_factor or 1
inter_character_stretch_factor = data.inter_character_stretch_factor or 1
inter_character_shrink_factor = data.inter_character_shrink_factor or 1
end
- local font = current.font
+ local font = getfont(current)
if lastfont ~= font then
local pf = parameters[font]
space = pf.space
@@ -104,9 +112,9 @@ local function process(head,first,last)
local injector = false
local current = first
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local scriptstatus = current[a_scriptstatus]
+ local scriptstatus = getattr(current,a_scriptstatus)
local category = numbertocategory[scriptstatus]
if injector then
local action = injector[category]
@@ -121,7 +129,7 @@ local function process(head,first,last)
if current == last then
break
else
- current = current.next
+ current = getnext(current)
end
end
end
diff --git a/tex/context/base/scrp-ini.lua b/tex/context/base/scrp-ini.lua
index 56422e622..a6bfe4cf9 100644
--- a/tex/context/base/scrp-ini.lua
+++ b/tex/context/base/scrp-ini.lua
@@ -14,7 +14,7 @@ local attributes, nodes, node = attributes, nodes, node
local trace_analyzing = false trackers.register("scripts.analyzing", function(v) trace_analyzing = v end)
local trace_injections = false trackers.register("scripts.injections", function(v) trace_injections = v end)
local trace_splitting = false trackers.register("scripts.splitting", function(v) trace_splitting = v end)
-local trace_splitdetail = false trackers.register("scripts.splitring.detail", function(v) trace_splitdetail = v end)
+local trace_splitdetail = false trackers.register("scripts.splitting.detail", function(v) trace_splitdetail = v end)
local report_preprocessing = logs.reporter("scripts","preprocessing")
local report_splitting = logs.reporter("scripts","splitting")
@@ -22,9 +22,6 @@ local report_splitting = logs.reporter("scripts","splitting")
local utfbyte, utfsplit = utf.byte, utf.split
local gmatch = string.gmatch
-local first_glyph = node.first_glyph or node.first_character
-local traverse_id = node.traverse_id
-
local texsetattribute = tex.setattribute
local nodecodes = nodes.nodecodes
@@ -48,9 +45,23 @@ local setmetatableindex = table.setmetatableindex
local enableaction = nodes.tasks.enableaction
local disableaction = nodes.tasks.disableaction
-local insert_node_after = node.insert_after
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getchar = nuts.getchar
+local getfont = nuts.getfont
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local insert_node_after = nuts.insert_after
+local first_glyph = nuts.first_glyph
+local traverse_id = nuts.traverse_id
+
+local nodepool = nuts.pool
-local nodepool = nodes.pool
local new_glue = nodepool.glue
local new_rule = nodepool.rule
local new_penalty = nodepool.penalty
@@ -400,7 +411,7 @@ scripts.numbertocategory = numbertocategory
local function colorize(start,stop)
for n in traverse_id(glyph_code,start) do
- local kind = numbertocategory[n[a_scriptstatus]]
+ local kind = numbertocategory[getattr(n,a_scriptstatus)]
if kind then
local ac = scriptcolors[kind]
if ac then
@@ -432,16 +443,17 @@ end
-- we can have a fonts.hashes.originals
function scripts.injectors.handler(head)
+ head = tonut(head)
local start = first_glyph(head) -- we already have glyphs here (subtype 1)
if not start then
- return head, false
+ return tonode(head), false
else
local last_a, normal_process, lastfont, originals = nil, nil, nil, nil
local done, first, last, ok = false, nil, nil, false
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- local a = start[a_scriptinjection]
+ local a = getattr(start,a_scriptinjection)
if a then
if a ~= last_a then
if first then
@@ -463,7 +475,7 @@ function scripts.injectors.handler(head)
normal_process = handler.injector
end
if normal_process then
- local f = start.font
+ local f = getfont(start)
if f ~= lastfont then
originals = fontdata[f].resources
if resources then
@@ -473,13 +485,13 @@ function scripts.injectors.handler(head)
end
lastfont = f
end
- local c = start.char
+ local c = getchar(start)
if originals then
c = originals[c] or c
end
local h = hash[c]
if h then
- start[a_scriptstatus] = categorytonumber[h]
+ setattr(start,a_scriptstatus,categorytonumber[h])
if not first then
first, last = start, start
else
@@ -540,7 +552,7 @@ function scripts.injectors.handler(head)
first, last = nil, nil
end
end
- start = start.next
+ start = getnext(start)
end
if ok then
if trace_analyzing then
@@ -553,7 +565,7 @@ function scripts.injectors.handler(head)
end
done = true
end
- return head, done
+ return tonode(head), done
end
end
@@ -683,11 +695,11 @@ end)
local categories = characters.categories or { }
local function hit(root,head)
- local current = head.next
+ local current = getnext(head)
local lastrun = false
local lastfinal = false
- while current and current.id == glyph_code do
- local char = current.char
+ while current and getid(current) == glyph_code do
+ local char = getchar(current)
local newroot = root[char]
if newroot then
local final = newroot.final
@@ -701,7 +713,7 @@ local function hit(root,head)
else
return lastrun, lastfinal
end
- current = current.next
+ current = getnext(current)
end
if lastrun then
return lastrun, lastfinal
@@ -710,12 +722,13 @@ end
local tree, attr, proc
-function splitters.handler(head)
+function splitters.handler(head) -- todo: also first_glyph test
+ head = tonut(head)
local current = head
local done = false
while current do
- if current.id == glyph_code then
- local a = current[a_scriptsplitting]
+ if getid(current) == glyph_code then
+ local a = getattr(current,a_scriptsplitting)
if a then
if a ~= attr then
local handler = numbertohandler[a]
@@ -724,14 +737,14 @@ function splitters.handler(head)
proc = handler.splitter
end
if proc then
- local root = tree[current.char]
+ local root = tree[getchar(current)]
if root then
-- we don't check for attributes in the hitter (yet)
local last, final = hit(root,current)
if last then
- local next = last.next
- if next and next.id == glyph_code then
- local nextchar = next.char
+ local next = getnext(last)
+ if next and getid(next) == glyph_code then
+ local nextchar = getchar(next)
if tree[nextchar] then
if trace_splitdetail then
if type(final) == "string" then
@@ -760,9 +773,9 @@ function splitters.handler(head)
end
end
end
- current = current.next
+ current = getnext(current)
end
- return head, done
+ return tonode(head), done
end
local function marker(head,current,font,color) -- could become: nodes.tracers.marker
@@ -792,8 +805,8 @@ end
local last_a, last_f, last_s, last_q
function splitters.insertafter(handler,head,first,last,detail)
- local a = first[a_scriptsplitting]
- local f = first.font
+ local a = getattr(first,a_scriptsplitting)
+ local f = getfont(first)
if a ~= last_a or f ~= last_f then
last_s = emwidths[f] * numbertodataset[a].inter_word_stretch_factor
last_a = a
@@ -870,15 +883,15 @@ setmetatableindex(cache_nop,function(t,k) local v = { } t[k] = v return v end)
-- playing nice
function autofontfeature.handler(head)
- for n in traverse_id(glyph_code,head) do
- -- if n[a_scriptinjection] then
+ for n in traverse_id(glyph_code,tonut(head)) do
+ -- if getattr(n,a_scriptinjection) then
-- -- already tagged by script feature, maybe some day adapt
-- else
- local char = n.char
+ local char = getchar(n)
local script = otfscripts[char]
if script then
- local dynamic = n[0] or 0
- local font = n.font
+ local dynamic = getattr(n,0) or 0
+ local font = getfont(n)
if dynamic > 0 then
local slot = cache_yes[font]
local attr = slot[script]
@@ -904,7 +917,7 @@ function autofontfeature.handler(head)
end
end
if attr ~= 0 then
- n[0] = attr
+ setattr(n,0,attr)
-- maybe set scriptinjection when associated
end
end
diff --git a/tex/context/base/spac-ali.lua b/tex/context/base/spac-ali.lua
index 25cc6cd66..cf7d45172 100644
--- a/tex/context/base/spac-ali.lua
+++ b/tex/context/base/spac-ali.lua
@@ -15,8 +15,25 @@ local prependaction = tasks.prependaction
local disableaction = tasks.disableaction
local enableaction = tasks.enableaction
-local slide_nodes = node.slide
-local hpack_nodes = node.hpack -- nodes.fasthpack not really faster here
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+
+local slide_nodes = nuts.slide
+local hpack_nodes = nuts.hpack -- nodes.fasthpack not really faster here
+local linked_nodes = nuts.linked
local unsetvalue = attributes.unsetvalue
@@ -27,8 +44,6 @@ local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local line_code = listcodes.line
-local nodepool = nodes.pool
-
local new_stretch = nodepool.stretch
local a_realign = attributes.private("realign")
@@ -56,10 +71,10 @@ local function handler(head,leftpage,realpageno)
local current = head
local done = false
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code then
- if current.subtype == line_code then
- local a = current[a_realign]
+ if getsubtype(current) == line_code then
+ local a = getattr(current,a_realign)
if not a or a == 0 then
-- skip
else
@@ -75,12 +90,12 @@ local function handler(head,leftpage,realpageno)
action = leftpage and 2 or 1
end
if action == 1 then
- current.list = hpack_nodes(current.list .. new_stretch(3),current.width,"exactly")
+ setfield(current,"list",hpack_nodes(linked_nodes(getlist(current),new_stretch(3)),getfield(current,"width"),"exactly"))
if trace_realign then
report_realign("flushing left, align %a, page %a, realpage %a",align,pageno,realpageno)
end
elseif action == 2 then
- current.list = hpack_nodes(new_stretch(3) .. current.list,current.width,"exactly")
+ setfield(current,"list",hpack_nodes(linked_nodes(new_stretch(3),getlist(current)),getfield(current,"width"),"exactly"))
if trace_realign then
report_realign("flushing right. align %a, page %a, realpage %a",align,pageno,realpageno)
end
@@ -90,14 +105,14 @@ local function handler(head,leftpage,realpageno)
done = true
nofrealigned = nofrealigned + 1
end
- current[a_realign] = unsetvalue
+ setattr(current,a_realign,unsetvalue)
end
end
- handler(current.list,leftpage,realpageno)
+ handler(getlist(current),leftpage,realpageno)
elseif id == vlist_code then
- handler(current.list,leftpage,realpageno)
+ handler(getlist(current),leftpage,realpageno)
end
- current = current.next
+ current = getnext(current)
end
return head, done
end
@@ -105,7 +120,8 @@ end
function alignments.handler(head)
local leftpage = isleftpage(true,false)
local realpageno = texgetcount("realpageno")
- return handler(head,leftpage,realpageno)
+ local head, done = handler(tonut(head),leftpage,realpageno)
+ return tonode(head), done
end
local enabled = false
diff --git a/tex/context/base/spac-chr.lua b/tex/context/base/spac-chr.lua
index db98b42a6..4122a64b6 100644
--- a/tex/context/base/spac-chr.lua
+++ b/tex/context/base/spac-chr.lua
@@ -22,14 +22,29 @@ report_characters = logs.reporter("typesetting","characters")
local nodes, node = nodes, node
-local insert_node_after = nodes.insert_after
-local remove_node = nodes.remove
-local copy_node_list = nodes.copy_list
-local traverse_id = nodes.traverse_id
+local nuts = nodes.nuts
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local copy_node_list = nuts.copy_list
+local traverse_id = nuts.traverse_id
local tasks = nodes.tasks
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_glue = nodepool.glue
@@ -63,48 +78,47 @@ local c_zero = byte('0')
local c_period = byte('.')
local function inject_quad_space(unicode,head,current,fraction)
- local attr = current.attr
+ local attr = getfield(current,"attr")
if fraction ~= 0 then
- fraction = fraction * fontquads[current.font]
+ fraction = fraction * fontquads[getfont(current)]
end
local glue = new_glue(fraction)
--- glue.attr = copy_node_list(attr)
- glue.attr = attr
- current.attr = nil
- glue[a_character] = unicode
+ setfield(glue,"attr",attr)
+ setfield(current,"attr",nil)
+ setattr(glue,a_character,unicode)
head, current = insert_node_after(head,current,glue)
return head, current
end
local function inject_char_space(unicode,head,current,parent)
- local attr = current.attr
- local font = current.font
+ local attr = getfield(current,"attr")
+ local font = getfont(current)
local char = fontcharacters[font][parent]
local glue = new_glue(char and char.width or fontparameters[font].space)
- glue.attr = current.attr
- current.attr = nil
- glue[a_character] = unicode
+ setfield(glue,"attr",attr)
+ setfield(current,"attr",nil)
+ setattr(glue,a_character,unicode)
head, current = insert_node_after(head,current,glue)
return head, current
end
local function inject_nobreak_space(unicode,head,current,space,spacestretch,spaceshrink)
- local attr = current.attr
+ local attr = getfield(current,"attr")
local glue = new_glue(space,spacestretch,spaceshrink)
local penalty = new_penalty(10000)
- glue.attr = attr
- current.attr = nil
- glue[a_character] = unicode
+ setfield(glue,"attr",attr)
+ setfield(current,"attr",nil)
+ setattr(glue,a_character,unicode)
head, current = insert_node_after(head,current,penalty)
head, current = insert_node_after(head,current,glue)
return head, current
end
local function nbsp(head,current)
- local para = fontparameters[current.font]
- if current[a_alignstate] == 1 then -- flushright
+ local para = fontparameters[getfont(current)]
+ if getattr(current,a_alignstate) == 1 then -- flushright
head, current = inject_nobreak_space(0x00A0,head,current,para.space,0,0)
- current.subtype = space_skip_code
+ setfield(current,"subtype",space_skip_code)
else
head, current = inject_nobreak_space(0x00A0,head,current,para.space,para.spacestretch,para.spaceshrink)
end
@@ -121,7 +135,7 @@ end
function characters.replacenbspaces(head)
for current in traverse_id(glyph_code,head) do
- if current.char == 0x00A0 then
+ if getchar(current) == 0x00A0 then
local h = nbsp(head,current)
if h then
head = remove_node(h,current,true)
@@ -147,21 +161,21 @@ local methods = {
-- don't have the 'local' value.
[0x00A0] = function(head,current) -- nbsp
- local next = current.next
- if next and next.id == glyph_code then
- local char = next.char
+ local next = getnext(current)
+ if next and getid(next) == glyph_code then
+ local char = getchar(next)
if char == 0x200C or char == 0x200D then -- nzwj zwj
- next = next.next
- if next and nbsphash[next.char] then
+ next = getnext(next)
+ if next and nbsphash[getchar(next)] then
return false
end
elseif nbsphash[char] then
return false
end
end
- local prev = current.prev
- if prev and prev.id == glyph_code and nbsphash[prev.char] then
- return false -- kannada
+ local prev = getprev(current)
+ if prev and getid(prev) == glyph_code and nbsphash[getchar(prev)] then
+ return false
end
return nbsp(head,current)
end,
@@ -215,11 +229,11 @@ local methods = {
end,
[0x202F] = function(head,current) -- narrownobreakspace
- return inject_nobreak_space(0x202F,head,current,fontquads[current.font]/8)
+ return inject_nobreak_space(0x202F,head,current,fontquads[getfont(current)]/8)
end,
[0x205F] = function(head,current) -- math thinspace
- return inject_nobreak_space(0x205F,head,current,fontparameters[current.font].space/8)
+ return inject_nobreak_space(0x205F,head,current,fontparameters[getfont(current)].space/8)
end,
-- [0xFEFF] = function(head,current) -- zerowidthnobreakspace
@@ -228,14 +242,15 @@ local methods = {
}
-function characters.handler(head)
+function characters.handler(head) -- todo: use traverse_id
+ head = tonut(head)
local current = head
local done = false
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local next = current.next
- local char = current.char
+ local next = getnext(current)
+ local char = getchar(current)
local method = methods[char]
if method then
if trace_characters then
@@ -249,8 +264,8 @@ function characters.handler(head)
end
current = next
else
- current = current.next
+ current = getnext(current)
end
end
- return head, done
+ return tonode(head), done
end
diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua
index 0035c4119..960180dc2 100644
--- a/tex/context/base/spac-ver.lua
+++ b/tex/context/base/spac-ver.lua
@@ -37,7 +37,6 @@ local nodes, node, trackers, attributes, context, commands, tex = nodes, node,
local texlists = tex.lists
local texgetdimen = tex.getdimen
local texnest = tex.nest
-local texgetbox = tex.getbox
local variables = interfaces.variables
@@ -63,23 +62,41 @@ local a_skiporder = attributes.private('skiporder')
local a_snapmethod = attributes.private('snapmethod')
local a_snapvbox = attributes.private('snapvbox')
-local find_node_tail = node.tail
-local free_node = node.free
-local free_node_list = node.flush_list
-local copy_node = node.copy
-local traverse_nodes = node.traverse
-local traverse_nodes_id = node.traverse_id
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local remove_node = nodes.remove
-local count_nodes = nodes.count
-local nodeidstostring = nodes.idstostring
-local hpack_node = node.hpack
-local vpack_node = node.vpack
-local writable_spec = nodes.writable_spec
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+local ntostring = nuts.tostring
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+local getbox = nuts.getbox
+
+local find_node_tail = nuts.tail
+local free_node = nuts.free
+local free_node_list = nuts.flush_list
+local copy_node = nuts.copy
+local traverse_nodes = nuts.traverse
+local traverse_nodes_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local count_nodes = nuts.count
+local hpack_node = nuts.hpack
+local vpack_node = nuts.vpack
+local writable_spec = nuts.writable_spec
+local nodereference = nuts.reference
+
local listtoutf = nodes.listtoutf
+local nodeidstostring = nodes.idstostring
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_kern = nodepool.kern
@@ -179,28 +196,26 @@ end
-- local rule_id = nodecodes.rule
-- local vlist_id = nodecodes.vlist
-- function nodes.makevtop(n)
--- if n.id == vlist_id then
--- local list = n.list
--- local height = (list and list.id <= rule_id and list.height) or 0
--- n.depth = n.depth - height + n.height
--- n.height = height
+-- if getid(n) == vlist_id then
+-- local list = getlist(n)
+-- local height = (list and getid(list) <= rule_id and getfield(list,"height")) or 0
+-- setfield(n,"depth",getfield(n,"depth") - height + getfield(n,"height")
+-- setfield(n,"height",height
-- end
-- end
-local reference = nodes.reference
-
local function validvbox(parentid,list)
if parentid == hlist_code then
- local id = list.id
+ local id = getid(list)
if id == whatsit_code then -- check for initial par subtype
- list = list.next
+ list = getnext(list)
if not next then
return nil
end
end
local done = nil
for n in traverse_nodes(list) do
- local id = n.id
+ local id = getid(n)
if id == vlist_code or id == hlist_code then
if done then
return nil
@@ -214,9 +229,9 @@ local function validvbox(parentid,list)
end
end
if done then
- local id = done.id
+ local id = getid(done)
if id == hlist_code then
- return validvbox(id,done.list)
+ return validvbox(id,getlist(done))
end
end
return done -- only one vbox
@@ -226,19 +241,19 @@ end
local function already_done(parentid,list,a_snapmethod) -- todo: done when only boxes and all snapped
-- problem: any snapped vbox ends up in a line
if list and parentid == hlist_code then
- local id = list.id
+ local id = getid(list)
if id == whatsit_code then -- check for initial par subtype
- list = list.next
+ list = getnext(list)
if not next then
return false
end
end
--~ local i = 0
for n in traverse_nodes(list) do
- local id = n.id
---~ i = i + 1 print(i,nodecodes[id],n[a_snapmethod])
+ local id = getid(n)
+--~ i = i + 1 print(i,nodecodes[id],getattr(n,a_snapmethod))
if id == hlist_code or id == vlist_code then
- local a = n[a_snapmethod]
+ local a = getattr(n,a_snapmethod)
if not a then
-- return true -- not snapped at all
elseif a == 0 then
@@ -276,11 +291,11 @@ end
-- check variables.none etc
local function snap_hlist(where,current,method,height,depth) -- method.strut is default
- local list = current.list
+ local list = getlist(current)
local t = trace_vsnapping and { }
if t then
t[#t+1] = formatters["list content: %s"](listtoutf(list))
- t[#t+1] = formatters["parent id: %s"](reference(current))
+ t[#t+1] = formatters["parent id: %s"](nodereference(current))
t[#t+1] = formatters["snap method: %s"](method.name)
t[#t+1] = formatters["specification: %s"](method.specification)
end
@@ -312,7 +327,8 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["auto: snapht %p snapdp %p"](snapht,snapdp)
end
end
- local h, d = height or current.height, depth or current.depth
+ local h = height or getfield(current,"height")
+ local d = depth or getfield(current,"depth")
local hr, dr, ch, cd = method.hfraction or 1, method.dfraction or 1, h, d
local tlines, blines = method.tlines or 1, method.blines or 1
local done, plusht, plusdp = false, snapht, snapdp
@@ -339,22 +355,22 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
if method.first then
local thebox = current
- local id = thebox.id
+ local id = getid(thebox)
if id == hlist_code then
- thebox = validvbox(id,thebox.list)
- id = thebox and thebox.id
+ thebox = validvbox(id,getlist(thebox))
+ id = thebox and getid(thebox)
end
if thebox and id == vlist_code then
- local list = thebox.list
+ local list = getlist(thebox)
local lh, ld
for n in traverse_nodes_id(hlist_code,list) do
- lh = n.height
- ld = n.depth
+ lh = getfield(n,"height")
+ ld = getfield(n,"depth")
break
end
if lh then
- local ht = thebox.height
- local dp = thebox.depth
+ local ht = getfield(thebox,"height")
+ local dp = getfield(thebox,"depth")
if t then
t[#t+1] = formatters["first line: height %p depth %p"](lh,ld)
t[#t+1] = formatters["dimensions: height %p depth %p"](ht,dp)
@@ -362,9 +378,9 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
local delta = h - lh
ch, cd = lh, delta + d
h, d = ch, cd
- local shifted = hpack_node(current.list)
- shifted.shift = delta
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",delta)
+ setfield(current,"list",shifted)
done = true
if t then
t[#t+1] = formatters["first: height %p depth %p shift %p"](ch,cd,delta)
@@ -377,20 +393,21 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
end
elseif method.last then
local thebox = current
- local id = thebox.id
+ local id = getid(thebox)
if id == hlist_code then
- thebox = validvbox(id,thebox.list)
- id = thebox and thebox.id
+ thebox = validvbox(id,getlist(thebox))
+ id = thebox and getid(thebox)
end
if thebox and id == vlist_code then
- local list, lh, ld = thebox.list
+ local list = getlist(thebox)
+ local lh, ld
for n in traverse_nodes_id(hlist_code,list) do
- lh = n.height
- ld = n.depth
+ lh = getfield(n,"height")
+ ld = getfield(n,"depth")
end
if lh then
- local ht = thebox.height
- local dp = thebox.depth
+ local ht = getfield(thebox,"height")
+ local dp = getfield(thebox,"depth")
if t then
t[#t+1] = formatters["last line: height %p depth %p" ](lh,ld)
t[#t+1] = formatters["dimensions: height %p depth %p"](ht,dp)
@@ -398,9 +415,9 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
local delta = d - ld
cd, ch = ld, delta + h
h, d = ch, cd
- local shifted = hpack_node(current.list)
- shifted.shift = delta
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",delta)
+ setfield(current,"list",shifted)
done = true
if t then
t[#t+1] = formatters["last: height %p depth %p shift %p"](ch,cd,delta)
@@ -461,25 +478,25 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
if offset then
-- we need to set the attr
if t then
- t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,current.width,current.height,current.depth)
+ t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,getfield(current,"width"),getfield(current,"height"),getfield(current,"depth"))
end
- local shifted = hpack_node(current.list)
- shifted.shift = offset
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",offset)
+ setfield(current,"list",shifted)
if t then
- t[#t+1] = formatters["after offset: %p (width %p height %p depth %p)"](offset,current.width,current.height,current.depth)
+ t[#t+1] = formatters["after offset: %p (width %p height %p depth %p)"](offset,getfield(current,"width"),getfield(current,"height"),getfield(current,"depth"))
end
- shifted[a_snapmethod] = 0
- current[a_snapmethod] = 0
+ setattr(shifted,a_snapmethod,0)
+ setattr(current,a_snapmethod,0)
end
if not height then
- current.height = ch
+ setfield(current,"height",ch)
if t then
t[#t+1] = formatters["forced height: %p"](ch)
end
end
if not depth then
- current.depth = cd
+ setfield(current,"depth",cd)
if t then
t[#t+1] = formatters["forced depth: %p"](cd)
end
@@ -493,17 +510,17 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["final depth: %p -> %p"](d,cd)
end
if t then
- report_snapper("trace: %s type %s\n\t%\n\tt",where,nodecodes[current.id],t)
+ report_snapper("trace: %s type %s\n\t%\n\tt",where,nodecodes[getid(current)],t)
end
return h, d, ch, cd, lines
end
local function snap_topskip(current,method)
- local spec = current.spec
- local w = spec.width
+ local spec = getfield(current,"spec")
+ local w = getfield(spec,"width")
local wd = w
- if spec.writable then
- spec.width = 0
+ if getfield(spec,"writable") then
+ setfield(spec,"width",0)
wd = 0
end
return w, wd
@@ -664,18 +681,18 @@ local trace_list, tracing_info, before, after = { }, false, "", ""
local function nodes_to_string(head)
local current, t = head, { }
while current do
- local id = current.id
+ local id = getid(current)
local ty = nodecodes[id]
if id == penalty_code then
- t[#t+1] = formatters["%s:%s"](ty,current.penalty)
+ t[#t+1] = formatters["%s:%s"](ty,getfield(current,"penalty"))
elseif id == glue_code then -- or id == kern_code then -- to be tested
t[#t+1] = formatters["%s:%p"](ty,current)
elseif id == kern_code then
- t[#t+1] = formatters["%s:%p"](ty,current.kern)
+ t[#t+1] = formatters["%s:%p"](ty,getfield(current,"kern"))
else
t[#t+1] = ty
end
- current = current.next
+ current = getnext(current)
end
return concat(t," + ")
end
@@ -699,7 +716,7 @@ local function trace_info(message, where, what)
end
local function trace_node(what)
- local nt = nodecodes[what.id]
+ local nt = nodecodes[getid(what)]
local tl = trace_list[#trace_list]
if tl and tl[1] == "node" then
trace_list[#trace_list] = { "node", formatters["%s + %s"](tl[2],nt) }
@@ -709,8 +726,8 @@ local function trace_node(what)
end
local function trace_done(str,data)
- if data.id == penalty_code then
- trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,data.penalty) }
+ if getid(data) == penalty_code then
+ trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getfield(data,"penalty")) }
else
trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,data) }
end
@@ -753,17 +770,17 @@ local free_glue_node = free_node
function vspacing.snapbox(n,how)
local sv = snapmethods[how]
if sv then
- local box = texgetbox(n)
- local list = box.list
+ local box = getbox(n)
+ local list = getlist(box)
if list then
- local s = list[a_snapmethod]
+ local s = getattr(list,a_snapmethod)
if s == 0 then
if trace_vsnapping then
-- report_snapper("box list not snapped, already done")
end
else
- local ht = box.height
- local dp = box.depth
+ local ht = getfield(box,"height")
+ local dp = getfield(box,"depth")
if false then -- todo: already_done
-- assume that the box is already snapped
if trace_vsnapping then
@@ -772,14 +789,14 @@ function vspacing.snapbox(n,how)
end
else
local h, d, ch, cd, lines = snap_hlist("box",box,sv,ht,dp)
- box.height= ch
- box.depth = cd
+ setfield(box,"height",ch)
+ setfield(box,"depth",cd)
if trace_vsnapping then
report_snapper("box list snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s",
h,d,ch,cd,sv.name,sv.specification,"direct",lines,listtoutf(list))
end
- box[a_snapmethod] = 0 --
- list[a_snapmethod] = 0 -- yes or no
+ setattr(box,a_snapmethod,0) --
+ setattr(list,a_snapmethod,0) -- yes or no
end
end
end
@@ -801,8 +818,10 @@ local w, h, d = 0, 0, 0
----- w, h, d = 100*65536, 65536, 65536
local function forced_skip(head,current,width,where,trace)
- if head == current and head.subtype == baselineskip_code then
- width = width - head.spec.width
+ if head == current then
+ if getsubtype(head) == baselineskip_code then
+ width = width - getfield(getfield(head,"spec"),"width")
+ end
end
if width == 0 then
-- do nothing
@@ -834,25 +853,25 @@ local special_penalty_max = 35000
local function specialpenalty(start,penalty)
-- nodes.showsimplelist(texlists.page_head,1)
- local current = find_node_tail(texlists.page_head)
+ local current = find_node_tail(tonut(texlists.page_head)) -- no texlists.page_tail yet
while current do
- local id = current.id
+ local id = getid(current)
if id == glue_code then
- current = current.prev
+ current = getprev(current)
elseif id == penalty_code then
- local p = current.penalty
+ local p = getfield(current,"penalty")
if p == penalty then
if trace_vspacing then
report_vspacing("overloading penalty %a",p)
end
return current
elseif p >= 10000 then
- current = current.prev
+ current = getprev(current)
else
break
end
else
- current = current.prev
+ current = getprev(current)
end
end
end
@@ -875,12 +894,12 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
head = insert_node_before(head,current,p)
end
if glue_data then
- local spec = glue_data.spec
+ local spec = getfield(glue_data,"spec")
if force_glue then
if trace then trace_done("flushed due to " .. why,glue_data) end
- head = forced_skip(head,current,spec.width,"before",trace)
+ head = forced_skip(head,current,getfield(spec,"width"),"before",trace)
free_glue_node(glue_data)
- elseif spec.writable then
+ elseif getfield(spec,"writable") then
if trace then trace_done("flushed due to " .. why,glue_data) end
head = insert_node_before(head,current,glue_data)
else
@@ -900,12 +919,12 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
end
if trace then trace_info("start analyzing",where,what) end
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code or id == vlist_code then
-- needs checking, why so many calls
if snap then
- local list = current.list
- local s = current[a_snapmethod]
+ local list = getlist(current)
+ local s = getattr(current,a_snapmethod)
if not s then
-- if trace_vsnapping then
-- report_snapper("mvl list not snapped")
@@ -919,8 +938,8 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
if sv then
-- check if already snapped
if list and already_done(id,list,a_snapmethod) then
- local ht = current.height
- local dp = current.depth
+ local ht = getfield(current,"height")
+ local dp = getfield(current,"depth")
-- assume that the box is already snapped
if trace_vsnapping then
report_snapper("mvl list already snapped at (%p,%p): %s",ht,dp,listtoutf(list))
@@ -935,37 +954,37 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
elseif trace_vsnapping then
report_snapper("mvl %a not snapped due to unknown snap specification: %s",nodecodes[id],listtoutf(list))
end
- current[a_snapmethod] = 0
+ setattr(current,a_snapmethod,0)
end
else
--
end
-- tex.prevdepth = 0
flush("list")
- current = current.next
+ current = getnext(current)
elseif id == penalty_code then
- -- natural_penalty = current.penalty
+ -- natural_penalty = getfield(current,"penalty")
-- if trace then trace_done("removed penalty",current) end
-- head, current = remove_node(head, current, true)
- current = current.next
+ current = getnext(current)
elseif id == kern_code then
- if snap and trace_vsnapping and current.kern ~= 0 then
- report_snapper("kern of %p kept",current.kern)
+ if snap and trace_vsnapping and getfield(current,"kern") ~= 0 then
+ report_snapper("kern of %p kept",getfield(current,"kern"))
end
flush("kern")
- current = current.next
+ current = getnext(current)
elseif id == glue_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == userskip_code then
- local sc = current[a_skipcategory] -- has no default, no unset (yet)
- local so = current[a_skiporder] or 1 -- has 1 default, no unset (yet)
- local sp = current[a_skippenalty] -- has no default, no unset (yet)
+ local sc = getattr(current,a_skipcategory) -- has no default, no unset (yet)
+ local so = getattr(current,a_skiporder) or 1 -- has 1 default, no unset (yet)
+ local sp = getattr(current,a_skippenalty) -- has no default, no unset (yet)
if sp and sc == penalty then
if where == "page" and sp >= special_penalty_min and sp <= special_penalty_max then
local previousspecial = specialpenalty(current,sp)
if previousspecial then
- previousspecial.penalty = 0
+ setfield(previousspecial,"penalty",0)
sp = 0
end
end
@@ -983,37 +1002,37 @@ end
if trace then trace_done("flush",glue_data) end
head = insert_node_before(head,current,glue_data)
if trace then trace_natural("natural",current) end
- current = current.next
+ current = getnext(current)
else
-- not look back across head
-- todo: prev can be whatsit (latelua)
- local previous = current.prev
- if previous and previous.id == glue_code and previous.subtype == userskip_code then
- local ps = previous.spec
- if ps.writable then
- local cs = current.spec
- if cs.writable and ps.stretch_order == 0 and ps.shrink_order == 0 and cs.stretch_order == 0 and cs.shrink_order == 0 then
- local pw, pp, pm = ps.width, ps.stretch, ps.shrink
- local cw, cp, cm = cs.width, cs.stretch, cs.shrink
+ local previous = getprev(current)
+ if previous and getid(previous) == glue_code and getsubtype(previous) == userskip_code then
+ local ps = getfield(previous,"spec")
+ if getfield(ps,"writable") then
+ local cs = getfield(current,"spec")
+ if getfield(cs,"writable") and getfield(ps,"stretch_order") == 0 and getfield(ps,"shrink_order") == 0 and getfield(cs,"stretch_order") == 0 and getfield(cs,"shrink_order") == 0 then
+ local pw, pp, pm = getfield(ps,"width"), getfield(ps,"stretch"), getfield(ps,"shrink")
+ local cw, cp, cm = getfield(cs,"width"), getfield(cs,"stretch"), getfield(cs,"shrink")
-- ps = writable_spec(previous) -- no writable needed here
-- ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm
- previous.spec = new_gluespec(pw + cw, pp + cp, pm + cm) -- else topskip can disappear
+ setfield(previous,"spec",new_gluespec(pw + cw, pp + cp, pm + cm)) -- else topskip can disappear
if trace then trace_natural("removed",current) end
head, current = remove_node(head, current, true)
-- current = previous
if trace then trace_natural("collapsed",previous) end
- -- current = current.next
+ -- current = getnext(current)
else
if trace then trace_natural("filler",current) end
- current = current.next
+ current = getnext(current)
end
else
if trace then trace_natural("natural (no prev spec)",current) end
- current = current.next
+ current = getnext(current)
end
else
if trace then trace_natural("natural (no prev)",current) end
- current = current.next
+ current = getnext(current)
end
end
glue_order, glue_data = 0, nil
@@ -1046,12 +1065,12 @@ end
elseif glue_order == so then
-- is now exclusive, maybe support goback as combi, else why a set
if sc == largest then
- local cs, gs = current.spec, glue_data.spec
- local cw, gw = cs.width, gs.width
+ local cs, gs = getfield(current,"spec"), getfield(glue_data,"spec")
+ local cw, gw = getfield(cs,"width"), getfield(gs,"width")
if cw > gw then
if trace then trace_skip("largest",sc,so,sp,current) end
free_glue_node(glue_data) -- also free spec
- head, current, glue_data = remove_node(head, current)
+ head, current, glue_data = remove_node(head,current)
else
if trace then trace_skip("remove smallest",sc,so,sp,current) end
head, current = remove_node(head, current, true)
@@ -1059,7 +1078,7 @@ end
elseif sc == goback then
if trace then trace_skip("goback",sc,so,sp,current) end
free_glue_node(glue_data) -- also free spec
- head, current, glue_data = remove_node(head, current)
+ head, current, glue_data = remove_node(head,current)
elseif sc == force then
-- last one counts, some day we can provide an accumulator and largest etc
-- but not now
@@ -1073,11 +1092,11 @@ end
head, current = remove_node(head, current, true)
elseif sc == add then
if trace then trace_skip("add",sc,so,sp,current) end
- -- local old, new = glue_data.spec, current.spec
- local old, new = writable_spec(glue_data), current.spec
- old.width = old.width + new.width
- old.stretch = old.stretch + new.stretch
- old.shrink = old.shrink + new.shrink
+ -- local old, new = glue_data.spec, getfield(current,"spec")
+ local old, new = writable_spec(glue_data), getfield(current,"spec")
+ setfield(old,"width",getfield(old,"width") + getfield(new,"width"))
+ setfield(old,"stretch",getfield(old,"stretch") + getfield(new,"stretch"))
+ setfield(old,"shrink",getfield(old,"shrink") + getfield(new,"shrink"))
-- toto: order
head, current = remove_node(head, current, true)
else
@@ -1093,12 +1112,13 @@ end
end
elseif subtype == lineskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
- if current.spec.writable then
+ setattr(current,a_snapmethod,0)
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") then
local spec = writable_spec(current)
- spec.width = 0
+ setfield(spec,"width",0)
if trace_vsnapping then
report_snapper("lineskip set to zero")
end
@@ -1111,15 +1131,16 @@ end
if trace then trace_skip("lineskip",sc,so,sp,current) end
flush("lineskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == baselineskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
- if current.spec.writable then
+ setattr(current,a_snapmethod,0)
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") then
local spec = writable_spec(current)
- spec.width = 0
+ setfield(spec,"width",0)
if trace_vsnapping then
report_snapper("baselineskip set to zero")
end
@@ -1132,17 +1153,17 @@ end
if trace then trace_skip("baselineskip",sc,so,sp,current) end
flush("baselineskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == parskip_code then
-- parskip always comes later
if ignore_whitespace then
if trace then trace_natural("ignored parskip",current) end
head, current = remove_node(head, current, true)
elseif glue_data then
- local ps = current.spec
- local gs = glue_data.spec
- if ps.writable and gs.writable and ps.width > gs.width then
- glue_data.spec = copy_node(ps)
+ local ps = getfield(current,"spec")
+ local gs = getfield(glue_data,"spec")
+ if getfield(ps,"writable") and getfield(gs,"writable") and getfield(ps,"width") > getfield(gs,"width") then
+ setfield(glue_data,"spec",copy_node(ps))
if trace then trace_natural("taking parskip",current) end
else
if trace then trace_natural("removed parskip",current) end
@@ -1154,9 +1175,9 @@ end
end
elseif subtype == topskip_code or subtype == splittopskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
+ setattr(current,a_snapmethod,0)
local sv = snapmethods[s]
local w, cw = snap_topskip(current,sv)
if trace_vsnapping then
@@ -1170,46 +1191,46 @@ end
if trace then trace_skip("topskip",sc,so,sp,current) end
flush("topskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == abovedisplayskip_code then
--
if trace then trace_skip("above display skip (normal)",sc,so,sp,current) end
flush("above display skip (normal)")
- current = current.next
+ current = getnext(current)
--
elseif subtype == belowdisplayskip_code then
--
if trace then trace_skip("below display skip (normal)",sc,so,sp,current) end
flush("below display skip (normal)")
- current = current.next
- --
+ current = getnext(current)
+ --
elseif subtype == abovedisplayshortskip_code then
--
if trace then trace_skip("above display skip (short)",sc,so,sp,current) end
flush("above display skip (short)")
- current = current.next
+ current = getnext(current)
--
elseif subtype == belowdisplayshortskip_code then
--
if trace then trace_skip("below display skip (short)",sc,so,sp,current) end
flush("below display skip (short)")
- current = current.next
+ current = getnext(current)
--
else -- other glue
if snap and trace_vsnapping then
- local spec = current.spec
- if spec.writable and spec.width ~= 0 then
- report_snapper("glue %p of type %a kept",current.spec.width,skipcodes[subtype])
- -- spec.width = 0
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") and getfield(spec,"width") ~= 0 then
+ report_snapper("glue %p of type %a kept",getfield(spec,"width"),skipcodes[subtype])
+ -- setfield(spec,"width",0)
end
end
- if trace then trace_skip(formatter["glue of type %a"](subtype),sc,so,sp,current) end
+ if trace then trace_skip(formatters["glue of type %a"](subtype),sc,so,sp,current) end
flush("some glue")
- current = current.next
+ current = getnext(current)
end
else
- flush("something else")
- current = current.next
+ flush(formatters["node with id %a"](id))
+ current = getnext(current)
end
end
if trace then trace_info("stop analyzing",where,what) end
@@ -1230,7 +1251,8 @@ end
if not tail then tail = find_node_tail(head) end
if trace then trace_done("result",glue_data) end
if force_glue then
- head, tail = forced_skip(head,tail,glue_data.spec.width,"after",trace)
+ local spec = getfield(glue_data,"spec")
+ head, tail = forced_skip(head,tail,getfield(spec,"width"),"after",trace)
free_glue_node(glue_data)
else
head, tail = insert_node_after(head,tail,glue_data)
@@ -1243,7 +1265,7 @@ texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevd
end
show_tracing(head)
if oldhead ~= head then
- trace_info("head has been changed from %a to %a",nodecodes[oldhead.id],nodecodes[head.id])
+ trace_info("head has been changed from %a to %a",nodecodes[getid(oldhead)],nodecodes[getid(head)])
end
end
return head, true
@@ -1271,16 +1293,17 @@ end
function vspacing.pagehandler(newhead,where)
-- local newhead = texlists.contrib_head
if newhead then
+ newhead = tonut(newhead)
local newtail = find_node_tail(newhead) -- best pass that tail, known anyway
local flush = false
stackhack = true -- todo: only when grid snapping once enabled
-- todo: fast check if head = tail
for n in traverse_nodes(newhead) do -- we could just look for glue nodes
- local id = n.id
+ local id = getid(n)
if id ~= glue_code then
flush = true
- elseif n.subtype == userskip_code then
- if n[a_skipcategory] then
+ elseif getsubtype(n) == userskip_code then
+ if getattr(n,a_skipcategory) then
stackhack = true
else
flush = true
@@ -1292,35 +1315,36 @@ function vspacing.pagehandler(newhead,where)
if flush then
if stackhead then
if trace_collect_vspacing then report("appending %s nodes to stack (final): %s",newhead) end
- stacktail.next = newhead
- newhead.prev = stacktail
+ setfield(stacktail,"next",newhead)
+ setfield(newhead,"prev",stacktail)
newhead = stackhead
stackhead, stacktail = nil, nil
end
if stackhack then
stackhack = false
if trace_collect_vspacing then report("processing %s nodes: %s",newhead) end
- -- texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
- newhead = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
+ -- texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
+ newhead = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
else
if trace_collect_vspacing then report("flushing %s nodes: %s",newhead) end
-- texlists.contrib_head = newhead
end
+ return tonode(newhead)
else
if stackhead then
if trace_collect_vspacing then report("appending %s nodes to stack (intermediate): %s",newhead) end
- stacktail.next = newhead
- newhead.prev = stacktail
+ setfield(stacktail,"next",newhead)
+ setfield(newhead,"prev",stacktail)
else
if trace_collect_vspacing then report("storing %s nodes in stack (initial): %s",newhead) end
stackhead = newhead
end
stacktail = newtail
-- texlists.contrib_head = nil
- newhead = nil
+ -- newhead = nil
end
end
- return newhead
+ return nil
end
local ignore = table.tohash {
@@ -1330,18 +1354,23 @@ local ignore = table.tohash {
}
function vspacing.vboxhandler(head,where)
- if head and not ignore[where] and head.next then
- head = collapser(head,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper
+ if head and not ignore[where] then
+ local h = tonut(head)
+ if getnext(h) then
+ h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper
+ return tonode(h)
+ end
end
return head
end
function vspacing.collapsevbox(n) -- for boxes but using global a_snapmethod
- local box = texgetbox(n)
+ local box = getbox(n)
if box then
- local list = box.list
+ local list = getlist(box)
if list then
- box.list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod))
+ list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod)
+ setfield(box,"list",vpack_node(list))
end
end
end
@@ -1352,7 +1381,9 @@ end
local outer = texnest[0]
function vspacing.resetprevdepth()
- outer.prevdepth = 0
+ if texlists.hold_head then
+ outer.prevdepth = 0
+ end
end
-- interface
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index 7782770b4..357d89ed7 100644
--- a/tex/context/base/status-files.pdf
+++ b/tex/context/base/status-files.pdf
Binary files differ
diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf
index e1fb8dcc7..3d1e83812 100644
--- a/tex/context/base/status-lua.pdf
+++ b/tex/context/base/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/strc-mar.lua b/tex/context/base/strc-mar.lua
index b3a6e8f35..258787d0a 100644
--- a/tex/context/base/strc-mar.lua
+++ b/tex/context/base/strc-mar.lua
@@ -19,14 +19,27 @@ local commands = commands
local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
-local traversenodes = nodes.traverse
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getbox = nuts.getbox
+
+local traversenodes = nuts.traverse
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local texsetattribute = tex.setattribute
-local texgetbox = tex.getbox
local a_marks = attributes.private("structure","marks")
@@ -106,9 +119,9 @@ end
local function sweep(head,first,last)
for n in traversenodes(head) do
- local id = n.id
+ local id = getid(n)
if id == glyph_code then
- local a = n[a_marks]
+ local a = getattr(n,a_marks)
if not a then
-- next
elseif first == 0 then
@@ -118,7 +131,7 @@ local function sweep(head,first,last)
end
elseif id == hlist_code or id == vlist_code then
if boxes_too then
- local a = n[a_marks]
+ local a = getattr(n,a_marks)
if not a then
-- next
elseif first == 0 then
@@ -127,7 +140,7 @@ local function sweep(head,first,last)
last = a
end
end
- local list = n.list
+ local list = getlist(n)
if list then
first, last = sweep(list,first,last)
end
@@ -143,9 +156,9 @@ setmetatableindex(classes, function(t,k) local s = settings_to_array(k) t[k] = s
local lasts = { }
function marks.synchronize(class,n,option)
- local box = texgetbox(n)
+ local box = getbox(n)
if box then
- local first, last = sweep(box.list,0,0)
+ local first, last = sweep(getlist(box),0,0)
if option == v_keep and first == 0 and last == 0 then
if trace_marks_get or trace_marks_set then
report_marks("action %a, class %a, box %a","retain at synchronize",class,n)
diff --git a/tex/context/base/supp-box.lua b/tex/context/base/supp-box.lua
index 27078f46f..3c5a3383d 100644
--- a/tex/context/base/supp-box.lua
+++ b/tex/context/base/supp-box.lua
@@ -26,101 +26,118 @@ local glue_code = nodecodes.glue
local kern_code = nodecodes.kern
local glyph_code = nodecodes.glyph
-local new_penalty = nodes.pool.penalty
-local new_hlist = nodes.pool.hlist
-local new_glue = nodes.pool.glue
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
-local free_node = nodes.free
-local copy_list = nodes.copy_list
-local copy_node = nodes.copy
-local find_tail = nodes.tail
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattribute = nuts.getattribute
+local getbox = nuts.getbox
+
+local setfield = nuts.setfield
+local setbox = nuts.setbox
+
+local free_node = nuts.free
+local copy_list = nuts.copy_list
+local copy_node = nuts.copy
+local find_tail = nuts.tail
+
+local listtoutf = nodes.listtoutf
+
+local nodepool = nuts.pool
+local new_penalty = nodepool.penalty
+local new_hlist = nodepool.hlist
+local new_glue = nodepool.glue
-local texsetbox = tex.setbox
-local texgetbox = tex.getbox
local texget = tex.get
-local function hyphenatedlist(list)
- while list do
- local id, next, prev = list.id, list.next, list.prev
+local function hyphenatedlist(head)
+ local current = head and tonut(head)
+ while current do
+ local id = getid(current)
+ local next = getnext(current)
+ local prev = getprev(current)
if id == disc_code then
- local hyphen = list.pre
+ local hyphen = getfield(current,"pre")
if hyphen then
local penalty = new_penalty(-500)
- hyphen.next, penalty.prev = penalty, hyphen
- prev.next, next.prev = hyphen, penalty
- penalty.next, hyphen.prev = next, prev
- list.pre = nil
- free_node(list)
+ -- insert_after etc
+ setfield(hyphen,"next",penalty)
+ setfield(penalty,"prev",hyphen)
+ setfield(prev,"next",hyphen)
+ setfield(next,"prev", penalty)
+ setfield(penalty,"next",next)
+ setfield(hyphen,"prev",prev)
+ setfield(current,"pre",nil)
+ free_node(current)
end
elseif id == vlist_code or id == hlist_code then
- hyphenatedlist(list.list)
+ hyphenatedlist(getlist(current))
end
- list = next
+ current = next
end
end
commands.hyphenatedlist = hyphenatedlist
function commands.showhyphenatedinlist(list)
- report_hyphenation("show: %s",nodes.listtoutf(list,false,true))
+ report_hyphenation("show: %s",listtoutf(tonut(list),false,true))
end
local function checkedlist(list)
if type(list) == "number" then
- return texgetbox(list).list
+ return getlist(getbox(tonut(list)))
else
- return list
+ return tonut(list)
end
end
-local function applytochars(list,what,nested)
- local doaction = context[what or "ruledhbox"]
- local noaction = context
- local current = checkedlist(list)
+local function applytochars(current,doaction,noaction,nested)
while current do
- local id = current.id
+ local id = getid(current)
if nested and (id == hlist_code or id == vlist_code) then
context.beginhbox()
- applytochars(current.list,what,nested)
+ applytochars(getlist(current),what,nested)
context.endhbox()
elseif id ~= glyph_code then
- noaction(copy_node(current))
+ noaction(tonode(copy_node(current)))
else
- doaction(copy_node(current))
+ doaction(tonode(copy_node(current)))
end
- current = current.next
+ current = getnext(current)
end
end
-local function applytowords(list,what,nested)
- local doaction = context[what or "ruledhbox"]
- local noaction = context
- local current = checkedlist(list)
+local function applytowords(current,doaction,noaction,nested)
local start
while current do
- local id = current.id
+ local id = getid(current)
if id == glue_code then
if start then
- doaction(copy_list(start,current))
+ doaction(tonode(copy_list(start,current)))
start = nil
end
- noaction(copy_node(current))
+ noaction(tonode(copy_node(current)))
elseif nested and (id == hlist_code or id == vlist_code) then
context.beginhbox()
- applytowords(current.list,what,nested)
+ applytowords(getlist(current),what,nested)
context.egroup()
elseif not start then
start = current
end
- current = current.next
+ current = getnext(current)
end
if start then
- doaction(copy_list(start))
+ doaction(tonode(copy_list(start)))
end
end
-commands.applytochars = applytochars
-commands.applytowords = applytowords
+commands.applytochars = function(list,what,nested) applytochars(checkedlist(list),context[what or "ruledhbox"],context,nested) end
+commands.applytowords = function(list,what,nested) applytowords(checkedlist(list),context[what or "ruledhbox"],context,nested) end
local split_char = lpeg.Ct(lpeg.C(1)^0)
local split_word = lpeg.tsplitat(lpeg.patterns.space)
@@ -176,36 +193,36 @@ end
local a_vboxtohboxseparator = attributes.private("vboxtohboxseparator")
function commands.vboxlisttohbox(original,target,inbetween)
- local current = texgetbox(original).list
+ local current = getlist(getbox(original))
local head = nil
local tail = nil
while current do
- local id = current.id
- local next = current.next
+ local id = getid(current)
+ local next = getnext(current)
if id == hlist_code then
- local list = current.list
+ local list = getlist(current)
if head then
if inbetween > 0 then
local n = new_glue(0,0,inbetween)
- tail.next = n
- n.prev = tail
+ setfield(tail,"next",n)
+ setfield(n,"prev",tail)
tail = n
end
- tail.next = list
- list.prev = tail
+ setfield(tail,"next",list)
+ setfield(list,"prev",tail)
else
head = list
end
tail = find_tail(list)
-- remove last separator
- if tail.id == hlist_code and tail[a_vboxtohboxseparator] == 1 then
+ if getid(tail) == hlist_code and getattribute(tail,a_vboxtohboxseparator) == 1 then
local temp = tail
- local prev = tail.prev
+ local prev = getprev(tail)
if next then
- local list = tail.list
- prev.next = list
- list.prev = prev
- tail.list = nil
+ local list = getlist(tail)
+ setfield(prev,"next",list)
+ setfield(list,"prev",prev)
+ setfield(tail,"list",nil)
tail = find_tail(list)
else
tail = prev
@@ -213,21 +230,21 @@ function commands.vboxlisttohbox(original,target,inbetween)
free_node(temp)
end
-- done
- tail.next = nil
- current.list = nil
+ setfield(tail,"next",nil)
+ setfield(current,"list",nil)
end
current = next
end
local result = new_hlist()
- result.list = head
- texsetbox(target,result)
+ setfield(result,"list",head)
+ setbox(target,result)
end
function commands.hboxtovbox(original)
- local b = texgetbox(original)
+ local b = getbox(original)
local factor = texget("baselineskip").width / texget("hsize")
- b.depth = 0
- b.height = b.width * factor
+ setfield(b,"depth",0)
+ setfield(b,"height",getfield(b,"width") * factor)
end
function commands.boxtostring(n)
diff --git a/tex/context/base/tabl-xtb.lua b/tex/context/base/tabl-xtb.lua
index 488ef5b78..653eb6e08 100644
--- a/tex/context/base/tabl-xtb.lua
+++ b/tex/context/base/tabl-xtb.lua
@@ -25,18 +25,21 @@ this mechamism will be improved so that it can replace its older cousin.
-- todo: use linked list instead of r/c array
-local commands, context, tex, node = commands, context, tex, node
+local tonumber = tonumber
-local texgetcount = tex.getcount
-local texsetcount = tex.setcount
-local texgetbox = tex.getbox
-local texgetdimen = tex.getdimen
-local texsetdimen = tex.setdimen
-local texget = tex.get
+local commands = commands
+local context = context
+local tex = tex
+
+local texgetcount = tex.getcount
+local texsetcount = tex.setcount
+local texgetdimen = tex.getdimen
+local texsetdimen = tex.setdimen
+local texget = tex.get
-local format = string.format
-local concat = table.concat
-local points = number.points
+local format = string.format
+local concat = table.concat
+local points = number.points
local context = context
local context_beginvbox = context.beginvbox
@@ -49,13 +52,23 @@ local variables = interfaces.variables
local setmetatableindex = table.setmetatableindex
local settings_to_hash = utilities.parsers.settings_to_hash
-local copy_node_list = node.copy_list
-local hpack_node_list = node.hpack
-local vpack_node_list = node.vpack
-local slide_node_list = node.slide
-local flush_node_list = node.flush_list
+local nuts = nodes.nuts -- here nuts gain hardly nothing
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local getbox = nuts.getbox
+
+local setfield = nuts.setfield
-local nodepool = nodes.pool
+local copy_node_list = nuts.copy_list
+local hpack_node_list = nuts.hpack
+local flush_node_list = nuts.flush_list
+
+local nodepool = nuts.pool
local new_glue = nodepool.glue
local new_kern = nodepool.kern
@@ -215,20 +228,20 @@ function xtables.set_reflow_width()
while row[c].span do -- can also be previous row ones
c = c + 1
end
- local tb = texgetbox("b_tabl_x")
+ local tb = getbox("b_tabl_x")
local drc = row[c]
--
drc.list = true -- we don't need to keep the content around as we're in trial mode (no: copy_node_list(tb))
--
- local widths, width = data.widths, tb.width
+ local widths, width = data.widths, getfield(tb,"width")
if width > widths[c] then
widths[c] = width
end
- local heights, height = data.heights, tb.height
+ local heights, height = data.heights, getfield(tb,"height")
if height > heights[r] then
heights[r] = height
end
- local depths, depth = data.depths, tb.depth
+ local depths, depth = data.depths, getfield(tb,"depth")
if depth > depths[r] then
depths[r] = depth
end
@@ -319,14 +332,14 @@ function xtables.set_reflow_height()
-- while row[c].span do -- we could adapt drc.nx instead
-- c = c + 1
-- end
- local tb = texgetbox("b_tabl_x")
+ local tb = getbox("b_tabl_x")
local drc = row[c]
if data.fixedrows[r] == 0 then -- and drc.dimensionstate < 2
- local heights, height = data.heights, tb.height
+ local heights, height = data.heights, getfield(tb,"height")
if height > heights[r] then
heights[r] = height
end
- local depths, depth = data.depths, tb.depth
+ local depths, depth = data.depths, getfield(tb,"depth")
if depth > depths[r] then
depths[r] = depth
end
@@ -373,7 +386,7 @@ function xtables.set_construct()
-- end
local drc = row[c]
-- this will change as soon as in luatex we can reset a box list without freeing
- drc.list = copy_node_list(texgetbox("b_tabl_x"))
+ drc.list = copy_node_list(getbox("b_tabl_x"))
-- c = c + drc.nx - 1
-- data.currentcolumn = c
end
@@ -646,23 +659,23 @@ function xtables.construct()
end
local list = drc.list
if list then
- list.shift = list.height + list.depth
+ setfield(list,"shift",getfield(list,"height") + getfield(list,"depth"))
-- list = hpack_node_list(list) -- is somehow needed
- -- list.width = 0
- -- list.height = 0
- -- list.depth = 0
+ -- setfield(list,"width",0)
+ -- setfield(list,"height",0)
+ -- setfield(list,"depth",0)
-- faster:
local h = new_hlist()
- h.list = list
+ setfield(h,"list",list)
list = h
--
if start then
- stop.next = list
- list.prev = stop
+ setfield(stop,"next",list)
+ setfield(list,"prev",stop)
else
start = list
end
- stop = list -- one node anyway, so not needed: slide_node_list(list)
+ stop = list
end
local step = widths[c]
if c < nofcolumns then
@@ -670,8 +683,8 @@ function xtables.construct()
end
local kern = new_kern(step)
if stop then
- stop.next = kern
- kern.prev = stop
+ setfield(stop,"next",kern)
+ setfield(kern,"prev",stop)
else -- can be first spanning next row (ny=...)
start = kern
end
@@ -680,8 +693,8 @@ function xtables.construct()
if start then
if rightmargindistance > 0 then
local kern = new_kern(rightmargindistance)
- stop.next = kern
- kern.prev = stop
+ setfield(stop,"next",kern)
+ setfield(kern,"prev",stop)
-- stop = kern
end
return start, heights[r] + depths[r], hasspan
@@ -721,7 +734,7 @@ function xtables.construct()
texsetdimen("global","d_tabl_x_final_width",0)
else
texsetcount("global","c_tabl_x_state",1)
- texsetdimen("global","d_tabl_x_final_width",body[1][1].width)
+ texsetdimen("global","d_tabl_x_final_width",getfield(body[1][1],"width"))
end
end
@@ -734,8 +747,8 @@ local function inject(row,copy,package)
end
if package then
context_beginvbox()
- context(list)
- context(new_kern(row[2]))
+ context(tonode(list))
+ context(tonode(new_kern(row[2])))
context_endvbox()
context_nointerlineskip() -- figure out a better way
if row[4] then
@@ -743,13 +756,13 @@ local function inject(row,copy,package)
elseif row[3] then
context_blank(row[3] .. "sp") -- why blank ?
else
- context(new_glue(0))
+ context(tonode(new_glue(0)))
end
else
- context(list)
- context(new_kern(row[2]))
+ context(tonode(list))
+ context(tonode(new_kern(row[2])))
if row[3] then
- context(new_glue(row[3]))
+ context(tonode(new_glue(row[3])))
end
end
end
@@ -822,7 +835,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
inject(head[i],repeatheader)
end
if rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
if not repeatheader then
results[head_mode] = { }
@@ -835,7 +848,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
inject(more[i],true)
end
if rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
end
elseif headsize > 0 and repeatheader then -- following chunk gets head
@@ -845,7 +858,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
inject(head[i],true)
end
if rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
end
else -- following chunk gets nothing
@@ -872,7 +885,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
-- all is flushed and footer fits
if footsize > 0 then
if rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
for i=1,#foot do
inject(foot[i])
@@ -886,7 +899,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
-- todo: try to flush a few more lines
if repeatfooter and footsize > 0 then
if rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
for i=1,#foot do
inject(foot[i],true)
@@ -938,13 +951,13 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
inject(head[i])
end
if #head > 0 and rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
for i=1,#body do
inject(body[i])
end
if #foot > 0 and rowdistance > 0 then
- context(new_glue(rowdistance))
+ context(tonode(new_glue(rowdistance)))
end
for i=1,#foot do
inject(foot[i])
@@ -964,6 +977,24 @@ function xtables.cleanup()
flush_node_list(r[1])
end
end
+
+ -- local rows = data.rows
+ -- for i=1,#rows do
+ -- local row = rows[i]
+ -- for i=1,#row do
+ -- local cell = row[i]
+ -- local list = cell.list
+ -- if list then
+ -- cell.width = getfield(list,"width")
+ -- cell.height = getfield(list,"height")
+ -- cell.depth = getfield(list,"depth")
+ -- cell.list = true
+ -- end
+ -- end
+ -- end
+ -- data.result = nil
+ -- inspect(data)
+
data = table.remove(stack)
end
diff --git a/tex/context/base/trac-jus.lua b/tex/context/base/trac-jus.lua
index 38220a752..d95e48816 100644
--- a/tex/context/base/trac-jus.lua
+++ b/tex/context/base/trac-jus.lua
@@ -14,14 +14,29 @@ typesetters.checkers = checkers
local a_alignstate = attributes.private("alignstate")
local a_justification = attributes.private("justification")
-local tracers = nodes.tracers
-local tracedrule = tracers.rule
-
-local new_rule = nodes.pool.rule
-local new_hlist = nodes.pool.hlist
-local new_glue = nodes.pool.glue
-local new_kern = nodes.pool.kern
-local get_list_dimensions = node.dimensions
+local nuts = nodes.nuts
+local tonut = tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local setlist = nuts.setlist
+
+local traverse_id = nuts.travers_id
+local get_list_dimensions = nuts.dimensions
+local linked_nodes = nuts.linked
+local copy_node = nuts.copy
+
+local tracedrule = nodes.tracers.pool.nuts.rule
+
+local nodepool = nuts.pool
+
+local new_rule = nodepool.rule
+local new_hlist = nodepool.hlist
+local new_glue = nodepool.glue
+local new_kern = nodepool.kern
+
local hlist_code = nodes.nodecodes.hlist
local texsetattribute = tex.setattribute
@@ -59,34 +74,35 @@ trackers.register("visualizers.justification", function(v)
end)
function checkers.handler(head)
- for current in node.traverse_id(hlist_code,head) do
- if current[a_justification] == 1 then
- current[a_justification] = 0
- local width = current.width
+ for current in traverse_id(hlist_code,tonut(head)) do
+ if getattr(current,a_justification) == 1 then
+ setattr(current,a_justification,0)
+ local width = setfield(current,"width")
if width > 0 then
- local list = current.list
+ local list = getlist(current)
if list then
local naturalwidth, naturalheight, naturaldepth = get_list_dimensions(list)
local delta = naturalwidth - width
if naturalwidth == 0 or delta == 0 then
-- special box
elseif delta >= max_threshold then
- local rule = tracedrule(delta,naturalheight,naturaldepth,list.glue_set == 1 and "trace:dr"or "trace:db")
- current.list = list .. new_hlist(rule)
+ local rule = tracedrule(delta,naturalheight,naturaldepth,getfield(list,"glue_set") == 1 and "trace:dr" or "trace:db")
+ setfield(current,"list",linked_nodes(list,new_hlist(rule)))
elseif delta <= min_threshold then
- local alignstate = list[a_alignstate]
+ local alignstate = getattr(list,a_alignstate)
if alignstate == 1 then
local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dc")
- current.list = new_hlist(rule) .. list
+ setfield(current,"list",linked_nodes(new_hlist(rule),list))
elseif alignstate == 2 then
- local rule = tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy")
- current.list = new_hlist(rule^1) .. list .. new_kern(delta/2) .. new_hlist(rule)
+ local lrule = tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy")
+ local rrule = copy_node(lrule)
+ setfield(current,"list",linked_nodes(new_hlist(lrule),list,new_kern(delta/2),new_hlist(rrule)))
elseif alignstate == 3 then
local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dm")
- current.list = list .. new_kern(delta) .. new_hlist(rule)
+ setfield(current,"list",linked_nodes(list,new_kern(delta),new_hlist(rule)))
else
local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dg")
- current.list = list .. new_kern(delta) .. new_hlist(rule)
+ setfield(current,"list",linked_nodes(list,new_kern(delta),new_hlist(rule)))
end
end
end
diff --git a/tex/context/base/trac-par.lua b/tex/context/base/trac-par.lua
deleted file mode 100644
index 262a9cc33..000000000
--- a/tex/context/base/trac-par.lua
+++ /dev/null
@@ -1,125 +0,0 @@
--- for the moment here:
-
-local utfchar = utf.char
-local concat = table.concat
-
-local nodecodes = nodes.nodecodes
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local glyph_code = nodecodes.glyph
-local kern_code = nodecodes.kern
-local setnodecolor = nodes.tracers.colors.set
-local parameters = fonts.hashes.parameters
-local basepoints = number.basepoints
-
--- definecolor[hz:positive] [r=0.6]
--- definecolor[hz:negative] [g=0.6]
--- definecolor[hz:zero] [b=0.6]
-
--- scale = multiplier + ef/multiplier
-
-local trace_both = false trackers.register("builders.paragraphs.expansion.both", function(v) trace_verbose = false trace_both = v end)
-local trace_verbose = false trackers.register("builders.paragraphs.expansion.verbose", function(v) trace_verbose = v trace_color = v end)
-
-local report_verbose = logs.reporter("fonts","expansion")
-
-local function colorize(n)
- local size, font, ef, width, list, flush, length
- if trace_verbose then
- width = 0
- length = 0
- list = { }
- flush = function()
- if length > 0 then
- report_verbose("%0.3f : %10s %10s %s",ef/1000,basepoints(width),basepoints(width*ef/1000000),concat(list,"",1,length))
- width = 0
- length = 0
- end
- end
- else
- length = 0
- end
- -- tricky: the built-in method creates dummy fonts and the last line normally has the
- -- original font and that one then has ex.auto set
- while n do
- local id = n.id
- if id == glyph_code then
- local ne = n.expansion_factor
- if ne == 0 then
- if length > 0 then flush() end
- setnodecolor(n,"hz:zero")
- else
- local f = n.font
- if f ~= font then
- if length > 0 then
- flush()
- end
- local pf = parameters[f]
- local ex = pf.expansion
- if ex and ex.auto then
- size = pf.size
- font = f -- save lookups
- else
- size = false
- end
- end
- if size then
- if ne ~= ef then
- if length > 0 then
- flush()
- end
- ef = ne
- end
- if ef > 1 then
- setnodecolor(n,"hz:plus")
- elseif ef < 1 then
- setnodecolor(n,"hz:minus")
- else
- setnodecolor(n,"hz:zero")
- end
- if trace_verbose then
- length = length + 1
- list[length] = utfchar(n.char)
- width = width + n.width -- no kerning yet
- end
- end
- end
- elseif id == hlist_code or id == vlist_code then
- if length > 0 then
- flush()
- end
- colorize(n.list,flush)
- else -- nothing to show on kerns
- if length > 0 then
- flush()
- end
- end
- n = n.next
- end
- if length > 0 then
- flush()
- end
-end
-
-builders.paragraphs.expansion = builders.paragraphs.expansion or { }
-
-function builders.paragraphs.expansion.trace(head)
- colorize(head,true)
- return head
-end
-
-local tasks = nodes.tasks
-
-tasks.prependaction("shipouts","normalizers","builders.paragraphs.expansion.trace")
-tasks.disableaction("shipouts","builders.paragraphs.expansion.trace")
-
-local function set(v)
- if v then
- tasks.enableaction("shipouts","builders.paragraphs.expansion.trace")
- else
- tasks.disableaction("shipouts","builders.paragraphs.expansion.trace")
- end
-end
-
-trackers.register("builders.paragraphs.expansion.verbose",set)
-trackers.register("builders.paragraphs.expansion.both",set)
diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua
index dc8bcc5e7..420e9a00d 100644
--- a/tex/context/base/trac-vis.lua
+++ b/tex/context/base/trac-vis.lua
@@ -34,6 +34,7 @@ local formatters = string.formatters
-- todo: inline concat (more efficient)
local nodecodes = nodes.nodecodes
+local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
local glyph_code = nodecodes.glyph
local hlist_code = nodecodes.hlist
@@ -58,21 +59,41 @@ local rightskip_code = gluecodes.rightskip
local whatsitcodes = nodes.whatsitcodes
-local hpack_nodes = node.hpack
-local vpack_nodes = node.vpack
-local fast_hpack_string = nodes.typesetters.fast_hpack
-local copy_node = node.copy
-local copy_list = node.copy_list
-local free_node = node.free
-local free_node_list = node.flush_list
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local fast_hpack = nodes.fasthpack
-local traverse_nodes = node.traverse
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getbox = nuts.getbox
+local getlist = nuts.getlist
+local getleader = nuts.getleader
+
+local hpack_nodes = nuts.hpack
+local vpack_nodes = nuts.vpack
+local copy_node = nuts.copy
+local copy_list = nuts.copy_list
+local free_node = nuts.free
+local free_node_list = nuts.flush_list
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local traverse_nodes = nuts.traverse
+local linked_nodes = nuts.linked
+
+local fast_hpack = nuts.fasthpack
+local fast_hpack_string = nuts.typesetters.fast_hpack
local texgetattribute = tex.getattribute
local texsetattribute = tex.setattribute
-local texgetbox = tex.getbox
+
local unsetvalue = attributes.unsetvalue
local current_font = font.current
@@ -81,7 +102,7 @@ local exheights = fonts.hashes.exheights
local emwidths = fonts.hashes.emwidths
local pt_factor = number.dimenfactors.pt
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_rule = nodepool.rule
local new_kern = nodepool.kern
local new_glue = nodepool.glue
@@ -293,39 +314,39 @@ local c_white_d = "trace:dw"
local function sometext(str,layer,color,textcolor) -- we can just paste verbatim together .. no typesteting needed
local text = fast_hpack_string(str,usedfont)
- local size = text.width
+ local size = getfield(text,"width")
local rule = new_rule(size,2*exheight,exheight/2)
local kern = new_kern(-size)
if color then
setcolor(rule,color)
end
if textcolor then
- setlistcolor(text.list,textcolor)
+ setlistcolor(getlist(text),textcolor)
end
- local info = rule .. kern .. text
+ local info = linked_nodes(rule,kern,text)
setlisttransparency(info,c_zero)
info = fast_hpack(info)
if layer then
- info[a_layer] = layer
+ setattr(info,a_layer,layer)
end
- local width = info.width
- info.width = 0
- info.height = 0
- info.depth = 0
+ local width = getfield(info,"width")
+ setfield(info,"width",0)
+ setfield(info,"height",0)
+ setfield(info,"depth",0)
return info, width
end
local f_cache = { }
local function fontkern(head,current)
- local kern = current.kern
+ local kern = getfield(current,"kern")
local info = f_cache[kern]
if info then
-- print("hit fontkern")
else
local text = fast_hpack_string(formatters[" %0.3f"](kern*pt_factor),usedfont)
local rule = new_rule(emwidth/10,6*exheight,2*exheight)
- local list = text.list
+ local list = getlist(text)
if kern > 0 then
setlistcolor(list,c_positive_d)
elseif kern < 0 then
@@ -335,13 +356,12 @@ local function fontkern(head,current)
end
setlisttransparency(list,c_text_d)
settransparency(rule,c_text_d)
- text.shift = -5 * exheight
- info = rule .. text
- info = fast_hpack(info)
- info[a_layer] = l_fontkern
- info.width = 0
- info.height = 0
- info.depth = 0
+ setfield(text,"shift",-5 * exheight)
+ info = fast_hpack(linked_nodes(rule,text))
+ setattr(info,a_layer,l_fontkern)
+ setfield(info,"width",0)
+ setfield(info,"height",0)
+ setfield(info,"depth",0)
f_cache[kern] = info
end
head = insert_node_before(head,current,copy_list(info))
@@ -382,7 +402,7 @@ local tags = {
}
local function whatsit(head,current)
- local what = current.subtype
+ local what = getsubtype(current)
local info = w_cache[what]
if info then
-- print("hit whatsit")
@@ -390,7 +410,7 @@ local function whatsit(head,current)
local tag = whatsitcodes[what]
-- maybe different text colors per tag
info = sometext(formatters["W:%s"](tag and tags[tag] or what),usedfont,nil,c_white)
- info[a_layer] = l_whatsit
+ setattr(info,a_layer,l_whatsit)
w_cache[what] = info
end
head, current = insert_node_after(head,current,copy_list(info))
@@ -398,13 +418,13 @@ local function whatsit(head,current)
end
local function user(head,current)
- local what = current.subtype
+ local what = getsubtype(current)
local info = w_cache[what]
if info then
-- print("hit user")
else
info = sometext(formatters["U:%s"](what),usedfont)
- info[a_layer] = l_user
+ setattr(info,a_layer,l_user)
w_cache[what] = info
end
head, current = insert_node_after(head,current,copy_list(info))
@@ -414,14 +434,14 @@ end
local b_cache = { }
local function ruledbox(head,current,vertical,layer,what,simple,previous)
- local wd = current.width
+ local wd = getfield(current,"width")
if wd ~= 0 then
- local ht = current.height
- local dp = current.depth
- local next = current.next
- local prev = previous -- current.prev ... prev can be wrong in math mode
- current.next = nil
- current.prev = nil
+ local ht = getfield(current,"height")
+ local dp = getfield(current,"depth")
+ local next = getnext(current)
+ local prev = previous -- getprev(current) ... prev can be wrong in math mode
+ setfield(current,"next",nil)
+ setfield(current,"prev",nil)
local linewidth = emwidth/10
local baseline, baseskip
if dp ~= 0 and ht ~= 0 then
@@ -430,16 +450,16 @@ local function ruledbox(head,current,vertical,layer,what,simple,previous)
if not baseline then
-- due to an optimized leader color/transparency we need to set the glue node in order
-- to trigger this mechanism
- local leader = new_glue(2*linewidth) .. new_rule(6*linewidth,linewidth,0) .. new_glue(2*linewidth)
+ local leader = linked_nodes(new_glue(2*linewidth),new_rule(6*linewidth,linewidth,0),new_glue(2*linewidth))
-- setlisttransparency(leader,c_text)
leader = fast_hpack(leader)
-- setlisttransparency(leader,c_text)
baseline = new_glue(0)
- baseline.leader = leader
- baseline.subtype = cleaders_code
- local spec = baseline.spec
- spec.stretch = 65536
- spec.stretch_order = 2
+ setfield(baseline,"leader",leader)
+ setfield(baseline,"subtype",cleaders_code)
+ local spec = getfield(baseline,"spec")
+ setfield(spec,"stretch",65536)
+ setfield(spec,"stretch_order",2)
setlisttransparency(baseline,c_text)
b_cache.baseline = baseline
end
@@ -461,47 +481,49 @@ local function ruledbox(head,current,vertical,layer,what,simple,previous)
this = b_cache[what]
if not this then
local text = fast_hpack_string(what,usedfont)
- this = new_kern(-text.width) .. text
+ this = linked_nodes(new_kern(-getfield(text,"width")),text)
setlisttransparency(this,c_text)
this = fast_hpack(this)
- this.width = 0
- this.height = 0
- this.depth = 0
+ setfield(this,"width",0)
+ setfield(this,"height",0)
+ setfield(this,"depth",0)
b_cache[what] = this
end
end
-- we need to trigger the right mode (else sometimes no whatits)
- local info =
- (this and copy_list(this) or nil) ..
- new_rule(linewidth,ht,dp) ..
- new_rule(wd-2*linewidth,-dp+linewidth,dp) ..
- new_rule(linewidth,ht,dp) ..
- new_kern(-wd+linewidth) ..
+ local info = linked_nodes(
+ this and copy_list(this) or nil,
+ new_rule(linewidth,ht,dp),
+ new_rule(wd-2*linewidth,-dp+linewidth,dp),
+ new_rule(linewidth,ht,dp),
+ new_kern(-wd+linewidth),
new_rule(wd-2*linewidth,ht,-ht+linewidth)
+ )
if baseskip then
- info = info .. baseskip .. baseline
+ info = linked_nodes(info,baseskip,baseline)
end
setlisttransparency(info,c_text)
info = fast_hpack(info)
- info.width = 0
- info.height = 0
- info.depth = 0
- info[a_layer] = layer
- local info = current .. new_kern(-wd) .. info
+ setfield(info,"width",0)
+ setfield(info,"height",0)
+ setfield(info,"depth",0)
+ setattr(info,a_layer,layer)
+ local info = linked_nodes(current,new_kern(-wd),info)
info = fast_hpack(info,wd)
if vertical then
info = vpack_nodes(info)
end
if next then
- info.next = next
- next.prev = info
+ setfield(info,"next",next)
+ setfield(next,"prev",info)
end
if prev then
- if prev.id == gluespec_code then
- -- weird, how can this happen, an inline glue-spec
+ if getid(prev) == gluespec_code then
+ report_visualize("ignoring invalid prev")
+ -- weird, how can this happen, an inline glue-spec, probably math
else
- info.prev = prev
- prev.next = info
+ setfield(info,"prev",prev)
+ setfield(prev,"next",info)
end
end
if head == current then
@@ -515,14 +537,14 @@ local function ruledbox(head,current,vertical,layer,what,simple,previous)
end
local function ruledglyph(head,current,previous)
- local wd = current.width
+ local wd = getfield(current,"width")
if wd ~= 0 then
- local ht = current.height
- local dp = current.depth
- local next = current.next
+ local ht = getfield(current,"height")
+ local dp = getfield(current,"depth")
+ local next = getnext(current)
local prev = previous
- current.next = nil
- current.prev = nil
+ setfield(current,"next",nil)
+ setfield(current,"prev",nil)
local linewidth = emwidth/20
local baseline
if dp ~= 0 and ht ~= 0 then
@@ -530,31 +552,32 @@ local function ruledglyph(head,current,previous)
end
local doublelinewidth = 2*linewidth
-- could be a pdf rule
- local info =
- new_rule(linewidth,ht,dp) ..
- new_rule(wd-doublelinewidth,-dp+linewidth,dp) ..
- new_rule(linewidth,ht,dp) ..
- new_kern(-wd+linewidth) ..
- new_rule(wd-doublelinewidth,ht,-ht+linewidth) ..
- new_kern(-wd+doublelinewidth) ..
+ local info = linked_nodes(
+ new_rule(linewidth,ht,dp),
+ new_rule(wd-doublelinewidth,-dp+linewidth,dp),
+ new_rule(linewidth,ht,dp),
+ new_kern(-wd+linewidth),
+ new_rule(wd-doublelinewidth,ht,-ht+linewidth),
+ new_kern(-wd+doublelinewidth),
baseline
+ )
setlistcolor(info,c_glyph)
setlisttransparency(info,c_glyph_d)
info = fast_hpack(info)
- info.width = 0
- info.height = 0
- info.depth = 0
- info[a_layer] = l_glyph
- local info = current .. new_kern(-wd) .. info
+ setfield(info,"width",0)
+ setfield(info,"height",0)
+ setfield(info,"depth",0)
+ setattr(info,a_layer,l_glyph)
+ local info = linked_nodes(current,new_kern(-wd),info)
info = fast_hpack(info)
- info.width = wd
+ setfield(info,"width",wd)
if next then
- info.next = next
- next.prev = info
+ setfield(info,"next",next)
+ setfield(next,"prev",info)
end
if prev then
- info.prev = prev
- prev.next = info
+ setfield(info,"prev",prev)
+ setfield(prev,"next",info)
end
if head == current then
return info, info
@@ -599,9 +622,9 @@ local tags = {
-- we sometimes pass previous as we can have issues in math (not watertight for all)
local function ruledglue(head,current,vertical)
- local spec = current.spec
- local width = spec.width
- local subtype = current.subtype
+ local spec = getfield(current,"spec")
+ local width = getfield(spec,"width")
+ local subtype = getsubtype(current)
local amount = formatters["%s:%0.3f"](tags[subtype] or (vertical and "VS") or "HS",width*pt_factor)
local info = g_cache[amount]
if info then
@@ -629,13 +652,13 @@ local function ruledglue(head,current,vertical)
info = vpack_nodes(info)
end
head, current = insert_node_before(head,current,info)
- return head, current.next
+ return head, getnext(current)
end
local k_cache = { }
local function ruledkern(head,current,vertical)
- local kern = current.kern
+ local kern = getfield(current,"kern")
local info = k_cache[kern]
if info then
-- print("kern hit")
@@ -655,13 +678,13 @@ local function ruledkern(head,current,vertical)
info = vpack_nodes(info)
end
head, current = insert_node_before(head,current,info)
- return head, current.next
+ return head, getnext(current)
end
local p_cache = { }
local function ruledpenalty(head,current,vertical)
- local penalty = current.penalty
+ local penalty = getfield(current,"penalty")
local info = p_cache[penalty]
if info then
-- print("penalty hit")
@@ -681,7 +704,7 @@ local function ruledpenalty(head,current,vertical)
info = vpack_nodes(info)
end
head, current = insert_node_before(head,current,info)
- return head, current.next
+ return head, getnext(current)
end
local function visualize(head,vertical)
@@ -702,8 +725,8 @@ local function visualize(head,vertical)
local attr = unsetvalue
local prev_trace_fontkern = nil
while current do
- local id = current.id
- local a = current[a_visual] or unsetvalue
+ local id = getid(current)
+ local a = getattr(current,a_visual) or unsetvalue
if a ~= attr then
prev_trace_fontkern = trace_fontkern
if a == unsetvalue then
@@ -736,30 +759,30 @@ local function visualize(head,vertical)
attr = a
end
if trace_strut then
- current[a_layer] = l_strut
+ setattr(current,a_layer,l_strut)
elseif id == glyph_code then
if trace_glyph then
head, current = ruledglyph(head,current,previous)
end
elseif id == disc_code then
if trace_glyph then
- local pre = current.pre
+ local pre = getfield(current,"pre")
if pre then
- current.pre = ruledglyph(pre,pre)
+ setfield(current,"pre",ruledglyph(pre,pre))
end
- local post = current.post
+ local post = getfield(current,"post")
if post then
- current.post = ruledglyph(post,post)
+ setfield(current,"post",ruledglyph(post,post))
end
- local replace = current.replace
+ local replace = getfield(current,"replace")
if replace then
- current.replace = ruledglyph(replace,replace)
+ setfield(current,"replace",ruledglyph(replace,replace))
end
end
elseif id == kern_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
-- tricky ... we don't copy the trace attribute in node-inj (yet)
- if subtype == font_kern_code or current[a_fontkern] then
+ if subtype == font_kern_code or getattr(current,a_fontkern) then
if trace_fontkern or prev_trace_fontkern then
head, current = fontkern(head,current)
end
@@ -769,9 +792,9 @@ local function visualize(head,vertical)
end
end
elseif id == glue_code then
- local content = current.leader
+ local content = getleader(current)
if content then
- current.leader = visualize(content,false)
+ setfield(current,"leader",visualize(content,false))
elseif trace_glue then
head, current = ruledglue(head,current,vertical)
end
@@ -780,21 +803,21 @@ local function visualize(head,vertical)
head, current = ruledpenalty(head,current,vertical)
end
elseif id == disc_code then
- current.pre = visualize(current.pre)
- current.post = visualize(current.post)
- current.replace = visualize(current.replace)
+ setfield(current,"pre",visualize(getfield(current,"pre")))
+ setfield(current,"post",isualize(getfield(current,"post")))
+ setfield(current,"replace",visualize(getfield(current,"replace")))
elseif id == hlist_code then
- local content = current.list
+ local content = getlist(current)
if content then
- current.list = visualize(content,false)
+ setfield(current,"list",visualize(content,false))
end
if trace_hbox then
head, current = ruledbox(head,current,false,l_hbox,"H__",trace_simple,previous)
end
elseif id == vlist_code then
- local content = current.list
+ local content = getlist(current)
if content then
- current.list = visualize(content,true)
+ setfield(current,"list",visualize(content,true))
end
if trace_vtop then
head, current = ruledbox(head,current,true,l_vtop,"_T_",trace_simple,previous)
@@ -811,7 +834,7 @@ local function visualize(head,vertical)
end
end
previous = current
- current = current.next
+ current = getnext(current)
end
return head
end
@@ -840,25 +863,36 @@ local function cleanup()
-- report_visualize("cache: %s fontkerns, %s skips, %s penalties, %s kerns, %s whatsits, %s boxes",nf,ng,np,nk,nw,nb)
end
-function visualizers.handler(head)
+local function handler(head)
if usedfont then
starttiming(visualizers)
-- local l = texgetattribute(a_layer)
-- local v = texgetattribute(a_visual)
-- texsetattribute(a_layer,unsetvalue)
-- texsetattribute(a_visual,unsetvalue)
- head = visualize(head)
+ head = visualize(tonut(head))
-- texsetattribute(a_layer,l)
-- texsetattribute(a_visual,v)
-- -- cleanup()
stoptiming(visualizers)
+ return tonode(head), true
+ else
+ return head, false
end
- return head, false
end
+visualizers.handler = handler
+
function visualizers.box(n)
- local box = texgetbox(n)
- box.list = visualizers.handler(box.list)
+ if usedfont then
+ starttiming(visualizers)
+ local box = getbox(n)
+ setfield(box,"list",visualize(getlist(box)))
+ stoptiming(visualizers)
+ return head, true
+ else
+ return head, false
+ end
end
local last = nil
@@ -872,9 +906,9 @@ local mark = {
local function markfonts(list)
for n in traverse_nodes(list) do
- local id = n.id
+ local id = getid(n)
if id == glyph_code then
- local font = n.font
+ local font = getfont(n)
local okay = used[font]
if not okay then
last = last + 1
@@ -883,14 +917,14 @@ local function markfonts(list)
end
setcolor(n,okay)
elseif id == hlist_code or id == vlist_code then
- markfonts(n.list)
+ markfonts(getlist(n))
end
end
end
function visualizers.markfonts(list)
last, used = 0, { }
- markfonts(type(n) == "number" and texgetbox(n).list or n)
+ markfonts(type(n) == "number" and getlist(getbox(n)) or n)
end
function commands.markfonts(n)
diff --git a/tex/context/base/typo-bld.lua b/tex/context/base/typo-bld.lua
index bc9f66ee4..1cdda7c4b 100644
--- a/tex/context/base/typo-bld.lua
+++ b/tex/context/base/typo-bld.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['typo-bld'] = { -- was node-par
license = "see context related readme files"
}
+-- no need for nuts in the one-line demo (that might move anyway)
+
local insert, remove = table.insert, table.remove
local builders, nodes, node = builders, nodes, node
@@ -36,8 +38,8 @@ local texlists = tex.lists
local nodepool = nodes.pool
local new_baselineskip = nodepool.baselineskip
local new_lineskip = nodepool.lineskip
-local insert_node_before = node.insert_before
-local hpack_node = node.hpack
+local insert_node_before = nodes.insert_before
+local hpack_node = nodes.hpack
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
diff --git a/tex/context/base/typo-brk.lua b/tex/context/base/typo-brk.lua
index 3558efa8e..be11da9c3 100644
--- a/tex/context/base/typo-brk.lua
+++ b/tex/context/base/typo-brk.lua
@@ -20,19 +20,36 @@ local report_breakpoints = logs.reporter("typesetting","breakpoints")
local nodes, node = nodes, node
local settings_to_array = utilities.parsers.settings_to_array
-local copy_node = node.copy
-local copy_nodelist = node.copy_list
-local free_node = node.free
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local remove_node = nodes.remove -- ! nodes
-local tonodes = nodes.tonodes
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+local getfont = nuts.getfont
+local getid = nuts.getid
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local copy_node = nuts.copy
+local copy_nodelist = nuts.copy_list
+local free_node = nuts.free
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+
+local tonodes = nuts.tonodes
local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local tasks = nodes.tasks
local v_reset = interfaces.variables.reset
@@ -80,74 +97,82 @@ local function insert_break(head,start,before,after)
end
methods[1] = function(head,start)
- if start.prev and start.next then
+ if getprev(start) and getnext(start) then
insert_break(head,start,10000,0)
end
return head, start
end
methods[2] = function(head,start) -- ( => (-
- if start.prev and start.next then
+ if getprev(start) and getnext(start) then
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- start.attr = copy_nodelist(tmp.attr) -- todo: critical only
- start.replace = tmp
- local tmp, hyphen = copy_node(tmp), copy_node(tmp)
- hyphen.char = languages.prehyphenchar(tmp.lang)
- tmp.next, hyphen.prev = hyphen, tmp
- start.post = tmp
+ setfield(start,"attr",copy_nodelist(getfield(tmp,"attr")))
+ setfield(start,"replace",tmp)
+ local tmp = copy_node(tmp)
+ local hyphen = copy_node(tmp)
+ setfield(hyphen,"char",languages.prehyphenchar(getfield(tmp,"lang")))
+ setfield(tmp,"next",hyphen)
+ setfield(hyphen,"prev",tmp)
+ setfield(start,"post",tmp)
insert_break(head,start,10000,10000)
end
return head, start
end
methods[3] = function(head,start) -- ) => -)
- if start.prev and start.next then
+ if getprev(start) and getnext(start) then
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- start.attr = copy_nodelist(tmp.attr) -- todo: critical only
- start.replace = tmp
- local tmp, hyphen = copy_node(tmp), copy_node(tmp)
- hyphen.char = languages.prehyphenchar(tmp.lang)
- tmp.prev, hyphen.next = hyphen, tmp
- start.pre = hyphen
+ setfield(start,"attr",copy_nodelist(getfield(tmp,"attr")))
+ setfield(start,"replace",tmp)
+ local tmp = copy_node(tmp)
+ local hyphen = copy_node(tmp)
+ setfield(hyphen,"char",languages.prehyphenchar(getfield(tmp,"lang")))
+ setfield(tmp,"prev",hyphen)
+ setfield(hyphen,"next",tmp)
+ setfield(start,"pre",hyphen)
insert_break(head,start,10000,10000)
end
return head, start
end
methods[4] = function(head,start) -- - => - - -
- if start.prev and start.next then
+ if getprev(start) and getnext(start) then
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- start.attr = copy_nodelist(tmp.attr) -- todo: critical only
- start.pre, start.post, start.replace = copy_node(tmp), copy_node(tmp), tmp
+ setfield(start,"attr",copy_nodelist(getfield(tmp,"attr")))
+ setfield(start,"pre",copy_node(tmp))
+ setfield(start,"post",copy_node(tmp))
+ setfield(start,"replace",tmp)
insert_break(head,start,10000,10000)
end
return head, start
end
methods[5] = function(head,start,settings) -- x => p q r
- if start.prev and start.next then
+ if getprev(start) and getnext(start) then
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- local attr = tmp.attr
- local font = tmp.font
- start.attr = copy_nodelist(attr) -- todo: critical only
- local left, right, middle = settings.left, settings.right, settings.middle
+ local attr = getfield(tmp,"attr")
+ local font = getfont(tmp)
+ local left = settings.left
+ local right = settings.right
+ local middle = settings.middle
if left then
- start.pre = tonodes(tostring(left),font,attr) -- was right
+ setfield(start,"pre",(tonodes(tostring(left),font,attr))) -- was right
end
if right then
- start.post = tonodes(tostring(right),font,attr) -- was left
+ setfield(start,"post",(tonodes(tostring(right),font,attr))) -- was left
end
if middle then
- start.replace = tonodes(tostring(middle),font,attr)
+ setfield(start,"replace",(tonodes(tostring(middle),font,attr)))
end
+ setfield(start,"attr",copy_nodelist(attr)) -- todo: critical only
free_node(tmp)
insert_break(head,start,10000,10000)
end
@@ -155,31 +180,32 @@ methods[5] = function(head,start,settings) -- x => p q r
end
function breakpoints.handler(head)
+ head = tonut(head)
local done, numbers = false, languages.numbers
local start, n = head, 0
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- local attr = start[a_breakpoints]
+ local attr = getattr(start,a_breakpoints)
if attr and attr > 0 then
- start[a_breakpoints] = unsetvalue -- maybe test for subtype > 256 (faster)
+ setattr(start,a_breakpoints,unsetvalue) -- maybe test for subtype > 256 (faster)
-- look ahead and back n chars
local data = mapping[attr]
if data then
local map = data.characters
- local cmap = map[start.char]
+ local cmap = map[getchar(start)]
if cmap then
- local lang = start.lang
+ local lang = getfield(start,"lang")
-- we do a sanity check for language
local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
if smap then
if n >= smap.nleft then
local m = smap.nright
- local next = start.next
+ local next = getnext(start)
while next do -- gamble on same attribute (not that important actually)
- local id = next.id
+ local id = getid(next)
if id == glyph_code then -- gamble on same attribute (not that important actually)
- if map[next.char] then
+ if map[getchar(next)] then
break
elseif m == 1 then
local method = methods[smap.type]
@@ -190,10 +216,10 @@ function breakpoints.handler(head)
break
else
m = m - 1
- next = next.next
+ next = getnext(next)
end
- elseif id == kern_code and next.subtype == kerning_code then
- next = next.next
+ elseif id == kern_code and getsubtype(next) == kerning_code then
+ next = getnext(next)
-- ignore intercharacter kerning, will go way
else
-- we can do clever and set n and jump ahead but ... not now
@@ -214,14 +240,14 @@ function breakpoints.handler(head)
else
-- n = n + 1 -- if we want single char handling (|-|) then we will use grouping and then we need this
end
- elseif id == kern_code and start.subtype == kerning_code then
+ elseif id == kern_code and getsubtype(start) == kerning_code then
-- ignore intercharacter kerning, will go way
else
n = 0
end
- start = start.next
+ start = getnext(start)
end
- return head, done
+ return tonode(head), done
end
local enabled = false
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua
index 0fc1a3093..78ed8700a 100644
--- a/tex/context/base/typo-cap.lua
+++ b/tex/context/base/typo-cap.lua
@@ -16,9 +16,23 @@ local report_casing = logs.reporter("typesetting","casing")
local nodes, node = nodes, node
-local copy_node = nodes.copy
-local end_of_math = nodes.end_of_math
-
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local copy_node = nuts.copy
+local end_of_math = nuts.end_of_math
local nodecodes = nodes.nodecodes
local skipcodes = nodes.skipcodes
@@ -96,14 +110,14 @@ local lccodes = characters.lccodes
-- true false true == mixed
local function helper(start,attr,lastfont,n,codes,special,once,keepother)
- local char = start.char
+ local char = getchar(start)
local dc = codes[char]
if dc then
- local fnt = start.font
+ local fnt = getfont(start)
if keepother and dc == char then
local lfa = lastfont[n]
if lfa then
- start.font = lfa
+ setfield(start,"font",lfa)
return start, true
else
return start, false
@@ -112,10 +126,10 @@ local function helper(start,attr,lastfont,n,codes,special,once,keepother)
if special then
local lfa = lastfont[n]
if lfa then
- local previd = start.prev.id
+ local previd = getid(getprev(start))
if previd ~= glyph_code and previd ~= disc_code then
fnt = lfa
- start.font = lfa
+ setfield(start,"font",lfa)
end
end
end
@@ -137,18 +151,18 @@ local function helper(start,attr,lastfont,n,codes,special,once,keepother)
local chr = dc[i]
prev = start
if i == 1 then
- start.char = chr
+ setfield(start,"char",chr)
else
local g = copy_node(original)
- g.char = chr
- local next = start.next
- g.prev = start
+ setfield(g,"char",chr)
+ local next = getnext(start)
+ setfield(g,"prev",start)
if next then
- g.next = next
- start.next = g
- next.prev = g
+ setfield(g,"next",next)
+ setfield(start,"next",g)
+ setfield(next,"prev",g)
end
- start = g
+ start = g
end
end
if once then
@@ -161,7 +175,7 @@ local function helper(start,attr,lastfont,n,codes,special,once,keepother)
end
return start, false
elseif ifc[dc] then
- start.char = dc
+ setfield(start,"char",dc)
if once then
lastfont[n] = false
end
@@ -203,29 +217,29 @@ local function word(start,attr,lastfont,n)
end
local function blockrest(start)
- local n = start.next
+ local n = getnext(start)
while n do
- local id = n.id
- if id == glyph_code or id == disc_node and n[a_cases] == attr then
- n[a_cases] = unsetvalue
+ local id = getid(n)
+ if id == glyph_code or id == disc_node and getattr(n,a_cases) == attr then
+ setattr(n,a_cases,unsetvalue)
else
-- break -- we can have nested mess
end
- n = n.next
+ n = getnext(n)
end
end
local function Word(start,attr,lastfont,n) -- looks quite complex
lastfont[n] = false
- local prev = start.prev
- if prev and prev.id == kern_code and prev.subtype == kerning_code then
- prev = prev.prev
+ local prev = getprev(start)
+ if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then
+ prev = getprev(prev)
end
if not prev then
blockrest(start)
return helper(start,attr,lastfont,n,uccodes)
end
- local previd = prev.id
+ local previd = getid(prev)
if previd ~= glyph_code and previd ~= disc_code then
-- only the first character is treated
blockrest(start)
@@ -239,14 +253,14 @@ end
local function Words(start,attr,lastfont,n)
lastfont[n] = false
- local prev = start.prev
- if prev and prev.id == kern_code and prev.subtype == kerning_code then
- prev = prev.prev
+ local prev = getprev(start)
+ if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then
+ prev = getprev(prev)
end
if not prev then
return helper(start,attr,lastfont,n,uccodes)
end
- local previd = prev.id
+ local previd = getid(prev)
if previd ~= glyph_code and previd ~= disc_code then
return helper(start,attr,lastfont,n,uccodes)
else
@@ -272,15 +286,15 @@ end
local function random(start,attr,lastfont,n)
lastfont[n] = false
- local ch = start.char
- local tfm = fontchar[start.font]
+ local ch = getchar(start)
+ local tfm = fontchar[getfont(start)]
if lccodes[ch] then
while true do
local d = chardata[randomnumber(1,0xFFFF)]
if d then
local uc = uccodes[d]
if uc and tfm[uc] then -- this also intercepts tables
- start.char = uc
+ setfield(start,"char",uc)
return start, true
end
end
@@ -291,7 +305,7 @@ local function random(start,attr,lastfont,n)
if d then
local lc = lccodes[d]
if lc and tfm[lc] then -- this also intercepts tables
- start.char = lc
+ setfield(start,"char",lc)
return start, true
end
end
@@ -314,19 +328,20 @@ register(variables.cap, variables.capital) -- clone
register(variables.Cap, variables.Capital) -- clone
function cases.handler(head) -- not real fast but also not used on much data
+ head = tonut(head)
local lastfont = { }
local lastattr = nil
local done = false
local start = head
while start do -- while because start can jump ahead
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- local attr = start[a_cases]
+ local attr = getattr(start,a_cases)
if attr and attr > 0 then
if attr ~= lastattr then
lastattr = attr
end
- start[a_cases] = unsetvalue
+ setattr(start,a_cases,unsetvalue)
local n, id, m = get(attr)
if lastfont[n] == nil then
lastfont[n] = id
@@ -345,27 +360,27 @@ function cases.handler(head) -- not real fast but also not used on much data
end
end
elseif id == disc_code then
- local attr = start[a_cases]
+ local attr = getattr(start,a_cases)
if attr and attr > 0 then
if attr ~= lastattr then
lastattr = attr
end
- start[a_cases] = unsetvalue
+ setattr(start,a_cases,unsetvalue)
local n, id, m = get(attr)
if lastfont[n] == nil then
lastfont[n] = id
end
local action = actions[n] -- map back to low number
if action then
- local replace = start.replace
+ local replace = getfield(start,"replace")
if replace then
action(replace,attr,lastfont,n)
end
- local pre = start.pre
+ local pre = getfield(start,"pre")
if pre then
action(pre,attr,lastfont,n)
end
- local post = start.post
+ local post = getfield(start,"post")
if post then
action(post,attr,lastfont,n)
end
@@ -375,10 +390,10 @@ function cases.handler(head) -- not real fast but also not used on much data
start = end_of_math(start)
end
if start then -- why test
- start = start.next
+ start = getnext(start)
end
end
- return head, done
+ return tonode(head), done
end
local enabled = false
diff --git a/tex/context/base/typo-cln.lua b/tex/context/base/typo-cln.lua
index 2aa05b6d1..b7e337662 100644
--- a/tex/context/base/typo-cln.lua
+++ b/tex/context/base/typo-cln.lua
@@ -28,7 +28,14 @@ local tasks = nodes.tasks
local texsetattribute = tex.setattribute
-local traverse_id = node.traverse_id
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local setfield = nuts.setfield
+local getchar = nuts.getchar
+local getattr = nuts.getattr
+
+local traverse_id = nuts.traverse_id
local unsetvalue = attributes.unsetvalue
@@ -48,18 +55,18 @@ local resetter = { -- this will become an entry in char-def
function cleaners.handler(head)
local inline, done = false, false
- for n in traverse_id(glyph_code,head) do
- local char = n.char
+ for n in traverse_id(glyph_code,tonut(head)) do
+ local char = getchar(n)
if resetter[char] then
inline = false
elseif not inline then
- local a = n[a_cleaner]
+ local a = getattr(n,a_cleaner)
if a == 1 then -- currently only one cleaner so no need to be fancy
local upper = uccodes[char]
if type(upper) == "table" then
-- some day, not much change that \SS ends up here
else
- n.char = upper
+ setfield(n,"char",upper)
done = true
if trace_autocase then
report_autocase("")
diff --git a/tex/context/base/typo-dha.lua b/tex/context/base/typo-dha.lua
index d5ad66e7e..15e345ff8 100644
--- a/tex/context/base/typo-dha.lua
+++ b/tex/context/base/typo-dha.lua
@@ -49,13 +49,30 @@ local trace_directions = false trackers.register("typesetters.directions.defa
local report_directions = logs.reporter("typesetting","text directions")
-
-local insert_node_before = nodes.insert_before
-local insert_node_after = nodes.insert_after
-local remove_node = nodes.remove
-local end_of_math = nodes.end_of_math
-
-local nodepool = nodes.pool
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local nutstring = nuts.tostring
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local end_of_math = nuts.end_of_math
+
+
+local nodepool = nuts.pool
local nodecodes = nodes.nodecodes
local whatcodes = nodes.whatcodes
@@ -108,7 +125,7 @@ end
local function process(start)
- local head = start
+ local head = tonut(start) -- we have a global head
local current = head
local inserted = nil
@@ -180,31 +197,31 @@ local function process(start)
end
local function nextisright(current)
- current = current.next
- local id = current.id
+ current = getnext(current)
+ local id = getid(current)
if id == glyph_code then
- local character = current.char
+ local character = getchar(current)
local direction = chardirections[character]
return direction == "r" or direction == "al" or direction == "an"
end
end
local function previsright(current)
- current = current.prev
- local id = current.id
+ current = getprev(current)
+ local id = getid(current)
if id == glyph_code then
- local char = current.char
+ local character = getchar(current)
local direction = chardirections[character]
return direction == "r" or direction == "al" or direction == "an"
end
end
while current do
- local id = current.id
+ local id = getid(current)
if id == math_code then
- current = end_of_math(current.next).next
+ current = getnext(end_of_math(getnext(current)))
else
- local attr = current[a_directions]
+ local attr = getattr(current,a_directions)
if attr and attr > 0 and attr ~= prevattr then
if not getglobal(a) then
lro, rlo = false, false
@@ -213,7 +230,7 @@ local function process(start)
end
if id == glyph_code then
if attr and attr > 0 then
- local character = current.char
+ local character = getchar(current)
local direction = chardirections[character]
local reversed = false
if rlo or override > 0 then
@@ -223,24 +240,24 @@ local function process(start)
end
elseif lro or override < 0 then
if direction == "r" or direction == "al" then
- current[a_state] = s_isol
+ setattr(current,a_state,s_isol)
direction = "l"
reversed = true
end
end
if direction == "on" then
local mirror = charmirrors[character]
- if mirror and fontchar[current.font][mirror] then
+ if mirror and fontchar[getfont(current)][mirror] then
local class = charclasses[character]
if class == "open" then
if nextisright(current) then
if autodir >= 0 then
force_auto_right_before(direction)
end
- current.char = mirror
+ setfield(current,"char",mirror)
done = true
elseif autodir < 0 then
- current.char = mirror
+ setfield(current,"char",mirror)
done = true
else
mirror = false
@@ -251,14 +268,14 @@ local function process(start)
local fencedir = fences[#fences]
fences[#fences] = nil
if fencedir < 0 then
- current.char = mirror
+ setfield(current,"char",mirror)
done = true
force_auto_right_before(direction)
else
mirror = false
end
elseif autodir < 0 then
- current.char = mirror
+ setfield(current,"char",mirror)
done = true
else
mirror = false
@@ -336,9 +353,9 @@ local function process(start)
-- we do nothing
end
elseif id == whatsit_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == localpar_code then
- local dir = current.dir
+ local dir = getfield(current,"dir")
if dir == 'TRT' then
autodir = -1
elseif dir == 'TLT' then
@@ -351,7 +368,7 @@ local function process(start)
if finish then
finish_auto_before()
end
- local dir = current.dir
+ local dir = getfield(current,"dir")
if dir == "+TRT" then
finish, autodir = "TRT", -1
elseif dir == "-TRT" then
@@ -370,7 +387,7 @@ local function process(start)
elseif finish then
finish_auto_before()
end
- local cn = current.next
+ local cn = getnext(current)
if cn then
-- we're okay
elseif finish then
@@ -390,7 +407,7 @@ local function process(start)
end
end
- return head, done
+ return tonode(head), done
end
diff --git a/tex/context/base/typo-dig.lua b/tex/context/base/typo-dig.lua
index ef05e62da..67849c6d4 100644
--- a/tex/context/base/typo-dig.lua
+++ b/tex/context/base/typo-dig.lua
@@ -19,10 +19,24 @@ local report_digits = logs.reporter("typesetting","digits")
local nodes, node = nodes, node
-local hpack_node = node.hpack
-local traverse_id = node.traverse_id
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local hpack_node = nuts.hpack
+local traverse_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
@@ -30,7 +44,7 @@ local unsetvalue = attributes.unsetvalue
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local tasks = nodes.tasks
local new_glue = nodepool.glue
@@ -66,16 +80,20 @@ function nodes.aligned(head,start,stop,width,how)
if how == "flushleft" or how == "middle" then
head, stop = insert_node_after(head,stop,new_glue(0,65536,65536))
end
- local prv, nxt = start.prev, stop.next
- start.prev, stop.next = nil, nil
+ local prv = getprev(start)
+ local nxt = getnext(stop)
+ setfield(start,"prev",nil)
+ setfield(stop,"next",nil)
local packed = hpack_node(start,width,"exactly") -- no directional mess here, just lr
if prv then
- prv.next, packed.prev = packed, prv
+ setfield(prv,"next",packed)
+ setfield(packed,"prev",prv)
end
if nxt then
- nxt.prev, packed.next = packed, nxt
+ setfield(nxt,"prev",packed)
+ setfield(packed,"next",nxt)
end
- if packed.prev then
+ if getprev(packed) then
return head, packed
else
return packed, packed
@@ -83,12 +101,13 @@ function nodes.aligned(head,start,stop,width,how)
end
actions[1] = function(head,start,attr)
- local font = start.font
- local char = start.char
+ local font = getfont(start)
+ local char = getchar(start)
local unic = chardata[font][char].tounicode
local what = unic and tonumber(unic,16) or char
if charbase[what].category == "nd" then
- local oldwidth, newwidth = start.width, getdigitwidth(font)
+ local oldwidth = getfield(start,"width")
+ local newwidth = getdigitwidth(font)
if newwidth ~= oldwidth then
if trace_digits then
report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s",
@@ -102,12 +121,13 @@ actions[1] = function(head,start,attr)
end
function digits.handler(head)
+ head = tonut(head)
local done, current, ok = false, head, false
while current do
- if current.id == glyph_code then
- local attr = current[a_digits]
+ if getid(current) == glyph_code then
+ local attr = getattr(current,a_digits)
if attr and attr > 0 then
- current[a_digits] = unsetvalue
+ setattr(current,a_digits,unsetvalue)
local action = actions[attr%100] -- map back to low number
if action then
head, current, ok = action(head,current,attr)
@@ -117,9 +137,11 @@ function digits.handler(head)
end
end
end
- current = current and current.next
+ if current then
+ current = getnext(current)
+ end
end
- return head, done
+ return tonode(head), done
end
local m, enabled = 0, false -- a trick to make neighbouring ranges work
diff --git a/tex/context/base/typo-dir.lua b/tex/context/base/typo-dir.lua
index a04028452..fbca0f024 100644
--- a/tex/context/base/typo-dir.lua
+++ b/tex/context/base/typo-dir.lua
@@ -40,21 +40,35 @@ local trace_directions = false trackers.register("typesetters.directions",
local report_textdirections = logs.reporter("typesetting","text directions")
local report_mathdirections = logs.reporter("typesetting","math directions")
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local nutstring = nuts.tostring
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local hasbit = number.hasbit
-
-local traverse_id = node.traverse_id
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local remove_node = nodes.remove
-local end_of_math = nodes.end_of_math
+local traverse_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local end_of_math = nuts.end_of_math
local texsetattribute = tex.setattribute
local texsetcount = tex.setcount
local unsetvalue = attributes.unsetvalue
-local hasbit = number.hasbit
-
local nodecodes = nodes.nodecodes
local whatcodes = nodes.whatcodes
local mathcodes = nodes.mathcodes
@@ -76,7 +90,7 @@ local vlist_code = nodecodes.vlist
local localpar_code = whatcodes.localpar
local dir_code = whatcodes.dir
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_textdir = nodepool.textdir
diff --git a/tex/context/base/typo-drp.lua b/tex/context/base/typo-drp.lua
index 903140dae..b3f840ae1 100644
--- a/tex/context/base/typo-drp.lua
+++ b/tex/context/base/typo-drp.lua
@@ -24,15 +24,31 @@ typesetters.initials = initials or { }
local nodes = nodes
local tasks = nodes.tasks
-local hpack_nodes = nodes.hpack
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local hpack_nodes = nuts.hpack
+
local nodecodes = nodes.nodecodes
local whatsitcodes = nodes.whatsitcodes
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_kern = nodepool.kern
-local insert_before = nodes.insert_before
-local insert_after = nodes.insert_after
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
local variables = interfaces.variables
local v_default = variables.default
@@ -86,48 +102,48 @@ commands.setinitial = initials.set
actions[v_default] = function(head,setting)
local done = false
- if head.id == whatsit_code and head.subtype == localpar_code then
+ if getid(head) == whatsit_code and getsubtype(head) == localpar_code then
-- begin of par
- local first = head.next
+ local first = getnext(head)
-- parbox .. needs to be set at 0
- if first and first.id == hlist_code then
- first = first.next
+ if first and getid(first) == hlist_code then
+ first = getnext(first)
end
-- we need to skip over kerns and glues (signals)
- while first and first.id ~= glyph_code do
- first = first.next
+ while first and getid(first) ~= glyph_code do
+ first = getnext(first)
end
- if first and first.id == glyph_code then
- local char = first.char
- local prev = first.prev
- local next = first.next
- -- if prev.id == hlist_code then
+ if first and getid(first) == glyph_code then
+ local char = getchar(first)
+ local prev = getprev(first)
+ local next = getnext(first)
+ -- if getid(prev) == hlist_code then
-- -- set the width to 0
-- end
- if next and next.id == kern_node then
- next.kern = 0
+ if next and getid(next) == kern_node then
+ setfield(next,"kern",0)
end
if setting.font then
- first.font = setting.font
+ setfield(first,"font",setting.font)
end
if setting.dynamic > 0 then
- first[0] = setting.dynamic
+ setattr(first,0,setting.dynamic)
end
-- can be a helper
local ma = setting.ma or 0
local ca = setting.ca
local ta = setting.ta
if ca and ca > 0 then
- first[a_colorspace] = ma == 0 and 1 or ma
- first[a_color] = ca
+ setattr(first,a_colorspace,ma == 0 and 1 or ma)
+ setattr(first,a_color,ca)
end
if ta and ta > 0 then
- first[a_transparency] = ta
+ setattr(first,a_transparency,ta)
end
--
- local width = first.width
- local height = first.height
- local depth = first.depth
+ local width = getfield(first,"width")
+ local height = getfield(first,"height")
+ local depth = getfield(first,"depth")
local distance = setting.distance or 0
local voffset = setting.voffset or 0
local hoffset = setting.hoffset or 0
@@ -135,22 +151,22 @@ actions[v_default] = function(head,setting)
local baseline = texget("baselineskip").width
local lines = tonumber(setting.n) or 0
--
- first.xoffset = - width - hoffset - distance - parindent
- first.yoffset = - voffset -- no longer - height here
+ setfield(first,"xoffset",- width - hoffset - distance - parindent)
+ setfield(first,"yoffset",- voffset) -- no longer - height here
-- We pack so that successive handling cannot touch the dropped cap. Packaging
-- in a hlist is also needed because we cannot locally adapt e.g. parindent (not
-- yet stored in with localpar).
- first.prev = nil
- first.next = nil
+ setfield(first,"prev",nil)
+ setfield(first,"next",nil)
local h = hpack_nodes(first)
- h.width = 0
- h.height = 0
- h.depth = 0
- prev.next = h
- next.prev = h
- h.next = next
- h.prev = prev
-
+ setfield(h,"width",0)
+ setfield(h,"height",0)
+ setfield(h,"depth",0)
+ setfield(prev,"next",h)
+ setfield(next,"prev",h)
+ setfield(h,"next",next)
+ setfield(h,"prev",prev)
+ first = h
-- end of packaging
if setting.location == v_margin then
-- okay
@@ -178,16 +194,17 @@ actions[v_default] = function(head,setting)
end
function initials.handler(head)
+ head = tonut(head)
local start = head
local attr = nil
while start do
- attr = start[a_initial]
+ attr = getattr(start,a_initial)
if attr then
break
- elseif start.id == glyph then
+ elseif getid(start) == glyph then
break
else
- start = start.next
+ start = getnext(start)
end
end
if attr then
@@ -201,8 +218,8 @@ function initials.handler(head)
report_initials("processing initials, alternative %a",alternative)
end
local head, done = action(head,settings)
- return head, done
+ return tonode(head), done
end
end
- return head, false
+ return tonode(head), false
end
diff --git a/tex/context/base/typo-dua.lua b/tex/context/base/typo-dua.lua
index ec85a3d9f..91a27a30e 100644
--- a/tex/context/base/typo-dua.lua
+++ b/tex/context/base/typo-dua.lua
@@ -66,11 +66,24 @@ local formatters = string.formatters
local directiondata = characters.directions
local mirrordata = characters.mirrors
-local remove_node = nodes.remove
-local insert_node_after = nodes.insert_after
-local insert_node_before = nodes.insert_before
-
-local nodepool = nodes.pool
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local nutstring = nuts.tostring
+
+local getnext = nuts.getnext
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+
+local remove_node = nuts.remove
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+
+local nodepool = nuts.pool
local new_textdir = nodepool.textdir
local nodecodes = nodes.nodecodes
@@ -189,17 +202,17 @@ local function build_list(head) -- todo: store node pointer ... saves loop
local size = 0
while current do
size = size + 1
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local chr = current.char
+ local chr = getchar(current)
local dir = directiondata[chr]
list[size] = { char = chr, direction = dir, original = dir, level = 0 }
- current = current.next
+ current = getnext(current)
elseif id == glue_code then
list[size] = { char = 0x0020, direction = "ws", original = "ws", level = 0 }
- current = current.next
- elseif id == whatsit_code and current.subtype == dir_code then
- local dir = current.dir
+ current = getnext(current)
+ elseif id == whatsit_code and getsubtype(current) == dir_code then
+ local dir = getfield(current,"dir")
if dir == "+TLT" then
list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 }
elseif dir == "+TRT" then
@@ -209,27 +222,27 @@ local function build_list(head) -- todo: store node pointer ... saves loop
else
list[size] = { char = 0xFFFC, direction = "on", original = "on", level = 0, id = id } -- object replacement character
end
- current = current.next
+ current = getnext(current)
elseif id == math_code then
local skip = 0
- current = current.next
- while current.id ~= math_code do
+ current = getnext(current)
+ while getid(current) ~= math_code do
skip = skip + 1
- current = current.next
+ current = getnext(current)
end
- skip = skip + 1
- current = current.next
+ skip = skip + 1
+ current = getnext(current)
list[size] = { char = 0xFFFC, direction = "on", original = "on", level = 0, skip = skip, id = id }
else
local skip = 0
local last = id
- current = current.next
+ current = getnext(current)
while n do
- local id = current.id
- if id ~= glyph_code and id ~= glue_code and not (id == whatsit_code and current.subtype == dir_code) then
+ local id = getid(current)
+ if id ~= glyph_code and id ~= glue_code and not (id == whatsit_code and getsubtype(current) == dir_code) then
skip = skip + 1
last = id
- current = current.next
+ current = getnext(current)
else
break
end
@@ -289,8 +302,8 @@ local function find_run_limit_b_s_ws_on(list,start,limit)
end
local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for local_par)
- if head.id == whatsit_code and head.subtype == localpar_code then
- if head.dir == "TRT" then
+ if getid(head) == whatsit_code and getsubtype(head) == localpar_code then
+ if getfield(head,"dir") == "TRT" then
return 1, "TRT", true
else
return 0, "TLT", true
@@ -677,30 +690,30 @@ local function apply_to_list(list,size,head,pardir)
report_directions("fatal error, size mismatch")
break
end
- local id = current.id
+ local id = getid(current)
local entry = list[index]
local begindir = entry.begindir
local enddir = entry.enddir
if id == glyph_code then
local mirror = entry.mirror
if mirror then
- current.char = mirror
+ setfield(current,"char",mirror)
end
if trace_directions then
local direction = entry.direction
setcolor(current,direction,direction ~= entry.original,mirror)
end
elseif id == hlist_code or id == vlist_code then
- current.dir = pardir -- is this really needed?
+ setfield(current,"dir",pardir) -- is this really needed?
elseif id == glue_code then
- if enddir and current.subtype == parfillskip_code then
+ if enddir and getsubtype(current) == parfillskip_code then
-- insert the last enddir before \parfillskip glue
head = insert_node_before(head,current,new_textdir(enddir))
enddir = false
done = true
end
elseif id == whatsit_code then
- if begindir and current.subtype == localpar_code then
+ if begindir and getsubtype(current) == localpar_code then
-- local_par should always be the 1st node
head, current = insert_node_after(head,current,new_textdir(begindir))
begindir = nil
@@ -714,7 +727,7 @@ local function apply_to_list(list,size,head,pardir)
local skip = entry.skip
if skip and skip > 0 then
for i=1,skip do
- current = current.next
+ current = getnext(current)
end
end
if enddir then
@@ -722,13 +735,13 @@ local function apply_to_list(list,size,head,pardir)
done = true
end
if not entry.remove then
- current = current.next
+ current = getnext(current)
elseif remove_controls then
-- X9
head, current = remove_node(head,current,true)
done = true
else
- current = current.next
+ current = getnext(current)
end
index = index + 1
end
@@ -736,6 +749,7 @@ local function apply_to_list(list,size,head,pardir)
end
local function process(head)
+ head = tonut(head)
local list, size = build_list(head)
local baselevel, pardir, dirfound = get_baselevel(head,list,size) -- we always have an inline dir node in context
if not dirfound and trace_details then
@@ -752,7 +766,7 @@ local function process(head)
report_directions("result : %s",show_done(list,size))
end
head, done = apply_to_list(list,size,head,pardir)
- return head, done
+ return tonode(head), done
end
directions.installhandler(interfaces.variables.one,process)
diff --git a/tex/context/base/typo-dub.lua b/tex/context/base/typo-dub.lua
index 3ecfce364..4dc0f21fb 100644
--- a/tex/context/base/typo-dub.lua
+++ b/tex/context/base/typo-dub.lua
@@ -54,11 +54,25 @@ local directiondata = characters.directions
local mirrordata = characters.mirrors
local textclassdata = characters.textclasses
-local remove_node = nodes.remove
-local insert_node_after = nodes.insert_after
-local insert_node_before = nodes.insert_before
-
-local nodepool = nodes.pool
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local nutstring = nuts.tostring
+
+local getnext = nuts.getnext
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+
+local remove_node = nuts.remove
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+
+local nodepool = nuts.pool
local new_textdir = nodepool.textdir
local nodecodes = nodes.nodecodes
@@ -242,17 +256,17 @@ local function build_list(head) -- todo: store node pointer ... saves loop
local size = 0
while current do
size = size + 1
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local chr = current.char
+ local chr = getchar(current)
local dir = directiondata[chr]
list[size] = { char = chr, direction = dir, original = dir, level = 0 }
- current = current.next
+ current = getnext(current)
elseif id == glue_code then
list[size] = { char = 0x0020, direction = "ws", original = "ws", level = 0 }
- current = current.next
- elseif id == whatsit_code and current.subtype == dir_code then
- local dir = current.dir
+ current = getnext(current)
+ elseif id == whatsit_code and getsubtype(current) == dir_code then
+ local dir = getfield(current,"dir")
if dir == "+TLT" then
list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 }
elseif dir == "+TRT" then
@@ -262,27 +276,27 @@ local function build_list(head) -- todo: store node pointer ... saves loop
else
list[size] = { char = 0xFFFC, direction = "on", original = "on", level = 0, id = id } -- object replacement character
end
- current = current.next
+ current = getnext(current)
elseif id == math_code then
local skip = 0
- current = current.next
- while current.id ~= math_code do
+ current = getnext(current)
+ while getid(current) ~= math_code do
skip = skip + 1
- current = current.next
+ current = getnext(current)
end
skip = skip + 1
- current = current.next
+ current = getnext(current)
list[size] = { char = 0xFFFC, direction = "on", original = "on", level = 0, skip = skip, id = id }
else
local skip = 0
local last = id
- current = current.next
+ current = getnext(current)
while n do
- local id = current.id
- if id ~= glyph_code and id ~= glue_code and not (id == whatsit_code and current.subtype == dir_code) then
+ local id = getid(current)
+ if id ~= glyph_code and id ~= glue_code and not (id == whatsit_code and getsubtype(current) == dir_code) then
skip = skip + 1
last = id
- current = current.next
+ current = getnext(current)
else
break
end
@@ -365,8 +379,8 @@ end
-- the action
local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for local_par)
- if head.id == whatsit_code and head.subtype == localpar_code then
- if head.dir == "TRT" then
+ if getid(head) == whatsit_code and getsubtype(head) == localpar_code then
+ if getfield(head,"dir") == "TRT" then
return 1, "TRT", true
else
return 0, "TLT", true
@@ -785,30 +799,30 @@ local function apply_to_list(list,size,head,pardir)
report_directions("fatal error, size mismatch")
break
end
- local id = current.id
+ local id = getid(current)
local entry = list[index]
local begindir = entry.begindir
local enddir = entry.enddir
if id == glyph_code then
local mirror = entry.mirror
if mirror then
- current.char = mirror
+ setfield(current,"char",mirror)
end
if trace_directions then
local direction = entry.direction
setcolor(current,direction,direction ~= entry.original,mirror)
end
elseif id == hlist_code or id == vlist_code then
- current.dir = pardir -- is this really needed?
+ setfield(current,"dir",pardir) -- is this really needed?
elseif id == glue_code then
- if enddir and current.subtype == parfillskip_code then
+ if enddir and getsubtype(current) == parfillskip_code then
-- insert the last enddir before \parfillskip glue
head = insert_node_before(head,current,new_textdir(enddir))
enddir = false
done = true
end
elseif id == whatsit_code then
- if begindir and current.subtype == localpar_code then
+ if begindir and getsubtype(current) == localpar_code then
-- local_par should always be the 1st node
head, current = insert_node_after(head,current,new_textdir(begindir))
begindir = nil
@@ -822,7 +836,7 @@ local function apply_to_list(list,size,head,pardir)
local skip = entry.skip
if skip and skip > 0 then
for i=1,skip do
- current = current.next
+ current = getnext(current)
end
end
if enddir then
@@ -830,13 +844,13 @@ local function apply_to_list(list,size,head,pardir)
done = true
end
if not entry.remove then
- current = current.next
+ current = getnext(current)
elseif remove_controls then
-- X9
head, current = remove_node(head,current,true)
done = true
else
- current = current.next
+ current = getnext(current)
end
index = index + 1
end
@@ -844,8 +858,9 @@ local function apply_to_list(list,size,head,pardir)
end
local function process(head)
+ head = tonut(head)
-- for the moment a whole paragraph property
- local attr = head[a_directions]
+ local attr = getattr(head,a_directions)
local analyze_fences = getfences(attr)
--
local list, size = build_list(head)
@@ -864,7 +879,7 @@ local function process(head)
report_directions("result : %s",show_done(list,size))
end
head, done = apply_to_list(list,size,head,pardir)
- return head, done
+ return tonode(head), done
end
directions.installhandler(interfaces.variables.two,process)
diff --git a/tex/context/base/typo-fln.lua b/tex/context/base/typo-fln.lua
index 4c97af450..7ce41cd81 100644
--- a/tex/context/base/typo-fln.lua
+++ b/tex/context/base/typo-fln.lua
@@ -23,25 +23,38 @@ local firstlines = typesetters.firstlines
local nodes = nodes
local tasks = nodes.tasks
-local getbox = nodes.getbox
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getfield = nuts.getfield
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local getbox = nuts.getbox
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
-local traverse_id = nodes.traverse_id
-local free_node_list = nodes.flush_list
-local free_node = nodes.flush_node
-local copy_node_list = nodes.copy_list
-local insert_node_after = nodes.insert_after
-local insert_node_before = nodes.insert_before
-local hpack_node_list = nodes.hpack
-local remove_node = nodes.remove
+local traverse_id = nuts.traverse_id
+local free_node_list = nuts.flush_list
+local free_node = nuts.flush_node
+local copy_node_list = nuts.copy_list
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local hpack_node_list = nuts.hpack
+local remove_node = nuts.remove
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local newpenalty = nodepool.penalty
local newkern = nodepool.kern
-local tracerrule = nodes.tracers.pool.nodes.rule
+local tracerrule = nodes.tracers.pool.nuts.rule
local actions = { }
firstlines.actions = actions
@@ -92,9 +105,9 @@ actions[v_line] = function(head,setting)
local linebreaks = { }
for g in traverse_id(glyph_code,temp) do
if dynamic > 0 then
- g[0] = dynamic
+ setattr(g,0,dynamic)
end
- g.font = font
+ setfield(g,"font",font)
end
local start = temp
local list = temp
@@ -108,7 +121,7 @@ actions[v_line] = function(head,setting)
hsize = hsize - hangindent
end
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
n = n + 1
elseif id == disc_code then
@@ -117,7 +130,7 @@ actions[v_line] = function(head,setting)
-- this could be an option
elseif n > 0 then
local pack = hpack_node_list(copy_node_list(list,start))
- if pack.width > hsize then
+ if getfield(pack,"width") > hsize then
free_node_list(pack)
list = prev
break
@@ -128,7 +141,7 @@ actions[v_line] = function(head,setting)
nofchars = n
end
end
- start = start.next
+ start = getnext(start)
end
if not linebreaks[i] then
linebreaks[i] = n
@@ -139,18 +152,18 @@ actions[v_line] = function(head,setting)
for i=1,noflines do
local linebreak = linebreaks[i]
while start and n < nofchars do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then -- or id == disc_code then
if dynamic > 0 then
- start[0] = dynamic
+ setattr(start,0,dynamic)
end
- start.font = font
+ setfield(start,"font",font)
if ca and ca > 0 then
- start[a_colorspace] = ma == 0 and 1 or ma
- start[a_color] = ca
+ setattr(start,a_colorspace,ma == 0 and 1 or ma)
+ setattr(start,a_color,ca)
end
if ta and ta > 0 then
- start[a_transparency] = ta
+ setattr(start,a_transparency,ta)
end
n = n + 1
end
@@ -163,7 +176,7 @@ actions[v_line] = function(head,setting)
head, start = insert_node_after(head,start,newpenalty(-10000)) -- break
break
end
- start = start.next
+ start = getnext(start)
end
end
free_node_list(temp)
@@ -182,7 +195,7 @@ actions[v_word] = function(head,setting)
local ca = setting.ca
local ta = setting.ta
while start do
- local id = start.id
+ local id = getid(start)
-- todo: delete disc nodes
if id == glyph_code then
if not ok then
@@ -190,16 +203,16 @@ actions[v_word] = function(head,setting)
ok = true
end
if ca and ca > 0 then
- start[a_colorspace] = ma == 0 and 1 or ma
- start[a_color] = ca
+ setattr(start,a_colorspace,ma == 0 and 1 or ma)
+ setattr(start,a_color,ca)
end
if ta and ta > 0 then
- start[a_transparency] = ta
+ setattr(start,a_transparency,ta)
end
if dynamic > 0 then
- start[0] = dynamic
+ setattr(start,0,dynamic)
end
- start.font = font
+ setfield(start,"font",font)
elseif id == disc_code then
-- continue
elseif id == kern_code then -- todo: fontkern
@@ -210,7 +223,7 @@ actions[v_word] = function(head,setting)
break
end
end
- start = start.next
+ start = getnext(start)
end
return head, true
end
@@ -218,16 +231,17 @@ end
actions[v_default] = actions[v_line]
function firstlines.handler(head)
+ head = tonut(head)
local start = head
local attr = nil
while start do
- attr = start[a_firstline]
+ attr = getattr(start,a_firstline)
if attr then
break
- elseif start.id == glyph then
+ elseif getid(start) == glyph_code then
break
else
- start = start.next
+ start = getnext(start)
end
end
if attr then
@@ -240,17 +254,18 @@ function firstlines.handler(head)
if trace_firstlines then
report_firstlines("processing firstlines, alternative %a",alternative)
end
- return action(head,settings)
+ local head, done = action(head,settings)
+ return tonode(head), done
end
end
- return head, false
+ return tonode(head), false
end
-- goodie
function commands.applytofirstcharacter(box,what)
local tbox = getbox(box) -- assumes hlist
- local list = tbox.list
+ local list = getlist(tbox)
local done = nil
for n in traverse_id(glyph_code,list) do
list = remove_node(list,n)
@@ -258,10 +273,10 @@ function commands.applytofirstcharacter(box,what)
break
end
if done then
- tbox.list = list
+ setfield(tbox,"list",list)
local kind = type(what)
if kind == "string" then
- context[what](done)
+ context[what](tonode(done))
elseif kind == "function" then
what(done)
else
diff --git a/tex/context/base/typo-itc.lua b/tex/context/base/typo-itc.lua
index 452b623c8..997190675 100644
--- a/tex/context/base/typo-itc.lua
+++ b/tex/context/base/typo-itc.lua
@@ -24,17 +24,30 @@ local math_code = nodecodes.math
local tasks = nodes.tasks
-local insert_node_after = node.insert_after
-local delete_node = nodes.delete
-local end_of_math = node.end_of_math
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getnext = nuts.getnext
+local getid = nuts.getid
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getattr = nuts.getattr
+
+local insert_node_after = nuts.insert_after
+local delete_node = nuts.delete
+local end_of_math = nuts.end_of_math
local texgetattribute = tex.getattribute
local texsetattribute = tex.setattribute
local a_italics = attributes.private("italics")
local unsetvalue = attributes.unsetvalue
-local new_correction_kern = nodes.pool.fontkern
-local new_correction_glue = nodes.pool.glue
+local new_correction_kern = nodepool.fontkern
+local new_correction_glue = nodepool.glue
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
@@ -83,6 +96,7 @@ end
-- todo: clear attribute
function italics.handler(head)
+ head = tonut(head)
local done = false
local italic = 0
local lastfont = nil
@@ -92,10 +106,10 @@ function italics.handler(head)
local current = head
local inserted = nil
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local font = current.font
- local char = current.char
+ local font = getfont(current)
+ local char = getchar(current)
local data = italicsdata[font]
if font ~= lastfont then
if italic ~= 0 then
@@ -121,7 +135,7 @@ function italics.handler(head)
lastfont = font
end
if data then
- local attr = forcedvariant or current[a_italics]
+ local attr = forcedvariant or getattr(current,a_italics)
if attr and attr > 0 then
local cd = data[char]
if not cd then
@@ -173,7 +187,7 @@ function italics.handler(head)
italic = 0
done = true
end
- current = current.next
+ current = getnext(current)
end
if italic ~= 0 and lastattr > 1 then -- more control is needed here
if trace_italics then
@@ -182,7 +196,7 @@ function italics.handler(head)
insert_node_after(head,previous,new_correction_kern(italic))
done = true
end
- return head, done
+ return tonode(head), done
end
local enable
diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua
index 56f58bb73..a8ffe557b 100644
--- a/tex/context/base/typo-krn.lua
+++ b/tex/context/base/typo-krn.lua
@@ -13,21 +13,36 @@ local utfchar = utf.char
local nodes, node, fonts = nodes, node, fonts
-local find_node_tail = node.tail or node.slide
-local free_node = node.free
-local free_nodelist = node.flush_list
-local copy_node = node.copy
-local copy_nodelist = node.copy_list
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local end_of_math = node.end_of_math
+local tasks = nodes.tasks
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local find_node_tail = nuts.tail
+local free_node = nuts.free
+local free_nodelist = nuts.flush_list
+local copy_node = nuts.copy
+local copy_nodelist = nuts.copy_list
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local end_of_math = nuts.end_of_math
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
-local nodepool = nodes.pool
-local tasks = nodes.tasks
-
local new_gluespec = nodepool.gluespec
local new_kern = nodepool.kern
local new_glue = nodepool.glue
@@ -107,10 +122,10 @@ kerns.keeptogether = false -- just for fun (todo: control setting with key/value
-- blue : keep by goodie
function kerns.keepligature(n) -- might become default
- local f = n.font
- local a = n[0] or 0
+ local f = getfont(n)
+ local a = getattr(n,0) or 0
if trace_ligatures then
- local c = n.char
+ local c = getchar(n)
local d = fontdescriptions[f][c].name
if a > 0 and contextsetups[a].keepligatures == v_auto then
report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","dynamic","keepligatures")
@@ -169,9 +184,9 @@ end
local function kern_injector(fillup,kern)
if fillup then
local g = new_glue(kern)
- local s = g.spec
- s.stretch = kern
- s.stretch_order = 1
+ local s = getfield(g,"spec")
+ setfield(s,"stretch",kern)
+ setfield(s,"stretch_order",1)
return g
else
return new_kern(kern)
@@ -181,7 +196,7 @@ end
local function spec_injector(fillup,width,stretch,shrink)
if fillup then
local s = new_gluespec(width,2*stretch,2*shrink)
- s.stretch_order = 1
+ setfield(s,"stretch_order",1)
return s
else
return new_gluespec(width,stretch,shrink)
@@ -197,9 +212,9 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
local fillup = false
while start do
-- faster to test for attr first
- local attr = force or start[a_kerns]
+ local attr = force or getattr(start,a_kerns)
if attr and attr > 0 then
- start[a_kerns] = unsetvalue
+ setattr(start,a_kerns,unsetvalue)
local krn = mapping[attr]
if krn == v_max then
krn = .25
@@ -208,10 +223,10 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
fillup = false
end
if krn and krn ~= 0 then
- local id = start.id
- if id == glyph_code then
- lastfont = start.font
- local c = start.components
+ local id = getid(start)
+ if id == glyph_code then -- we could use the subtype ligature
+ lastfont = getfont(start)
+ local c = getfield(start,"components")
if not c then
-- fine
elseif keepligature and keepligature(start) then
@@ -219,47 +234,47 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
else
c = do_process(c,attr)
local s = start
- local p, n = s.prev, s.next
+ local p, n = getprev(s), getnext(s)
local tail = find_node_tail(c)
if p then
- p.next = c
- c.prev = p
+ setfield(p,"next",c)
+ setfield(c,"prev",p)
else
head = c
end
if n then
- n.prev = tail
+ setfield(n,"prev",tail)
end
- tail.next = n
+ setfield(tail,"next",n)
start = c
- s.components = nil
+ setfield(s,"components",nil)
-- we now leak nodes !
- -- free_node(s)
+ -- free_node(s)
done = true
end
- local prev = start.prev
+ local prev = getprev(start)
if not prev then
-- skip
- elseif markdata[lastfont][start.char] then
+ elseif markdata[lastfont][getchar(start)] then
-- skip
else
- local pid = prev.id
+ local pid = getid(prev)
if not pid then
-- nothing
elseif pid == kern_code then
- if prev.subtype == kerning_code or prev[a_fontkern] then
- if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then -- we could also pass start
+ if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
+ if keeptogether and getid(getprev(prev)) == glyph_code and keeptogether(getprev(prev),start) then -- we could also pass start
-- keep 'm
else
-- not yet ok, as injected kerns can be overlays (from node-inj.lua)
- prev.subtype = userkern_code
- prev.kern = prev.kern + quaddata[lastfont]*krn -- here
+ setfield(prev,"subtype",userkern_code)
+ setfield(prev,"kern",getfield(prev,"kern") + quaddata[lastfont]*krn) -- here
done = true
end
end
elseif pid == glyph_code then
- if prev.font == lastfont then
- local prevchar, lastchar = prev.char, start.char
+ if getfont(prev) == lastfont then
+ local prevchar, lastchar = getchar(prev), getchar(start)
if keeptogether and keeptogether(prev,start) then
-- keep 'm
else
@@ -278,102 +293,102 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
-- a bit too complicated, we can best not copy and just calculate
-- but we could have multiple glyphs involved so ...
local disc = prev -- disc
- local prv, nxt = disc.prev, disc.next
- if disc.subtype == discretionary_code then
+ local prv, nxt = getprev(disc), getnext(disc)
+ if getsubtype(disc) == discretionary_code then
-- maybe we should forget about this variant as there is no glue
-- possible
- local pre, post, replace = disc.pre, disc.post, disc.replace
- if pre and prv then -- must pair with start.prev
- -- this one happens in most cases
+ local pre, post, replace = getfield(disc,"pre"), getfield(disc,"post"), getfield(disc,"replace")
+ if pre and prv then -- must pair with getprev(start)
local before = copy_node(prv)
- pre.prev = before
- before.next = pre
- before.prev = nil
+ setfield(pre,"prev",before)
+ setfield(before,"next",pre)
+ setfield(before,"prev",nil)
pre = do_process(before,attr)
- pre = pre.next
- pre.prev = nil
- disc.pre = pre
+ pre = getnext(pre)
+ setfield(pre,"prev",nil)
+ setfield(disc,"pre",pre)
free_node(before)
end
if post and nxt then -- must pair with start
local after = copy_node(nxt)
local tail = find_node_tail(post)
- tail.next = after
- after.prev = tail
- after.next = nil
+ setfield(tail,"next",after)
+ setfield(after,"prev",tail)
+ setfield(after,"next",nil)
post = do_process(post,attr)
- tail.next = nil
- disc.post = post
+ setfield(tail,"next",nil)
+ setfield(disc,"post",post)
free_node(after)
end
if replace and prv and nxt then -- must pair with start and start.prev
local before = copy_node(prv)
local after = copy_node(nxt)
local tail = find_node_tail(replace)
- replace.prev = before
- before.next = replace
- before.prev = nil
- tail.next = after
- after.prev = tail
- after.next = nil
+ setfield(replace,"prev",before)
+ setfield(before,"next",replace)
+ setfield(before,"prev",nil)
+ setfield(tail,"next",after)
+ setfield(after,"prev",tail)
+ setfield(after,"next",nil)
replace = do_process(before,attr)
- replace = replace.next
- replace.prev = nil
- after.prev.next = nil
- disc.replace = replace
+ replace = getnext(replace)
+ setfield(replace,"prev",nil)
+ setfield(getfield(after,"prev"),"next",nil)
+ setfield(disc,"replace",replace)
free_node(after)
free_node(before)
- elseif prv and prv.id == glyph_code and prv.font == lastfont then
- local prevchar, lastchar = prv.char, start.char
+ elseif prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
+ local prevchar, lastchar = getchar(prv), getchar(start)
local kerns = chardata[lastfont][prevchar].kerns
local kern = kerns and kerns[lastchar] or 0
krn = kern + quaddata[lastfont]*krn -- here
- disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue
+ setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
else
krn = quaddata[lastfont]*krn -- here
- disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue
+ setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
end
else
-- this one happens in most cases: automatic (-), explicit (\-), regular (patterns)
- if prv and prv.id == glyph_code and prv.font == lastfont then
- local prevchar, lastchar = prv.char, start.char
+ if prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
+ -- the normal case
+ local prevchar, lastchar = getchar(prv), getchar(start)
local kerns = chardata[lastfont][prevchar].kerns
local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn -- here
+ krn = kern + quaddata[lastfont]*krn
else
- krn = quaddata[lastfont]*krn -- here
+ krn = quaddata[lastfont]*krn
end
insert_node_before(head,start,kern_injector(fillup,krn))
end
end
end
elseif id == glue_code then
- local subtype = start.subtype
+ local subtype = getsubtype(start)
if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
- local s = start.spec
- local w = s.width
+ local s = getfield(start,"spec")
+ local w = getfield(s,"width")
if w > 0 then
- local width, stretch, shrink = w+gluefactor*w*krn, s.stretch, s.shrink
- start.spec = spec_injector(fillup,width,stretch*width/w,shrink*width/w)
+ local width, stretch, shrink = w+gluefactor*w*krn, getfield(s,"stretch"), getfield(s,"shrink")
+ setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
done = true
end
end
elseif id == kern_code then
- -- if start.subtype == kerning_code then -- handle with glyphs
- -- local sk = start.kern
+ -- if getsubtype(start) == kerning_code then -- handle with glyphs
+ -- local sk = getfield(start,"kern")
-- if sk > 0 then
- -- start.kern = sk*krn
+ -- setfield(start,"kern",sk*krn)
-- done = true
-- end
-- end
elseif lastfont and (id == hlist_code or id == vlist_code) then -- todo: lookahead
- local p = start.prev
- if p and p.id ~= glue_code then
+ local p = getprev(start)
+ if p and getid(p) ~= glue_code then
insert_node_before(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
done = true
end
- local n = start.next
- if n and n.id ~= glue_code then
+ local n = getnext(start)
+ if n and getid(n) ~= glue_code then
insert_node_after(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
done = true
end
@@ -383,7 +398,7 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
end
end
if start then
- start = start.next
+ start = getnext(start)
end
end
return head, done
@@ -414,7 +429,8 @@ function kerns.set(factor)
end
function kerns.handler(head)
- return do_process(head) -- no direct map, because else fourth argument is tail == true
+ local head, done = do_process(tonut(head)) -- no direct map, because else fourth argument is tail == true
+ return tonode(head), done
end
-- interface
diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua
index 85d5c85a8..a41a409dd 100644
--- a/tex/context/base/typo-mar.lua
+++ b/tex/context/base/typo-mar.lua
@@ -115,13 +115,31 @@ local v_first = variables.first
local v_text = variables.text
local v_column = variables.column
-local copy_node_list = node.copy_list
-local slide_nodes = node.slide
-local hpack_nodes = node.hpack -- nodes.fasthpack not really faster here
-local traverse_id = node.traverse_id
-local free_node_list = node.flush_list
-local insert_node_after = node.insert_after
-local insert_node_before = node.insert_before
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local copy_node_list = nuts.copy_list
+local slide_nodes = nuts.slide
+local hpack_nodes = nuts.hpack -- nodes.fasthpack not really faster here
+local traverse_id = nuts.traverse_id
+local free_node_list = nuts.flush_list
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local linked_nodes = nuts.linked
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+local getbox = nuts.getbox
+local getlist = nuts.getlist
local nodecodes = nodes.nodecodes
local listcodes = nodes.listcodes
@@ -144,7 +162,7 @@ local userdefined_code = whatsitcodes.userdefined
local dir_code = whatsitcodes.dir
local localpar_code = whatsitcodes.localpar
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_kern = nodepool.kern
local new_glue = nodepool.glue
@@ -155,13 +173,12 @@ local new_latelua = nodepool.latelua
local texgetcount = tex.getcount
local texgetdimen = tex.getdimen
-local texgetbox = tex.getbox
local texget = tex.get
local points = number.points
local isleftpage = layouts.status.isleftpage
-local registertogether = builders.paragraphs.registertogether
+local registertogether = builders.paragraphs.registertogether -- tonode
local jobpositions = job.positions
local getposition = jobpositions.position
@@ -170,7 +187,7 @@ local a_margindata = attributes.private("margindata")
local inline_mark = nodepool.userids["margins.inline"]
-local margins = { }
+local margins = { }
typesetters.margins = margins
local locations = { v_left, v_right, v_inner, v_outer } -- order might change
@@ -242,7 +259,7 @@ end
function margins.save(t)
setmetatable(t,defaults)
- local content = texgetbox(t.number)
+ local content = getbox(t.number)
local location = t.location
local category = t.category
local inline = t.inline
@@ -310,11 +327,11 @@ function margins.save(t)
-- nice is to make a special status table mechanism
local leftmargindistance = texgetdimen("naturalleftmargindistance")
local rightmargindistance = texgetdimen("naturalrightmargindistance")
- local strutbox = texgetbox("strutbox")
- t.strutdepth = strutbox.depth
- t.strutheight = strutbox.height
- t.leftskip = texget("leftskip").width -- we're not in forgetall
- t.rightskip = texget("rightskip").width -- we're not in forgetall
+ local strutbox = getbox("strutbox")
+ t.strutdepth = getfield(strutbox,"depth")
+ t.strutheight = getfield(strutbox,"height")
+ t.leftskip = getfield(texget("leftskip"),"width") -- we're not in forgetall
+ t.rightskip = getfield(texget("rightskip"),"width") -- we're not in forgetall
t.leftmargindistance = leftmargindistance -- todo:layoutstatus table
t.rightmargindistance = rightmargindistance
t.leftedgedistance = texgetdimen("naturalleftedgedistance")
@@ -404,7 +421,7 @@ local function realign(current,candidate)
-- we assume that list is a hbox, otherwise we had to take the whole current
-- in order to get it right
- current.width = 0
+ setfield(current,"width",0)
local anchornode, move_x
-- this mess is needed for alignments (combinations) so we use that
@@ -446,9 +463,9 @@ local function realign(current,candidate)
report_margindata("realigned %a, location %a, margin %a",candidate.n,location,margin)
end
end
-
- current.list = hpack_nodes(anchornode .. new_kern(-delta) .. current.list .. new_kern(delta))
- current.width = 0
+ local list = hpack_nodes(linked_nodes(anchornode,new_kern(-delta),getlist(current),new_kern(delta)))
+ setfield(current,"list",list)
+ setfield(current,"width",0)
end
local function realigned(current,a)
@@ -490,7 +507,8 @@ local function markovershoot(current)
v_anchors = v_anchors + 1
cache[v_anchors] = stacked
local anchor = new_latelua(format("typesetters.margins.ha(%s)",v_anchors)) -- todo: alleen als offset > line
- current.list = hpack_nodes(anchor .. current.list)
+ local list = hpack_nodes(linked_nodes(anchor,getlist(current)))
+ setfield(current,"list",list)
end
local function getovershoot(location)
@@ -512,10 +530,10 @@ end
local function inject(parent,head,candidate)
local box = candidate.box
- local width = box.width
- local height = box.height
- local depth = box.depth
- local shift = box.shift
+ local width = getfield(box,"width")
+ local height = getfield(box,"height")
+ local depth = getfield(box,"depth")
+ local shift = getfield(box,"shift")
local stack = candidate.stack
local location = candidate.location
local method = candidate.method
@@ -524,7 +542,7 @@ local function inject(parent,head,candidate)
local baseline = candidate.baseline
local strutheight = candidate.strutheight
local strutdepth = candidate.strutdepth
- local psubtype = parent.subtype
+ local psubtype = getsubtype(parent)
local offset = stacked[location]
local firstonstack = offset == false or offset == nil
nofstatus = nofstatus + 1
@@ -546,7 +564,7 @@ local function inject(parent,head,candidate)
end
end
candidate.width = width
- candidate.hsize = parent.width -- we can also pass textwidth
+ candidate.hsize = getfield(parent,"width") -- we can also pass textwidth
candidate.psubtype = psubtype
if trace_margindata then
report_margindata("processing, index %s, height %p, depth %p, parent %s",candidate.n,height,depth,listcodes[psubtype])
@@ -573,7 +591,7 @@ local function inject(parent,head,candidate)
-- experimental.
-- -- --
if method == v_top then
- local delta = height - parent.height
+ local delta = height - getfield(parent,"height")
if trace_margindata then
report_margindata("top aligned by %p",delta)
end
@@ -616,22 +634,23 @@ local function inject(parent,head,candidate)
shift = shift + delta
offset = offset + delta
end
- box.shift = shift
- box.width = 0
+ setfield(box,"shift",shift)
+ setfield(box,"width",0)
if not head then
head = box
- elseif head.id == whatsit_code and head.subtype == localpar_code then
+ elseif getid(head) == whatsit_code and getsubtype(head) == localpar_code then
-- experimental
- if head.dir == "TRT" then
- box.list = hpack_nodes(new_kern(candidate.hsize) .. box.list .. new_kern(-candidate.hsize))
+ if getfield(head,"dir") == "TRT" then
+ local list = hpack_nodes(linked_nodes(new_kern(candidate.hsize),getlist(box),new_kern(-candidate.hsize)))
+ setfield(box,"list",list)
end
insert_node_after(head,head,box)
else
- head.prev = box
- box.next = head
+ setfield(head,"prev",box)
+ setfield(box,"next",head)
head = box
end
- box[a_margindata] = nofstatus
+ setfield(box,a_margindata,nofstatus)
if trace_margindata then
report_margindata("injected, location %a, shift %p",location,shift)
end
@@ -656,12 +675,12 @@ local function flushinline(parent,head)
local current = head
local done = false
local continue = false
- local room, don, con
+ local room, don, con, list
while current and nofinlined > 0 do
- local id = current.id
+ local id = getid(current)
if id == whatsit_code then
- if current.subtype == userdefined_code and current.user_id == inline_mark then
- local n = current.value
+ if getsubtype(current) == userdefined_code and getfield(current,"user_id") == inline_mark then
+ local n = getfield(current,"value")
local candidate = inlinestore[n]
if candidate then -- no vpack, as we want to realign
inlinestore[n] = nil
@@ -674,11 +693,12 @@ local function flushinline(parent,head)
end
elseif id == hlist_code or id == vlist_code then
-- optional (but sometimes needed)
- current.list, don, con = flushinline(current,current.list)
+ list, don, con = flushinline(current,getlist(current))
+ setfield(current,"list",list)
continue = continue or con
done = done or don
end
- current = current.next
+ current = getnext(current)
end
return head, done, continue
end
@@ -686,7 +706,7 @@ end
local a_linenumber = attributes.private('linenumber')
local function flushed(scope,parent) -- current is hlist
- local head = parent.list
+ local head = getlist(parent)
local done = false
local continue = false
local room, con, don
@@ -702,7 +722,7 @@ local function flushed(scope,parent) -- current is hlist
done = true
continue = continue or con
nofstored = nofstored - 1
- registertogether(parent,room)
+ registertogether(tonode(parent),room) -- !! tonode
else
break
end
@@ -711,17 +731,18 @@ local function flushed(scope,parent) -- current is hlist
end
if nofinlined > 0 then
if done then
- parent.list = head
+ setfield(parent,"list",head)
end
head, don, con = flushinline(parent,head)
continue = continue or con
done = done or don
end
if done then
- local a = head[a_linenumber] -- hack .. we need a more decent critical attribute inheritance mechanism
- parent.list = hpack_nodes(head,parent.width,"exactly")
+ local a = getattr(head,a_linenumber) -- hack .. we need a more decent critical attribute inheritance mechanism
+ local l = hpack_nodes(head,getfield(parent,"width"),"exactly")
+ setfield(parent,"list",l)
if a then
- parent.list[a_linenumber] = a
+ setattr(l,a_linenumber,a)
end
-- resetstacked()
end
@@ -736,14 +757,15 @@ local function handler(scope,head,group)
if trace_margindata then
report_margindata("flushing stage one, stored %s, scope %s, delayed %s, group %a",nofstored,scope,nofdelayed,group)
end
+ head = tonut(head)
local current = head
local done = false
while current do
- local id = current.id
- if (id == vlist_code or id == hlist_code) and not current[a_margindata] then
+ local id = getid(current)
+ if (id == vlist_code or id == hlist_code) and not getattr(current,a_margindata) then
local don, continue = flushed(scope,current)
if don then
- current[a_margindata] = 0 -- signal to prevent duplicate processing
+ setattr(current,a_margindata,0) -- signal to prevent duplicate processing
if continue then
markovershoot(current)
end
@@ -753,12 +775,12 @@ local function handler(scope,head,group)
done = true
end
end
- current = current.next
+ current = getnext(current)
end
-- if done then
resetstacked() -- why doesn't done work ok here?
-- end
- return head, done
+ return tonode(head), done
else
return head, false
end
@@ -811,11 +833,11 @@ local function finalhandler(head)
local current = head
local done = false
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code then
- local a = current[a_margindata]
+ local a = getattr(current,a_margindata)
if not a or a == 0 then
- finalhandler(current.list)
+ finalhandler(getlist(current))
elseif realigned(current,a) then
done = true
if nofdelayed == 0 then
@@ -823,9 +845,9 @@ local function finalhandler(head)
end
end
elseif id == vlist_code then
- finalhandler(current.list)
+ finalhandler(getlist(current))
end
- current = current.next
+ current = getnext(current)
end
return head, done
else
@@ -838,7 +860,10 @@ function margins.finalhandler(head)
-- if trace_margindata then
-- report_margindata("flushing stage two, instore: %s, delayed: %s",nofstored,nofdelayed)
-- end
- return finalhandler(head)
+head = tonut(head)
+local head, done = finalhandler(head)
+head = tonode(head)
+ return head, done
else
return head, false
end
diff --git a/tex/context/base/typo-pag.lua b/tex/context/base/typo-pag.lua
index 0dd75ddf9..148eac875 100644
--- a/tex/context/base/typo-pag.lua
+++ b/tex/context/base/typo-pag.lua
@@ -14,13 +14,23 @@ local glue_code = nodecodes.glue
local kern_code = nodecodes.kern
local penalty_code = nodecodes.penalty
-local insert_node_after = node.insert_after
-local new_penalty = nodes.pool.penalty
-
local unsetvalue = attributes.unsetvalue
-
local a_keeptogether = attributes.private("keeptogether")
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+
+local insert_node_after = nuts.insert_after
+local new_penalty = nuts.pool.penalty
+
local trace_keeptogether = false
local report_keeptogether = logs.reporter("parbuilders","keeptogether")
@@ -37,7 +47,7 @@ function builders.paragraphs.registertogether(line,specification) -- might chang
if not enabled then
nodes.tasks.enableaction("finalizers","builders.paragraphs.keeptogether")
end
- local a = line[a_keeptogether]
+ local a = getattr(line,a_keeptogether)
local c = a and cache[a]
if c then
local height = specification.height
@@ -64,7 +74,7 @@ function builders.paragraphs.registertogether(line,specification) -- might chang
if not specification.slack then
specification.slack = 0
end
- line[a_keeptogether] = last
+ setattr(line,a_keeptogether,last)
end
if trace_keeptogether then
local a = a or last
@@ -88,24 +98,24 @@ local function keeptogether(start,a)
if start then
local specification = cache[a]
if a then
- local current = start.next
+ local current = getnext(start)
local previous = start
- local total = previous.depth
+ local total = getfield(previous,"depth")
local slack = specification.slack
local threshold = specification.depth - slack
if trace_keeptogether then
report_keeptogether("%s, index %s, total %p, threshold %p, slack %p","list",a,total,threshold,slack)
end
while current do
- local id = current.id
+ local id = getid(current)
if id == vlist_code or id == hlist_code then
- total = total + current.height + current.depth
+ total = total + getfield(current,"height") + getfield(current,"depth")
if trace_keeptogether then
report_keeptogether("%s, index %s, total %p, threshold %p","list",a,total,threshold)
end
if total <= threshold then
- if previous.id == penalty_code then
- previous.penalty = 10000
+ if getid(previous) == penalty_code then
+ setfield(previous,"penalty",10000)
else
insert_node_after(head,previous,new_penalty(10000))
end
@@ -114,13 +124,13 @@ local function keeptogether(start,a)
end
elseif id == glue_code then
-- hm, breakpoint, maybe turn this into kern
- total = total + current.spec.width
+ total = total + getfield(getfield(current,"spec"),"width")
if trace_keeptogether then
report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold)
end
if total <= threshold then
- if previous.id == penalty_code then
- previous.penalty = 10000
+ if getid(previous) == penalty_code then
+ setfield(previous,"penalty",10000)
else
insert_node_after(head,previous,new_penalty(10000))
end
@@ -128,13 +138,13 @@ local function keeptogether(start,a)
break
end
elseif id == kern_code then
- total = total + current.kern
+ total = total + getfield(current,"kern")
if trace_keeptogether then
report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold)
end
if total <= threshold then
- if previous.id == penalty_code then
- previous.penalty = 10000
+ if getid(previous) == penalty_code then
+ setfield(previous,"penalty",10000)
else
insert_node_after(head,previous,new_penalty(10000))
end
@@ -143,16 +153,16 @@ local function keeptogether(start,a)
end
elseif id == penalty_code then
if total <= threshold then
- if previous.id == penalty_code then
- previous.penalty = 10000
+ if getid(previous) == penalty_code then
+ setfield(previous,"penalty",10000)
end
- current.penalty = 10000
+ setfield(current,"penalty",10000)
else
break
end
end
previous = current
- current = current.next
+ current = getnext(current)
end
end
end
@@ -162,18 +172,18 @@ end
function builders.paragraphs.keeptogether(head)
local done = false
- local current = head
+ local current = tonut(head)
while current do
- if current.id == hlist_code then
- local a = current[a_keeptogether]
+ if getid(current) == hlist_code then
+ local a = getattr(current,a_keeptogether)
if a and a > 0 then
keeptogether(current,a)
- current[a_keeptogether] = unsetvalue
+ setattr(current,a_keeptogether,unsetvalue)
cache[a] = nil
done = true
end
end
- current = current.next
+ current = getnext(current)
end
return head, done
end
diff --git a/tex/context/base/typo-rep.lua b/tex/context/base/typo-rep.lua
index 01868f490..95b801e2e 100644
--- a/tex/context/base/typo-rep.lua
+++ b/tex/context/base/typo-rep.lua
@@ -10,31 +10,44 @@ if not modules then modules = { } end modules ['typo-rep'] = {
-- endure it by listening to a couple cd's by The Scene and The Lau
-- on the squeezebox on my desk.
+local next, type, tonumber = next, type, tonumber
+
local trace_stripping = false trackers.register("nodes.stripping", function(v) trace_stripping = v end)
trackers.register("fonts.stripping", function(v) trace_stripping = v end)
local report_stripping = logs.reporter("fonts","stripping")
-local nodes, node = nodes, node
+local nodes = nodes
+local tasks = nodes.tasks
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getattr = nuts.getid
-local delete_node = nodes.delete
-local replace_node = nodes.replace
-local copy_node = node.copy
+local setattr = nuts.setattr
+
+local delete_node = nuts.delete
+local replace_node = nuts.replace
+local copy_node = nuts.copy
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
local chardata = characters.data
local collected = false
-local a_stripping = attributes.private("stripping")
local fontdata = fonts.hashes.identifiers
-local tasks = nodes.tasks
+local a_stripping = attributes.private("stripping")
local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
local v_reset = interfaces.variables.reset
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-
-- todo: other namespace -> typesetters
nodes.stripping = nodes.stripping or { } local stripping = nodes.stripping
@@ -59,13 +72,13 @@ local function process(what,head,current,char)
head, current = delete_node(head,current)
elseif type(what) == "function" then
head, current = what(head,current)
- current = current.next
+ current = getnext(current)
if trace_stripping then
report_stripping("processing %C in text",char)
end
elseif what then -- assume node
head, current = replace_node(head,current,copy_node(what))
- current = current.next
+ current = getnext(current)
if trace_stripping then
report_stripping("replacing %C in text",char)
end
@@ -74,28 +87,29 @@ local function process(what,head,current,char)
end
function nodes.handlers.stripping(head)
+ head = tonut(head)
local current, done = head, false
while current do
- if current.id == glyph_code then
+ if getid(current) == glyph_code then
-- it's more efficient to keep track of what needs to be kept
- local todo = current[a_stripping]
+ local todo = getattr(current,a_stripping)
if todo == 1 then
- local char = current.char
+ local char = getchar(current)
local what = glyphs[char]
if what then
head, current = process(what,head,current,char)
done = true
else -- handling of spacing etc has to be done elsewhere
- current = current.next
+ current = getnext(current)
end
else
- current = current.next
+ current = getnext(current)
end
else
- current = current.next
+ current = getnext(current)
end
end
- return head, done
+ return tonode(head), done
end
local enabled = false
diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua
index c3f50fe98..039f7c81d 100644
--- a/tex/context/base/typo-spa.lua
+++ b/tex/context/base/typo-spa.lua
@@ -15,10 +15,7 @@ local report_spacing = logs.reporter("typesetting","spacing")
local nodes, fonts, node = nodes, fonts, node
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local remove_node = nodes.remove
-local end_of_math = node.end_of_math
+local tasks = nodes.tasks
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
@@ -29,6 +26,27 @@ local unsetvalue = attributes.unsetvalue
local v_reset = interfaces.variables.reset
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getattr = nuts.getattr
+
+local setattr = nuts.setattr
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local end_of_math = nuts.end_of_math
+
+local nodepool = nuts.pool
+local new_penalty = nodepool.penalty
+local new_glue = nodepool.glue
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local math_code = nodecodes.math
@@ -36,12 +54,6 @@ local math_code = nodecodes.math
local somespace = nodes.somespace
local somepenalty = nodes.somepenalty
-local nodepool = nodes.pool
-local tasks = nodes.tasks
-
-local new_penalty = nodepool.penalty
-local new_glue = nodepool.glue
-
typesetters = typesetters or { }
local typesetters = typesetters
@@ -52,7 +64,6 @@ spacings.mapping = spacings.mapping or { }
spacings.numbers = spacings.numbers or { }
local a_spacings = attributes.private("spacing")
-spacings.attribute = a_spacings
storage.register("typesetters/spacings/mapping", spacings.mapping, "typesetters.spacings.mapping")
@@ -67,29 +78,30 @@ end
-- todo cache lastattr
function spacings.handler(head)
+ head = tonut(head)
local done = false
local start = head
-- head is always begin of par (whatsit), so we have at least two prev nodes
-- penalty followed by glue
while start do
- local id = start.id
+ local id = getid(start)
if id == glyph_code then
- local attr = start[a_spacings]
+ local attr = getattr(start,a_spacings)
if attr and attr > 0 then
local data = mapping[attr]
if data then
- local char = start.char
+ local char = getchar(start)
local map = data.characters[char]
- start[a_spacings] = unsetvalue -- needed?
+ setattr(start,a_spacings,unsetvalue) -- needed?
if map then
local left = map.left
local right = map.right
local alternative = map.alternative
- local quad = quaddata[start.font]
- local prev = start.prev
+ local quad = quaddata[getfont(start)]
+ local prev = getprev(start)
if left and left ~= 0 and prev then
local ok = false
- local prevprev = prev.prev
+ local prevprev = getprev(prev)
if alternative == 1 then
local somespace = somespace(prev,true)
if somespace then
@@ -120,10 +132,10 @@ function spacings.handler(head)
done = true
end
end
- local next = start.next
+ local next = getnext(start)
if right and right ~= 0 and next then
local ok = false
- local nextnext = next.next
+ local nextnext = getnext(next)
if alternative == 1 then
local somepenalty = somepenalty(next,10000)
if somepenalty then
@@ -164,10 +176,10 @@ function spacings.handler(head)
start = end_of_math(start) -- weird, can return nil .. no math end?
end
if start then
- start = start.next
+ start = getnext(start)
end
end
- return head, done
+ return tonode(head), done
end
local enabled = false
diff --git a/tex/context/base/typo-tal.lua b/tex/context/base/typo-tal.lua
index 63a66d037..e8c14e3e3 100644
--- a/tex/context/base/typo-tal.lua
+++ b/tex/context/base/typo-tal.lua
@@ -20,19 +20,34 @@ local fontcharacters = fonts.hashes.characters
local unicodes = fonts.hashes.unicodes
local categories = characters.categories -- nd
-local insert_node_before = nodes.insert_before
-local insert_node_after = nodes.insert_after
-local traverse_list_by_id = nodes.traverse_id
-local dimensions_of_list = nodes.dimensions
-local first_glyph = nodes.first_glyph
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
-local nodepool = nodes.pool
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getattr = nuts.getattr
+local getfield = nuts.getfield
+
+local setattr = nuts.setattr
+local setfield = nuts.setfield
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local traverse_list_by_id = nuts.traverse_id
+local dimensions_of_list = nuts.dimensions
+local first_glyph = nuts.first_glyph
+
+local nodepool = nuts.pool
local new_kern = nodepool.kern
local new_gluespec = nodepool.gluespec
local tracers = nodes.tracers
local setcolor = tracers.colors.set
-local tracedrule = tracers.pool.nodes.rule
+local tracedrule = tracers.pool.nuts.rule
local characteralign = { }
typesetters.characteralign = characteralign
@@ -69,10 +84,11 @@ local function traced_kern(w)
return tracedrule(w,nil,nil,"darkgray")
end
-function characteralign.handler(head,where)
+function characteralign.handler(originalhead,where)
if not datasets then
- return head, false
+ return originalhead, false
end
+ local head = tonut(originalhead)
-- local first = first_glyph(head) -- we could do that once
local first
for n in traverse_list_by_id(glyph_code,head) do
@@ -80,11 +96,11 @@ function characteralign.handler(head,where)
break
end
if not first then
- return head, false
+ return originalhead, false
end
- local a = first[a_characteralign]
+ local a = getattr(first,a_characteralign)
if not a or a == 0 then
- return head, false
+ return originalhead, false
end
local column = div(a,100)
local row = a % 100
@@ -100,10 +116,10 @@ function characteralign.handler(head,where)
local sign = nil
-- we can think of constraints
while current do
- local id = current.id
+ local id = getid(current)
if id == glyph_code then
- local char = current.char
- local font = current.font
+ local char = getchar(current)
+ local font = getfont(current)
local unicode = unicodes[font][char]
if not unicode then
-- no unicode so forget about it
@@ -126,13 +142,13 @@ function characteralign.handler(head,where)
if not b_start then
if sign then
b_start = sign
- local new = validsigns[sign.char]
- if char == new or not fontcharacters[sign.font][new] then
+ local new = validsigns[getchar(sign)]
+ if char == new or not fontcharacters[getfont(sign)][new] then
if trace_split then
setcolor(sign,"darkyellow")
end
else
- sign.char = new
+ setfield(sign,"char",new)
if trace_split then
setcolor(sign,"darkmagenta")
end
@@ -158,14 +174,14 @@ function characteralign.handler(head,where)
end
elseif (b_start or a_start) and id == glue_code then
-- somewhat inefficient
- local next = current.next
- local prev = current.prev
- if next and prev and next.id == glyph_code and prev.id == glyph_code then -- too much checking
- local width = fontcharacters[b_start.font][separator or period].width
- -- local spec = current.spec
+ local next = getnext(current)
+ local prev = getprev(current)
+ if next and prev and getid(next) == glyph_code and getid(prev) == glyph_code then -- too much checking
+ local width = fontcharacters[getfont(b_start)][separator or period].width
+ -- local spec = getfield(current,"spec")
-- nodes.free(spec) -- hm, we leak but not that many specs
- current.spec = new_gluespec(width)
- current[a_character] = punctuationspace
+ setfield(current,"spec",new_gluespec(width))
+ setattr(current,a_character,punctuationspace)
if a_start then
a_stop = current
elseif b_start then
@@ -173,7 +189,7 @@ function characteralign.handler(head,where)
end
end
end
- current = current.next
+ current = getnext(current)
end
local entry = list[row]
if entry then
@@ -207,7 +223,7 @@ function characteralign.handler(head,where)
if not c then
-- print("[before]")
if dataset.hasseparator then
- local width = fontcharacters[b_stop.font][separator].width
+ local width = fontcharacters[getfont(b_stop)][separator].width
insert_node_after(head,b_stop,new_kern(maxafter+width))
end
elseif a_start then
@@ -229,7 +245,7 @@ function characteralign.handler(head,where)
end
else
-- print("[after]")
- local width = fontcharacters[b_stop.font][separator].width
+ local width = fontcharacters[getfont(b_stop)][separator].width
head = insert_node_before(head,a_start,new_kern(maxbefore+width))
end
if after < maxafter then
@@ -246,12 +262,12 @@ function characteralign.handler(head,where)
end
else
entry = {
- before = b_start and dimensions_of_list(b_start,b_stop.next) or 0,
- after = a_start and dimensions_of_list(a_start,a_stop.next) or 0,
+ before = b_start and dimensions_of_list(b_start,getnext(b_stop)) or 0,
+ after = a_start and dimensions_of_list(a_start,getnext(a_stop)) or 0,
}
list[row] = entry
end
- return head, true
+ return tonode(head), true
end
function setcharacteralign(column,separator)
diff --git a/tex/generic/context/luatex/luatex-fonts-inj.lua b/tex/generic/context/luatex/luatex-fonts-inj.lua
new file mode 100644
index 000000000..ae48150a6
--- /dev/null
+++ b/tex/generic/context/luatex/luatex-fonts-inj.lua
@@ -0,0 +1,526 @@
+if not modules then modules = { } end modules ['node-inj'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- This is very experimental (this will change when we have luatex > .50 and
+-- a few pending thingies are available. Also, Idris needs to make a few more
+-- test fonts. Btw, future versions of luatex will have extended glyph properties
+-- that can be of help. Some optimizations can go away when we have faster machines.
+
+-- todo: make a special one for context
+
+local next = next
+local utfchar = utf.char
+
+local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+
+local report_injections = logs.reporter("nodes","injections")
+
+local attributes, nodes, node = attributes, nodes, node
+
+fonts = fonts
+local fontdata = fonts.hashes.identifiers
+
+nodes.injections = nodes.injections or { }
+local injections = nodes.injections
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
+local nodepool = nodes.pool
+local newkern = nodepool.kern
+
+local traverse_id = node.traverse_id
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+
+local a_kernpair = attributes.private('kernpair')
+local a_ligacomp = attributes.private('ligacomp')
+local a_markbase = attributes.private('markbase')
+local a_markmark = attributes.private('markmark')
+local a_markdone = attributes.private('markdone')
+local a_cursbase = attributes.private('cursbase')
+local a_curscurs = attributes.private('curscurs')
+local a_cursdone = attributes.private('cursdone')
+
+-- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as
+-- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner
+-- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure
+-- that this code is not 100% okay but examples are needed to figure things out.
+
+function injections.installnewkern(nk)
+ newkern = nk or newkern
+end
+
+local cursives = { }
+local marks = { }
+local kerns = { }
+
+-- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in
+-- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we
+-- can share tables.
+
+-- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs
+-- checking with husayni (volt and fontforge).
+
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+ local ws, wn = tfmstart.width, tfmnext.width
+ local bound = #cursives + 1
+ start[a_cursbase] = bound
+ nxt[a_curscurs] = bound
+ cursives[bound] = { rlmode, dx, dy, ws, wn }
+ return dx, dy, bound
+end
+
+function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
+ local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
+ -- dy = y - h
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
+ local bound = current[a_kernpair]
+ if bound then
+ local kb = kerns[bound]
+ -- inefficient but singles have less, but weird anyway, needs checking
+ kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
+ else
+ bound = #kerns + 1
+ current[a_kernpair] = bound
+ kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
+ end
+ return x, y, w, h, bound
+ end
+ return x, y, w, h -- no bound
+end
+
+function injections.setkern(current,factor,rlmode,x,tfmchr)
+ local dx = factor*x
+ if dx ~= 0 then
+ local bound = #kerns + 1
+ current[a_kernpair] = bound
+ kerns[bound] = { rlmode, dx }
+ return dx, bound
+ else
+ return 0, 0
+ end
+end
+
+function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) -- ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) -- the index argument is no longer used but when this
+ local bound = base[a_markbase] -- fails again we should pass it
+ local index = 1
+ if bound then
+ local mb = marks[bound]
+ if mb then
+ -- if not index then index = #mb + 1 end
+ index = #mb + 1
+ mb[index] = { dx, dy, rlmode }
+ start[a_markmark] = bound
+ start[a_markdone] = index
+ return dx, dy, bound
+ else
+ report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
+ end
+ end
+-- index = index or 1
+ index = index or 1
+ bound = #marks + 1
+ base[a_markbase] = bound
+ start[a_markmark] = bound
+ start[a_markdone] = index
+ marks[bound] = { [index] = { dx, dy, rlmode, baseismark } }
+ return dx, dy, bound
+end
+
+local function dir(n)
+ return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
+end
+
+local function trace(head)
+ report_injections("begin run")
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ local kp = n[a_kernpair]
+ local mb = n[a_markbase]
+ local mm = n[a_markmark]
+ local md = n[a_markdone]
+ local cb = n[a_cursbase]
+ local cc = n[a_curscurs]
+ local char = n.char
+ report_injections("font %s, char %U, glyph %c",n.font,char,char)
+ if kp then
+ local k = kerns[kp]
+ if k[3] then
+ report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
+ else
+ report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
+ end
+ end
+ if mb then
+ report_injections(" markbase: bound %a",mb)
+ end
+ if mm then
+ local m = marks[mm]
+ if mb then
+ local m = m[mb]
+ if m then
+ report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
+ else
+ report_injections(" markmark: bound %a, missing index",mm)
+ end
+ else
+ m = m[1]
+ report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
+ end
+ end
+ if cb then
+ report_injections(" cursbase: bound %a",cb)
+ end
+ if cc then
+ local c = cursives[cc]
+ report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
+ end
+ end
+ end
+ report_injections("end run")
+end
+
+-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
+-- todo: check for attribute
+
+-- We can have a fast test on a font being processed, so we can check faster for marks etc
+-- but I'll make a context variant anyway.
+
+local function show_result(head)
+ local current = head
+ local skipping = false
+ while current do
+ local id = current.id
+ if id == glyph_code then
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
+ skipping = false
+ elseif id == kern_code then
+ report_injections("kern: %p",current.kern)
+ skipping = false
+ elseif not skipping then
+ report_injections()
+ skipping = true
+ end
+ current = current.next
+ end
+end
+
+function injections.handler(head,where,keep)
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ if trace_injections then
+ trace(head)
+ end
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
+ if has_kerns then -- move outside loop
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
+ if n.subtype < 256 then
+ nofvalid = nofvalid + 1
+ valid[nofvalid] = n
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
+ end
+ local k = n[a_kernpair]
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ rl[n] = kk[1] -- could move in test
+ end
+ end
+ end
+ end
+ else
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ nofvalid = nofvalid + 1
+ valid[nofvalid] = n
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
+ end
+ end
+ end
+ end
+ if nofvalid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local p_cursbase, p = nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,nofvalid do -- valid == glyphs
+ local n = valid[i]
+ if not mk[n] then
+ local n_cursbase = n[a_cursbase]
+ if p_cursbase then
+ local n_curscurs = n[a_curscurs]
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+ cx[n] = dx
+ rl[n] = rlmode
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ti.yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ for i=1,nofvalid do
+ local p = valid[i]
+ local p_markbase = p[a_markbase]
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ local nofmarks = #mrks
+ for n in traverse_id(glyph_code,p.next) do
+ local n_markmark = n[a_markmark]
+ if p_markbase == n_markmark then
+ local index = n[a_markdone] or 1
+ local d = mrks[index]
+ if d then
+ local rlmode = d[3]
+ --
+ local k = wx[p]
+ if k then
+ local x = k[2]
+ local w = k[4]
+ if w then
+ if rlmode and rlmode >= 0 then
+ -- kern(x) glyph(p) kern(w-x) mark(n)
+ n.xoffset = p.xoffset - p.width + d[1] - (w-x)
+ else
+ -- kern(w-x) glyph(p) kern(x) mark(n)
+ n.xoffset = p.xoffset - d[1] - x
+ end
+ else
+ if rlmode and rlmode >= 0 then
+ -- okay for husayni
+ n.xoffset = p.xoffset - p.width + d[1]
+ else
+ -- needs checking: is x ok here?
+ n.xoffset = p.xoffset - d[1] - x
+ end
+ end
+ else
+ if rlmode and rlmode >= 0 then
+ n.xoffset = p.xoffset - p.width + d[1]
+ else
+ n.xoffset = p.xoffset - d[1]
+ end
+ local w = n.width
+ if w ~= 0 then
+ insert_node_before(head,n,newkern(-w/2))
+ insert_node_after(head,n,newkern(-w/2))
+ end
+ end
+ -- --
+ if mk[p] then
+ n.yoffset = p.yoffset + d[2]
+ else
+ n.yoffset = n.yoffset + p.yoffset + d[2]
+ end
+ --
+ if nofmarks == 1 then
+ break
+ else
+ nofmarks = nofmarks - 1
+ end
+ end
+ else
+ -- KE: there can be <mark> <mkmk> <mark> sequences in ligatures
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil (kernclasses), can be sped up when w == nil
+ local x = k[2]
+ local w = k[4]
+ if w then
+ local rl = k[1] -- r2l = k[6]
+ local wx = w - x
+ if rl < 0 then -- KE: don't use r2l here
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx)) -- type 0/2
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x)) -- type 0/2
+ end
+ else
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x)) -- type 0/2
+ end
+ if wx ~= 0 then
+ insert_node_after (head,n,newkern(wx)) -- type 0/2
+ end
+ end
+ elseif x ~= 0 then
+ -- this needs checking for rl < 0 but it is unlikely that a r2l script
+ -- uses kernclasses between glyphs so we're probably safe (KE has a
+ -- problematic font where marks interfere with rl < 0 in the previous
+ -- case)
+ insert_node_before(head,n,newkern(x)) -- a real font kern, type 0
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ if k ~= 0 then
+ local rln = rl[n]
+ if rln and rln < 0 then
+ insert_node_before(head,n,newkern(-k)) -- type 0/2
+ else
+ insert_node_before(head,n,newkern(k)) -- type 0/2
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ -- if trace_injections then
+ -- show_result(head)
+ -- end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ if trace_injections then
+ trace(head)
+ end
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ local k = n[a_kernpair]
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
+ if y and y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ if w then
+ -- copied from above
+ -- local r2l = kk[6]
+ local wx = w - x
+ if rl < 0 then -- KE: don't use r2l here
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ if wx ~= 0 then
+ insert_node_after(head,n,newkern(wx))
+ end
+ end
+ else
+ -- simple (e.g. kernclass kerns)
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ -- if trace_injections then
+ -- show_result(head)
+ -- end
+ return head, true
+ else
+ -- no tracing needed
+ end
+ return head, false
+end
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 5255cd5d0..79755720a 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 01/07/14 01:06:05
+-- merge date : 01/07/14 14:00:03
do -- begin closure to overcome local limits and interference
@@ -8903,26 +8903,12 @@ nodes.injections=nodes.injections or {}
local injections=nodes.injections
local nodecodes=nodes.nodecodes
local glyph_code=nodecodes.glyph
-local disc_code=nodecodes.disc
local kern_code=nodecodes.kern
-local nuts=nodes.nuts
-local nodepool=nuts.pool
+local nodepool=nodes.pool
local newkern=nodepool.kern
-local tonode=nuts.tonode
-local tonut=nuts.tonut
-local getfield=nuts.getfield
-local getnext=nuts.getnext
-local getprev=nuts.getprev
-local getid=nuts.getid
-local getattr=nuts.getattr
-local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
-local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
-local traverse_id=nuts.traverse_id
-local insert_node_before=nuts.insert_before
-local insert_node_after=nuts.insert_after
+local traverse_id=node.traverse_id
+local insert_node_before=node.insert_before
+local insert_node_after=node.insert_after
local a_kernpair=attributes.private('kernpair')
local a_ligacomp=attributes.private('ligacomp')
local a_markbase=attributes.private('markbase')
@@ -8941,21 +8927,21 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
local ws,wn=tfmstart.width,tfmnext.width
local bound=#cursives+1
- setattr(start,a_cursbase,bound)
- setattr(nxt,a_curscurs,bound)
+ start[a_cursbase]=bound
+ nxt[a_curscurs]=bound
cursives[bound]={ rlmode,dx,dy,ws,wn }
return dx,dy,bound
end
function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
if x~=0 or w~=0 or y~=0 or h~=0 then
- local bound=getattr(current,a_kernpair)
+ local bound=current[a_kernpair]
if bound then
local kb=kerns[bound]
kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
else
bound=#kerns+1
- setattr(current,a_kernpair,bound)
+ current[a_kernpair]=bound
kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
end
return x,y,w,h,bound
@@ -8966,7 +8952,7 @@ function injections.setkern(current,factor,rlmode,x,tfmchr)
local dx=factor*x
if dx~=0 then
local bound=#kerns+1
- setattr(current,a_kernpair,bound)
+ current[a_kernpair]=bound
kerns[bound]={ rlmode,dx }
return dx,bound
else
@@ -8975,25 +8961,25 @@ function injections.setkern(current,factor,rlmode,x,tfmchr)
end
function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
- local bound=getattr(base,a_markbase)
+ local bound=base[a_markbase]
local index=1
if bound then
local mb=marks[bound]
if mb then
index=#mb+1
mb[index]={ dx,dy,rlmode }
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
+ start[a_markmark]=bound
+ start[a_markdone]=index
return dx,dy,bound
else
- report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+ report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
end
end
index=index or 1
bound=#marks+1
- setattr(base,a_markbase,bound)
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
+ base[a_markbase]=bound
+ start[a_markmark]=bound
+ start[a_markdone]=index
marks[bound]={ [index]={ dx,dy,rlmode,baseismark } }
return dx,dy,bound
end
@@ -9003,15 +8989,15 @@ end
local function trace(head)
report_injections("begin run")
for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local kp=getattr(n,a_kernpair)
- local mb=getattr(n,a_markbase)
- local mm=getattr(n,a_markmark)
- local md=getattr(n,a_markdone)
- local cb=getattr(n,a_cursbase)
- local cc=getattr(n,a_curscurs)
- local char=getchar(n)
- report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
+ if n.subtype<256 then
+ local kp=n[a_kernpair]
+ local mb=n[a_markbase]
+ local mm=n[a_markmark]
+ local md=n[a_markdone]
+ local cb=n[a_cursbase]
+ local cc=n[a_curscurs]
+ local char=n.char
+ report_injections("font %s, char %U, glyph %c",n.font,char,char)
if kp then
local k=kerns[kp]
if k[3] then
@@ -9052,23 +9038,21 @@ local function show_result(head)
local current=head
local skipping=false
while current do
- local id=getid(current)
+ local id=current.id
if id==glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",
- getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
skipping=false
elseif id==kern_code then
- report_injections("kern: %p",getfield(current,"kern"))
+ report_injections("kern: %p",current.kern)
skipping=false
elseif not skipping then
report_injections()
skipping=true
end
- current=getnext(current)
+ current=current.next
end
end
function injections.handler(head,where,keep)
- head=tonut(head)
local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
if has_marks or has_cursives then
if trace_injections then
@@ -9078,18 +9062,17 @@ function injections.handler(head,where,keep)
if has_kerns then
local nf,tm=nil,nil
for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
+ if n.subtype<256 then
nofvalid=nofvalid+1
valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
+ if n.font~=nf then
+ nf=n.font
+ tm=fontdata[nf].resources.marks
end
if tm then
- mk[n]=tm[getchar(n)]
+ mk[n]=tm[n.char]
end
- local k=getattr(n,a_kernpair)
+ local k=n[a_kernpair]
if k then
local kk=kerns[k]
if kk then
@@ -9109,16 +9092,15 @@ function injections.handler(head,where,keep)
else
local nf,tm=nil,nil
for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
+ if n.subtype<256 then
nofvalid=nofvalid+1
valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
+ if n.font~=nf then
+ nf=n.font
+ tm=fontdata[nf].resources.marks
end
if tm then
- mk[n]=tm[getchar(n)]
+ mk[n]=tm[n.char]
end
end
end
@@ -9127,7 +9109,7 @@ function injections.handler(head,where,keep)
local cx={}
if has_kerns and next(ky) then
for n,k in next,ky do
- setfield(n,"yoffset",k)
+ n.yoffset=k
end
end
if has_cursives then
@@ -9136,9 +9118,9 @@ function injections.handler(head,where,keep)
for i=1,nofvalid do
local n=valid[i]
if not mk[n] then
- local n_cursbase=getattr(n,a_cursbase)
+ local n_cursbase=n[a_cursbase]
if p_cursbase then
- local n_curscurs=getattr(n,a_curscurs)
+ local n_curscurs=n[a_curscurs]
if p_cursbase==n_curscurs then
local c=cursives[n_curscurs]
if c then
@@ -9161,20 +9143,20 @@ function injections.handler(head,where,keep)
end
end
elseif maxt>0 then
- local ny=getfield(n,"yoffset")
+ local ny=n.yoffset
for i=maxt,1,-1 do
ny=ny+d[i]
local ti=t[i]
- setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+ ti.yoffset=ti.yoffset+ny
end
maxt=0
end
if not n_cursbase and maxt>0 then
- local ny=getfield(n,"yoffset")
+ local ny=n.yoffset
for i=maxt,1,-1 do
ny=ny+d[i]
local ti=t[i]
- setfield(ti,"yoffset",ny)
+ ti.yoffset=ny
end
maxt=0
end
@@ -9182,11 +9164,11 @@ function injections.handler(head,where,keep)
end
end
if maxt>0 then
- local ny=getfield(n,"yoffset")
+ local ny=n.yoffset
for i=maxt,1,-1 do
ny=ny+d[i]
local ti=t[i]
- setfield(ti,"yoffset",ny)
+ ti.yoffset=ny
end
maxt=0
end
@@ -9197,66 +9179,57 @@ function injections.handler(head,where,keep)
if has_marks then
for i=1,nofvalid do
local p=valid[i]
- local p_markbase=getattr(p,a_markbase)
+ local p_markbase=p[a_markbase]
if p_markbase then
local mrks=marks[p_markbase]
local nofmarks=#mrks
- for n in traverse_id(glyph_code,getnext(p)) do
- local n_markmark=getattr(n,a_markmark)
+ for n in traverse_id(glyph_code,p.next) do
+ local n_markmark=n[a_markmark]
if p_markbase==n_markmark then
- local index=getattr(n,a_markdone) or 1
+ local index=n[a_markdone] or 1
local d=mrks[index]
if d then
local rlmode=d[3]
local k=wx[p]
- local px=getfield(p,"xoffset")
- local ox=0
if k then
local x=k[2]
local w=k[4]
if w then
if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]-(w-x)
+ n.xoffset=p.xoffset-p.width+d[1]-(w-x)
else
- ox=px-d[1]-x
+ n.xoffset=p.xoffset-d[1]-x
end
else
if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]
+ n.xoffset=p.xoffset-p.width+d[1]
else
- ox=px-d[1]-x
+ n.xoffset=p.xoffset-d[1]-x
end
end
else
- local wp=getfield(p,"width")
- local wn=getfield(n,"width")
if rlmode and rlmode>=0 then
- ox=px-wp+d[1]
+ n.xoffset=p.xoffset-p.width+d[1]
else
- ox=px-d[1]
+ n.xoffset=p.xoffset-d[1]
end
- if wn~=0 then
- insert_node_before(head,n,newkern(-wn/2))
- insert_node_after(head,n,newkern(-wn/2))
+ local w=n.width
+ if w~=0 then
+ insert_node_before(head,n,newkern(-w/2))
+ insert_node_after(head,n,newkern(-w/2))
end
end
- setfield(n,"xoffset",ox)
- local py=getfield(p,"yoffset")
- local oy=0
if mk[p] then
- oy=py+d[2]
+ n.yoffset=p.yoffset+d[2]
else
- oy=getfield(n,"yoffset")+py+d[2]
+ n.yoffset=n.yoffset+p.yoffset+d[2]
end
- setfield(n,"yoffset",oy)
if nofmarks==1 then
break
else
nofmarks=nofmarks-1
end
end
- elseif not n_markmark then
- break
else
end
end
@@ -9308,7 +9281,6 @@ function injections.handler(head,where,keep)
if not keep then
kerns={}
end
-head=tonode(head)
return head,true
elseif not keep then
kerns,cursives,marks={},{},{}
@@ -9318,14 +9290,14 @@ head=tonode(head)
trace(head)
end
for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local k=getattr(n,a_kernpair)
+ if n.subtype<256 then
+ local k=n[a_kernpair]
if k then
local kk=kerns[k]
if kk then
local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
if y and y~=0 then
- setfield(n,"yoffset",y)
+ n.yoffset=y
end
if w then
local wx=w-x
@@ -9356,10 +9328,10 @@ head=tonode(head)
if not keep then
kerns={}
end
- return tonode(head),true
+ return head,true
else
end
- return tonode(head),false
+ return head,false
end
end -- closure
@@ -9774,25 +9746,12 @@ registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
registertracker("otf.actions","otf.replacements,otf.positions")
registertracker("otf.injections","nodes.injections")
registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
-local getfield=nuts.getfield
-local getnext=nuts.getnext
-local getprev=nuts.getprev
-local getid=nuts.getid
-local getattr=nuts.getattr
-local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
-local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
-local insert_node_after=nuts.insert_after
-local delete_node=nuts.delete
-local copy_node=nuts.copy
-local find_node_tail=nuts.tail
-local flush_node_list=nuts.flush_list
-local end_of_math=nuts.end_of_math
+local insert_node_after=node.insert_after
+local delete_node=nodes.delete
+local copy_node=node.copy
+local find_node_tail=node.tail or node.slide
+local flush_node_list=node.flush_list
+local end_of_math=node.end_of_math
local setmetatableindex=table.setmetatableindex
local zwnj=0x200C
local zwj=0x200D
@@ -9903,83 +9862,83 @@ local function pref(kind,lookupname)
return formatters["feature %a, lookup %a"](kind,lookupname)
end
local function copy_glyph(g)
- local components=getfield(g,"components")
+ local components=g.components
if components then
- setfield(g,"components",nil)
+ g.components=nil
local n=copy_node(g)
- setfield(g,"components",components)
+ g.components=components
return n
else
return copy_node(g)
end
end
local function markstoligature(kind,lookupname,head,start,stop,char)
- if start==stop and getchar(start)==char then
+ if start==stop and start.char==char then
return head,start
else
- local prev=getprev(start)
- local next=getnext(stop)
- setfield(start,"prev",nil)
- setfield(stop,"next",nil)
+ local prev=start.prev
+ local next=stop.next
+ start.prev=nil
+ stop.next=nil
local base=copy_glyph(start)
if head==start then
head=base
end
- setfield(base,"char",char)
- setfield(base,"subtype",ligature_code)
- setfield(base,"components",start)
+ base.char=char
+ base.subtype=ligature_code
+ base.components=start
if prev then
- setfield(prev,"next",base)
+ prev.next=base
end
if next then
- setfield(next,"prev",base)
+ next.prev=base
end
- setfield(base,"next",next)
- setfield(base,"prev",prev)
+ base.next=next
+ base.prev=prev
return head,base
end
end
local function getcomponentindex(start)
- if getid(start)~=glyph_code then
+ if start.id~=glyph_code then
return 0
- elseif getsubtype(start)==ligature_code then
+ elseif start.subtype==ligature_code then
local i=0
- local components=getfield(start,"components")
+ local components=start.components
while components do
i=i+getcomponentindex(components)
- components=getnext(components)
+ components=components.next
end
return i
- elseif not marks[getchar(start)] then
+ elseif not marks[start.char] then
return 1
else
return 0
end
end
local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound)
- if start==stop and getchar(start)==char then
- setfield(start,"char",char)
+ if start==stop and start.char==char then
+ start.char=char
return head,start
end
- local prev=getprev(start)
- local next=getnext(stop)
- setfield(start,"prev",nil)
- setfield(stop,"next",nil)
+ local prev=start.prev
+ local next=stop.next
+ start.prev=nil
+ stop.next=nil
local base=copy_glyph(start)
if start==head then
head=base
end
- setfield(base,"char",char)
- setfield(base,"subtype",ligature_code)
- setfield(base,"components",start)
+ base.char=char
+ base.subtype=ligature_code
+ base.components=start
if prev then
- setfield(prev,"next",base)
+ prev.next=base
end
if next then
- setfield(next,"prev",base)
+ next.prev=base
end
- setfield(base,"next",next)
- setfield(base,"prev",prev)
+ base.next=next
+ base.prev=prev
if not discfound then
local deletemarks=markflag~="mark"
local components=start
@@ -9988,42 +9947,42 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
local head=base
local current=base
while start do
- local char=getchar(start)
+ local char=start.char
if not marks[char] then
baseindex=baseindex+componentindex
componentindex=getcomponentindex(start)
elseif not deletemarks then
- setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex))
+ start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
end
head,current=insert_node_after(head,current,copy_node(start))
elseif trace_marks then
logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
end
- start=getnext(start)
+ start=start.next
end
- local start=getnext(current)
- while start and getid(start)==glyph_code do
- local char=getchar(start)
+ local start=current.next
+ while start and start.id==glyph_code do
+ local char=start.char
if marks[char] then
- setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex))
+ start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
if trace_marks then
- logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
+ logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
end
else
break
end
- start=getnext(start)
+ start=start.next
end
end
return head,base
end
function handlers.gsub_single(head,start,kind,lookupname,replacement)
if trace_singles then
- logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement))
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
end
- setfield(start,"char",replacement)
+ start.char=replacement
return head,start,true
end
local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
@@ -10049,7 +10008,7 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives
return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
end
elseif value==0 then
- return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
+ return start.char,trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
elseif value<1 then
return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
else
@@ -10060,25 +10019,25 @@ end
local function multiple_glyphs(head,start,multiple,ignoremarks)
local nofmultiples=#multiple
if nofmultiples>0 then
- setfield(start,"char",multiple[1])
+ start.char=multiple[1]
if nofmultiples>1 then
- local sn=getnext(start)
+ local sn=start.next
for k=2,nofmultiples do
local n=copy_node(start)
- setfield(n,"char",multiple[k])
- setfield(n,"next",sn)
- setfield(n,"prev",start)
+ n.char=multiple[k]
+ n.next=sn
+ n.prev=start
if sn then
- setfield(sn,"prev",n)
+ sn.prev=n
end
- setfield(start,"next",n)
+ start.next=n
start=n
end
end
return head,start,true
else
if trace_multiples then
- logprocess("no multiple for %s",gref(getchar(start)))
+ logprocess("no multiple for %s",gref(start.char))
end
return head,start,false
end
@@ -10088,34 +10047,34 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence
local choice,comment=get_alternative_glyph(start,alternative,value,trace_alternatives)
if choice then
if trace_alternatives then
- logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment)
+ logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
end
- setfield(start,"char",choice)
+ start.char=choice
else
if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment)
+ logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
end
end
return head,start,true
end
function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
if trace_multiples then
- logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(getchar(start)),gref(multiple))
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
end
return multiple_glyphs(head,start,multiple,sequence.flags[1])
end
function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
- local s,stop,discfound=getnext(start),nil,false
- local startchar=getchar(start)
+ local s,stop,discfound=start.next,nil,false
+ local startchar=start.char
if marks[startchar] then
while s do
- local id=getid(s)
- if id==glyph_code and getfont(s)==currentfont and getsubtype(s)<256 then
- local lg=ligature[getchar(s)]
+ local id=s.id
+ if id==glyph_code and s.font==currentfont and s.subtype<256 then
+ local lg=ligature[s.char]
if lg then
stop=s
ligature=lg
- s=getnext(s)
+ s=s.next
else
break
end
@@ -10127,9 +10086,9 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
local lig=ligature.ligature
if lig then
if trace_ligatures then
- local stopchar=getchar(stop)
+ local stopchar=stop.char
head,start=markstoligature(kind,lookupname,head,start,stop,lig)
- logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
+ logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
head,start=markstoligature(kind,lookupname,head,start,stop,lig)
end
@@ -10140,18 +10099,18 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
else
local skipmark=sequence.flags[1]
while s do
- local id=getid(s)
- if id==glyph_code and getsubtype(s)<256 then
- if getfont(s)==currentfont then
- local char=getchar(s)
+ local id=s.id
+ if id==glyph_code and s.subtype<256 then
+ if s.font==currentfont then
+ local char=s.char
if skipmark and marks[char] then
- s=getnext(s)
+ s=s.next
else
local lg=ligature[char]
if lg then
stop=s
ligature=lg
- s=getnext(s)
+ s=s.next
else
break
end
@@ -10161,7 +10120,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
end
elseif id==disc_code then
discfound=true
- s=getnext(s)
+ s=s.next
else
break
end
@@ -10170,35 +10129,36 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
if lig then
if stop then
if trace_ligatures then
- local stopchar=getchar(stop)
+ local stopchar=stop.char
head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
- logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
end
+ return head,start,true
else
- setfield(start,"char",lig)
+ start.char=lig
if trace_ligatures then
logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
end
+ return head,start,true
end
- return head,start,true
else
end
end
return head,start,false
end
function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
- local base=getprev(start)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ local base=start.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
if marks[basechar] then
while true do
- base=getprev(base)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- basechar=getchar(base)
+ base=base.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ basechar=base.char
if not marks[basechar] then
break
end
@@ -10247,16 +10207,16 @@ function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence
return head,start,false
end
function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
- local base=getprev(start)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ local base=start.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
if marks[basechar] then
while true do
- base=getprev(base)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- basechar=getchar(base)
+ base=base.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ basechar=base.char
if not marks[basechar] then
break
end
@@ -10268,7 +10228,7 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
end
end
end
- local index=getattr(start,a_ligacomp)
+ local index=start[a_ligacomp]
local baseanchors=descriptions[basechar]
if baseanchors then
baseanchors=baseanchors.anchors
@@ -10313,22 +10273,22 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
return head,start,false
end
function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
- local base=getprev(start)
- local slc=getattr(start,a_ligacomp)
+ local base=start.prev
+ local slc=start[a_ligacomp]
if slc then
while base do
- local blc=getattr(base,a_ligacomp)
+ local blc=base[a_ligacomp]
if blc and blc~=slc then
- base=getprev(base)
+ base=base.prev
else
break
end
end
end
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
local baseanchors=descriptions[basechar]
if baseanchors then
baseanchors=baseanchors.anchors
@@ -10366,20 +10326,20 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
return head,start,false
end
function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
- local alreadydone=cursonce and getattr(start,a_cursbase)
+ local alreadydone=cursonce and start[a_cursbase]
if not alreadydone then
local done=false
- local startchar=getchar(start)
+ local startchar=start.char
if marks[startchar] then
if trace_cursive then
logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
end
else
- local nxt=getnext(start)
- while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do
- local nextchar=getchar(nxt)
+ local nxt=start.next
+ while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
+ local nextchar=nxt.char
if marks[nextchar] then
- nxt=getnext(nxt)
+ nxt=nxt.next
else
local entryanchors=descriptions[nextchar]
if entryanchors then
@@ -10413,13 +10373,13 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
return head,start,done
else
if trace_cursive and trace_details then
- logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
end
return head,start,false
end
end
function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
- local startchar=getchar(start)
+ local startchar=start.char
local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
@@ -10427,33 +10387,33 @@ function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
return head,start,false
end
function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
- local snext=getnext(start)
+ local snext=start.next
if not snext then
return head,start,false
else
local prev,done=start,false
local factor=tfmdata.parameters.factor
local lookuptype=lookuptypes[lookupname]
- while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do
- local nextchar=getchar(snext)
+ while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
+ local nextchar=snext.char
local krn=kerns[nextchar]
if not krn and marks[nextchar] then
prev=snext
- snext=getnext(snext)
+ snext=snext.next
else
if not krn then
elseif type(krn)=="table" then
if lookuptype=="pair" then
local a,b=krn[2],krn[3]
if a and #a>0 then
- local startchar=getchar(start)
+ local startchar=start.char
local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b>0 then
- local startchar=getchar(start)
+ local startchar=start.char
local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -10466,7 +10426,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
elseif krn~=0 then
local k=setkern(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
end
done=true
end
@@ -10501,13 +10461,13 @@ function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,looku
return head,start,false
end
function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
- local char=getchar(start)
+ local char=start.char
local replacement=replacements[char]
if replacement then
if trace_singles then
logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
end
- setfield(start,"char",replacement)
+ start.char=replacement
return head,start,true
else
return head,start,false
@@ -10520,8 +10480,8 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
end
while current do
- if getid(current)==glyph_code then
- local currentchar=getchar(current)
+ if current.id==glyph_code then
+ local currentchar=current.char
local lookupname=subtables[1]
local replacement=lookuphash[lookupname]
if not replacement then
@@ -10538,21 +10498,21 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
if trace_singles then
logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
end
- setfield(current,"char",replacement)
+ current.char=replacement
end
end
return head,start,true
elseif current==stop then
break
else
- current=getnext(current)
+ current=current.next
end
end
return head,start,false
end
chainmores.gsub_single=chainprocs.gsub_single
function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local startchar=getchar(start)
+ local startchar=start.char
local subtables=currentlookup.subtables
local lookupname=subtables[1]
local replacements=lookuphash[lookupname]
@@ -10581,8 +10541,8 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
local subtables=currentlookup.subtables
local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue
while current do
- if getid(current)==glyph_code then
- local currentchar=getchar(current)
+ if current.id==glyph_code then
+ local currentchar=current.char
local lookupname=subtables[1]
local alternatives=lookuphash[lookupname]
if not alternatives then
@@ -10597,7 +10557,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
if trace_alternatives then
logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
end
- setfield(start,"char",choice)
+ start.char=choice
else
if trace_alternatives then
logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
@@ -10611,14 +10571,14 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
elseif current==stop then
break
else
- current=getnext(current)
+ current=current.next
end
end
return head,start,false
end
chainmores.gsub_alternate=chainprocs.gsub_alternate
function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
- local startchar=getchar(start)
+ local startchar=start.char
local subtables=currentlookup.subtables
local lookupname=subtables[1]
local ligatures=lookuphash[lookupname]
@@ -10633,20 +10593,20 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
end
else
- local s=getnext(start)
+ local s=start.next
local discfound=false
local last=stop
local nofreplacements=0
local skipmark=currentlookup.flags[1]
while s do
- local id=getid(s)
+ local id=s.id
if id==disc_code then
- s=getnext(s)
+ s=s.next
discfound=true
else
- local schar=getchar(s)
+ local schar=s.char
if skipmark and marks[schar] then
- s=getnext(s)
+ s=s.next
else
local lg=ligatures[schar]
if lg then
@@ -10654,7 +10614,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if s==stop then
break
else
- s=getnext(s)
+ s=s.next
end
else
break
@@ -10671,7 +10631,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if start==stop then
logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
else
- logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)),gref(l2))
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
end
end
head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
@@ -10680,7 +10640,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
if start==stop then
logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
else
- logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)))
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
end
end
end
@@ -10689,7 +10649,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
end
chainmores.gsub_ligature=chainprocs.gsub_ligature
function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
local subtables=currentlookup.subtables
local lookupname=subtables[1]
@@ -10698,14 +10658,14 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
markanchors=markanchors[markchar]
end
if markanchors then
- local base=getprev(start)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ local base=start.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
if marks[basechar] then
while true do
- base=getprev(base)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- basechar=getchar(base)
+ base=base.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ basechar=base.char
if not marks[basechar] then
break
end
@@ -10752,7 +10712,7 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
return head,start,false
end
function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
local subtables=currentlookup.subtables
local lookupname=subtables[1]
@@ -10761,14 +10721,14 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
markanchors=markanchors[markchar]
end
if markanchors then
- local base=getprev(start)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ local base=start.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
if marks[basechar] then
while true do
- base=getprev(base)
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- basechar=getchar(base)
+ base=base.prev
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ basechar=base.char
if not marks[basechar] then
break
end
@@ -10780,7 +10740,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
end
end
end
- local index=getattr(start,a_ligacomp)
+ local index=start[a_ligacomp]
local baseanchors=descriptions[basechar].anchors
if baseanchors then
local baseanchors=baseanchors['baselig']
@@ -10819,7 +10779,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
return head,start,false
end
function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local markchar=getchar(start)
+ local markchar=start.char
if marks[markchar] then
local subtables=currentlookup.subtables
local lookupname=subtables[1]
@@ -10828,20 +10788,20 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
markanchors=markanchors[markchar]
end
if markanchors then
- local base=getprev(start)
- local slc=getattr(start,a_ligacomp)
+ local base=start.prev
+ local slc=start[a_ligacomp]
if slc then
while base do
- local blc=getattr(base,a_ligacomp)
+ local blc=base[a_ligacomp]
if blc and blc~=slc then
- base=getprev(base)
+ base=base.prev
else
break
end
end
end
- if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
- local basechar=getchar(base)
+ if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+ local basechar=base.char
local baseanchors=descriptions[basechar].anchors
if baseanchors then
baseanchors=baseanchors['basemark']
@@ -10877,9 +10837,9 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
return head,start,false
end
function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- local alreadydone=cursonce and getattr(start,a_cursbase)
+ local alreadydone=cursonce and start[a_cursbase]
if not alreadydone then
- local startchar=getchar(start)
+ local startchar=start.char
local subtables=currentlookup.subtables
local lookupname=subtables[1]
local exitanchors=lookuphash[lookupname]
@@ -10893,11 +10853,11 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
end
else
- local nxt=getnext(start)
- while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do
- local nextchar=getchar(nxt)
+ local nxt=start.next
+ while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
+ local nextchar=nxt.char
if marks[nextchar] then
- nxt=getnext(nxt)
+ nxt=nxt.next
else
local entryanchors=descriptions[nextchar]
if entryanchors then
@@ -10931,7 +10891,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
return head,start,done
else
if trace_cursive and trace_details then
- logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
end
return head,start,false
end
@@ -10939,7 +10899,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
return head,start,false
end
function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
- local startchar=getchar(start)
+ local startchar=start.char
local subtables=currentlookup.subtables
local lookupname=subtables[1]
local kerns=lookuphash[lookupname]
@@ -10956,9 +10916,9 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo
end
chainmores.gpos_single=chainprocs.gpos_single
function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
- local snext=getnext(start)
+ local snext=start.next
if snext then
- local startchar=getchar(start)
+ local startchar=start.char
local subtables=currentlookup.subtables
local lookupname=subtables[1]
local kerns=lookuphash[lookupname]
@@ -10968,26 +10928,26 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
local lookuptype=lookuptypes[lookupname]
local prev,done=start,false
local factor=tfmdata.parameters.factor
- while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do
- local nextchar=getchar(snext)
+ while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
+ local nextchar=snext.char
local krn=kerns[nextchar]
if not krn and marks[nextchar] then
prev=snext
- snext=getnext(snext)
+ snext=snext.next
else
if not krn then
elseif type(krn)=="table" then
if lookuptype=="pair" then
local a,b=krn[2],krn[3]
if a and #a>0 then
- local startchar=getchar(start)
+ local startchar=start.char
local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b>0 then
- local startchar=getchar(start)
+ local startchar=start.char
local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -10999,7 +10959,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
if a and a~=0 then
local k=setkern(snext,factor,rlmode,a)
if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
end
end
if b and b~=0 then
@@ -11010,7 +10970,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
elseif krn~=0 then
local k=setkern(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
end
done=true
end
@@ -11031,10 +10991,6 @@ local function show_skip(kind,chainname,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
end
end
-local quit_on_no_replacement=true
-directives.register("otf.chain.quitonnoreplacement",function(value)
- quit_on_no_replacement=value
-end)
local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
local flags=sequence.flags
local done=false
@@ -11052,7 +11008,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local seq=ck[3]
local s=#seq
if s==1 then
- match=getid(current)==glyph_code and getfont(current)==currentfont and getsubtype(current)<256 and seq[1][getchar(current)]
+ match=current.id==glyph_code and current.font==currentfont and current.subtype<256 and seq[1][current.char]
else
local f,l=ck[4],ck[5]
if f==1 and f==l then
@@ -11060,13 +11016,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if f==l then
else
local n=f+1
- last=getnext(last)
+ last=last.next
while n<=l do
if last then
- local id=getid(last)
+ local id=last.id
if id==glyph_code then
- if getfont(last)==currentfont and getsubtype(last)<256 then
- local char=getchar(last)
+ if last.font==currentfont and last.subtype<256 then
+ local char=last.char
local ccd=descriptions[char]
if ccd then
local class=ccd.class
@@ -11075,10 +11031,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if trace_skips then
show_skip(kind,chainname,char,ck,class)
end
- last=getnext(last)
+ last=last.next
elseif seq[n][char] then
if n<l then
- last=getnext(last)
+ last=last.next
end
n=n+1
else
@@ -11094,7 +11050,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id==disc_code then
- last=getnext(last)
+ last=last.next
else
match=false
break
@@ -11107,15 +11063,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
if match and f>1 then
- local prev=getprev(start)
+ local prev=start.prev
if prev then
local n=f-1
while n>=1 do
if prev then
- local id=getid(prev)
+ local id=prev.id
if id==glyph_code then
- if getfont(prev)==currentfont and getsubtype(prev)<256 then
- local char=getchar(prev)
+ if prev.font==currentfont and prev.subtype<256 then
+ local char=prev.char
local ccd=descriptions[char]
if ccd then
local class=ccd.class
@@ -11145,7 +11101,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
match=false
break
end
- prev=getprev(prev)
+ prev=prev.prev
elseif seq[n][32] then
n=n -1
else
@@ -11165,15 +11121,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
if match and s>l then
- local current=last and getnext(last)
+ local current=last and last.next
if current then
local n=l+1
while n<=s do
if current then
- local id=getid(current)
+ local id=current.id
if id==glyph_code then
- if getfont(current)==currentfont and getsubtype(current)<256 then
- local char=getchar(current)
+ if current.font==currentfont and current.subtype<256 then
+ local char=current.char
local ccd=descriptions[char]
if ccd then
local class=ccd.class
@@ -11203,7 +11159,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
match=false
break
end
- current=getnext(current)
+ current=current.next
elseif seq[n][32] then
n=n+1
else
@@ -11226,7 +11182,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if match then
if trace_contexts then
local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5]
- local char=getchar(start)
+ local char=start.char
if ck[9] then
logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
@@ -11260,12 +11216,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
repeat
if skipped then
while true do
- local char=getchar(start)
+ local char=start.char
local ccd=descriptions[char]
if ccd then
local class=ccd.class
if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- start=getnext(start)
+ start=start.next
else
break
end
@@ -11295,7 +11251,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
if start then
- start=getnext(start)
+ start=start.next
else
end
until i>nofchainlookups
@@ -11305,7 +11261,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if replacements then
head,start,done=chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements)
else
- done=quit_on_no_replacement
+ done=true
if trace_contexts then
logprocess("%s: skipping match",cref(kind,chainname))
end
@@ -11422,7 +11378,6 @@ local function featuresprocessor(head,font,attr)
if not lookuphash then
return head,false
end
- head=tonut(head)
if trace_steps then
checkstep(head)
end
@@ -11455,10 +11410,10 @@ local function featuresprocessor(head,font,attr)
local handler=handlers[typ]
local start=find_node_tail(head)
while start do
- local id=getid(start)
+ local id=start.id
if id==glyph_code then
- if getfont(start)==font and getsubtype(start)<256 then
- local a=getattr(start,0)
+ if start.font==font and start.subtype<256 then
+ local a=start[0]
if a then
a=a==attr
else
@@ -11469,7 +11424,7 @@ local function featuresprocessor(head,font,attr)
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start.char]
if lookupmatch then
head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
@@ -11480,15 +11435,15 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(typ,lookupname)
end
end
- if start then start=getprev(start) end
+ if start then start=start.prev end
else
- start=getprev(start)
+ start=start.prev
end
else
- start=getprev(start)
+ start=start.prev
end
else
- start=getprev(start)
+ start=start.prev
end
end
else
@@ -11506,16 +11461,16 @@ local function featuresprocessor(head,font,attr)
local head=start
local done=false
while start do
- local id=getid(start)
- if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
- local a=getattr(start,0)
+ local id=start.id
+ if id==glyph_code and start.font==font and start.subtype<256 then
+ local a=start[0]
if a then
- a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
+ a=(a==attr) and (not attribute or start[a_state]==attribute)
else
- a=not attribute or getattr(start,a_state)==attribute
+ a=not attribute or start[a_state]==attribute
end
if a then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start.char]
if lookupmatch then
local ok
head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
@@ -11523,12 +11478,12 @@ local function featuresprocessor(head,font,attr)
done=true
end
end
- if start then start=getnext(start) end
+ if start then start=start.next end
else
- start=getnext(start)
+ start=start.next
end
else
- start=getnext(start)
+ start=start.next
end
end
if done then
@@ -11537,18 +11492,18 @@ local function featuresprocessor(head,font,attr)
end
end
local function kerndisc(disc)
- local prev=getprev(disc)
- local next=getnext(disc)
+ local prev=disc.prev
+ local next=disc.next
if prev and next then
- setfield(prev,"next",next)
- local a=getattr(prev,0)
+ prev.next=next
+ local a=prev[0]
if a then
- a=(a==attr) and (not attribute or getattr(prev,a_state)==attribute)
+ a=(a==attr) and (not attribute or prev[a_state]==attribute)
else
- a=not attribute or getattr(prev,a_state)==attribute
+ a=not attribute or prev[a_state]==attribute
end
if a then
- local lookupmatch=lookupcache[getchar(prev)]
+ local lookupmatch=lookupcache[prev.char]
if lookupmatch then
local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
@@ -11557,22 +11512,22 @@ local function featuresprocessor(head,font,attr)
end
end
end
- setfield(prev,"next",disc)
+ prev.next=disc
end
return next
end
while start do
- local id=getid(start)
+ local id=start.id
if id==glyph_code then
- if getfont(start)==font and getsubtype(start)<256 then
- local a=getattr(start,0)
+ if start.font==font and start.subtype<256 then
+ local a=start[0]
if a then
- a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
+ a=(a==attr) and (not attribute or start[a_state]==attribute)
else
- a=not attribute or getattr(start,a_state)==attribute
+ a=not attribute or start[a_state]==attribute
end
if a then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start.char]
if lookupmatch then
local ok
head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
@@ -11580,38 +11535,38 @@ local function featuresprocessor(head,font,attr)
success=true
end
end
- if start then start=getnext(start) end
+ if start then start=start.next end
else
- start=getnext(start)
+ start=start.next
end
else
- start=getnext(start)
+ start=start.next
end
elseif id==disc_code then
- if getsubtype(start)==discretionary_code then
- local pre=getfield(start,"pre")
+ if start.subtype==discretionary_code then
+ local pre=start.pre
if pre then
local new=subrun(pre)
- if new then setfield(start,"pre",new) end
+ if new then start.pre=new end
end
- local post=getfield(start,"post")
+ local post=start.post
if post then
local new=subrun(post)
- if new then setfield(start,"post",new) end
+ if new then start.post=new end
end
- local replace=getfield(start,"replace")
+ local replace=start.replace
if replace then
local new=subrun(replace)
- if new then setfield(start,"replace",new) end
+ if new then start.replace=new end
end
elseif typ=="gpos_single" or typ=="gpos_pair" then
kerndisc(start)
end
- start=getnext(start)
+ start=start.next
elseif id==whatsit_code then
- local subtype=getsubtype(start)
+ local subtype=start.subtype
if subtype==dir_code then
- local dir=getfield(start,"dir")
+ local dir=start.dir
if dir=="+TRT" or dir=="+TLT" then
topstack=topstack+1
dirstack[topstack]=dir
@@ -11630,7 +11585,7 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype==localpar_code then
- local dir=getfield(start,"dir")
+ local dir=start.dir
if dir=="TRT" then
rlparmode=-1
elseif dir=="TLT" then
@@ -11643,11 +11598,11 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
- start=getnext(start)
+ start=start.next
elseif id==math_code then
- start=getnext(end_of_math(start))
+ start=end_of_math(start).next
else
- start=getnext(start)
+ start=start.next
end
end
end
@@ -11656,20 +11611,20 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
local head=start
local done=false
while start do
- local id=getid(start)
- if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
- local a=getattr(start,0)
+ local id=start.id
+ if id==glyph_code and start.id==font and start.subtype<256 then
+ local a=start[0]
if a then
- a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
+ a=(a==attr) and (not attribute or start[a_state]==attribute)
else
- a=not attribute or getattr(start,a_state)==attribute
+ a=not attribute or start[a_state]==attribute
end
if a then
for i=1,ns do
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start.char]
if lookupmatch then
local ok
head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
@@ -11684,12 +11639,12 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_missing_cache(typ,lookupname)
end
end
- if start then start=getnext(start) end
+ if start then start=start.next end
else
- start=getnext(start)
+ start=start.next
end
else
- start=getnext(start)
+ start=start.next
end
end
if done then
@@ -11698,22 +11653,22 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
end
end
local function kerndisc(disc)
- local prev=getprev(disc)
- local next=getnext(disc)
+ local prev=disc.prev
+ local next=disc.next
if prev and next then
- setfield(prev,"next",next)
- local a=getattr(prev,0)
+ prev.next=next
+ local a=prev[0]
if a then
- a=(a==attr) and (not attribute or getattr(prev,a_state)==attribute)
+ a=(a==attr) and (not attribute or prev[a_state]==attribute)
else
- a=not attribute or getattr(prev,a_state)==attribute
+ a=not attribute or prev[a_state]==attribute
end
if a then
for i=1,ns do
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(prev)]
+ local lookupmatch=lookupcache[prev.char]
if lookupmatch then
local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
@@ -11726,26 +11681,26 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
end
end
end
- setfield(prev,"next",disc)
+ prev.next=disc
end
return next
end
while start do
- local id=getid(start)
+ local id=start.id
if id==glyph_code then
- if getfont(start)==font and getsubtype(start)<256 then
- local a=getattr(start,0)
+ if start.font==font and start.subtype<256 then
+ local a=start[0]
if a then
- a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
+ a=(a==attr) and (not attribute or start[a_state]==attribute)
else
- a=not attribute or getattr(start,a_state)==attribute
+ a=not attribute or start[a_state]==attribute
end
if a then
for i=1,ns do
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start.char]
if lookupmatch then
local ok
head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
@@ -11760,38 +11715,38 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_missing_cache(typ,lookupname)
end
end
- if start then start=getnext(start) end
+ if start then start=start.next end
else
- start=getnext(start)
+ start=start.next
end
else
- start=getnext(start)
+ start=start.next
end
elseif id==disc_code then
- if getsubtype(start)==discretionary_code then
- local pre=getfield(start,"pre")
+ if start.subtype==discretionary_code then
+ local pre=start.pre
if pre then
local new=subrun(pre)
- if new then setfield(start,"pre",new) end
+ if new then start.pre=new end
end
- local post=getfield(start,"post")
+ local post=start.post
if post then
local new=subrun(post)
- if new then setfield(start,"post",new) end
+ if new then start.post=new end
end
- local replace=getfield(start,"replace")
+ local replace=start.replace
if replace then
local new=subrun(replace)
- if new then setfield(start,"replace",new) end
+ if new then start.replace=new end
end
elseif typ=="gpos_single" or typ=="gpos_pair" then
kerndisc(start)
end
- start=getnext(start)
+ start=start.next
elseif id==whatsit_code then
- local subtype=getsubtype(start)
+ local subtype=start.subtype
if subtype==dir_code then
- local dir=getfield(start,"dir")
+ local dir=start.dir
if dir=="+TRT" or dir=="+TLT" then
topstack=topstack+1
dirstack[topstack]=dir
@@ -11810,7 +11765,7 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
end
elseif subtype==localpar_code then
- local dir=getfield(start,"dir")
+ local dir=start.dir
if dir=="TRT" then
rlparmode=-1
elseif dir=="TLT" then
@@ -11823,11 +11778,11 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
end
end
- start=getnext(start)
+ start=start.next
elseif id==math_code then
- start=getnext(end_of_math(start))
+ start=end_of_math(start).next
else
- start=getnext(start)
+ start=start.next
end
end
end
@@ -11839,7 +11794,6 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
registerstep(head)
end
end
- head=tonode(head)
return head,done
end
local function generic(lookupdata,lookupname,unicode,lookuphash)
diff --git a/tex/generic/context/luatex/luatex-fonts-otn.lua b/tex/generic/context/luatex/luatex-fonts-otn.lua
new file mode 100644
index 000000000..c57be5f02
--- /dev/null
+++ b/tex/generic/context/luatex/luatex-fonts-otn.lua
@@ -0,0 +1,2848 @@
+if not modules then modules = { } end modules ['font-otn'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- preprocessors = { "nodes" }
+
+-- this is still somewhat preliminary and it will get better in due time;
+-- much functionality could only be implemented thanks to the husayni font
+-- of Idris Samawi Hamid to who we dedicate this module.
+
+-- in retrospect it always looks easy but believe it or not, it took a lot
+-- of work to get proper open type support done: buggy fonts, fuzzy specs,
+-- special made testfonts, many skype sessions between taco, idris and me,
+-- torture tests etc etc ... unfortunately the code does not show how much
+-- time it took ...
+
+-- todo:
+--
+-- kerning is probably not yet ok for latin around dics nodes (interesting challenge)
+-- extension infrastructure (for usage out of context)
+-- sorting features according to vendors/renderers
+-- alternative loop quitters
+-- check cursive and r2l
+-- find out where ignore-mark-classes went
+-- default features (per language, script)
+-- handle positions (we need example fonts)
+-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
+-- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests)
+-- remove some optimizations (when I have a faster machine)
+--
+-- maybe redo the lot some way (more context specific)
+
+--[[ldx--
+<p>This module is a bit more split up that I'd like but since we also want to test
+with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/>
+and discussion about improvements and functionality mostly happens on the
+<l n='context'/> mailing list.</p>
+
+<p>The specification of OpenType is kind of vague. Apart from a lack of a proper
+free specifications there's also the problem that Microsoft and Adobe
+may have their own interpretation of how and in what order to apply features.
+In general the Microsoft website has more detailed specifications and is a
+better reference. There is also some information in the FontForge help files.</p>
+
+<p>Because there is so much possible, fonts might contain bugs and/or be made to
+work with certain rederers. These may evolve over time which may have the side
+effect that suddenly fonts behave differently.</p>
+
+<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
+implementation. Of course all errors are mine and of course the code can be
+improved. There are quite some optimizations going on here and processing speed
+is currently acceptable. Not all functions are implemented yet, often because I
+lack the fonts for testing. Many scripts are not yet supported either, but I will
+look into them as soon as <l n='context'/> users ask for it.</p>
+
+<p>Because there are different interpretations possible, I will extend the code
+with more (configureable) variants. I can also add hooks for users so that they can
+write their own extensions.</p>
+
+<p>Glyphs are indexed not by unicode but in their own way. This is because there is no
+relationship with unicode at all, apart from the fact that a font might cover certain
+ranges of characters. One character can have multiple shapes. However, at the
+<l n='tex'/> end we use unicode so and all extra glyphs are mapped into a private
+space. This is needed because we need to access them and <l n='tex'/> has to include
+then in the output eventually.</p>
+
+<p>The raw table as it coms from <l n='fontforge'/> gets reorganized in to fit out needs.
+In <l n='context'/> that table is packed (similar tables are shared) and cached on disk
+so that successive runs can use the optimized table (after loading the table is
+unpacked). The flattening code used later is a prelude to an even more compact table
+format (and as such it keeps evolving).</p>
+
+<p>This module is sparsely documented because it is a moving target. The table format
+of the reader changes and we experiment a lot with different methods for supporting
+features.</p>
+
+<p>As with the <l n='afm'/> code, we may decide to store more information in the
+<l n='otf'/> table.</p>
+
+<p>Incrementing the version number will force a re-cache. We jump the number by one
+when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that
+results in different tables.</p>
+--ldx]]--
+
+-- action handler chainproc chainmore comment
+--
+-- gsub_single ok ok ok
+-- gsub_multiple ok ok not implemented yet
+-- gsub_alternate ok ok not implemented yet
+-- gsub_ligature ok ok ok
+-- gsub_context ok --
+-- gsub_contextchain ok --
+-- gsub_reversecontextchain ok --
+-- chainsub -- ok
+-- reversesub -- ok
+-- gpos_mark2base ok ok
+-- gpos_mark2ligature ok ok
+-- gpos_mark2mark ok ok
+-- gpos_cursive ok untested
+-- gpos_single ok ok
+-- gpos_pair ok ok
+-- gpos_context ok --
+-- gpos_contextchain ok --
+--
+-- todo: contextpos and contextsub and class stuff
+--
+-- actions:
+--
+-- handler : actions triggered by lookup
+-- chainproc : actions triggered by contextual lookup
+-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij)
+--
+-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
+-- remark: we need to check what to do with discretionaries
+
+-- We used to have independent hashes for lookups but as the tags are unique
+-- we now use only one hash. If needed we can have multiple again but in that
+-- case I will probably prefix (i.e. rename) the lookups in the cached font file.
+
+-- Todo: make plugin feature that operates on char/glyphnode arrays
+
+local concat, insert, remove = table.concat, table.insert, table.remove
+local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local lpegmatch = lpeg.match
+local random = math.random
+local formatters = string.formatters
+
+local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
+
+local registertracker = trackers.register
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+
+local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end)
+local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end)
+local trace_details = false registertracker("otf.details", function(v) trace_details = v end)
+local trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end)
+local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
+local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end)
+
+local report_direct = logs.reporter("fonts","otf direct")
+local report_subchain = logs.reporter("fonts","otf subchain")
+local report_chain = logs.reporter("fonts","otf chain")
+local report_process = logs.reporter("fonts","otf process")
+local report_prepare = logs.reporter("fonts","otf prepare")
+local report_warning = logs.reporter("fonts","otf warning")
+
+registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
+registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
+
+registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
+registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
+registertracker("otf.actions","otf.replacements,otf.positions")
+registertracker("otf.injections","nodes.injections")
+
+registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local find_node_tail = node.tail or node.slide
+local flush_node_list = node.flush_list
+local end_of_math = node.end_of_math
+
+local setmetatableindex = table.setmetatableindex
+
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
+
+local nodecodes = nodes.nodecodes
+local whatcodes = nodes.whatcodes
+local glyphcodes = nodes.glyphcodes
+local disccodes = nodes.disccodes
+
+local glyph_code = nodecodes.glyph
+local glue_code = nodecodes.glue
+local disc_code = nodecodes.disc
+local whatsit_code = nodecodes.whatsit
+local math_code = nodecodes.math
+
+local dir_code = whatcodes.dir
+local localpar_code = whatcodes.localpar
+
+local discretionary_code = disccodes.discretionary
+
+local ligature_code = glyphcodes.ligature
+
+local privateattribute = attributes.private
+
+-- Something is messed up: we have two mark / ligature indices, one at the injection
+-- end and one here ... this is bases in KE's patches but there is something fishy
+-- there as I'm pretty sure that for husayni we need some connection (as it's much
+-- more complex than an average font) but I need proper examples of all cases, not
+-- of only some.
+
+local a_state = privateattribute('state')
+local a_markbase = privateattribute('markbase')
+local a_markmark = privateattribute('markmark')
+local a_markdone = privateattribute('markdone') -- assigned at the injection end
+local a_cursbase = privateattribute('cursbase')
+local a_curscurs = privateattribute('curscurs')
+local a_cursdone = privateattribute('cursdone')
+local a_kernpair = privateattribute('kernpair')
+local a_ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined)
+
+local injections = nodes.injections
+local setmark = injections.setmark
+local setcursive = injections.setcursive
+local setkern = injections.setkern
+local setpair = injections.setpair
+
+local markonce = true
+local cursonce = true
+local kernonce = true
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+local onetimemessage = fonts.loggers.onetimemessage or function() end
+
+otf.defaultnodealternate = "none" -- first last
+
+-- we share some vars here, after all, we have no nested lookups and less code
+
+local tfmdata = false
+local characters = false
+local descriptions = false
+local resources = false
+local marks = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local lookuptypes = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
+
+-- head is always a whatsit so we can safely assume that head is not changed
+
+-- we use this for special testing and documentation
+
+local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
+local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
+local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ report_direct(...)
+end
+
+local function logwarning(...)
+ report_direct(...)
+end
+
+local f_unicode = formatters["%U"]
+local f_uniname = formatters["%U (%s)"]
+local f_unilist = formatters["% t (% t)"]
+
+local function gref(n) -- currently the same as in font-otb
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return f_uniname(n,name)
+ else
+ return f_unicode(n)
+ end
+ elseif n then
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ if tonumber(ni) then -- later we will start at 2
+ local di = descriptions[ni]
+ num[i] = f_unicode(ni)
+ nam[i] = di and di.name or "-"
+ end
+ end
+ return f_unilist(num,nam)
+ else
+ return "<error in node mode tracing>"
+ end
+end
+
+local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_
+ if index then
+ return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index)
+ elseif lookupname then
+ return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname)
+ elseif chainlookupname then
+ return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname)
+ elseif chainname then
+ return formatters["feature %a, chain %a"](kind,chainname)
+ else
+ return formatters["feature %a"](kind)
+ end
+end
+
+local function pref(kind,lookupname)
+ return formatters["feature %a, lookup %a"](kind,lookupname)
+end
+
+-- We can assume that languages that use marks are not hyphenated. We can also assume
+-- that at most one discretionary is present.
+
+-- We do need components in funny kerning mode but maybe I can better reconstruct then
+-- as we do have the font components info available; removing components makes the
+-- previous code much simpler. Also, later on copying and freeing becomes easier.
+-- However, for arabic we need to keep them around for the sake of mark placement
+-- and indices.
+
+local function copy_glyph(g) -- next and prev are untouched !
+ local components = g.components
+ if components then
+ g.components = nil
+ local n = copy_node(g)
+ g.components = components
+ return n
+ else
+ return copy_node(g)
+ end
+end
+
+-- start is a mark and we need to keep that one
+
+local function markstoligature(kind,lookupname,head,start,stop,char)
+ if start == stop and start.char == char then
+ return head, start
+ else
+ local prev = start.prev
+ local next = stop.next
+ start.prev = nil
+ stop.next = nil
+ local base = copy_glyph(start)
+ if head == start then
+ head = base
+ end
+ base.char = char
+ base.subtype = ligature_code
+ base.components = start
+ if prev then
+ prev.next = base
+ end
+ if next then
+ next.prev = base
+ end
+ base.next = next
+ base.prev = prev
+ return head, base
+ end
+end
+
+-- The next code is somewhat complicated by the fact that some fonts can have ligatures made
+-- from ligatures that themselves have marks. This was identified by Kai in for instance
+-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes
+-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next
+-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
+-- third component.
+
+local function getcomponentindex(start)
+ if start.id ~= glyph_code then
+ return 0
+ elseif start.subtype == ligature_code then
+ local i = 0
+ local components = start.components
+ while components do
+ i = i + getcomponentindex(components)
+ components = components.next
+ end
+ return i
+ elseif not marks[start.char] then
+ return 1
+ else
+ return 0
+ end
+end
+
+-- eventually we will do positioning in an other way (needs addional w/h/d fields)
+
+local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head
+ if start == stop and start.char == char then
+ start.char = char
+ return head, start
+ end
+ local prev = start.prev
+ local next = stop.next
+ start.prev = nil
+ stop.next = nil
+ local base = copy_glyph(start)
+ if start == head then
+ head = base
+ end
+ base.char = char
+ base.subtype = ligature_code
+ base.components = start -- start can have components
+ if prev then
+ prev.next = base
+ end
+ if next then
+ next.prev = base
+ end
+ base.next = next
+ base.prev = prev
+ if not discfound then
+ local deletemarks = markflag ~= "mark"
+ local components = start
+ local baseindex = 0
+ local componentindex = 0
+ local head = base
+ local current = base
+ -- first we loop over the glyphs in start .. stop
+ while start do
+ local char = start.char
+ if not marks[char] then
+ baseindex = baseindex + componentindex
+ componentindex = getcomponentindex(start)
+ elseif not deletemarks then -- quite fishy
+ start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
+ end
+ head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components
+ elseif trace_marks then
+ logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
+ end
+ start = start.next
+ end
+ -- we can have one accent as part of a lookup and another following
+ -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added)
+ local start = current.next
+ while start and start.id == glyph_code do
+ local char = start.char
+ if marks[char] then
+ start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex)
+ if trace_marks then
+ logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
+ end
+ else
+ break
+ end
+ start = start.next
+ end
+ end
+ return head, base
+end
+
+function handlers.gsub_single(head,start,kind,lookupname,replacement)
+ if trace_singles then
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
+ end
+ start.char = replacement
+ return head, start, true
+end
+
+local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
+ local n = #alternatives
+ if value == "random" then
+ local r = random(1,n)
+ return alternatives[r], trace_alternatives and formatters["value %a, taking %a"](value,r)
+ elseif value == "first" then
+ return alternatives[1], trace_alternatives and formatters["value %a, taking %a"](value,1)
+ elseif value == "last" then
+ return alternatives[n], trace_alternatives and formatters["value %a, taking %a"](value,n)
+ else
+ value = tonumber(value)
+ if type(value) ~= "number" then
+ return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
+ elseif value > n then
+ local defaultalt = otf.defaultnodealternate
+ if defaultalt == "first" then
+ return alternatives[n], trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
+ elseif defaultalt == "last" then
+ return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,n)
+ else
+ return false, trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
+ end
+ elseif value == 0 then
+ return start.char, trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
+ elseif value < 1 then
+ return alternatives[1], trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
+ else
+ return alternatives[value], trace_alternatives and formatters["value %a, taking %a"](value,value)
+ end
+ end
+end
+
+local function multiple_glyphs(head,start,multiple,ignoremarks)
+ local nofmultiples = #multiple
+ if nofmultiples > 0 then
+ start.char = multiple[1]
+ if nofmultiples > 1 then
+ local sn = start.next
+ for k=2,nofmultiples do -- todo: use insert_node
+-- untested:
+--
+-- while ignoremarks and marks[sn.char] then
+-- local sn = sn.next
+-- end
+ local n = copy_node(start) -- ignore components
+ n.char = multiple[k]
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return head, start, true
+ else
+ if trace_multiples then
+ logprocess("no multiple for %s",gref(start.char))
+ end
+ return head, start, false
+ end
+end
+
+function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence)
+ local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
+ local choice, comment = get_alternative_glyph(start,alternative,value,trace_alternatives)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
+ end
+ start.char = choice
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
+ end
+ end
+ return head, start, true
+end
+
+function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
+ end
+ return multiple_glyphs(head,start,multiple,sequence.flags[1])
+end
+
+function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
+ local s, stop, discfound = start.next, nil, false
+ local startchar = start.char
+ if marks[startchar] then
+ while s do
+ local id = s.id
+ if id == glyph_code and s.font == currentfont and s.subtype<256 then
+ local lg = ligature[s.char]
+ if lg then
+ stop = s
+ ligature = lg
+ s = s.next
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if stop then
+ local lig = ligature.ligature
+ if lig then
+ if trace_ligatures then
+ local stopchar = stop.char
+ head, start = markstoligature(kind,lookupname,head,start,stop,lig)
+ logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ head, start = markstoligature(kind,lookupname,head,start,stop,lig)
+ end
+ return head, start, true
+ else
+ -- ok, goto next lookup
+ end
+ end
+ else
+ local skipmark = sequence.flags[1]
+ while s do
+ local id = s.id
+ if id == glyph_code and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ if skipmark and marks[char] then
+ s = s.next
+ else
+ local lg = ligature[char]
+ if lg then
+ stop = s
+ ligature = lg
+ s = s.next
+ else
+ break
+ end
+ end
+ else
+ break
+ end
+ elseif id == disc_code then
+ discfound = true
+ s = s.next
+ else
+ break
+ end
+ end
+ local lig = ligature.ligature
+ if lig then
+ if stop then
+ if trace_ligatures then
+ local stopchar = stop.char
+ head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
+ logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
+ end
+ return head, start, true
+ else
+ -- weird but happens (in some arabic font)
+ start.char = lig
+ if trace_ligatures then
+ logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
+ end
+ return head, start, true
+ end
+ else
+ -- weird but happens
+ end
+ end
+ return head, start, false
+end
+
+--[[ldx--
+<p>We get hits on a mark, but we're not sure if the it has to be applied so
+we need to explicitly test for basechar, baselig and basemark entries.</p>
+--ldx]]--
+
+function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ end
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ elseif trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
+ -- check chainpos variant
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+ end
+ end
+ end
+ local index = start[a_ligacomp]
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index
+ if trace_marks then
+ logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return head, start, true
+ else
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(kind,lookupname),gref(markchar),gref(basechar),index)
+ end
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ local slc = start[a_ligacomp]
+ if slc then -- a rather messy loop ... needs checking with husayni
+ while base do
+ local blc = base[a_ligacomp]
+ if blc and blc ~= slc then
+ base = base.prev
+ else
+ break
+ end
+ end
+ end
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) -- to be checked
+ local alreadydone = cursonce and start[a_cursbase]
+ if not alreadydone then
+ local done = false
+ local startchar = start.char
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ elseif trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ end
+ break
+ end
+ end
+ end
+ return head, start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return head, start, false
+ end
+end
+
+function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
+ local startchar = start.char
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
+ end
+ return head, start, false
+end
+
+function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
+ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
+ -- todo: kerns in components of ligatures
+ local snext = start.next
+ if not snext then
+ return head, start, false
+ else
+ local prev, done = start, false
+ local factor = tfmdata.parameters.factor
+ local lookuptype = lookuptypes[lookupname]
+ while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
+ local nextchar = snext.char
+ local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if lookuptype == "pair" then -- probably not needed
+ local a, b = krn[2], krn[3]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else -- wrong ... position has different entries
+ report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ -- end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = setkern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return head, start, done
+ end
+end
+
+--[[ldx--
+<p>I will implement multiple chain replacements once I run into a font that uses
+it. It's not that complex to handle.</p>
+--ldx]]--
+
+local chainmores = { }
+local chainprocs = { }
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ report_subchain(...)
+end
+
+local logwarning = report_subchain
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ report_chain(...)
+end
+
+local logwarning = report_chain
+
+-- We could share functions but that would lead to extra function calls with many
+-- arguments, redundant tests and confusing messages.
+
+function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
+ logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return head, start, false
+end
+
+function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
+ logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return head, start, false
+end
+
+-- The reversesub is a special case, which is why we need to store the replacements
+-- in a bit weird way. There is no lookup and the replacement comes from the lookup
+-- itself. It is meant mostly for dealing with Urdu.
+
+function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
+ local char = start.char
+ local replacement = replacements[char]
+ if replacement then
+ if trace_singles then
+ logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
+ end
+ start.char = replacement
+ return head, start, true
+ else
+ return head, start, false
+ end
+end
+
+--[[ldx--
+<p>This chain stuff is somewhat tricky since we can have a sequence of actions to be
+applied: single, alternate, multiple or ligature where ligature can be an invalid
+one in the sense that it will replace multiple by one but not neccessary one that
+looks like the combination (i.e. it is the counterpart of multiple then). For
+example, the following is valid:</p>
+
+<typing>
+<line>xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx</line>
+</typing>
+
+<p>Therefore we we don't really do the replacement here already unless we have the
+single lookup case. The efficiency of the replacements can be improved by deleting
+as less as needed but that would also make the code even more messy.</p>
+--ldx]]--
+
+-- local function delete_till_stop(head,start,stop,ignoremarks) -- keeps start
+-- local n = 1
+-- if start == stop then
+-- -- done
+-- elseif ignoremarks then
+-- repeat -- start x x m x x stop => start m
+-- local next = start.next
+-- if not marks[next.char] then
+-- local components = next.components
+-- if components then -- probably not needed
+-- flush_node_list(components)
+-- end
+-- head = delete_node(head,next)
+-- end
+-- n = n + 1
+-- until next == stop
+-- else -- start x x x stop => start
+-- repeat
+-- local next = start.next
+-- local components = next.components
+-- if components then -- probably not needed
+-- flush_node_list(components)
+-- end
+-- head = delete_node(head,next)
+-- n = n + 1
+-- until next == stop
+-- end
+-- return head, n
+-- end
+
+--[[ldx--
+<p>Here we replace start by a single variant, First we delete the rest of the
+match.</p>
+--ldx]]--
+
+function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
+ -- todo: marks ?
+ local current = start
+ local subtables = currentlookup.subtables
+ if #subtables > 1 then
+ logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
+ end
+ while current do
+ if current.id == glyph_code then
+ local currentchar = current.char
+ local lookupname = subtables[1] -- only 1
+ local replacement = lookuphash[lookupname]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ replacement = replacement[currentchar]
+ if not replacement or replacement == "" then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
+ end
+ current.char = replacement
+ end
+ end
+ return head, start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return head, start, false
+end
+
+chainmores.gsub_single = chainprocs.gsub_single
+
+--[[ldx--
+<p>Here we replace start by a sequence of new glyphs. First we delete the rest of
+the match.</p>
+--ldx]]--
+
+function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ -- local head, n = delete_till_stop(head,start,stop)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local replacements = lookuphash[lookupname]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ replacements = replacements[startchar]
+ if not replacements or replacement == "" then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
+ end
+ else
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
+ end
+ return multiple_glyphs(head,start,replacements,currentlookup.flags[1])
+ end
+ end
+ return head, start, false
+end
+
+chainmores.gsub_multiple = chainprocs.gsub_multiple
+
+--[[ldx--
+<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
+--ldx]]--
+
+-- char_1 mark_1 -> char_x mark_1 (ignore marks)
+-- char_1 mark_1 -> char_x
+
+-- to be checked: do we always have just one glyph?
+-- we can also have alternates for marks
+-- marks come last anyway
+-- are there cases where we need to delete the mark
+
+function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local current = start
+ local subtables = currentlookup.subtables
+ local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
+ while current do
+ if current.id == glyph_code then -- is this check needed?
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local alternatives = lookuphash[lookupname]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative hit",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ alternatives = alternatives[currentchar]
+ if alternatives then
+ local choice, comment = get_alternative_glyph(current,alternatives,value,trace_alternatives)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
+ end
+ start.char = choice
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: no alternative for %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar),comment)
+ end
+ end
+ return head, start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return head, start, false
+end
+
+chainmores.gsub_alternate = chainprocs.gsub_alternate
+
+--[[ldx--
+<p>When we replace ligatures we use a helper that handles the marks. I might change
+this function (move code inline and handle the marks by a separate function). We
+assume rather stupid ligatures (no complex disc nodes).</p>
+--ldx]]--
+
+function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local ligatures = lookuphash[lookupname]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ ligatures = ligatures[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ end
+ else
+ local s = start.next
+ local discfound = false
+ local last = stop
+ local nofreplacements = 0
+ local skipmark = currentlookup.flags[1]
+ while s do
+ local id = s.id
+ if id == disc_code then
+ s = s.next
+ discfound = true
+ else
+ local schar = s.char
+ if skipmark and marks[schar] then -- marks
+ s = s.next
+ else
+ local lg = ligatures[schar]
+ if lg then
+ ligatures, last, nofreplacements = lg, s, nofreplacements + 1
+ if s == stop then
+ break
+ else
+ s = s.next
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ local l2 = ligatures.ligature
+ if l2 then
+ if chainindex then
+ stop = last
+ end
+ if trace_ligatures then
+ if start == stop then
+ logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ end
+ end
+ head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
+ return head, start, true, nofreplacements
+ elseif trace_bugs then
+ if start == stop then
+ logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ else
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
+ end
+ end
+ end
+ end
+ return head, start, false, 0
+end
+
+chainmores.gsub_ligature = chainprocs.gsub_ligature
+
+function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = lookuphash[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return head, start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = lookuphash[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
+ end
+ return head, start, false
+ end
+ end
+ end
+ -- todo: like marks a ligatures hash
+ local index = start[a_ligacomp]
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return head, start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname)
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ -- local alreadydone = markonce and start[a_markmark]
+ -- if not alreadydone then
+ -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = lookuphash[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ local slc = start[a_ligacomp]
+ if slc then -- a rather messy loop ... needs checking with husayni
+ while base do
+ local blc = base[a_ligacomp]
+ if blc and blc ~= slc then
+ base = base.prev
+ else
+ break
+ end
+ end
+ end
+ if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ -- elseif trace_marks and trace_details then
+ -- logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+ -- end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return head, start, false
+end
+
+function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
+ local alreadydone = cursonce and start[a_cursbase]
+ if not alreadydone then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local exitanchors = lookuphash[lookupname]
+ if exitanchors then
+ exitanchors = exitanchors[startchar]
+ end
+ if exitanchors then
+ local done = false
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ elseif trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ end
+ break
+ end
+ end
+ end
+ return head, start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return head, start, false
+ end
+ end
+ return head, start, false
+end
+
+function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ -- untested .. needs checking for the new model
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = lookuphash[lookupname]
+ if kerns then
+ kerns = kerns[startchar] -- needed ?
+ if kerns then
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
+ end
+ end
+ end
+ return head, start, false
+end
+
+chainmores.gpos_single = chainprocs.gpos_single -- okay?
+
+-- when machines become faster i will make a shared function
+
+function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ local snext = start.next
+ if snext then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = lookuphash[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local lookuptype = lookuptypes[lookupname]
+ local prev, done = start, false
+ local factor = tfmdata.parameters.factor
+ while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do
+ local nextchar = snext.char
+ local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if lookuptype == "pair" then
+ local a, b = krn[2], krn[3]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
+ local a, b = krn[2], krn[6]
+ if a and a ~= 0 then
+ local k = setkern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = setkern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return head, start, done
+ end
+ end
+ end
+ return head, start, false
+end
+
+chainmores.gpos_pair = chainprocs.gpos_pair -- okay?
+
+-- what pointer to return, spec says stop
+-- to be discussed ... is bidi changer a space?
+-- elseif char == zwnj and sequence[n][32] then -- brrr
+
+-- somehow l or f is global
+-- we don't need to pass the currentcontext, saves a bit
+-- make a slow variant then can be activated but with more tracing
+
+local function show_skip(kind,chainname,char,ck,class)
+ if ck[9] then
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ else
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ end
+end
+
+local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
+ -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
+ local flags = sequence.flags
+ local done = false
+ local skipmark = flags[1]
+ local skipligature = flags[2]
+ local skipbase = flags[3]
+ local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
+ local markclass = sequence.markclass -- todo, first we need a proper test
+ local skipped = false
+ for k=1,#contexts do
+ local match = true
+ local current = start
+ local last = start
+ local ck = contexts[k]
+ local seq = ck[3]
+ local s = #seq
+ -- f..l = mid string
+ if s == 1 then
+ -- never happens
+ match = current.id == glyph_code and current.font == currentfont and current.subtype<256 and seq[1][current.char]
+ else
+ -- maybe we need a better space check (maybe check for glue or category or combination)
+ -- we cannot optimize for n=2 because there can be disc nodes
+ local f, l = ck[4], ck[5]
+ -- current match
+ if f == 1 and f == l then -- current only
+ -- already a hit
+ -- match = true
+ else -- before/current/after | before/current | current/after
+ -- no need to test first hit (to be optimized)
+ if f == l then -- new, else last out of sync (f is > 1)
+ -- match = true
+ else
+ local n = f + 1
+ last = last.next
+ while n <= l do
+ if last then
+ local id = last.id
+ if id == glyph_code then
+ if last.font == currentfont and last.subtype<256 then
+ local char = last.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ last = last.next
+ elseif seq[n][char] then
+ if n < l then
+ last = last.next
+ end
+ n = n + 1
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ elseif id == disc_code then
+ last = last.next
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ end
+ end
+ end
+ -- before
+ if match and f > 1 then
+ local prev = start.prev
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = prev.id
+ if id == glyph_code then
+ if prev.font == currentfont and prev.subtype<256 then -- normal char
+ local char = prev.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n -1
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ elseif id == disc_code then
+ -- skip 'm
+ elseif seq[n][32] then
+ n = n -1
+ else
+ match = false
+ break
+ end
+ prev = prev.prev
+ elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
+ n = n -1
+ else
+ match = false
+ break
+ end
+ end
+ elseif f == 2 then
+ match = seq[1][32]
+ else
+ for n=f-1,1 do
+ if not seq[n][32] then
+ match = false
+ break
+ end
+ end
+ end
+ end
+ -- after
+ if match and s > l then
+ local current = last and last.next
+ if current then
+ -- removed optimization for s-l == 1, we have to deal with marks anyway
+ local n = l + 1
+ while n <= s do
+ if current then
+ local id = current.id
+ if id == glyph_code then
+ if current.font == currentfont and current.subtype<256 then -- normal char
+ local char = current.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n + 1
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ elseif id == disc_code then
+ -- skip 'm
+ elseif seq[n][32] then -- brrr
+ n = n + 1
+ else
+ match = false
+ break
+ end
+ current = current.next
+ elseif seq[n][32] then
+ n = n + 1
+ else
+ match = false
+ break
+ end
+ end
+ elseif s-l == 1 then
+ match = seq[s][32]
+ else
+ for n=l+1,s do
+ if not seq[n][32] then
+ match = false
+ break
+ end
+ end
+ end
+ end
+ end
+ if match then
+ -- ck == currentcontext
+ if trace_contexts then
+ local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5]
+ local char = start.char
+ if ck[9] then
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
+ cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
+ else
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
+ cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
+ end
+ end
+ local chainlookups = ck[6]
+ if chainlookups then
+ local nofchainlookups = #chainlookups
+ -- we can speed this up if needed
+ if nofchainlookups == 1 then
+ local chainlookupname = chainlookups[1]
+ local chainlookup = lookuptable[chainlookupname]
+ if chainlookup then
+ local cp = chainprocs[chainlookup.type]
+ if cp then
+ local ok
+ head, start, ok = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ if ok then
+ done = true
+ end
+ else
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ else -- shouldn't happen
+ logprocess("%s is not yet supported",cref(kind,chainname,chainlookupname))
+ end
+ else
+ local i = 1
+ repeat
+ if skipped then
+ while true do
+ local char = start.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ start = start.next
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ end
+ local chainlookupname = chainlookups[i]
+ local chainlookup = lookuptable[chainlookupname]
+ if not chainlookup then
+ -- okay, n matches, < n replacements
+ i = i + 1
+ else
+ local cp = chainmores[chainlookup.type]
+ if not cp then
+ -- actually an error
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ i = i + 1
+ else
+ local ok, n
+ head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
+ -- messy since last can be changed !
+ if ok then
+ done = true
+ -- skip next one(s) if ligature
+ i = i + (n or 1)
+ else
+ i = i + 1
+ end
+ end
+ end
+ if start then
+ start = start.next
+ else
+ -- weird
+ end
+ until i > nofchainlookups
+ end
+ else
+ local replacements = ck[7]
+ if replacements then
+ head, start, done = chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
+ else
+ done = true -- can be meant to be skipped
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(kind,chainname))
+ end
+ end
+ end
+ end
+ end
+ return head, start, done
+end
+
+-- Because we want to keep this elsewhere (an because speed is less an issue) we
+-- pass the font id so that the verbose variant can access the relevant helper tables.
+
+local verbose_handle_contextchain = function(font,...)
+ logwarning("no verbose handler installed, reverting to 'normal'")
+ otf.setcontextchain()
+ return normal_handle_contextchain(...)
+end
+
+otf.chainhandlers = {
+ normal = normal_handle_contextchain,
+ verbose = verbose_handle_contextchain,
+}
+
+function otf.setcontextchain(method)
+ if not method or method == "normal" or not otf.chainhandlers[method] then
+ if handlers.contextchain then -- no need for a message while making the format
+ logwarning("installing normal contextchain handler")
+ end
+ handlers.contextchain = normal_handle_contextchain
+ else
+ logwarning("installing contextchain handler %a",method)
+ local handler = otf.chainhandlers[method]
+ handlers.contextchain = function(...)
+ return handler(currentfont,...) -- hm, get rid of ...
+ end
+ end
+ handlers.gsub_context = handlers.contextchain
+ handlers.gsub_contextchain = handlers.contextchain
+ handlers.gsub_reversecontextchain = handlers.contextchain
+ handlers.gpos_contextchain = handlers.contextchain
+ handlers.gpos_context = handlers.contextchain
+end
+
+otf.setcontextchain()
+
+local missing = { } -- we only report once
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ report_process(...)
+end
+
+local logwarning = report_process
+
+local function report_missing_cache(typ,lookup)
+ local f = missing[currentfont] if not f then f = { } missing[currentfont] = f end
+ local t = f[typ] if not t then t = { } f[typ] = t end
+ if not t[lookup] then
+ t[lookup] = true
+ logwarning("missing cache for lookup %a, type %a, font %a, name %a",lookup,typ,currentfont,tfmdata.properties.fullname)
+ end
+end
+
+local resolved = { } -- we only resolve a font,script,language pair once
+
+-- todo: pass all these 'locals' in a table
+
+local lookuphashes = { }
+
+setmetatableindex(lookuphashes, function(t,font)
+ local lookuphash = fontdata[font].resources.lookuphash
+ if not lookuphash or not next(lookuphash) then
+ lookuphash = false
+ end
+ t[font] = lookuphash
+ return lookuphash
+end)
+
+-- fonts.hashes.lookups = lookuphashes
+
+local autofeatures = fonts.analyzers.features -- was: constants
+
+local function initialize(sequence,script,language,enabled)
+ local features = sequence.features
+ if features then
+ for kind, scripts in next, features do
+ local valid = enabled[kind]
+ if valid then
+ local languages = scripts[script] or scripts[wildcard]
+ if languages and (languages[language] or languages[wildcard]) then
+ return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence }
+ end
+ end
+ end
+ end
+ return false
+end
+
+function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
+ local shared = tfmdata.shared
+ local properties = tfmdata.properties
+ local language = properties.language or "dflt"
+ local script = properties.script or "dflt"
+ local enabled = shared.features
+ local res = resolved[font]
+ if not res then
+ res = { }
+ resolved[font] = res
+ end
+ local rs = res[script]
+ if not rs then
+ rs = { }
+ res[script] = rs
+ end
+ local rl = rs[language]
+ if not rl then
+ rl = {
+ -- indexed but we can also add specific data by key
+ }
+ rs[language] = rl
+ local sequences = tfmdata.resources.sequences
+-- setmetatableindex(rl, function(t,k)
+-- if type(k) == "number" then
+-- local v = enabled and initialize(sequences[k],script,language,enabled)
+-- t[k] = v
+-- return v
+-- end
+-- end)
+for s=1,#sequences do
+ local v = enabled and initialize(sequences[s],script,language,enabled)
+ if v then
+ rl[#rl+1] = v
+ end
+end
+ end
+ return rl
+end
+
+-- elseif id == glue_code then
+-- if p[5] then -- chain
+-- local pc = pp[32]
+-- if pc then
+-- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+-- if ok then
+-- done = true
+-- end
+-- if start then start = start.next end
+-- else
+-- start = start.next
+-- end
+-- else
+-- start = start.next
+-- end
+
+-- there will be a new direction parser (pre-parsed etc)
+
+-- less bytecode: 290 -> 254
+--
+-- attr = attr or false
+--
+-- local a = getattr(start,0)
+-- if (a == attr and (not attribute or getattr(start,a_state) == attribute)) or (not attribute or getattr(start,a_state) == attribute) then
+-- -- the action
+-- end
+
+local function featuresprocessor(head,font,attr)
+
+ local lookuphash = lookuphashes[font] -- we can also check sequences here
+
+ if not lookuphash then
+ return head, false
+ end
+
+ if trace_steps then
+ checkstep(head)
+ end
+
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ resources = tfmdata.resources
+
+ marks = resources.marks
+ anchorlookups = resources.lookup_to_anchor
+ lookuptable = resources.lookups
+ lookuptypes = resources.lookuptypes
+
+ currentfont = font
+ rlmode = 0
+
+ local sequences = resources.sequences
+ local done = false
+ local datasets = otf.dataset(tfmdata,font,attr)
+
+ local dirstack = { } -- could move outside function
+
+ -- We could work on sub start-stop ranges instead but I wonder if there is that
+ -- much speed gain (experiments showed that it made not much sense) and we need
+ -- to keep track of directions anyway. Also at some point I want to play with
+ -- font interactions and then we do need the full sweeps.
+
+ -- Keeping track of the headnode is needed for devanagari (I generalized it a bit
+ -- so that multiple cases are also covered.)
+
+ for s=1,#datasets do
+ local dataset = datasets[s]
+ featurevalue = dataset[1] -- todo: pass to function instead of using a global
+
+ local sequence = dataset[5] -- sequences[s] -- also dataset[5]
+ local rlparmode = 0
+ local topstack = 0
+ local success = false
+ local attribute = dataset[2]
+ local chain = dataset[3] -- sequence.chain or 0
+ local typ = sequence.type
+ local subtables = sequence.subtables
+ if chain < 0 then
+ -- this is a limited case, no special treatments like 'init' etc
+ local handler = handlers[typ]
+ -- we need to get rid of this slide! probably no longer needed in latest luatex
+ local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
+ while start do
+ local id = start.id
+ if id == glyph_code then
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
+ if a then
+ a = a == attr
+ else
+ a = true
+ end
+ if a then
+ for i=1,#subtables do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if success then
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.prev end
+ else
+ start = start.prev
+ end
+ else
+ start = start.prev
+ end
+ else
+ start = start.prev
+ end
+ end
+ else
+ local handler = handlers[typ]
+ local ns = #subtables
+ local start = head -- local ?
+ rlmode = 0 -- to be checked ?
+ if ns == 1 then -- happens often
+ local lookupname = subtables[1]
+ local lookupcache = lookuphash[lookupname]
+ if not lookupcache then -- also check for empty cache
+ report_missing_cache(typ,lookupname)
+ else
+
+ local function subrun(start)
+ -- mostly for gsub, gpos would demand a more clever approach
+ local head = start
+ local done = false
+ while start do
+ local id = start.id
+ if id == glyph_code and start.font == font and start.subtype <256 then
+ local a = start[0]
+ if a then
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
+ else
+ a = not attribute or start[a_state] == attribute
+ end
+ if a then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ done = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ else
+ start = start.next
+ end
+ end
+ if done then
+ success = true
+ return head
+ end
+ end
+
+ local function kerndisc(disc) -- we can assume that prev and next are glyphs
+ local prev = disc.prev
+ local next = disc.next
+ if prev and next then
+ prev.next = next
+ -- next.prev = prev
+ local a = prev[0]
+ if a then
+ a = (a == attr) and (not attribute or prev[a_state] == attribute)
+ else
+ a = not attribute or prev[a_state] == attribute
+ end
+ if a then
+ local lookupmatch = lookupcache[prev.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ done = true
+ success = true
+ end
+ end
+ end
+ prev.next = disc
+ -- next.prev = disc
+ end
+ return next
+ end
+
+ while start do
+ local id = start.id
+ if id == glyph_code then
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
+ if a then
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
+ else
+ a = not attribute or start[a_state] == attribute
+ end
+ if a then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ success = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ else
+ start = start.next
+ end
+ elseif id == disc_code then
+ -- mostly for gsub
+ if start.subtype == discretionary_code then
+ local pre = start.pre
+ if pre then
+ local new = subrun(pre)
+ if new then start.pre = new end
+ end
+ local post = start.post
+ if post then
+ local new = subrun(post)
+ if new then start.post = new end
+ end
+ local replace = start.replace
+ if replace then
+ local new = subrun(replace)
+ if new then start.replace = new end
+ end
+elseif typ == "gpos_single" or typ == "gpos_pair" then
+ kerndisc(start)
+ end
+ start = start.next
+ elseif id == whatsit_code then -- will be function
+ local subtype = start.subtype
+ if subtype == dir_code then
+ local dir = start.dir
+ if dir == "+TRT" or dir == "+TLT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ elseif dir == "-TRT" or dir == "-TLT" then
+ topstack = topstack - 1
+ end
+ local newdir = dirstack[topstack]
+ if newdir == "+TRT" then
+ rlmode = -1
+ elseif newdir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = rlparmode
+ end
+ if trace_directions then
+ report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
+ end
+ elseif subtype == localpar_code then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlparmode = -1
+ elseif dir == "TLT" then
+ rlparmode = 1
+ else
+ rlparmode = 0
+ end
+ -- one might wonder if the par dir should be looked at, so we might as well drop the next line
+ rlmode = rlparmode
+ if trace_directions then
+ report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
+ end
+ end
+ start = start.next
+ elseif id == math_code then
+ start = end_of_math(start).next
+ else
+ start = start.next
+ end
+ end
+ end
+ else
+
+ local function subrun(start)
+ -- mostly for gsub, gpos would demand a more clever approach
+ local head = start
+ local done = false
+ while start do
+ local id = start.id
+ if id == glyph_code and start.id == font and start.subtype <256 then
+ local a = start[0]
+ if a then
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
+ else
+ a = not attribute or start[a_state] == attribute
+ end
+ if a then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ done = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ else
+ start = start.next
+ end
+ end
+ if done then
+ success = true
+ return head
+ end
+ end
+
+ local function kerndisc(disc) -- we can assume that prev and next are glyphs
+ local prev = disc.prev
+ local next = disc.next
+ if prev and next then
+ prev.next = next
+ -- next.prev = prev
+ local a = prev[0]
+ if a then
+ a = (a == attr) and (not attribute or prev[a_state] == attribute)
+ else
+ a = not attribute or prev[a_state] == attribute
+ end
+ if a then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[prev.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ done = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ end
+ prev.next = disc
+ -- next.prev = disc
+ end
+ return next
+ end
+
+ while start do
+ local id = start.id
+ if id == glyph_code then
+ if start.font == font and start.subtype<256 then
+ local a = start[0]
+ if a then
+ a = (a == attr) and (not attribute or start[a_state] == attribute)
+ else
+ a = not attribute or start[a_state] == attribute
+ end
+ if a then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ success = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ else
+ start = start.next
+ end
+ elseif id == disc_code then
+ -- mostly for gsub
+ if start.subtype == discretionary_code then
+ local pre = start.pre
+ if pre then
+ local new = subrun(pre)
+ if new then start.pre = new end
+ end
+ local post = start.post
+ if post then
+ local new = subrun(post)
+ if new then start.post = new end
+ end
+ local replace = start.replace
+ if replace then
+ local new = subrun(replace)
+ if new then start.replace = new end
+ end
+elseif typ == "gpos_single" or typ == "gpos_pair" then
+ kerndisc(start)
+ end
+ start = start.next
+ elseif id == whatsit_code then
+ local subtype = start.subtype
+ if subtype == dir_code then
+ local dir = start.dir
+ if dir == "+TRT" or dir == "+TLT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ elseif dir == "-TRT" or dir == "-TLT" then
+ topstack = topstack - 1
+ end
+ local newdir = dirstack[topstack]
+ if newdir == "+TRT" then
+ rlmode = -1
+ elseif newdir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = rlparmode
+ end
+ if trace_directions then
+ report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
+ end
+ elseif subtype == localpar_code then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlparmode = -1
+ elseif dir == "TLT" then
+ rlparmode = 1
+ else
+ rlparmode = 0
+ end
+ rlmode = rlparmode
+ if trace_directions then
+ report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
+ end
+ end
+ start = start.next
+ elseif id == math_code then
+ start = end_of_math(start).next
+ else
+ start = start.next
+ end
+ end
+ end
+ end
+ if success then
+ done = true
+ end
+ if trace_steps then -- ?
+ registerstep(head)
+ end
+ end
+ return head, done
+end
+
+local function generic(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if target then
+ target[unicode] = lookupdata
+ else
+ lookuphash[lookupname] = { [unicode] = lookupdata }
+ end
+end
+
+local action = {
+
+ substitution = generic,
+ multiple = generic,
+ alternate = generic,
+ position = generic,
+
+ ligature = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ for i=1,#lookupdata do
+ local li = lookupdata[i]
+ local tu = target[li]
+ if not tu then
+ tu = { }
+ target[li] = tu
+ end
+ target = tu
+ end
+ target.ligature = unicode
+ end,
+
+ pair = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ local others = target[unicode]
+ local paired = lookupdata[1]
+ if others then
+ others[paired] = lookupdata
+ else
+ others = { [paired] = lookupdata }
+ target[unicode] = others
+ end
+ end,
+
+}
+
+local function prepare_lookups(tfmdata)
+
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local anchor_to_lookup = resources.anchor_to_lookup
+ local lookup_to_anchor = resources.lookup_to_anchor
+ local lookuptypes = resources.lookuptypes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+
+ -- we cannot free the entries in the descriptions as sometimes we access
+ -- then directly (for instance anchors) ... selectively freeing does save
+ -- much memory as it's only a reference to a table and the slot in the
+ -- description hash is not freed anyway
+
+ for unicode, character in next, characters do -- we cannot loop over descriptions !
+
+ local description = descriptions[unicode]
+
+ if description then
+
+ local lookups = description.slookups
+ if lookups then
+ for lookupname, lookupdata in next, lookups do
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
+ end
+ end
+
+ local lookups = description.mlookups
+ if lookups then
+ for lookupname, lookuplist in next, lookups do
+ local lookuptype = lookuptypes[lookupname]
+ for l=1,#lookuplist do
+ local lookupdata = lookuplist[l]
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
+ end
+ end
+ end
+
+ local list = description.kerns
+ if list then
+ for lookup, krn in next, list do -- ref to glyph, saves lookup
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = krn
+ else
+ lookuphash[lookup] = { [unicode] = krn }
+ end
+ end
+ end
+
+ local list = description.anchors
+ if list then
+ for typ, anchors in next, list do -- types
+ if typ == "mark" or typ == "cexit" then -- or entry?
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = anchors
+ else
+ lookuphash[lookup] = { [unicode] = anchors }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ end
+
+ end
+
+end
+
+local function split(replacement,original)
+ local result = { }
+ for i=1,#replacement do
+ result[original[i]] = replacement[i]
+ end
+ return result
+end
+
+local valid = {
+ coverage = { chainsub = true, chainpos = true, contextsub = true },
+ reversecoverage = { reversesub = true },
+ glyphs = { chainsub = true, chainpos = true },
+}
+
+local function prepare_contextchains(tfmdata)
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local lookups = rawdata.lookups
+ if lookups then
+ for lookupname, lookupdata in next, rawdata.lookups do
+ local lookuptype = lookupdata.type
+ if lookuptype then
+ local rules = lookupdata.rules
+ if rules then
+ local format = lookupdata.format
+ local validformat = valid[format]
+ if not validformat then
+ report_prepare("unsupported format %a",format)
+ elseif not validformat[lookuptype] then
+ -- todo: dejavu-serif has one (but i need to see what use it has)
+ report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname)
+ else
+ local contexts = lookuphash[lookupname]
+ if not contexts then
+ contexts = { }
+ lookuphash[lookupname] = contexts
+ end
+ local t, nt = { }, 0
+ for nofrules=1,#rules do
+ local rule = rules[nofrules]
+ local current = rule.current
+ local before = rule.before
+ local after = rule.after
+ local replacements = rule.replacements
+ local sequence = { }
+ local nofsequences = 0
+ -- Eventually we can store start, stop and sequence in the cached file
+ -- but then less sharing takes place so best not do that without a lot
+ -- of profiling so let's forget about it.
+ if before then
+ for n=1,#before do
+ nofsequences = nofsequences + 1
+ sequence[nofsequences] = before[n]
+ end
+ end
+ local start = nofsequences + 1
+ for n=1,#current do
+ nofsequences = nofsequences + 1
+ sequence[nofsequences] = current[n]
+ end
+ local stop = nofsequences
+ if after then
+ for n=1,#after do
+ nofsequences = nofsequences + 1
+ sequence[nofsequences] = after[n]
+ end
+ end
+ if sequence[1] then
+ -- Replacements only happen with reverse lookups as they are single only. We
+ -- could pack them into current (replacement value instead of true) and then
+ -- use sequence[start] instead but it's somewhat ugly.
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ else
+ -- no rules
+ end
+ else
+ report_prepare("missing lookuptype for lookupname %a",lookupname)
+ end
+ end
+ end
+end
+
+-- we can consider lookuphash == false (initialized but empty) vs lookuphash == table
+
+local function featuresinitializer(tfmdata,value)
+ if true then -- value then
+ -- beware we need to use the topmost properties table
+ local rawdata = tfmdata.shared.rawdata
+ local properties = rawdata.properties
+ if not properties.initialized then
+ local starttime = trace_preparing and os.clock()
+ local resources = rawdata.resources
+ resources.lookuphash = resources.lookuphash or { }
+ prepare_contextchains(tfmdata)
+ prepare_lookups(tfmdata)
+ properties.initialized = true
+ if trace_preparing then
+ report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,tfmdata.properties.fullname)
+ end
+ end
+ end
+end
+
+registerotffeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ position = 1,
+ node = featuresinitializer,
+ },
+ processors = {
+ node = featuresprocessor,
+ }
+}
+
+-- This can be used for extra handlers, but should be used with care!
+
+otf.handlers = handlers
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index 7995be33e..5e5c9a4cf 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -210,9 +210,9 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
loadmodule('font-oti.lua')
loadmodule('font-otf.lua')
loadmodule('font-otb.lua')
- loadmodule('node-inj.lua') -- will be replaced (luatex >= .70)
+ loadmodule('luatex-fonts-inj.lua') -- will be replaced (luatex >= .80)
loadmodule('font-ota.lua')
- loadmodule('font-otn.lua')
+ loadmodule('luatex-fonts-otn.lua')
loadmodule('font-otp.lua') -- optional
loadmodule('luatex-fonts-lua.lua')
loadmodule('font-def.lua')