diff options
author | Hans Hagen <pragma@wxs.nl> | 2019-02-22 20:29:46 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2019-02-22 20:29:46 +0100 |
commit | 7b271baae19db1528fbe6621bdf50af89a5a336b (patch) | |
tree | 4fc24a8f2be20aa90e90f6e1bcb62d69f4946235 /tex/context/base/mkiv/node-ltp.lua | |
parent | 67b9965fe473d18f13ed4c40f1e4e008eb870322 (diff) | |
download | context-7b271baae19db1528fbe6621bdf50af89a5a336b.tar.gz |
2019-02-22 19:43:00
Diffstat (limited to 'tex/context/base/mkiv/node-ltp.lua')
-rw-r--r-- | tex/context/base/mkiv/node-ltp.lua | 3261 |
1 files changed, 1627 insertions, 1634 deletions
diff --git a/tex/context/base/mkiv/node-ltp.lua b/tex/context/base/mkiv/node-ltp.lua index 865f69c2c..0d501890b 100644 --- a/tex/context/base/mkiv/node-ltp.lua +++ b/tex/context/base/mkiv/node-ltp.lua @@ -134,6 +134,53 @@ if not modules then modules = { } end modules ['node-par'] = { ]]-- +--[[-- + +#define dir_TLT 0 +#define dir_TRT 1 +#define dir_LTL 2 +#define dir_RTT 3 + +#define dir_TLT_or_TRT(A) (A < 2) +#define dir_LTL_or_RTT(A) (A > 1) + +#define textdir_parallel(A,B) (\ +(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \ +(dir_LTL_or_RTT(A) and dir_LTL_or_RTT(B))\ +) + +#define pardir_parallel(A,B) (\ +(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \ +(dir_LTL_or_RTT(A) and dir_LTL_or_RTT(B))\ +) + +#define pardir_opposite(A,B) (\ +(A == dir_LTL and B == dir_RTT) or \ +(A == dir_RTT and B == dir_LTL)\ +) + +#define textdir_opposite(A,B) (\ +(A == dir_TLT and B == dir_TRT) or \ +(A == dir_TRT and B == dir_TLT)\ +) + +#define glyphdir_opposite(A,B) 0 + +#define pardir_equal(A,B) (\ +(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \ +(A == dir_LTL and B == dir_LTL) or \ +(A == dir_RTT and B == dir_RTT)\ +) + +#define textdir_equal(A,B) (\ +(A == dir_TLT and B == dir_TLT) or \ +(A == dir_TRT and B == dir_TRT) or \ +(A == dir_LTL and dir_LTL_or_RTT(B)) or \ +(A == dir_RTT and dir_LTL_or_RTT(B))\ +) + +--]]-- + local tonumber = tonumber local utfchar = utf.char local write, write_nl = texio.write, texio.write_nl @@ -191,7 +238,6 @@ local parameters = fonthashes.parameters local nuts = nodes.nuts local tonut = nuts.tonut -local tonode = nuts.tonode local getfield = nuts.getfield local getid = nuts.getid @@ -200,21 +246,20 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getboth = nuts.getboth local getlist = nuts.getlist -local getfont = nuts.getfont -local getchar = nuts.getchar local getdisc = nuts.getdisc local getattr = nuts.getattr local getdisc = nuts.getdisc local getglue = nuts.getglue local getwhd = nuts.getwhd -local getcomponents = nuts.getcomponents local getkern = nuts.getkern local getpenalty = nuts.getpenalty -local getdir = nuts.getdir +local getdirection = nuts.getdirection local getshift = nuts.getshift local getwidth = nuts.getwidth local getheight = nuts.getheight local getdepth = nuts.getdepth +local getdata = nuts.getdata +local getwhd = nuts.getwhd local isglyph = nuts.isglyph @@ -229,11 +274,10 @@ local setsubtype = nuts.setsubtype local setglue = nuts.setglue local setwhd = nuts.setwhd local setkern = nuts.setkern -local setdir = nuts.setdir +local setdirection = nuts.setdirection local setshift = nuts.setshift local setwidth = nuts.setwidth ------ setheight = nuts.setheight ------ setdepth = nuts.setdepth +local setexpansion = nuts.setexpansion local slide_node_list = nuts.slide -- get rid of this, probably ok > 78.2 local find_tail = nuts.tail @@ -246,13 +290,14 @@ local replace_node = nuts.replace local insert_node_after = nuts.insert_after local insert_node_before = nuts.insert_before local is_zero_glue = nuts.is_zero_glue +local is_skipable = nuts.protrusion_skippable local nodepool = nuts.pool local nodecodes = nodes.nodecodes local kerncodes = nodes.kerncodes local glyphcodes = nodes.glyphcodes -local gluecodes = nodes.gluecodes +local leadercodes = nodes.leadercodes local margincodes = nodes.margincodes local disccodes = nodes.disccodes local mathcodes = nodes.mathcodes @@ -276,9 +321,9 @@ local marginkern_code = nodecodes.marginkern local dir_code = nodecodes.dir local boundary_code = nodecodes.boundary -local protrusion_code = boundarycodes.protrusion +local protrusionboundary_code = boundarycodes.protrusion -local leaders_code = gluecodes.leaders +local leaders_code = leadercodes.leaders local localpar_code = nodecodes.localpar @@ -287,17 +332,17 @@ local italickern_code = kerncodes.italiccorrection local fontkern_code = kerncodes.fontkern local accentkern_code = kerncodes.accentkern -local ligature_code = glyphcodes.ligature +local ligatureglyph_code = glyphcodes.ligature -local stretch_orders = nodes.fillcodes +local fillcodes = nodes.fillcodes local leftmargin_code = margincodes.left ----- 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 automaticdisc_code = disccodes.automatic +local regulardisc_code = disccodes.regular +local firstdisc_code = disccodes.first +local seconddisc_code = disccodes.second local endmath_code = mathcodes.endmath @@ -323,7 +368,7 @@ 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_direction = nodepool.direction local new_leftmarginkern = nodepool.leftmarginkern local new_rightmarginkern = nodepool.rightmarginkern local new_leftskip = nodepool.leftskip @@ -334,17 +379,6 @@ local new_temp = nodepool.temp local new_rule = nodepool.rule local new_hlist = nodepool.hlist -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 = nuts.protrusion_skippable - -- helpers -- -- It makes more sense to move the somewhat messy dir state tracking @@ -359,22 +393,24 @@ end -- in the parbuilder. local function checked_line_dir(stack,current) - if not dir_pops[current] then + local direction, pop = getdirection(current) + if not pop then local n = stack.n + 1 stack.n = n stack[n] = current - return getdir(current) + return direction elseif n > 0 then local n = stack.n local dirnode = stack[n] dirstack.n = n - 1 - return getdir(dirnode) + direction = getdirection(dirnode) -- we could save it + return direction 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 +-- The next function checks 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. @@ -382,10 +418,12 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) local e = start local n = stack.n local h = nil + -- todo: traverse while start and start ~= stop do local id = getid(start) if id == dir_code then - if not dir_pops[getdir(start)] then -- weird, what is this # + local direction, pop = getdirection(start) + if not pop then n = n + 1 stack[n] = start elseif n > 0 then @@ -397,7 +435,7 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) start = getnext(start) end for i=n,1,-1 do - h, current = insert_node_after(current,current,new_dir(dir_negations[getdir(stack[i])])) + h, current = insert_node_after(current,current,new_direction(getdirection(stack[i]),true)) end stack.n = n return current @@ -406,7 +444,7 @@ 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])) + h, current = insert_node_after(current,current,new_direction(stack[i])) end stack.n = 0 return current @@ -507,9 +545,9 @@ end) local function kern_stretch_shrink(p,d) local left = getprev(p) if left then - local char = isglyph(left) + local char, font = isglyph(left) if char then - local data = expansions[getfont(left)][char] + local data = expansions[font][char] if data then local stretch = data.stretch local shrink = data.shrink @@ -630,8 +668,8 @@ local function find(head) -- do we really want to recurse into an hlist? head = getnext(head) end elseif id == boundary_code then - if getsubtype(head) == protrusion_code then - local v = getfield(head,"value") + if getsubtype(head) == protrusionboundary_code then + local v = getdata(head) if v == 1 or v == 3 then head = getnext(head) if head then @@ -654,19 +692,19 @@ end local function find_protchar_left(l) -- weird function local ln = getnext(l) - if ln and getid(ln) == hlist_code and not getlist(ln) and getfield(ln,"width") == 0 and getfield(ln,"height") == 0 and getfield(ln,"depth") == 0 then - l = getnext(l) - else -- if d then -- was always true - local id = getid(l) - while ln and not (id == glyph_code or id < math_code) do -- is there always a glyph? - l = ln - ln = getnext(l) - id = getid(ln) - end + if ln and getid(ln) == hlist_code and not getlist(ln) then + local w, h, d = getwhd(ln) + if w == 0 and h == 0 and d == 0 then + l = getnext(l) + return find(l) or l + end + end -- if d then -- was always true + local id = getid(l) + while ln and not (id == glyph_code or id < math_code) do -- is there always a glyph? + l = ln + ln = getnext(l) + id = getid(ln) end - -- if getid(l) == glyph_code then - -- return l - -- end return find(l) or l end @@ -684,8 +722,8 @@ local function find(head,tail) tail = getprev(tail) end elseif id == boundary_code then - if getsubtype(head) == protrusion_code then - local v = getfield(tail,"value") + if getsubtype(head) == protrusionboundary_code then + local v = getdata(tail) if v == 2 or v == 3 then tail = getprev(tail) if tail then @@ -711,8 +749,8 @@ local function find_protchar_right(l,r) end local function left_pw(p) - local font = getfont(p) - local prot = chardata[font][getchar(p)].left_protruding + local char, font = isglyph(p) + local prot = chardata[font][char].left_protruding if not prot or prot == 0 then return 0 end @@ -720,8 +758,8 @@ local function left_pw(p) end local function right_pw(p) - local font = getfont(p) - local prot = chardata[font][getchar(p)].right_protruding + local char, font = isglyph(p) + local prot = chardata[font][char].right_protruding if not prot or prot == 0 then return 0 end @@ -748,13 +786,13 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw local char, id = isglyph(s) if char then local wd, ht, dp = getwhd(s) - if is_rotated[line_break_dir] then -- can be shared + if is_rotated(line_break_dir) then size = size + ht + dp else size = size + wd end if checked_expansion then - local data = checked_expansion[getfont(s)] + local data = checked_expansion[id] -- id == font if data then data = data[char] if data then @@ -765,7 +803,7 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw end elseif id == hlist_code or id == vlist_code then local wd, ht, dp = getwhd(s) - if is_parallel[getdir(s)][line_break_dir] then + if textdir_parallel(getdirection(s),line_break_dir) then size = size + wd else size = size + ht + dp @@ -796,1709 +834,1712 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw 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 pre, post, replace = getdisc(p) - 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 - 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 = getnext(p) - else - return - end - end - while p do -- skip spacing etc - local id = getid(p) - if id == glyph_code then - return -- happens often - elseif id == glue_code then - local wd, stretch, shrink, stretch_order = getglue(p) - local order = stretch_orders[stretch_order] - break_width.size = break_width.size - wd - break_width[order] = break_width[order] - stretch - break_width.shrink = break_width.shrink - shrink - elseif id == penalty_code then - -- do nothing - elseif id == kern_code then - local s = getsubtype(p) - if s == userkern_code or s == italickern_code then - break_width.size = break_width.size - getkern(p) +-- We can actually make par local to this module as we never break inside a break call and that way the +-- array is reused. At some point the information will be part of the paragraph spec as passed. + +local hztolerance = 2500 +local hzwarned = false + +do + + 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 pre, post, replace = getdisc(p) + 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 + 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 = getnext(p) else return end - elseif id == math_code then - break_width.size = break_width.size - getkern(p) -- surround - -- new in luatex - local wd, stretch, shrink, stretch_order = getglue(p) - local order = stretch_orders[stretch_order] - break_width.size = break_width.size - wd - break_width[order] = break_width[order] - stretch - break_width.shrink = break_width.shrink - shrink - else - return end - p = getnext(p) - end -end - -local function append_to_vlist(par, b) - local prev_depth = par.prev_depth - local head_field = par.head_field - local tail_field = head_field and slide_node_list(head_field) -- todo: find_tail - local is_hlist = getid(b) == hlist_code - -- if prev_depth > par.ignored_dimen then - if prev_depth > ignore_depth then - if is_hlist then - local width, stretch, shrink, stretch_order, shrink_order = getglue(par.baseline_skip) - local delta = width - prev_depth - getheight(b) -- deficiency of space between baselines - local skip = nil - if delta < par.line_skip_limit then - width, stretch, shrink, stretch_order, shrink_order = getglue(par.lineskip) - skip = new_lineskip(width, stretch, shrink, stretch_order, shrink_order) - else - skip = new_baselineskip(delta, stretch, shrink, stretch_order, shrink_order) - end - if head_field then - setlink(tail_field,skip) + while p do -- skip spacing etc + local id = getid(p) + if id == glyph_code then + return -- happens often + elseif id == glue_code then + local wd, stretch, shrink, stretch_order = getglue(p) + local order = fillcodes[stretch_order] + break_width.size = break_width.size - wd + break_width[order] = break_width[order] - stretch + break_width.shrink = break_width.shrink - shrink + elseif id == penalty_code then + -- do nothing + elseif id == kern_code then + local s = getsubtype(p) + if s == userkern_code or s == italickern_code then + break_width.size = break_width.size - getkern(p) + else + return + end + elseif id == math_code then + break_width.size = break_width.size - getkern(p) -- surround + -- new in luatex + local wd, stretch, shrink, stretch_order = getglue(p) + local order = fillcodes[stretch_order] + break_width.size = break_width.size - wd + break_width[order] = break_width[order] - stretch + break_width.shrink = break_width.shrink - shrink else - par.head_field = skip - head_field = skip + return end - tail_field = skip + p = getnext(p) end end - if head_field then - setlink(tail_field,b) - else - par.head_field = b - end - if is_hlist then - local pd = getdepth(b) - 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_node_list(head_field) -- todo: find_tail - setlink(n,b) - else - par.head_field = b + local function append_to_vlist(par, b) + local prev_depth = par.prev_depth + local head_field = par.head_field + local tail_field = head_field and slide_node_list(head_field) -- todo: find_tail + local is_hlist = getid(b) == hlist_code + -- if prev_depth > par.ignored_dimen then + if prev_depth > ignore_depth then + if is_hlist then + local width, stretch, shrink, stretch_order, shrink_order = getglue(par.baseline_skip) + local delta = width - prev_depth - getheight(b) -- deficiency of space between baselines + local skip = nil + if delta < par.line_skip_limit then + width, stretch, shrink, stretch_order, shrink_order = getglue(par.lineskip) + skip = new_lineskip(width, stretch, shrink, stretch_order, shrink_order) + else + skip = new_baselineskip(delta, stretch, shrink, stretch_order, shrink_order) + end + if head_field then + setlink(tail_field,skip) + else + par.head_field = skip + head_field = skip + end + tail_field = skip + end + end + if head_field then + setlink(tail_field,b) + else + par.head_field = b + end + if is_hlist then + local pd = getdepth(b) + par.prev_depth = pd + texnest[texnest.ptr].prevdepth = pd + end end -end - --- We can actually make par local to this module as we never break inside a break call and that way the --- array is reused. At some point the information will be part of the paragraph spec as passed. - -local hztolerance = 2500 -local hzwarned = false - -local function used_skip(s) - return s and not is_zero_glue(s) and s -end -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 = tonut(tex.leftskip) -- nodes - local right_skip = tonut(tex.rightskip) -- nodes - local pretolerance = tex.pretolerance - local tolerance = tex.tolerance - local adjust_spacing = tex.adjustspacing - local protrude_chars = tex.protrudechars - local last_line_fit = tex.lastlinefit - - local newhead = new_temp() - setnext(newhead,head) - - local adjust_spacing_status = adjust_spacing > 1 and -1 or 0 - - -- metatables - - local par = { - head = newhead, - head_field = nil, - display = display, - font_in_short_display = 0, - no_shrink_error_yet = true, -- have we complained about infinite shrinkage? - second_pass = false, -- is this our second attempt to break this paragraph? - final_pass = false, -- is this our final attempt to break this paragraph? - threshold = 0, -- maximum badness on feasible lines - - passive = nil, -- most recent node on passive list - printed_node = head, -- most recent node that has been printed - pass_number = 0, -- the number of passive nodes allocated on this pass - auto_breaking = 0, -- make auto_breaking accessible out of line_break - - active_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 }, - break_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 }, - disc_width = { size = 0, adjust_stretch = 0, adjust_shrink = 0 }, - fill_width = { stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 }, - background = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 }, - - hang_indent = hang_indent, - hsize = hsize, - hang_after = hang_after, - par_shape_ptr = par_shape_ptr, - left_skip = left_skip, - right_skip = right_skip, - pretolerance = pretolerance, - tolerance = tolerance, - - protrude_chars = protrude_chars, - adjust_spacing = adjust_spacing, - max_stretch_ratio = adjust_spacing_status, - max_shrink_ratio = adjust_spacing_status, - cur_font_step = adjust_spacing_status, - checked_expansion = false, - tracing_paragraphs = tex.tracingparagraphs > 0, - - emergency_stretch = tex.emergencystretch or 0, - looseness = tex.looseness or 0, - line_penalty = tex.linepenalty or 0, - hyphen_penalty = tex.hyphenpenalty or 0, - broken_penalty = tex.brokenpenalty or 0, - inter_line_penalty = tex.interlinepenalty or 0, - club_penalty = tex.clubpenalty or 0, - widow_penalty = tex.widowpenalty or 0, - display_widow_penalty = tex.displaywidowpenalty or 0, - ex_hyphen_penalty = tex.exhyphenpenalty or 0, - - adj_demerits = tex.adjdemerits or 0, - double_hyphen_demerits = tex.doublehyphendemerits or 0, - final_hyphen_demerits = tex.finalhyphendemerits or 0, - - first_line = 0, -- tex.nest[tex.nest.ptr].modeline, -- 0, -- cur_list.pg_field - - -- each_line_height = tex.pdfeachlineheight or 0, -- this will go away - -- each_line_depth = tex.pdfeachlinedepth or 0, -- this will go away - -- first_line_height = tex.pdffirstlineheight or 0, -- this will go away - -- last_line_depth = tex.pdflastlinedepth or 0, -- this will go away - - -- ignored_dimen = tex.pdfignoreddimen or 0, - - baseline_skip = tonut(tex.baselineskip), - lineskip = tonut(tex.lineskip), - line_skip_limit = tex.lineskiplimit, - - prev_depth = texnest[texnest.ptr].prevdepth, - - final_par_glue = slide_node_list(head), -- todo: we know tail already, slow - - par_break_dir = tex.pardir, - line_break_dir = tex.pardir, - - internal_pen_inter = 0, -- running localinterlinepenalty - internal_pen_broken = 0, -- running localbrokenpenalty - internal_left_box = nil, -- running localleftbox - internal_left_box_width = 0, -- running localleftbox width - init_internal_left_box = nil, -- running localleftbox - init_internal_left_box_width = 0, -- running localleftbox width - internal_right_box = nil, -- running localrightbox - internal_right_box_width = 0, -- running localrightbox width - - best_place = { }, -- how to achieve minimal_demerits - best_pl_line = { }, -- corresponding line number - easy_line = 0, -- line numbers easy_line are equivalent in break nodes - last_special_line = 0, -- line numbers last_special_line all have the same width - first_width = 0, -- the width of all lines last_special_line, if no parshape has been specified - second_width = 0, -- the width of all lines last_special_line - first_indent = 0, -- left margin to go with first_width - second_indent = 0, -- left margin to go with second_width - - best_bet = nil, -- use this passive node and its predecessors - fewest_demerits = 0, -- the demerits associated with best_bet - best_line = 0, -- line number following the last line of the new paragraph - line_diff = 0, -- the difference between the current line number and the optimum best_line - - -- not yet used - - best_pl_short = { }, -- shortfall corresponding to minimal_demerits - best_pl_glue = { }, -- corresponding glue stretch or shrink - do_last_line_fit = false, - last_line_fit = last_line_fit, - - minimum_demerits = awful_badness, - - minimal_demerits = { - - [fit_very_loose_class] = awful_badness, - [fit_loose_class] = awful_badness, - [fit_decent_class] = awful_badness, - [fit_tight_class] = awful_badness, - - }, - - prev_char_p = nil, - - statistics = { - - noflines = 0, - nofprotrudedlines = 0, - nofadjustedlines = 0, - - }, - - -- -- just a thought ... parshape functions ... it would be nice to - -- -- also store the height so far (probably not too hard) although - -- -- in most cases we work on grids in such cases - -- - -- adapt_width = function(par,line) - -- -- carry attribute, so that we can accumulate - -- local left = 655360 * (line - 1) - -- local right = 655360 * (line - 1) - -- return left, right - -- end + local function append_list(par, b) + local head_field = par.head_field + if head_field then + local n = slide_node_list(head_field) -- todo: find_tail + setlink(n,b) + else + par.head_field = b + end + end + + local function used_skip(s) + return s and not is_zero_glue(s) and s + end + + 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 = tonut(tex.leftskip) -- nodes + local right_skip = tonut(tex.rightskip) -- nodes + local pretolerance = tex.pretolerance + local tolerance = tex.tolerance + local adjust_spacing = tex.adjustspacing + local protrude_chars = tex.protrudechars + local last_line_fit = tex.lastlinefit + local par_dir = tex.pardirection + + local newhead = new_temp() + setnext(newhead,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, -- texnest[texnest.ptr].modeline, -- 0, -- cur_list.pg_field + + -- each_line_height = tex.pdfeachlineheight or 0, -- this will go away + -- each_line_depth = tex.pdfeachlinedepth or 0, -- this will go away + -- first_line_height = tex.pdffirstlineheight or 0, -- this will go away + -- last_line_depth = tex.pdflastlinedepth or 0, -- this will go away + + -- ignored_dimen = tex.pdfignoreddimen or 0, + + baseline_skip = tonut(tex.baselineskip), + lineskip = tonut(tex.lineskip), + line_skip_limit = tex.lineskiplimit, + + prev_depth = texnest[texnest.ptr].prevdepth, + + final_par_glue = slide_node_list(head), -- todo: we know tail already, slow + + par_break_dir = par_dir, + line_break_dir = par_dir, + + internal_pen_inter = 0, -- running localinterlinepenalty + internal_pen_broken = 0, -- running localbrokenpenalty + internal_left_box = nil, -- running localleftbox + internal_left_box_width = 0, -- running localleftbox width + init_internal_left_box = nil, -- running localleftbox + init_internal_left_box_width = 0, -- running localleftbox width + internal_right_box = nil, -- running localrightbox + internal_right_box_width = 0, -- running localrightbox width + + best_place = { }, -- how to achieve minimal_demerits + best_pl_line = { }, -- corresponding line number + easy_line = 0, -- line numbers easy_line are equivalent in break nodes + last_special_line = 0, -- line numbers last_special_line all have the same width + first_width = 0, -- the width of all lines last_special_line, if no parshape has been specified + second_width = 0, -- the width of all lines last_special_line + first_indent = 0, -- left margin to go with first_width + second_indent = 0, -- left margin to go with second_width + + best_bet = nil, -- use this passive node and its predecessors + fewest_demerits = 0, -- the demerits associated with best_bet + best_line = 0, -- line number following the last line of the new paragraph + line_diff = 0, -- the difference between the current line number and the optimum best_line + + -- not yet used + + best_pl_short = { }, -- shortfall corresponding to minimal_demerits + best_pl_glue = { }, -- corresponding glue stretch or shrink + do_last_line_fit = false, + last_line_fit = last_line_fit, + + minimum_demerits = awful_badness, + + minimal_demerits = { + + [fit_very_loose_class] = awful_badness, + [fit_loose_class] = awful_badness, + [fit_decent_class] = awful_badness, + [fit_tight_class] = awful_badness, + + }, + + prev_char_p = nil, + + statistics = { + + noflines = 0, + nofprotrudedlines = 0, + nofadjustedlines = 0, + + }, + + -- -- just a thought ... parshape functions ... it would be nice to + -- -- also store the height so far (probably not too hard) although + -- -- in most cases we work on grids in such cases + -- + -- adapt_width = function(par,line) + -- -- carry attribute, so that we can accumulate + -- local left = 655360 * (line - 1) + -- local right = 655360 * (line - 1) + -- return left, right + -- end - } + } - -- optimizers + -- optimizers - par.used_left_skip = used_skip(par.left_skip) - par.used_right_skip = used_skip(par.right_skip) + par.used_left_skip = used_skip(par.left_skip) + par.used_right_skip = used_skip(par.right_skip) - -- so far + -- so far - if adjust_spacing > 1 then - local checked_expansion = { par = par } - setmetatableindex(checked_expansion,check_expand_pars) - par.checked_expansion = checked_expansion + if adjust_spacing > 1 then + local checked_expansion = { par = par } + setmetatableindex(checked_expansion,check_expand_pars) + par.checked_expansion = checked_expansion - if par.tolerance < hztolerance then - if not hzwarned then - report_parbuilders("setting tolerance to %a for hz",hztolerance) - hzwarned = true + if par.tolerance < hztolerance then + if not hzwarned then + report_parbuilders("setting tolerance to %a for hz",hztolerance) + hzwarned = true + end + par.tolerance = hztolerance end - par.tolerance = hztolerance - end - expand_kerns = expand_kerns_mode or (adjust_spacing == 2) + expand_kerns = expand_kerns_mode or (adjust_spacing == 2) - end + end - -- we need par for the error message + -- we need par for the error message - local background = par.background + local background = par.background - local l = check_shrinkage(par,left_skip) - local r = check_shrinkage(par,right_skip) + local l = check_shrinkage(par,left_skip) + local r = check_shrinkage(par,right_skip) - local lwidth, lstretch, lshrink, lstretch_order, lshrink_order = getglue(l) - local rwidth, rstretch, rshrink, rstretch_order, rshrink_order = getglue(r) + local lwidth, lstretch, lshrink, lstretch_order, lshrink_order = getglue(l) + local rwidth, rstretch, rshrink, rstretch_order, rshrink_order = getglue(r) - local l_order = stretch_orders[lstretch_order] - local r_order = stretch_orders[rstretch_order] + local l_order = fillcodes[lstretch_order] + local r_order = fillcodes[rstretch_order] - background.size = lwidth + rwidth - background.shrink = lshrink + rshrink - background[l_order] = lstretch - background[r_order] = rstretch + background[r_order] + background.size = lwidth + rwidth + background.shrink = lshrink + rshrink + background[l_order] = lstretch + background[r_order] = rstretch + background[r_order] - -- this will move up so that we can assign the whole par table + -- 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 + if not par_shape_ptr then + if hang_indent == 0 then 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 + local abs_hang_after = hang_after >0 and hang_after or -hang_after + local abs_hang_indent = hang_indent>0 and hang_indent or -hang_indent + par.last_special_line = abs_hang_after + if hang_after < 0 then + par.first_width = hsize - abs_hang_indent + if hang_indent >= 0 then + par.first_indent = hang_indent + else + par.first_indent = 0 + end + par.second_width = hsize par.second_indent = 0 + else + par.first_width = hsize + par.first_indent = 0 + par.second_width = hsize - abs_hang_indent + if hang_indent >= 0 then + par.second_indent = hang_indent + else + par.second_indent = 0 + end end end + else + local last_special_line = #par_shape_ptr + par.last_special_line = last_special_line + local parshape = par_shape_ptr[last_special_line] + par.second_width = parshape[2] + par.second_indent = parshape[1] end - else - local last_special_line = #par_shape_ptr - par.last_special_line = last_special_line - local parshape = par_shape_ptr[last_special_line] - par.second_width = parshape[2] - par.second_indent = parshape[1] - end - if par.looseness == 0 then - par.easy_line = par.last_special_line - else - par.easy_line = max_halfword - end + if 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") + 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 - end - if last_line_fit > 0 then - local final_par_glue = par.final_par_glue - local stretch = getfield(final_par_glue,"stretch") - local stretch_order = getfield(final_par_glue,"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) + if last_line_fit > 0 then + local final_par_glue = par.final_par_glue + local stretch = getfield(final_par_glue,"stretch") + local stretch_order = getfield(final_par_glue,"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 = fillcodes[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 - par.fill_width[si] = stretch end - end - return par -end + return par + end --- there are still all kind of artefacts in here (a side effect I guess of pdftex, --- etex, omega and other extensions that got obscured by patching) + -- there are still all kind of artefacts in here (a side effect I guess of pdftex, + -- etex, omega and other extensions that got obscured by patching) -local function post_line_break(par) + local function post_line_break(par) - local prevgraf = texnest[texnest.ptr].prevgraf - local current_line = prevgraf + 1 -- the current line number being justified + local prevgraf = texnest[texnest.ptr].prevgraf + local current_line = prevgraf + 1 -- the current line number being justified - local adjust_spacing = par.adjust_spacing - local protrude_chars = par.protrude_chars - local statistics = par.statistics + local adjust_spacing = par.adjust_spacing + local protrude_chars = par.protrude_chars + local statistics = par.statistics - local stack = new_dir_stack() + local stack = new_dir_stack() - local leftskip = par.used_left_skip -- used or normal ? - local rightskip = par.right_skip - local parshape = par.par_shape_ptr - ----- ignored_dimen = par.ignored_dimen + local leftskip = par.used_left_skip -- used or normal ? + local rightskip = par.right_skip + local parshape = par.par_shape_ptr + ----- ignored_dimen = par.ignored_dimen - local adapt_width = par.adapt_width + local adapt_width = par.adapt_width - -- reverse the links of the relevant passive nodes, goto first breakpoint + -- reverse the links of the relevant passive nodes, goto first breakpoint - local current_break = nil + local current_break = nil - local break_node = par.best_bet.break_node - repeat - local first_break = break_node - break_node = break_node.prev_break - first_break.prev_break = current_break - current_break = first_break - until not break_node + local break_node = par.best_bet.break_node + repeat + local first_break = break_node + break_node = break_node.prev_break + first_break.prev_break = current_break + current_break = first_break + until not break_node - local head = par.head + local head = par.head - -- maybe : each_... + -- maybe : each_... - while current_break do + while current_break do - inject_dirs_at_begin_of_line(stack,head) + inject_dirs_at_begin_of_line(stack,head) - local disc_break = false - local post_disc_break = false - local glue_break = false + local disc_break = false + local post_disc_break = false + local glue_break = false - local lineend = nil -- q lineend refers to the last node of the line (and paragraph) - local lastnode = current_break.cur_break -- r lastnode refers to the node after which the dir nodes should be closed + local lineend = nil -- lineend : the last node of the line (and paragraph) + local lastnode = current_break.cur_break -- lastnode: the node after which the dir nodes should be closed - if not lastnode then - -- only at the end - lastnode = slide_node_list(head) -- todo: find_tail - if lastnode == par.final_par_glue then - lineend = lastnode - lastnode = getprev(lastnode) - end - else -- todo: use insert_list_after - local id = getid(lastnode) - if id == glue_code then - -- lastnode is normal skip - lastnode = replace_node(lastnode,new_rightskip(rightskip)) - glue_break = true - lineend = lastnode - lastnode = getprev(lastnode) - elseif id == disc_code then - local prevlast = getprev(lastnode) - local nextlast = getnext(lastnode) - local subtype = getsubtype(lastnode) - local pre, post, replace, pretail, posttail, replacetail = getdisc(lastnode,true) - if subtype == second_disc_code then - if not (getid(prevlast) == disc_code and getsubtype(prevlast) == first_disc_code) then - report_parbuilders('unsupported disc at location %a',3) - end - if pre then - flush_node_list(pre) - pre = nil -- signal + if not lastnode then + -- only at the end + lastnode = slide_node_list(head) -- todo: find_tail + if lastnode == par.final_par_glue then + lineend = lastnode + lastnode = getprev(lastnode) + end + else -- todo: use insert_list_after + local id = getid(lastnode) + if id == glue_code then + -- lastnode is normal skip + lastnode = replace_node(lastnode,new_rightskip(rightskip)) + glue_break = true + lineend = lastnode + lastnode = getprev(lastnode) + elseif id == disc_code then + local prevlast = getprev(lastnode) + local nextlast = getnext(lastnode) + local subtype = getsubtype(lastnode) + local pre, post, replace, pretail, posttail, replacetail = getdisc(lastnode,true) + if subtype == seconddisc_code then + if not (getid(prevlast) == disc_code and getsubtype(prevlast) == firstdisc_code) then + report_parbuilders('unsupported disc at location %a',3) + end + if pre then + flush_node_list(pre) + pre = nil -- signal + end + if replace then + setlink(prevlast,replace) + setlink(replacetail,lastnode) + replace = nil -- signal + end + setdisc(lastnode,pre,post,replace) + local pre, post, replace = getdisc(prevlast) + if pre then + flush_node_list(pre) + end + if replace then + flush_node_list(replace) + end + if post then + flush_node_list(post) + end + setdisc(prevlast) -- nil,nil,nil + elseif subtype == firstdisc_code then + -- what is v ... next probably + if not (getid(v) == disc_code and getsubtype(v) == seconddisc_code) then + report_parbuilders('unsupported disc at location %a',4) + end + setsubtype(nextlast,regulardisc_code) + setfield(nextlast,"replace",post) + setfield(lastnode,"post") -- nil end if replace then - setlink(prevlast,replace) - setlink(replacetail,lastnode) - replace = nil -- signal + flush_node_list(replace) end - setdisc(lastnode,pre,post,replace) - local pre, post, replace = getdisc(prevlast) if pre then - flush_node_list(pre) - end - if replace then - flush_node_list(replace) + setlink(prevlast,pre) + setlink(pretail,lastnode) end if post then - flush_node_list(post) - end - setdisc(prevlast) -- nil,nil,nil - elseif subtype == first_disc_code then - -- what is v ... next probably - if not (getid(v) == disc_code and getsubtype(v) == second_disc_code) then - report_parbuilders('unsupported disc at location %a',4) + setlink(lastnode,post) + setlink(posttail,nextlast) + post_disc_break = true end - setsubtype(nextlast,regular_disc_code) - setfield(nextlast,"replace",post) - setfield(lastnode,"post") -- nil - end - if replace then - flush_node_list(replace) + setdisc(lastnode) -- nil, nil, nil + disc_break = true + elseif id == kern_code then + setkern(lastnode,0) + elseif getid(lastnode) == math_code then + setkern(lastnode,0) -- surround + -- new in luatex + setglue(lastnode) -- zeros end - if pre then - setlink(prevlast,pre) - setlink(pretail,lastnode) + end + lastnode = inject_dirs_at_end_of_line(stack,lastnode,getnext(head),current_break.cur_break) + local rightbox = current_break.passive_right_box + if rightbox then + lastnode = insert_node_after(lastnode,lastnode,copy_node(rightbox)) + end + if not lineend then + lineend = lastnode + end + if lineend and lineend ~= head and protrude_chars > 0 then + local id = getid(lineend) + local c = (disc_break and (id == glyph_code or id ~= disc_code) and lineend) or getprev(lineend) + local p = find_protchar_right(getnext(head),c) + if p and getid(p) == glyph_code then + local w, last_rightmost_char = right_pw(p) + if last_rightmost_char and w ~= 0 then + -- so we inherit attributes, lineend is new pseudo head + lineend, c = insert_node_after(lineend,c,new_rightmarginkern(copy_node(last_rightmost_char),-w)) + end end - if post then - setlink(lastnode,post) - setlink(posttail,nextlast) - post_disc_break = true + end + -- we finish the line + local r = getnext(lineend) + setnext(lineend) + if not glue_break then + if rightskip then + insert_node_after(lineend,lineend,new_rightskip(right_skip)) -- lineend moves on as pseudo head end - setdisc(lastnode) -- nil, nil, nil - disc_break = true - elseif id == kern_code then - setkern(lastnode,0) - elseif getid(lastnode) == math_code then - setkern(lastnode,0) -- surround - -- new in luatex - setglue(lastnode) -- zeros end - end - lastnode = inject_dirs_at_end_of_line(stack,lastnode,getnext(head),current_break.cur_break) - local rightbox = current_break.passive_right_box - if rightbox then - lastnode = insert_node_after(lastnode,lastnode,copy_node(rightbox)) - end - if not lineend then - lineend = lastnode - end - if lineend and lineend ~= head and protrude_chars > 0 then - local id = getid(lineend) - local c = (disc_break and (id == glyph_code or id ~= disc_code) and lineend) or getprev(lineend) - local p = find_protchar_right(getnext(head),c) - if p and getid(p) == glyph_code then - local w, last_rightmost_char = right_pw(p) - if last_rightmost_char and w ~= 0 then - -- so we inherit attributes, lineend is new pseudo head - lineend, c = insert_node_after(lineend,c,new_rightmarginkern(copy_node(last_rightmost_char),-w)) + -- each time ? + local q = getnext(head) + setlink(head,r) + -- insert leftbox (if needed after parindent) + local leftbox = current_break.passive_left_box + if leftbox then + local first = getnext(q) + if first and current_line == (par.first_line + 1) and getid(first) == hlist_code and not getlist(first) then + insert_node_after(q,q,copy_node(leftbox)) + else + q = insert_node_before(q,q,copy_node(leftbox)) end end - end - -- we finish the line - local r = getnext(lineend) - setnext(lineend) - if not glue_break then - if rightskip then - insert_node_after(lineend,lineend,new_rightskip(right_skip)) -- lineend moves on as pseudo head + if protrude_chars > 0 then + local p = find_protchar_left(q) + if p and getid(p) == 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 - end - -- each time ? - local q = getnext(head) - setlink(head,r) - -- insert leftbox (if needed after parindent) - local leftbox = current_break.passive_left_box - if leftbox then - local first = getnext(q) - if first and current_line == (par.first_line + 1) and getid(first) == hlist_code and not getlist(first) then - insert_node_after(q,q,copy_node(leftbox)) + if leftskip then + q = insert_node_before(q,q,new_leftskip(leftskip)) + end + local cur_width, cur_indent + if current_line > par.last_special_line then + cur_indent = par.second_indent + cur_width = par.second_width + elseif parshape then + local shape = parshape[current_line] + cur_indent = shape[1] + cur_width = shape[2] else - q = insert_node_before(q,q,copy_node(leftbox)) - end - end - if protrude_chars > 0 then - local p = find_protchar_left(q) - if p and getid(p) == 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 + cur_indent = par.first_indent + cur_width = par.first_width end - end - if leftskip then - q = insert_node_before(q,q,new_leftskip(leftskip)) - end - local cur_width, cur_indent - if current_line > par.last_special_line then - cur_indent = par.second_indent - cur_width = par.second_width - elseif parshape then - local shape = parshape[current_line] - cur_indent = shape[1] - cur_width = shape[2] - else - cur_indent = par.first_indent - cur_width = par.first_width - end - if adapt_width then -- extension - local l, r = adapt_width(par,current_line) - cur_indent = cur_indent + l - cur_width = cur_width - l - r - end + if adapt_width then -- extension + local l, r = adapt_width(par,current_line) + cur_indent = cur_indent + l + cur_width = cur_width - l - r + end - statistics.noflines = statistics.noflines + 1 - local finished_line = nil - if adjust_spacing > 0 then - statistics.nofadjustedlines = statistics.nofadjustedlines + 1 - finished_line = xpack_nodes(q,cur_width,"cal_expand_ratio",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis) - else - finished_line = xpack_nodes(q,cur_width,"exactly",par.par_break_dir,par.first_line,current_line) -- ,current_break.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 - -- - setshift(finished_line,cur_indent) - -- - -- -- this is gone: - -- - -- if par.each_line_height ~= ignored_dimen then - -- setheight(finished_line,par.each_line_height) - -- end - -- if par.each_line_depth ~= ignored_dimen then - -- setdepth(finished_line,par.each_line_depth) - -- end - -- if par.first_line_height ~= ignored_dimen and (current_line == par.first_line + 1) then - -- setheight(finished_line,par.first_line_height) - -- end - -- if par.last_line_depth ~= ignored_dimen and current_line + 1 == par.best_line then - -- setdepth(finished_line,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,finished_line) - if texlists.adjust_head ~= adjust_head then - append_list(par, texlists.adjust_head) - texlists.adjust_head = adjust_head - end - -- - local pen - if current_line + 1 ~= par.best_line then - if current_break.passive_pen_inter then - pen = current_break.passive_pen_inter + statistics.noflines = statistics.noflines + 1 + local finished_line = nil + if adjust_spacing > 0 then + statistics.nofadjustedlines = statistics.nofadjustedlines + 1 + finished_line = xpack_nodes(q,cur_width,"cal_expand_ratio",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis) else - pen = par.inter_line_penalty - end - if current_line == prevgraf + 1 then - pen = pen + par.club_penalty - end - if current_line + 2 == par.best_line then - if par.display then - pen = pen + par.display_widow_penalty + finished_line = xpack_nodes(q,cur_width,"exactly",par.par_break_dir,par.first_line,current_line) -- ,current_break.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 + -- + setshift(finished_line,cur_indent) + -- + -- -- this is gone: + -- + -- if par.each_line_height ~= ignored_dimen then + -- setheight(finished_line,par.each_line_height) + -- end + -- if par.each_line_depth ~= ignored_dimen then + -- setdepth(finished_line,par.each_line_depth) + -- end + -- if par.first_line_height ~= ignored_dimen and (current_line == par.first_line + 1) then + -- setheight(finished_line,par.first_line_height) + -- end + -- if par.last_line_depth ~= ignored_dimen and current_line + 1 == par.best_line then + -- setdepth(finished_line,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,finished_line) + if texlists.adjust_head ~= adjust_head then + append_list(par, texlists.adjust_head) + texlists.adjust_head = adjust_head + end + -- + local pen + if current_line + 1 ~= par.best_line then + if current_break.passive_pen_inter then + pen = current_break.passive_pen_inter else - pen = pen + par.widow_penalty + pen = par.inter_line_penalty end - end - if disc_break then - if current_break.passive_pen_broken ~= 0 then - pen = pen + current_break.passive_pen_broken - else - pen = pen + par.broken_penalty + if current_line == prevgraf + 1 then + pen = pen + par.club_penalty end - end - if pen ~= 0 then - append_to_vlist(par,new_penalty(pen)) - end - end - current_line = current_line + 1 - current_break = current_break.prev_break - if current_break and not post_disc_break then - local current = head - local next = nil - while true do - next = getnext(current) - if next == current_break.cur_break then - break + if current_line + 2 == par.best_line then + if par.display then + pen = pen + par.display_widow_penalty + else + pen = pen + par.widow_penalty + end end - local id = getid(next) - if id == glyph_code then - break - elseif id == localpar_code then - -- nothing - elseif id < math_code then - -- messy criterium - break - elseif id == math_code then - -- keep the math node - setkern(next,0) -- surround - -- new in luatex - setglue(lastnode) -- zeros - break - elseif id == kern_code then - local subtype = getsubtype(next) - if subtype == fontkern_code or subtype == accentkern_code then - -- fontkerns and accent kerns as well as otf injections - break + if disc_break then + if current_break.passive_pen_broken ~= 0 then + pen = pen + current_break.passive_pen_broken + else + pen = pen + par.broken_penalty end end - current = next + if pen ~= 0 then + append_to_vlist(par,new_penalty(pen)) + end end - if current ~= head then - setnext(current) - flush_node_list(getnext(head)) - setlink(head,next) + current_line = current_line + 1 + current_break = current_break.prev_break + if current_break and not post_disc_break then + local current = head + local next = nil + while true do + next = getnext(current) + if next == current_break.cur_break then + break + end + local id = getid(next) + if id == glyph_code then + break + elseif id == localpar_code then + -- nothing + elseif id < math_code then + -- messy criterium + break + elseif id == math_code then + -- keep the math node + setkern(next,0) -- surround + -- new in luatex + setglue(lastnode) -- zeros + break + elseif id == kern_code then + local subtype = getsubtype(next) + if subtype == fontkern_code or subtype == accentkern_code then + -- fontkerns and accent kerns as well as otf injections + break + end + end + current = next + end + if current ~= head then + setnext(current) + flush_node_list(getnext(head)) + setlink(head,next) + end end end - end - -- if current_line ~= par.best_line then - -- report_parbuilders("line breaking") - -- end - par.head = nil -- needs checking - current_line = current_line - 1 - if trace_basic then - report_parbuilders("paragraph broken into %a lines",current_line) - end - texnest[texnest.ptr].prevgraf = current_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 - setwidth(glue,getwidth(glue) + active_short - active_glue) - setfield(glue,"stretch",0) - if trace_lastlinefit then - report_parbuilders("applying last line fit, short %a, glue %p",active_short,active_glue) - end + -- if current_line ~= par.best_line then + -- report_parbuilders("line breaking") + -- end + par.head = nil -- needs checking + current_line = current_line - 1 + if trace_basic then + report_parbuilders("paragraph broken into %a lines",current_line) end + texnest[texnest.ptr].prevgraf = current_line end - -- we have a bunch of glue and and temp nodes not freed - local head = par.head - if getid(head) == temp_code then - par.head = getnext(head) - 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 but it doesn't save much (as we still need to keep indices then --- in next) - -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 + local function wrap_up(par) + if par.tracing_paragraphs then + diagnostics.stop() 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 + 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 + setwidth(glue,getwidth(glue) + active_short - active_glue) + setfield(glue,"stretch",0) + if trace_lastlinefit then + report_parbuilders("applying last line fit, short %a, glue %p",active_short,active_glue) + end 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 + -- we have a bunch of glue and and temp nodes not freed + local head = par.head + if getid(head) == temp_code then + par.head = getnext(head) + 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 but it doesn't save much (as we still need to keep indices then + -- in next) + + 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 - prev_r.next = r.next - -- removes r - -- r = nil end + return prev_r, r 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 + 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 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 + 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 - elseif adjustment < 0 then - local shrink = cur_active_width.shrink - if -adjustment > shrink then - adjustment = -shrink + 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 - 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 + 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 - else - return false, 0, fit_decent_class, 0, 0 - end -end - --- todo: statistics .. count tries and so - -local trialcount = 0 - -local function try_break(pi, break_type, par, first_p, current, checked_expansion) - --- trialcount = trialcount + 1 --- print(trialcount,pi,break_type,current,nuts.tostring(current)) - - if pi >= infinite_penalty then -- this breakpoint is inhibited by infinite penalty - local p_active = par.active - return p_active, p_active and p_active.next - elseif pi <= -infinite_penalty then -- this breakpoint will be forced - pi = eject_penalty - 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 current? - 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 adapt_width = par.adapt_width - - local parshape = par.par_shape_ptr - - 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 + 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 - 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 + return false, 0, fit_decent_class, 0, 0 + end + end + + -- todo: statistics .. count tries and so + + local trialcount = 0 + + local function try_break(pi, break_type, par, first_p, current, checked_expansion) + + -- trialcount = trialcount + 1 + -- print(trialcount,pi,break_type,current,nuts.tostring(current)) + + if pi >= infinite_penalty then -- this breakpoint is inhibited by infinite penalty + local p_active = par.active + return p_active, p_active and p_active.next + elseif pi <= -infinite_penalty then -- this breakpoint will be forced + pi = eject_penalty + 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 current? + 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 adapt_width = par.adapt_width + + local parshape = par.par_shape_ptr + + 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 current then + compute_break_width(par,break_type,current) + end end - if current then - compute_break_width(par,break_type,current) + 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 - 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 + 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 - 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 + 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 current + 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 = current, + 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,current) + end + end + minimal_demerits[fit_class] = awful_badness 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 current - 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 = current, - 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, + 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, } - 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_prev_r = prev_r prev_r = q - if tracing_paragraphs then - diagnostics.break_node(par,q,fit_class,break_type,current) - 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 r, r and r.next -- p_active, n_active - 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 + if r == par.active then + return r, r and r.next -- p_active, n_active + end + if line_number > par.easy_line then + old_line_number = max_halfword - 1 line_width = par.second_width - elseif parshape then - line_width = parshape[line_number][2] else - line_width = par.first_width + old_line_number = line_number + if line_number > par.last_special_line then + line_width = par.second_width + elseif parshape then + line_width = parshape[line_number][2] + else + line_width = par.first_width + end end - end - if adapt_width then - local l, r = adapt_width(par,line_number) - line_width = line_width - l - r - 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 = current and getprev(current) - if current and getid(current) == disc_code then - local pre, _, _, pretail = getdisc(current,true) - if pre then - o = pretail - else - o = find_protchar_right(l,o) + if adapt_width then + local l, r = adapt_width(par,line_number) + line_width = line_width - l - r end - else - o = find_protchar_right(l,o) end - if o and getid(o) == glyph_code then - pw, rp = right_pw(o) - shortfall = shortfall + pw - end - local id = getid(l) - if id == glyph_code then - -- ok ? - elseif id == disc_code and getfield(l,"post") then - l = getfield(l,"post") -- TODO: first char could be a disc + 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 - l = find_protchar_left(l) - end - if l and getid(l) == glyph_code then - pw, lp = left_pw(l) - shortfall = shortfall + pw + shortfall = shortfall - (r.break_node.passive_last_left_box_width or 0) end - end - if checked_expansion and shortfall ~= 0 then - local margin_kern_stretch = 0 - local margin_kern_shrink = 0 + local pw, lp, rp -- used later on if protrude_chars > 1 then - if lp then - local data = expansions[getfont(lp)][getchar(lp)] - if data then - margin_kern_stretch, margin_kern_shrink = data.glyphstretch, data.glyphshrink + -- this is quite time consuming + local b = r.break_node + local l = b and b.cur_break or first_p + local o = current and getprev(current) + if current and getid(current) == disc_code then + local pre, _, _, pretail = getdisc(current,true) + if pre then + o = pretail + else + o = find_protchar_right(l,o) end + else + o = find_protchar_right(l,o) end - if rp then - local data = expansions[getfont(lp)][getchar(lp)] - if data then - margin_kern_stretch = margin_kern_stretch + data.glyphstretch - margin_kern_shrink = margin_kern_shrink + data.glyphshrink - end + if o and getid(o) == glyph_code then + pw, rp = right_pw(o) + shortfall = shortfall + pw 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 + local id = getid(l) + if id == glyph_code then + -- ok ? + elseif id == disc_code and getfield(l,"post") then + l = getfield(l,"post") -- TODO: first char could be a disc else - shortfall = shortfall - total + l = find_protchar_left(l) 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 + if l and getid(l) == glyph_code then + pw, lp = left_pw(l) + shortfall = shortfall + pw end end - end - local b = 0 - local g = 0 - local fit_class = fit_decent_class - local found = false - if shortfall > 0 then - if cur_active_width.fi ~= 0 or cur_active_width.fil ~= 0 or cur_active_width.fill ~= 0 or cur_active_width.filll ~= 0 then - if not do_last_line_fit then - -- okay - elseif not current 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) + 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 + local char, font = isglyph(lp) + local data = expansions[font][char] + if data then + margin_kern_stretch, margin_kern_shrink = data.glyphstretch, data.glyphshrink + end + end + if rp then + local char, font = isglyph(rp) + local data = expansions[font][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 - shortfall = 0 + 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 - else - local stretch = cur_active_width.stretch - if shortfall > 7230584 and stretch < 1663497 then - b = infinite_badness - fit_class = fit_very_loose_class + 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 current 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 - b = calculate_badness(shortfall,stretch) - if b > 99 then + local stretch = cur_active_width.stretch + if shortfall > 7230584 and stretch < 1663497 then + b = infinite_badness fit_class = fit_very_loose_class - elseif b > 12 then - fit_class = fit_loose_class else - fit_class = fit_decent_class + 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 - 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 current 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 + 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 - 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 + if do_last_line_fit and not found then + if not current 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 - else - prev_r = r - if b > par.threshold then - continue_only = true + -- ::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 - 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 + prev_r = r + if b > par.threshold then + continue_only = true else - d = d * d + node_r_stays_active = true 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 current then - d = d + par.double_hyphen_demerits + 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 + par.final_hyphen_demerits + 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 current 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 - local delta = fit_class - r.subtype - if (delta >= 0 and delta or -delta) > 1 then -- abs(delta) - d = d + par.adj_demerits + if tracing_paragraphs then + diagnostics.feasible_break(par,current,r,b,pi,d,artificial_demerits) end - end - if tracing_paragraphs then - diagnostics.feasible_break(par,current,r,b,pi,d,artificial_demerits) - end - d = d + r.total_demerits -- this is the minimum total demerits from the beginning to current 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) + d = d + r.total_demerits -- this is the minimum total demerits from the beginning to current 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 d < par.minimum_demerits then - par.minimum_demerits = d + 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 - 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 - --- we can call the normal one for simple box building in the otr so we need --- frequent enabling/disabling -local dcolor = { [0] = "red", "green", "blue", "magenta", "cyan", "gray" } + -- we can call the normal one for simple box building in the otr so we need + -- frequent enabling/disabling -local temp_head = new_temp() + local temp_head = new_temp() -function constructors.methods.basic(head,d) - head = tonut(head) - - if trace_basic then - report_parbuilders("starting at %a",head) - end + 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 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 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() + local dirstack = new_dir_stack() - if tracing_paragraphs then - diagnostics.start() - if par.pretolerance >= 0 then - diagnostics.current_pass(par,"firstpass") + if tracing_paragraphs then + diagnostics.start() + if par.pretolerance >= 0 then + diagnostics.current_pass(par,"firstpass") + end 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 + 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 - par.passive = nil -- = 0 - par.printed_node = temp_head -- only when tracing, shared - par.pass_number = 0 --- par.auto_breaking = true + if checked_expansion then + active_width.adjust_stretch = 0 + active_width.adjust_shrink = 0 + end - setnext(temp_head,head) + par.passive = nil -- = 0 + par.printed_node = temp_head -- only when tracing, shared + par.pass_number = 0 + -- par.auto_breaking = true - local current = head - local first_p = current + setnext(temp_head,head) - local auto_breaking = true + local current = head + local first_p = current - par.font_in_short_display = 0 + local auto_breaking = true - if current then - local id = getid(current) - if id == localpar_code then - par.init_internal_left_box = getfield(current,"box_left") - par.init_internal_left_box_width = getfield(current,"box_left_width") - par.internal_pen_inter = getfield(current,"pen_inter") - par.internal_pen_broken = getfield(current,"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 = getfield(current,"box_right") - par.internal_right_box_width = getfield(current,"box_right_width") + par.font_in_short_display = 0 + + if current then + local id = getid(current) + if id == localpar_code then + par.init_internal_left_box = getfield(current,"box_left") + par.init_internal_left_box_width = getfield(current,"box_left_width") + par.internal_pen_inter = getfield(current,"pen_inter") + par.internal_pen_broken = getfield(current,"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 = getfield(current,"box_right") + par.internal_right_box_width = getfield(current,"box_right_width") + end end - 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 + -- 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 + -- split into normal and expansion loop - -- use an active local + -- use an active local - local fontexp, lastfont -- we can pass fontexp to calculate width if needed + local fontexp, lastfont -- we can pass fontexp to calculate width if needed - -- i flattened the inner loop over glyphs .. it looks nicer and the extra p_active ~= n_active - -- test is fast enough (and try_break now returns the updated values); the kern helper has been - -- inlined as it did a double check on id so in fact we had hardly any code to share + -- i flattened the inner loop over glyphs .. it looks nicer and the extra p_active ~= n_active + -- test is fast enough (and try_break now returns the updated values); the kern helper has been + -- inlined as it did a double check on id so in fact we had hardly any code to share - local p_active = par.active - local n_active = p_active and p_active.next - local second_pass = par.second_pass + local p_active = par.active + local n_active = p_active and p_active.next + local second_pass = par.second_pass - trialcount = 0 + trialcount = 0 - while current and p_active ~= n_active do - local char, id = isglyph(current) - if char then - local wd, ht, dp = getwhd(current) - if is_rotated[par.line_break_dir] then - active_width.size = active_width.size + ht + dp - else - active_width.size = active_width.size + wd - end - if checked_expansion then - local currentfont = getfont(current) - local data = checked_expansion[currentfont] - if data then - 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[char] - if expansion then - active_width.adjust_stretch = active_width.adjust_stretch + expansion.glyphstretch - active_width.adjust_shrink = active_width.adjust_shrink + expansion.glyphshrink + while current and p_active ~= n_active do + local char, id = isglyph(current) + if char then + local wd, ht, dp = getwhd(current) + if is_rotated(par.line_break_dir) then + active_width.size = active_width.size + ht + dp + else + active_width.size = active_width.size + wd + end + if checked_expansion then + local font = id -- == font + local data = checked_expansion[font] + if data then + if font ~= lastfont then + fontexps = checked_expansion[font] -- a bit redundant for the par line packer + lastfont = currentfont + end + if fontexps then + local expansion = fontexps[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 - end - elseif id == hlist_code or id == vlist_code then - local wd, ht, dp = getwhd(current) - if is_parallel[getdir(current)][par.line_break_dir] then - active_width.size = active_width.size + wd - else - active_width.size = active_width.size + ht + dp - end - elseif id == glue_code then --- if par.auto_breaking then - if auto_breaking then - local prev_p = getprev(current) - if prev_p and prev_p ~= temp_head then - local id = getid(prev_p) - -- we need to check this with the latest patches to the tex kernel - if (id == glyph_code) or (id < math_code) then - p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) - elseif id == kern_code then - local s = getsubtype(prev_p) - if s ~= userkern_code and s ~= italickern_code then + elseif id == hlist_code or id == vlist_code then + local wd, ht, dp = getwhd(current) + if textdir_parallel(getdirection(current),par.line_break_dir) then + active_width.size = active_width.size + wd + else + active_width.size = active_width.size + ht + dp + end + elseif id == glue_code then + -- if par.auto_breaking then + if auto_breaking then + local prev_p = getprev(current) + if prev_p and prev_p ~= temp_head then + local id = getid(prev_p) + -- we need to check this with the latest patches to the tex kernel + if (id == glyph_code) or (id < math_code) then p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) + elseif id == kern_code then + local s = getsubtype(prev_p) + if s ~= userkern_code and s ~= italickern_code then + p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) + end end end end - end - check_shrinkage(par,current) - local width, stretch, shrink, stretch_order = getglue(current) - local order = stretch_orders[stretch_order] - active_width.size = active_width.size + width - active_width[order] = active_width[order] + stretch - active_width.shrink = active_width.shrink + shrink - elseif id == disc_code then - local subtype = getsubtype(current) - if subtype ~= second_disc_code then - local line_break_dir = par.line_break_dir - if second_pass or subtype <= automatic_disc_code then - local actual_pen = subtype == automatic_disc_code and par.ex_hyphen_penalty or par.hyphen_penalty - -- 0.81 : - -- local actual_pen = getpenalty(current) - -- - local pre, post, replace = getdisc(current) - 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 - p_active, n_active = try_break(actual_pen, hyphenated_code, par, first_p, current, 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 + check_shrinkage(par,current) + local width, stretch, shrink, stretch_order = getglue(current) + local order = fillcodes[stretch_order] + active_width.size = active_width.size + width + active_width[order] = active_width[order] + stretch + active_width.shrink = active_width.shrink + shrink + elseif id == disc_code then + local subtype = getsubtype(current) + if subtype ~= seconddisc_code then + local line_break_dir = par.line_break_dir + if second_pass or subtype <= automaticdisc_code then + local actual_pen = subtype == automaticdisc_code and par.ex_hyphen_penalty or par.hyphen_penalty + -- 0.81 : + -- local actual_pen = getpenalty(current) + -- + local pre, post, replace = getdisc(current) + 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 + p_active, n_active = try_break(actual_pen, hyphenated_code, par, first_p, current, checked_expansion) else - -- disc_width.adjust_stretch = 0 - -- disc_width.adjust_shrink = 0 - end - p_active, n_active = try_break(actual_pen, hyphenated_code, par, first_p, current, checked_expansion) - if subtype == first_disc_code then - local cur_p_next = getnext(current) - if getid(cur_p_next) ~= disc_code or getsubtype(cur_p_next) ~= second_disc_code then - report_parbuilders("unsupported disc at location %a",1) + 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 - local pre = getfield(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 - p_active, n_active = 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(current)); - -- add_to_widths(s, line_break_dir, adjust_spacing,disc_width); - -- ext_try_break(...,first_p,vlink(current)); - -- + -- disc_width.adjust_stretch = 0 + -- disc_width.adjust_shrink = 0 + end + p_active, n_active = try_break(actual_pen, hyphenated_code, par, first_p, current, checked_expansion) + if subtype == firstdisc_code then + local cur_p_next = getnext(current) + if getid(cur_p_next) ~= disc_code or getsubtype(cur_p_next) ~= seconddisc_code then + report_parbuilders("unsupported disc at location %a",1) else - report_parbuilders("unsupported disc at location %a",2) + local pre = getfield(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 + p_active, n_active = 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(current)); + -- add_to_widths(s, line_break_dir, adjust_spacing,disc_width); + -- ext_try_break(...,first_p,vlink(current)); + -- + 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 - -- beware, we cannot restore to a saved value as the try_break adapts active_width - active_width.size = active_width.size - disc_width.size + end + 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 - disc_width.adjust_stretch - active_width.adjust_shrink = active_width.adjust_shrink - disc_width.adjust_shrink + active_width.adjust_stretch = active_width.adjust_stretch + adjust_stretch + active_width.adjust_shrink = active_width.adjust_shrink + adjust_shrink end end end - 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 + elseif id == kern_code then + local s = getsubtype(current) + if s == userkern_code or s == italickern_code then + local v = getnext(current) + -- if par.auto_breaking and getid(v) == glue_code then + if auto_breaking and getid(v) == glue_code then + p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) + end + local active_width = par.active_width + active_width.size = active_width.size + getkern(current) + else + local kern = getkern(current) + if kern ~= 0 then + active_width.size = active_width.size + kern + if checked_expansion and expand_kerns and getsubtype(current) == fontkern_code then + local stretch, shrink = kern_stretch_shrink(current,kern) + if expand_kerns == "stretch" then + active_width.adjust_stretch = active_width.adjust_stretch + stretch + elseif expand_kerns == "shrink" then + active_width.adjust_shrink = active_width.adjust_shrink + shrink + else + active_width.adjust_stretch = active_width.adjust_stretch + stretch + active_width.adjust_shrink = active_width.adjust_shrink + shrink + end + end end end - end - elseif id == kern_code then - local s = getsubtype(current) - if s == userkern_code or s == italickern_code then + elseif id == math_code then + -- par.auto_breaking = getsubtype(current) == endmath_code + auto_breaking = getsubtype(current) == endmath_code local v = getnext(current) - -- if par.auto_breaking and getid(v) == glue_code then + -- if par.auto_breaking and getid(v) == glue_code then if auto_breaking and getid(v) == glue_code then p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) end local active_width = par.active_width - active_width.size = active_width.size + getkern(current) - else - local kern = getkern(current) - if kern ~= 0 then - active_width.size = active_width.size + kern - if checked_expansion and expand_kerns and getsubtype(current) == fontkern_code then - local stretch, shrink = kern_stretch_shrink(current,kern) - if expand_kerns == "stretch" then - active_width.adjust_stretch = active_width.adjust_stretch + stretch - elseif expand_kerns == "shrink" then - active_width.adjust_shrink = active_width.adjust_shrink + shrink - else - active_width.adjust_stretch = active_width.adjust_stretch + stretch - active_width.adjust_shrink = active_width.adjust_shrink + shrink - end - end + active_width.size = active_width.size + getkern(current) -- surround + -- new in luatex + + getwidth(current) + elseif id == rule_code then + active_width.size = active_width.size + getwidth(current) + elseif id == penalty_code then + p_active, n_active = try_break(getpenalty(current), unhyphenated_code, par, first_p, current, checked_expansion) + elseif id == dir_code then + par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir + elseif id == localpar_code then + par.internal_pen_inter = getfield(current,"pen_inter") + par.internal_pen_broken = getfield(current,"pen_broken") + par.internal_left_box = getfield(current,"box_left") + par.internal_left_box_width = getfield(current,"box_left_width") + par.internal_right_box = getfield(current,"box_right") + par.internal_right_box_width = getfield(current,"box_right_width") + elseif trace_unsupported then + if 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 end - elseif id == math_code then --- par.auto_breaking = getsubtype(current) == endmath_code - auto_breaking = getsubtype(current) == endmath_code - local v = getnext(current) --- if par.auto_breaking and getid(v) == glue_code then - if auto_breaking and getid(v) == glue_code then - p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) - end - local active_width = par.active_width - active_width.size = active_width.size + getkern(current) -- surround - -- new in luatex - + getwidth(current) - elseif id == rule_code then - active_width.size = active_width.size + getwidth(current) - elseif id == penalty_code then - p_active, n_active = try_break(getpenalty(current), unhyphenated_code, par, first_p, current, checked_expansion) - elseif id == dir_code then - par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir - elseif id == localpar_code then - par.internal_pen_inter = getfield(current,"pen_inter") - par.internal_pen_broken = getfield(current,"pen_broken") - par.internal_left_box = getfield(current,"box_left") - par.internal_left_box_width = getfield(current,"box_left_width") - par.internal_right_box = getfield(current,"box_right") - par.internal_right_box_width = getfield(current,"box_right_width") - elseif trace_unsupported then - if 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 + current = getnext(current) end - current = getnext(current) - end - if not current then - local p_active, n_active = try_break(eject_penalty, hyphenated_code, par, first_p, current, checked_expansion) - 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 tonode(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 + if not current then + local p_active, n_active = try_break(eject_penalty, hyphenated_code, par, first_p, current, checked_expansion) + 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 - elseif line_diff == actual_looseness and r.total_demerits < par.fewest_demerits then par.best_bet = r - par.fewest_demerits = r.total_demerits 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 + par.best_line = par.best_bet.line_number + if actual_looseness == asked_looseness or par.final_pass then + return wrap_up(par) end - r = r.next - until r == p_active - par.best_line = par.best_bet.line_number - if actual_looseness == asked_looseness or par.final_pass then - return tonode(wrap_up(par)) end end - end - reset_meta(par) -- clean up the memory by removing the break nodes - if not 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") + reset_meta(par) -- clean up the memory by removing the break nodes + if not 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 - par.background.stretch = par.background.stretch + par.emergency_stretch - par.final_pass = true end + return wrap_up(par) end - return tonode(wrap_up(par)) + end -- standard tex logging .. will be adapted .. @@ -2531,16 +2572,19 @@ do while a do local char, id = isglyph(a) if char then - local font = getfont(a) - if font ~= font_in_short_display then - write(target,tex.fontidentifier(font) .. ' ') - font_in_short_display = font + -- id == font + if id ~= font_in_short_display then + write(target,tex.fontidentifier(id) .. ' ') + font_in_short_display = id end - -- todo: instead of components the split tounicode string - if getsubtype(a) == ligature_code then - font_in_short_display = short_display(target,getcomponents(a),font_in_short_display) + local u = chardata[id][char] + local u = u.unicode or char + if type(u) == "table" then + for i=1,#u do + write(target,utfchar(u[i])) + end else - write(target,utfchar(char)) + write(target,utfchar(u)) end elseif id == disc_code then local pre, post, replace = getdisc(a) @@ -2713,55 +2757,6 @@ do local setnodecolor = nodes.tracers.colors.set - local function glyph_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else - local half = wd / 2 - return ht + dp, half, half - end - elseif is_rotated[pdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else - return ht + dp, wd, 0 -- weird - end - else - if glyphdir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- can this happen? - return ht + dp, wd, 0 - end - end - end - - local function pack_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else -- can this happen? - local half = wd / 2 - return ht + dp, half, half - end - else - if pardir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- weird dimensions, can this happen? - return ht + dp, wd, 0 - end - end - end - -- local function xpack(head,width,method,direction,analysis) -- -- -- inspect(analysis) @@ -2776,7 +2771,7 @@ do -- local hlist = new_hlist() -- -- setlist(hlist,head) - -- setdir(hlist,direction or tex.textdir) + -- setdirection(hlist,direction or tex.textdirection) -- setwhd(hlist,width,height,depth) -- -- if delta == 0 then @@ -2889,7 +2884,7 @@ do local hlist = new_hlist() - setdir(hlist,direction) + setdirection(hlist,direction) if head == nil then setwidth(hlist,width) @@ -2942,10 +2937,10 @@ do local char, id = isglyph(current) if char then if cal_expand_ratio then - local currentfont = getfont(current) - if currentfont ~= lastfont then - fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer - lastfont = currentfont + local font = id -- == font + if font ~= lastfont then + fontexps = checked_expansion[font] -- a bit redundant for the par line packer + lastfont = font end if fontexps then local expansion = fontexps[char] @@ -2958,7 +2953,7 @@ do end end -- use inline - local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ? + local wd, ht, dp = getwhd(current) natural = natural + wd if ht > height then height = ht @@ -2984,7 +2979,7 @@ do end elseif id == disc_code then local subtype = getsubtype(current) - if subtype ~= second_disc_code then + if subtype ~= seconddisc_code then -- todo : local stretch, shrink = char_stretch_shrink(s) local replace = getfield(current,"replace") if replace then @@ -3008,7 +3003,7 @@ do end elseif id == hlist_code or id == vlist_code then local sh = getshift(current) - local wd, ht, dp = pack_width_height_depth(hpack_dir,getdir(current) or hpack_dir,current) -- added: or pack_dir + local wd, ht, dp = getwhd(current) local hs, ds = ht - sh, dp + sh natural = natural + wd if hs > height then @@ -3114,14 +3109,13 @@ do local fontexps, lastfont for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) + local g = expansion_stack[i] + local e = 0 + local char, font = isglyph(g) if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont + if font ~= lastfont then + fontexps = expansions[font] + lastfont = font end local data = fontexps[char] if trace_expansion then @@ -3133,7 +3127,7 @@ do local stretch, shrink = kern_stretch_shrink(g,kern) e = font_expand_ratio * stretch / 1000 end - setfield(g,"expansion_factor",e) + setexpansion(g,e) end end local tso = total_stretch[order] @@ -3171,14 +3165,13 @@ do local fontexps, lastfont for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) + local g = expansion_stack[i] + local e = 0 + local char, font = isglyph(g) if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont + if font ~= lastfont then + fontexps = expansions[font] + lastfont = font end local data = fontexps[char] if trace_expansion then @@ -3190,7 +3183,7 @@ do local stretch, shrink = kern_stretch_shrink(g,kern) e = font_expand_ratio * shrink / 1000 end - setfield(g,"expansion_factor",e) + setexpansion(g,e) end end local tso = total_shrink[order] @@ -3214,7 +3207,7 @@ do local overfullrule = tex.overfullrule if fuzz > hfuzz and overfullrule > 0 then -- weird, is always called and no rules shows up - setnext(slide_node_list(list),new_rule(overfullrule,nil,nil,getdir(hlist))) -- todo: find_tail + setnext(slide_node_list(list),new_rule(overfullrule,nil,nil,getdirection(hlist))) -- todo: find_tail end diagnostics.overfull_hbox(hlist,line,-delta) end |