diff options
author | Marius <mariausol@gmail.com> | 2012-07-17 13:16:14 +0300 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2012-07-17 13:16:14 +0300 |
commit | c30a841cef093918b475e0ea95ecf9fc9f30697d (patch) | |
tree | 861e4f6cf85f9ad0b0abe5b501a0bac21a6f63ab /tex/context/base/font-sol.lua | |
parent | a13773bf241efe852de82ad42770e2abcc3ddf54 (diff) | |
download | context-c30a841cef093918b475e0ea95ecf9fc9f30697d.tar.gz |
beta 2012.07.17 00:23
Diffstat (limited to 'tex/context/base/font-sol.lua')
-rw-r--r-- | tex/context/base/font-sol.lua | 283 |
1 files changed, 168 insertions, 115 deletions
diff --git a/tex/context/base/font-sol.lua b/tex/context/base/font-sol.lua index 861331785..e97e627b4 100644 --- a/tex/context/base/font-sol.lua +++ b/tex/context/base/font-sol.lua @@ -41,6 +41,7 @@ local v_normal = variables.normal local v_reverse = variables.reverse local v_preroll = variables.preroll local v_random = variables.random +local v_split = variables.split local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash @@ -108,7 +109,8 @@ local preroll = true local criterium = 0 local randomseed = nil local optimize = nil -- set later -local variant = "normal" +local variant = v_normal +local splitwords = true local cache = { } local variants = { } @@ -125,23 +127,29 @@ local dummy = { criterium = 0, preroll = false, optimize = nil, - variant = "normal", + splitwords = false, + variant = v_normal, } local function checksettings(r,settings) local s = r.settings local method = settings_to_hash(settings.method or "") - local optimize + local optimize, preroll, splitwords for k, v in next, method do - if variants[k] then + if k == v_preroll then + preroll = true + elseif k == v_split then + splitwords = true + elseif variants[k] then variant = k - optimize = variants[k] -- last? + optimize = variants[k] -- last one wins end end r.randomseed = tonumber(settings.randomseed) or s.randomseed or r.randomseed or 0 r.criterium = tonumber(settings.criterium ) or s.criterium or r.criterium or 0 - r.preroll = method[v_preroll] and true or false - r.optimize = optimize or s.optimize or r.optimize + r.preroll = preroll or false + r.splitwords = splitwords or false + r.optimize = optimize or s.optimize or r.optimize or variants[v_normal] end local function pushsplitter(name,settings) @@ -159,6 +167,7 @@ local function pushsplitter(name,settings) criterium = r.criterium or 0 preroll = r.preroll or false optimize = r.optimize or nil + splitwords = r.splitwords or nil -- texsetattribute(a_split,r.attribute) return #stack @@ -327,22 +336,33 @@ function splitters.split(head) if m > max_more then max_more = m end start, stop, done = nil, nil, true end - while current do + while current do -- also nextid + local next = current.next local id = current.id - if id == glyph_code and current.subtype < 256 then - local a = has_attribute(current,a_split) - if not a then - start, stop = nil, nil - elseif not start then - start, stop, attribute = current, current, a - elseif a ~= attribute then - start, stop = nil, nil - else - stop = current + if id == glyph_code then + if current.subtype < 256 then + local a = has_attribute(current,a_split) + if not a then + start, stop = nil, nil + elseif not start then + start, stop, attribute = current, current, a + elseif a ~= attribute then + start, stop = nil, nil + else + stop = current + end end - current = current.next elseif id == disc_code then - start, stop, current = nil, nil, current.next + if splitwords then + if start then + flush() + end + elseif start and next and next.id == glyph_code and next.subtype < 256 then + -- beware: we can cross future lines + stop = next + else + start, stop = nil, nil + end elseif id == whatsit_code then if start then flush() @@ -351,13 +371,12 @@ function splitters.split(head) if subtype == dir_code or subtype == localpar_code then rlmode = current.dir end - current = current.next else if start then flush() end - current = current.next end + current = next end if start then flush() @@ -370,14 +389,18 @@ end local function collect_words(list) local words, w, word = { }, 0, nil for current in traverse_ids(whatsit_code,list) do - if current.subtype == userdefined_code then + if current.subtype == userdefined_code then -- hm local user_id = current.user_id if user_id == splitter_one then word = { current.value, current, current } w = w + 1 words[w] = word elseif user_id == splitter_two then - word[3] = current + if word then + word[3] = current + else + -- something is wrong + end end end end @@ -386,11 +409,36 @@ end -- we could avoid a hpack but hpack is not that slow + + local function doit(word,list,best,width,badness,line,set,listdir) local changed = 0 local n = word[1] local found = cache[n] if found then + + local h = word[2].next -- head of current word + local t = word[3].prev -- tail of current word + + if splitwords then + -- there are no lines crossed in a word + else + local ok = false + local c = h + while c do + if c == t then + ok = true + break + else + c = c.next + end + end + if not ok then + report_solutions("skipping hyphenated word (for now)") + return false, changed + end + end + local original, attribute, direction = found.original, found.attribute, found.direction local solution = solutions[attribute] local features = solution and solution[set] @@ -436,8 +484,8 @@ local function doit(word,list,best,width,badness,line,set,listdir) report_solutions("fatal error, no dynamics for font %s",font) end first = inject_kerns(first) - local h = word[2].next -- head of current word - local t = word[3].prev -- tail of current word +-- local h = word[2].next -- head of current word +-- local t = word[3].prev -- tail of current word if first.id == whatsit_code then local temp = first first = first.next @@ -555,112 +603,117 @@ local function show_quality(current,what,line) end function splitters.optimize(head) + if not optimize then + report_optimizers("no optimizer set") + return + end local nc = #cache - if nc > 0 then - starttiming(splitters) - local listdir = nil -- todo ! ! ! - if randomseed then - math.setrandomseedi(randomseed) - randomseed = nil - end - local line = 0 - local tex_hbadness, tex_hfuzz = tex.hbadness, tex.hfuzz - tex.hbadness, tex.hfuzz = 10000, number.maxdimen - if trace_optimize then - report_optimizers("preroll: %s, variant: %s, preroll criterium: %s, cache size: %s", - tostring(preroll),variant,criterium,nc) - end - for current in traverse_ids(hlist_code,head) do - -- report_splitters("before: [%s] => %s",current.dir,nodes.tosequence(current.list,nil)) - line = line + 1 - local sign, dir, list, width = current.glue_sign, current.dir, current.list, current.width - local temp, badness = repack_hlist(list,width,'exactly',dir) -- it would be nice if the badness was stored in the node - if badness > 0 then - if sign == 0 then + if nc == 0 then + return + end + starttiming(splitters) + local listdir = nil -- todo ! ! ! + if randomseed then + math.setrandomseedi(randomseed) + randomseed = nil + end + local line = 0 + local tex_hbadness, tex_hfuzz = tex.hbadness, tex.hfuzz + tex.hbadness, tex.hfuzz = 10000, number.maxdimen + if trace_optimize then + report_optimizers("preroll: %s, variant: %s, preroll criterium: %s, cache size: %s", + tostring(preroll),variant,criterium,nc) + end + for current in traverse_ids(hlist_code,head) do + -- report_splitters("before: [%s] => %s",current.dir,nodes.tosequence(current.list,nil)) + line = line + 1 + local sign, dir, list, width = current.glue_sign, current.dir, current.list, current.width + local temp, badness = repack_hlist(list,width,'exactly',dir) -- it would be nice if the badness was stored in the node + if badness > 0 then + if sign == 0 then + if trace_optimize then + report_optimizers("line %s, badness %s, okay",line,badness) + end + else + local set, max + if sign == 1 then if trace_optimize then - report_optimizers("line %s, badness %s, okay",line,badness) + report_optimizers("line %s, badness %s, underfull, trying more",line,badness) end + set, max = "more", max_more else - local set, max - if sign == 1 then - if trace_optimize then - report_optimizers("line %s, badness %s, underfull, trying more",line,badness) - end - set, max = "more", max_more - else - if trace_optimize then - report_optimizers("line %s, badness %s, overfull, trying less",line,badness) - end - set, max = "less", max_less + if trace_optimize then + report_optimizers("line %s, badness %s, overfull, trying less",line,badness) end - -- we can keep the best variants - local lastbest, lastbadness = nil, badness - if preroll then - local bb, base - for i=1,max do - if base then - free_nodelist(base) - end - base = copy_nodelist(list) - local words = collect_words(base) -- beware: words is adapted - for j=i,max do - local temp, done, changes, b = optimize(words,base,j,width,badness,line,set,dir) - base = temp - if trace_optimize then - report_optimizers("line %s, alternative: %s.%s, changes: %s, badness %s",line,i,j,changes,b) - end - bb = b - if b <= criterium then - break - end - -- if done then - -- break - -- end + set, max = "less", max_less + end + -- we can keep the best variants + local lastbest, lastbadness = nil, badness + if preroll then + local bb, base + for i=1,max do + if base then + free_nodelist(base) + end + base = copy_nodelist(list) + local words = collect_words(base) -- beware: words is adapted + for j=i,max do + local temp, done, changes, b = optimize(words,base,j,width,badness,line,set,dir) + base = temp + if trace_optimize then + report_optimizers("line %s, alternative: %s.%s, changes: %s, badness %s",line,i,j,changes,b) end - if bb and bb > criterium then -- needs checking - if not lastbest then - lastbest, lastbadness = i, bb - elseif bb > lastbadness then - lastbest, lastbadness = i, bb - end - else + bb = b + if b <= criterium then break end + -- if done then + -- break + -- end end - free_nodelist(base) - end - local words = collect_words(list) - for best=lastbest or 1,max do - local temp, done, changes, b = optimize(words,list,best,width,badness,line,set,dir) - current.list = temp - if trace_optimize then - report_optimizers("line %s, alternative: %s, changes: %s, badness %s",line,best,changes,b) - end - if done then - if b <= criterium then -- was == 0 - protect_glyphs(list) - break + if bb and bb > criterium then -- needs checking + if not lastbest then + lastbest, lastbadness = i, bb + elseif bb > lastbadness then + lastbest, lastbadness = i, bb end + else + break end end + free_nodelist(base) end - else - if trace_optimize then - report_optimizers("line %s, not bad enough",line) + local words = collect_words(list) + for best=lastbest or 1,max do + local temp, done, changes, b = optimize(words,list,best,width,badness,line,set,dir) + current.list = temp + if trace_optimize then + report_optimizers("line %s, alternative: %s, changes: %s, badness %s",line,best,changes,b) + end + if done then + if b <= criterium then -- was == 0 + protect_glyphs(list) + break + end + end end end - -- we pack inside the outer hpack and that way keep the original wd/ht/dp as bonus - current.list = hpack_nodes(current.list,width,'exactly',listdir) - -- report_splitters("after: [%s] => %s",temp.dir,nodes.tosequence(temp.list,nil)) - end - for i=1,nc do - local ci = cache[i] - free_nodelist(ci.original) + else + if trace_optimize then + report_optimizers("line %s, not bad enough",line) + end end - cache = { } - tex.hbadness, tex.hfuzz = tex_hbadness, tex_hfuzz - stoptiming(splitters) + -- we pack inside the outer hpack and that way keep the original wd/ht/dp as bonus + current.list = hpack_nodes(current.list,width,'exactly',listdir) + -- report_splitters("after: [%s] => %s",temp.dir,nodes.tosequence(temp.list,nil)) + end + for i=1,nc do + local ci = cache[i] + free_nodelist(ci.original) end + cache = { } + tex.hbadness, tex.hfuzz = tex_hbadness, tex_hfuzz + stoptiming(splitters) end statistics.register("optimizer statistics", function() |