diff options
Diffstat (limited to 'tex')
171 files changed, 7133 insertions, 2279 deletions
diff --git a/tex/context/base/anch-pos.lua b/tex/context/base/anch-pos.lua index 7321d7d99..9cc9fb128 100644 --- a/tex/context/base/anch-pos.lua +++ b/tex/context/base/anch-pos.lua @@ -26,9 +26,14 @@ local rawget = rawget local lpegmatch = lpeg.match local insert, remove = table.insert, table.remove local allocate, mark = utilities.storage.allocate, utilities.storage.mark -local texsp, texcount, texbox, texdimen, texsetcount = tex.sp, tex.count, tex.box, tex.dimen, tex.setcount +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 @@ -170,7 +175,7 @@ local function setdim(name,w,h,d,extra) -- will be used when we move to sp allov if extra == "" then extra = nil end -- todo: sparse tobesaved[name] = { - p = texcount.realpageno, + p = texgetcount("realpageno"), x = x, y = y, w = w, @@ -217,7 +222,7 @@ local function enhance(data) data.y = pdf.v end if data.p == true then - data.p = texcount.realpageno + data.p = texgetcount("realpageno") end if data.c == true then data.c = column @@ -315,16 +320,16 @@ function jobpositions.b_region(tag) local last = tobesaved[tag] last.x = pdf.h last.y = pdf.v - last.p = texcount.realpageno + last.p = texgetcount("realpageno") insert(regions,tag) region = tag end function jobpositions.e_region(correct) local last = tobesaved[region] -if correct then - last.h = last.y - pdf.v -end + if correct then + last.h = last.y - pdf.v + end last.y = pdf.v remove(regions) region = regions[#regions] @@ -335,7 +340,7 @@ function jobpositions.markregionbox(n,tag,correct) nofregions = nofregions + 1 tag = f_region(nofregions) end - local box = texbox[n] + local box = texgetbox(n) local w = box.width local h = box.height local d = box.depth @@ -378,7 +383,7 @@ 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 = texbox.strutbox + local strutbox = texgetbox("strutbox") local t = { p = true, c = true, @@ -387,14 +392,14 @@ function commands.parpos() -- todo: relate to localpar (so this is an intermedia y = true, h = strutbox.height, d = strutbox.depth, - hs = tex.hsize, + hs = texget("hsize"), } - local leftskip = tex.leftskip.width - local rightskip = tex.rightskip.width - local hangindent = tex.hangindent - local hangafter = tex.hangafter - local parindent = tex.parindent - local parshape = tex.parshape + local leftskip = texget("leftskip").width + local rightskip = texget("rightskip").width + local hangindent = texget("hangindent") + local hangafter = texget("hangafter") + local parindent = texget("parindent") + local parshape = texget("parshape") if leftskip ~= 0 then t.ls = leftskip end @@ -462,7 +467,7 @@ function commands.posplus(name,w,h,d,extra) end function commands.posstrut(name,w,h,d) - local strutbox = texbox.strutbox + local strutbox = texgetbox("strutbox") tobesaved[name] = { p = true, c = column, @@ -478,7 +483,7 @@ end function jobpositions.getreserved(tag,n) if tag == v_column then - local fulltag = f_tag_three(tag,texcount.realpageno,n or 1) + local fulltag = f_tag_three(tag,texgetcount("realpageno"),n or 1) local data = collected[fulltag] if data then return data, fulltag @@ -486,7 +491,7 @@ function jobpositions.getreserved(tag,n) tag = v_text end if tag == v_text then - local fulltag = f_tag_two(tag,texcount.realpageno) + local fulltag = f_tag_two(tag,texgetcount("realpageno")) return collected[fulltag] or false, fulltag end return collected[tag] or false, tag @@ -1015,7 +1020,7 @@ function commands.doifpositionsonsamepageelse(list,page) end function commands.doifpositionsonthispageelse(list) - doifelse(onsamepage(list,tostring(tex.count.realpageno))) + doifelse(onsamepage(list,tostring(texgetcount("realpageno")))) end function commands.doifelsepositionsused() diff --git a/tex/context/base/attr-eff.lua b/tex/context/base/attr-eff.lua index 4dce5419a..b187b64c7 100644 --- a/tex/context/base/attr-eff.lua +++ b/tex/context/base/attr-eff.lua @@ -13,7 +13,7 @@ local tex = tex local states = attributes.states local tasks = nodes.tasks local nodeinjections = backends.nodeinjections -local settexattribute = tex.setattribute +local texsetattribute = tex.setattribute local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex local formatters = string.formatters @@ -107,5 +107,5 @@ function commands.triggereffect(specification) enable() enabled = true end - settexattribute(a_effect,register(specification)) + texsetattribute(a_effect,register(specification)) end diff --git a/tex/context/base/attr-ini.lua b/tex/context/base/attr-ini.lua index 206a86d79..ad4081681 100644 --- a/tex/context/base/attr-ini.lua +++ b/tex/context/base/attr-ini.lua @@ -20,6 +20,9 @@ local attributes = attributes local sharedstorage = storage.shared +local texgetcount = tex.getcount +local texsetattribute = tex.setattribute + attributes.names = attributes.names or { } attributes.numbers = attributes.numbers or { } attributes.list = attributes.list or { } @@ -64,7 +67,7 @@ sharedstorage.attributes_last_private = sharedstorage.attributes_last_private or -- setmetatable(private, { -- __index = function(t,name) -- local number = sharedstorage.attributes_last_private --- if number < 1023 then -- tex.count.minallocatedattribute - 1 +-- if number < 1023 then -- texgetcount("minallocatedattribute") - 1 -- number = number + 1 -- sharedstorage.attributes_last_private = number -- end @@ -81,7 +84,7 @@ function attributes.private(name) -- at the lua end (hidden from user) local number = numbers[name] if not number then local last = sharedstorage.attributes_last_private - if last < 1023 then -- tex.count.minallocatedattribute - 1 + if last < 1023 then -- texgetcount("minallocatedattribute") - 1 last = last + 1 sharedstorage.attributes_last_private = last else @@ -155,7 +158,7 @@ function commands.restorecurrentattributes(name) local font = t.font if attr then for k, v in next, attr do - tex.attribute[k] = v + texsetattribute(k,v) end end if font then diff --git a/tex/context/base/back-exp.lua b/tex/context/base/back-exp.lua index 4d219a18b..1ff1cd7a0 100644 --- a/tex/context/base/back-exp.lua +++ b/tex/context/base/back-exp.lua @@ -81,6 +81,8 @@ local xspaceskip_code = skipcodes.xspaceskip local line_code = listcodes.line +local texgetcount = tex.getcount + local a_characters = attributes.private('characters') local a_exportstatus = attributes.private('exportstatus') @@ -94,9 +96,6 @@ local a_textblock = attributes.private("textblock") local traverse_id = node.traverse_id local traverse_nodes = node.traverse local slide_nodelist = node.slide -local texattribute = tex.attribute -local texdimen = tex.dimen -local texcount = tex.count local locate_node = nodes.locate local references = structures.references @@ -454,7 +453,7 @@ local function checkdocument(root) end function extras.document(result,element,detail,n,fulltag,di) - result[#result+1] = format(" language=%q",languagenames[tex.count.mainlanguagenumber]) + result[#result+1] = format(" language=%q",languagenames[texgetcount("mainlanguagenumber")]) if not less_state then result[#result+1] = format(" file=%q",tex.jobname) result[#result+1] = format(" date=%q",os.date()) @@ -2353,7 +2352,7 @@ local function stopexport(v) images = uniqueusedimages(), root = xhtmlfile, files = files, - language = languagenames[tex.count.mainlanguagenumber], + language = languagenames[texgetcount("mainlanguagenumber")], title = validstring(finetuning.title) or validstring(identity.title), subtitle = validstring(finetuning.subtitle) or validstring(identity.subtitle), author = validstring(finetuning.author) or validstring(identity.author), @@ -2377,13 +2376,13 @@ end local function startexport(v) if v and not exporting then report_export("enabling export to xml") --- not yet known in task-ini + -- not yet known in task-ini appendaction("shipouts","normalizers", "nodes.handlers.export") --- enableaction("shipouts","nodes.handlers.export") + -- enableaction("shipouts","nodes.handlers.export") enableaction("shipouts","nodes.handlers.accessibility") enableaction("math", "noads.handlers.tags") ---~ appendaction("finalizers","lists","builders.paragraphs.tag") ---~ enableaction("finalizers","builders.paragraphs.tag") + -- appendaction("finalizers","lists","builders.paragraphs.tag") + -- enableaction("finalizers","builders.paragraphs.tag") luatex.registerstopactions(function() stopexport(v) end) exporting = true end diff --git a/tex/context/base/back-pdf.mkiv b/tex/context/base/back-pdf.mkiv index 1cf7a3703..3be1c4ec1 100644 --- a/tex/context/base/back-pdf.mkiv +++ b/tex/context/base/back-pdf.mkiv @@ -195,14 +195,14 @@ \pdfrestore \advance\backendtransformlevel\minusone}}} -\unexpanded\def\dostartclipping#1#2#3% +\unexpanded\def\dostartclipping#1#2#3% we can move this to lua and only set a box here {\PointsToBigPoints{#2}\width \PointsToBigPoints{#3}\height \meta_grab_clip_path{#1}\width\height{0 0 m \width\space 0 l \width \height l 0 \height l}% \pdfliteral{q 0 w \MPclippath\space W n}} \unexpanded\def\dostopclipping - {\pdfliteral{Q n}} + {\pdfliteral{Q}} %D The following will move to the backend \LUA\ code: diff --git a/tex/context/base/blob-ini.lua b/tex/context/base/blob-ini.lua index 4debaf94c..32fac7662 100644 --- a/tex/context/base/blob-ini.lua +++ b/tex/context/base/blob-ini.lua @@ -31,30 +31,37 @@ if not modules then modules = { } end modules ['blob-ini'] = { local type, tostring = type, tostring local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns -local report_blobs = logs.reporter("blobs") +local report_blobs = logs.reporter("blobs") -local t_tonodes = typesetters.tonodes -local t_hpack = typesetters.hpack +local flush_node_list = node.flush_list +local hpack_node_list = node.hpack +local vpack_node_list = node.vpack +local write_node = node.write -local flush_node_list = node.flush_list -local hpack_node_list = node.hpack -local vpack_node_list = node.vpack -local write_node = node.write +local typesetters = nodes.typesetters +local tonodes = typesetters.tonodes +local tohpack = typesetters.tohpack +local tohpackfast = typesetters.tohpackfast +local tovpack = typesetters.tovpack +local tovpackfast = typesetters.tovpackfast blobs = blobs or { } -local newline = lpegpatterns.newline -local space = lpegpatterns.spacer -local spacing = newline * space^0 -local content = (space^1)/" " + (1-spacing) +-- provide copies here (nicer for manuals) -local ctxtextcapture = lpeg.Ct ( ( -- needs checking (see elsewhere) - space^0 * ( - newline^2 * space^0 * lpeg.Cc("") - + newline * space^0 * lpeg.Cc(" ") - + lpeg.Cs(content^1) - ) -)^0) +blobs.tonodes = tonodes +blobs.tohpack = tohpack +blobs.tohpackfast = tohpackfast +blobs.tovpack = tovpack +blobs.tovpackfast = tovpackfast + +-- end of helpers + +local newline = lpeg.patterns.newline +local space = lpeg.patterns.spacer +local newpar = (space^0*newline*space^0)^2 + +local ctxtextcapture = lpeg.Ct ( ( space^0 * ( newpar + lpeg.Cs(((space^1/" " + 1)-newpar)^1) ) )^0) function blobs.new() return { @@ -81,33 +88,12 @@ function blobs.append(t,str) -- compare concat and link str = tostring(str) typ = "string" end - local list = t.list if typ == "string" then local pars = lpegmatch(ctxtextcapture,str) - local noflist = #list + local list = t.list for p=1,#pars do - local str = pars[p] - if #str == 0 then - noflist = noflist + 1 - list[noflist] = { head = nil, tail = nil } - else - local l = list[noflist] - if not l then - l = { head = nil, tail = nil } - noflist = noflist + 1 - list[noflist] = l - end - local head, tail = t_tonodes(str,nil,nil) - if head then - if l.head then - l.tail.next = head - head.prev = l.tail - l.tail = tail - else - l.head, l.tail = head, tail - end - end - end + local head, tail = tonodes(pars[p],nil,nil) + list[#list+1] = { head = head, tail = tail } end end end @@ -121,7 +107,7 @@ function blobs.pack(t,how) end if how == "vertical" then -- we need to prepend a local par node - -- list[i].pack = node.vpack(list[i].head,"exactly") + -- list[i].pack = vpack_node_list(list[i].head,"exactly") report_blobs("vpack not yet supported") else list[i].pack = hpack_node_list(list[i].head,"exactly") @@ -176,12 +162,44 @@ end -- for the moment here: -function commands.widthofstring(str) - local l = t_hpack(str) - context(number.todimen(l.width)) +local function strwd(str) + local l = tohpack(str) + local w = l.width flush_node_list(l) + return w end +local function strht(str) + local l = tohpack(str) + local h = l.height + flush_node_list(l) + return h +end + +local function strdp(str) + local l = tohpack(str) + local d = l.depth + flush_node_list(l) + return d +end + +local function strhd(str) + local l = tohpack(str) + local s = l.height + l.depth + flush_node_list(l) + return s +end + +blobs.strwd = strwd +blobs.strht = strht +blobs.strdp = strdp +blobs.strhd = strhd + +function commands.strwd(str) context(strwd(str)) end +function commands.strht(str) context(strht(str)) end +function commands.strdp(str) context(strdp(str)) end +function commands.strhd(str) context(strhd(str)) end + -- less efficient: -- -- function commands.widthof(str) diff --git a/tex/context/base/blob-ini.mkiv b/tex/context/base/blob-ini.mkiv index 4fdb9e4b6..1dfb766f4 100644 --- a/tex/context/base/blob-ini.mkiv +++ b/tex/context/base/blob-ini.mkiv @@ -27,7 +27,19 @@ % this one takes simple (utf) strings -\def\widthofstring#1{\ctxcommand{widthofstring(\!!bs#1\!!es)}} +\def\wdofstring#1{\dimexpr\ctxcommand{strwd(\!!bs#1\!!es)}\scaledpoint\relax} +\def\htofstring#1{\dimexpr\ctxcommand{strht(\!!bs#1\!!es)}\scaledpoint\relax} +\def\dpofstring#1{\dimexpr\ctxcommand{strdp(\!!bs#1\!!es)}\scaledpoint\relax} +\def\hdofstring#1{\dimexpr\ctxcommand{strhd(\!!bs#1\!!es)}\scaledpoint\relax} + +\def\widthofstring {\the\wdofstring} +\def\heightofstring {\the\htofstring} +\def\depthofstring {\the\dpofstring} +\def\heightanddepthofstring{\the\hdofstring} + +\let\htdpofstring \hdofstring + +\let\hd\htdp % if yes then move this % this one takes anything that can be typeset diff --git a/tex/context/base/chem-str.lua b/tex/context/base/chem-str.lua index 8c1bf38fc..347363345 100644 --- a/tex/context/base/chem-str.lua +++ b/tex/context/base/chem-str.lua @@ -37,25 +37,24 @@ local concat, insert, remove, unique, sorted = table.concat, table.insert, table local processor_tostring = typesetters and typesetters.processors.tostring local settings_to_array = utilities.parsers.settings_to_array local settings_to_array_with_repeat = utilities.parsers.settings_to_array_with_repeat -local formatters = string.formatters local lpegmatch = lpeg.match local P, R, S, C, Cs, Ct, Cc, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cmt -local variables = interfaces and interfaces.variables -local commands = commands -local context = context -local formatters = string.formatters -local texcount = tex.count - -local v_default = variables.default -local v_small = variables.small -local v_medium = variables.medium -local v_big = variables.big -local v_normal = variables.normal -local v_fit = variables.fit -local v_on = variables.on -local v_none = variables.none +local variables = interfaces and interfaces.variables +local commands = commands +local context = context +local formatters = string.formatters +local texgetcount = tex.getcount + +local v_default = variables.default +local v_small = variables.small +local v_medium = variables.medium +local v_big = variables.big +local v_normal = variables.normal +local v_fit = variables.fit +local v_on = variables.on +local v_none = variables.none local mpnamedcolor = attributes.colors.mpnamedcolor local topoints = number.topoints @@ -717,7 +716,7 @@ function chemistry.start(settings) width, left, right, sp_width = calculated(width, left, right,factor,unit,scale) height, bottom, top, sp_height = calculated(height,bottom,top, factor,unit,scale) -- - if width ~= "true" and height ~= "true" and texcount["@@trialtypesetting"] ~= 0 then + if width ~= "true" and height ~= "true" and texgetcount("@@trialtypesetting") ~= 0 then if trace_structure then report_chemistry("skipping trial run") end diff --git a/tex/context/base/cldf-bas.lua b/tex/context/base/cldf-bas.lua index 6adeb2272..b982fc364 100644 --- a/tex/context/base/cldf-bas.lua +++ b/tex/context/base/cldf-bas.lua @@ -38,7 +38,8 @@ local new_rule = nodepool.rule local new_glyph = nodepool.glyph local current_font = font.current -local texcount = tex.count +local texgetcount = tex.getcount +local texsetcount = tex.setcount function context.char(k) -- used as escape too, so don't change to utf if type(k) == "table" then @@ -163,9 +164,9 @@ context.endhbox = context.egroup local function allocate(name,what,cmd) local a = format("c_syst_last_allocated_%s",what) - local n = texcount[a] + 1 - if n <= texcount.c_syst_max_allocated_register then - texcount[a] = n + local n = texgetcount(a) + 1 + if n <= texgetcount("c_syst_max_allocated_register") then + texsetcount(a,n) end context("\\global\\expandafter\\%sdef\\csname %s\\endcsname %s\\relax",cmd or what,name,n) return n diff --git a/tex/context/base/cldf-ini.lua b/tex/context/base/cldf-ini.lua index 2272c05ea..44bf522d3 100644 --- a/tex/context/base/cldf-ini.lua +++ b/tex/context/base/cldf-ini.lua @@ -38,7 +38,7 @@ local texsprint = tex.sprint local textprint = tex.tprint local texprint = tex.print local texwrite = tex.write -local texcount = tex.count +local texgetcount = tex.getcount local isnode = node.is_node -- after 0.65 just node.type local writenode = node.write @@ -86,13 +86,13 @@ local function _flush_f_(n) else local tn = type(sn) if tn == "function" then - if not sn() and texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! + if not sn() and texgetcount("@@trialtypesetting") == 0 then -- @@trialtypesetting is private! _stack_f_[n] = nil else -- keep, beware, that way the stack can grow end else - if texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! + if texgetcount("@@trialtypesetting") == 0 then -- @@trialtypesetting is private! writenode(sn) _stack_f_[n] = nil else @@ -107,7 +107,7 @@ local function _flush_n_(n) local sn = _stack_n_[n] if not sn then report_cld("data with id %a cannot be found on stack",n) - elseif texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! + elseif texgetcount("@@trialtypesetting") == 0 then -- @@trialtypesetting is private! writenode(sn) _stack_n_[n] = nil else diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 0e3ff6cf6..283e924cc 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{2013.06.10 22:51} +\newcontextversion{2013.07.12 19:10} %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 Binary files differindex f08b763d1..3bf5f1c53 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 2d018984d..e6cc65a9d 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -25,7 +25,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2013.06.10 22:51} +\edef\contextversion{2013.07.12 19:10} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/core-dat.lua b/tex/context/base/core-dat.lua index 826d3a675..242d362d0 100644 --- a/tex/context/base/core-dat.lua +++ b/tex/context/base/core-dat.lua @@ -21,13 +21,17 @@ local trace_pagestates = false trackers.register("job.pagestates", function(v) local report_dataset = logs.reporter("dataset") local report_pagestate = logs.reporter("pagestate") -local allocate = utilities.storage.allocate +local allocate = utilities.storage.allocate local settings_to_hash = utilities.parsers.settings_to_hash -local texcount = tex.count -local formatters = string.formatters -local v_yes = interfaces.variables.yes -local new_latelua = nodes.pool.latelua +local texgetcount = tex.getcount +local texsetcount = tex.setcount + +local formatters = string.formatters + +local v_yes = interfaces.variables.yes + +local new_latelua = nodes.pool.latelua local collected = allocate() local tobesaved = allocate() @@ -86,7 +90,7 @@ local function setdata(settings) set.index = index data.index = index data.order = index - data.realpage = texcount.realpageno + data.realpage = texgetcount("realpageno") if trace_datasets then report_dataset("action %a, name %a, tag %a, index %a","assign delayed",name,tag,index) end @@ -101,7 +105,7 @@ datasets.setdata = setdata function datasets.extend(name,tag) local set = sets[name] local order = set.order + 1 - local realpage = texcount.realpageno + local realpage = texgetcount("realpageno") set.order = order local t = tobesaved[name][tag] t.realpage = realpage @@ -207,7 +211,7 @@ local function setstate(settings) else tag = tonumber(tag) or tag -- autonumber saves keys end - local realpage = texcount.realpageno + local realpage = texgetcount("realpageno") local data = realpage list[tag] = data if trace_pagestates then @@ -219,7 +223,7 @@ end pagestates.setstate = setstate function pagestates.extend(name,tag) - local realpage = texcount.realpageno + local realpage = texgetcount("realpageno") if trace_pagestates then report_pagestate("action %a, name %a, tag %a, preset %a","synchronize",name,tag,realpage) end @@ -261,9 +265,5 @@ end function commands.setpagestaterealpageno(name,tag) local t = collected[name] t = t and (t[tag] or t[tonumber(tag)]) - if t then - texcount.realpagestateno = t - else - texcount.realpagestateno = texcount.realpageno - end + texsetcount("realpagestateno",t or texgetcount("realpageno")) end diff --git a/tex/context/base/core-env.lua b/tex/context/base/core-env.lua index de977d0bb..a4d1fdd92 100644 --- a/tex/context/base/core-env.lua +++ b/tex/context/base/core-env.lua @@ -15,7 +15,7 @@ local P, C, S, Cc, lpegmatch, patterns = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc, lpeg.m local csname_id = token.csname_id local create = token.create -local texcount = tex.count +local texgetcount = tex.getcount local texsetcount = tex.setcount local allocate = utilities.storage.allocate @@ -44,8 +44,8 @@ setmetatableindex(tex.modes, function(t,k) if csname_id(n) == undefined then return false else - modes[k] = function() return texcount[n] >= 1 end - return texcount[n] >= 1 + modes[k] = function() return texgetcount(n) >= 1 end + return texgetcount(n) >= 1 end end end) @@ -59,18 +59,18 @@ setmetatableindex(tex.systemmodes, function(t,k) if csname_id(n) == undefined then return false else - systemmodes[k] = function() return texcount[n] >= 1 end - return texcount[n] >= 1 + systemmodes[k] = function() return texgetcount(n) >= 1 end + return texgetcount(n) >= 1 end end end) setmetatableindex(tex.constants, function(t,k) - return csname_id(k) ~= undefined and texcount[k] or 0 + return csname_id(k) ~= undefined and texgetcount(k) or 0 end) setmetatableindex(tex.conditionals, function(t,k) -- 0 == true - return csname_id(k) ~= undefined and texcount[k] == 0 + return csname_id(k) ~= undefined and texgetcount(k) == 0 end) setmetatableindex(tex.ifs, function(t,k) @@ -86,7 +86,7 @@ end) -- if glob then -- texsetcount("global",name,0) -- else --- texcount[name] = 0 +-- texsetcount(name,0) -- end -- end -- @@ -94,7 +94,7 @@ end) -- if glob then -- texsetcount("global",name,1) -- else --- texcount[name] = 1 +-- texsetcount(name,1) -- end -- end diff --git a/tex/context/base/core-uti.lua b/tex/context/base/core-uti.lua index 53ff891e2..4e3c839bd 100644 --- a/tex/context/base/core-uti.lua +++ b/tex/context/base/core-uti.lua @@ -20,7 +20,6 @@ saves much runtime but at the cost of more memory usage.</p> local format, match = string.format, string.match local next, type, tostring = next, type, tostring local concat = table.concat -local texcount = tex.count local definetable = utilities.tables.definetable local accesstable = utilities.tables.accesstable @@ -30,6 +29,8 @@ local packers = utilities.packers local allocate = utilities.storage.allocate local mark = utilities.storage.mark +local texgetcount = tex.getcount + local report_passes = logs.reporter("job","passes") job = job or { } @@ -149,7 +150,7 @@ function job.save(filename) -- we could return a table but it can get pretty lar local f = io.open(filename,'w') if f then f:write("local utilitydata = { }\n\n") - f:write(serialize(comment,"utilitydata.comment",true,true),"\n\n") + f:write(serialize(comment,"utilitydata.comment",true),"\n\n") for l=1,#savelist do local list = savelist[l] local target = format("utilitydata.%s",list[1]) @@ -162,11 +163,11 @@ function job.save(filename) -- we could return a table but it can get pretty lar packers.pack(data,jobpacker,true) end local definer, name = definetable(target,true,true) -- no first and no last - f:write(definer,"\n\n",serialize(data,name,true,true),"\n\n") + f:write(definer,"\n\n",serialize(data,name,true),"\n\n") end if job.pack then packers.strip(jobpacker) - f:write(serialize(jobpacker,"utilitydata.job.packed",true,true),"\n\n") + f:write(serialize(jobpacker,"utilitydata.job.packed",true),"\n\n") end f:write("return utilitydata") f:close() @@ -264,7 +265,7 @@ end) statistics.register("callbacks", function() local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0 - local pages = texcount['realpageno'] - 1 + local pages = texgetcount('realpageno') - 1 if pages > 1 then return format("direct: %s, indirect: %s, total: %s (%i per page)", total-indirect, indirect, total, total/pages) else @@ -280,8 +281,8 @@ end) function statistics.formatruntime(runtime) if not environment.initex then -- else error when testing as not counters yet - local shipped = texcount['nofshipouts'] - local pages = texcount['realpageno'] + local shipped = texgetcount('nofshipouts') + local pages = texgetcount('realpageno') if pages > shipped then pages = shipped end diff --git a/tex/context/base/data-met.lua b/tex/context/base/data-met.lua index 96da70bfd..ee9de3fd9 100644 --- a/tex/context/base/data-met.lua +++ b/tex/context/base/data-met.lua @@ -36,7 +36,7 @@ local function splitmethod(filename) -- todo: filetype in specification end filename = file.collapsepath(filename,".") -- hm, we should keep ./ in some cases --- filename = gsub(filename,"^%./",getcurrentdir().."/") -- we will merge dir.expandname and collapse some day + -- filename = gsub(filename,"^%./",getcurrentdir().."/") -- we will merge dir.expandname and collapse some day if not find(filename,"://") then return { scheme = "file", path = filename, original = filename, filename = filename } @@ -49,6 +49,16 @@ local function splitmethod(filename) -- todo: filetype in specification end end +-- local function splitmethod(filename) -- todo: filetype in specification +-- if not filename then +-- return { scheme = "unknown", original = filename } +-- end +-- if type(filename) == "table" then +-- return filename -- already split +-- end +-- return url.hashed(filename) +-- end + resolvers.splitmethod = splitmethod -- bad name but ok -- the second argument is always analyzed (saves time later on) and the original diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua index 532b6261f..f1ddb62aa 100644 --- a/tex/context/base/data-res.lua +++ b/tex/context/base/data-res.lua @@ -1303,7 +1303,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults) -- other end -- we could have a loop over the 6 functions but then we'd have to --- always analyze +-- always analyze .. todo: use url split collect_instance_files = function(filename,askedformat,allresults) -- uses nested askedformat = askedformat or "" diff --git a/tex/context/base/file-ini.lua b/tex/context/base/file-ini.lua index 1872ed3d3..2bc742a1f 100644 --- a/tex/context/base/file-ini.lua +++ b/tex/context/base/file-ini.lua @@ -13,13 +13,13 @@ if not modules then modules = { } end modules ['file-ini'] = { resolvers.jobs = resolvers.jobs or { } -local texcount = tex.count -local setvalue = context.setvalue +local texsetcount = tex.setcount +local setvalue = context.setvalue function commands.splitfilename(fullname) local t = file.nametotable(fullname) local path = t.path - texcount.splitoffkind = (path == "" and 0) or (path == '.' and 1) or 2 + texsetcount("splitoffkind",(path == "" and 0) or (path == '.' and 1) or 2) setvalue("splitofffull",fullname) setvalue("splitoffpath",path) setvalue("splitoffname",t.name) diff --git a/tex/context/base/font-chk.lua b/tex/context/base/font-chk.lua index 467afae9b..6dc1667bb 100644 --- a/tex/context/base/font-chk.lua +++ b/tex/context/base/font-chk.lua @@ -68,7 +68,7 @@ local function onetimemessage(font,char,message) -- char == false returns table if char == false then return table.sortedkeys(category) elseif not category[char] then - report_fonts("char %U in font %a with id %a: %s",char,tfmdata.properties.fullname,font,message) + report_fonts("char %C in font %a with id %a: %s",char,tfmdata.properties.fullname,font,message) category[char] = true end end @@ -210,6 +210,7 @@ function checkers.missing(head) local char = n.char if font ~= lastfont then characters = fontcharacters[font] + lastfont = font end if not characters[char] and is_character[chardata[char].category] then if action == "remove" then @@ -363,7 +364,7 @@ end) -- for the moment here -function helpers.expandglyph(characters,index,done) +local function expandglyph(characters,index,done) done = done or { } if not done[index] then local data = characters[index] @@ -390,3 +391,5 @@ function helpers.expandglyph(characters,index,done) end end end + +helpers.expandglyph = expandglyph diff --git a/tex/context/base/font-col.lua b/tex/context/base/font-col.lua index 20c99c9b4..d461d60b4 100644 --- a/tex/context/base/font-col.lua +++ b/tex/context/base/font-col.lua @@ -15,9 +15,9 @@ local file, lpeg, table, string = file, lpeg, table, string local type, next, toboolean = type, next, toboolean local gmatch = string.gmatch local fastcopy = table.fastcopy ------ P, Cc, lpegmatch = lpeg.P, lpeg.Cc, lpeg.match -local traverse_id = node.traverse_id +local traverse_id = nodes.traverse_id + local settings_to_hash = utilities.parsers.settings_to_hash local trace_collecting = false trackers.register("fonts.collecting", function(v) trace_collecting = v end) @@ -215,7 +215,8 @@ function collections.process(head) -- this way we keep feature processing if trace_collecting then report_fonts("remapping character %a in font %a to character %a in font %a",n.char,n.font,newchar,newid) end - n.font, n.char = newid, newchar + n.font = newid + n.char = newchar else if trace_collecting then report_fonts("remapping font %a to %a for character %a",n.font,id,n.char) diff --git a/tex/context/base/font-con.lua b/tex/context/base/font-con.lua index 790d4877a..6a466a027 100644 --- a/tex/context/base/font-con.lua +++ b/tex/context/base/font-con.lua @@ -1278,7 +1278,8 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report) local whathandler = handlers[what] local whatfeatures = whathandler.features local whatprocessors = whatfeatures.processors - local processors = whatprocessors[properties.mode] + local mode = properties.mode + local processors = whatprocessors[mode] if processors then for i=1,#processors do local step = processors[i] @@ -1295,7 +1296,7 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report) end end elseif trace then - report("no feature processors for mode %a for font %a",mode,tfmdata.properties.fullname) + report("no feature processors for mode %a for font %a",mode,properties.fullname) end end return processes @@ -1309,7 +1310,8 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) local whathandler = handlers[what] local whatfeatures = whathandler.features local whatmanipulators = whatfeatures.manipulators - local manipulators = whatmanipulators[properties.mode] + local mode = properties.mode + local manipulators = whatmanipulators[mode] if manipulators then for i=1,#manipulators do local step = manipulators[i] @@ -1318,7 +1320,7 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) if value then local action = step.action if trace then - report("applying feature manipulator %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) + report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname) end if action then action(tfmdata,feature,value) diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index 31de74578..7388a49ca 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -14,7 +14,6 @@ if not modules then modules = { } end modules ['font-ctx'] = { local context, commands = context, commands -local texcount, texsetcount = tex.count, tex.setcount local format, gmatch, match, find, lower, gsub, byte = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte local concat, serialize, sort, fastcopy, mergedtable = table.concat, table.serialize, table.sort, table.fastcopy, table.merged local sortedhash, sortedkeys, sequenced = table.sortedhash, table.sortedkeys, table.sequenced @@ -56,8 +55,15 @@ local fontgoodies = fonts.goodies local helpers = fonts.helpers local hashes = fonts.hashes local currentfont = font.current -local texattribute = tex.attribute -local texdimen = tex.dimen + +local texgetattribute = tex.getattribute +local texsetattribute = tex.setattribute +local texgetdimen = tex.getdimen +local texsetcount = tex.setcount +local texget = tex.get + +local texdefinefont = tex.definefont +local texsp = tex.sp local fontdata = hashes.identifiers local characters = hashes.chardata @@ -659,14 +665,14 @@ end -- local withcache = { } -- concat might be less efficient than nested tables -- -- local function withset(name,what) --- local zero = texattribute[0] +-- local zero = texgetattribute(0) -- local hash = zero .. "+" .. name .. "*" .. what -- local done = withcache[hash] -- if not done then -- done = mergecontext(zero,name,what) -- withcache[hash] = done -- end --- texattribute[0] = done +-- texsetattribute(0,done) -- end -- -- local function withfnt(name,what,font) @@ -677,7 +683,7 @@ end -- done = registercontext(font,name,what) -- withcache[hash] = done -- end --- texattribute[0] = done +-- texsetattribute(0,done) -- end function specifiers.showcontext(name) @@ -848,18 +854,18 @@ function commands.definefont_one(str) if size and size ~= "" then local mode, size = lpegmatch(sizepattern,size) if size and mode then - texcount.scaledfontmode = mode + texsetcount("scaledfontmode",mode) setsomefontsize(size) else - texcount.scaledfontmode = 0 + texsetcount("scaledfontmode",0) setemptyfontsize() end elseif true then -- so we don't need to check in tex - texcount.scaledfontmode = 2 + texsetcount("scaledfontmode",2) setemptyfontsize() else - texcount.scaledfontmode = 0 + texsetcount("scaledfontmode",0) setemptyfontsize() end specification = definers.makespecification(str,lookup,name,sub,method,detail,size) @@ -983,7 +989,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize) end csnames[tfmdata] = specification.cs - tex.definefont(global,cs,tfmdata) + texdefinefont(global,cs,tfmdata) -- resolved (when designsize is used): setsomefontsize((fontdata[tfmdata].parameters.size or 0) .. "sp") lastfontid = tfmdata @@ -1001,7 +1007,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature csnames[id] = specification.cs tfmdata.properties.id = id definers.register(tfmdata,id) -- to be sure, normally already done - tex.definefont(global,cs,id) + texdefinefont(global,cs,id) constructors.cleanuptable(tfmdata) constructors.finalize(tfmdata) if trace_defining then @@ -1050,7 +1056,7 @@ function definers.define(specification) specification.detail = specification.detail or (detail ~= "" and detail) or "" -- if type(specification.size) == "string" then - specification.size = tex.sp(specification.size) or 655260 + specification.size = texsp(specification.size) or 655260 end -- specification.specification = "" -- not used @@ -1074,7 +1080,7 @@ function definers.define(specification) return -1, nil elseif type(tfmdata) == "number" then if cs then - tex.definefont(specification.global,cs,tfmdata) + texdefinefont(specification.global,cs,tfmdata) csnames[tfmdata] = cs end return tfmdata, fontdata[tfmdata] @@ -1083,7 +1089,7 @@ function definers.define(specification) tfmdata.properties.id = id definers.register(tfmdata,id) if cs then - tex.definefont(specification.global,cs,id) + texdefinefont(specification.global,cs,id) csnames[id] = cs end constructors.cleanuptable(tfmdata) @@ -1103,7 +1109,7 @@ local n = 0 function definers.internal(specification,cs) specification = specification or { } local name = specification.name - local size = specification.size and number.todimen(specification.size) or texdimen.bodyfontsize + local size = specification.size and number.todimen(specification.size) or texgetdimen("bodyfontsize") local number = tonumber(specification.number) local id = nil if number then @@ -1423,11 +1429,11 @@ function commands.featureattribute(tag) end function commands.setfontfeature(tag) - texattribute[0] = contextnumber(tag) + texsetattribute(0,contextnumber(tag)) end function commands.resetfontfeature() - texattribute[0] = 0 + texsetattribute(0,0) end -- function commands.addfs(tag) withset(tag, 1) end @@ -1578,19 +1584,24 @@ end local quads = hashes.quads local xheights = hashes.xheights -setmetatableindex(number.dimenfactors, function(t,k) +setmetatableindex(dimenfactors, function(t,k) if k == "ex" then - return xheigths[currentfont()] + return 1/xheights[currentfont()] elseif k == "em" then - return quads[currentfont()] - elseif k == "%" then - return dimen.hsize/100 + return 1/quads[currentfont()] + elseif k == "pct" or k == "%" then + return 1/(texget("hsize")/100) else -- error("wrong dimension: " .. (s or "?")) -- better a message return false end end) +dimenfactors.ex = nil +dimenfactors.em = nil +dimenfactors["%"] = nil +dimenfactors.pct = nil + --[[ldx-- <p>Before a font is passed to <l n='tex'/> we scale it. Here we also need to scale virtual characters.</p> @@ -1668,17 +1679,17 @@ local hows = { function commands.feature(how,parent,name,font) -- 0/1 test temporary for testing if not how or how == 0 then - if trace_features and texattribute[0] ~= 0 then + if trace_features and texgetattribute(0) ~= 0 then report_cummulative("font %!font:name!, reset",fontdata[font or true]) end - texattribute[0] = 0 + texsetattribute(0,0) elseif how == true or how == 1 then local hash = "feature > " .. parent local done = cache[hash] if trace_features and done then report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]]) end - texattribute[0] = done or 0 + texsetattribute(0,done or 0) else local full = parent .. how .. name local hash = "feature > " .. full @@ -1696,7 +1707,7 @@ function commands.feature(how,parent,name,font) -- 0/1 test temporary for testin report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]]) end end - texattribute[0] = done + texsetattribute(0,done) end end @@ -1823,7 +1834,7 @@ local function analyzeprocessor(head,font,attr) end registerotffeature { -- adapts - name = "analyze", + name = "analyze", processors = { node = analyzeprocessor, } diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua index 89d5927d4..3d78b0a3c 100644 --- a/tex/context/base/font-ext.lua +++ b/tex/context/base/font-ext.lua @@ -469,7 +469,7 @@ end registerotffeature { name = "protrusion", - description = "shift characters into the left and or right margin", + description = "l/r margin character protrusion", initializers = { base = initializeprotrusion, node = initializeprotrusion, diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua index 6332f40b0..1b2ac0009 100644 --- a/tex/context/base/font-gds.lua +++ b/tex/context/base/font-gds.lua @@ -18,6 +18,7 @@ local trace_goodies = false trackers.register("fonts.goodies", function(v) local report_goodies = logs.reporter("fonts","goodies") local allocate = utilities.storage.allocate +local setmetatableindex = table.setmetatableindex local otf = fonts.handlers.otf local afm = fonts.handlers.afm @@ -43,6 +44,10 @@ local addotffeature = otf.enhancers.addfeature local findfile = resolvers.findfile +local glyph_code = nodes.nodecodes.glyph + +local traverse_id = nodes.traverse_id + function fontgoodies.report(what,trace,goodies) if trace_goodies or trace then local whatever = goodies[what] @@ -298,27 +303,104 @@ local function setcolorscheme(tfmdata,scheme) tfmdata.properties.colorscheme = false end -local fontdata = fonts.hashes.identifiers -local setnodecolor = nodes.tracers.colors.set -local traverse_id = node.traverse_id -local a_colorscheme = attributes.private('colorscheme') -local glyph = node.id("glyph") +local fontproperties = fonts.hashes.properties + +local a_colorscheme = attributes.private('colorscheme') +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] +-- if a then +-- local f = n.font +-- if f ~= lastfont then +-- lastscheme = fontproperties[f].colorscheme +-- lastfont = f +-- end +-- if lastscheme then +-- local sc = lastscheme[n.char] +-- if sc then +-- done = true +-- setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow +-- end +-- end +-- end +-- end +-- return head, done +-- end + +-- seldom used, mostly in manuals, so non critical .. anyhow, somewhat faster: + +-- function colorschemes.coloring(head) +-- local lastfont = nil +-- 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] +-- if a then +-- if a ~= lastattr then +-- lastattr = a +-- lastprefix = "colorscheme:" .. a .. ":" +-- end +-- local f = n.font +-- if f ~= lastfont then +-- lastfont = f +-- lastscheme = fontproperties[f].colorscheme +-- end +-- if lastscheme then +-- local sc = lastscheme[n.char] +-- if sc then +-- setnodecolor(n,lastprefix .. sc) -- slow +-- done = true +-- end +-- end +-- end +-- end +-- return head, done +-- end + +-- ok, in case we have hundreds of pages colored: + +local cache = { } -- this could be a weak table + +setmetatableindex(cache,function(t,a) + local v = { } + setmetatableindex(v,function(t,c) + local v = "colorscheme:" .. a .. ":" .. c + t[c] = v + return c + end) + t[a]= v + return v +end) function colorschemes.coloring(head) - local lastfont, lastscheme - local done = false - for n in traverse_id(glyph,head) do + local lastfont = nil + local lastattr = nil + local lastcache = nil + local lastscheme = nil + local done = nil + for n in traverse_id(glyph_code,head) do local a = n[a_colorscheme] if a then local f = n.font if f ~= lastfont then - lastscheme, lastfont = fontdata[f].properties.colorscheme, f + lastfont = f + lastscheme = fontproperties[f].colorscheme + end + if a ~= lastattr then + lastattr = a + lastcache = cache[a] end if lastscheme then local sc = lastscheme[n.char] if sc then + setnodecolor(n,lastcache[sc]) -- we could inline this one done = true - setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow end end end @@ -691,7 +773,7 @@ function fontgoodies.designsizes.register(name,size,specification) d.default = specification else if type(size) == "string" then - size = texsp(size) + size = texsp(size) -- hm end local ranges = d.ranges ranges[#ranges+1] = { size, specification } diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua index f99130279..7fa3297d4 100644 --- a/tex/context/base/font-nod.lua +++ b/tex/context/base/font-nod.lua @@ -41,10 +41,12 @@ tracers.characters = char_tracers local step_tracers = tracers.steppers or { } tracers.steppers = step_tracers -local copy_node_list = node.copy_list -local hpack_node_list = node.hpack -local free_node_list = node.flush_list -local traverse_nodes = node.traverse +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 @@ -232,7 +234,8 @@ end function step_tracers.glyphs(n,i) local c = collection[i] if c then - tex.box[n] = hpack_node_list(copy_node_list(c)) + local b = hpack_node_list(copy_node_list(c)) -- multiple arguments + texsetbox(n,b) end end diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua index 79fcf3fa2..295452cce 100644 --- a/tex/context/base/font-ota.lua +++ b/tex/context/base/font-ota.lua @@ -32,6 +32,7 @@ local a_state = attributes.private('state') 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 @@ -118,7 +119,7 @@ function analyzers.setstate(head,font) end elseif id == disc_code then -- always in the middle - current[a_state] = s_midi + current[a_state] = s_medi last = current else -- finish if first and first == last then @@ -179,7 +180,7 @@ end registerotffeature { name = "analyze", - description = "analysis of (for instance) character classes", + description = "analysis of character classes", default = true, initializers = { node = analyzeinitializer, diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index e0cb9acbc..dbec53ca3 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -530,7 +530,7 @@ local function multiple_glyphs(head,start,multiple) -- marks ? end function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence) - local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue + 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 @@ -648,7 +648,7 @@ function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence 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 + 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 diff --git a/tex/context/base/font-otx.lua b/tex/context/base/font-otx.lua index 5c41ad66f..e3f680c22 100644 --- a/tex/context/base/font-otx.lua +++ b/tex/context/base/font-otx.lua @@ -32,6 +32,7 @@ local a_state = attributes.private('state') 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 @@ -123,7 +124,7 @@ function analyzers.setstate(head,font) end elseif id == disc_code then -- always in the middle - current[a_state] = s_midi + current[a_state] = s_medi last = current else -- finish if first and first == last then diff --git a/tex/context/base/font-pre.mkiv b/tex/context/base/font-pre.mkiv index ef3694c2b..919a40805 100644 --- a/tex/context/base/font-pre.mkiv +++ b/tex/context/base/font-pre.mkiv @@ -72,28 +72,38 @@ [mode=none, features=no] -\definefontfeature % might move - [arabic] - [mode=node,language=dflt,script=arab,ccmp=yes, +\definefontfeature + [semetic-complete] + [mode=node,analyze=yes,language=dflt,ccmp=yes, init=yes,medi=yes,fina=yes,isol=yes, - liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes, - mark=yes,mkmk=yes,kern=yes,curs=yes] + mark=yes,mkmk=yes,kern=yes,curs=yes, + liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes] + +\definefontfeature + [semetic-simple] + [mode=node,analyze=yes,language=dflt,ccmp=yes, + init=yes,medi=yes,fina=yes,isol=yes, + mark=yes,mkmk=yes,kern=yes,curs=yes, + rlig=yes,calt=yes] \definefontfeature - [hebrew] [arabic] + [semetic-complete] + [script=arab] + +\definefontfeature + [hebrew] + [semetic-complete] [script=hebr] -\definefontfeature % might move +\definefontfeature [simplearabic] - [mode=node,language=dflt,script=arab, - init=yes,medi=yes,fina=yes, - rlig=yes,calt=yes, - mark=yes,mkmk=yes,curs=yes] + [semetic-simple] + [script=arab] \definefontfeature [simplehebrew] - [simplearabic] + [semetic-simple] [script=hebr] % \definefont [DevaOne] [file:chandas.ttf*devanagari-one at 12pt] @@ -195,6 +205,13 @@ [missing] [missing=yes] +%D Nice to have too: + +\definefontfeature + [quality] + [expansion=quality, + protrusion=quality] + %D We define some colors that are used in tracing (for instance \OPENTYPE\ %D features). We cannot yet inherit because no colors are predefined. diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index eb420e5be..7e62771a3 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -1722,3 +1722,49 @@ function names.resolvespec(askedname,sub) -- overloads previous definition report_names("unresolved: %s",askedname) end end + +-- We could generate typescripts with designsize info from the name database but +-- it's not worth the trouble as font names remain a mess: for instance how do we +-- idenfity a font? Names, families, subfamilies or whatever snippet can contain +-- a number related to the design size and so we end up with fuzzy logic again. So, +-- instead it's easier to make a few goody files. +-- +-- local hash = { } +-- +-- for i=1,#specifications do +-- local s = specifications[i] +-- local min = s.minsize +-- local max = s.maxsize +-- if min ~= 0 or max ~= 0 then +-- -- the usual name mess: +-- -- antykwa has modifiers so we need to take these into account, otherwise we get weird combinations +-- -- ebgaramond has modifiers with the size encoded, so we need to strip this in order to recognized similar styles +-- -- lm has 'slanted appended in some names so how to choose that one +-- -- +-- local modifier = string.gsub(s.modifiers or "normal","%d","") +-- -- print funny modifier +-- local instance = string.formatters["%s-%s-%s-%s-%s-%s"](s.familyname,s.width,s.style,s.weight,s.variant,modifier) +-- local h = hash[instance] +-- if not h then +-- h = { } +-- hash[instance] = h +-- end +-- size = string.formatters["%0.1fpt"]((min)/10) +-- h[size] = s.filename +-- end +-- end +-- +-- local newhash = { } +-- +-- for k, v in next, hash do +-- if next(v,next(v)) then +-- -- local instance = string.match(k,"(.+)%-.+%-.+%-.+$") +-- local instance = string.match(k,"(.+)%-.+%-.+$") +-- local instance = string.gsub(instance,"%-normal$","") +-- if not newhash[instance] then +-- newhash[instance] = v +-- end +-- end +-- end +-- +-- inspect(newhash) diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua index be1b7f45a..4f9d7fd92 100644 --- a/tex/context/base/grph-inc.lua +++ b/tex/context/base/grph-inc.lua @@ -38,7 +38,6 @@ run TeX code from within Lua. Some more functionality will move to Lua. ]]-- local format, lower, find, match, gsub, gmatch = string.format, string.lower, string.find, string.match, string.gsub, string.gmatch -local texbox = tex.box local contains = table.contains local concat, insert, remove = table.concat, table.insert, table.remove local todimen = string.todimen @@ -57,6 +56,11 @@ local replacetemplate = utilities.templates.replace local images = img +local texgetbox = tex.getbox +local texsetbox = tex.setbox + +local hpack = node.hpack + local context = context local variables = interfaces.variables @@ -975,7 +979,7 @@ function figures.done(data) figures.nofprocessed = figures.nofprocessed + 1 data = data or callstack[#callstack] or lastfiguredata local dr, du, ds, nr = data.request, data.used, data.status, figures.boxnumber - local box = texbox[nr] + local box = texgetbox(nr) ds.width = box.width ds.height = box.height ds.xscale = ds.width /(du.width or 1) @@ -987,7 +991,7 @@ end function figures.dummy(data) data = data or callstack[#callstack] or lastfiguredata local dr, du, nr = data.request, data.used, figures.boxnumber - local box = node.hpack(node.new("hlist")) -- we need to set the dir (luatex 0.60 buglet) + local box = hpack(node.new("hlist")) -- we need to set the dir (luatex 0.60 buglet) du.width = du.width or figures.defaultwidth du.height = du.height or figures.defaultheight du.depth = du.depth or figures.defaultdepth @@ -995,7 +999,7 @@ function figures.dummy(data) box.width = du.width box.height = du.height box.depth = du.depth - texbox[nr] = box -- hm, should be global (to be checked for consistency) + texsetbox(nr,box) -- hm, should be global (to be checked for consistency) end -- -- -- generic -- -- -- @@ -1096,10 +1100,10 @@ function includers.generic(data) if figure then local nr = figures.boxnumber -- it looks like we have a leak in attributes here .. todo - local box = node.hpack(images.node(figure)) -- images.node(figure) not longer valid + local box = hpack(images.node(figure)) -- images.node(figure) not longer valid indexed[figure.index] = figure box.width, box.height, box.depth = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet) - texbox[nr] = box + texsetbox(nr,box) ds.objectnumber = figure.objnum context.relocateexternalfigure() end diff --git a/tex/context/base/grph-inc.mkiv b/tex/context/base/grph-inc.mkiv index 8557bbb0b..4e2f8da93 100644 --- a/tex/context/base/grph-inc.mkiv +++ b/tex/context/base/grph-inc.mkiv @@ -297,11 +297,12 @@ % \edef\p_width {\externalfigureparameter\c!width}% \edef\p_height{\externalfigureparameter\c!height}% + \edef\p_label {\externalfigureparameter\c!label}% % \dostarttagged\t!image\empty \ctxlua{figures.push { name = "\p_grph_include_name", - label = "\p_grph_include_label", + label = "\ifx\p_label\empty\p_grph_include_label\else\p_label\fi", page = "\externalfigureparameter\c!page", size = "\externalfigureparameter\c!size", object = "\externalfigureparameter\c!object", diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua index a64ee8656..ebb2b39f4 100644 --- a/tex/context/base/l-file.lua +++ b/tex/context/base/l-file.lua @@ -368,11 +368,14 @@ function file.joinpath(tab,separator) -- table return tab and concat(tab,separator or io.pathseparator) -- can have trailing // end +local someslash = S("\\/") local stripper = Cs(P(fwslash)^0/"" * reslasher) -local isnetwork = fwslash * fwslash * (1-fwslash) + (1-fwslash-colon)^1 * colon +local isnetwork = someslash * someslash * (1-someslash) + + (1-fwslash-colon)^1 * colon local isroot = fwslash^1 * -1 local hasroot = fwslash^1 +local reslasher = lpeg.replacer(S("\\/"),"/") local deslasher = lpeg.replacer(S("\\/")^1,"/") -- If we have a network or prefix then there is a change that we end up with two @@ -386,8 +389,13 @@ function file.join(...) local lst = { ... } local one = lst[1] if lpegmatch(isnetwork,one) then + local one = lpegmatch(reslasher,one) local two = lpegmatch(deslasher,concat(lst,"/",2)) - return one .. "/" .. two + if lpegmatch(hasroot,two) then + return one .. two + else + return one .. "/" .. two + end elseif lpegmatch(isroot,one) then local two = lpegmatch(deslasher,concat(lst,"/",2)) if lpegmatch(hasroot,two) then @@ -412,6 +420,8 @@ end -- print(file.join("http://a","/y")) -- print(file.join("http:///a","/y")) -- print(file.join("//nas-1","/y")) +-- print(file.join("//nas-1/a/b/c","/y")) +-- print(file.join("\\\\nas-1\\a\\b\\c","\\y")) -- The previous one fails on "a.b/c" so Taco came up with a split based -- variant. After some skyping we got it sort of compatible with the old @@ -421,9 +431,14 @@ end -- finds were replaced by lpegs. local drivespec = R("az","AZ")^1 * colon -local anchors = fwslash + drivespec -local untouched = periods + (1-period)^1 * P(-1) -local splitstarter = (Cs(drivespec * (bwslash/"/" + fwslash)^0) + Cc(false)) * Ct(lpeg.splitat(S("/\\")^1)) +local anchors = fwslash + + drivespec +local untouched = periods + + (1-period)^1 * P(-1) +local mswindrive = Cs(drivespec * (bwslash/"/" + fwslash)^0) +local mswinuncpath = (bwslash + fwslash) * (bwslash + fwslash) * Cc("//") +local splitstarter = (mswindrive + mswinuncpath + Cc(false)) + * Ct(lpeg.splitat(S("/\\")^1)) local absolute = fwslash function file.collapsepath(str,anchor) -- anchor: false|nil, true, "." @@ -490,6 +505,7 @@ end -- test("a/./b/..") test("a/aa/../b/bb") test("a/.././././b/..") test("a/./././b/..") -- test("a/b/c/../..") test("./a/b/c/../..") test("a/b/c/../..") -- test("./a") +-- test([[\\a.b.c\d\e]]) local validchars = R("az","09","AZ","--","..") local pattern_a = lpeg.replacer(1-validchars) diff --git a/tex/context/base/l-io.lua b/tex/context/base/l-io.lua index 06e1fb5ef..e3a443be8 100644 --- a/tex/context/base/l-io.lua +++ b/tex/context/base/l-io.lua @@ -35,6 +35,7 @@ local function readall(f) return f:read('*all') else local done = f:seek("set",0) + local step if size < 1024*1024 then step = 1024 * 1024 elseif size > 16*1024*1024 then diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua index 7be86d38f..b33df96b7 100644 --- a/tex/context/base/l-lpeg.lua +++ b/tex/context/base/l-lpeg.lua @@ -13,6 +13,19 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +-- The latest lpeg doesn't have print any more, and even the new ones are not +-- available by default (only when debug mode is enabled), which is a pitty as +-- as it helps bailign down bottlenecks. Performance seems comparable, although +-- +-- local p = lpeg.C(lpeg.P(1)^0 * lpeg.P(-1)) +-- local a = string.rep("123",10) +-- lpeg.match(p,a) +-- +-- is nearly 20% slower and also still suboptimal (i.e. a match that runs from +-- begin to end, one of the cases where string matchers win). + +if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end + -- tracing (only used when we encounter a problem in integration of lpeg in luatex) -- some code will move to unicode and string @@ -212,7 +225,7 @@ patterns.propername = (uppercase + lowercase + underscore) * (uppercase + low patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1 patterns.beginline = #(1-newline) -patterns.longtostring = Cs(whitespace^0/"" * nonwhitespace^0 * ((whitespace^0/" " * (patterns.quoted + nonwhitespace)^1)^0)) +patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^1 + whitespace^1/"" * (P(-1) + Cc(" ")))^0)) local function anywhere(pattern) --slightly adapted from website return P { P(pattern) + 1 * V(1) } diff --git a/tex/context/base/l-pdfview.lua b/tex/context/base/l-pdfview.lua index fc3875ef4..6302fd6f6 100644 --- a/tex/context/base/l-pdfview.lua +++ b/tex/context/base/l-pdfview.lua @@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['l-pdfview'] = { license = "see context related readme files" } +-- Todo: add options in cnf file + -- Todo: figure out pdfopen/pdfclose on linux. Calling e.g. okular directly -- doesn't work in linux when issued from scite as it blocks the editor (no -- & possible or so). Unfortunately pdfopen keeps changing with not keeping @@ -15,66 +17,107 @@ if not modules then modules = { } end modules ['l-pdfview'] = { local format, concat = string.format, table.concat +local report = logs.reporter("pdfview") +local replace = utilities.templates.replace + pdfview = pdfview or { } -local opencalls, closecalls, allcalls, runner +local opencalls -- a table with templates that open a given pdf document +local closecalls -- a table with templates that close a given pdf document +local allcalls -- a table with templates that close all open pdf documents +local runner -- runner function +local expander -- filename cleanup function --- this might become template based +-- maybe spawn/execute spec in calls if os.type == "windows" then + -- os.setenv("path",os.getenv("path") .. ";" .. "c:/data/system/pdf-xchange") + -- os.setenv("path",os.getenv("path") .. ";" .. "c:/data/system/sumatrapdf") + + -- start is more flexible as it locates binaries in more places and doesn't lock + opencalls = { - ['default'] = "pdfopen --rxi --file", - ['acrobat'] = "pdfopen --rxi --file", - ['fullacrobat'] = "pdfopen --axi --file", - ['okular'] = 'start "test" "c:/data/system/kde/bin/okular.exe" --unique', -- todo! - ['sumatra'] = 'start "test" "c:/data/system/sumatrapdf/sumatrapdf.exe" -reuse-instance', - ['okular'] = 'start "test" "okular.exe" --unique', - ['sumatra'] = 'start "test" "sumatrapdf.exe" -reuse-instance -bg-color 0xCCCCCC', + ['default'] = [[pdfopen --rxi --file "%filename%"]], + ['acrobat'] = [[pdfopen --rxi --file "%filename%"]], + ['fullacrobat'] = [[pdfopen --axi --file "%filename%"]], + ['okular'] = [[start "test" okular.exe --unique "%filename%"]], + ['pdfxcview'] = [[start "test" pdfxcview.exe /A "nolock=yes=OpenParameters" "%filename%"]], + ['sumatra'] = [[start "test" sumatrapdf.exe -reuse-instance -bg-color 0xCCCCCC "%filename%"]], + ['auto'] = [[start "%filename%"]], } closecalls= { - ['default'] = "pdfclose --file", - ['acrobat'] = "pdfclose --file", - ['okular'] = false, - ['sumatra'] = false, + ['default'] = [[pdfclose --file "%filename%"]], + ['acrobat'] = [[pdfclose --file "%filename%"]], + ['okular'] = false, + ['pdfxcview'] = false, -- [[pdfxcview.exe /close:discard "%filename%"]], + ['sumatra'] = false, + ['auto'] = false, } allcalls = { - ['default'] = "pdfclose --all", - ['acrobat'] = "pdfclose --all", - ['okular'] = false, - ['sumatra'] = false, + ['default'] = [[pdfclose --all]], + ['acrobat'] = [[pdfclose --all]], + ['okular'] = false, + ['pdfxcview'] = false, + ['sumatra'] = false, + ['auto'] = false, } - pdfview.method = "acrobat" -- no longer useful due to green pop up line and clasing reader/full + pdfview.method = "acrobat" -- no longer useful due to green pop up line and clashing reader/full + -- pdfview.method = "pdfxcview" pdfview.method = "sumatra" - runner = function(cmd) - os.execute(cmd) -- .. " > /null" + runner = function(template,variables) + local cmd = replace(template,variables) + -- cmd = cmd .. " > /null" + report("command: %s",cmd) + os.execute(cmd) + end + + expander = function(name) + -- We need to avoid issues with chdir to UNC paths and therefore expand + -- the path when we're current. (We could use one of the helpers instead) + if file.pathpart(name) == "" then + return file.collapsepath(file.join(lfs.currentdir(),name)) + else + return name + end end else opencalls = { - ['default'] = "pdfopen", -- we could pass the default here - ['okular'] = 'okular --unique', - ['sumatra'] = 'wine "sumatrapdf.exe" -reuse-instance -bg-color 0xCCCCCC', + ['default'] = [[pdfopen "%filename%"]], + ['okular'] = [[okular --unique "%filename%"]], + ['sumatra'] = [[wine "sumatrapdf.exe" -reuse-instance -bg-color 0xCCCCCC "%filename%"]], + ['pdfxcview'] = [[wine "pdfxcview.exe" /A "nolock=yes=OpenParameters" "%filename%"]], + ['auto'] = [[open "%filename%"]], } closecalls= { - ['default'] = "pdfclose --file", - ['okular'] = false, - ['sumatra'] = false, + ['default'] = [[pdfclose --file "%filename%"]], + ['okular'] = false, + ['sumatra'] = false, + ['auto'] = false, } allcalls = { - ['default'] = "pdfclose --all", - ['okular'] = false, - ['sumatra'] = false, + ['default'] = [[pdfclose --all]], + ['okular'] = false, + ['sumatra'] = false, + ['auto'] = false, } pdfview.method = "okular" - pdfview.method = "sumatra" + pdfview.method = "sumatra" -- faster and more complete + + runner = function(template,variables) + local cmd = replace(template,variables) + cmd = cmd .. " 1>/dev/null 2>/dev/null &" + report("command: %s",cmd) + os.execute(cmd) + end - runner = function(cmd) - os.execute(cmd .. " 1>/dev/null 2>/dev/null &") + expander = function(name) + return name end end @@ -97,8 +140,6 @@ function pdfview.status() return format("pdfview methods: %s, current method: %s (directives_pdfview_method)",pdfview.methods(),tostring(pdfview.method)) end --- local openedfiles = { } - local function fullname(name) return file.addsuffix(name,"pdf") end @@ -108,10 +149,9 @@ function pdfview.open(...) if opencall then local t = { ... } for i=1,#t do - local name = fullname(t[i]) + local name = expander(fullname(t[i])) if io.exists(name) then - runner(format('%s "%s"', opencall, name)) - -- openedfiles[name] = true + runner(opencall,{ filename = name }) end end end @@ -122,14 +162,10 @@ function pdfview.close(...) if closecall then local t = { ... } for i=1,#t do - local name = fullname(t[i]) - -- if openedfiles[name] then - runner(format('%s "%s"', closecall, name)) - -- openedfiles[name] = nil - -- else - -- pdfview.closeall() - -- break - -- end + local name = expander(fullname(t[i])) + if io.exists(name) then + replace(closecall,{ filename = name }) + end end end end @@ -137,13 +173,8 @@ end function pdfview.closeall() local allcall = allcalls[pdfview.method] if allcall then - runner(format('%s', allcall)) + runner(allcall) end - -- openedfiles = { } end ---~ pdfview.open("t:/document/show-exa.pdf") ---~ os.sleep(3) ---~ pdfview.close("t:/document/show-exa.pdf") - return pdfview diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua index 4f6b9b4ed..11cb66bef 100644 --- a/tex/context/base/l-table.lua +++ b/tex/context/base/l-table.lua @@ -346,6 +346,7 @@ local noquotes, hexify, handle, reduce, compact, inline, functions local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while', + 'NaN', 'goto', } local function simple_table(t) diff --git a/tex/context/base/lang-rep.lua b/tex/context/base/lang-rep.lua new file mode 100644 index 000000000..16cd93e4a --- /dev/null +++ b/tex/context/base/lang-rep.lua @@ -0,0 +1,198 @@ +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 + +local function process(namespace,attribute,head) + -- we could avoid this wrapper and use: + -- local function process(head) + local current = head + local done = false + while current do + if current.id == glyph_code then + -- local a = current[a_replacements] + local a = current[attribute] + 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 + +replacements.handler = nodes.installattributehandler { + name = "replacements", + namespace = replacements, + processor = process, +} + +-- 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 06a2311a6..bf066fc09 100644 --- a/tex/context/base/lang-wrd.lua +++ b/tex/context/base/lang-wrd.lua @@ -334,17 +334,17 @@ end -- for the moment we hook it into the attribute handler ---~ languagehacks = { } +-- languagehacks = { } ---~ function languagehacks.process(namespace,attribute,head) ---~ return languages.check(head) ---~ end +-- function languagehacks.process(namespace,attribute,head) +-- return languages.check(head) +-- end ---~ chars.plugins[chars.plugins+1] = { ---~ name = "language", ---~ namespace = languagehacks, ---~ processor = languagehacks.process ---~ } +-- chars.plugins[chars.plugins+1] = { +-- name = "language", +-- namespace = languagehacks, +-- processor = languagehacks.process +-- } -- interface diff --git a/tex/context/base/layo-ini.lua b/tex/context/base/layo-ini.lua index 56ced2c0b..d35d7ef69 100644 --- a/tex/context/base/layo-ini.lua +++ b/tex/context/base/layo-ini.lua @@ -6,17 +6,10 @@ if not modules then modules = { } end modules ['layo-ini'] = { license = "see context related readme files" } --- We need to share information between the TeX and Lua end --- about the typographical model. This happens here. --- --- Code might move. +-- We need to share information between the TeX and Lua end about the typographical +-- model. This happens here. This code might move. --- conditionals.layoutisdoublesided --- conditionals.layoutissinglesided --- texcount.pagenoshift --- texcount.realpageno - -local texcount = tex.count +local texgetcount = tex.getcount local conditionals = tex.conditionals layouts = { @@ -33,14 +26,14 @@ function status.leftorrightpagection(left,right) return left, right elseif conditionals.layoutissinglesided then return left, right - elseif texcount.pagenoshift % 2 == 0 then - if texcount.realpageno % 2 == 0 then + elseif texgetcount("pagenoshift") % 2 == 0 then + if texgetcount("realpageno") % 2 == 0 then return right, left else return left, right end else - if texcount.realpageno % 2 == 0 then + if texgetcount("realpageno") % 2 == 0 then return left, right else return right, left @@ -53,9 +46,9 @@ function status.isleftpage() return false elseif conditionals.layoutissinglesided then return false - elseif texcount.pagenoshift % 2 == 0 then - return texcount.realpageno % 2 == 0 + elseif texgetcount("pagenoshift") % 2 == 0 then + return texgetcount("realpageno") % 2 == 0 else - return not texcount.realpageno % 2 == 0 + return not texgetcount("realpageno") % 2 == 0 end end diff --git a/tex/context/base/lpdf-ano.lua b/tex/context/base/lpdf-ano.lua index 990e87abd..3f0e718b3 100644 --- a/tex/context/base/lpdf-ano.lua +++ b/tex/context/base/lpdf-ano.lua @@ -12,7 +12,6 @@ if not modules then modules = { } end modules ['lpdf-ano'] = { local next, tostring = next, tostring local rep, format = string.rep, string.format -local texcount = tex.count local lpegmatch = lpeg.match local formatters = string.formatters @@ -52,6 +51,8 @@ local pdfannotation_node = nodepool.pdfannotation local pdfdestination_node = nodepool.pdfdestination local latelua_node = nodepool.latelua +local texgetcount = tex.getcount + local pdfdictionary = lpdf.dictionary local pdfarray = lpdf.array local pdfreference = lpdf.reference @@ -512,7 +513,7 @@ end function specials.deltapage(var,actions) local p = tonumber(var.operation) if p then - p = references.checkedrealpage(p + texcount.realpageno) + p = references.checkedrealpage(p + texgetcount("realpageno")) return link(nil,nil,nil,p,actions) end end diff --git a/tex/context/base/lpdf-fmt.lua b/tex/context/base/lpdf-fmt.lua index 94c005f65..b444f03c3 100644 --- a/tex/context/base/lpdf-fmt.lua +++ b/tex/context/base/lpdf-fmt.lua @@ -36,7 +36,7 @@ local pdfstring = lpdf.string local pdfverbose = lpdf.verbose local pdfflushstreamfileobject = lpdf.flushstreamfileobject -local texset = tex.set -- we could make tex.setglobal +local texset = tex.set local addtoinfo = lpdf.addtoinfo local injectxmpinfo = lpdf.injectxmpinfo diff --git a/tex/context/base/lpdf-nod.lua b/tex/context/base/lpdf-nod.lua index 60d3fcd5b..d90ca1612 100644 --- a/tex/context/base/lpdf-nod.lua +++ b/tex/context/base/lpdf-nod.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['lpdf-nod'] = { license = "see context related readme files" } -local format = string.format +local formatters = string.formatters local copy_node = node.copy local new_node = node.new @@ -59,7 +59,7 @@ end function nodepool.pdfsetmatrix(rx,sx,sy,ry,tx,ty) local t = copy_node(pdfsetmatrix) - t.data = format("%s %s %s %s",rx or 0,sx or 0,sy or 0,ry or 0) -- todo: tx ty + 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 @@ -127,8 +127,12 @@ function nodepool.pdfdestination(w,h,d,name,view,n) 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 + s.next = m + m.next = t + t.next = r + m.prev = s + t.prev = m + 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 8cdb5f6a4..29ffcd207 100644 --- a/tex/context/base/lpdf-tag.lua +++ b/tex/context/base/lpdf-tag.lua @@ -32,6 +32,8 @@ local pdfflushobject = lpdf.flushobject local pdfreserveobject = lpdf.reserveobject local pdfpagereference = lpdf.pagereference +local texgetcount = tex.getcount + local nodepool = nodes.pool local pdfliteral = nodepool.pdfliteral @@ -69,10 +71,9 @@ local dashsplitter = lpeg.splitat("-") local add_ids = false -- true - ---~ function codeinjections.maptag(original,target,kind) ---~ mapping[original] = { target, kind or "inline" } ---~ end +-- function codeinjections.maptag(original,target,kind) +-- mapping[original] = { target, kind or "inline" } +-- end local function finishstructure() if #structure_kids > 0 then @@ -133,7 +134,7 @@ local pdf_struct_element = pdfconstant("StructElem") local function initializepage() index = 0 - pagenum = tex.count.realpageno + pagenum = texgetcount("realpageno") pageref = pdfreference(pdfpagereference(pagenum)) list = pdfarray() tree[pagenum] = list -- we can flush after done, todo diff --git a/tex/context/base/lpdf-wid.lua b/tex/context/base/lpdf-wid.lua index 5bb809327..30bd3572b 100644 --- a/tex/context/base/lpdf-wid.lua +++ b/tex/context/base/lpdf-wid.lua @@ -8,7 +8,6 @@ if not modules then modules = { } end modules ['lpdf-wid'] = { local gmatch, gsub, find, lower, format = string.gmatch, string.gsub, string.find, string.lower, string.format local stripstring = string.strip -local texbox, texcount = tex.box, tex.count local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash @@ -20,6 +19,8 @@ local lpdf = lpdf local nodes = nodes local context = context +local texgetcount = tex.getcount + local nodeinjections = backends.pdf.nodeinjections local codeinjections = backends.pdf.codeinjections local registrations = backends.pdf.registrations @@ -490,8 +491,8 @@ end local function insertrenderingwindow(specification) local label = specification.label ---~ local openpage = specification.openpage ---~ local closepage = specification.closepage + -- local openpage = specification.openpage + -- local closepage = specification.closepage if specification.option == v_auto then if openpageaction then -- \handlereferenceactions{\v!StartRendering{#2}} @@ -507,7 +508,7 @@ local function insertrenderingwindow(specification) PC = (closepage and lpdf.action(closepage)) or nil, } end - local page = tonumber(specification.page) or texcount.realpageno -- todo + local page = tonumber(specification.page) or texgetcount("realpageno") -- todo local r = mu[label] or pdfreserveannotation() -- why the reserve here? local a = pdfdictionary { S = pdfconstant("Rendition"), @@ -539,34 +540,34 @@ local function insertrendering(specification) if not mf[label] then local filename = specification.filename local isurl = find(filename,"://") - --~ local start = pdfdictionary { - --~ Type = pdfconstant("MediaOffset"), - --~ S = pdfconstant("T"), -- time - --~ T = pdfdictionary { -- time - --~ Type = pdfconstant("Timespan"), - --~ S = pdfconstant("S"), - --~ V = 3, -- time in seconds - --~ }, - --~ } - --~ local start = pdfdictionary { - --~ Type = pdfconstant("MediaOffset"), - --~ S = pdfconstant("F"), -- frame - --~ F = 100 -- framenumber - --~ } - --~ local start = pdfdictionary { - --~ Type = pdfconstant("MediaOffset"), - --~ S = pdfconstant("M"), -- mark - --~ M = "somemark", - --~ } - --~ local parameters = pdfdictionary { - --~ BE = pdfdictionary { - --~ B = start, - --~ } - --~ } - --~ local parameters = pdfdictionary { - --~ Type = pdfconstant(MediaPermissions), - --~ TF = pdfstring("TEMPALWAYS") }, -- TEMPNEVER TEMPEXTRACT TEMPACCESS TEMPALWAYS - --~ } + -- local start = pdfdictionary { + -- Type = pdfconstant("MediaOffset"), + -- S = pdfconstant("T"), -- time + -- T = pdfdictionary { -- time + -- Type = pdfconstant("Timespan"), + -- S = pdfconstant("S"), + -- V = 3, -- time in seconds + -- }, + -- } + -- local start = pdfdictionary { + -- Type = pdfconstant("MediaOffset"), + -- S = pdfconstant("F"), -- frame + -- F = 100 -- framenumber + -- } + -- local start = pdfdictionary { + -- Type = pdfconstant("MediaOffset"), + -- S = pdfconstant("M"), -- mark + -- M = "somemark", + -- } + -- local parameters = pdfdictionary { + -- BE = pdfdictionary { + -- B = start, + -- } + -- } + -- local parameters = pdfdictionary { + -- Type = pdfconstant(MediaPermissions), + -- TF = pdfstring("TEMPALWAYS") }, -- TEMPNEVER TEMPEXTRACT TEMPACCESS TEMPALWAYS + -- } local descriptor = pdfdictionary { Type = pdfconstant("Filespec"), F = filename, diff --git a/tex/context/base/luat-env.lua b/tex/context/base/luat-env.lua index 8753972c6..5558e0303 100644 --- a/tex/context/base/luat-env.lua +++ b/tex/context/base/luat-env.lua @@ -20,6 +20,8 @@ local report_lua = logs.reporter("resolvers","lua") local luautilities = utilities.lua local luasuffixes = luautilities.suffixes +local texgettoks = tex and tex.gettoks + environment = environment or { } local environment = environment @@ -28,7 +30,7 @@ local environment = environment local mt = { __index = function(_,k) if k == "version" then - local version = tex.toks and tex.toks.contextversiontoks + local version = texgettoks and texgettoks("contextversiontoks") if version and version ~= "" then rawset(environment,"version",version) return version @@ -36,7 +38,7 @@ local mt = { return "unknown" end elseif k == "kind" then - local kind = tex.toks and tex.toks.contextkindtoks + local kind = texgettoks and texgettoks("contextkindtoks") if kind and kind ~= "" then rawset(environment,"kind",kind) return kind diff --git a/tex/context/base/luat-fio.lua b/tex/context/base/luat-fio.lua index d61c6f142..dcc183167 100644 --- a/tex/context/base/luat-fio.lua +++ b/tex/context/base/luat-fio.lua @@ -84,26 +84,6 @@ if not resolvers.instance then end -local report_system = logs.reporter("system","files") -local report_files = logs.reporter("used files") - -luatex.registerstopactions(function() - local foundintrees = resolvers.instance.foundintrees - if #foundintrees > 0 then - logs.pushtarget("logfile") - logs.newline() - report_system("start used files") - logs.newline() - for i=1,#foundintrees do - report_files("%4i: % T",i,foundintrees[i]) - end - logs.newline() - report_system("stop used files") - logs.newline() - logs.poptarget() - end -end) - statistics.register("resource resolver", function() local scandata = resolvers.scandata() return format("loadtime %s seconds, %s scans with scantime %s seconds, %s shared scans, %s found files, scanned paths: %s", diff --git a/tex/context/base/lxml-css.lua b/tex/context/base/lxml-css.lua index c5a85c2bd..5b389626c 100644 --- a/tex/context/base/lxml-css.lua +++ b/tex/context/base/lxml-css.lua @@ -30,8 +30,9 @@ if tex then local exheights = fonts.hashes.exheights local emwidths = fonts.hashes.emwidths + local texget = tex.get - percentage = function(s,pcf) return tonumber(s) * (pcf or tex.hsize) end + percentage = function(s,pcf) return tonumber(s) * (pcf or texget("hsize") end exheight = function(s,exf) return tonumber(s) * (exf or exheights[true]) end emwidth = function(s,emf) return tonumber(s) * (emf or emwidths[true]) end pixels = function(s,pxf) return tonumber(s) * (pxf or emwidths[true]/300) end @@ -109,17 +110,17 @@ css.padding = padding -- print(padding("0",pixel,hsize,exheight,emwidth)) --- local currentfont = font.current --- local texdimen = tex.dimen --- local hashes = fonts.hashes --- local quads = hashes.quads --- local xheights = hashes.xheights +-- local currentfont = font.current +-- local texget = tex.get +-- local hashes = fonts.hashes +-- local quads = hashes.quads +-- local xheights = hashes.xheights -- -- local function padding(str) -- local font = currentfont() -- local exheight = xheights[font] -- local emwidth = quads[font] --- local hsize = texdimen.hsize/100 +-- local hsize = texget("hsize")/100 -- local pixel = emwidth/100 -- return padding(str,pixel,hsize,exheight,emwidth) -- end diff --git a/tex/context/base/lxml-tab.lua b/tex/context/base/lxml-tab.lua index 9d2266886..3e10eb96d 100644 --- a/tex/context/base/lxml-tab.lua +++ b/tex/context/base/lxml-tab.lua @@ -34,7 +34,7 @@ as the current variant was written when <l n='lpeg'/> showed up and it's easier build tables in one go.</p> --ldx]]-- -lpeg.setmaxstack(1000) -- deeply nested xml files +if lpeg.setmaxstack then lpeg.setmaxstack(1000) end -- deeply nested xml files xml = xml or { } local xml = xml diff --git a/tex/context/base/m-nodechart.lua b/tex/context/base/m-nodechart.lua new file mode 100644 index 000000000..612b73767 --- /dev/null +++ b/tex/context/base/m-nodechart.lua @@ -0,0 +1,175 @@ +if not modules then modules = { } end modules ['m-nodechart'] = { + version = 1.001, + comment = "companion to m-nodechart.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local format = string.format +local points = number.nopts +local ptfactor = number.dimenfactors.pt + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes +local penaltycodes = nodes.penaltycodes +local gluecodes = nodes.gluecodes +local whatsitcodes = nodes.whatsitcodes + +moduledata.charts = moduledata.charts or { } +moduledata.charts.nodes = moduledata.charts.nodes or { } + +local formatters = { } + +-- subtype font char lang left right uchyph components xoffset yoffset width height depth + +function formatters.glyph(n,comment) + return format("\\doFLOWglyphnode{%s}{%s}{%s}{%s}{U+%05X}",comment,n.subtype,n.font,n.char,n.char) +end + +-- pre post replace + +function formatters.disc(n,comment) + return format("\\doFLOWdiscnode{%s}{%s}",comment,n.subtype) +end + +-- subtype kern + +function formatters.kern(n,comment) + -- return format("\\doFLOWkernnode{%s}{%s}{%s}",comment,kerncodes[n.subtype],points(n.kern)) + return format("\\doFLOWkernnode{%s}{%s}{%.4f}",comment,kerncodes[n.subtype],n.kern*ptfactor) +end + +-- subtype penalty + +function formatters.penalty(n,comment) + return format("\\doFLOWpenaltynode{%s}{%s}{%s}",comment,"penalty",n.penalty) +end + +-- subtype width leader spec (stretch shrink ... + +function formatters.glue(n,comment) + local s = n.spec + -- return format("\\doFLOWgluenode{%s}{%s}{%s}{%s}{%s}",comment,gluecodes[n.subtype],points(s.width),points(s.stretch),points(s.shrink)) + return format("\\doFLOWgluenode{%s}{%s}{%.4f}{%.4f}{%.4f}",comment,gluecodes[n.subtype],s.width*ptfactor,s.stretch*ptfactor,s.shrink*ptfactor) +end + +-- subtype width leader spec (stretch shrink ... + +function formatters.whatsit(n,comment) + local subtype = n.subtype + local whatsit = whatsitcodes[subtype] + if whatsit == "dir" or whatsit == "localpar" then + return format("\\doFLOWdirnode{%s}{%s}{%s}",comment,whatsit,n.dir) + else + return nodecodes[n.id] + end +end + +-- I will make a dedicated set of shapes for this. + +local shapes = { + glyph = "procedure", + disc = "procedure", + kern = "action", + penalty = "action", + glue = "action", +} + +local function flow_nodes_to_chart(specification) + local head = specification.head + local box = specification.box + local comment = specification.comment or "" + local x = specification.x or 1 + local y = specification.y or 0 + -- + if box then + box = tex.getbox(tonumber(box)) + head = box and box.list + end + -- + local current = head + -- + while current do + local nodecode = nodecodes[current.id] + local formatter = formatters[nodecode] + local shape = shapes[nodecode] + y = y + 1 + local next = current.next + commands.flow_start_cell { shape = { framecolor = "nodechart:" .. nodecode } } + commands.flow_set_name(tostring(current)) + commands.flow_set_location(x,y) + if shape then + commands.flow_set_shape(shape) + end + if formatter then + commands.flow_set_text("node",formatter(current,comment)) + else + commands.flow_set_text("node",nodecode) + end + if next then + commands.flow_set_connection("bt","",tostring(next)) + end + if nodecode == "glyph" then + local components = current.components + if components then + commands.flow_set_connection("rl","",tostring(components)) + commands.flow_stop_cell() + n = flow_nodes_to_chart { head = components, comment = "component",x = x+2, y = y-1 } + else + commands.flow_stop_cell() + end + elseif nodecode == "disc" then + local pre = current.pre + local pos = current.post + local rep = current.replace + if pre and not rep and not rep then + if pre then + commands.flow_set_connection("rl","",tostring(pre)) + end + commands.flow_stop_cell() + if pre then + n = flow_nodes_to_chart { head = pre, comment = "prebreak", x = x+1, y = y-1 } + end + else + if pre then + commands.flow_set_connection("+rl","",tostring(pre)) + end + if rep then + commands.flow_set_connection("rl","",tostring(rep)) + end + if pos then + commands.flow_set_connection("-rl","",tostring(pos)) + end + commands.flow_stop_cell() + if pre then + n = flow_nodes_to_chart{ head = pre, comment = "prebreak", x = x+1, y = y-2 } + end + if rep then + n = flow_nodes_to_chart{ head = rep, comment = "replacement", x = x+1, y = y-1 } + end + if pos then + n = flow_nodes_to_chart{ head = pos, comment = "postbreak", x = x+1, y = y } + end + end + elseif nodecode == "hlist" then + local list = current.list + if list then + commands.flow_set_connection("rl","",tostring(list)) + commands.flow_stop_cell() + n = flow_nodes_to_chart { head = list, comment = "list", x = x+2, y = y-1 } + else + commands.flow_stop_cell() + end + else + commands.flow_stop_cell() + end + current = next + end +end + +function moduledata.charts.nodes.chart(specification) + commands.flow_start_chart(specification.name) + flow_nodes_to_chart(specification) + commands.flow_stop_chart() +end diff --git a/tex/context/base/m-nodechart.mkvi b/tex/context/base/m-nodechart.mkvi index 359d598ce..c9d985850 100644 --- a/tex/context/base/m-nodechart.mkvi +++ b/tex/context/base/m-nodechart.mkvi @@ -1,154 +1,19 @@ -\usemodule[chart] +%D \module +%D [ file=m-nodechart, +%D version=2011.11.11, % nos sure when it started, needed for fonts-mkiv +%D title=\CONTEXT\ Modules, +%D subtitle=Node Visualization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] + +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. -\startluacode - -local format = string.format -local points = number.nopts -local ptfactor = number.dimenfactors.pt - -local nodecodes = nodes.nodecodes -local kerncodes = nodes.kerncodes -local penaltycodes = nodes.penaltycodes -local gluecodes = nodes.gluecodes -local whatsitcodes = nodes.whatsitcodes - -local formatters = { } - -function formatters.glyph(n,comment) - -- subtype font char lang left right uchyph components xoffset yoffset width height depth - return format("\\doFLOWglyphnode{%s}{%s}{%s}{%s}{U+%05X}",comment,n.subtype,n.font,n.char,n.char) -end - -function formatters.disc(n,comment) - -- pre post replace - return format("\\doFLOWdiscnode{%s}{%s}",comment,n.subtype) -end - -function formatters.kern(n,comment) - -- subtype kern - -- return format("\\doFLOWkernnode{%s}{%s}{%s}",comment,kerncodes[n.subtype],points(n.kern)) - return format("\\doFLOWkernnode{%s}{%s}{%.4f}",comment,kerncodes[n.subtype],n.kern*ptfactor) -end - -function formatters.penalty(n,comment) - -- subtype penalty - return format("\\doFLOWpenaltynode{%s}{%s}{%s}",comment,"penalty",n.penalty) -end - -function formatters.glue(n,comment) - -- subtype width leader spec (stretch shrink ... - local s = n.spec - -- return format("\\doFLOWgluenode{%s}{%s}{%s}{%s}{%s}",comment,gluecodes[n.subtype],points(s.width),points(s.stretch),points(s.shrink)) - return format("\\doFLOWgluenode{%s}{%s}{%.4f}{%.4f}{%.4f}",comment,gluecodes[n.subtype],s.width*ptfactor,s.stretch*ptfactor,s.shrink*ptfactor) -end - -function formatters.whatsit(n,comment) - -- subtype width leader spec (stretch shrink ... - local subtype = n.subtype - local whatsit = whatsitcodes[subtype] - if whatsit == "dir" or whatsit == "localpar" then - return format("\\doFLOWdirnode{%s}{%s}{%s}",comment,whatsit,n.dir) - else - return nodecodes[n.id] - end -end - -local shapes = { -- I will make a dedicated set of shapes for this. - glyph = "procedure", - disc = "procedure", - kern = "action", - penalty = "action", - glue = "action", -} - -local function flow_nodes_to_chart(head,comment,x,y,how) - local current = head - while current do - local nodecode = nodecodes[current.id] - local formatter = formatters[nodecode] - local shape = shapes[nodecode] - y = y + 1 - local next = current.next - commands.flow_start_cell { shape = { framecolor = "nodechart:" .. nodecode } } - commands.flow_set_name(tostring(current)) - commands.flow_set_location(x,y) - if shape then - commands.flow_set_shape(shape) - end - if formatter then - commands.flow_set_text("node",formatter(current,comment)) - else - commands.flow_set_text("node",nodecode) - end - if next then - commands.flow_set_connection("bt","",tostring(next)) - end - if nodecode == "glyph" then - local components = current.components - if components then - commands.flow_set_connection("rl","",tostring(components)) - commands.flow_stop_cell() - n = flow_nodes_to_chart(components,"component",x+2,y-1) - else - commands.flow_stop_cell() - end - elseif nodecode == "disc" then - local pre = current.pre - local pos = current.post - local rep = current.replace - if pre and not rep and not rep then - if pre then - commands.flow_set_connection("rl","",tostring(pre)) - end - commands.flow_stop_cell() - if pre then - n = flow_nodes_to_chart(pre,"prebreak",x+1,y-1) - end - else - if pre then - commands.flow_set_connection("+rl","",tostring(pre)) - end - if rep then - commands.flow_set_connection("rl","",tostring(rep)) - end - if pos then - commands.flow_set_connection("-rl","",tostring(pos)) - end - commands.flow_stop_cell() - if pre then - n = flow_nodes_to_chart(pre,"prebreak",x+1,y-2) - end - if rep then - n = flow_nodes_to_chart(rep,"replacement",x+1,y-1) - end - if pos then - n = flow_nodes_to_chart(pos,"postbreak",x+1,y) - end - end - elseif nodecode == "hlist" then - local list = current.list - if list then - commands.flow_set_connection("rl","",tostring(list)) - commands.flow_stop_cell() - n = flow_nodes_to_chart(list,"list",x+2,y-1) - else - commands.flow_stop_cell() - end - else - commands.flow_stop_cell() - end - current = next - end - return n -end - -function commands.flow_nodes_to_chart(name,head,max) - commands.flow_start_chart(name) - flow_nodes_to_chart(head,"",1,0) - commands.flow_stop_chart() -end - -\stopluacode +\registerctxluafile{m-nodechart}{1.001} + +\usemodule[chart] \unprotect @@ -200,17 +65,20 @@ end % this is a temporary interface ... we will have instances and optional settings -\unexpanded\def\boxtoFLOWchart#name#max#box% - {\ctxcommand{flow_nodes_to_chart("#name",tex.box[\number#box].list,\number#max)}} +\unexpanded\def\boxtoFLOWchart[#name]#box% + {\ctxlua{moduledata.charts.nodes.chart { + name = "#name", + box = \number#box, + }}} -\unexpanded\def\nextboxtoFLOWchart#name#max% - {\dowithnextbox{\boxtoFLOWchart{#name}{#max}\nextbox}} +\unexpanded\def\nextboxtoFLOWchart[#name]% + {\dowithnextbox{\boxtoFLOWchart[#name]\nextbox}} -\unexpanded\def\hboxtoFLOWchart#name#max% - {\nextboxtoFLOWchart{#name}{#max}\hbox} +\unexpanded\def\hboxtoFLOWchart[#name]% + {\nextboxtoFLOWchart[#name]\hbox} -\unexpanded\def\vboxtoFLOWchart#name#max% - {\nextboxtoFLOWchart{#name}{#max}\vbox} +\unexpanded\def\vboxtoFLOWchart[#name]% + {\nextboxtoFLOWchart[#name]\vbox} \protect @@ -224,7 +92,7 @@ end \startTEXpage[offset=10pt] - \hboxtoFLOWchart{dummy}{3}{an affil\discretionary{-}{-}{!}iation} + \hboxtoFLOWchart[dummy]{an affil\discretionary{-}{-}{!}iation} \FLOWchart[dummy][width=14em,height=3em,dx=1em,dy=.75em,hcompact=yes] @@ -232,7 +100,7 @@ end \startTEXpage[offset=10pt] - \hboxtoFLOWchart{dummy}{3}{an affiliation} + \hboxtoFLOWchart[dummy]{an affiliation} \FLOWchart[dummy][width=14em,height=3em,dx=.5em,dy=.75em,hcompact=yes] @@ -240,7 +108,7 @@ end \startTEXpage[offset=10pt] - \hboxtoFLOWchart{dummy}{3}{\nl effe fijn fietsen} + \hboxtoFLOWchart[dummy]{\nl effe fijn fietsen} \FLOWchart[dummy][width=14em,height=3em,dx=.5em,dy=.75em,hcompact=yes] @@ -248,7 +116,7 @@ end \startTEXpage[offset=10pt] - \hboxtoFLOWchart{dummy}{3}{\righttoleft t\kern 1pt est} + \hboxtoFLOWchart[dummy]{\righttoleft t\kern 1pt est} \FLOWchart[dummy][width=14em,height=3em,dx=.5em,dy=.75em,hcompact=yes] diff --git a/tex/context/base/m-r.tex b/tex/context/base/m-r.mkii index ac895905c..c2cb7ba88 100644 --- a/tex/context/base/m-r.tex +++ b/tex/context/base/m-r.mkii @@ -30,7 +30,7 @@ \newcounter\nofRfiles -\def\Rfile{\TEXbufferfile{\Rbufferprefix\nofRfiles}}% +\def\Rfile{\TEXbufferfile{\Rbufferprefix\nofRfiles}} \def\startR {\doglobal\increment\nofRfiles diff --git a/tex/context/base/m-spreadsheet.lua b/tex/context/base/m-spreadsheet.lua index 9d5106e35..f329acf9a 100644 --- a/tex/context/base/m-spreadsheet.lua +++ b/tex/context/base/m-spreadsheet.lua @@ -172,7 +172,7 @@ function functions._s_(row,col,c,f,t) for i=f,t do local ci = c[i] if type(ci) == "number" then - r = r + c[i] + r = r + ci end end return r diff --git a/tex/context/base/m-translate.mkiv b/tex/context/base/m-translate.mkiv index 363f115cb..f36f9a9fb 100644 --- a/tex/context/base/m-translate.mkiv +++ b/tex/context/base/m-translate.mkiv @@ -89,7 +89,6 @@ \continueifinputfile{m-translate.mkiv} - \starttext \translateinput[Moica][Mojca] diff --git a/tex/context/base/m-zint.mkiv b/tex/context/base/m-zint.mkiv index 95b265c57..4957c8461 100644 --- a/tex/context/base/m-zint.mkiv +++ b/tex/context/base/m-zint.mkiv @@ -29,17 +29,21 @@ moduledata.zint = { } local format, lower, gsub = string.format, string.lower, string.gsub local patterns = lpeg.patterns -local zint = "zint" -- '"c:/program files/zint/zint.exe"' +local zint = "zint" -- '"c:/program files/zint/zint.exe"' +local defaultcode = "PDF417" -local whitespace = patterns.whitespace -local spaces = whitespace^0 -local key = (spaces / "") * patterns.digit^0 * (patterns.colon * spaces / "") -local value = (whitespace / "" + (1 - key))^1 -local pattern = lpeg.Cf(lpeg.Ct("") * (lpeg.Cg((lpeg.Cs(key) / tonumber) * (lpeg.Cs(value) / lower)) + patterns.anything)^0,rawset) +local whitespace = patterns.whitespace +local spaces = whitespace^0 +local key = (spaces / "") * patterns.digit^0 * (patterns.colon * spaces / "") +local value = (whitespace / "" + (1 - key))^1 +local pattern = lpeg.Cf(lpeg.Ct("") * (lpeg.Cg((lpeg.Cs(key) / tonumber) * (lpeg.Cs(value) / lower)) + patterns.anything)^0,rawset) local reverse local function cleancode(code) + if not code or code == "" then + code = defaultcode + end return lower(gsub(code," ","")) end @@ -76,6 +80,19 @@ end \stopluacode +\unprotect + +\unexpanded\def\barcode[#1]% [alternative=,text=] + {\bgroup + \getdummyparameters + [\c!alternative=,\c!text=,#1]% + \externalfigure + [\cldcontext{moduledata.zint.generate("\dummyparameter\c!alternative",\!!bs\dummyparameter\c!text\!!es)}]% + [#1,\c!alternative=,\c!text=]% + \egroup} + +\protect + \continueifinputfile{m-zint.mkiv} \starttext @@ -85,6 +102,10 @@ end \externalfigure[\cldcontext{moduledata.zint.generate("PDF417","Ton Otten")}] \blank \externalfigure[\cldcontext{moduledata.zint.generate("ISBN","9789490688011")}] + \blank + \barcode[text=Does It Work?,width=\textwidth] + \blank + \barcode[alternative=isbn,text=9789490688011,width=3cm] \stoptext diff --git a/tex/context/base/math-act.lua b/tex/context/base/math-act.lua index 7c75dc56e..a03542b3e 100644 --- a/tex/context/base/math-act.lua +++ b/tex/context/base/math-act.lua @@ -18,7 +18,7 @@ local report_math = logs.reporter("mathematics","initializing") local context = context local commands = commands local mathematics = mathematics -local texdimen = tex.dimen +local texsetdimen = tex.setdimen local abs = math.abs local sequencers = utilities.sequencers @@ -296,78 +296,95 @@ function tweaks.fixbadprime(target,original) target.characters[0xFE325] = target.characters[0x2032] end -local function accent_to_extensible(target,newchr,original,oldchr,height,depth) - local characters = target.characters - -- if not characters[newchr] then -- xits needs an enforce - local olddata = characters[oldchr] - if olddata then - height = height or 0 - depth = depth or 0 - local addprivate = fonts.helpers.addprivate - local correction = { "down", olddata.height } - local newdata = { - commands = { correction, { "slot", 1, oldchr } }, - width = olddata.width, - height = height, - depth = depth, - } - characters[newchr] = newdata - local nextglyph = olddata.next - while nextglyph do - local oldnextdata = characters[nextglyph] - local newnextdata = { - commands = { correction, { "slot", 1, nextglyph } }, - width = oldnextdata.width, - height = height, - depth = depth, - } - local newnextglyph = addprivate(target,formatters["overline-%H"](nextglyph),newnextdata) - newdata.next = newnextglyph - local nextnextglyph = oldnextdata.next - if nextnextglyph == nextglyph then - break - else - olddata = oldnextdata - newdata = newnextdata - nextglyph = nextnextglyph - end - end - local hv = olddata.horiz_variants - if hv then - hv = fastcopy(hv) - newdata.horiz_variants = hv - for i=1,#hv do - local hvi = hv[i] - local oldglyph = hvi.glyph - local olddata = characters[oldglyph] - local newdata = { - commands = { correction, { "slot", 1, oldglyph } }, - width = olddata.width, - height = height, - depth = depth, - } - hvi.glyph = addprivate(target,formatters["overline-%H"](oldglyph),newdata) - end - end - end - -- end -end - -function tweaks.fixoverline(target,original) - local height, depth = 0, 0 - local mathparameters = target.mathparameters - if mathparameters then - height = mathparameters.OverbarVerticalGap - depth = mathparameters.UnderbarVerticalGap - else - height = target.parameters.xheight/4 - depth = height - end - accent_to_extensible(target,0x203E,original,0x0305,height,depth) --- inspect(fonts.helpers.expandglyph(target.characters,0x203E)) -end - -sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweaks.fixoverline") -- for the moment always +-- these could go to math-fbk + +-- local function accent_to_extensible(target,newchr,original,oldchr,height,depth,swap) +-- local characters = target.characters +-- -- if not characters[newchr] then -- xits needs an enforce +-- local addprivate = fonts.helpers.addprivate +-- local olddata = characters[oldchr] +-- if olddata then +-- if swap then +-- swap = characters[swap] +-- height = swap.depth +-- depth = 0 +-- else +-- height = height or 0 +-- depth = depth or 0 +-- end +-- local correction = swap and { "down", (olddata.height or 0) - height } or { "down", olddata.height } +-- local newdata = { +-- commands = { correction, { "slot", 1, oldchr } }, +-- width = olddata.width, +-- height = height, +-- depth = depth, +-- } +-- characters[newchr] = newdata +-- local nextglyph = olddata.next +-- while nextglyph do +-- local oldnextdata = characters[nextglyph] +-- local newnextdata = { +-- commands = { correction, { "slot", 1, nextglyph } }, +-- width = oldnextdata.width, +-- height = height, +-- depth = depth, +-- } +-- local newnextglyph = addprivate(target,formatters["original-%H"](nextglyph),newnextdata) +-- newdata.next = newnextglyph +-- local nextnextglyph = oldnextdata.next +-- if nextnextglyph == nextglyph then +-- break +-- else +-- olddata = oldnextdata +-- newdata = newnextdata +-- nextglyph = nextnextglyph +-- end +-- end +-- local hv = olddata.horiz_variants +-- if hv then +-- hv = fastcopy(hv) +-- newdata.horiz_variants = hv +-- for i=1,#hv do +-- local hvi = hv[i] +-- local oldglyph = hvi.glyph +-- local olddata = characters[oldglyph] +-- local newdata = { +-- commands = { correction, { "slot", 1, oldglyph } }, +-- width = olddata.width, +-- height = height, +-- depth = depth, +-- } +-- hvi.glyph = addprivate(target,formatters["original-%H"](oldglyph),newdata) +-- end +-- end +-- end +-- -- end +-- end + +-- function tweaks.fixoverline(target,original) +-- local height, depth = 0, 0 +-- local mathparameters = target.mathparameters +-- if mathparameters then +-- height = mathparameters.OverbarVerticalGap +-- depth = mathparameters.UnderbarVerticalGap +-- else +-- height = target.parameters.xheight/4 +-- depth = height +-- end +-- accent_to_extensible(target,0x203E,original,0x0305,height,depth) +-- -- also crappy spacing for our purpose: push to top of baseline +-- accent_to_extensible(target,0xFE3DE,original,0x23DE,height,depth,0x23DF) +-- accent_to_extensible(target,0xFE3DC,original,0x23DC,height,depth,0x23DD) +-- accent_to_extensible(target,0xFE3B4,original,0x23B4,height,depth,0x23B5) +-- -- for symmetry +-- target.characters[0xFE3DF] = original.characters[0x23DF] +-- target.characters[0xFE3DD] = original.characters[0x23DD] +-- target.characters[0xFE3B5] = original.characters[0x23B5] +-- -- inspect(fonts.helpers.expandglyph(target.characters,0x203E)) +-- -- inspect(fonts.helpers.expandglyph(target.characters,0x23DE)) +-- end + +-- sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweaks.fixoverline") -- for the moment always -- helpers @@ -455,24 +472,24 @@ function commands.horizontalcode(family,unicode) local charlist = data[3].horiz_variants local characters = fontcharacters[font] local left = charlist[1] - texdimen.scratchleftoffset = abs((left["start"] or 0) - (left["end"] or 0)) - texdimen.scratchrightoffset = 0 + texsetdimen("scratchleftoffset",abs((left["start"] or 0) - (left["end"] or 0))) + texsetdimen("scratchrightoffset",0) elseif kind == e_right then local charlist = data[3].horiz_variants local characters = fontcharacters[font] local right = charlist[#charlist] - texdimen.scratchleftoffset = 0 - texdimen.scratchrightoffset = abs((right["start"] or 0) - (right["end"] or 0)) + texsetdimen("scratchleftoffset",0) + texsetdimen("scratchrightoffset",abs((right["start"] or 0) - (right["end"] or 0))) elseif kind == e_horizontal then local charlist = data[3].horiz_variants local characters = fontcharacters[font] local left = charlist[1] local right = charlist[#charlist] - texdimen.scratchleftoffset = abs((left["start"] or 0) - (left["end"] or 0)) - texdimen.scratchrightoffset = abs((right["start"] or 0) - (right["end"] or 0)) + texsetdimen("scratchleftoffset", abs((left ["start"] or 0) - (left ["end"] or 0))) + texsetdimen("scratchrightoffset",abs((right["start"] or 0) - (right["end"] or 0))) else - texdimen.scratchleftoffset = 0 - texdimen.scratchrightoffset = 0 + texsetdimen("scratchleftoffset",0) + texsetdimen("scratchrightoffset",0) end context(kind) end diff --git a/tex/context/base/math-def.mkiv b/tex/context/base/math-def.mkiv index 9201fc540..99e6a8a18 100644 --- a/tex/context/base/math-def.mkiv +++ b/tex/context/base/math-def.mkiv @@ -348,18 +348,21 @@ \unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits} \unexpanded\def\stackrel #1#2{\mathrel{\mathop{#2}\limits^{#1}}} -\unexpanded\def\overbrace {\mathopwithlimits\normaloverbrace } -\unexpanded\def\underbrace {\mathopwithlimits\normalunderbrace } -\unexpanded\def\doublebrace {\mathopwithlimits\normaldoublebrace } -\unexpanded\def\overparent {\mathopwithlimits\normaloverparent } -\unexpanded\def\underparent {\mathopwithlimits\normalunderparent } -\unexpanded\def\overbracket {\mathopwithlimits\normaloverbracket } -\unexpanded\def\underbracket {\mathopwithlimits\normalunderbracket } -\unexpanded\def\doubleparent {\mathopwithlimits\normaldoubleparent } -\unexpanded\def\underleftarrow {\mathopwithlimits\normalunderleftarrow } -\unexpanded\def\overleftarrow {\mathopwithlimits\normaloverleftarrow } -\unexpanded\def\underrightarrow{\mathopwithlimits\normalunderrightarrow} -\unexpanded\def\overrightarrow {\mathopwithlimits\normaloverrightarrow } +% these are stackers now + +%\unexpanded\def\overbrace {\mathopwithlimits\normaloverbrace } +%\unexpanded\def\underbrace {\mathopwithlimits\normalunderbrace } +%\unexpanded\def\doublebrace {\mathopwithlimits\normaldoublebrace } +%\unexpanded\def\overparent {\mathopwithlimits\normaloverparent } +%\unexpanded\def\underparent {\mathopwithlimits\normalunderparent } +%\unexpanded\def\overbracket {\mathopwithlimits\normaloverbracket } +%\unexpanded\def\underbracket {\mathopwithlimits\normalunderbracket } +%\unexpanded\def\doubleparent {\mathopwithlimits\normaldoubleparent } + +%unexpanded\def\underleftarrow {\mathopwithlimits\normalunderleftarrow } +%unexpanded\def\overleftarrow {\mathopwithlimits\normaloverleftarrow } +%unexpanded\def\underrightarrow{\mathopwithlimits\normalunderrightarrow} +%unexpanded\def\overrightarrow {\mathopwithlimits\normaloverrightarrow } \let\lceil \lceiling \let\rceil \rceiling diff --git a/tex/context/base/math-fbk.lua b/tex/context/base/math-fbk.lua index eebc4e4e7..0800f3007 100644 --- a/tex/context/base/math-fbk.lua +++ b/tex/context/base/math-fbk.lua @@ -10,6 +10,9 @@ local trace_fallbacks = false trackers.register("math.fallbacks", function(v) t local report_fallbacks = logs.reporter("math","fallbacks") +local formatters = string.formatters +local fastcopy = table.fastcopy + local fallbacks = { } mathematics.fallbacks = fallbacks @@ -39,7 +42,7 @@ function fallbacks.apply(target,original) end -- This is not okay yet ... we have no proper way to refer to 'self' -- otherwise I will make my own id allocator). -local self = #usedfonts == 0 and font.nextid() or nil -- will be true + local self = #usedfonts == 0 and font.nextid() or nil -- will be true local textid, scriptid, scriptscriptid local textindex, scriptindex, scriptscriptindex local textdata, scriptdata, scriptscriptdata @@ -48,19 +51,19 @@ local self = #usedfonts == 0 and font.nextid() or nil -- will be true -- textid = nil -- self -- scriptid = nil -- no smaller -- scriptscriptid = nil -- no smaller -textid = self -scriptid = self -scriptscriptid = self + textid = self + scriptid = self + scriptscriptid = self elseif mathsize == 2 then -- scriptsize -- textid = nil -- self -textid = self + textid = self scriptid = lastmathids[3] scriptscriptid = lastmathids[3] else -- textsize -- textid = nil -- self -textid = self + textid = self scriptid = lastmathids[2] scriptscriptid = lastmathids[3] end @@ -87,8 +90,7 @@ textid = self scriptscriptindex = scriptindex scriptscriptdata = scriptdata end --- report_fallbacks("used textid: %s, used script id: %s, used scriptscript id: %s", --- tostring(textid),tostring(scriptid),tostring(scriptscriptid)) + -- report_fallbacks("used textid: %S, used script id: %S, used scriptscript id: %S",textid,scriptid,scriptscriptid) local data = { textdata = textdata, scriptdata = scriptdata, @@ -103,7 +105,7 @@ textid = self size = size, mathsize = mathsize, } --- inspect(usedfonts) + -- inspect(usedfonts) for k, v in next, virtualcharacters do if not characters[k] then local tv = type(v) @@ -310,3 +312,129 @@ virtualcharacters[0xFE352] = function(data) end end +-- we could move the defs from math-act here + +addextra(0xFE3DE, { description="EXTENSIBLE OF 0x03DE", unicodeslot=0xFE3DE, mathextensible = "r", mathstretch = "h" } ) +addextra(0xFE3DF, { description="EXTENSIBLE OF 0x03DF", unicodeslot=0xFE3DF, mathextensible = "r", mathstretch = "h" } ) +addextra(0xFE3DC, { description="EXTENSIBLE OF 0x03DC", unicodeslot=0xFE3DC, mathextensible = "r", mathstretch = "h" } ) +addextra(0xFE3DD, { description="EXTENSIBLE OF 0x03DD", unicodeslot=0xFE3DD, mathextensible = "r", mathstretch = "h" } ) +addextra(0xFE3B4, { description="EXTENSIBLE OF 0x03B4", unicodeslot=0xFE3B4, mathextensible = "r", mathstretch = "h" } ) +addextra(0xFE3B5, { description="EXTENSIBLE OF 0x03B5", unicodeslot=0xFE3B5, mathextensible = "r", mathstretch = "h" } ) + +local function accent_to_extensible(target,newchr,original,oldchr,height,depth,swap) + local characters = target.characters + local addprivate = fonts.helpers.addprivate + local olddata = characters[oldchr] + if olddata then + if swap then + swap = characters[swap] + height = swap.depth + depth = 0 + else + height = height or 0 + depth = depth or 0 + end + local correction = swap and { "down", (olddata.height or 0) - height } or { "down", olddata.height } + local newdata = { + commands = { correction, { "slot", 1, oldchr } }, + width = olddata.width, + height = height, + depth = depth, + } + local glyphdata = newdata + local nextglyph = olddata.next + while nextglyph do + local oldnextdata = characters[nextglyph] + local newnextdata = { + commands = { correction, { "slot", 1, nextglyph } }, + width = oldnextdata.width, + height = height, + depth = depth, + } + local newnextglyph = addprivate(target,formatters["original-%H"](nextglyph),newnextdata) + newdata.next = newnextglyph + local nextnextglyph = oldnextdata.next + if nextnextglyph == nextglyph then + break + else + olddata = oldnextdata + newdata = newnextdata + nextglyph = nextnextglyph + end + end + local hv = olddata.horiz_variants + if hv then + hv = fastcopy(hv) + newdata.horiz_variants = hv + for i=1,#hv do + local hvi = hv[i] + local oldglyph = hvi.glyph + local olddata = characters[oldglyph] + local newdata = { + commands = { correction, { "slot", 1, oldglyph } }, + width = olddata.width, + height = height, + depth = depth, + } + hvi.glyph = addprivate(target,formatters["original-%H"](oldglyph),newdata) + end + end + return glyphdata + end +end + +virtualcharacters[0x203E] = function(data) -- could be FE33E instead + local target = data.target + local height, depth = 0, 0 + local mathparameters = target.mathparameters + if mathparameters then + height = mathparameters.OverbarVerticalGap + depth = mathparameters.UnderbarVerticalGap + else + height = target.parameters.xheight/4 + depth = height + end + return accent_to_extensible(target,0x203E,data.original,0x0305,height,depth) +end + +virtualcharacters[0xFE3DE] = function(data) + local target, original = data.target, data.original + local chardata = target.characters[0x23DE] + if chardata and chardata.height > target.parameters.xheight then + return accent_to_extensible(target,0xFE3DE,original,0x23DE,0,0,0x23DF) + else + return original.characters[0x23DE] + end +end + +virtualcharacters[0xFE3DC] = function(data) + local target, original = data.target, data.original + local chardata = target.characters[0x23DC] + if chardata and chardata.height > target.parameters.xheight then + return accent_to_extensible(target,0xFE3DC,original,0x23DC,0,0,0x23DD) + else + return original.characters[0x23DC] + end +end + +virtualcharacters[0xFE3B4] = function(data) + local target, original = data.target, data.original + local chardata = target.characters[0x23B4] + if chardata and chardata.height > target.parameters.xheight then + return accent_to_extensible(target,0xFE3B4,original,0x23B4,0,0,0x23B5) + else + return original.characters[0x23B4] + end +end + +virtualcharacters[0xFE3DF] = function(data) + return data.original.characters[0x23DF] +end + +virtualcharacters[0xFE3DD] = function(data) + return data.original.characters[0x23DD] +end + +virtualcharacters[0xFE3B5] = function(data) + return data.original.characters[0x23B5] +end diff --git a/tex/context/base/math-ini.lua b/tex/context/base/math-ini.lua index 6e667d083..dc1e9f29a 100644 --- a/tex/context/base/math-ini.lua +++ b/tex/context/base/math-ini.lua @@ -17,8 +17,6 @@ if not modules then modules = { } end modules ['math-ini'] = { local formatters, find = string.formatters, string.find local utfchar, utfbyte = utf.char, utf.byte -local setmathcode, setdelcode = tex.setmathcode, tex.setdelcode -local settexattribute = tex.setattribute local floor = math.floor local context = context @@ -41,6 +39,10 @@ local unsetvalue = attributes.unsetvalue local allocate = utilities.storage.allocate local chardata = characters.data +local texsetattribute = tex.setattribute +local setmathcode = tex.setmathcode +local setdelcode = tex.setdelcode + local families = allocate { mr = 0, mb = 1, @@ -503,10 +505,10 @@ end -- -- function commands.taggedmathfunction(tag,label) -- if label then --- settexattribute(a_mathcategory,registercategory(1,tag,tag)) +-- texsetattribute(a_mathcategory,registercategory(1,tag,tag)) -- context.mathlabeltext(tag) -- else --- settexattribute(a_mathcategory,1) +-- texsetattribute(a_mathcategory,1) -- context(tag) -- end -- end @@ -529,13 +531,13 @@ function commands.taggedmathfunction(tag,label,apply) noffunctions = noffunctions + 1 functions[noffunctions] = tag functions[tag] = noffunctions - settexattribute(a_mathcategory,noffunctions + delta) + texsetattribute(a_mathcategory,noffunctions + delta) else - settexattribute(a_mathcategory,n + delta) + texsetattribute(a_mathcategory,n + delta) end context.mathlabeltext(tag) else - settexattribute(a_mathcategory,1000 + delta) + texsetattribute(a_mathcategory,1000 + delta) context(tag) end end @@ -554,6 +556,6 @@ function commands.resetmathattributes() end end for i=1,#list do - settexattribute(list[i],unsetvalue) + texsetattribute(list[i],unsetvalue) end end diff --git a/tex/context/base/math-map.lua b/tex/context/base/math-map.lua index a0d7457d1..9158d945a 100644 --- a/tex/context/base/math-map.lua +++ b/tex/context/base/math-map.lua @@ -36,11 +36,15 @@ local merged = table.merged local extract = bit32.extract local allocate = utilities.storage.allocate -local texattribute = tex.attribute + local otffeatures = fonts.constructors.newfeatures("otf") local registerotffeature = otffeatures.register + local setmetatableindex = table.setmetatableindex +local texgetattribute = tex.getattribute +local texsetattribute = tex.setattribute + local trace_greek = false trackers.register("math.greek", function(v) trace_greek = v end) local report_remapping = logs.reporter("mathematics","remapping") @@ -524,7 +528,7 @@ function mathematics.getboth(alphabet,style) end function mathematics.getstyle(style) - local r = mathremap[texattribute[mathalphabet]] + local r = mathremap[texgetattribute(mathalphabet)] local alphabet = r and r.alphabet or "regular" local data = alphabets[alphabet][style] return data and data.attribute @@ -533,22 +537,22 @@ end function mathematics.syncboth(alphabet,style) local data = alphabet and alphabets[alphabet] or regular data = style and data[style] or data.tf - texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet] + texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet]) end function mathematics.syncstyle(style) - local r = mathremap[texattribute[mathalphabet]] + local r = mathremap[texgetattribute(mathalphabet)] local alphabet = r and r.alphabet or "regular" local data = alphabets[alphabet][style] - texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet] + texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet]) end function mathematics.syncname(alphabet) -- local r = mathremap[mathalphabet] - local r = mathremap[texattribute[mathalphabet]] + local r = mathremap[texgetattribute(mathalphabet)] local style = r and r.style or "tf" local data = alphabets[alphabet][style] - texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet] + texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet]) end local islcgreek = regular_tf.lcgreek diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua index b309ba077..903c91f34 100644 --- a/tex/context/base/math-noa.lua +++ b/tex/context/base/math-noa.lua @@ -62,7 +62,6 @@ local new_node = node.new -- todo: pool: math_noad math_sub local new_kern = nodes.pool.kern local new_rule = nodes.pool.rule -local concat_nodes = nodes.concat local topoints = number.points @@ -75,7 +74,8 @@ local fontemwidths = fonthashes.emwidths local fontexheights = fonthashes.exheights local variables = interfaces.variables -local texattribute = tex.attribute +local texsetattribute = tex.setattribute +local texgetattribute = tex.getattribute local unsetvalue = attributes.unsetvalue local chardata = characters.data @@ -462,135 +462,6 @@ function handlers.resize(head,style,penalties) return true end --- respacing - --- local mathpunctuation = attributes.private("mathpunctuation") --- --- local respace = { } processors.respace = respace - --- only [nd,ll,ul][po][nd,ll,ul] - --- respace[math_char] = function(pointer,what,n,parent) -- not math_noad .. math_char ... and then parent --- pointer = parent --- if pointer and pointer.subtype == noad_ord then --- local a = pointer[mathpunctuation] --- if a and a > 0 then --- pointer[mathpunctuation] = 0 --- local current_nucleus = pointer.nucleus --- if current_nucleus.id == math_char then --- local current_char = current_nucleus.char --- local fc = chardata[current_char] --- fc = fc and fc.category --- if fc == "nd" or fc == "ll" or fc == "lu" then --- local next_noad = pointer.next --- if next_noad and next_noad.id == math_noad and next_noad.subtype == noad_punct then --- local next_nucleus = next_noad.nucleus --- if next_nucleus.id == math_char then --- local next_char = next_nucleus.char --- local nc = chardata[next_char] --- nc = nc and nc.category --- if nc == "po" then --- local last_noad = next_noad.next --- if last_noad and last_noad.id == math_noad and last_noad.subtype == noad_ord then --- local last_nucleus = last_noad.nucleus --- if last_nucleus.id == math_char then --- local last_char = last_nucleus.char --- local lc = chardata[last_char] --- lc = lc and lc.category --- if lc == "nd" or lc == "ll" or lc == "lu" then --- local ord = new_node(math_noad) -- todo: pool --- ord.subtype, ord.nucleus, ord.sub, ord.sup, ord.attr = noad_ord, next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr --- -- next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr = nil, nil, nil, nil --- next_noad.nucleus, next_noad.sub, next_noad.sup = nil, nil, nil -- else crash with attributes ref count --- --~ next_noad.attr = nil --- ord.next = last_noad --- pointer.next = ord --- free_node(next_noad) --- end --- end --- end --- end --- end --- end --- end --- end --- end --- end --- end - --- local comma = 0x002C --- local period = 0x002E --- --- respace[math_char] = function(pointer,what,n,parent) --- pointer = parent --- if pointer and pointer.subtype == noad_punct then --- local current_nucleus = pointer.nucleus --- if current_nucleus.id == math_char then --- local current_nucleus = pointer.nucleus --- if current_nucleus.id == math_char then --- local current_char = current_nucleus.char --- local a = pointer[mathpunctuation] --- if not a or a == 0 then --- if current_char == comma then --- -- default tex: 2,5 or 2, 5 --> 2, 5 --- elseif current_char == period then --- -- default tex: 2.5 or 2. 5 --> 2.5 --- pointer.subtype = noad_ord --- end --- elseif a == 1 then --- local next_noad = pointer.next --- if next_noad and next_noad.id == math_noad then --- local next_nucleus = next_noad.nucleus --- if next_nucleus.id == math_char and next_nucleus.char == 0 then --- nodes.remove(pointer,next_noad,true) --- end --- if current_char == comma then --- -- default tex: 2,5 or 2, 5 --> 2, 5 --- elseif current_char == period then --- -- default tex: 2.5 or 2. 5 --> 2.5 --- pointer.subtype = noad_ord --- end --- end --- elseif a == 2 then --- if current_char == comma or current_char == period then --- local next_noad = pointer.next --- if next_noad and next_noad.id == math_noad then --- local next_nucleus = next_noad.nucleus --- if next_nucleus.id == math_char and next_nucleus.char == 0 then --- if current_char == comma then --- -- adaptive: 2, 5 --> 2, 5 --- elseif current_char == period then --- -- adaptive: 2. 5 --> 2. 5 --- end --- nodes.remove(pointer,next_noad,true) --- else --- if current_char == comma then --- -- adaptive: 2,5 --> 2,5 --- pointer.subtype = noad_ord --- elseif current_char == period then --- -- adaptive: 2.5 --> 2.5 --- pointer.subtype = noad_ord --- end --- end --- end --- end --- end --- end --- end --- end --- end --- --- function handlers.respace(head,style,penalties) --- processnoads(head,respace,"respace") --- return true --- end - --- The following code is dedicated to Luigi Scarso who pointed me --- to the fact that \not= is not producing valid pdf-a code. --- The code does not solve this for virtual characters but it does --- a decent job on collapsing so that fonts that have the right --- glyph will have a decent unicode point. In the meantime this code --- has been moved elsewhere. local collapse = { } processors.collapse = collapse @@ -824,7 +695,7 @@ function mathematics.setalternate(fam,tag) local mathalternates = tfmdata.shared and tfmdata.shared.mathalternates if mathalternates then local m = mathalternates[tag] - tex.attribute[a_mathalternate] = m and m.attribute or unsetvalue + texsetattribute(a_mathalternate,m and m.attribute or unsetvalue) end end @@ -947,11 +818,7 @@ trackers.register("math.italics", function(v) if k > 0 then return setcolor(new_rule(k,ex,ex),c_positive_d) else - return concat_nodes { - old_kern(k), - setcolor(new_rule(-k,ex,ex),c_negative_d), - old_kern(k), - } + return old_kern(k) .. setcolor(new_rule(-k,ex,ex),c_negative_d) .. old_kern(k) end end else @@ -1063,14 +930,14 @@ function mathematics.setitalics(n) enable() end if n == variables.reset then - texattribute[a_mathitalics] = unsetvalue + texsetattribute(a_mathitalics,unsetvalue) else - texattribute[a_mathitalics] = tonumber(n) or unsetvalue + texsetattribute(a_mathitalics,tonumber(n) or unsetvalue) end end function mathematics.resetitalics() - texattribute[a_mathitalics] = unsetvalue + texsetattribute(a_mathitalics,unsetvalue) end -- variants diff --git a/tex/context/base/math-ren.lua b/tex/context/base/math-ren.lua index 2e7dba13d..5c4c13369 100644 --- a/tex/context/base/math-ren.lua +++ b/tex/context/base/math-ren.lua @@ -63,7 +63,3 @@ mathematics.renderset = renderset function commands.mathrenderset(list) context(renderset(list)) end - --- function commands.setmatrendering(list) --- tex.setattribute(renderset(list)) --- end diff --git a/tex/context/base/math-stc.mkvi b/tex/context/base/math-stc.mkvi index ae601bc4c..5f92f3801 100644 --- a/tex/context/base/math-stc.mkvi +++ b/tex/context/base/math-stc.mkvi @@ -395,11 +395,23 @@ %D The next one deals with under and over extensibles (arrows mostly): -\unexpanded\def\math_stackers_double#where#category#codepoint#text% +\installcorenamespace {mathclasses} + +\letvalue{\??mathclasses }\mathord +\letvalue{\??mathclasses rel}\mathrel +\letvalue{\??mathclasses ord}\mathord + +\def\math_class_by_parameter#1% + {\normalexpanded{\noexpand\math_class_by_parameter_indeed{#1\c!mathclass}}} + +\def\math_class_by_parameter_indeed#1% + {\csname\??mathclasses\ifcsname\??mathclasses#1\endcsname#1\fi\endcsname} + +\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#text% {\begingroup \edef\currentmathstackers{#category}% \mathstackersparameter\c!left\relax - \ifmmode\mathrel\else\dontleavehmode\fi + \ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi {\edef\currentmathstackers{#category}% \edef\m_math_stackers_text_middle {#text}% % @@ -436,12 +448,18 @@ % \ifdim\htdp\scratchboxtwo>\zeropoint \kern-\scratchwidth - \ifcase#where\relax + \ifcase#top\else \math_stackers_top\bgroup \raise\dimexpr\scratchheight+\scratchtopoffset\relax \box\scratchboxtwo \egroup - \else + \fi + \scratchunicode#codeextra\relax + \ifcase\scratchunicode\else + \kern-\scratchwidth + \setbox\scratchboxtwo\math_stackers_content + \fi + \ifcase#bottom\else \math_stackers_bottom\bgroup \lower\dimexpr\scratchdepth+\ht\scratchboxtwo+\scratchbottomoffset\relax \box\scratchboxtwo @@ -449,36 +467,53 @@ \fi \fi}% \mathstackersparameter\c!right\relax - \endgroup} + \edef\p_limits{\mathstackersparameter\c!mathlimits}% + \ifx\p_limits\v!yes + \expandafter\endgroup\expandafter\limits + \else + \expandafter\endgroup + \fi} -\unexpanded\def\definemathoverextensible {\dotripleempty\math_extensiblies_define_over } -\unexpanded\def\definemathunderextensible{\dotripleempty\math_extensiblies_define_under} +\unexpanded\def\definemathoverextensible {\dotripleempty \math_extensiblies_define_over } +\unexpanded\def\definemathunderextensible {\dotripleempty \math_extensiblies_define_under} +\unexpanded\def\definemathdoubleextensible{\doquadrupleempty\math_extensiblies_define_double} \def\math_extensiblies_define_over[#1][#2][#3]% {\ifthirdargument - \setuevalue{#2}{\math_stackers_double\zerocount{#1}{\number#3}}% + \setuevalue{#2}{\math_stackers_make_double\plusone \zerocount{#1}{\number#3}{0}}% \else - \setuevalue{#1}{\math_stackers_double\zerocount\noexpand\currentmathstackers{\number#2}}% + \setuevalue{#1}{\math_stackers_make_double\plusone \zerocount\noexpand\currentmathstackers{\number#2}{0}}% \fi} \def\math_extensiblies_define_under[#1][#2][#3]% {\ifthirdargument - \setuevalue{#2}{\math_stackers_double\plusone{#1}{\number#3}}% + \setuevalue{#2}{\math_stackers_make_double\zerocount\plusone{#1}{\number#3}{0}}% \else - \setuevalue{#1}{\math_stackers_double\plusone\noexpand\currentmathstackers{\number#2}}% + \setuevalue{#1}{\math_stackers_make_double\zerocount\plusone\noexpand\currentmathstackers{\number#2}{0}}% \fi} -\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over } -\unexpanded\def\mathunder{\begingroup\dosingleempty\math_stackers_handle_under} +\def\math_extensiblies_define_double[#1][#2][#3][#4]% + {\ifthirdargument + \setuevalue{#2}{\math_stackers_make_double\plusone \plusone{#1}{\number#3}{\number#4}}% + \else + \setuevalue{#1}{\math_stackers_make_double\plusone \plusone\noexpand\currentmathstackers{\number#2}{\number#3}}% + \fi} + +\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over } +\unexpanded\def\mathunder {\begingroup\dosingleempty\math_stackers_handle_under } +\unexpanded\def\mathdouble{\begingroup\dodoubleempty\math_stackers_handle_double} \def\math_stackers_handle_over[#category]% - {\math_stackers_handle_double\zerocount{\iffirstargument#category\else\v!top \fi}} % will be defined later on + {\math_stackers_direct_double\plusone\zerocount{\iffirstargument#category\else\v!top \fi}} % will be defined later on \def\math_stackers_handle_under[#category]#codepoint#bottomtext% - {\math_stackers_handle_double\plusone {\iffirstargument#category\else\v!bottom\fi}} % will be defined later on + {\math_stackers_direct_double\zerocount\plusone{\iffirstargument#category\else\v!bottom\fi}} % will be defined later on + +\def\math_stackers_handle_double[#category]#codepoint#bottomtext% + {\math_stackers_direct_double\plusone\plusone {\iffirstargument#category\else\v!bottom\fi}} % will be defined later on -\def\math_stackers_handle_double#location#category#codepoint#text% - {\math_stackers_double#location{#category}{#codepoint}{#text}% +\def\math_stackers_direct_double#top#bottom#category#codepoint#text% + {\math_stackers_make_double#top#bottom{#category}{#codepoint}{#text}% \endgroup} %D Here is a bonus macro that takes three texts. It can be used to get consistent @@ -558,20 +593,26 @@ [\c!order=\v!reverse] \definemathstackers - [\v!top] + [\v!both] [\v!mathematics] - [\c!location=\v!top, + [\c!location=\v!top, % ? \c!strut=\v!no, \c!middlecommand=\mathematics, \c!hoffset=\zeropoint] \definemathstackers + [\v!top] + [\v!both] + +\definemathstackers [\v!bottom] - [\v!mathematics] - [\c!location=\v!top, % ? - \c!strut=\v!no, - \c!middlecommand=\mathematics, - \c!hoffset=\zeropoint] + [\v!both] + +\definemathstackers + [vfenced] + [\v!both] + [\c!mathclass=\s!ord, + \c!mathlimits=\v!yes] % These are compatibity definitions, math only. @@ -680,8 +721,23 @@ % stuff in the backend (okay, we still need to deal with some cut and paste % issues but at least we now know what we deal with. -\definemathunderextensible [\v!bottom] [underbar] ["203E] -\definemathoverextensible [\v!top] [overbar] ["203E] +\definemathunderextensible [vfenced] [underbar] ["203E] +\definemathoverextensible [vfenced] [overbar] ["203E] +\definemathoverextensible [vfenced] [doublebar] ["203E] ["203E] + +\definemathoverextensible [vfenced] [overbrace] ["FE3DE] % ["023DE] +\definemathunderextensible [vfenced] [underbrace] ["FE3DF] % ["023DF] +\definemathdoubleextensible [vfenced] [doublebrace] ["FE3DE] ["FE3DF] + +\definemathoverextensible [vfenced] [overparent] ["FE3DC] % ["023DC] +\definemathunderextensible [vfenced] [underparent] ["FE3DD] % ["023DD] +\definemathdoubleextensible [vfenced] [doubleparent] ["FE3DC] ["FE3DD] + +\definemathoverextensible [vfenced] [overbracket] ["FE3B4] % ["023B4] +\definemathunderextensible [vfenced] [underbracket] ["FE3B5] % ["023B5] +\definemathdoubleextensible [vfenced] [doublebracket] ["FE3B4] ["FE3B5] + +% \unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits} %D Some bonus ones (for the moment here): diff --git a/tex/context/base/meta-pdf.lua b/tex/context/base/meta-pdf.lua index e51290e42..c49ad92ae 100644 --- a/tex/context/base/meta-pdf.lua +++ b/tex/context/base/meta-pdf.lua @@ -23,6 +23,8 @@ local report_mptopdf = logs.reporter("graphics","mptopdf") local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context +local texgetattribute = tex.getattribute + local pdfrgbcode = lpdf.rgbcode local pdfcmykcode = lpdf.cmykcode local pdfgraycode = lpdf.graycode @@ -84,7 +86,7 @@ end local function flushconcat() if m_stack_concat then - mpscode(f_concatm(unpack(m_stack_concat))) + mpscode(f_concat(unpack(m_stack_concat))) m_stack_concat = nil end end @@ -539,7 +541,7 @@ function mptopdf.convertmpstopdf(name) resetall() local ok, m_data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load ! if ok then - mps.colormodel = tex.attribute[a_colorspace] + mps.colormodel = texgetattribute(a_colorspace) statistics.starttiming(mptopdf) mptopdf.nofconverted = mptopdf.nofconverted + 1 pdfcode(formatters["\\letterpercent\\space mptopdf begin: n=%s, file=%s"](mptopdf.nofconverted,file.basename(name))) diff --git a/tex/context/base/meta-pdf.mkiv b/tex/context/base/meta-pdf.mkiv index a8fdaff42..3469419d4 100644 --- a/tex/context/base/meta-pdf.mkiv +++ b/tex/context/base/meta-pdf.mkiv @@ -37,7 +37,7 @@ \def\PDFMPformoffset{\ifdefined\objectoffset\objectoffset\else\zeropoint\fi} % obsolete, will go -\def\convertMPtoPDF#1#2#3% scaling no longer supported at this level (so #2 & #3 are ignored) +\unexpanded\def\convertMPtoPDF#1#2#3% scaling no longer supported at this level (so #2 & #3 are ignored) {\dostarttagged\t!mpgraphic\empty \naturalvbox attr \imageattribute 1 \bgroup \message{[MP to PDF]}% diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua index 93bddc2dd..4a887150d 100644 --- a/tex/context/base/mlib-pps.lua +++ b/tex/context/base/mlib-pps.lua @@ -19,7 +19,8 @@ local formatters = string.formatters local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context -local texbox = tex.box +local texgetbox = tex.getbox +local texsetbox = tex.setbox local copy_list = node.copy_list local free_list = node.flush_list local setmetatableindex = table.setmetatableindex @@ -227,8 +228,8 @@ local function freeboxes() local tn = textexts[n] if tn then free_list(tn) - -- texbox[scratchbox] = tn - -- texbox[scratchbox] = nil -- this frees too + -- texsetbox("scratchbox",tn) + -- texsetbox("scratchbox",nil) -- this frees too if trace_textexts then report_textexts("freeing box %s",n) end @@ -244,15 +245,15 @@ end metapost.resettextexts = freeboxes function metapost.settext(box,slot) - textexts[slot] = copy_list(texbox[box]) - texbox[box] = nil + textexts[slot] = copy_list(texgetbox(box)) + texsetbox(box,nil) -- this will become - -- textexts[slot] = texbox[box] + -- textexts[slot] = texgetbox(box) -- unsetbox(box) end function metapost.gettext(box,slot) - texbox[box] = copy_list(textexts[slot]) + texsetbox(box,copy_list(textexts[slot])) if trace_textexts then report_textexts("putting text %s in box %s",slot,box) end diff --git a/tex/context/base/mult-de.mkii b/tex/context/base/mult-de.mkii index 893a9d358..60eccd7f7 100644 --- a/tex/context/base/mult-de.mkii +++ b/tex/context/base/mult-de.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{beschriftung} \setinterfaceconstant{marstyle}{beschrstil} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua index fdb8803bf..10e99888e 100644 --- a/tex/context/base/mult-def.lua +++ b/tex/context/base/mult-def.lua @@ -10363,9 +10363,15 @@ return { ["pe"]="بست", ["ro"]="strut", }, + ["mathclass"]={ + ["en"]="mathclass", + }, ["mathstyle"]={ ["en"]="mathstyle", }, + ["mathlimits"]={ + ["en"]="mathlimits", + }, ["style"]={ ["cs"]="pismeno", ["de"]="stil", diff --git a/tex/context/base/mult-def.mkiv b/tex/context/base/mult-def.mkiv index cb165b055..6fff33f6a 100644 --- a/tex/context/base/mult-def.mkiv +++ b/tex/context/base/mult-def.mkiv @@ -88,6 +88,9 @@ \def\s!current {current} +\def\s!rel {rel} +\def\s!ord {ord} + \def\c!HL {HL} \def\c!VL {VL} \def\c!NL {NL} diff --git a/tex/context/base/mult-en.mkii b/tex/context/base/mult-en.mkii index c3ab2fc16..49076741c 100644 --- a/tex/context/base/mult-en.mkii +++ b/tex/context/base/mult-en.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{marking} \setinterfaceconstant{marstyle}{marstyle} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-fr.mkii b/tex/context/base/mult-fr.mkii index 1ba4f3c8c..945c5f74f 100644 --- a/tex/context/base/mult-fr.mkii +++ b/tex/context/base/mult-fr.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{marquage} \setinterfaceconstant{marstyle}{stylemarquage} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-it.mkii b/tex/context/base/mult-it.mkii index 0d1ea911d..20fe0be3f 100644 --- a/tex/context/base/mult-it.mkii +++ b/tex/context/base/mult-it.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{marcatura} \setinterfaceconstant{marstyle}{stilemarcatura} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-nl.mkii b/tex/context/base/mult-nl.mkii index 5f1bada7a..11c25f4e9 100644 --- a/tex/context/base/mult-nl.mkii +++ b/tex/context/base/mult-nl.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{markering} \setinterfaceconstant{marstyle}{marletter} \setinterfaceconstant{mask}{masker} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-pe.mkii b/tex/context/base/mult-pe.mkii index f55a7ab59..39ae60042 100644 --- a/tex/context/base/mult-pe.mkii +++ b/tex/context/base/mult-pe.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{نشانه‌گذاری} \setinterfaceconstant{marstyle}{سبک‌Øاش} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{بیشترین} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-ro.mkii b/tex/context/base/mult-ro.mkii index 34dd385a3..f61321e8b 100644 --- a/tex/context/base/mult-ro.mkii +++ b/tex/context/base/mult-ro.mkii @@ -801,6 +801,8 @@ \setinterfaceconstant{marking}{marcaje} \setinterfaceconstant{marstyle}{stilmarcaj} \setinterfaceconstant{mask}{mask} +\setinterfaceconstant{mathclass}{mathclass} +\setinterfaceconstant{mathlimits}{mathlimits} \setinterfaceconstant{mathstyle}{mathstyle} \setinterfaceconstant{max}{max} \setinterfaceconstant{maxdepth}{maxdepth} diff --git a/tex/context/base/mult-sys.mkiv b/tex/context/base/mult-sys.mkiv index f0db9fa67..74e4d70ea 100644 --- a/tex/context/base/mult-sys.mkiv +++ b/tex/context/base/mult-sys.mkiv @@ -163,6 +163,9 @@ \definesystemconstant {both} +\definesystemconstant {internal} +\definesystemconstant {external} + \definesystemconstant {attribute} \definesystemconstant {none} diff --git a/tex/context/base/node-acc.lua b/tex/context/base/node-acc.lua index 4380ec3a4..81ae496b2 100644 --- a/tex/context/base/node-acc.lua +++ b/tex/context/base/node-acc.lua @@ -35,7 +35,7 @@ local function injectspaces(head) while n do local id = n.id 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 n.spec.width > 0 then -- threshold if p and p.id == glyph_code then local g = copy_node(p) local c = g.components @@ -56,7 +56,7 @@ local function injectspaces(head) s[a_characters] = 0 n[a_characters] = 0 end ---~ end + -- end elseif id == hlist_code or id == vlist_code then injectspaces(n.list,attribute) -- elseif id == kern_code then -- the backend already collapses @@ -83,58 +83,58 @@ nodes.handlers.accessibility = injectspaces -- todo: ---~ local a_hyphenated = attributes.private('hyphenated') ---~ ---~ local hyphenated, codes = { }, { } ---~ ---~ local function compact(n) ---~ local t = { } ---~ for n in traverse_id(glyph_code,n) do ---~ t[#t+1] = utfchar(n.char) -- check for unicode ---~ end ---~ return concat(t,"") ---~ end ---~ ---~ local function injectspans(head) ---~ for n in traverse_nodes(head) do ---~ local id = n.id ---~ if id == disc then ---~ local r, p = n.replace, n.pre ---~ if r and p then ---~ local str = compact(r) ---~ local hsh = hyphenated[str] ---~ if not hsh then ---~ hsh = #codes + 1 ---~ hyphenated[str] = hsh ---~ codes[hsh] = str ---~ end ---~ n[a_hyphenated] = hsh ---~ end ---~ elseif id == hlist_code or id == vlist_code then ---~ injectspans(n.list) ---~ end ---~ end ---~ return head, true ---~ end ---~ ---~ nodes.injectspans = injectspans ---~ ---~ tasks.appendaction("processors", "words", "nodes.injectspans") ---~ ---~ local function injectspans(head) ---~ for n in traverse_nodes(head) do ---~ local id = n.id ---~ if id == disc then ---~ local a = 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) ---~ end ---~ elseif id == hlist_code or id == vlist_code then ---~ injectspans(n.list) ---~ end ---~ end ---~ end +-- local a_hyphenated = attributes.private('hyphenated') +-- +-- local hyphenated, codes = { }, { } +-- +-- local function compact(n) +-- local t = { } +-- for n in traverse_id(glyph_code,n) do +-- t[#t+1] = utfchar(n.char) -- check for unicode +-- end +-- return concat(t,"") +-- end +-- +-- local function injectspans(head) +-- for n in traverse_nodes(head) do +-- local id = n.id +-- if id == disc then +-- local r, p = n.replace, n.pre +-- if r and p then +-- local str = compact(r) +-- local hsh = hyphenated[str] +-- if not hsh then +-- hsh = #codes + 1 +-- hyphenated[str] = hsh +-- codes[hsh] = str +-- end +-- n[a_hyphenated] = hsh +-- end +-- elseif id == hlist_code or id == vlist_code then +-- injectspans(n.list) +-- end +-- end +-- return head, true +-- end +-- +-- nodes.injectspans = injectspans +-- +-- tasks.appendaction("processors", "words", "nodes.injectspans") +-- +-- local function injectspans(head) +-- for n in traverse_nodes(head) do +-- local id = n.id +-- if id == disc then +-- local a = 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) +-- end +-- elseif id == hlist_code or id == vlist_code then +-- injectspans(n.list) +-- end +-- end +-- end diff --git a/tex/context/base/node-aux.lua b/tex/context/base/node-aux.lua index e3fc7ad6f..16e6d55a0 100644 --- a/tex/context/base/node-aux.lua +++ b/tex/context/base/node-aux.lua @@ -43,7 +43,7 @@ local unsetvalue = attributes.unsetvalue local current_font = font.current -local texbox = tex.box +local texgetbox = tex.getbox local report_error = logs.reporter("node-aux:error") @@ -195,7 +195,7 @@ function nodes.firstcharacter(n,untagged) -- tagged == subtype > 255 end function nodes.firstcharinbox(n) - local l = texbox[n].list + local l = texgetbox(n).list if l then for g in traverse_id(glyph_code,l) do return g.char @@ -369,21 +369,3 @@ local function locate(start,wantedid,wantedsubtype) end nodes.locate = locate - -function nodes.concat(list) - local head, tail - for i=1,#list do - local li = list[i] - if not li then - -- skip - elseif head then - tail.next = li - li.prev = tail - tail = li.next and slide_nodes(li) or li - else - head = li - tail = li.next and slide_nodes(li) or li - end - end - return head, tail -end diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua index 54359117e..6d5ed6ca0 100644 --- a/tex/context/base/node-fnt.lua +++ b/tex/context/base/node-fnt.lua @@ -48,12 +48,31 @@ local run = 0 local setfontdynamics = { } local fontprocesses = { } +-- setmetatableindex(setfontdynamics, function(t,font) +-- local tfmdata = fontdata[font] +-- local shared = tfmdata.shared +-- local v = shared and shared.dynamics and otf.setdynamics or false +-- t[font] = v +-- return v +-- end) + setmetatableindex(setfontdynamics, function(t,font) local tfmdata = fontdata[font] local shared = tfmdata.shared - local v = shared and shared.dynamics and otf.setdynamics or false - t[font] = v - return v + local f = shared and shared.dynamics and otf.setdynamics or false + if f then + local v = { } + t[font] = v + setmetatableindex(v,function(t,k) + local v = f(font,k) + t[k] = v + return v + end) + return v + else + t[font] = false + return false + end end) setmetatableindex(fontprocesses, function(t,font) @@ -75,8 +94,8 @@ fonts.hashes.processes = fontprocesses function handlers.characters(head) -- either next or not, but definitely no already processed list starttiming(nodes) - local usedfonts, attrfonts, done = { }, { }, false - local a, u, prevfont, prevattr = 0, 0, nil, 0 + local usedfonts, attrfonts = { }, { } + local a, u, prevfont, prevattr, done = 0, 0, nil, 0, false if trace_fontrun then run = run + 1 report_fonts() @@ -107,16 +126,8 @@ function handlers.characters(head) attrfonts[font] = used end if not used[attr] then - local sd = setfontdynamics[font] - if sd then -- always true ? - local d = sd(font,attr) -- can we cache this one? - if d then - used[attr] = d - a = a + 1 - else - -- can't happen ... otherwise best use nil/false distinction - end - end + used[attr] = setfontdynamics[font][attr] + a = a + 1 end else local used = usedfonts[font] @@ -125,9 +136,7 @@ function handlers.characters(head) if fp then usedfonts[font] = fp u = u + 1 - else - -- can't happen ... otherwise best use nil/false distinction - end + end end end prevfont = font @@ -141,34 +150,25 @@ function handlers.characters(head) report_fonts("dynamics: %s",(a > 0 and concat(keys(attrfonts)," ")) or "none") report_fonts() end + -- in context we always have at least 2 processors if u == 0 then -- skip elseif u == 1 then local font, processors = next(usedfonts) - local n = #processors - if n > 0 then - local h, d = processors[1](head,font,0) - head = h or head - done = done or d - if n > 1 then - for i=2,n do - local h, d = processors[i](head,font,0) - head = h or head - done = done or d - end + for i=1,#processors do + local h, d = processors[i](head,font,0) + if d then + head = h or head + done = true end end else for font, processors in next, usedfonts do - local n = #processors - local h, d = processors[1](head,font,0) - head = h or head - done = done or d - if n > 1 then - for i=2,n do - local h, d = processors[i](head,font,0) + for i=1,#processors do + local h, d = processors[i](head,font,0) + if d then head = h or head - done = done or d + done = true end end end @@ -178,38 +178,22 @@ function handlers.characters(head) elseif a == 1 then local font, dynamics = next(attrfonts) for attribute, processors in next, dynamics do -- attr can switch in between - local n = #processors - if n == 0 then - report_fonts("no processors associated with dynamic %s",attribute) - else - local h, d = processors[1](head,font,attribute) - head = h or head - done = done or d - if n > 1 then - for i=2,n do - local h, d = processors[i](head,font,attribute) - head = h or head - done = done or d - end + for i=1,#processors do + local h, d = processors[i](head,font,attribute) + if d then + head = h or head + done = true end end end else for font, dynamics in next, attrfonts do for attribute, processors in next, dynamics do -- attr can switch in between - local n = #processors - if n == 0 then - report_fonts("no processors associated with dynamic %s",attribute) - else - local h, d = processors[1](head,font,attribute) - head = h or head - done = done or d - if n > 1 then - for i=2,n do - local h, d = processors[i](head,font,attribute) - head = h or head - done = done or d - end + for i=1,#processors do + local h, d = processors[i](head,font,attribute) + if d then + head = h or head + done = true end end end @@ -222,5 +206,178 @@ function handlers.characters(head) return head, true end + +-- local formatters = string.formatters + +-- local function make(processors,font,attribute) +-- _G.__temp = processors +-- local t = { } +-- for i=1,#processors do +-- if processors[i] then +-- t[#t+1] = formatters["local p_%s = _G.__temp[%s]"](i,i) +-- end +-- end +-- t[#t+1] = "return function(head,done)" +-- if #processors == 1 then +-- t[#t+1] = formatters["return p_%s(head,%s,%s)"](1,font,attribute or 0) +-- else +-- for i=1,#processors do +-- if processors[i] then +-- t[#t+1] = formatters["local h,d=p_%s(head,%s,%s) if d then head=h or head done=true end"](i,font,attribute or 0) +-- end +-- end +-- t[#t+1] = "return head, done" +-- end +-- t[#t+1] = "end" +-- t = concat(t,"\n") +-- t = load(t)(processors) +-- _G.__temp = nil +-- return t +-- end + +-- setmetatableindex(fontprocesses, function(t,font) +-- local tfmdata = fontdata[font] +-- local shared = tfmdata.shared -- we need to check shared, only when same features +-- local processes = shared and shared.processes +-- if processes and #processes > 0 then +-- processes = make(processes,font,0) +-- t[font] = processes +-- return processes +-- else +-- t[font] = false +-- return false +-- end +-- end) + +-- setmetatableindex(setfontdynamics, function(t,font) +-- local tfmdata = fontdata[font] +-- local shared = tfmdata.shared +-- local f = shared and shared.dynamics and otf.setdynamics or false +-- if f then +-- local v = { } +-- t[font] = v +-- setmetatableindex(v,function(t,k) +-- local v = f(font,k) +-- v = make(v,font,k) +-- t[k] = v +-- return v +-- end) +-- return v +-- else +-- t[font] = false +-- return false +-- end +-- end) + +-- function handlers.characters(head) +-- -- either next or not, but definitely no already processed list +-- starttiming(nodes) +-- local usedfonts, attrfonts +-- local a, u, prevfont, prevattr, done = 0, 0, nil, 0, false +-- if trace_fontrun then +-- run = run + 1 +-- report_fonts() +-- report_fonts("checking node list, run %s",run) +-- report_fonts() +-- local n = head +-- while n do +-- local id = n.id +-- if id == glyph_code then +-- local font = n.font +-- local attr = n[0] or 0 +-- report_fonts("font %03i, dynamic %03i, glyph %s",font,attr,utf.char(n.char)) +-- else +-- report_fonts("[%s]",nodecodes[n.id]) +-- end +-- n = n.next +-- 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 +-- if font ~= prevfont or attr ~= prevattr then +-- if attr > 0 then +-- if not attrfonts then +-- attrfonts = { +-- [font] = { +-- [attr] = setfontdynamics[font][attr] +-- } +-- } +-- a = 1 +-- else +-- local used = attrfonts[font] +-- if not used then +-- attrfonts[font] = { +-- [attr] = setfontdynamics[font][attr] +-- } +-- a = a + 1 +-- elseif not used[attr] then +-- used[attr] = setfontdynamics[font][attr] +-- a = a + 1 +-- end +-- end +-- else +-- if not usedfonts then +-- local fp = fontprocesses[font] +-- if fp then +-- usedfonts = { +-- [font] = fp +-- } +-- u = 1 +-- end +-- else +-- local used = usedfonts[font] +-- if not used then +-- local fp = fontprocesses[font] +-- if fp then +-- usedfonts[font] = fp +-- u = u + 1 +-- end +-- end +-- end +-- end +-- prevfont = font +-- prevattr = attr +-- end +-- -- end +-- end +-- if trace_fontrun then +-- report_fonts() +-- report_fonts("statics : %s",(u > 0 and concat(keys(usedfonts)," ")) or "none") +-- report_fonts("dynamics: %s",(a > 0 and concat(keys(attrfonts)," ")) or "none") +-- report_fonts() +-- end +-- if not usedfonts then +-- -- skip +-- elseif u == 1 then +-- local font, processors = next(usedfonts) +-- head, done = processors(head,done) +-- else +-- for font, processors in next, usedfonts do +-- head, done = processors(head,done) +-- end +-- end +-- if not attrfonts then +-- -- skip +-- elseif a == 1 then +-- local font, dynamics = next(attrfonts) +-- for attribute, processors in next, dynamics do +-- head, done = processors(head,done) +-- end +-- else +-- for font, dynamics in next, attrfonts do +-- for attribute, processors in next, dynamics do +-- head, done = processors(head,done) +-- end +-- end +-- end +-- stoptiming(nodes) +-- if trace_characters then +-- nodes.report(head,done) +-- end +-- return head, true +-- end + handlers.protectglyphs = node.protect_glyphs handlers.unprotectglyphs = node.unprotect_glyphs diff --git a/tex/context/base/node-ini.lua b/tex/context/base/node-ini.lua index 5a3986c3a..ae50215cb 100644 --- a/tex/context/base/node-ini.lua +++ b/tex/context/base/node-ini.lua @@ -13,13 +13,10 @@ modules.</p> -- this module is being reconstructed -local next, type = next, type -local format, match, gsub = string.format, string.match, string.gsub +local next, type, tostring = next, type, tostring +local gsub = string.gsub local concat, remove = table.concat, table.remove -local sortedhash, sortedkeys, swapped, tohash = table.sortedhash, table.sortedkeys, table.swapped, table.tohash -local utfchar = utf.char -local lpegmatch = lpeg.match -local formatcolumns = utilities.formatters.formatcolumns +local sortedhash, sortedkeys, swapped = table.sortedhash, table.sortedkeys, table.swapped --[[ldx-- <p>Access to nodes is what gives <l n='luatex'/> its power. Here we @@ -54,20 +51,12 @@ into the <l n='tex'/> engine, but this is a not so natural extension.</p> also ignore the empty nodes. [This is obsolete!]</p> --ldx]]-- -local traverse = node.traverse -local traverse_id = node.traverse_id -local free_node = node.free -local remove_node = node.remove -local insert_node_before = node.insert_before -local insert_node_after = node.insert_after -local node_fields = node.fields - -local allocate = utilities.storage.allocate +nodes = nodes or { } +local nodes = nodes +nodes.handlers = nodes.handlers or { } -nodes = nodes or { } -local nodes = nodes - -nodes.handlers = nodes.handlers or { } +local allocate = utilities.storage.allocate +local formatcolumns = utilities.formatters.formatcolumns -- there will be more of this: @@ -248,174 +237,4 @@ function nodes.showcodes() end end -local whatsit_node = nodecodes.whatsit - -local messyhack = tohash { -- temporary solution - nodecodes.attributelist, - nodecodes.attribute, - nodecodes.gluespec, - nodecodes.action, -} - -function nodes.fields(n) - local id = n.id - if id == whatsit_node then - return node_fields(id,n.subtype) - else - local t = node_fields(id) - if messyhack[id] then - for i=1,#t do - if t[i] == "subtype" then - remove(t,i) - break - end - end - end - return t - end -end - trackers.register("system.showcodes", nodes.showcodes) - -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist -local glue_code = nodecodes.glue - --- if t.id == glue_code then --- local s = t.spec --- print(t) --- print(s,s and s.writable) --- if s and s.writable then --- free_node(s) --- end --- t.spec = nil --- end - -local function remove(head, current, free_too) - local t = current - head, current = remove_node(head,current) - if t then - if free_too then - free_node(t) - t = nil - else - t.next = nil - t.prev = nil - end - end - return head, current, t -end - -nodes.remove = remove - -function nodes.delete(head,current) - return remove(head,current,true) -end - -nodes.before = insert_node_before -nodes.after = insert_node_after - --- we need to test this, as it might be fixed now - -function nodes.before(h,c,n) - if c then - if c == h then - n.next = h - n.prev = nil - h.prev = n - else - local cp = c.prev - n.next = c - n.prev = cp - if cp then - cp.next = n - end - c.prev = n - return h, n - end - end - return n, n -end - -function nodes.after(h,c,n) - if c then - local cn = c.next - if cn then - n.next = cn - cn.prev = n - else - n.next = nil - end - c.next = n - n.prev = c - return h, n - end - return n, n -end - --- local h, c = nodes.replace(head,current,new) --- local c = nodes.replace(false,current,new) --- local c = nodes.replace(current,new) - -function nodes.replace(head,current,new) -- no head returned if false - if not new then - head, current, new = false, head, current - end - local prev, next = current.prev, current.next - if next then - new.next = next - next.prev = new - end - if prev then - new.prev = prev - prev.next = new - end - if head then - if head == current then - head = new - end - free_node(current) - return head, new - else - free_node(current) - return new - end -end - --- will move - -local function count(stack,flat) - local n = 0 - while stack do - local id = stack.id - if not flat and id == hlist_code or id == vlist_code then - local list = stack.list - if list then - n = n + 1 + count(list) -- self counts too - else - n = n + 1 - end - else - n = n + 1 - end - stack = stack.next - end - return n -end - -nodes.count = count - -local left, space = lpeg.P("<"), lpeg.P(" ") - -local reference = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0) - -function nodes.reference(n) - return lpegmatch(reference,tostring(n)) -end - -if not node.next then - - function node.next(n) return n and n.next end - function node.prev(n) return n and n.prev end - -end diff --git a/tex/context/base/node-ini.mkiv b/tex/context/base/node-ini.mkiv index 39d48a00a..e99653327 100644 --- a/tex/context/base/node-ini.mkiv +++ b/tex/context/base/node-ini.mkiv @@ -18,6 +18,10 @@ \newcount\filterstate \filterstate\plusone % hm, public \registerctxluafile{node-ini}{1.001} +\registerctxluafile{node-met}{1.001} + +\ctxlua{if nodes.gonuts then context.registerctxluafile("node-nut","1.001") end} + \registerctxluafile{node-res}{1.001} \registerctxluafile{node-dir}{1.001} \registerctxluafile{node-aux}{1.001} diff --git a/tex/context/base/node-inj.lua b/tex/context/base/node-inj.lua index 697370cfb..abbe9b449 100644 --- a/tex/context/base/node-inj.lua +++ b/tex/context/base/node-inj.lua @@ -11,6 +11,8 @@ 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 + local next = next local utfchar = utf.char diff --git a/tex/context/base/node-ltp.lua b/tex/context/base/node-ltp.lua new file mode 100644 index 000000000..97e61cf18 --- /dev/null +++ b/tex/context/base/node-ltp.lua @@ -0,0 +1,3207 @@ +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: 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) + + 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 + + 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 = math.round +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 + +-- 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 + 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) + 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) + return 0, 0 +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 + 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 + 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 + if checked_expansion and s.subtype == kerning_code then + local d = s.kern + if d ~= 0 then + local stretch, shrink = kern_stretch_shrink(s,d) + adjust_stretch = adjust_stretch + stretch + adjust_shrink = adjust_shrink + shrink + end + end + size = size + s.kern + 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.prev = s, 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.prev = b, 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.prev = b, 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 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.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, + 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, + + font_steps = { }, -- mine + + statistics = { + + noflines = 0, + nofprotrudedlines = 0, + nofadjustedlines = 0, + + } + + } + + if adjust_spacing > 1 then + local checked_expansion = { par = par } + setmetatableindex(checked_expansion,check_expand_pars) + par.checked_expansion = checked_expansion + 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 ptr = par_shape_ptr[last_special_line] + par.second_width = ptr[2] + par.second_indent = ptr[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 + 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 + 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 + else + shortfall = shortfall + total + end + end + end + par.font_steps[line_number] = par.cur_font_step -- mine + else + par.font_steps[line_number] = 0 -- mine + 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 + active_width.size = active_width.size + cur_p.kern + if checked_expansion and cur_p.subtype == kerning_code then + local d = cur_p.kern + if d ~= 0 then + local stretch, shrink = kern_stretch_shrink(cur_p,d) + active_width.adjust_stretch = active_width.adjust_stretch + stretch + active_width.adjust_shrink = active_width.adjust_shrink + shrink + 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 .. missing font names and to many [] + +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 expansion_stack = { } -- no dealloc + +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" -- "subst_ex_font" -- is gone + + direction = direction or tex.textdir + + local pack_begin_line = 0 + 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 + elseif current.subtype == kerning_code then -- check p.kern + if cal_expand_ratio then + local stretch, shrink = kern_stretch_shrink(current,kern) + font_stretch = font_stretch + stretch + font_shrink = font_shrink + shrink + expansion_index = expansion_index + 1 + expansion_stack[expansion_index] = current + end + natural = natural + kern + else + natural = natural + kern + end + current = current.next + elseif id == disc_code then + if current.subtype ~= second_disc_code then + -- todo : local stretch, shrink = char_stretch_shrink(s) + 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 + -- -- pre post replace + -- + -- local stretch, shrink = char_stretch_shrink(current.pre) + -- font_stretch = font_stretch + stretch + -- font_shrink = font_shrink + shrink + -- expansion_index = expansion_index + 1 + -- expansion_stack[expansion_index] = current.pre + -- + 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 + 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 + if cal_expand_ratio and order == 0 and font_stretch > 0 then + font_expand_ratio = (delta/font_stretch) * 1000 -- round(delta/font_stretch * 1000) + else + 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 +-- print("stretch",hlist.glue_sign,hlist.glue_order,hlist.glue_set) + if order == 0 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,pack_begin_line,line,last_badness) + else + diagnostics.loose_hbox(hlist,pack_begin_line,line,last_badness) + end + end + end + end + else + 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 + if cal_expand_ratio and order == 0 and font_shrink > 0 then + font_expand_ratio = (delta/font_shrink) * 1000 -- round(delta/font_shrink * 1000) + else -- why was this else commented + 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 +-- print("shrink",hlist.glue_sign,hlist.glue_order,hlist.glue_set) + if total_shrink[order] < -delta and order == 0 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,pack_begin_line,line,-delta) -- - added + end + elseif order == 0 and hlist.list and last_badness > tex.hbadness then + diagnostics.bad_hbox(hlist,pack_begin_line,line,last_badness) + end + end + end + if cal_expand_ratio and font_expand_ratio ~= 0 then + -- if font_expand_ratio > 1000 then + -- font_expand_ratio = 1000 + -- elseif font_expand_ratio < -1000 then + -- font_expand_ratio = -1000 + -- end + + local fontexps, lastfont + + if font_expand_ratio > 0 then + for i=1,expansion_index do + local g = expansion_stack[i] + 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 + g.expansion_factor = font_expand_ratio * data.glyphstretch + else + local stretch, shrink = kern_stretch_shrink(g,g.kern) + g.expansion_factor = font_expand_ratio * stretch + end + end + else + for i=1,expansion_index do + local g = expansion_stack[i] + 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 + g.expansion_factor = font_expand_ratio * data.glyphshrink + else + local stretch, shrink = kern_stretch_shrink(g,g.kern) + g.expansion_factor = font_expand_ratio * shrink + end + end + end + + end + return hlist, last_badness +end + +nodes.hpack = hpack +hpack_nodes = hpack -- comment this for old fashioned expansion +xpack_nodes = hpack -- comment this for old fashioned expansion + +local function common_message(hlist,pack_begin_line,line,str) + write_nl("") + if status.output_active then -- unset + write(str," has occurred while \\output is active") + end + if pack_begin_line > 0 then + write(str," in paragraph at lines ",pack_begin_line,"--",line) + elseif pack_begin_line < 0 then + write(str," in alignment at lines ",-pack_begin_line,"--",line) + else + write(str," detected at line ",line) + 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,pack_begin_line,line,d) + common_message(hlist,pack_begin_line,line,format("Overfull \\hbox (%spt too wide)",number.toscaled(d))) +end + +function diagnostics.bad_hbox(hlist,pack_begin_line,line,b) + common_message(hlist,pack_begin_line,line,format("Tight \\hbox (badness %i)",b)) +end + +function diagnostics.underfull_hbox(hlist,pack_begin_line,line,b) + common_message(hlist,pack_begin_line,line,format("Underfull \\hbox (badness %i)",b)) +end + +function diagnostics.loose_hbox(hlist,pack_begin_line,line,b) + common_message(hlist,pack_begin_line,line,format("Loose \\hbox (badness %i)",b)) +end + +-- 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_verbose = false trackers.register("builders.paragraphs.expansion.verbose", function(v) trace_verbose = v end) + +local report_verbose = logs.reporter("fonts","expansion") + +local function colorize(n) + local size, font, ef, width, scale, 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",scale,basepoints(width),basepoints(width*scale),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 + 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 + -- scale = 1.0 + ef / 1000 / 1000 / 1000 + scale = 1.0 + ef / 1000000000 + if scale > 1 then + setnodecolor(n,"hz:positive") + elseif scale < 1 then + setnodecolor(n,"hz:negative") + else + setnodecolor(n,"hz:zero") + end + if report_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") + +trackers.register("builders.paragraphs.expansion.verbose", function(v) + if v then + tasks.enableaction("shipouts","builders.paragraphs.expansion.trace") + else + tasks.disableaction("shipouts","builders.paragraphs.expansion.trace") + end +end) diff --git a/tex/context/base/node-met.lua b/tex/context/base/node-met.lua new file mode 100644 index 000000000..aff427185 --- /dev/null +++ b/tex/context/base/node-met.lua @@ -0,0 +1,616 @@ +if not modules then modules = { } end modules ['node-nut'] = { + 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 an experimental module. Don't use nuts for generic code, at least not till +-- the regular code is proven stable. No support otherwise. + +-- luatex: todo: copylist should return h, t +-- todo: see if using insert_before and insert_after makes sense here + +-- This file is a side effect of the \LUATEX\ speed optimization project of Luigi +-- Scarso and me. As \CONTEXT\ spends over half its time in \LUA, we though that +-- using \LUAJIT\ could improve performance. We've published some of our experiences +-- elsewhere, but to summarize: \LUAJITTEX\ benefits a lot from the faster virtual +-- machine, but when jit is turned of we loose some again. We experimented with +-- ffi (without messing up the \CONTEXT\ code too much) but there we also lost more +-- than we gained (mostly due to lack of compatible userdata support: it's all or +-- nothing). This made us decide to look into the \LUA||\TEX\ interfacing and by +-- profiling and careful looking at the (of course then still beta source code) we +-- could come up with some improvements. The first showed up in 0.75 and we've more +-- on the agenda for 0.80. Although some interfaces could be sped up significantly +-- in practice we're only talking of 5||10\% on a \CONTEXT\ run and maybe more when +-- complex and extensive node list manipulations happens (we're talking of hundreds +-- of millions cross boundary calls then for documents of hundreds pages). One of the +-- changes in the \CONTEXT\ code base is that we went from indexed access to nodes to +-- function calls (in principle faster weren't it that the accessors need to do more +-- checking which makes them slower) and from there to optimizing these calls as well +-- as providing fast variants for well defined situations. At first optimizations were +-- put in a separate \type {node.fast} table although some improvements could be +-- ported to the main node functions. Because we got the feeling that more gain was +-- possible (especially when using more complex fonts and \MKIV\ functionality) we +-- eventually abandoned this approach and dropped the \type {fast} table in favour of +-- another hack. In the process we had done lots of profiling and testing so we knew +-- where time was wasted, +-- +-- As lots of testing and experimenting was part of this project, I could not have +-- done without stacks of new \CD s and \DVD s. This time Porcupine Tree, No-Man +-- and Archive were came to rescue. + +local type, select = type, select +local setmetatableindex = table.setmetatableindex + +-- First we get the metatable of a node: + +local metatable = nil + +do + local glyph = node.new("glyph",0) + metatable = getmetatable(glyph) + node.free(glyph) +end + +-- statistics.tracefunction(node, "node", "getfield","setfield") +-- statistics.tracefunction(node.direct,"node.direct","getfield","setfield") + +-- We start with some helpers and provide all relevant basic functions in the +-- node namespace as well. + +local gonuts = type(node.direct) == "table" +-- local gonuts = false + +nodes = nodes or { } +local nodes = nodes + +nodes.gonuts = gonuts + +local nodecodes = nodes.codes +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist + +nodes.tostring = node.tostring or tostring +nodes.copy = node.copy +nodes.copy_list = node.copy_list +nodes.delete = node.delete +nodes.dimensions = node.dimensions +nodes.end_of_math = node.end_of_math +nodes.flush_list = node.flush_list +nodes.flush_node = node.flush_node +nodes.free = node.free +nodes.insert_after = node.insert_after +nodes.insert_before = node.insert_before +nodes.hpack = node.hpack +nodes.new = node.new +nodes.tail = node.tail +nodes.traverse = node.traverse +nodes.traverse_id = node.traverse_id +nodes.slide = node.slide +nodes.vpack = node.vpack + +nodes.first_glyph = node.first_glyph +nodes.first_character = node.first_character +nodes.has_glyph = node.has_glyph or node.first_glyph + +nodes.current_attr = node.current_attr +nodes.do_ligature_n = node.do_ligature_n +nodes.has_field = node.has_field +nodes.last_node = node.last_node +nodes.usedlist = node.usedlist +nodes.protrusion_skippable = node.protrusion_skippable +nodes.write = node.write + +nodes.has_attribute = node.has_attribute +nodes.set_attribute = node.set_attribute +nodes.unset_attribute = node.unset_attribute + +nodes.protect_glyphs = node.protect_glyphs +nodes.unprotect_glyphs = node.unprotect_glyphs +nodes.kerning = node.kerning +nodes.ligaturing = node.ligaturing +nodes.mlist_to_hlist = node.mlist_to_hlist + + +if not gonuts or not node.getfield then + node.getfield = metatable.__index + node.setfield = metatable.__newindex +end + +if not gonuts then + nodes.tonode = function(n) return n end + nodes.todirect = function(n) return n end + nodes.tonut = function(n) return n end +end + +local getfield = node.getfield +local setfield = node.setfield + +local getattr = getfield +local setattr = setfield + +local getnext = node.getnext or function(n) return getfield(n,"next") end +local getprev = node.getprev or function(n) return getfield(n,"prev") end +local getid = node.getid or function(n) return getfield(n,"id") end +local getchar = node.getchar or function(n) return getfield(n,"char") end +local getfont = node.getfont or function(n) return getfield(n,"font") end +local getsubtype = node.getsubtype or function(n) return getfield(n,"subtype") end +local getlist = node.getlist or function(n) return getfield(n,"list") end +local getleader = node.getleader or function(n) return getfield(n,"leader") end + +nodes.getfield = getfield +nodes.getattr = getattr + +nodes.setfield = setfield +nodes.setattr = setattr + +nodes.getnext = getnext +nodes.getprev = getprev +nodes.getid = getid +nodes.getchar = getchar +nodes.getfont = getfont +nodes.getsubtype = getsubtype +nodes.getlist = getlist +nodes.getleader = getleader + +nodes.getbox = node.getbox or tex.getbox +nodes.setbox = node.setbox or tex.setbox +nodes.getskip = node.getskip or tex.get + +local n_new_node = nodes.new +local n_free_node = nodes.free +local n_setfield = nodes.setfield +local n_getfield = nodes.getfield +local n_getnext = nodes.getnext +local n_getprev = nodes.getprev +local n_getid = nodes.getid +local n_getlist = nodes.getlist +local n_copy_node = nodes.copy +local n_copy_list = nodes.copy_list +local n_find_tail = nodes.tail +local n_insert_after = nodes.insert_after +local n_insert_before = nodes.insert_before +local n_slide = nodes.slide + +local n_remove_node = node.remove -- not yet nodes.remove + +-- if t.id == glue_code then +-- local s = t.spec +-- if s and s.writable then +-- free_node(s) +-- end +-- t.spec = nil +-- end + +local function remove(head,current,free_too) + local t = current + head, current = n_remove_node(head,current) + if t then + if free_too then + n_free_node(t) + t = nil + else + n_setfield(t,"next",nil) + n_setfield(t,"prev",nil) + end + end + return head, current, t +end + +nodes.remove = remove + +function nodes.delete(head,current) + return remove(head,current,true) +end + +-- local h, c = nodes.replace(head,current,new) +-- local c = nodes.replace(false,current,new) +-- local c = nodes.replace(current,new) +-- +-- todo: check for new.next and find tail + +function nodes.replace(head,current,new) -- no head returned if false + if not new then + head, current, new = false, head, current +-- current, new = head, current + end + local prev = n_getprev(current) + local next = n_getnext(current) + if next then + n_setfield(new,"next",next) + n_setfield(next,"prev",new) + end + if prev then + n_setfield(new,"prev",prev) + n_setfield(prev,"next",new) + end + if head then + if head == current then + head = new + end + n_free_node(current) + return head, new + else + n_free_node(current) + return new + end +end + +local function count(stack,flat) + local n = 0 + while stack do + local id = n_getid(stack) + if not flat and id == hlist_code or id == vlist_code then + local list = n_getlist(stack) + if list then + n = n + 1 + count(list) -- self counts too + else + n = n + 1 + end + else + n = n + 1 + end + stack = n_getnext(stack) + end + return n +end + +nodes.count = count + +function nodes.append(head,current,...) + for i=1,select("#",...) do + head, current = n_insert_after(head,current,(select(i,...))) + end + return head, current +end + +function nodes.prepend(head,current,...) + for i=1,select("#",...) do + head, current = n_insert_before(head,current,(select(i,...))) + end + return head, current +end + +function nodes.linked(...) + local head, last + for i=1,select("#",...) do + local next = select(i,...) + if next then + if head then + n_setfield(last,"next",next) + n_setfield(next,"prev",last) + else + head = next + end + last = n_find_tail(next) -- we could skip the last one + end + end + return head +end + +function nodes.concat(list) -- consider tail instead of slide + local head, tail + for i=1,#list do + local li = list[i] + if li then + if head then + n_setfield(tail,"next",li) + n_setfield(li,"prev",tail) + else + head = li + end + tail = n_slide(li) + end + end + return head, tail +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_getfield(n,"spec") + if not spec then + spec = n_copy_node(glue_spec) + n_setfield(n,"spec",spec) + elseif not n_getfield(spec,"writable") then + spec = n_copy_node(spec) + n_setfield(n,"spec",spec) + end + return spec +end + +if gonuts then + + function nodes.reference(n) + return n and tonut(n) or "<none>" + end + +else + + local left, space = lpeg.P("<"), lpeg.P(" ") + + local reference = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0) + + function nodes.reference(n) + return n and lpegmatch(reference,tostring(n)) or "<none>" + end + +end + +-- Here starts an experiment with metatables. Of course this only works with nodes +-- wrapped in userdata with a metatable. +-- +-- Nodes are kind of special in the sense that you need to keep an eye on creation +-- and destruction. This is quite natural if you consider that changing the content +-- of a node would also change any copy (or alias). As there are too many pitfalls +-- we don't have this kind of support built in \LUATEX, which means that macro +-- packages are free to provide their own. One can even use local variants. +-- +-- n1 .. n2 : append nodes, no copies +-- n1 * 5 : append 4 copies of nodes +-- 5 + n1 : strip first 5 nodes +-- n1 - 5 : strip last 5 nodes +-- n1 + n2 : inject n2 after first of n1 +-- n1 - n2 : inject n2 before last of n1 +-- n1^2 : two copies of nodes (keep orginal) +-- - n1 : reverse nodes +-- n1/f : apply function to nodes + +-- local s = nodes.typesetters.tonodes +-- +-- local function w(lst) +-- context.dontleavehmode() +-- context(lst) +-- context.par() +-- end +-- +-- local n1 = s("a") +-- local n2 = s("b") +-- local n3 = s("c") +-- local n4 = s("d") +-- local n5 = s("e") +-- local n6 = s("f") +-- local n7 = s("g") +-- +-- local n0 = n1 .. (n2 * 10).. n3 .. (5 * n4) .. n5 .. ( 5 * n6 ) .. n7 / function(n) n.char = string.byte("!") return n end +-- +-- w(#n0) +-- +-- w(n0) +-- +-- local n1 = s("a") * 10 +-- local n2 = s("b") * 10 +-- +-- local n0 = ((5 + n1) .. (n2 - 5) ) +-- local n0 = - n0 +-- +-- local n0 = nil .. n0^3 .. nil +-- +-- w(n0) +-- +-- w ( s("a") + s("b") ) w ( s("a") + 4*s("b") ) w ( 4*s("a") + s("b") ) w ( 4*s("a") + 4*s("b") ) +-- w ( s("a") - s("b") ) w ( s("a") - 4*s("b") ) w ( 4*s("a") - s("b") ) w ( 4*s("a") - 4*s("b") ) + +local n_remove_node = nodes.remove + +metatable.__concat = function(n1,n2) -- todo: accept nut on one end + if not n1 then + return n2 + elseif not n2 then + return n1 + elseif n1 == n2 then + -- or abort + return n2 -- or n2 * 2 + else + local tail = n_find_tail(n1) + n_setfield(tail,"next",n2) + n_setfield(n2,"prev",tail) + return n1 + end +end + +metatable.__mul = function(n,multiplier) + if type(multiplier) ~= "number" then + n, multiplier = multiplier, n + end + if multiplier <= 1 then + return n + elseif n_getnext(n) then + local head + for i=2,multiplier do + local h = n_copy_list(n) + if head then + local t = n_find_tail(h) + n_setfield(t,"next",head) + n_setfield(head,"prev",t) + end + head = h + end + local t = n_find_tail(n) + n_setfield(t,"next",head) + n_setfield(head,"prev",t) + else + local head + for i=2,multiplier do + local c = n_copy_node(n) + if head then + n_setfield(c,"next",head) + n_setfield(head,"prev",c) + end + head = c + end + n_setfield(n,"next",head) + n_setfield(head,"prev",n) + end + return n +end + +metatable.__sub = function(first,second) + if type(second) == "number" then + local tail = n_find_tail(first) + for i=1,second do + local prev = n_getfield(tail,"prev") + n_free_node(tail) -- can become flushlist/flushnode + if prev then + tail = prev + else + return nil + end + end + if tail then + n_setfield(tail,"next",nil) + return first + else + return nil + end + else + -- aaaaa - bbb => aaaabbba + local firsttail = n_find_tail(first) + local prev = n_getprev(firsttail) + if prev then + local secondtail = n_find_tail(second) + n_setfield(secondtail,"next",firsttail) + n_setfield(firsttail,"prev",ltail) + n_setfield(prev,"next",second) + n_setfield(second,"prev",prev) + return first + else + local secondtail = n_find_tail(second) + n_setfield(secondtail,"next",first) + n_setfield(first,"prev",ltail) + return second + end + end +end + +metatable.__add = function(first,second) + if type(first) == "number" then + local head = second + for i=1,first do + local second = n_getnext(head) + n_free_node(head) -- can become flushlist/flushnode + if second then + head = second + else + return nil + end + end + if head then + n_setfield(head,"prev",nil) + return head + else + return nil + end + else + -- aaaaa + bbb => abbbaaaa + local next = n_getnext(first) + if next then + local secondtail = n_find_tail(second) + n_setfield(first,"next",second) + n_setfield(second,"prev",first) + n_setfield(secondtail,"next",next) + n_setfield(next,"prev",secondtail) + else + n_setfield(first,"next",second) + n_setfield(second,"prev",first) + end + return first + end +end + +metatable.__len = function(current) + local length = 0 + while current do + current = n_getnext(current) + length = length + 1 + end + return length +end + +metatable.__div = function(list,action) + return action(list) or list -- always a value +end + +metatable.__pow = function(n,multiplier) + local tail = n + local head = nil + if getnext(n) then + if multiplier == 1 then + head = n_copy_list(n) + else + for i=1,multiplier do + local h = n_copy_list(n) + if head then + local t = n_find_tail(h) + n_setfield(t,"next",head) + n_setfield(head,"prev",t) + end + head = h + end + end + else + if multiplier == 1 then + head = n_copy_node(n) + else + for i=2,multiplier do + local c = n_copy_node(n) + if head then + n_setfield(head,"next",c) + n_setfield(c,"prev",head) + end + head = c + end + end + end + -- todo: tracing + return head +end + +metatable.__unm = function(head) + local last = head + local first = head + local current = n_getnext(head) + while current do + local next = n_getnext(current) + n_setfield(first,"prev",current) + n_setfield(current,"next",first) + first = current + current = next + end + n_setfield(first,"prev",nil) + n_setfield(last,"next",nil) + return first +end + +-- see node-nut.lua for more info on going nuts + +if not gonuts then + + local nuts = { } + nodes.nuts = nuts + + local function dummy(f) return f end + + nodes.vianuts = dummy + nodes.vianodes = dummy + + for k, v in next, nodes do + if type(v) == "function" then + nuts[k] = v + end + end + +end diff --git a/tex/context/base/node-pro.lua b/tex/context/base/node-pro.lua index b98292abb..aa6692d7b 100644 --- a/tex/context/base/node-pro.lua +++ b/tex/context/base/node-pro.lua @@ -66,36 +66,12 @@ processors.tracer = tracer 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 --- if found then --- if trace_callbacks then --- local before = nodes.count(head,true) --- local head, done = actions(head,groupcode,size,packtype,direction) -- todo : pass first --- local after = nodes.count(head,true) --- if done then --- tracer("pre_linebreak","changed",head,groupcode,before,after,true) --- else --- tracer("pre_linebreak","unchanged",head,groupcode,before,after,true) --- end --- return done and head or true --- else --- local head, done = actions(head,groupcode,size,packtype,direction) -- todo : pass first --- return done and head or true --- end --- elseif trace_callbacks then --- local n = nodes.count(head,false) --- tracer("pre_linebreak","no chars",head,groupcode,n,n) --- end --- return true --- end - -function processors.pre_linebreak_filter(head,groupcode) +function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction local first, found = first_glyph(head) -- they really need to be glyphs if found then if trace_callbacks then local before = nodes.count(head,true) - local head, done = actions(head,groupcode) + local head, done = actions(head,groupcode) -- ,size,packtype,direction local after = nodes.count(head,true) if done then tracer("pre_linebreak","changed",head,groupcode,before,after,true) @@ -104,7 +80,7 @@ function processors.pre_linebreak_filter(head,groupcode) end return done and head or true else - local head, done = actions(head,groupcode) + local head, done = actions(head,groupcode) -- ,size,packtype,direction return done and head or true end elseif trace_callbacks then diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua index 09e066434..baece6e50 100644 --- a/tex/context/base/node-ref.lua +++ b/tex/context/base/node-ref.lua @@ -16,61 +16,60 @@ if not modules then modules = { } end modules ['node-ref'] = { -- is grouplevel still used? -local format = string.format - -local allocate, mark = utilities.storage.allocate, utilities.storage.mark +local attributes, nodes, node = attributes, nodes, node -local cleanupreferences, cleanupdestinations = false, true +local allocate = utilities.storage.allocate, utilities.storage.mark +local mark = utilities.storage.allocate, utilities.storage.mark -local attributes, nodes, node = attributes, nodes, node -local nodeinjections = backends.nodeinjections -local codeinjections = backends.codeinjections +local nodeinjections = backends.nodeinjections +local codeinjections = backends.codeinjections -local transparencies = attributes.transparencies -local colors = attributes.colors -local references = structures.references -local tasks = nodes.tasks +local cleanupreferences = false +local cleanupdestinations = true -local hpack_list = node.hpack -local list_dimensions = node.dimensions +local transparencies = attributes.transparencies +local colors = attributes.colors +local references = structures.references +local tasks = nodes.tasks --- current.glue_set current.glue_sign +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) +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) -local report_reference = logs.reporter("backend","references") -local report_destination = logs.reporter("backend","destinations") -local report_area = logs.reporter("backend","areas") +local report_reference = logs.reporter("backend","references") +local report_destination = logs.reporter("backend","destinations") +local report_area = logs.reporter("backend","areas") -local nodecodes = nodes.nodecodes -local skipcodes = nodes.skipcodes -local whatcodes = nodes.whatcodes -local listcodes = nodes.listcodes +local nodecodes = nodes.nodecodes +local skipcodes = nodes.skipcodes +local whatcodes = nodes.whatcodes +local listcodes = nodes.listcodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist -local glue_code = nodecodes.glue -local whatsit_code = nodecodes.whatsit +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local glue_code = nodecodes.glue +local whatsit_code = nodecodes.whatsit -local leftskip_code = skipcodes.leftskip -local rightskip_code = skipcodes.rightskip -local parfillskip_code = skipcodes.parfillskip +local leftskip_code = skipcodes.leftskip +local rightskip_code = skipcodes.rightskip +local parfillskip_code = skipcodes.parfillskip -local localpar_code = whatcodes.localpar -local dir_code = whatcodes.dir +local localpar_code = whatcodes.localpar +local dir_code = whatcodes.dir -local line_code = listcodes.line +local line_code = listcodes.line -local nodepool = nodes.pool +local nodepool = nodes.pool -local new_kern = nodepool.kern +local new_kern = nodepool.kern -local traverse = node.traverse -local find_node_tail = node.tail or node.slide -local tosequence = nodes.tosequence +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 @@ -362,20 +361,19 @@ local function colorize(width,height,depth,n,reference,what) end end -local nodepool = nodes.pool +-- references: -local new_kern = nodepool.kern +local nodepool = nodes.pool +local new_kern = nodepool.kern -local texattribute = tex.attribute -local texcount = tex.count +local texsetattribute = tex.setattribute +local texsetcount = tex.setcount --- references: - -local stack = { } -local done = { } -local attribute = attributes.private('reference') -local nofreferences = 0 -local topofstack = 0 +local stack = { } +local done = { } +local attribute = attributes.private('reference') +local nofreferences = 0 +local topofstack = 0 nodes.references = { attribute = attribute, @@ -390,8 +388,8 @@ local function setreference(h,d,r) -- the preroll permits us to determine samepage (but delayed also has some advantages) -- so some part of the backend work is already done here stack[topofstack] = { r, h, d, codeinjections.prerollreference(r) } - -- texattribute[attribute] = topofstack -- todo -> at tex end - texcount.lastreferenceattribute = topofstack + -- texsetattribute(attribute,topofstack) -- todo -> at tex end + texsetcount("lastreferenceattribute",topofstack) end function references.get(n) -- not public so functionality can change @@ -540,7 +538,7 @@ function references.inject(prefix,reference,h,d,highlight,newwindow,layer) -- to -- unknown ref, just don't set it and issue an error else -- check - set.highlight, set.newwindow,set.layer = highlight, newwindow, layer + set.highlight, set.newwindow, set.layer = highlight, newwindow, layer setreference(h,d,set) -- sets attribute / todo: for set[*].error end end @@ -573,7 +571,7 @@ end statistics.register("interactive elements", function() if nofreferences > 0 or nofdestinations > 0 then - return format("%s references, %s destinations",nofreferences,nofdestinations) + return string.format("%s references, %s destinations",nofreferences,nofdestinations) else return nil end diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua index 768aac404..ca9d67f91 100644 --- a/tex/context/base/node-res.lua +++ b/tex/context/base/node-res.lua @@ -35,6 +35,9 @@ 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) @@ -57,11 +60,10 @@ function pool.cleanup(nofboxes) -- todo -- end end if nofboxes then - local tb = tex.box for i=0,nofboxes do - local l = tb[i] + local l = texgetbox(i) if l then - free_node(tb[i]) + free_node(l) -- also list ? nl = nl + 1 end end @@ -293,12 +295,38 @@ function pool.noad() return copy_node(noad) end -function pool.hlist() - return copy_node(hlist) +function pool.hlist(list,width,height,depth) + local n = copy_node(hlist) + if list then + n.list = list + end + if width then + n.width = width + end + if height then + n.height = height + end + if depth then + n.depth = depth + end + return n end -function pool.vlist() - return copy_node(vlist) +function pool.vlist(list,width,height,depth) + local n = copy_node(vlist) + if list then + n.list = list + end + if width then + n.width = width + end + if height then + n.height = height + end + if depth then + n.depth = depth + end + return n end --[[ @@ -396,7 +424,7 @@ function pool.special(str) end statistics.register("cleaned up reserved nodes", function() - return format("%s nodes, %s lists of %s", pool.cleanup(tex.count["c_syst_last_allocated_box"])) + return format("%s nodes, %s lists of %s", pool.cleanup(texgetcount("c_syst_last_allocated_box"))) end) -- \topofboxstack statistics.register("node memory usage", function() -- comes after cleanup ! diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua index 953beb186..5c64c0113 100644 --- a/tex/context/base/node-rul.lua +++ b/tex/context/base/node-rul.lua @@ -85,6 +85,9 @@ local variables = interfaces.variables local dimenfactor = fonts.helpers.dimenfactor local splitdimen = number.splitdimen +local v_yes = variables.yes +local v_foreground = variables.foreground + local nodecodes = nodes.nodecodes local skipcodes = nodes.skipcodes local whatcodes = nodes.whatcodes @@ -150,7 +153,7 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi else -- possible extensions: when in same class then keep spanning local newlevel, newclass = floor(aa/1000), aa%1000 ---~ strip = not continue or level == 1 -- 0 + -- strip = not continue or level == 1 -- 0 if f then if class == newclass then -- and newlevel > level then head, done = flush(head,f,l,d,level,parent,false), true @@ -161,7 +164,7 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi f, l, a = n, n, aa level, class = newlevel, newclass d = data[class] - continue = d.continue == variables.yes + continue = d.continue == v_yes end else if f then @@ -169,8 +172,16 @@ 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 - l = n +-- elseif f and (id == disc_code or (id == kern_code and n.subtype == 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 + if f then + l = n + end elseif id == hlist_code or id == vlist_code then if f then head, done = flush(head,f,l,d,level,parent,strip), true @@ -188,13 +199,12 @@ local function processwords(attribute,data,flush,head,parent) -- we have hlistdi if continue then if id == penalty_code then l = n - elseif id == kern_code then - l = n + -- elseif id == kern_code then + -- l = n elseif id == glue_code then -- catch \underbar{a} \underbar{a} (subtype test is needed) local subtype = n.subtype - if continue and n[attribute] and - (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_code) then + if n[attribute] and (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_code) then l = n else head, done = flush(head,f,l,d,level,parent,strip), true @@ -261,7 +271,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a 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 foreground = order == variables.foreground + local foreground = order == v_foreground local e = dimenfactor(unit,fontdata[f.font]) -- what if no glyph node diff --git a/tex/context/base/node-ser.lua b/tex/context/base/node-ser.lua index 70743123c..ab59616bc 100644 --- a/tex/context/base/node-ser.lua +++ b/tex/context/base/node-ser.lua @@ -18,8 +18,8 @@ local context = context local nodes = nodes local node = node -local traverse = node.traverse -local is_node = node.is_node +local traverse = nodes.traverse +local is_node = nodes.is_node local nodecodes = nodes.nodecodes local noadcodes = nodes.noadcodes diff --git a/tex/context/base/node-shp.lua b/tex/context/base/node-shp.lua index 8f7a411a7..32024e5da 100644 --- a/tex/context/base/node-shp.lua +++ b/tex/context/base/node-shp.lua @@ -24,7 +24,7 @@ local mark_code = nodecodes.mark local kern_code = nodecodes.kern local glue_code = nodecodes.glue -local texbox = tex.box +local texgetbox = tex.getbox local free_node = node.free local remove_node = node.remove @@ -73,7 +73,7 @@ end -- interface function commands.finalizebox(n) - actions(texbox[n]) + actions(texgetbox(n)) end -- just in case we want to optimize lookups: @@ -129,8 +129,8 @@ trackers.register("nodes.frequencies",function(v) if type(v) == "string" then frequencies.filename = v end - handlers.frequencies_shipouts_before = register("shipouts", "begin") - handlers.frequencies_shipouts_after = register("shipouts", "end") + handlers.frequencies_shipouts_before = register("shipouts", "begin") + handlers.frequencies_shipouts_after = register("shipouts", "end") handlers.frequencies_processors_before = register("processors", "begin") handlers.frequencies_processors_after = register("processors", "end") tasks.prependaction("shipouts", "before", "nodes.handlers.frequencies_shipouts_before") diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua index 916b2143d..bfdfa543b 100644 --- a/tex/context/base/node-tra.lua +++ b/tex/context/base/node-tra.lua @@ -22,6 +22,8 @@ nodes = nodes or { } local nodes, node, context = nodes, node, context +local texgetattribute = tex.getattribute + local tracers = nodes.tracers or { } nodes.tracers = tracers @@ -57,6 +59,7 @@ 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 @@ -342,7 +345,7 @@ local function numbertodimen(d,unit,fmt,strip) local str = formatters[fmt](d*dimenfactors[unit],unit) return strip and lpegmatch(stripper,str) or str end - local id = node.id + local id = d.id if id == kern_code then local str = formatters[fmt](d.width*dimenfactors[unit],unit) return strip and lpegmatch(stripper,str) or str @@ -522,8 +525,49 @@ end -- for the moment here -nodes.visualizers = { } +local visualizers = nodes.visualizers or { } +nodes.visualizers = visualizers -function nodes.visualizers.handler(head) +function visualizers.handler(head) return head, false end + +-- we could cache attribute lists and set attr (copy will increment count) .. todo .. +-- although tracers are used seldom + +local function setproperties(n,c,s) + 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] + return n +end + +tracers.setproperties = setproperties + +function tracers.setlistv(n,c,s) + local f = 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 + end + return f +end + +function tracers.resetproperties(n) + n[a_color] = unsetvalue + n[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 diff --git a/tex/context/base/node-typ.lua b/tex/context/base/node-typ.lua index 6e1a31643..4a2ef8d49 100644 --- a/tex/context/base/node-typ.lua +++ b/tex/context/base/node-typ.lua @@ -6,21 +6,23 @@ if not modules then modules = { } end modules ['node-typ'] = { license = "see context related readme files" } -local utfvalues = utf.values +-- code has been moved to blob-ini.lua -local currentfont = font.current -local fontparameters = fonts.hashes.parameters +local typesetters = nodes.typesetters or { } +nodes.typesetters = typesetters -local hpack = node.hpack -local vpack = node.vpack -local fast_hpack = nodes.fasthpack +local hpack_node_list = nodes.hpack +local vpack_node_list = nodes.vpack +local fast_hpack_list = nodes.fasthpack -local nodepool = nodes.pool +local nodepool = nodes.pool +local new_glyph = nodepool.glyph +local new_glue = nodepool.glue -local newglyph = nodepool.glyph -local newglue = nodepool.glue +local utfvalues = utf.values -typesetters = typesetters or { } +local currentfont = font.current +local fontparameters = fonts.hashes.parameters local function tonodes(str,fontid,spacing) -- quick and dirty local head, prev = nil, nil @@ -39,11 +41,11 @@ local function tonodes(str,fontid,spacing) -- quick and dirty local next if c == 32 then if not spacedone then - next = newglue(s,p,m) + next = new_glue(s,p,m) spacedone = true end else - next = newglyph(fontid or 1,c) + next = new_glyph(fontid or 1,c) spacedone = false end if not next then @@ -59,21 +61,33 @@ local function tonodes(str,fontid,spacing) -- quick and dirty return head end -typesetters.tonodes = tonodes - -function typesetters.hpack(str,fontid,spacing) - return hpack(tonodes(str,fontid,spacing),"exactly") +local function tohpack(str,fontid,spacing) + return hpack_node_list(tonodes(str,fontid,spacing),"exactly") end -function typesetters.fast_hpack(str,fontid,spacing) - return fast_hpack(tonodes(str,fontid,spacing),"exactly") +local function tohpackfast(str,fontid,spacing) + return fast_hpack_list(tonodes(str,fontid,spacing),"exactly") end -function typesetters.vpack(str,fontid,spacing) +local function tovpack(str,fontid,spacing) -- vpack is just a hack, and a proper implentation is on the agenda -- as it needs more info etc than currently available - return vpack(tonodes(str,fontid,spacing)) + return vpack_node_list(tonodes(str,fontid,spacing)) end ---~ node.write(typesetters.hpack("Hello World!")) ---~ node.write(typesetters.hpack("Hello World!",1,100*1024*10)) +local tovpackfast = tovpack + +typesetters.tonodes = tonodes +typesetters.tohpack = tohpack +typesetters.tohpackfast = tohpackfast +typesetters.tovpack = tovpack +typesetters.tovpackfast = tovpackfast + +typesetters.hpack = tohpack +typesetters.fast_hpack = tohpackfast +typesetters.vpack = tovpack + +-- node.write(nodes.typestters.hpack("Hello World!")) +-- node.write(nodes.typestters.hpack("Hello World!",1,100*1024*10)) + +string.tonodes = tonodes -- quite convenient diff --git a/tex/context/base/pack-obj.lua b/tex/context/base/pack-obj.lua index 1e4e0f59e..70876a346 100644 --- a/tex/context/base/pack-obj.lua +++ b/tex/context/base/pack-obj.lua @@ -13,8 +13,7 @@ reusable components.</p> local commands, context = commands, context -local texcount = tex.count -local allocate = utilities.storage.allocate +local allocate = utilities.storage.allocate local collected = allocate() local tobesaved = allocate() diff --git a/tex/context/base/pack-rul.lua b/tex/context/base/pack-rul.lua index a990936e7..909c0c168 100644 --- a/tex/context/base/pack-rul.lua +++ b/tex/context/base/pack-rul.lua @@ -10,16 +10,21 @@ if not modules then modules = { } end modules ['pack-rul'] = { <p>An explanation is given in the history document <t>mk</t>.</p> --ldx]]-- -local texsetdimen, texsetcount, texbox = tex.setdimen, tex.setcount, tex.box -local hpack, free, copy, traverse_id = node.hpack, node.free, node.copy_list, node.traverse_id -local texdimen, texcount = tex.dimen, tex.count +local hpack = node.hpack +local free = node.free +local copy = node.copy_list +local traverse_id = node.traverse_id +local node_dimensions = node.dimensions local hlist_code = nodes.nodecodes.hlist local box_code = nodes.listcodes.box -local node_dimensions = node.dimensions + +local texsetdimen = tex.setdimen +local texsetcount = tex.setcount +local texgetbox = tex.getbox function commands.doreshapeframedbox(n) - local box = texbox[n] + local box = texgetbox(n) local noflines = 0 local firstheight = nil local lastdepth = nil @@ -76,17 +81,16 @@ function commands.doreshapeframedbox(n) end end end - -- print("reshape", noflines, firstheight or 0, lastdepth or 0) - texsetcount("global","framednoflines", noflines) - texsetdimen("global","framedfirstheight", firstheight or 0) - texsetdimen("global","framedlastdepth", lastdepth or 0) - texsetdimen("global","framedminwidth", minwidth) - texsetdimen("global","framedmaxwidth", maxwidth) - texsetdimen("global","framedaveragewidth", noflines > 0 and totalwidth/noflines or 0) + texsetcount("global","framednoflines",noflines) + texsetdimen("global","framedfirstheight",firstheight or 0) + texsetdimen("global","framedlastdepth",lastdepth or 0) + texsetdimen("global","framedminwidth",minwidth) + texsetdimen("global","framedmaxwidth",maxwidth) + texsetdimen("global","framedaveragewidth",noflines > 0 and totalwidth/noflines or 0) end function commands.doanalyzeframedbox(n) - local box = texbox[n] + local box = texgetbox(n) local noflines = 0 local firstheight = nil local lastdepth = nil @@ -102,8 +106,7 @@ function commands.doanalyzeframedbox(n) end end end - -- print("analyze", noflines, firstheight or 0, lastdepth or 0) - texsetcount("global","framednoflines", noflines) - texsetdimen("global","framedfirstheight", firstheight or 0) - texsetdimen("global","framedlastdepth", lastdepth or 0) + texsetcount("global","framednoflines",noflines) + texsetdimen("global","framedfirstheight",firstheight or 0) + texsetdimen("global","framedlastdepth",lastdepth or 0) end diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv index e7db332b4..a591e5576 100644 --- a/tex/context/base/pack-rul.mkiv +++ b/tex/context/base/pack-rul.mkiv @@ -1749,17 +1749,45 @@ \edef\currentmathframed{#1}% \dosingleempty\pack_framed_mathframed_indeed} +% \def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here +% {\iffirstargument +% \setupcurrentmathframed[#1]% +% \fi +% \c_framed_mstyle\mathstyle +% \doifnot{\mathframedparameter\c!location}\v!low{\let\normalstrut\pack_framed_math_strut}% +% \inheritedmathframedframed{\Ustartmath\triggermathstyle\c_framed_mstyle#2\Ustopmath}% +% \endgroup} + +\newcount\c_pack_framed_mc + +\def\pack_framed_math_pos + {\global\advance\c_pack_framed_mc\plusone + \xdef\pack_framed_mc_one{mcf:1:\number\c_pack_framed_mc}% + \xdef\pack_framed_mc_two{mcf:2:\number\c_pack_framed_mc}% + \xypos\pack_framed_mc_two} + \def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here {\iffirstargument \setupcurrentmathframed[#1]% \fi \c_framed_mstyle\mathstyle - \doifnot{\mathframedparameter\c!location}\v!low{\let\normalstrut\pack_framed_math_strut}% + \edef\m_framed_location{\mathframedparameter\c!location}% + \ifx\m_framed_location\v!mathematics + \let\normalstrut\pack_framed_math_pos + \else\ifx\m_framed_location\v!low\else + \let\normalstrut\pack_framed_math_strut + \fi\fi \inheritedmathframedframed{\Ustartmath\triggermathstyle\c_framed_mstyle#2\Ustopmath}% \endgroup} +\installframedlocator \v!mathematics + {} + {\lower\dimexpr\MPy\pack_framed_mc_two-\MPy\pack_framed_mc_one\relax + \hbox{\xypos\pack_framed_mc_one\box\b_framed_normal}} + \definemathframed[mframed] \definemathframed[inmframed][\c!location=\v!low] +\definemathframed[mcframed] [\c!location=\v!mathematics] %D So instead of the rather versatile \type {\framed}, we use \type {\mframed}: %D diff --git a/tex/context/base/page-app.mkiv b/tex/context/base/page-app.mkiv index 5f1c2f297..272245cce 100644 --- a/tex/context/base/page-app.mkiv +++ b/tex/context/base/page-app.mkiv @@ -106,7 +106,7 @@ \fi \d_page_fitting_width \wd\b_page_fitting \d_page_fitting_height\ht\b_page_fitting - \startlocallayout % still valid? +% wrong now: \startlocallayout % still valid? \let\checkcurrentlayout\relax % else interference with odd/even layout \processaction [\fittingpageparameter\c!paper] @@ -117,7 +117,7 @@ \startmakeup[fittingpage]% \box\b_page_fitting \stopmakeup - \stoplocallayout % still valid? +% wrong now: \stoplocallayout % still valid? \egroup \autostoptext} diff --git a/tex/context/base/page-flt.lua b/tex/context/base/page-flt.lua index ab7a534eb..11aa2be21 100644 --- a/tex/context/base/page-flt.lua +++ b/tex/context/base/page-flt.lua @@ -11,9 +11,6 @@ if not modules then modules = { } end modules ['page-flt'] = { local insert, remove = table.insert, table.remove local find = string.find -local setdimen, setcount, texbox = tex.setdimen, tex.setcount, tex.box - -local copy_node_list = node.copy_list local trace_floats = false trackers.register("graphics.floats", function(v) trace_floats = v end) -- name might change @@ -24,10 +21,20 @@ local C, S, P, lpegmatch = lpeg.C, lpeg.S, lpeg.P, lpeg.match -- we use floatbox, floatwidth, floatheight -- text page leftpage rightpage (todo: top, bottom, margin, order) -floats = floats or { } -local floats = floats +local copy_node_list = node.copy_list + +local setdimen = tex.setdimen +local setcount = tex.setcount +local texgetbox = tex.getbox +local texsetbox = tex.setbox + +floats = floats or { } +local floats = floats -local noffloats, last, default, pushed = 0, nil, "text", { } +local noffloats = 0 +local last = nil +local default = "text" +local pushed = { } local function initialize() return { @@ -98,7 +105,7 @@ end function floats.save(which,data) which = which or default - local b = texbox.floatbox + local b = texgetbox("floatbox") if b then local stack = stacks[which] noffloats = noffloats + 1 @@ -108,7 +115,7 @@ function floats.save(which,data) data = data or { }, box = copy_node_list(b), } - texbox.floatbox = nil + texsetbox("floatbox",nil) insert(stack,t) setcount("global","savednoffloats",#stacks[default]) if trace_floats then @@ -125,10 +132,10 @@ function floats.resave(which) if last then which = which or default local stack = stacks[which] - local b = texbox.floatbox + local b = texgetbox("floatbox") local w, h, d = b.width, b.height, b.depth last.box = copy_node_list(b) - texbox.floatbox = nil + texsetbox("floatbox",nil) insert(stack,1,last) setcount("global","savednoffloats",#stacks[default]) if trace_floats then @@ -152,7 +159,7 @@ function floats.flush(which,n,bylabel) else interfaces.showmessage("floatblocks",3,t.n) end - texbox.floatbox = b + texsetbox("floatbox",b) last = remove(stack,n) last.box = nil setcount("global","savednoffloats",#stacks[default]) -- default? diff --git a/tex/context/base/page-inj.lua b/tex/context/base/page-inj.lua index f9b56fddb..56e5a234e 100644 --- a/tex/context/base/page-inj.lua +++ b/tex/context/base/page-inj.lua @@ -8,6 +8,8 @@ if not modules then modules = { } end modules ["page-inj"] = { -- Adapted a bit by HH: numbered states, tracking, delayed, order, etc. +local type, tonumber = type, tonumber + local injections = pagebuilders.injections or { } pagebuilders.injections = injections @@ -19,6 +21,8 @@ local variables = interfaces.variables local context = context local commands = commands +local texsetcount = tex.setcount + local v_yes = variables.yes local v_previous = variables.previous local v_next = variables.next @@ -34,7 +38,7 @@ function injections.save(specification) -- maybe not public, just commands.* state = tonumber(specification.state) or specification.state, parameters = specification.userdata, } - tex.setcount("global","c_page_boxes_flush_n",#cache) + texsetcount("global","c_page_boxes_flush_n",#cache) end function injections.flushbefore() -- maybe not public, just commands.* @@ -65,7 +69,7 @@ function injections.flushbefore() -- maybe not public, just commands.* end context.unprotect() cache = delayed - tex.setcount("global","c_page_boxes_flush_n",#cache) + texsetcount("global","c_page_boxes_flush_n",#cache) end end @@ -95,7 +99,7 @@ function injections.flushafter() -- maybe not public, just commands.* end context.protect() cache = delayed - tex.setcount("global","c_page_boxes_flush_n",#cache) + texsetcount("global","c_page_boxes_flush_n",#cache) end end diff --git a/tex/context/base/page-lin.lua b/tex/context/base/page-lin.lua index e6b500e8b..7e8e9ad8a 100644 --- a/tex/context/base/page-lin.lua +++ b/tex/context/base/page-lin.lua @@ -12,8 +12,6 @@ local trace_numbers = false trackers.register("lines.numbers", function(v) tra local report_lines = logs.reporter("lines") -local texbox = tex.box - local attributes, nodes, node, context = attributes, nodes, node, context nodes.lines = nodes.lines or { } @@ -23,6 +21,8 @@ lines.data = lines.data or { } -- start step tag local data = lines.data local last = #data +local texgetbox = tex.getbox + lines.scratchbox = lines.scratchbox or 0 local leftmarginwidth = nodes.leftmarginwidth @@ -208,7 +208,7 @@ local function identify(list) end function boxed.stage_zero(n) - return identify(texbox[n].list) + return identify(texgetbox(n).list) end -- reset ranges per page @@ -217,9 +217,9 @@ end function boxed.stage_one(n,nested) current_list = { } - local head = texbox[n] - if head then - local list = head.list + local box = texgetbox(n) + if box then + local list = box.list if nested then list = identify(list) end @@ -268,7 +268,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,texbox[m].list) do + for l in traverse_id(hlist_code,texgetbox(m).list) do tn = tn + 1 t[tn] = copy_node(l) end diff --git a/tex/context/base/page-lin.mkiv b/tex/context/base/page-lin.mkiv index 0f8b78398..876d2e781 100644 --- a/tex/context/base/page-lin.mkiv +++ b/tex/context/base/page-lin.mkiv @@ -156,28 +156,28 @@ % todo: text -\installcorenamespace{linennumberinglocation} -\installcorenamespace{linennumberingalternative} - -\expandafter\let\csname\??linennumberinglocation\v!middle \endcsname \zerocount -\expandafter\let\csname\??linennumberinglocation\v!left \endcsname \plusone -\expandafter\let\csname\??linennumberinglocation\v!margin \endcsname \plusone -\expandafter\let\csname\??linennumberinglocation\v!inmargin \endcsname \plusone -\expandafter\let\csname\??linennumberinglocation\v!inleft \endcsname \plusone -\expandafter\let\csname\??linennumberinglocation\v!right \endcsname \plustwo -\expandafter\let\csname\??linennumberinglocation\v!inright \endcsname \plustwo -\expandafter\let\csname\??linennumberinglocation\v!inner \endcsname \plusthree -\expandafter\let\csname\??linennumberinglocation\v!outer \endcsname \plusfour -\expandafter\let\csname\??linennumberinglocation\v!text \endcsname \plusfive -\expandafter\let\csname\??linennumberinglocation\v!begin \endcsname \plussix -\expandafter\let\csname\??linennumberinglocation\v!end \endcsname \plusseven - -\expandafter\let\csname\??linennumberingalternative\v!middle \endcsname \zerocount -\expandafter\let\csname\??linennumberingalternative\v!right \endcsname \plusone -\expandafter\let\csname\??linennumberingalternative\v!flushleft \endcsname \plusone -\expandafter\let\csname\??linennumberingalternative\v!left \endcsname \plustwo -\expandafter\let\csname\??linennumberingalternative\v!flushright\endcsname \plustwo -\expandafter\let\csname\??linennumberingalternative\v!auto \endcsname \plusfive +\installcorenamespace{linenumberinglocation} +\installcorenamespace{linenumberingalternative} + +\expandafter\let\csname\??linenumberinglocation\v!middle \endcsname \zerocount +\expandafter\let\csname\??linenumberinglocation\v!left \endcsname \plusone +\expandafter\let\csname\??linenumberinglocation\v!margin \endcsname \plusone +\expandafter\let\csname\??linenumberinglocation\v!inmargin \endcsname \plusone +\expandafter\let\csname\??linenumberinglocation\v!inleft \endcsname \plusone +\expandafter\let\csname\??linenumberinglocation\v!right \endcsname \plustwo +\expandafter\let\csname\??linenumberinglocation\v!inright \endcsname \plustwo +\expandafter\let\csname\??linenumberinglocation\v!inner \endcsname \plusthree +\expandafter\let\csname\??linenumberinglocation\v!outer \endcsname \plusfour +\expandafter\let\csname\??linenumberinglocation\v!text \endcsname \plusfive +\expandafter\let\csname\??linenumberinglocation\v!begin \endcsname \plussix +\expandafter\let\csname\??linenumberinglocation\v!end \endcsname \plusseven + +\expandafter\let\csname\??linenumberingalternative\v!middle \endcsname \zerocount +\expandafter\let\csname\??linenumberingalternative\v!right \endcsname \plusone +\expandafter\let\csname\??linenumberingalternative\v!flushleft \endcsname \plusone +\expandafter\let\csname\??linenumberingalternative\v!left \endcsname \plustwo +\expandafter\let\csname\??linenumberingalternative\v!flushright\endcsname \plustwo +\expandafter\let\csname\??linenumberingalternative\v!auto \endcsname \plusfive % \startlinenumbering[<startvalue>|continue|settings|name] % \startlinenumbering[name][<startvalue>|continue|settings] @@ -339,8 +339,8 @@ \else \setfalse\c_page_lines_fake_number \fi - \c_page_lines_location \executeifdefined{\??linennumberinglocation \linenumberingparameter\c!location}\plusone \relax % left - \c_page_lines_alignment\executeifdefined{\??linennumberingalternative\linenumberingparameter\c!align }\plusfive\relax % auto + \c_page_lines_location \executeifdefined{\??linenumberinglocation \linenumberingparameter\c!location}\plusone \relax % left + \c_page_lines_alignment\executeifdefined{\??linenumberingalternative\linenumberingparameter\c!align }\plusfive\relax % auto \ifcase\c_page_lines_last_column\relax \settrue \c_page_lines_fake_number \or diff --git a/tex/context/base/page-mix.lua b/tex/context/base/page-mix.lua index f265ac8f9..f86e2f279 100644 --- a/tex/context/base/page-mix.lua +++ b/tex/context/base/page-mix.lua @@ -34,11 +34,14 @@ 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 texbox = tex.box -local texskip = tex.skip -local texdimen = tex.dimen local points = number.points + local settings_to_hash = utilities.parsers.settings_to_hash local variables = interfaces.variables @@ -79,7 +82,7 @@ local function collectinserts(result,nxt,nxtid) if not c then c = { } inserts[s] = c - local width = texskip[s].width + local width = texgetskip(s).width if not result.inserts[s] then currentskips = currentskips + width end @@ -199,7 +202,7 @@ local function setsplit(specification) -- a rather large function report_state("fatal error, no box") return end - local list = texbox[box] + local list = texgetbox(box) if not list then report_state("fatal error, no list") return @@ -464,7 +467,7 @@ local function setsplit(specification) -- a rather large function specification.overflow = overflow specification.discarded = discarded - texbox[specification.box].head = nil + texgetbox(specification.box).list = nil return specification end @@ -613,9 +616,9 @@ function mixedcolumns.getsplit(result,n) end for c, list in next, r.inserts do - -- tex.setbox("global",c,vpack(nodes.concat(list))) - -- tex.setbox(c,vpack(nodes.concat(list))) - texbox[c] = vpack(nodes.concat(list)) + local b = vpack(concatnodes(list)) -- multiple arguments + -- texsetbox("global",c,b) + texsetbox(c,b) r.inserts[c] = nil end diff --git a/tex/context/base/page-mix.mkiv b/tex/context/base/page-mix.mkiv index ef26c5f70..56a1249ca 100644 --- a/tex/context/base/page-mix.mkiv +++ b/tex/context/base/page-mix.mkiv @@ -59,7 +59,7 @@ %\c!align=, % inherit %\c!before=, %\c!after=, - %\c!rule=\v!none, + %\c!separator=\v!none, %\c!setups=, \c!frame=\v!off, \c!strut=\v!no, @@ -69,6 +69,7 @@ \c!maxwidth=\makeupwidth, \c!grid=\v!tolerant, \c!step=.25\lineheight, % needs some experimenting + %\c!splitmethod=\v!fixed, % will be default \c!method=\ifinner\s!box\else\s!otr\fi] % automatic as suggested by WS \let\startmixedcolumns\relax % defined later @@ -163,7 +164,8 @@ \definemixedcolumns [\s!itemgroupcolumns] [\c!n=\itemgroupparameter\c!n, - \c!rule=\v!off, + \c!separator=\v!none, + \c!splitmethod=\v!none, \c!balance=\v!yes] \unexpanded\def\strc_itemgroups_start_columns @@ -294,7 +296,7 @@ \unexpanded\def\page_mix_command_inject_separator {\bgroup \hss - \csname\??mixedcolumnsseparator\mixedcolumnsparameter\c!separator\endcsname + \csname\??mixedcolumnsseparator\mixedcolumnsparameter\c!separator\endcsname % was \c!rule \hss \egroup} @@ -487,10 +489,17 @@ \usealignparameter\mixedcolumnsparameter \usesetupsparameter\mixedcolumnsparameter} +% \setvalue{\??mixedcolumnsstop\s!otr}% +% {\par +% \ifcase\c_page_mix_otr_nesting\or +% \c_page_mix_routine\c_page_mix_routine_balance +% \page_otr_trigger_output_routine +% \fi} + \setvalue{\??mixedcolumnsstop\s!otr}% {\par \ifcase\c_page_mix_otr_nesting\or - \c_page_mix_routine\c_page_mix_routine_balance + \doif{\mixedcolumnsparameter\c!balance}\v!yes{\c_page_mix_routine\c_page_mix_routine_balance}% \page_otr_trigger_output_routine \fi} @@ -518,34 +527,13 @@ strutht = \number\strutht, strutdp = \number\strutdp, threshold = \number\d_page_mix_threshold, + splitmethod = "\mixedcolumnsparameter\c!splitmethod", balance = "#1", alternative = "\mixedcolumnsparameter\c!alternative", grid = \ifgridsnapping true\else false\fi, }}% \deadcycles\zerocount} -% \unexpanded\def\page_mix_routine_package -% {\ctxcommand{mixfinalize()}% -% \setbox\b_page_mix_collected\vbox \bgroup -% \ifvoid\b_page_mix_preceding \else -% \box\b_page_mix_preceding -% \global\d_page_mix_preceding_height\zeropoint -% \nointerlineskip -% \fi -% \hskip\d_page_mix_leftskip -% \page_mix_hbox to \d_page_mix_max_width \bgroup -% \letmixedcolumnsparameter\c!strut \v!no -% \letmixedcolumnsparameter\c!align \empty % probably not needed as we could use a simple variant -% \letmixedcolumnsparameter\c!setups\empty -% \dorecurse\c_page_mix_n_of_columns {% -% \inheritedmixedcolumnsframed{\page_mix_command_package_column}% -% \ifnum\recurselevel<\c_page_mix_n_of_columns -% \page_mix_command_inject_separator -% \fi -% }% -% \egroup -% \egroup} - \unexpanded\def\page_mix_routine_package {\ctxcommand{mixfinalize()}% \setbox\b_page_mix_collected\vbox \bgroup @@ -557,9 +545,13 @@ \hskip\d_page_mix_leftskip \page_mix_hbox to \d_page_mix_max_width \bgroup \dorecurse\c_page_mix_n_of_columns{% - % \inheritedmixedcolumnsframed{\page_mix_command_package_column}% needs reset of strut, align, setups etc - \setbox\scratchbox\page_mix_command_package_column % needs packaging anyway + % needs packaging anyway + \setbox\scratchbox\page_mix_command_package_column + % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner + \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone + % the framed needs a reset of strut, align, setups etc \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox + % optional \ifnum\recurselevel<\c_page_mix_n_of_columns \page_mix_command_inject_separator \fi diff --git a/tex/context/base/page-pst.lua b/tex/context/base/page-pst.lua index f714c25d9..2fc400a14 100644 --- a/tex/context/base/page-pst.lua +++ b/tex/context/base/page-pst.lua @@ -8,12 +8,16 @@ if not modules then modules = { } end modules ['page-pst'] = { -- todo: adapt message +local tonumber, next = tonumber, next local format, validstring = string.format, string.valid local sortedkeys = table.sortedkeys local context = context local commands = commands +local texgetcount = tex.getcount +local texsetcount = tex.setcount + local cache = { } local function flush(page) @@ -35,14 +39,14 @@ local function setnextpage() elseif n > 0 then -- upcoming page (realpageno) end - tex.setcount("global","c_page_postponed_blocks_next_page",n) + texsetcount("global","c_page_postponed_blocks_next_page",n) end function commands.flushpostponedblocks(page) -- we need to flush previously pending pages as well and the zero -- slot is the generic one so that one is always flushed local t = sortedkeys(cache) - local p = tonumber(page) or tex.count.realpageno or 0 + local p = tonumber(page) or texgetcount("realpageno") or 0 for i=1,#t do local ti = t[i] if ti <= p then @@ -57,7 +61,7 @@ end function commands.registerpostponedblock(page) if type(page) == "string" then if string.find(page,"^+") then - page = tex.count.realpageno + (tonumber(page) or 1) -- future delta page + page = texgetcount("realpageno") + (tonumber(page) or 1) -- future delta page else page = tonumber(page) or 0 -- preferred page or otherwise first possible occasion end diff --git a/tex/context/base/page-str.lua b/tex/context/base/page-str.lua index f6314657f..35ce85609 100644 --- a/tex/context/base/page-str.lua +++ b/tex/context/base/page-str.lua @@ -12,18 +12,25 @@ if not modules then modules = { } end modules ['page-str'] = { local concat, insert, remove = table.concat, table.insert, table.remove -local find_tail, write_node, free_node, copy_nodelist = node.slide, node.write, node.free, node.copy_list -local vpack_nodelist, hpack_nodelist = node.vpack, node.hpack -local texdimen, texbox = tex.dimen, tex.box -local settings_to_array = utilities.parsers.settings_to_array - local nodes, node = nodes, node -local nodepool = nodes.pool -local tasks = nodes.tasks +local nodepool = nodes.pool +local tasks = nodes.tasks + +local new_kern = nodepool.kern +local new_glyph = nodepool.glyph + +local find_tail = node.slide +local write_node = node.write +local free_node = node.free +local copy_nodelist = node.copy_list +local vpack_nodelist = node.vpack +local hpack_nodelist = node.hpack + +local settings_to_array = utilities.parsers.settings_to_array -local new_kern = nodepool.kern -local new_glyph = nodepool.glyph +local texgetdimen = tex.getdimen +local texgetbox = tex.getbox local trace_collecting = false trackers.register("streams.collecting", function(v) trace_collecting = v end) local trace_flushing = false trackers.register("streams.flushing", function(v) trace_flushing = v end) @@ -175,7 +182,8 @@ function streams.synchronize(list) -- this is an experiment ! if trace_flushing then report_streams("slot %s has max height %p and max depth %p",m,height,depth) end - local strutht, strutdp = texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth + local strutht = texgetdimen("globalbodyfontstrutheight") + local strutdp = texgetdimen("globalbodyfontstrutdepth") local struthtdp = strutht + strutdp for i=1,#list do local name = list[i] @@ -198,7 +206,7 @@ function streams.synchronize(list) -- this is an experiment ! local n, delta = 0, delta_height -- for tracing while delta > 0 do -- we need to add some interline penalties - local line = copy_nodelist(tex.box.strutbox) + local line = copy_nodelist(texgetbox("strutbox")) line.height, line.depth = strutht, strutdp if tail then tail.next, line.prev = line, tail diff --git a/tex/context/base/s-inf-03.pdf b/tex/context/base/s-inf-03.pdf Binary files differnew file mode 100644 index 000000000..a2de80fab --- /dev/null +++ b/tex/context/base/s-inf-03.pdf diff --git a/tex/context/base/scrn-fld.lua b/tex/context/base/scrn-fld.lua index 9836cbebe..69480b887 100644 --- a/tex/context/base/scrn-fld.lua +++ b/tex/context/base/scrn-fld.lua @@ -11,6 +11,8 @@ if not modules then modules = { } end modules ['scrn-fld'] = { local variables = interfaces.variables local v_yes = variables.yes +local texsetbox = tex.setbox + local fields = { } interactions.fields = fields @@ -43,7 +45,7 @@ commands.definefieldset = defineset commands.clonefield = clone function commands.insertfield(name,specification) - tex.box["b_scrn_field_body"] = insert(name,specification) + texsetbox("b_scrn_field_body",insert(name,specification)) end -- (for the monent) only tex interface diff --git a/tex/context/base/scrn-hlp.lua b/tex/context/base/scrn-hlp.lua index 1e9d1f570..d344ce280 100644 --- a/tex/context/base/scrn-hlp.lua +++ b/tex/context/base/scrn-hlp.lua @@ -21,6 +21,8 @@ local hpack_nodelist = node.hpack local register_list = nodes.pool.register +local texgetbox = tex.getbox + local nodecodes = nodes.nodecodes local hlist_code = nodecodes.hlist @@ -51,7 +53,7 @@ function help.register(number,name,box) interactions.javascripts.setpreamble("HelpTexts",helpscript) helpscript = false end - local b = copy_nodelist(tex.box[box]) + local b = copy_nodelist(texgetbox(box)) register_list(b) data[number] = b if name and name ~= "" then @@ -84,7 +86,7 @@ end function help.collect(box) if next(data) then - return collect(tex.box[box].list) + return collect(texgetbox(box).list) end end diff --git a/tex/context/base/scrn-wid.lua b/tex/context/base/scrn-wid.lua index a2b3e28b9..90aaed609 100644 --- a/tex/context/base/scrn-wid.lua +++ b/tex/context/base/scrn-wid.lua @@ -24,8 +24,12 @@ interactions.soundclips = soundclips interactions.renderings = renderings interactions.linkedlists = linkedlists +local texsetbox = tex.setbox + local jobpasses = job.passes +local texgetcount = tex.getcount + local codeinjections = backends.codeinjections local nodeinjections = backends.nodeinjections @@ -107,7 +111,7 @@ end commands.registerattachment = attachments.register function commands.insertattachment(specification) - tex.box["b_scrn_attachment_link"] = attachments.insert(specification) + texsetbox("b_scrn_attachment_link",attachments.insert(specification)) end -- Comment @@ -121,7 +125,7 @@ function comments.insert(specification) end function commands.insertcomment(specification) - tex.box["b_scrn_comment_link"] = comments.insert(specification) + texsetbox("b_scrn_comment_link",comments.insert(specification)) end -- Soundclips @@ -199,7 +203,7 @@ end function commands.enhancelinkedlist(tag,n) local ll = jobpasses.gettobesaved(tag) if ll then - ll[n] = texcount.realpageno + ll[n] = texgetcount("realpageno") end end diff --git a/tex/context/base/scrn-wid.mkvi b/tex/context/base/scrn-wid.mkvi index ae5f7c556..fad451651 100644 --- a/tex/context/base/scrn-wid.mkvi +++ b/tex/context/base/scrn-wid.mkvi @@ -16,6 +16,7 @@ \registerctxluafile{scrn-wid}{1.001} % todo: expansion in comments (default is expanded) +% todo: check renderings ... acrobat crashes too easily on missing one \unprotect @@ -566,8 +567,8 @@ \definereference[PauseCurrentRendering] [\v!PauseRendering {\currentrendering}] \definereference[ResumeCurrentRendering][\v!ResumeRendering{\currentrendering}] -\def\useexternalrendering{\doquadrupleempty\scrn_rendering_use} -\def\setinternalrendering{\dodoubleempty \scrn_rendering_set} +\unexpanded\def\useexternalrendering{\doquadrupleempty\scrn_rendering_use} +\unexpanded\def\setinternalrendering{\dodoubleempty \scrn_rendering_set} \def\scrn_rendering_use[#tag][#mime][#file][#option]% {\ctxcommand{registerrendering{ @@ -578,7 +579,7 @@ option = "#option", }}} -\def\scrn_rendering_set[#tag][#option]% {content} +\def\scrn_rendering_set[#tag][#option]% {content} % crappy {\bgroup \dowithnextbox {\ctxcommand{registerrendering{ @@ -615,17 +616,9 @@ \unexpanded\def\placerenderingwindow {\dodoubleempty\scrn_rendering_place_window} -\def\scrn_rendering_place_window[#window][#rendering]% +\def\scrn_rendering_place_window[#window][#rendering]% do all in lua {\bgroup \edef\currentrendering{\ifsecondargument#rendering\else#window\fi}% - \doifelse{\renderingtype\currentrendering}{internal} % an object - {\getobjectdimensions{IRO}\currentrendering - \d_scrn_rendering_height\dimexpr\objectheight+\objectdepth\relax - \d_scrn_rendering_width\objectwidth\relax - \dogetobjectreferencepage{IRO}\currentrendering\m_scrn_rendering_page}% - {\d_scrn_rendering_height\vsize - \d_scrn_rendering_width\hsize - \let\m_scrn_rendering_page\realpageno}% % create fall back if needed \edef\currentrenderingwindow{\namedrenderingwindowparameter{#window}\c!width}% stupid test, we need a proper one here \ifx\currentrenderingwindow\empty @@ -634,6 +627,21 @@ \else \edef\currentrenderingwindow{#window}% \fi + \edef\currentrenderingtype{\renderingtype\currentrendering}% + \ifx\currentrenderingtype\s!internal + \getobjectdimensions{IRO}\currentrendering + \d_scrn_rendering_height\dimexpr\objectheight+\objectdepth\relax + \d_scrn_rendering_width\objectwidth\relax + \dogetobjectreferencepage{IRO}\currentrendering\m_scrn_rendering_page + \else\ifx\currentrenderingwindow\s!default + \d_scrn_rendering_height\vsize + \d_scrn_rendering_width \hsize + \let\m_scrn_rendering_page\realpageno + \else + \d_scrn_rendering_height\renderingwindowparameter\c!height + \d_scrn_rendering_width \renderingwindowparameter\c!width + \let\m_scrn_rendering_page\realpageno + \fi\fi % todo: % \handlereferenceactions{\renderingwindowparameter\c!openpageaction }\dosetuprenderingopenpageaction % \handlereferenceactions{\renderingwindowparameter\c!closepageaction}\dosetuprenderingclosepageaction diff --git a/tex/context/base/spac-ali.lua b/tex/context/base/spac-ali.lua index ceb278433..25cc6cd66 100644 --- a/tex/context/base/spac-ali.lua +++ b/tex/context/base/spac-ali.lua @@ -20,8 +20,6 @@ local hpack_nodes = node.hpack -- nodes.fasthpack not really faster here local unsetvalue = attributes.unsetvalue -local concat_nodes = nodes.concat - local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes @@ -35,8 +33,8 @@ local new_stretch = nodepool.stretch local a_realign = attributes.private("realign") -local texattribute = tex.attribute -local texcount = tex.count +local texsetattribute = tex.setattribute +local texgetcount = tex.getcount local isleftpage = layouts.status.isleftpage @@ -77,12 +75,12 @@ local function handler(head,leftpage,realpageno) action = leftpage and 2 or 1 end if action == 1 then - current.list = hpack_nodes(concat_nodes{current.list,new_stretch(3)},current.width,"exactly") + current.list = hpack_nodes(current.list .. new_stretch(3),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(concat_nodes{new_stretch(3),current.list},current.width,"exactly") + current.list = hpack_nodes(new_stretch(3) .. current.list,current.width,"exactly") if trace_realign then report_realign("flushing right. align %a, page %a, realpage %a",align,pageno,realpageno) end @@ -106,7 +104,7 @@ end function alignments.handler(head) local leftpage = isleftpage(true,false) - local realpageno = texcount.realpageno + local realpageno = texgetcount("realpageno") return handler(head,leftpage,realpageno) end @@ -120,7 +118,7 @@ function alignments.set(n) report_realign("enabled") end end - texattribute[a_realign] = texcount.realpageno * 10 + n + texsetattribute(a_realign,texgetcount("realpageno") * 10 + n) end commands.setrealign = alignments.set diff --git a/tex/context/base/spac-chr.lua b/tex/context/base/spac-chr.lua index 24364978a..f3c62bb77 100644 --- a/tex/context/base/spac-chr.lua +++ b/tex/context/base/spac-chr.lua @@ -74,7 +74,6 @@ local function inject_char_space(unicode,head,current,parent) local font = current.font local char = fontcharacters[font][parent] local glue = new_glue(char and char.width or fontparameters[font].space) - -- glue.attr = copy_node_list(current.attr) glue.attr = current.attr current.attr = nil glue[a_character] = unicode @@ -86,10 +85,8 @@ local function inject_nobreak_space(unicode,head,current,space,spacestretch,spac local attr = current.attr local glue = new_glue(space,spacestretch,spaceshrink) local penalty = new_penalty(10000) - -- glue.attr = copy_node_list(attr) glue.attr = attr current.attr = nil - -- penalty.attr = attr glue[a_character] = unicode head, current = insert_node_after(head,current,penalty) head, current = insert_node_after(head,current,glue) diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua index 36fa357d0..406896e4d 100644 --- a/tex/context/base/spac-ver.lua +++ b/tex/context/base/spac-ver.lua @@ -23,8 +23,7 @@ if not modules then modules = { } end modules ['spac-ver'] = { local next, type, tonumber = next, type, tonumber local gmatch, concat = string.gmatch, table.concat -local ceil, floor, max, min, round, abs = math.ceil, math.floor, math.max, math.min, math.round, math.abs -local texlists, texdimen, texbox = tex.lists, tex.dimen, tex.box +local ceil, floor = math.ceil, math.floor local lpegmatch = lpeg.match local unpack = unpack or table.unpack local allocate = utilities.storage.allocate @@ -33,12 +32,13 @@ local formatters = string.formatters local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc -local nodes, node, trackers, attributes, context, commands = nodes, node, trackers, attributes, context, commands +local nodes, node, trackers, attributes, context, commands, tex = nodes, node, trackers, attributes, context, commands, tex -local variables = interfaces.variables +----- texlists = tex.lists +local texgetdimen = tex.getdimen +local texgetbox = tex.getbox -local starttiming = statistics.starttiming -local stoptiming = statistics.stoptiming +local variables = interfaces.variables -- vertical space handler @@ -87,7 +87,6 @@ local new_gluespec = nodepool.gluespec local nodecodes = nodes.nodecodes local skipcodes = nodes.skipcodes -local fillcodes = nodes.fillcodes local penalty_code = nodecodes.penalty local kern_code = nodecodes.kern @@ -96,7 +95,6 @@ local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist local whatsit_code = nodecodes.whatsit -local userskip_code = skipcodes.userskip local vspacing = builders.vspacing or { } builders.vspacing = vspacing @@ -288,20 +286,24 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is local snapht, snapdp if method["local"] then -- snapping is done immediately here - snapht, snapdp = texdimen.bodyfontstrutheight, texdimen.bodyfontstrutdepth + snapht = texgetdimen("bodyfontstrutheight") + snapdp = texgetdimen("bodyfontstrutdepth") if t then t[#t+1] = formatters["local: snapht %p snapdp %p"](snapht,snapdp) end elseif method["global"] then - snapht, snapdp = texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth + snapht = texgetdimen("globalbodyfontstrutheight") + snapdp = texgetdimen("globalbodyfontstrutdepth") if t then t[#t+1] = formatters["global: snapht %p snapdp %p"](snapht,snapdp) end else -- maybe autolocal -- snapping might happen later in the otr - snapht, snapdp = texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth - local lsnapht, lsnapdp = texdimen.bodyfontstrutheight, texdimen.bodyfontstrutdepth + snapht = texgetdimen("globalbodyfontstrutheight") + snapdp = texgetdimen("globalbodyfontstrutdepth") + local lsnapht = texgetdimen("bodyfontstrutheight") + local lsnapdp = texgetdimen("bodyfontstrutdepth") if snapht ~= lsnapht and snapdp ~= lsnapdp then snapht, snapdp = lsnapht, lsnapdp end @@ -342,13 +344,16 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is id = thebox and thebox.id end if thebox and id == vlist_code then - local list, lh, ld = thebox.list + local list = thebox.list + local lh, ld for n in traverse_nodes_id(hlist_code,list) do - lh, ld = n.height, n.depth + lh = n.height + ld = n.depth break end if lh then - local ht, dp = thebox.height, thebox.depth + local ht = thebox.height + local dp = 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) @@ -379,10 +384,12 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is if thebox and id == vlist_code then local list, lh, ld = thebox.list for n in traverse_nodes_id(hlist_code,list) do - lh, ld = n.height, n.depth + lh = n.height + ld = n.depth end if lh then - local ht, dp = thebox.height, thebox.depth + local ht = thebox.height + local dp = 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) @@ -479,7 +486,7 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is local lines = (ch+cd)/snaphtdp if t then local original = (h+d)/snaphtdp - local whatever = (ch+cd)/(texdimen.globalbodyfontstrutheight + texdimen.globalbodyfontstrutdepth) + local whatever = (ch+cd)/(texgetdimen("globalbodyfontstrutheight") + texgetdimen("globalbodyfontstrutdepth")) t[#t+1] = formatters["final lines: %s -> %s (%s)"](original,lines,whatever) t[#t+1] = formatters["final height: %p -> %p"](h,ch) t[#t+1] = formatters["final depth: %p -> %p"](d,cd) @@ -495,7 +502,8 @@ local function snap_topskip(current,method) local w = spec.width local wd = w if spec.writable then - spec.width, wd = 0, 0 + spec.width = 0 + wd = 0 end return w, wd end @@ -740,21 +748,11 @@ local topskip_code = skipcodes.topskip local splittopskip_code = skipcodes.splittopskip local free_glue_node = free_node -local discard, largest, force, penalty, add, disable, nowhite, goback, together = 0, 1, 2, 3, 4, 5, 6, 7, 8 - --- local function free_glue_node(n) --- -- free_node(n.spec) --- print("before",n) --- logs.flush() --- free_node(n) --- print("after") --- logs.flush() --- end function vspacing.snapbox(n,how) local sv = snapmethods[how] if sv then - local box = texbox[n] + local box = texgetbox(n) local list = box.list if list then local s = list[a_snapmethod] @@ -763,7 +761,8 @@ function vspacing.snapbox(n,how) -- report_snapper("box list not snapped, already done") end else - local ht, dp = box.height, box.depth + local ht = box.height + local dp = box.depth if false then -- todo: already_done -- assume that the box is already snapped if trace_vsnapping then @@ -772,7 +771,8 @@ function vspacing.snapbox(n,how) end else local h, d, ch, cd, lines = snap_hlist("box",box,sv,ht,dp) - box.height, box.depth = ch, cd + box.height= ch + 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)) @@ -805,6 +805,8 @@ end -- penalty only works well when before skip +local discard, largest, force, penalty, add, disable, nowhite, goback, together = 0, 1, 2, 3, 4, 5, 6, 7, 8 -- move into function when upvalue 60 issue + local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also pass tail if trace then reset_tracing(head) @@ -823,11 +825,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 if force_glue then if trace then trace_done("flushed due to " .. why,glue_data) end - head = forced_skip(head,current,glue_data.spec.width,"before",trace) + head = forced_skip(head,current,spec.width,"before",trace) free_glue_node(glue_data) - elseif glue_data.spec.writable then + elseif spec.writable then if trace then trace_done("flushed due to " .. why,glue_data) end head = insert_node_before(head,current,glue_data) else @@ -841,8 +844,9 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also end if trace_vsnapping then report_snapper("global ht/dp = %p/%p, local ht/dp = %p/%p", - texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth, - texdimen.bodyfontstrutheight, texdimen.bodyfontstrutdepth) + texgetdimen("globalbodyfontstrutheight"), texgetdimen("globalbodyfontstrutdepth"), + texgetdimen("bodyfontstrutheight"), texgetdimen("bodyfontstrutdepth") + ) end if trace then trace_info("start analyzing",where,what) end while current do @@ -865,7 +869,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, dp = current.height, current.depth + local ht = current.height + local dp = 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)) @@ -936,9 +941,9 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also 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 + -- current = previous if trace then trace_natural("collapsed",previous) end - -- current = current.next + -- current = current.next else if trace then trace_natural("filler",current) end current = current.next @@ -1075,7 +1080,8 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also if trace then trace_natural("ignored parskip",current) end head, current = remove_node(head, current, true) elseif glue_data then - local ps, gs = current.spec, glue_data.spec + 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) if trace then trace_natural("taking parskip",current) end @@ -1131,11 +1137,14 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also current = current.next -- else -- other glue - if snap and trace_vsnapping and current.spec.writable and current.spec.width ~= 0 then - report_snapper("glue %p of type %a kept",current.spec.width,skipcodes[subtype]) - --~ current.spec.width = 0 + 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 + end end - if trace then trace_skip(formatted["glue of type %a"](subtype),sc,so,sp,current) end + if trace then trace_skip(formatter["glue of type %a"](subtype),sc,so,sp,current) end flush("some glue") current = current.next end @@ -1227,11 +1236,11 @@ function vspacing.pagehandler(newhead,where) 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) + -- 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 + -- texlists.contrib_head = newhead end else if stackhead then @@ -1258,97 +1267,21 @@ local ignore = table.tohash { function vspacing.vboxhandler(head,where) if head and not ignore[where] and head.next then - -- starttiming(vspacing) head = collapser(head,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper - -- stoptiming(vspacing) end return head end function vspacing.collapsevbox(n) -- for boxes but using global a_snapmethod - local list = texbox[n].list - if list then - -- starttiming(vspacing) - texbox[n].list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod)) - -- stoptiming(vspacing) - end -end - --- We will split this module so a few locals are repeated. Also this will be --- rewritten. - -nodes.builders = nodes.builder or { } -local builders = nodes.builders - -local actions = nodes.tasks.actions("vboxbuilders") - -function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction) - local done = false - if head then - starttiming(builders) - if trace_vpacking then - local before = nodes.count(head) - head, done = actions(head,groupcode,size,packtype,maxdepth,direction) - local after = nodes.count(head) - if done then - nodes.processors.tracer("vpack","changed",head,groupcode,before,after,true) - else - nodes.processors.tracer("vpack","unchanged",head,groupcode,before,after,true) - end - else - head, done = actions(head,groupcode) - end - stoptiming(builders) - end - return head, done -end - --- This one is special in the sense that it has no head and we operate on the mlv. Also, --- we need to do the vspacing last as it removes items from the mvl. - -local actions = nodes.tasks.actions("mvlbuilders") - -local function report(groupcode,head) - report_page_builder("trigger: %s",groupcode) - report_page_builder(" vsize : %p",tex.vsize) - report_page_builder(" pagegoal : %p",tex.pagegoal) - report_page_builder(" pagetotal: %p",tex.pagetotal) - report_page_builder(" list : %s",head and nodeidstostring(head) or "<empty>") -end - -function builders.buildpage_filter(groupcode) - local head, done = texlists.contrib_head, false - -- if head and head.next and head.next.id == hlist_code and head.next.width == 1 then - -- report_page_builder("trigger otr calculations") - -- free_node_list(head) - -- head = nil - -- end - if head then - starttiming(builders) - if trace_page_builder then - report(groupcode,head) - end - head, done = actions(head,groupcode) - stoptiming(builders) - -- -- doesn't work here (not passed on?) - -- tex.pagegoal = tex.vsize - tex.dimen.d_page_floats_inserted_top - tex.dimen.d_page_floats_inserted_bottom - texlists.contrib_head = head - return done and head or true - else - if trace_page_builder then - report(groupcode) + local box = texgetbox(n) + if box then + local list = box.list + if list then + setfield(box,"list",vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod))) end - return nil, false end end -callbacks.register('vpack_filter', builders.vpack_filter, "vertical spacing etc") -callbacks.register('buildpage_filter', builders.buildpage_filter, "vertical spacing etc (mvl)") - -statistics.register("v-node processing time", function() - return statistics.elapsedseconds(builders) -end) - -- interface commands.vspacing = vspacing.analyze diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex bff528ee0..af631be91 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.log b/tex/context/base/status-lua.log new file mode 100644 index 000000000..71ade66ca --- /dev/null +++ b/tex/context/base/status-lua.log @@ -0,0 +1,78 @@ +(cont-yes.mkiv + +ConTeXt ver: 2013.07.12 19:10 MKIV beta fmt: 2013.7.12 int: english/english + +system > 'cont-new.mkiv' loaded +(cont-new.mkiv) +system > 'cont-loc.mkiv' loaded +(c:/data/develop/context/sources/cont-loc.mkiv) +system > 'cont-exp.mkiv' loaded +interface > macros > processed mkvi file 'c:/data/develop/context/sources/cont-exp.mkiv', delta 0 +interface > macros > processed mkvi file 'c:/data/develop/context/sources/cont-exp.mkiv', delta 0 +(c:/data/develop/context/sources/cont-exp.mkiv) +system > files > jobname 's-inf-03', input './s-inf-03.mkiv', result 'status-lua.pdf' +fonts > latin modern fonts are not preloaded +languages > language 'en' is active +(c:/data/develop/context/texmf/tex/context/base/s-inf-03.mkiv (c:/data/develop/context/sources/type-loc.mkiv) (type-imp-dejavu.mkiv) (type-imp-xits.mkiv (type-imp-texgyre.mkiv)){c:/data/develop/tex-context/tex/texmf-context/fonts/map/pdftex/context/mkiv-base.map} (virtual://buffer.noname.1 +references > unknown reference '[][]' +references > unknown reference '[][attributes]' +references > unknown reference '[][backends]' +references > unknown reference '[][bibtex]' +references > unknown reference '[][bit32]' +references > unknown reference '[][blobs]' +references > unknown reference '[][boolean]' +references > unknown reference '[][buffers]' +references > unknown reference '[][builders]' +references > unknown reference '[][caches]' +references > unknown reference '[][callback]' +references > unknown reference '[][callbacks]' +references > unknown reference '[][catcodes]' +references > unknown reference '[][characters]' +references > unknown reference '[][chemistry]' +references > unknown reference '[][commands]' +references > unknown reference '[][containers]' +references > unknown reference '[][context]' +references > unknown reference '[][converters]' +references > unknown reference '[][coroutine]' +references > unknown reference '[][ctxrunner]' +references > unknown reference '[][debug]' +references > unknown reference '[][dir]' +references > unknown reference '[][directives]' +references > unknown reference '[][document]' +references > unknown reference '[][documentdata]' +references > unknown reference '[][environment]' +references > unknown reference '[][epdf]' +references > unknown reference '[][experiments]' +references > unknown reference '[][figures]' +references > unknown reference '[][file]' +references > unknown reference '[][floats]' +references > unknown reference '[][font]' +references > unknown reference '[][fontloader]' +references > unknown reference '[][fonts]' +references > unknown reference '[][functions]' +references > unknown reference '[][graphics]' +references > unknown reference '[][gzip]' +references > unknown reference '[][img]' +references > unknown reference '[][interactions]' +references > unknown reference '[][interfaces]' +references > unknown reference '[][io]' +references > unknown reference '[][job]' +references > unknown reference '[][lang]' +references > unknown reference '[][languages]' +references > unknown reference '[][layouts]' +references > unknown reference '[][lfs]' +references > unknown reference '[][libraries]' +references > unknown reference '[][lmx]' +references > unknown reference '[][logs]' +references > unknown reference '[][lpdf]' +references > unknown reference '[][lpeg]' +references > unknown reference '[][ltn12]' +references > unknown reference '[][lua]' +references > unknown reference '[][luatex]' +references > unknown reference '[][lxml]' +references > unknown reference '[][math]' +references > unknown reference '[][mathematics]' +references > unknown reference '[][mbox]' +references > unknown reference '[][md5]' +references > unknown reference '[][metapost]' +references > unknown reference '[][mime]'
\ No newline at end of file diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differdeleted file mode 100644 index c2a6132f1..000000000 --- a/tex/context/base/status-lua.pdf +++ /dev/null diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua index 443eee60e..1e8d55c9c 100644 --- a/tex/context/base/status-mkiv.lua +++ b/tex/context/base/status-mkiv.lua @@ -3714,7 +3714,12 @@ return { { category = "lua", filename = "m-database", - status = "todo", + status = "okay", + }, + { + category = "lua", + filename = "m-nodechart", + status = "okay", }, { category = "lua", @@ -5090,7 +5095,12 @@ return { { category = "mkiv", filename = "m-database", - status = "todo", + status = "okay", + }, + { + category = "mkiv", + filename = "m-nodechart", + status = "okay", }, { category = "tex", diff --git a/tex/context/base/strc-ini.lua b/tex/context/base/strc-ini.lua index 1e60e253f..09ed79288 100644 --- a/tex/context/base/strc-ini.lua +++ b/tex/context/base/strc-ini.lua @@ -20,12 +20,13 @@ but it does not make sense to store all processdata. ]]-- -local formatters = string.formatters local lpegmatch = lpeg.match -local count = tex.count local type, next, tonumber, select = type, next, tonumber, select -local settings_to_array, settings_to_hash = utilities.parsers.settings_to_array, utilities.parsers.settings_to_hash -local allocate = utilities.storage.allocate + +local formatters = string.formatters +local settings_to_array = utilities.parsers.settings_to_array +local settings_to_hash = utilities.parsers.settings_to_hash +local allocate = utilities.storage.allocate local catcodenumbers = catcodes.numbers -- better use the context(...) way to switch diff --git a/tex/context/base/strc-itm.lua b/tex/context/base/strc-itm.lua index 8a745f356..4945c282f 100644 --- a/tex/context/base/strc-itm.lua +++ b/tex/context/base/strc-itm.lua @@ -10,19 +10,19 @@ local structures = structures local itemgroups = structures.itemgroups local jobpasses = job.passes -local setfield = jobpasses.save -local getfield = jobpasses.getfield +local setvariable = jobpasses.save +local getvariable = jobpasses.getfield function itemgroups.register(name,nofitems,maxwidth) - setfield("itemgroup", { nofitems, maxwidth }) + setvariable("itemgroup", { nofitems, maxwidth }) end function itemgroups.nofitems(name,index) - return getfield("itemgroup", index, 1, 0) + return getvariable("itemgroup", index, 1, 0) end function itemgroups.maxwidth(name,index) - return getfield("itemgroup", index, 2, 0) + return getvariable("itemgroup", index, 2, 0) end -- interface (might become counter/dimension) @@ -30,9 +30,9 @@ end commands.registeritemgroup = itemgroups.register function commands.nofitems(name,index) - context(getfield("itemgroup", index, 1, 0)) + context(getvariable("itemgroup", index, 1, 0)) end function commands.maxitemwidth(name,index) - context(getfield("itemgroup", index, 2, 0)) + context(getvariable("itemgroup", index, 2, 0)) end diff --git a/tex/context/base/strc-lnt.mkvi b/tex/context/base/strc-lnt.mkvi index 4a2cd1cc0..2c26acec7 100644 --- a/tex/context/base/strc-lnt.mkvi +++ b/tex/context/base/strc-lnt.mkvi @@ -79,6 +79,8 @@ \letvalue\??linenotespreviousfrom\empty \letvalue\??linenotespreviousto \empty +% maybe do this in lua + \def\page_lines_in_from{\in[lr:b:\currentlinenotereference]} \def\page_lines_in_to {\in[lr:e:\currentlinenotereference]} @@ -113,14 +115,11 @@ \notationparameter\c!compressseparator \else \page_lines_in_from + \ifx\m_page_lines_current_from\m_page_lines_current_to\else\endash\page_lines_in_to\fi \fi \else \page_lines_in_from - \ifx\m_page_lines_current_from\m_page_lines_current_to - \else - \endash - \page_lines_in_to - \fi + \ifx\m_page_lines_current_from\m_page_lines_current_to\else\endash\page_lines_in_to\fi \fi \else \page_lines_in_from diff --git a/tex/context/base/strc-lst.lua b/tex/context/base/strc-lst.lua index d5597109f..f6a355707 100644 --- a/tex/context/base/strc-lst.lua +++ b/tex/context/base/strc-lst.lua @@ -17,7 +17,6 @@ if not modules then modules = { } end modules ['strc-lst'] = { local format, gmatch, gsub = string.format, string.gmatch, string.gsub local tonumber = tonumber -local texcount = tex.count local concat, insert, remove = table.concat, table.insert, table.remove local lpegmatch = lpeg.match local simple_hash_to_string, settings_to_hash = utilities.parsers.simple_hash_to_string, utilities.parsers.settings_to_hash @@ -30,6 +29,8 @@ local report_lists = logs.reporter("structure","lists") local context = context local commands = commands +local texgetcount = tex.getcount + local structures = structures local lists = structures.lists local sections = structures.sections @@ -208,7 +209,7 @@ function lists.enhance(n) -- save in the right order (happens at shipout) lists.tobesaved[#lists.tobesaved+1] = l -- default enhancer (cross referencing) - references.realpage = texcount.realpageno + references.realpage = texgetcount("realpageno") -- tags local kind = metadata.kind local name = metadata.name diff --git a/tex/context/base/strc-mar.lua b/tex/context/base/strc-mar.lua index 26603fe72..02d676fb9 100644 --- a/tex/context/base/strc-mar.lua +++ b/tex/context/base/strc-mar.lua @@ -24,9 +24,10 @@ local glyph_code = nodecodes.glyph local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist -local traversenodes = node.traverse +local traversenodes = nodes.traverse + local texsetattribute = tex.setattribute -local texbox = tex.box +local texgetbox = tex.getbox local a_marks = attributes.private("structure","marks") @@ -137,7 +138,7 @@ setmetatableindex(classes, function(t,k) local s = settings_to_array(k) t[k] = s local lasts = { } function marks.synchronize(class,n,option) - local box = texbox[n] + local box = texgetbox(n) if box then local first, last = sweep(box.list,0,0) if option == v_keep and first == 0 and last == 0 then @@ -153,11 +154,16 @@ function marks.synchronize(class,n,option) for i=1,#classlist do local class = classlist[i] local range = ranges[class] - if not range then - range = { } + if range then + range.first = first + range.last = last + else + range = { + first = first, + last = last, + } ranges[class] = range end - range.first, range.last = first, last if trace_marks_get or trace_marks_set then report_marks("action %a, class %a, first %a, last %a","synchronize",class,range.first,range.last) end diff --git a/tex/context/base/strc-not.lua b/tex/context/base/strc-not.lua index 8aae8878b..40b78d59f 100644 --- a/tex/context/base/strc-not.lua +++ b/tex/context/base/strc-not.lua @@ -8,7 +8,6 @@ if not modules then modules = { } end modules ['strc-not'] = { local format = string.format local next = next -local texcount = tex.count local trace_notes = false trackers.register("structures.notes", function(v) trace_notes = v end) local trace_references = false trackers.register("structures.notes.references", function(v) trace_references = v end) @@ -24,6 +23,9 @@ local notes = structures.notes local references = structures.references local counterspecials = counters.specials +local texgetcount = tex.getcount +local texgetbox = tex.getbox + notes.states = notes.states or { } lists.enhancers = lists.enhancers or { } @@ -189,7 +191,7 @@ local function hascontent(tag) local ok = notestates[tag] if ok then if ok.kind == "insert" then - ok = tex.box[ok.number] + ok = texgetbox(ok.number) if ok then ok = tbs.list ok = lst and lst.next @@ -257,7 +259,7 @@ function notes.checkpagechange(tag) -- called before increment ! end elseif current then -- we need to locate the next one, best guess - if texcount.realpageno > current.pagenumber.number then + if texgetcount("realpageno") > current.pagenumber.number then counters.reset(tag) end end @@ -280,7 +282,7 @@ commands.postponenotes = notes.postpone function notes.setsymbolpage(tag,n,l) local l = l or listindex(tag,n) if l then - local p = texcount.realpageno + local p = texgetcount("realpageno") if trace_notes or trace_references then report_notes("note %a of %a with list index %a gets symbol page %a",n,tag,l,p) end @@ -382,7 +384,7 @@ function commands.flushnotes(tag,whatkind,how) -- store and postpone local rp = get(tag,i) rp = rp and rp.references rp = rp and rp.symbolpage or 0 - if rp > texcount.realpageno then + if rp > texgetcount("realpageno") then state.start = i return end diff --git a/tex/context/base/strc-num.lua b/tex/context/base/strc-num.lua index b0eae6b78..866dc146c 100644 --- a/tex/context/base/strc-num.lua +++ b/tex/context/base/strc-num.lua @@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['strc-num'] = { local format = string.format local next, type = next, type local min, max = math.min, math.max -local texcount, texsetcount = tex.count, tex.setcount +local texsetcount = tex.setcount -- Counters are managed here. They can have multiple levels which makes it easier to synchronize -- them. Synchronization is sort of special anyway, as it relates to document structuring. diff --git a/tex/context/base/strc-pag.lua b/tex/context/base/strc-pag.lua index a71c6bca6..02ed5610f 100644 --- a/tex/context/base/strc-pag.lua +++ b/tex/context/base/strc-pag.lua @@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['strc-pag'] = { license = "see context related readme files" } -local texcount = tex.count - local allocate, mark = utilities.storage.allocate, utilities.storage.mark local trace_pages = false trackers.register("structures.pages", function(v) trace_pages = v end) @@ -33,6 +31,9 @@ local applyprocessor = processors.apply local startapplyprocessor = processors.startapply local stopapplyprocessor = processors.stopapply +local texsetcount = tex.setcount +local texgetcount = tex.getcount + -- storage local collected, tobesaved = allocate(), allocate() @@ -50,7 +51,8 @@ job.register('structures.pages.collected', tobesaved, initializer) local specification = { } -- to be checked function pages.save(prefixdata,numberdata) - local realpage, userpage = texcount.realpageno, texcount.userpageno + local realpage = texgetcount("realpageno") + local userpage = texgetcount("userpageno") if realpage > 0 then if trace_pages then report_pages("saving page %s.%s",realpage,userpage) @@ -74,24 +76,24 @@ end -- builder we have to make sure it starts at least at 1. function counters.specials.userpage() - local r = texcount.realpageno + local r = texgetcount("realpageno") if r > 0 then local t = tobesaved[r] if t then - t.number = texcount.userpageno + t.number = texgetcount("userpageno") if trace_pages then report_pages("forcing pagenumber of realpage %s to %s",r,t.number) end return end end - local u = texcount.userpageno + local u = texgetcount("userpageno") if u == 0 then if trace_pages then report_pages("forcing pagenumber of realpage %s to %s (probably a bug)",r,1) end counters.setvalue("userpage",1) - texcount.userpageno = 1 + texsetcount("userpageno",1) -- not global ? end end @@ -253,8 +255,8 @@ function helpers.prefix(data,prefixspec) end function pages.is_odd(n) - n = n or texcount.realpageno - if texcount.pagenoshift % 2 == 0 then + n = n or texgetcount("realpageno") + if texgetcount("pagenoshift") % 2 == 0 then return n % 2 == 0 else return n % 2 ~= 0 diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua index 8e65a6b19..4c4a0fe7f 100644 --- a/tex/context/base/strc-ref.lua +++ b/tex/context/base/strc-ref.lua @@ -15,7 +15,6 @@ if not modules then modules = { } end modules ['strc-ref'] = { -- todo: autoload components when ::: local format, find, gmatch, match, concat = string.format, string.find, string.gmatch, string.match, table.concat -local texcount, texsetcount = tex.count, tex.setcount local floor = math.floor local rawget, tonumber = rawget, tonumber local lpegmatch = lpeg.match @@ -49,15 +48,15 @@ local constants = interfaces.constants local context = context local commands = commands +local texgetcount = tex.getcount +local texsetcount = tex.setcount +local texconditionals = tex.conditionals + local v_default = variables.default local v_url = variables.url local v_file = variables.file local v_unknown = variables.unknown local v_yes = variables.yes - -local texcount = tex.count -local texconditionals = tex.conditionals - local productcomponent = resolvers.jobs.productcomponent local justacomponent = resolvers.jobs.justacomponent @@ -212,7 +211,7 @@ local function referredpage(n) end end -- fallback - return texcount.realpageno + return texgetcount("realpageno") end -- setmetatableindex(referred,function(t,k) return referredpage(k) end ) @@ -224,7 +223,7 @@ function references.registerpage(n) -- called in the backend code if n > maxreferred then maxreferred = n end - tobereferred[n] = texcount.realpageno + tobereferred[n] = texgetcount("realpageno") end end @@ -250,7 +249,7 @@ references.setnextorder = setnextorder function references.setnextinternal(kind,name) setnextorder(kind,name) -- always incremented with internal - local n = texcount.locationcount + 1 + local n = texgetcount("locationcount") + 1 texsetcount("global","locationcount",n) return n end @@ -309,7 +308,7 @@ end function references.enhance(prefix,tag) local l = tobesaved[prefix][tag] if l then - l.references.realpage = texcount.realpageno + l.references.realpage = texgetcount("realpageno") end end @@ -1545,7 +1544,7 @@ local function identify(prefix,reference) end local set = resolve(prefix,reference) local bug = false - texcount.referencehastexstate = set.has_tex and 1 or 0 + texsetcount("referencehastexstate",set.has_tex and 1 or 0) nofidentified = nofidentified + 1 set.n = nofidentified for i=1,#set do @@ -1673,14 +1672,14 @@ function references.setinternalreference(prefix,tag,internal,view) -- needs chec t[tn] = "aut:" .. internal end local destination = references.mark(t,nil,nil,view) -- returns an attribute - texcount.lastdestinationattribute = destination + texsetcount("lastdestinationattribute",destination) return destination end end function references.setandgetattribute(kind,prefix,tag,data,view) -- maybe do internal automatically here local attr = references.set(kind,prefix,tag,data) and references.setinternalreference(prefix,tag,nil,view) or unsetvalue - texcount.lastdestinationattribute = attr + texsetcount("lastdestinationattribute",attr) return attr end @@ -2039,7 +2038,7 @@ function references.checkedrealpage(r) realpageofpage(r) -- just initialize end if not r then - return texcount.realpageno + return texgetcount("realpageno") elseif r < 1 then return 1 elseif r > nofrealpages then @@ -2132,7 +2131,7 @@ end function specials.deltapage(var,actions) local p = tonumber(var.operation) if p then - p = references.checkedrealpage(p + texcount.realpageno) + p = references.checkedrealpage(p + texgetcount("realpageno")) var.r = p actions.realpage = actions.realpage or p -- first wins end diff --git a/tex/context/base/strc-reg.lua b/tex/context/base/strc-reg.lua index f4682c90d..2356acb9b 100644 --- a/tex/context/base/strc-reg.lua +++ b/tex/context/base/strc-reg.lua @@ -7,7 +7,6 @@ if not modules then modules = { } end modules ['strc-reg'] = { } local next, type = next, type -local texcount = tex.count local format, gmatch = string.format, string.gmatch local equal, concat, remove = table.are_equal, table.concat, table.remove local utfchar = utf.char @@ -33,6 +32,8 @@ local replacements = sorters.replacements local processors = typesetters.processors local splitprocessor = processors.split +local texgetcount = tex.getcount + local variables = interfaces.variables local context = context local commands = commands @@ -287,7 +288,7 @@ end function registers.enhance(name,n) local r = tobesaved[name].entries[n] if r then - r.references.realpage = texcount.realpageno + r.references.realpage = texgetcount("realpageno") end end @@ -299,7 +300,7 @@ function registers.extend(name,tag,rawdata) -- maybe do lastsection internally local r = tobesaved[name].entries[tag] if r then local rr = r.references - rr.lastrealpage = texcount.realpageno + rr.lastrealpage = texgetcount("realpageno") rr.lastsection = sections.currentid() if rawdata then if rawdata.entries then diff --git a/tex/context/base/supp-box.lua b/tex/context/base/supp-box.lua index 8e75b4f63..a8603ace3 100644 --- a/tex/context/base/supp-box.lua +++ b/tex/context/base/supp-box.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['supp-box'] = { license = "see context related readme files" } --- this is preliminary code +-- this is preliminary code, use insert_before etc local report_hyphenation = logs.reporter("languages","hyphenation") @@ -30,7 +30,9 @@ local copy_list = node.copy_list local copy_node = node.copy local find_tail = node.tail -local texbox = tex.box +local texsetbox = tex.setbox +local texgetbox = tex.getbox +local texget = tex.get local function hyphenatedlist(list) while list do @@ -60,7 +62,7 @@ end local function checkedlist(list) if type(list) == "number" then - return texbox[list].list + return texgetbox(list).list else return list end @@ -116,7 +118,7 @@ commands.applytochars = applytochars commands.applytowords = applytowords function commands.vboxlisttohbox(original,target,inbetween) - local current = texbox[original].list + local current = texgetbox(original).list local head = nil local tail = nil while current do @@ -142,12 +144,12 @@ function commands.vboxlisttohbox(original,target,inbetween) end local result = new_hlist() result.list = head - texbox[target] = result + texsetbox(target,result) end function commands.hboxtovbox(original) - local b = texbox[original] - local factor = tex.baselineskip.width / tex.hsize + local b = texgetbox(original) + local factor = texget("baselineskip").width / texget("hsize") b.depth = 0 b.height = b.width * factor end diff --git a/tex/context/base/tabl-tbl.lua b/tex/context/base/tabl-tbl.lua index 19548e7b3..21564a472 100644 --- a/tex/context/base/tabl-tbl.lua +++ b/tex/context/base/tabl-tbl.lua @@ -15,7 +15,7 @@ local tonumber = tonumber local gsub, rep, sub, find = string.gsub, string.rep, string.sub, string.find local P, C, Cc, Ct, lpegmatch = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.match -local settexcount = tex.setcount +local texsetcount = tex.setcount local separator = P("|") local nested = lpeg.patterns.nested @@ -31,9 +31,9 @@ function commands.presettabulate(preamble) end local t = lpegmatch(pattern,preamble) local m = #t - 2 - settexcount("global","c_tabl_tabulate_nofcolumns", m/2) - settexcount("global","c_tabl_tabulate_has_rule_spec_first", t[1] == "" and 0 or 1) - settexcount("global","c_tabl_tabulate_has_rule_spec_last", t[m+1] == "" and 0 or 1) + texsetcount("global","c_tabl_tabulate_nofcolumns", m/2) + texsetcount("global","c_tabl_tabulate_has_rule_spec_first", t[1] == "" and 0 or 1) + texsetcount("global","c_tabl_tabulate_has_rule_spec_last", t[m+1] == "" and 0 or 1) for i=1,m,2 do context.settabulateentry(t[i],t[i+1]) end diff --git a/tex/context/base/tabl-xtb.lua b/tex/context/base/tabl-xtb.lua index 3ffe8a219..b0af0d5c8 100644 --- a/tex/context/base/tabl-xtb.lua +++ b/tex/context/base/tabl-xtb.lua @@ -27,11 +27,12 @@ this mechamism will be improved so that it can replace its older cousin. local commands, context, tex, node = commands, context, tex, node -local texdimen = tex.dimen -local texcount = tex.count -local texbox = tex.box +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 format = string.format local concat = table.concat @@ -171,11 +172,11 @@ function xtables.create(settings) settings.leftmargindistance = tonumber(settings.leftmargindistance) or 0 settings.rightmargindistance = tonumber(settings.rightmargindistance) or 0 settings.options = settings_to_hash(settings.option) - settings.textwidth = tonumber(settings.textwidth) or tex.hsize - settings.lineheight = tonumber(settings.lineheight) or texdimen.lineheight + settings.textwidth = tonumber(settings.textwidth) or texget("hsize") + settings.lineheight = tonumber(settings.lineheight) or texgetdimen("lineheight") settings.maxwidth = tonumber(settings.maxwidth) or settings.textwidth/8 -- if #stack > 0 then - -- settings.textwidth = tex.hsize + -- settings.textwidth = texget("hsize") -- end data.criterium_v = 2 * data.settings.lineheight data.criterium_h = .75 * data.settings.textwidth @@ -186,10 +187,10 @@ function xtables.initialize_reflow_width(option) local r = data.currentrow local c = data.currentcolumn + 1 local drc = data.rows[r][c] - drc.nx = texcount.c_tabl_x_nx - drc.ny = texcount.c_tabl_x_ny + drc.nx = texgetcount("c_tabl_x_nx") + drc.ny = texgetcount("c_tabl_x_ny") local distances = data.distances - local distance = texdimen.d_tabl_x_distance + local distance = texgetdimen("d_tabl_x_distance") if distance > distances[c] then distances[c] = distance end @@ -214,7 +215,7 @@ function xtables.set_reflow_width() while row[c].span do -- can also be previous row ones c = c + 1 end - local tb = texbox.b_tabl_x + local tb = texgetbox("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)) @@ -232,7 +233,7 @@ function xtables.set_reflow_width() depths[r] = depth end -- - local dimensionstate = texcount.frameddimensionstate + local dimensionstate = texgetcount("frameddimensionstate") local fixedcolumns = data.fixedcolumns local fixedrows = data.fixedrows if dimensionstate == 1 then @@ -294,19 +295,19 @@ function xtables.initialize_reflow_height() for x=1,drc.nx-1 do w = w + widths[c+x] end - texdimen.d_tabl_x_width = w + texsetdimen("d_tabl_x_width",w) local dimensionstate = drc.dimensionstate or 0 if dimensionstate == 1 or dimensionstate == 3 then -- width was fixed so height is known - texcount.c_tabl_x_skip_mode = 1 + texsetcount("c_tabl_x_skip_mode",1) elseif dimensionstate == 2 then -- height is enforced - texcount.c_tabl_x_skip_mode = 1 + texsetcount("c_tabl_x_skip_mode",1) elseif data.autowidths[c] then -- width has changed so we need to recalculate the height - texcount.c_tabl_x_skip_mode = 0 + texsetcount("c_tabl_x_skip_mode",0) else - texcount.c_tabl_x_skip_mode = 1 + texsetcount("c_tabl_x_skip_mode",1) end end @@ -315,10 +316,10 @@ function xtables.set_reflow_height() local c = data.currentcolumn local rows = data.rows local row = rows[r] --- while row[c].span do -- we could adapt drc.nx instead --- c = c + 1 --- end - local tb = texbox.b_tabl_x + -- while row[c].span do -- we could adapt drc.nx instead + -- c = c + 1 + -- end + local tb = texgetbox("b_tabl_x") local drc = row[c] if data.fixedrows[r] == 0 then -- and drc.dimensionstate < 2 local heights, height = data.heights, tb.height @@ -330,8 +331,8 @@ function xtables.set_reflow_height() depths[r] = depth end end --- c = c + drc.nx - 1 --- data.currentcolumn = c + -- c = c + drc.nx - 1 + -- data.currentcolumn = c end function xtables.initialize_construct() @@ -357,9 +358,9 @@ function xtables.initialize_construct() h = h + heights[r+y] d = d + depths[r+y] end - texdimen.d_tabl_x_width = w - texdimen.d_tabl_x_height = h + d - texdimen.d_tabl_x_depth = 0 + texsetdimen("d_tabl_x_width",w) + texsetdimen("d_tabl_x_height",h + d) + texsetdimen("d_tabl_x_depth",0) end function xtables.set_construct() @@ -367,14 +368,14 @@ function xtables.set_construct() local c = data.currentcolumn local rows = data.rows local row = rows[r] --- while row[c].span do -- can also be previous row ones --- c = c + 1 --- end + -- while row[c].span do -- can also be previous row ones + -- c = c + 1 + -- 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(texbox.b_tabl_x) --- c = c + drc.nx - 1 --- data.currentcolumn = c + drc.list = copy_node_list(texgetbox("b_tabl_x")) + -- c = c + drc.nx - 1 + -- data.currentcolumn = c end local function showwidths(where,widths,autowidths) @@ -669,8 +670,8 @@ function xtables.construct() end local kern = new_kern(step) if stop then - stop.prev = kern stop.next = kern + kern.prev = stop else -- can be first spanning next row (ny=...) start = kern end @@ -724,6 +725,8 @@ function xtables.construct() end end +-- todo: join as that is as efficient as fushing multiple + local function inject(row,copy,package) local list = row[1] if copy then @@ -966,7 +969,7 @@ end function xtables.next_row() local r = data.currentrow + 1 - data.modes[r] = texcount.c_tabl_x_mode + data.modes[r] = texgetcount("c_tabl_x_mode") data.currentrow = r data.currentcolumn = 0 end diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua index 0f477cb6e..107bfe226 100644 --- a/tex/context/base/task-ini.lua +++ b/tex/context/base/task-ini.lua @@ -103,7 +103,7 @@ appendaction("vboxbuilders", "normalizers", "builders.vspacing.vboxhandler") -- experimental too -appendaction("mvlbuilders","normalizers","typesetters.checkers.handler") +appendaction("mvlbuilders", "normalizers","typesetters.checkers.handler") appendaction("vboxbuilders","normalizers","typesetters.checkers.handler") -- speedup: only kick in when used diff --git a/tex/context/base/trac-deb.lua b/tex/context/base/trac-deb.lua index fe167c343..4cc48c4a5 100644 --- a/tex/context/base/trac-deb.lua +++ b/tex/context/base/trac-deb.lua @@ -11,22 +11,25 @@ local lpeg, status = lpeg, status local lpegmatch = lpeg.match local format, concat, match = string.format, table.concat, string.match local tonumber, tostring = tonumber, tostring -local texdimen, textoks, texcount = tex.dimen, tex.toks, tex.count -- maybe tracers -> tracers.tex (and tracers.lua for current debugger) local report_system = logs.reporter("system","tex") -tracers = tracers or { } -local tracers = tracers +tracers = tracers or { } +local tracers = tracers -tracers.lists = { } -local lists = tracers.lists +tracers.lists = { } +local lists = tracers.lists -tracers.strings = { } -local strings = tracers.strings +tracers.strings = { } +local strings = tracers.strings -strings.undefined = "undefined" +local texgetdimen = tex.getdimen +local texgettoks = tex.gettoks +local texgetcount = tex.getcount + +strings.undefined = "undefined" lists.scratch = { 0, 2, 4, 6, 8 @@ -71,16 +74,16 @@ function tracers.cs(csname) end function tracers.dimen(name) - local d = texdimen[name] + local d = texgetdimen(name) return d and number.topoints(d) or strings.undefined end function tracers.count(name) - return texcount[name] or strings.undefined + return texgetcount(name) or strings.undefined end function tracers.toks(name,limit) - local t = textoks[name] + local t = texgettoks(name) return t and string.limit(t,tonumber(limit) or 40) or strings.undefined end diff --git a/tex/context/base/trac-inf.lua b/tex/context/base/trac-inf.lua index eefc15a6f..79cbdba3f 100644 --- a/tex/context/base/trac-inf.lua +++ b/tex/context/base/trac-inf.lua @@ -11,20 +11,24 @@ if not modules then modules = { } end modules ['trac-inf'] = { -- get warnings about assignments. This is more efficient than using rawset -- and rawget. -local type, tonumber = type, tonumber +local type, tonumber, select = type, tonumber, select local format, lower = string.format, string.lower local concat = table.concat local clock = os.gettimeofday or os.clock -- should go in environment -statistics = statistics or { } -local statistics = statistics +local setmetatableindex = table.setmetatableindex +local serialize = table.serialize +local formatters = string.formatters -statistics.enable = true -statistics.threshold = 0.01 +statistics = statistics or { } +local statistics = statistics + +statistics.enable = true +statistics.threshold = 0.01 local statusinfo, n, registered, timers = { }, 0, { }, { } -table.setmetatableindex(timers,function(t,k) +setmetatableindex(timers,function(t,k) local v = { timing = 0, loadtime = 0 } t[k] = v return v @@ -178,6 +182,19 @@ function statistics.timed(action) report("total runtime: %s",elapsedtime("run")) end +-- goodie + +function statistics.tracefunction(base,tag,...) + for i=1,select("#",...) do + local name = select(i,...) + local stat = { } + local func = base[name] + setmetatableindex(stat,function(t,k) t[k] = 0 return 0 end) + base[name] = function(n,k,v) stat[k] = stat[k] + 1 return func(n,k,v) end + statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end) + end +end + -- where, not really the best spot for this: commands = commands or { } diff --git a/tex/context/base/trac-jus.lua b/tex/context/base/trac-jus.lua index 9d99f059d..38220a752 100644 --- a/tex/context/base/trac-jus.lua +++ b/tex/context/base/trac-jus.lua @@ -15,19 +15,16 @@ local a_alignstate = attributes.private("alignstate") local a_justification = attributes.private("justification") local tracers = nodes.tracers -local setcolor = tracers.colors.set -local settransparency = tracers.transparencies.set +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 concat_nodes = nodes.concat -local hpack_nodes = node.hpack -local copy_node = node.copy local get_list_dimensions = node.dimensions local hlist_code = nodes.nodecodes.hlist -local tex_set_attribute = tex.setattribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local min_threshold = 0 @@ -36,14 +33,14 @@ local max_threshold = 0 local function set(n) nodes.tasks.enableaction("mvlbuilders", "typesetters.checkers.handler") nodes.tasks.enableaction("vboxbuilders","typesetters.checkers.handler") - tex_set_attribute(a_justification,n or 1) + texsetattribute(a_justification,n or 1) function typesetters.checkers.set(n) - tex_set_attribute(a_justification,n or 1) + texsetattribute(a_justification,n or 1) end end local function reset() - tex_set_attribute(a_justification,unsetvalue) + texsetattribute(a_justification,unsetvalue) end checkers.set = set @@ -74,58 +71,22 @@ function checkers.handler(head) if naturalwidth == 0 or delta == 0 then -- special box elseif delta >= max_threshold then - local rule = new_rule(delta,naturalheight,naturaldepth) - list = hpack_nodes(list,width,"exactly") - if list.glue_set == 1 then - setcolor(rule,"trace:dr") - settransparency(rule,"trace:dr") - else - setcolor(rule,"trace:db") - settransparency(rule,"trace:db") - end - rule = hpack_nodes(rule) - rule.width = 0 - rule.height = 0 - rule.depth = 0 - current.list = concat_nodes { list, rule } - -- current.list = concat_nodes { list, new_kern(-naturalwidth+width), rule } + local rule = tracedrule(delta,naturalheight,naturaldepth,list.glue_set == 1 and "trace:dr"or "trace:db") + current.list = list .. new_hlist(rule) elseif delta <= min_threshold then local alignstate = list[a_alignstate] if alignstate == 1 then - local rule = new_rule(-delta,naturalheight,naturaldepth) - setcolor(rule,"trace:dc") - settransparency(rule,"trace:dc") - rule = hpack_nodes(rule) - rule.height = 0 - rule.depth = 0 - rule.width = 0 - current.list = nodes.concat { rule, list } + local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dc") + current.list = new_hlist(rule) .. list elseif alignstate == 2 then - local rule = new_rule(-delta/2,naturalheight,naturaldepth) - setcolor(rule,"trace:dy") - settransparency(rule,"trace:dy") - rule = hpack_nodes(rule) - rule.width = 0 - rule.height = 0 - rule.depth = 0 - current.list = concat_nodes { copy_node(rule), list, new_kern(delta/2), rule } + local rule = tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy") + current.list = new_hlist(rule^1) .. list .. new_kern(delta/2) .. new_hlist(rule) elseif alignstate == 3 then - local rule = new_rule(-delta,naturalheight,naturaldepth) - setcolor(rule,"trace:dm") - settransparency(rule,"trace:dm") - rule = hpack_nodes(rule) - rule.height = 0 - rule.depth = 0 - current.list = concat_nodes { list, new_kern(delta), rule } + local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dm") + current.list = list .. new_kern(delta) .. new_hlist(rule) else - local rule = new_rule(-delta,naturalheight,naturaldepth) - setcolor(rule,"trace:dg") - settransparency(rule,"trace:dg") - rule = hpack_nodes(rule) - rule.height = 0 - rule.depth = 0 - rule.width = 0 - current.list = concat_nodes { list, new_kern(delta), rule } + local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dg") + current.list = list .. new_kern(delta) .. new_hlist(rule) end end end diff --git a/tex/context/base/trac-log.lua b/tex/context/base/trac-log.lua index 1f2520130..0ae5d87e3 100644 --- a/tex/context/base/trac-log.lua +++ b/tex/context/base/trac-log.lua @@ -68,13 +68,14 @@ local write_nl, write = texio and texio.write_nl or print, texio and texio.write local format, gmatch, find = string.format, string.gmatch, string.find local concat, insert, remove = table.concat, table.insert, table.remove local topattern = string.topattern -local texcount = tex and tex.count local next, type, select = next, type, select local utfchar = utf.char local setmetatableindex = table.setmetatableindex local formatters = string.formatters +local texgetcount = tex and tex.getcount + --[[ldx-- <p>This is a prelude to a more extensive logging module. We no longer provide <l n='xml'/> based logging as parsing is relatively easy anyway.</p> @@ -129,7 +130,7 @@ setmetatableindex(logs, function(t,k) t[k] = ignore ; return ignore end) local report, subreport, status, settarget, setformats, settranslations -local direct, subdirect, writer, pushtarget, poptarget +local direct, subdirect, writer, pushtarget, poptarget, setlogfile if tex and (tex.jobname or tex.formatname) then @@ -270,11 +271,15 @@ if tex and (tex.jobname or tex.formatname) then translations = t end + setlogfile = ignore + else logs.flush = ignore - writer = write_nl + writer = function(s) + write_nl(s) + end newline = function() write_nl("\n") @@ -334,6 +339,29 @@ else setformats = ignore settranslations = ignore + local f_timed = formatters["[%S] "] + + setlogfile = function(name,keepopen) + if name and name ~= "" then + local localtime = os.localtime + local writeline = write_nl + if keepopen then + local f = io.open(name,"ab") + write_nl = function(s) + writeline(s) + f:write(f_timed(localtime()),s,"\n") + end + else + write_nl = function(s) + writeline(s) + local f = io.open(name,"ab") + f:write(f_timed(localtime()),s,"\n") + f:close() + end + end + end + end + end logs.report = report @@ -345,6 +373,8 @@ logs.poptarget = poptarget logs.setformats = setformats logs.settranslations = settranslations +logs.setlogfile = setlogfile + logs.direct = direct logs.subdirect = subdirect logs.writer = writer @@ -529,8 +559,9 @@ local report_pages = logs.reporter("pages") -- not needed but saves checking whe local real, user, sub function logs.start_page_number() - real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno --- real, user, sub = 0, 0, 0 + real = texgetcount("realpageno") + user = texgetcount("userpageno") + sub = texgetcount("subpageno") end local timing = false diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua index 762c71ab5..4a24dacf4 100644 --- a/tex/context/base/trac-vis.lua +++ b/tex/context/base/trac-vis.lua @@ -60,11 +60,9 @@ local rightskip_code = gluecodes.rightskip local whatsitcodes = nodes.whatsitcodes -local concat_nodes = nodes.concat local hpack_nodes = node.hpack local vpack_nodes = node.vpack -local hpack_string = typesetters.hpack -local fast_hpack_string = typesetters.fast_hpack +local fast_hpack_string = nodes.typesetters.fast_hpack local copy_node = node.copy local copy_list = node.copy_list local free_node = node.free @@ -74,8 +72,9 @@ local insert_node_after = node.insert_after local fast_hpack = nodes.fasthpack local traverse_nodes = node.traverse -local tex_attribute = tex.attribute -local tex_box = tex.box +local texgetattribute = tex.getattribute +local texsetattribute = tex.setattribute +local texgetbox = tex.getbox local unsetvalue = attributes.unsetvalue local current_font = font.current @@ -247,11 +246,11 @@ local function setvisual(n,a,what) -- this will become more efficient when we ha end function visualizers.setvisual(n) - tex_attribute[a_visual] = setvisual(n,tex_attribute[a_visual]) + texsetattribute(a_visual,setvisual(n,texgetattribute(a_visual))) end function visualizers.setlayer(n) - tex_attribute[a_layer] = layers[n] or unsetvalue + texsetattribute(a_layer,layers[n] or unsetvalue) end commands.setvisual = visualizers.setvisual @@ -262,7 +261,7 @@ function commands.visual(n) end local function set(mode,v) - tex_attribute[a_visual] = setvisual(mode,tex_attribute[a_visual],v) + texsetattribute(a_visual,setvisual(mode,texgetattribute(a_visual),v)) end for mode, value in next, modes do @@ -305,11 +304,7 @@ local function sometext(str,layer,color,textcolor) -- we can just paste verbatim if textcolor then setlistcolor(text.list,textcolor) end - local info = concat_nodes { - rule, - kern, - text, - } + local info = rule .. kern .. text setlisttransparency(info,c_zero) info = fast_hpack(info) if layer then @@ -343,10 +338,7 @@ local function fontkern(head,current) setlisttransparency(list,c_text_d) settransparency(rule,c_text_d) text.shift = -5 * exheight - info = concat_nodes { - rule, - text, - } + info = rule .. text info = fast_hpack(info) info[a_layer] = l_fontkern info.width = 0 @@ -426,9 +418,12 @@ local b_cache = { } local function ruledbox(head,current,vertical,layer,what,simple) local wd = current.width if wd ~= 0 then - local ht, dp = current.height, current.depth - local next, prev = current.next, current.prev - current.next, current.prev = nil, nil + local ht = current.height + local dp = current.depth + local next = current.next + local prev = current.prev + current.next = nil + current.prev = nil local linewidth = emwidth/10 local baseline, baseskip if dp ~= 0 and ht ~= 0 then @@ -437,19 +432,16 @@ local function ruledbox(head,current,vertical,layer,what,simple) 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 = concat_nodes { - new_glue(2*linewidth), -- 2.5 - new_rule(6*linewidth,linewidth,0), -- 5.0 - new_glue(2*linewidth), -- 2.5 - } + local leader = 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 - baseline.spec.stretch = 65536 - baseline.spec.stretch_order = 2 + local spec = baseline.spec + spec.stretch = 65536 + spec.stretch_order = 2 setlisttransparency(baseline,c_text) b_cache.baseline = baseline end @@ -471,10 +463,7 @@ local function ruledbox(head,current,vertical,layer,what,simple) this = b_cache[what] if not this then local text = fast_hpack_string(what,usedfont) - this = concat_nodes { - new_kern(-text.width), - text, - } + this = new_kern(-text.width) .. text setlisttransparency(this,c_text) this = fast_hpack(this) this.width = 0 @@ -483,27 +472,24 @@ local function ruledbox(head,current,vertical,layer,what,simple) b_cache[what] = this end end - local info = concat_nodes { - this and copy_list(this) or nil, -- this also triggers the right mode (else sometimes no whatits) - 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), - baseskip, - baseline, - } + -- 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) .. + new_rule(wd-2*linewidth,ht,-ht+linewidth) + if baseskip then + info = 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 = concat_nodes { - current, - new_kern(-wd), - info, - } + local info = current .. new_kern(-wd) .. info info = fast_hpack(info,wd) if vertical then info = vpack_nodes(info) @@ -533,25 +519,27 @@ end local function ruledglyph(head,current) local wd = current.width if wd ~= 0 then - local ht, dp = current.height, current.depth - local next, prev = current.next, current.prev - current.next, current.prev = nil, nil + local ht = current.height + local dp = current.depth + local next = current.next + local prev = current.prev + current.next = nil + current.prev = nil local linewidth = emwidth/20 local baseline if dp ~= 0 and ht ~= 0 then baseline = new_rule(wd-2*linewidth,linewidth,0) end local doublelinewidth = 2*linewidth - local info = concat_nodes { - -- could be a pdf rule - 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, - } + -- 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) .. + baseline setlistcolor(info,c_glyph) setlisttransparency(info,c_glyph_d) info = fast_hpack(info) @@ -559,11 +547,7 @@ local function ruledglyph(head,current) info.height = 0 info.depth = 0 info[a_layer] = l_glyph - local info = concat_nodes { - current, - new_kern(-wd), - info, - } + local info = current .. new_kern(-wd) .. info info = fast_hpack(info) info.width = wd if next then @@ -857,13 +841,13 @@ end function visualizers.handler(head) if usedfont then starttiming(visualizers) - -- local l = tex_attribute[a_layer] - -- local v = tex_attribute[a_visual] - -- tex_attribute[a_layer] = unsetvalue - -- tex_attribute[a_visual] = unsetvalue + -- local l = texgetattribute(a_layer) + -- local v = texgetattribute(a_visual) + -- texsetattribute(a_layer,unsetvalue) + -- texsetattribute(a_visual,unsetvalue) head = visualize(head) - -- tex_attribute[a_layer] = l - -- tex_attribute[a_visual] = v + -- texsetattribute(a_layer,l) + -- texsetattribute(a_visual,v) -- -- cleanup() stoptiming(visualizers) end @@ -871,7 +855,8 @@ function visualizers.handler(head) end function visualizers.box(n) - tex_box[n].list = visualizers.handler(tex_box[n].list) + local box = texgetbox(n) + box.list = visualizers.handler(box.list) end local last = nil @@ -903,7 +888,7 @@ end function visualizers.markfonts(list) last, used = 0, { } - markfonts(type(n) == "number" and tex_box[n].list or n) + markfonts(type(n) == "number" and texgetbox(n).list or n) end function commands.markfonts(n) diff --git a/tex/context/base/typo-bld.lua b/tex/context/base/typo-bld.lua index ed700add7..bc9f66ee4 100644 --- a/tex/context/base/typo-bld.lua +++ b/tex/context/base/typo-bld.lua @@ -31,6 +31,7 @@ constructors.attribute = a_parbuilder local unsetvalue = attributes.unsetvalue local texsetattribute = tex.setattribute local texnest = tex.nest +local texlists = tex.lists local nodepool = nodes.pool local new_baselineskip = nodepool.baselineskip @@ -183,3 +184,72 @@ commands.stopparbuilder = constructors.stop commands.setparbuilder = constructors.set commands.enableparbuilder = constructors.enable commands.disableparbuilder = constructors.disable + +-- todo: move from nodes.builders to builders + +nodes.builders = nodes.builder or { } +local builders = nodes.builders + +local actions = nodes.tasks.actions("vboxbuilders") + +function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction) + local done = false + if head then + starttiming(builders) + if trace_vpacking then + local before = nodes.count(head) + head, done = actions(head,groupcode,size,packtype,maxdepth,direction) + local after = nodes.count(head) + if done then + nodes.processors.tracer("vpack","changed",head,groupcode,before,after,true) + else + nodes.processors.tracer("vpack","unchanged",head,groupcode,before,after,true) + end + else + head, done = actions(head,groupcode) + end + stoptiming(builders) + end + return head, done +end + +-- This one is special in the sense that it has no head and we operate on the mlv. Also, +-- we need to do the vspacing last as it removes items from the mvl. + +local actions = nodes.tasks.actions("mvlbuilders") + +local function report(groupcode,head) + report_page_builder("trigger: %s",groupcode) + report_page_builder(" vsize : %p",tex.vsize) + report_page_builder(" pagegoal : %p",tex.pagegoal) + report_page_builder(" pagetotal: %p",tex.pagetotal) + report_page_builder(" list : %s",head and nodeidstostring(head) or "<empty>") +end + +function builders.buildpage_filter(groupcode) + local head, done = texlists.contrib_head, false + if head then + starttiming(builders) + if trace_page_builder then + report(groupcode,head) + end + head, done = actions(head,groupcode) + stoptiming(builders) + -- -- doesn't work here (not passed on?) + -- tex.pagegoal = tex.vsize - tex.dimen.d_page_floats_inserted_top - tex.dimen.d_page_floats_inserted_bottom + texlists.contrib_head = head + return done and head or true + else + if trace_page_builder then + report(groupcode) + end + return nil, false + end +end + +callbacks.register('vpack_filter', builders.vpack_filter, "vertical spacing etc") +callbacks.register('buildpage_filter', builders.buildpage_filter, "vertical spacing etc (mvl)") + +statistics.register("v-node processing time", function() + return statistics.elapsedseconds(builders) +end) diff --git a/tex/context/base/typo-brk.lua b/tex/context/base/typo-brk.lua index d6326ebeb..a05cca25b 100644 --- a/tex/context/base/typo-brk.lua +++ b/tex/context/base/typo-brk.lua @@ -29,7 +29,7 @@ local remove_node = nodes.remove -- ! nodes local tonodes = nodes.tonodes -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodepool = nodes.pool @@ -156,7 +156,7 @@ methods[5] = function(head,start,settings) -- x => p q r end local function process(namespace,attribute,head) - local done, numbers = false, languages.numbers + local done, numbers = false, languages.numbers local start, n = head, 0 while start do local id = start.id @@ -282,7 +282,7 @@ function breakpoints.set(n) n = n.number end end - texattribute[a_breakpoints] = n + texsetattribute(a_breakpoints,n) end breakpoints.handler = nodes.installattributehandler { diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua index fdbf2e353..e9c98c846 100644 --- a/tex/context/base/typo-cap.lua +++ b/tex/context/base/typo-cap.lua @@ -20,7 +20,7 @@ local traverse_id = node.traverse_id local copy_node = node.copy local end_of_math = node.end_of_math -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodecodes = nodes.nodecodes @@ -167,7 +167,7 @@ local function Word(start,attribute,attr) prev = prev.prev end if not prev or prev.id ~= glyph_code then - --- only the first character is treated + -- only the first character is treated for n in traverse_id(glyph_code,start.next) do if n[attribute] == attr then n[attribute] = unsetvalue @@ -316,7 +316,7 @@ function cases.set(n) n = unsetvalue end end - texattribute[a_cases] = n + texsetattribute(a_cases,n) -- return n -- bonus end diff --git a/tex/context/base/typo-cln.lua b/tex/context/base/typo-cln.lua index be00ac10d..b4b682bff 100644 --- a/tex/context/base/typo-cln.lua +++ b/tex/context/base/typo-cln.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['typo-cln'] = { } -- This quick and dirty hack took less time than listening to a CD (In --- this case Dream Theaters' Octavium. Of course extensions will take +-- this case Dream Theaters' Octavium). Of course extensions will take -- more time. local utfbyte = utf.byte @@ -26,7 +26,7 @@ local variables = interfaces.variables local nodecodes = nodes.nodecodes local tasks = nodes.tasks -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local traverse_id = node.traverse_id @@ -78,7 +78,7 @@ local enabled = false function cleaners.set(n) if n == variables.reset or not tonumber(n) or n == 0 then - texattribute[a_cleaner] = unsetvalue + texsetattribute(a_cleaner,unsetvalue) else if not enabled then tasks.enableaction("processors","typesetters.cleaners.handler") @@ -87,7 +87,7 @@ function cleaners.set(n) end enabled = true end - texattribute[a_cleaner] = n + texsetattribute(a_cleaner,n) end end diff --git a/tex/context/base/typo-dig.lua b/tex/context/base/typo-dig.lua index 62d17fa3b..829e4cc7a 100644 --- a/tex/context/base/typo-dig.lua +++ b/tex/context/base/typo-dig.lua @@ -24,7 +24,7 @@ local traverse_id = node.traverse_id local insert_node_before = node.insert_before local insert_node_after = node.insert_after -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodecodes = nodes.nodecodes @@ -148,7 +148,7 @@ function digits.set(n) -- number or 'reset' n = unsetvalue end end - texattribute[a_digits] = n + texsetattribute(a_digits,n) end digits.handler = nodes.installattributehandler { -- we could avoid this wrapper diff --git a/tex/context/base/typo-dir.lua b/tex/context/base/typo-dir.lua index 7e5f8c2d3..fcf3e3acb 100644 --- a/tex/context/base/typo-dir.lua +++ b/tex/context/base/typo-dir.lua @@ -25,7 +25,7 @@ local insert_node_before = node.insert_before local insert_node_after = node.insert_after local remove_node = nodes.remove -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodecodes = nodes.nodecodes @@ -167,6 +167,8 @@ end -- todo: use new dir functions +-- todo: use end_of_math + local s_isol = fonts.analyzers.states.isol function directions.process(namespace,attribute,start) -- todo: make faster @@ -451,7 +453,7 @@ function directions.set(n) -- todo: names and numbers n = unsetvalue -- maybe tracing end - texattribute[a_directions] = n + texsetattribute(a_directions,n) end commands.setdirection = directions.set diff --git a/tex/context/base/typo-itc.lua b/tex/context/base/typo-itc.lua index b39ea2f23..9ef0aaed3 100644 --- a/tex/context/base/typo-itc.lua +++ b/tex/context/base/typo-itc.lua @@ -28,7 +28,8 @@ local insert_node_after = node.insert_after local delete_node = nodes.delete local end_of_math = node.end_of_math -local texattribute = tex.attribute +local texgetattribute = tex.getattribute +local texsetattribute = tex.setattribute local a_italics = attributes.private("italics") local unsetvalue = attributes.unsetvalue @@ -199,14 +200,14 @@ function italics.set(n) enable() end if n == variables.reset then - texattribute[a_italics] = unsetvalue + texsetattribute(a_italics,unsetvalue) else - texattribute[a_italics] = tonumber(n) or unsetvalue + texsetattribute(a_italics,tonumber(n) or unsetvalue) end end function italics.reset() - texattribute[a_italics] = unsetvalue + texsetattribute(a_italics,unsetvalue) end italics.handler = nodes.installattributehandler { @@ -231,10 +232,10 @@ function commands.setupitaliccorrection(option) -- no grouping ! end if options[variables.global] then forcedvariant = variant - texattribute[a_italics] = unsetvalue + texsetattribute(a_italics,unsetvalue) else forcedvariant = false - texattribute[a_italics] = variant + texsetattribute(a_italics,variant) end if trace_italics then report_italics("forcing %a, variant %a",forcedvariant,variant ~= unsetvalue and variant) @@ -246,11 +247,11 @@ end local stack = { } function commands.pushitaliccorrection() - table.insert(stack,{forcedvariant, texattribute[a_italics] }) + table.insert(stack,{forcedvariant, texgetattribute(a_italics) }) end function commands.popitaliccorrection() local top = table.remove(stack) forcedvariant = top[1] - texattribute[a_italics] = top[2] + texsetattribute(a_italics,top[2]) end diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua index fb28d3b2d..fb394044f 100644 --- a/tex/context/base/typo-krn.lua +++ b/tex/context/base/typo-krn.lua @@ -20,7 +20,7 @@ local insert_node_before = node.insert_before local insert_node_after = node.insert_after local end_of_math = node.end_of_math -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodepool = nodes.pool @@ -316,7 +316,7 @@ function kerns.set(factor) else factor = unsetvalue end - texattribute[a_kerns] = factor + texsetattribute(a_kerns,factor) return factor end diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua index ec827883d..85d5c85a8 100644 --- a/tex/context/base/typo-mar.lua +++ b/tex/context/base/typo-mar.lua @@ -123,8 +123,6 @@ local free_node_list = node.flush_list local insert_node_after = node.insert_after local insert_node_before = node.insert_before -local concat_nodes = nodes.concat - local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes local gluecodes = nodes.gluecodes @@ -155,9 +153,10 @@ local new_stretch = nodepool.stretch local new_usernumber = nodepool.usernumber local new_latelua = nodepool.latelua -local texcount = tex.count -local texdimen = tex.dimen -local texbox = tex.box +local texgetcount = tex.getcount +local texgetdimen = tex.getdimen +local texgetbox = tex.getbox +local texget = tex.get local points = number.points @@ -243,7 +242,7 @@ end function margins.save(t) setmetatable(t,defaults) - local content = texbox[t.number] + local content = texgetbox(t.number) local location = t.location local category = t.category local inline = t.inline @@ -309,23 +308,24 @@ function margins.save(t) t.n = nofsaved -- used later (we will clean up this natural mess later) -- nice is to make a special status table mechanism - local leftmargindistance = texdimen.naturalleftmargindistance - local rightmargindistance = texdimen.naturalrightmargindistance - t.strutdepth = texbox.strutbox.depth - t.strutheight = texbox.strutbox.height - t.leftskip = tex.leftskip.width -- we're not in forgetall - t.rightskip = tex.rightskip.width -- we're not in forgetall + 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 t.leftmargindistance = leftmargindistance -- todo:layoutstatus table t.rightmargindistance = rightmargindistance - t.leftedgedistance = texdimen.naturalleftedgedistance - + texdimen.leftmarginwidth + t.leftedgedistance = texgetdimen("naturalleftedgedistance") + + texgetdimen("leftmarginwidth") + leftmargindistance - t.rightedgedistance = texdimen.naturalrightedgedistance - + texdimen.rightmarginwidth + t.rightedgedistance = texgetdimen("naturalrightedgedistance") + + texgetdimen("rightmarginwidth") + rightmargindistance - t.lineheight = texdimen.lineheight + t.lineheight = texgetdimen("lineheight") -- - -- t.realpageno = texcount.realpageno + -- t.realpageno = texgetcount("realpageno") if inline then context(new_usernumber(inline_mark,nofsaved)) store[nofsaved] = t -- no insert @@ -447,7 +447,7 @@ local function realign(current,candidate) end end - current.list = hpack_nodes(concat_nodes{anchornode,new_kern(-delta),current.list,new_kern(delta)}) + current.list = hpack_nodes(anchornode .. new_kern(-delta) .. current.list .. new_kern(delta)) current.width = 0 end @@ -490,7 +490,7 @@ 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(concat_nodes{anchor,current.list}) + current.list = hpack_nodes(anchor .. current.list) end local function getovershoot(location) @@ -623,7 +623,7 @@ local function inject(parent,head,candidate) elseif head.id == whatsit_code and head.subtype == localpar_code then -- experimental if head.dir == "TRT" then - box.list = hpack_nodes(concat_nodes{new_kern(candidate.hsize),box.list,new_kern(-candidate.hsize)}) + box.list = hpack_nodes(new_kern(candidate.hsize) .. box.list .. new_kern(-candidate.hsize)) end insert_node_after(head,head,box) else diff --git a/tex/context/base/typo-par.lua b/tex/context/base/typo-par.lua index b25ae4a5b..5f8bd8d4a 100644 --- a/tex/context/base/typo-par.lua +++ b/tex/context/base/typo-par.lua @@ -8,6 +8,9 @@ if not modules then modules = { } end modules ['typo-par'] = { -- A playground for experiments. +local tonumber, type, next = tonumber, type, next +local ceil = math.ceil + local utfbyte = utf.byte local utfchar = utf.char @@ -26,7 +29,7 @@ local tasks = nodes.tasks local variables = interfaces.variables -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local glyph_code = nodecodes.glyph @@ -91,9 +94,9 @@ local function process(namespace,attribute,head) first = first.next end if first and first.id == glyph_code then --- if texattribute[a_paragraph] >= 0 then --- texattribute[a_paragraph] = unsetvalue --- end + -- if texgetattribute(a_paragraph) >= 0 then + -- texsetattribute(a_paragraph,unsetvalue) + -- end local char = first.char local prev = first.prev local next = first.next @@ -103,7 +106,9 @@ local function process(namespace,attribute,head) if next and next.id == kern_node then next.kern = 0 end - first.font = dropper.font or first.font + if dropper.font then + first.font = dropper.font + end -- can be a helper local ma = dropper.ma or 0 local ca = dropper.ca @@ -142,7 +147,7 @@ local function process(namespace,attribute,head) else local lines = tonumber(dropper.n) or 0 if lines == 0 then -- safeguard, not too precise - lines = math.ceil((height+voffset) / tex.baselineskip.width) + lines = ceil((height+voffset) / tex.baselineskip.width) end tex.hangafter = - lines tex.hangindent = width + distance @@ -159,7 +164,7 @@ local enabled = false function paragraphs.set(n) if n == variables.reset or not tonumber(n) or n == 0 then - texattribute[a_paragraph] = unsetvalue + texsetattribute(a_paragraph,unsetvalue) else if not enabled then tasks.enableaction("processors","typesetters.paragraphs.handler") @@ -168,7 +173,7 @@ function paragraphs.set(n) end enabled = true end - texattribute[a_paragraph] = n + texsetattribute(a_paragraph,n) end end diff --git a/tex/context/base/typo-rep.lua b/tex/context/base/typo-rep.lua index 8451ce52b..01868f490 100644 --- a/tex/context/base/typo-rep.lua +++ b/tex/context/base/typo-rep.lua @@ -17,23 +17,23 @@ local report_stripping = logs.reporter("fonts","stripping") local nodes, node = nodes, node -local delete_node = nodes.delete -local replace_node = nodes.replace -local copy_node = node.copy +local delete_node = nodes.delete +local replace_node = nodes.replace +local copy_node = node.copy -local chardata = characters.data -local collected = false -local a_stripping = attributes.private("stripping") -local fontdata = fonts.hashes.identifiers -local tasks = nodes.tasks +local chardata = characters.data +local collected = false +local a_stripping = attributes.private("stripping") +local fontdata = fonts.hashes.identifiers +local tasks = nodes.tasks -local texattribute = tex.attribute -local unsetvalue = attributes.unsetvalue +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue -local v_reset = interfaces.variables.reset +local v_reset = interfaces.variables.reset -local nodecodes = nodes.nodecodes -local glyph_code = nodecodes.glyph +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph -- todo: other namespace -> typesetters @@ -115,7 +115,7 @@ function stripping.set(n) -- number or 'reset' n = unsetvalue end end - texattribute[a_stripping] = n + texsetattribute(a_stripping,n) end -- why not in task-ini? diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua index 5eba22889..a8df6e1f8 100644 --- a/tex/context/base/typo-spa.lua +++ b/tex/context/base/typo-spa.lua @@ -24,7 +24,7 @@ local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers local quaddata = fonthashes.quads -local texattribute = tex.attribute +local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local v_reset = interfaces.variables.reset @@ -209,11 +209,11 @@ function spacings.set(name) n = data.number or unsetvalue end end - texattribute[a_spacings] = n + texsetattribute(a_spacings,n) end function spacings.reset() - texattribute[a_spacings] = unsetvalue + texsetattribute(a_spacings,unsetvalue) end spacings.handler = nodes.installattributehandler { diff --git a/tex/context/base/util-dim.lua b/tex/context/base/util-dim.lua index 47b2706b7..69061495f 100644 --- a/tex/context/base/util-dim.lua +++ b/tex/context/base/util-dim.lua @@ -22,6 +22,8 @@ local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex local formatters = string.formatters +local texget = tex and tex.get or function() return 65536*10*100 end + --this might become another namespace number = number or { } @@ -137,7 +139,7 @@ capture takes place.</p> --ldx]]-- local amount = (S("+-")^0 * R("09")^0 * P(".")^0 * R("09")^0) + Cc("0") -local unit = R("az")^1 +local unit = R("az")^1 + P("%") local dimenpair = amount/tonumber * (unit^1/dimenfactors + Cc(1)) -- tonumber is new @@ -376,10 +378,10 @@ function dimen(a) a = k else local value, unit = lpegmatch(dimenpair,a) - if type(unit) == "function" then - k = value/unit() + if value and unit then + k = value/unit -- to be considered: round else - k = value/unit + k = 0 end known[a] = k a = k @@ -412,16 +414,16 @@ function string.todimen(str) -- maybe use tex.sp when available end end ---~ local known = { } - ---~ function string.todimen(str) -- maybe use tex.sp ---~ local k = known[str] ---~ if not k then ---~ k = tex.sp(str) ---~ known[str] = k ---~ end ---~ return k ---~ end +-- local known = { } +-- +-- function string.todimen(str) -- maybe use tex.sp +-- local k = known[str] +-- if not k then +-- k = tex.sp(str) +-- known[str] = k +-- end +-- return k +-- end stringtodimen = string.todimen -- local variable defined earlier @@ -439,7 +441,7 @@ probably use a hash instead of a one-element table.</p> --ldx]]-- function number.percent(n,d) -- will be cleaned up once luatex 0.30 is out - d = d or tex.hsize + d = d or texget("hsize") if type(d) == "string" then d = stringtodimen(d) end diff --git a/tex/context/base/util-jsn.lua b/tex/context/base/util-jsn.lua index 29587cd38..bbe25d89d 100644 --- a/tex/context/base/util-jsn.lua +++ b/tex/context/base/util-jsn.lua @@ -42,8 +42,20 @@ local dquote = P('"') local whitespace = lpeg.patterns.whitespace local optionalws = whitespace^0 -local escape = C(P("\\u") / "0x" * S("09","AF","af")) / function(s) return utfchar(tonumber(s)) end -local jstring = dquote * Cs((escape + (1-dquote))^0) * dquote +local escapes = { + -- ["\\"] = "\\", -- lua will escape these + -- ["/"] = "/", -- no need to escape this one + ["b"] = "\010", + ["f"] = "\014", + ["n"] = "\n", + ["r"] = "\r", + ["t"] = "\t", +} + +local escape_un = C(P("\\u") / "0x" * S("09","AF","af")) / function(s) return utfchar(tonumber(s)) end +local escape_bs = P([[\]]) / "" * (P(1) / escapes) -- if not found then P(1) is returned i.e. the to be escaped char + +local jstring = dquote * Cs((escape_un + escape_bs + (1-dquote))^0) * dquote local jtrue = P("true") * Cc(true) local jfalse = P("false") * Cc(false) local jnull = P("null") * Cc(nil) diff --git a/tex/context/base/util-lua.lua b/tex/context/base/util-lua.lua index 61d1190b2..e1dcdc94d 100644 --- a/tex/context/base/util-lua.lua +++ b/tex/context/base/util-lua.lua @@ -74,9 +74,16 @@ end function luautilities.loadedluacode(fullname,forcestrip,name) -- quite subtle ... doing this wrong incidentally can give more bytes name = name or fullname - local code = environment.loadpreprocessedfile and environment.loadpreprocessedfile(fullname) or loadfile(fullname) + local code, message + if environment.loadpreprocessedfile then + code, message = environment.loadpreprocessedfile(fullname) + else + code, message = loadfile(fullname) + end if code then code() + else + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") end if forcestrip and luautilities.stripcode then if type(forcestrip) == "function" then @@ -97,15 +104,16 @@ function luautilities.loadedluacode(fullname,forcestrip,name) end function luautilities.strippedloadstring(code,forcestrip,name) -- not executed + local code, message = load(code) + if not code then + report_lua("loading of file %a failed:\n\t%s",name,message or "no message") + end if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - code = load(code) - if not code then - report_lua("fatal error %a in file %a",3,name) - end register(name) - code = dump(code,true) + return load(dump(code,true)), 0 -- not yet executes + else + return code, 0 end - return load(code), 0 end function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) -- defaults: cleanup=false strip=true diff --git a/tex/context/base/util-prs.lua b/tex/context/base/util-prs.lua index 9b2a2b04c..7fe1e703b 100644 --- a/tex/context/base/util-prs.lua +++ b/tex/context/base/util-prs.lua @@ -410,7 +410,7 @@ function parsers.csvsplitter(specification) end whatever = quotedata + whatever end - local parser = Ct((Ct(whatever * (separator * whatever)^0) * S("\n\r"))^0 ) + local parser = Ct((Ct(whatever * (separator * whatever)^0) * S("\n\r")^1)^0 ) return function(data) return lpegmatch(parser,data) end diff --git a/tex/context/base/util-seq.lua b/tex/context/base/util-seq.lua index 4e042de59..35e693285 100644 --- a/tex/context/base/util-seq.lua +++ b/tex/context/base/util-seq.lua @@ -321,6 +321,8 @@ function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug else calls[n] = format(" head, ok = %s(head%s) done = done or ok",localized,args) end +-- local s = " print('" .. tostring(group) .. " " .. tostring(action) .. " : ' .. tostring(head)) " +-- calls[n] = s .. calls[n] .. s end end end diff --git a/tex/context/base/util-str.lua b/tex/context/base/util-str.lua index 0c8c0e2d2..13e1e0922 100644 --- a/tex/context/base/util-str.lua +++ b/tex/context/base/util-str.lua @@ -339,7 +339,7 @@ local format_i = function(f) if f and f ~= "" then return format("format('%%%si',a%s)",f,n) else - return format("a%s",n) + return format("format('%%i',a%s)",n) end end diff --git a/tex/context/base/util-tab.lua b/tex/context/base/util-tab.lua index b7db4fa84..f18c719e4 100644 --- a/tex/context/base/util-tab.lua +++ b/tex/context/base/util-tab.lua @@ -293,13 +293,12 @@ function tables.encapsulate(core,capsule,protect) end end --- we no longer have %q in keys as for this kind of tables we can --- assume sane keys +-- best keep [%q] keys (as we have some in older applications i.e. saving user data -local f_hashed_string = formatters["[%s]=%q,"] -local f_hashed_number = formatters["[%s]=%s,"] -local f_hashed_boolean = formatters["[%s]=%l,"] -local f_hashed_table = formatters["[%s]="] +local f_hashed_string = formatters["[%q]=%q,"] +local f_hashed_number = formatters["[%q]=%s,"] +local f_hashed_boolean = formatters["[%q]=%l,"] +local f_hashed_table = formatters["[%q]="] local f_indexed_string = formatters["%q,"] local f_indexed_number = formatters["%s,"] @@ -521,7 +520,7 @@ local serialize = table.serialize -- the extensive one, the one we started with function table.serialize(root,name,specification) - if specification then + if type(specification) == "table" then return serialize(root,name,specification) -- the original one end diff --git a/tex/context/base/util-tpl.lua b/tex/context/base/util-tpl.lua index dcc4c1216..e0c405a42 100644 --- a/tex/context/base/util-tpl.lua +++ b/tex/context/base/util-tpl.lua @@ -159,6 +159,14 @@ end templates.replace = replace +function templates.replacer(str,how,recurse) -- reads nicer + return function(mapping) + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + end +end + +-- local cmd = templates.replacer([[foo %bar%]]) print(cmd { bar = "foo" }) + function templates.load(filename,mapping,how,recurse) local data = io.loaddata(filename) or "" if mapping and next(mapping) then diff --git a/tex/context/base/x-asciimath.lua b/tex/context/base/x-asciimath.lua index 5ef741ce3..992c37eae 100644 --- a/tex/context/base/x-asciimath.lua +++ b/tex/context/base/x-asciimath.lua @@ -140,6 +140,8 @@ local reserved = { } +table.setmetatableindex(reserved,characters.entities) + local postmapper = Cs ( ( P("\\mathoptext ") * spaces * (P("\\bgroup ")/"{") * (1-P("\\egroup "))^1 * (P("\\egroup ")/"}") + diff --git a/tex/context/fonts/ebgaramond.lfg b/tex/context/fonts/ebgaramond.lfg new file mode 100644 index 000000000..43cc13c51 --- /dev/null +++ b/tex/context/fonts/ebgaramond.lfg @@ -0,0 +1,53 @@ +return { + name = "eb garamond", + version = "1.00", + comment = "Goodies that complement eb garamond.", + author = "Hans Hagen", + copyright = "ConTeXt development team", + designsizes = { + ["EBGaramond-Italic"] = { + ["8pt"] = "file:EBGaramond08-Italic", + ["9pt"] = "file:EBGaramond08-Italic", + ["9.5pt"] = "file:EBGaramond08-Italic", + ["10pt"] = "file:EBGaramond12-Italic", + ["11pt"] = "file:EBGaramond12-Italic", + ["12pt"] = "file:EBGaramond12-Italic", + default = "file:EBGaramond12-Italic", + }, + ["EBGaramond-Regular"] = { + ["8pt"] = "file:EBGaramond08-Regular", + ["9pt"] = "file:EBGaramond08-Regular", + ["9.5pt"] = "file:EBGaramond08-Regular", + ["10pt"] = "file:EBGaramond12-Regular", + ["11pt"] = "file:EBGaramond12-Regular", + ["12pt"] = "file:EBGaramond12-Regular", + default = "file:EBGaramond12-Regular", + }, + ["EBGaramond-SC"] = { + ["8pt"] = "file:EBGaramond08-SC", + ["9pt"] = "file:EBGaramond08-SC", + ["9.5pt"] = "file:EBGaramond08-SC", + ["10pt"] = "file:EBGaramond12-SC", + ["11pt"] = "file:EBGaramond12-SC", + ["12pt"] = "file:EBGaramond12-SC", + default = "file:EBGaramond12-SC", + }, + ["EBGaramond-Bold"] = { + default = "file:EBGaramond12-Bold", + }, + ["EBGaramond-AllSC"] = { + default = "file:EBGaramond12-AllSC", + }, + ["EBGaramond-Initials"] = { + default = "file:EBGaramondInitials", + }, + ["EBGaramond-InitialsF1"] = { + default = "file:EBGaramondInitialsF1", + }, + ["EBGaramond-InitialsF2"] = { + default = "file:EBGaramondInitialsF2", + }, + } +} + + diff --git a/tex/context/fonts/lm.lfg b/tex/context/fonts/lm.lfg index 7fad13afd..8d7614718 100644 --- a/tex/context/fonts/lm.lfg +++ b/tex/context/fonts/lm.lfg @@ -1,4 +1,4 @@ --- In order to be ale to use beta math fonts, we use our own file name and +-- In order to be able to use beta math fonts, we use our own file name and -- always remap. return { diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml index ad0cf2dca..2499186f3 100644 --- a/tex/context/interface/keys-cs.xml +++ b/tex/context/interface/keys-cs.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='znaceni'/> <cd:constant name='marstyle' value='stylsnacky'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml index 5d107ca40..6464bd44e 100644 --- a/tex/context/interface/keys-de.xml +++ b/tex/context/interface/keys-de.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='beschriftung'/> <cd:constant name='marstyle' value='beschrstil'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml index d9166d107..8a4eb55a9 100644 --- a/tex/context/interface/keys-en.xml +++ b/tex/context/interface/keys-en.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='marking'/> <cd:constant name='marstyle' value='marstyle'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml index c98826cf3..604e4560b 100644 --- a/tex/context/interface/keys-fr.xml +++ b/tex/context/interface/keys-fr.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='marquage'/> <cd:constant name='marstyle' value='stylemarquage'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml index afe3b8360..ff23d0973 100644 --- a/tex/context/interface/keys-it.xml +++ b/tex/context/interface/keys-it.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='marcatura'/> <cd:constant name='marstyle' value='stilemarcatura'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml index 226c96839..6597300b3 100644 --- a/tex/context/interface/keys-nl.xml +++ b/tex/context/interface/keys-nl.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='markering'/> <cd:constant name='marstyle' value='marletter'/> <cd:constant name='mask' value='masker'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml index 9303c29fd..212941015 100644 --- a/tex/context/interface/keys-pe.xml +++ b/tex/context/interface/keys-pe.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='نشانه‌گذاری'/> <cd:constant name='marstyle' value='سبک‌Øاش'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='بیشترین'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml index 29368c9bc..deb7ad559 100644 --- a/tex/context/interface/keys-ro.xml +++ b/tex/context/interface/keys-ro.xml @@ -807,6 +807,8 @@ <cd:constant name='marking' value='marcaje'/> <cd:constant name='marstyle' value='stilmarcaj'/> <cd:constant name='mask' value='mask'/> + <cd:constant name='mathclass' value='mathclass'/> + <cd:constant name='mathlimits' value='mathlimits'/> <cd:constant name='mathstyle' value='mathstyle'/> <cd:constant name='max' value='max'/> <cd:constant name='maxdepth' value='maxdepth'/> diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua index 4a46fbb07..26c1edc72 100644 --- a/tex/generic/context/luatex/luatex-basics-gen.lua +++ b/tex/generic/context/luatex/luatex-basics-gen.lua @@ -149,19 +149,29 @@ do local cachepaths = kpse.expand_var('$TEXMFCACHE') or "" - -- quite like tex live or so + -- quite like tex live or so (the weird $TEXMFCACHE test seems to be needed on miktex) - if cachepaths == "" then + if cachepaths == "" or cachepaths == "$TEXMFCACHE" then cachepaths = kpse.expand_var('$TEXMFVAR') or "" end - -- this also happened to be used + -- this also happened to be used (the weird $TEXMFVAR test seems to be needed on miktex) - if cachepaths == "" then + if cachepaths == "" or cachepaths == "$TEXMFVAR" then cachepaths = kpse.expand_var('$VARTEXMF') or "" end - -- and this is a last resort + -- and this is a last resort (hm, we could use TEMP or TEMPDIR) + + if cachepaths == "" then + local fallbacks = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } + for i=1,#fallbacks do + cachepaths = os.getenv(fallbacks[i]) or "" + if cachepath ~= "" and lfs.isdir(cachepath) then + break + end + end + end if cachepaths == "" then cachepaths = "." @@ -267,7 +277,7 @@ function caches.savedata(path,name,data) local luaname, lucname = makefullname(path,name) if luaname then texio.write(string.format("(save: %s)",luaname)) - table.tofile(luaname,data,true,{ reduce = true }) + table.tofile(luaname,data,true) if lucname and type(caches.compile) == "function" then os.remove(lucname) -- better be safe texio.write(string.format("(save: %s)",lucname)) diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua index 5ab9df7f9..58b27897d 100644 --- a/tex/generic/context/luatex/luatex-basics-nod.lua +++ b/tex/generic/context/luatex/luatex-basics-nod.lua @@ -88,17 +88,32 @@ function nodes.delete(head,current) return nodes.remove(head,current,true) end -nodes.before = node.insert_before -nodes.after = node.insert_after - function nodes.pool.kern(k) local n = new_node("kern",1) n.kern = k return n end -function nodes.endofmath(n) - for n in traverse_id(math_code,n.next) do - return n - end -end +-- experimental + +local getfield = node.getfield or function(n,tag) return n[tag] end end +local setfield = node.setfield or function(n,tag,value) n[tag] = value end end + +nodes.getfield = getfield +nodes.setfield = setfield + +nodes.getattr = getfield +nodes.setattr = setfield + +if node.getid then nodes.getid = node.getid else function nodes.getid (n) return getfield(n,"id") end end +if node.getsubtype then nodes.getsubtype = node.getsubtype else function nodes.getsubtype(n) return getfield(n,"subtype") end end +if node.getnext then nodes.getnext = node.getnext else function nodes.getnext (n) return getfield(n,"next") end end +if node.getprev then nodes.getprev = node.getprev else function nodes.getprev (n) return getfield(n,"prev") end end +if node.getchar then nodes.getchar = node.getchar else function nodes.getchar (n) return getfield(n,"char") end end +if node.getfont then nodes.getfont = node.getfont else function nodes.getfont (n) return getfield(n,"font") end end +if node.getlist then nodes.getlist = node.getlist else function nodes.getlist (n) return getfield(n,"list") end end + +function nodes.tonut (n) return n end +function nodes.tonode(n) return n end + +nodes.nuts = nodes -- we stay nodes diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 4cd0c4dc0..d7a1fab5b 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 : 06/10/13 22:51:12 +-- merge date : 07/12/13 19:10:11 do -- begin closure to overcome local limits and interference @@ -95,6 +95,7 @@ if not modules then modules={} end modules ['l-lpeg']={ license="see context related readme files" } lpeg=require("lpeg") +if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end local type,next,tostring=type,next,tostring local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format local floor=math.floor @@ -213,7 +214,7 @@ patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^ patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring patterns.somecontent=(anything-newline-space)^1 patterns.beginline=#(1-newline) -patterns.longtostring=Cs(whitespace^0/""*nonwhitespace^0*((whitespace^0/" "*(patterns.quoted+nonwhitespace)^1)^0)) +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) local function anywhere(pattern) return P { P(pattern)+1*V(1) } end @@ -1066,6 +1067,7 @@ local noquotes,hexify,handle,reduce,compact,inline,functions local reserved=table.tohash { 'and','break','do','else','elseif','end','false','for','function','if', 'in','local','nil','not','or','repeat','return','then','true','until','while', + 'NaN','goto', } local function simple_table(t) if #t>0 then @@ -1691,6 +1693,7 @@ local function readall(f) return f:read('*all') else local done=f:seek("set",0) + local step if size<1024*1024 then step=1024*1024 elseif size>16*1024*1024 then @@ -2214,17 +2217,24 @@ end function file.joinpath(tab,separator) return tab and concat(tab,separator or io.pathseparator) end +local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) -local isnetwork=fwslash*fwslash*(1-fwslash)+(1-fwslash-colon)^1*colon +local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon local isroot=fwslash^1*-1 local hasroot=fwslash^1 +local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(...) local lst={... } local one=lst[1] if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) local two=lpegmatch(deslasher,concat(lst,"/",2)) - return one.."/"..two + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end elseif lpegmatch(isroot,one) then local two=lpegmatch(deslasher,concat(lst,"/",2)) if lpegmatch(hasroot,two) then @@ -2241,7 +2251,9 @@ end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec local untouched=periods+(1-period)^1*P(-1) -local splitstarter=(Cs(drivespec*(bwslash/"/"+fwslash)^0)+Cc(false))*Ct(lpeg.splitat(S("/\\")^1)) +local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0) +local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//") +local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1)) local absolute=fwslash function file.collapsepath(str,anchor) if not str then @@ -2653,7 +2665,7 @@ local format_i=function(f) if f and f~="" then return format("format('%%%si',a%s)",f,n) else - return format("a%s",n) + return format("format('%%i',a%s)",n) end end local format_d=format_i @@ -3044,13 +3056,22 @@ if not caches.namespace or caches.namespace=="" or caches.namespace=="context" t end do local cachepaths=kpse.expand_var('$TEXMFCACHE') or "" - if cachepaths=="" then + if cachepaths=="" or cachepaths=="$TEXMFCACHE" then cachepaths=kpse.expand_var('$TEXMFVAR') or "" end - if cachepaths=="" then + if cachepaths=="" or cachepaths=="$TEXMFVAR" then cachepaths=kpse.expand_var('$VARTEXMF') or "" end if cachepaths=="" then + local fallbacks={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } + for i=1,#fallbacks do + cachepaths=os.getenv(fallbacks[i]) or "" + if cachepath~="" and lfs.isdir(cachepath) then + break + end + end + end + if cachepaths=="" then cachepaths="." end cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":") @@ -3143,7 +3164,7 @@ function caches.savedata(path,name,data) local luaname,lucname=makefullname(path,name) if luaname then texio.write(string.format("(save: %s)",luaname)) - table.tofile(luaname,data,true,{ reduce=true }) + table.tofile(luaname,data,true) if lucname and type(caches.compile)=="function" then os.remove(lucname) texio.write(string.format("(save: %s)",lucname)) @@ -3355,18 +3376,27 @@ end function nodes.delete(head,current) return nodes.remove(head,current,true) end -nodes.before=node.insert_before -nodes.after=node.insert_after function nodes.pool.kern(k) local n=new_node("kern",1) n.kern=k return n end -function nodes.endofmath(n) - for n in traverse_id(math_code,n.next) do - return n - end -end +local getfield=node.getfield or function(n,tag) return n[tag] end end +local setfield=node.setfield or function(n,tag,value) n[tag]=value end end +nodes.getfield=getfield +nodes.setfield=setfield +nodes.getattr=getfield +nodes.setattr=setfield +if node.getid then nodes.getid=node.getid else function nodes.getid (n) return getfield(n,"id") end end +if node.getsubtype then nodes.getsubtype=node.getsubtype else function nodes.getsubtype(n) return getfield(n,"subtype") end end +if node.getnext then nodes.getnext=node.getnext else function nodes.getnext (n) return getfield(n,"next") end end +if node.getprev then nodes.getprev=node.getprev else function nodes.getprev (n) return getfield(n,"prev") end end +if node.getchar then nodes.getchar=node.getchar else function nodes.getchar (n) return getfield(n,"char") end end +if node.getfont then nodes.getfont=node.getfont else function nodes.getfont (n) return getfield(n,"font") end end +if node.getlist then nodes.getlist=node.getlist else function nodes.getlist (n) return getfield(n,"list") end end +function nodes.tonut (n) return n end +function nodes.tonode(n) return n end +nodes.nuts=nodes end -- closure @@ -4415,7 +4445,8 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report) local whathandler=handlers[what] local whatfeatures=whathandler.features local whatprocessors=whatfeatures.processors - local processors=whatprocessors[properties.mode] + local mode=properties.mode + local processors=whatprocessors[mode] if processors then for i=1,#processors do local step=processors[i] @@ -4432,7 +4463,7 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report) end end elseif trace then - report("no feature processors for mode %a for font %a",mode,tfmdata.properties.fullname) + report("no feature processors for mode %a for font %a",mode,properties.fullname) end end return processes @@ -4443,7 +4474,8 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) local whathandler=handlers[what] local whatfeatures=whathandler.features local whatmanipulators=whatfeatures.manipulators - local manipulators=whatmanipulators[properties.mode] + local mode=properties.mode + local manipulators=whatmanipulators[mode] if manipulators then for i=1,#manipulators do local step=manipulators[i] @@ -4452,7 +4484,7 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) if value then local action=step.action if trace then - report("applying feature manipulator %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) + report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname) end if action then action(tfmdata,feature,value) @@ -7527,11 +7559,24 @@ local injections=nodes.injections local nodecodes=nodes.nodecodes local glyph_code=nodecodes.glyph 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') local a_markbase=attributes.private('markbase') @@ -7550,21 +7595,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 - 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 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=current[a_kernpair] + local bound=getattr(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 - 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 @@ -7575,7 +7620,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 @@ -7584,25 +7629,25 @@ function injections.setkern(current,factor,rlmode,x,tfmchr) end function injections.setmark(start,base,factor,rlmode,ba,ma,index) local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) - local bound=base[a_markbase] + local bound=getattr(base,a_markbase) local index=1 if bound then local mb=marks[bound] if mb then 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 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 } } return dx,dy,bound end @@ -7612,15 +7657,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 @@ -7661,21 +7706,23 @@ 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 @@ -7685,17 +7732,18 @@ 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 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 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 @@ -7715,15 +7763,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 + local f=getfont(n) + if f~=nf then + nf=f tm=fontdata[nf].resources.marks end if tm then - mk[n]=tm[n.char] + mk[n]=tm[getchar(n)] end end end @@ -7732,7 +7781,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 if has_cursives then @@ -7741,9 +7790,9 @@ function injections.handler(head,where,keep) for i=1,nofvalid do 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 @@ -7766,20 +7815,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 @@ -7787,11 +7836,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 @@ -7802,46 +7851,52 @@ 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] + 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 - n.xoffset=p.xoffset-p.width+d[1]-(w-x) + ox=px-getfield(p,"width")+d[1]-(w-x) else - n.xoffset=p.xoffset-d[1]-x + ox=px-d[1]-x end else if rlmode and rlmode>=0 then - n.xoffset=p.xoffset-p.width+d[1] + ox=px-getfield(p,"width")+d[1] else - n.xoffset=p.xoffset-d[1]-x + ox=px-d[1]-x end end else if rlmode and rlmode>=0 then - n.xoffset=p.xoffset-p.width+d[1] + ox=px-getfield(p,"width")+d[1] else - n.xoffset=p.xoffset-d[1] + ox=px-d[1] end 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 else @@ -7899,6 +7954,7 @@ 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={},{},{} @@ -7908,14 +7964,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 + setfield(n,"yoffset",y) end if w then local wx=w-x @@ -7946,10 +8002,10 @@ function injections.handler(head,where,keep) if not keep then kerns={} end - return head,true + return tonode(head),true else end - return head,false + return tonode(head),false end end -- closure @@ -7977,6 +8033,7 @@ analyzers.useunicodemarks=false local a_state=attributes.private('state') 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 @@ -8043,7 +8100,7 @@ function analyzers.setstate(head,font) first,last,n=nil,nil,0 end elseif id==disc_code then - current[a_state]=s_midi + current[a_state]=s_medi last=current else if first and first==last then @@ -8095,7 +8152,7 @@ local function analyzeprocessor(head,font,attr) end registerotffeature { name="analyze", - description="analysis of (for instance) character classes", + description="analysis of character classes", default=true, initializers={ node=analyzeinitializer, @@ -8358,12 +8415,25 @@ 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 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 local zwnj=0x200C local zwj=0x200D @@ -8472,83 +8542,83 @@ local function pref(kind,lookupname) return formatters["feature %a, lookup %a"](kind,lookupname) end local function copy_glyph(g) - 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) end end 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 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 end end local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) - 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 + 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) if not discfound then local deletemarks=markflag~="mark" local components=start @@ -8557,42 +8627,42 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local head=base local current=base 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 - 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)) elseif trace_marks then logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) end - start=start.next + start=getnext(start) end - 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 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 local function get_alternative_glyph(start,alternatives,value,trace_alternatives) @@ -8618,7 +8688,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 @@ -8629,25 +8699,25 @@ end local function multiple_glyphs(head,start,multiple) 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 local n=copy_node(start) - 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 @@ -8657,34 +8727,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(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 end function handlers.gsub_multiple(head,start,kind,lookupname,multiple) 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) 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 @@ -8696,9 +8766,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 @@ -8709,18 +8779,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 @@ -8730,7 +8800,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 @@ -8739,9 +8809,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=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 @@ -8753,16 +8823,16 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) return head,start,false end 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 - if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then - local basechar=base.char + local base=getprev(start) + 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 @@ -8811,16 +8881,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=start.char + local markchar=getchar(start) if marks[markchar] then - local base=start.prev - if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then - local basechar=base.char + local base=getprev(start) + 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 @@ -8832,7 +8902,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 @@ -8877,22 +8947,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=start.char + local markchar=getchar(start) if marks[markchar] then - local base=start.prev - local slc=start[a_ligacomp] + local base=getprev(start) + local slc=getattr(start,a_ligacomp) if slc then 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 - local basechar=base.char + if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then + local basechar=getchar(base) local baseanchors=descriptions[basechar] if baseanchors then baseanchors=baseanchors.anchors @@ -8930,20 +9000,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 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 - nxt=nxt.next + nxt=getnext(nxt) else local entryanchors=descriptions[nextchar] if entryanchors then @@ -8977,13 +9047,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(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) @@ -8991,19 +9061,19 @@ 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=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 local krn=kerns[nextchar] if not krn then @@ -9011,14 +9081,14 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) 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)",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) @@ -9031,7 +9101,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 @@ -9066,13 +9136,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=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 @@ -9083,9 +9153,9 @@ local function delete_till_stop(start,stop,ignoremarks) if start==stop then elseif ignoremarks then repeat - 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 flush_node_list(components) end @@ -9095,8 +9165,8 @@ local function delete_till_stop(start,stop,ignoremarks) until next==stop else repeat - local next=start.next - local components=next.components + local next=getnext(start) + local components=getfield(next,"components") if components then flush_node_list(components) end @@ -9113,8 +9183,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] local replacement=lookuphash[lookupname] if not replacement then @@ -9131,14 +9201,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 @@ -9146,7 +9216,7 @@ end chainmores.gsub_single=chainprocs.gsub_single function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) delete_till_stop(start,stop) - local startchar=start.char + local startchar=getchar(start) local subtables=currentlookup.subtables local lookupname=subtables[1] local replacements=lookuphash[lookupname] @@ -9175,8 +9245,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 - local currentchar=current.char + if getid(current)==glyph_code then + local currentchar=getchar(current) local lookupname=subtables[1] local alternatives=lookuphash[lookupname] if not alternatives then @@ -9191,7 +9261,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) @@ -9205,14 +9275,14 @@ 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 end chainmores.gsub_alternate=chainprocs.gsub_alternate 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] @@ -9227,20 +9297,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 - s=s.next + s=getnext(s) else local lg=ligatures[schar] if lg then @@ -9248,7 +9318,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 @@ -9265,7 +9335,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) @@ -9274,7 +9344,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 @@ -9283,7 +9353,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=start.char + local markchar=getchar(start) if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -9292,14 +9362,14 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext markanchors=markanchors[markchar] end if markanchors then - local base=start.prev - if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then - local basechar=base.char + local base=getprev(start) + 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 @@ -9346,7 +9416,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=start.char + local markchar=getchar(start) if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -9355,14 +9425,14 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon markanchors=markanchors[markchar] end if markanchors then - local base=start.prev - if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then - local basechar=base.char + local base=getprev(start) + 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 @@ -9374,7 +9444,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon end end end - local index=start[a_ligacomp] + local index=getattr(start,a_ligacomp) local baseanchors=descriptions[basechar].anchors if baseanchors then local baseanchors=baseanchors['baselig'] @@ -9413,7 +9483,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=start.char + local markchar=getchar(start) if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -9422,20 +9492,20 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext markanchors=markanchors[markchar] end if markanchors then - local base=start.prev - local slc=start[a_ligacomp] + local base=getprev(start) + local slc=getattr(start,a_ligacomp) if slc then 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 - local basechar=base.char + if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then + local basechar=getchar(base) local baseanchors=descriptions[basechar].anchors if baseanchors then baseanchors=baseanchors['basemark'] @@ -9471,9 +9541,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 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] @@ -9487,11 +9557,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=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 - nxt=nxt.next + nxt=getnext(nxt) else local entryanchors=descriptions[nextchar] if entryanchors then @@ -9525,7 +9595,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 @@ -9533,7 +9603,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=start.char + local startchar=getchar(start) local subtables=currentlookup.subtables local lookupname=subtables[1] local kerns=lookuphash[lookupname] @@ -9549,9 +9619,9 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo return head,start,false end 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] @@ -9561,26 +9631,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 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 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 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) @@ -9592,7 +9662,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 @@ -9603,7 +9673,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 @@ -9640,7 +9710,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local seq=ck[3] local s=#seq if s==1 then - 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 local f,l=ck[4],ck[5] if f==1 and f==l then @@ -9648,13 +9718,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if f==l then 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 @@ -9663,10 +9733,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 @@ -9682,7 +9752,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 @@ -9695,15 +9765,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end 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 - local char=prev.char + if getfont(prev)==currentfont and getsubtype(prev)<256 then + local char=getchar(prev) local ccd=descriptions[char] if ccd then local class=ccd.class @@ -9733,7 +9803,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 n=n -1 else @@ -9753,15 +9823,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if match and s>l then - local current=last and last.next + local current=last and getnext(last) if current then 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 - local char=current.char + if getfont(current)==currentfont and getsubtype(current)<256 then + local char=getchar(current) local ccd=descriptions[char] if ccd then local class=ccd.class @@ -9791,7 +9861,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 @@ -9814,7 +9884,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=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]) @@ -9844,12 +9914,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 @@ -9874,7 +9944,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq i=i+1 end if start then - start=start.next + start=getnext(start) else end until i>nofchainlookups @@ -10001,6 +10071,7 @@ local function featuresprocessor(head,font,attr) if not lookuphash then return head,false end + head=tonut(head) if trace_steps then checkstep(head) end @@ -10033,10 +10104,10 @@ local function featuresprocessor(head,font,attr) local handler=handlers[typ] local start=find_node_tail(head) 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 @@ -10047,7 +10118,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 @@ -10058,15 +10129,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 @@ -10081,17 +10152,17 @@ local function featuresprocessor(head,font,attr) report_missing_cache(typ,lookupname) else 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 local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) @@ -10099,17 +10170,17 @@ 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==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 @@ -10128,7 +10199,7 @@ local function featuresprocessor(head,font,attr) 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 @@ -10141,31 +10212,31 @@ local function featuresprocessor(head,font,attr) 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 else 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 local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) @@ -10180,17 +10251,17 @@ local function featuresprocessor(head,font,attr) 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==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 @@ -10209,7 +10280,7 @@ local function featuresprocessor(head,font,attr) 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 @@ -10222,11 +10293,11 @@ local function featuresprocessor(head,font,attr) 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 @@ -10238,6 +10309,7 @@ local function featuresprocessor(head,font,attr) 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.lua b/tex/generic/context/luatex/luatex-fonts.lua index 89592fcac..88d6a2f0e 100644 --- a/tex/generic/context/luatex/luatex-fonts.lua +++ b/tex/generic/context/luatex/luatex-fonts.lua @@ -192,7 +192,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then -- with context. The mtx-fonts script can be used to genate this file (using the --names option). -- In 2013/14 I will merge/move some generic files into luatex-fonts-* files (copies) so that - -- intermediate updates of context not interfere. We can then also use the general merger and + -- intermediate updates of context don't interfere. We can then also use the general merger and -- consider stripping debug code. loadmodule('font-ini.lua') @@ -209,7 +209,6 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('font-ota.lua') loadmodule('font-otn.lua') loadmodule('font-otp.lua') -- optional - ----------('luatex-fonts-chr.lua') loadmodule('luatex-fonts-lua.lua') loadmodule('font-def.lua') loadmodule('luatex-fonts-def.lua') |