diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-ots.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-ots.lua | 374 |
1 files changed, 207 insertions, 167 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua index f20a349eeb2..880bcb6d50a 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua @@ -1,5 +1,6 @@ if not modules then modules = { } end modules ['font-ots'] = { -- sequences version = 1.001, + optimize = true, comment = "companion to font-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -12,7 +13,7 @@ with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/> and discussion about improvements and functionality mostly happens on the <l n='context'/> mailing list.</p> -<p>The specification of OpenType is (or at least a decade ago was) kind of vague. +<p>The specification of OpenType is (or at least decades ago was) kind of vague. Apart from a lack of a proper free specifications there's also the problem that Microsoft and Adobe may have their own interpretation of how and in what order to apply features. In general the Microsoft website has more detailed specifications @@ -25,7 +26,7 @@ effect that suddenly fonts behave differently. We don't want to catch all font issues.</p> <p>After a lot of experiments (mostly by Taco, me and Idris) the first implementation -becaus quite useful. When it did most of what we wanted, a more optimized version +was already quite useful. When it did most of what we wanted, a more optimized version evolved. Of course all errors are mine and of course the code can be improved. There are quite some optimizations going on here and processing speed is currently quite acceptable and has been improved over time. Many complex scripts are not yet supported @@ -217,6 +218,7 @@ local copy_only_glyphs = nuts.copy_only_glyphs local count_components = nuts.count_components local set_components = nuts.set_components local get_components = nuts.get_components +local flush_components = nuts.flush_components --------------------------------------------------------------------------------------- @@ -250,7 +252,10 @@ local glue_code = nodecodes.glue local disc_code = nodecodes.disc local math_code = nodecodes.math local dir_code = nodecodes.dir -local localpar_code = nodecodes.localpar +local par_code = nodecodes.par + +local lefttoright_code = nodes.dirvalues.lefttoright +local righttoleft_code = nodes.dirvalues.righttoleft local discretionarydisc_code = disccodes.discretionary local ligatureglyph_code = glyphcodes.ligature @@ -484,6 +489,7 @@ local function markstoligature(head,start,stop,char) setsubtype(base,ligatureglyph_code) set_components(base,start) setlink(prev,base,next) + flush_components(start) return head, base end end @@ -496,9 +502,25 @@ end -- in the not discfound branch then. We now have skiphash too so we can be more -- selective if needed (todo). +-- we can have more granularity here but for now we only do a simple check + +local no_left_ligature_code = 1 +local no_right_ligature_code = 2 +local no_left_kern_code = 4 +local no_right_kern_code = 8 + +local has_glyph_option = node.direct.has_glyph_option or function(n,c) + if c == no_left_ligature_code or c == no_right_ligature_code then + return getattr(n,a_noligature) == 1 + else + return false + end +end + +-- in lmtx we need to check the components and can be slightly more clever + local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) -- brr head - if getattr(start,a_noligature) == 1 then - -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) + if has_glyph_option(start,no_right_ligature_code) then return head, start end if start == stop and getchar(start) == char then @@ -533,19 +555,19 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou if not marks[char] then baseindex = baseindex + componentindex componentindex = count_components(start,marks) - -- we can be more clever here: "not deletemarks or (skiphash and not skiphash[char])" - -- and such: + -- we can be more clever here: "not deletemarks or (skiphash and not skiphash[char])" + -- and such: elseif not deletemarks then -- we can get a loop when the font expects otherwise (i.e. unexpected deletemarks) setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) + logwarning("%s: keep ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) end local n = copy_node(start) copyinjection(n,start) -- is this ok ? we position later anyway head, current = insert_node_after(head,current,n) -- unlikely that mark has components elseif trace_marks then - logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char)) + logwarning("%s: delete ligature mark %s",pref(dataset,sequence),gref(char)) end start = getnext(start) end @@ -558,7 +580,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou if marks[char] then setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then - logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) + logwarning("%s: set ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) end start = getnext(start) else @@ -568,6 +590,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou break end end + flush_components(components) else -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks local discprev, discnext = getboth(discfound) @@ -806,6 +829,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip -- of{f-}{}{f}e o{f-}{}{f}fe o{-}{}{ff}e (oe and ff ligature) -- we can end up here when we have a start run .. testruns start at a disc but -- so here we have the other case: char + disc + -- + -- Challenge for Kai (latinmodern): \hyphenation{fii-f-f-iif} fiiffiif + -- if discfound then -- don't assume marks in a disc and we don't run over a disc (for now) local pre, post, replace = getdisc(discfound) @@ -898,81 +924,89 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local startchar = getchar(start) - local format = step.format - if format == "single" or type(kerns) == "table" then -- the table check can go - local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end + if has_glyph_option(start,no_right_kern_code) then + return head, start, false else - local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + local startchar = getchar(start) + local format = step.format + if format == "single" or type(kerns) == "table" then -- the table check can go + local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + end end + return head, start, true end - return head, start, true end function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local snext = getnext(start) - if not snext then + if has_glyph_option(start,no_right_kern_code) then return head, start, false else - local prev = start - while snext do - local nextchar = ischar(snext,currentfont) - if nextchar then - if skiphash and skiphash[nextchar] then -- includes marks too when flag - prev = snext - snext = getnext(snext) - else - local krn = kerns[nextchar] - if not krn then - break - end - local format = step.format - if format == "pair" then - local a = krn[1] - local b = krn[2] - if a == true then - -- zero - elseif a then -- #a > 0 - local x, y, w, h = setposition(1,start,factor,rlmode,a,injection) - if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") - end + local snext = getnext(start) + if not snext then + return head, start, false + else + local prev = start + while snext do + local nextchar = ischar(snext,currentfont) + if nextchar then + if skiphash and skiphash[nextchar] then -- includes marks too when flag + prev = snext + snext = getnext(snext) + else + local krn = kerns[nextchar] + if not krn then + break end - if b == true then - -- zero - start = snext -- cf spec - elseif b then -- #b > 0 - local x, y, w, h = setposition(2,snext,factor,rlmode,b,injection) + local format = step.format + if format == "pair" then + local a = krn[1] + local b = krn[2] + if a == true then + -- zero + elseif a then -- #a > 0 + local x, y, w, h = setposition(1,start,factor,rlmode,a,injection) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + end + if b == true then + -- zero + start = snext -- cf spec + elseif b then -- #b > 0 + local x, y, w, h = setposition(2,snext,factor,rlmode,b,injection) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + start = snext -- cf spec + elseif forcepairadvance then + start = snext -- for testing, not cf spec + end + return head, start, true + elseif krn ~= 0 then + local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn,injection) if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - start = snext -- cf spec - elseif forcepairadvance then - start = snext -- for testing, not cf spec - end - return head, start, true - elseif krn ~= 0 then - local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn,injection) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") + return head, start, true + else -- can't happen + break end - return head, start, true - else -- can't happen - break end + else + break end - else - break end + return head, start, false end - return head, start, false end end @@ -1501,92 +1535,98 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup end function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping = currentlookup.mapping - if mapping == nil then - mapping = getmapping(dataset,sequence,currentlookup) - end - if mapping then - local startchar = getchar(start) - local kerns = mapping[startchar] - if kerns then - local format = currentlookup.format - if format == "single" then - local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns) -- currentlookup.flags ? - if trace_kerns then - logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end - else -- needs checking .. maybe no kerns format for single - local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + -- we actually should check no_left_kern_code with next + if not has_glyph_option(start,no_right_kern_code) then + local mapping = currentlookup.mapping + if mapping == nil then + mapping = getmapping(dataset,sequence,currentlookup) + end + if mapping then + local startchar = getchar(start) + local kerns = mapping[startchar] + if kerns then + local format = currentlookup.format + if format == "single" then + local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns) -- currentlookup.flags ? + if trace_kerns then + logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else -- needs checking .. maybe no kerns format for single + local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + end end + return head, start, true end - return head, start, true end end return head, start, false end function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) -- todo: injections ? - local mapping = currentlookup.mapping - if mapping == nil then - mapping = getmapping(dataset,sequence,currentlookup) - end - if mapping then - local snext = getnext(start) - if snext then - local startchar = getchar(start) - local kerns = mapping[startchar] -- always 1 step - if kerns then - local prev = start - while snext do - local nextchar = ischar(snext,currentfont) - if not nextchar then - break - end - if skiphash and skiphash[nextchar] then - prev = snext - snext = getnext(snext) - else - local krn = kerns[nextchar] - if not krn then + -- we actually should check no_left_kern_code with next + if not has_glyph_option(start,no_right_kern_code) then + local mapping = currentlookup.mapping + if mapping == nil then + mapping = getmapping(dataset,sequence,currentlookup) + end + if mapping then + local snext = getnext(start) + if snext then + local startchar = getchar(start) + local kerns = mapping[startchar] -- always 1 step + if kerns then + local prev = start + while snext do + local nextchar = ischar(snext,currentfont) + if not nextchar then break end - local format = currentlookup.format - if format == "pair" then - local a = krn[1] - local b = krn[2] - if a == true then - -- zero - elseif a then - local x, y, w, h = setposition(1,start,factor,rlmode,a,"injections") -- currentlookups flags? - if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) - end + if skiphash and skiphash[nextchar] then + prev = snext + snext = getnext(snext) + else + local krn = kerns[nextchar] + if not krn then + break end - if b == true then - -- zero - start = snext -- cf spec - elseif b then -- #b > 0 - local x, y, w, h = setposition(2,snext,factor,rlmode,b,"injections") + local format = currentlookup.format + if format == "pair" then + local a = krn[1] + local b = krn[2] + if a == true then + -- zero + elseif a then + local x, y, w, h = setposition(1,start,factor,rlmode,a,"injections") -- currentlookups flags? + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b == true then + -- zero + start = snext -- cf spec + elseif b then -- #b > 0 + local x, y, w, h = setposition(2,snext,factor,rlmode,b,"injections") + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + start = snext -- cf spec + elseif forcepairadvance then + start = snext -- for testing, not cf spec + end + return head, start, true + elseif krn ~= 0 then + local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn) if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) end - start = snext -- cf spec - elseif forcepairadvance then - start = snext -- for testing, not cf spec - end - return head, start, true - elseif krn ~= 0 then - local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) + return head, start, true + else + break end - return head, start, true - else - break end end end @@ -2056,6 +2096,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) local sweepnode = sweepnode local sweeptype = sweeptype local sweepoverflow = false + local checkdisc = getprev(head) local keepdisc = not sweepnode local lookaheaddisc = nil local backtrackdisc = nil @@ -2089,6 +2130,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) sweepnode = current current = getnext(current) else + -- we can use an iterator while replace and i <= l do if getid(replace) == glyph_code then i = i + 1 @@ -2189,7 +2231,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) local current = prev local i = f local t = sweeptype == "pre" or sweeptype == "replace" - if not current and t and current == checkdisk then + if not current and t and current == checkdisc then current = getprev(sweepnode) end while current and i > 1 do -- missing getprev added / moved outside @@ -2218,7 +2260,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) end end current = getprev(current) - if t and current == checkdisk then + if t and current == checkdisc then current = getprev(sweepnode) end end @@ -2443,6 +2485,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s local current = start local last = start + if s == 1 then + goto next + end + -- current match if l > f then @@ -2512,10 +2558,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s break end end - -- commented, for Kai to check - -- if n <= l then - -- notmatchpre[last] = true - -- end + if n <= l then + notmatchpre[last] = true + end else notmatchpre[last] = true end @@ -3287,6 +3332,7 @@ local nesting = 0 local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) local done = false local sweep = sweephead[head] + local start if sweep then start = sweep -- sweephead[head] = nil @@ -3448,6 +3494,7 @@ end local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) local done = false local sweep = sweephead[head] + local start if sweep then start = sweep -- sweephead[head] = nil @@ -3618,8 +3665,6 @@ end local txtdirstate, pardirstate do -- this might change (no need for nxt in pardirstate) local getdirection = nuts.getdirection - local lefttoright = 0 - local righttoleft = 1 txtdirstate = function(start,stack,top,rlparmode) local dir, pop = getdirection(start) @@ -3628,19 +3673,19 @@ local txtdirstate, pardirstate do -- this might change (no need for nxt in pard return 0, rlparmode else top = top - 1 - if stack[top] == righttoleft then + if stack[top] == righttoleft_code then return top, -1 else return top, 1 end end - elseif dir == lefttoright then + elseif dir == lefttoright_code then top = top + 1 - stack[top] = lefttoright + stack[top] = lefttoright_code return top, 1 - elseif dir == righttoleft then + elseif dir == righttoleft_code then top = top + 1 - stack[top] = righttoleft + stack[top] = righttoleft_code return top, -1 else return top, rlparmode @@ -3649,14 +3694,9 @@ local txtdirstate, pardirstate do -- this might change (no need for nxt in pard pardirstate = function(start) local dir = getdirection(start) - if dir == lefttoright then - return 1, 1 - elseif dir == righttoleft then - return -1, -1 - -- for old times sake we we handle strings too - elseif dir == "TLT" then + if dir == lefttoright_code then return 1, 1 - elseif dir == "TRT" then + elseif dir == righttoleft_code then return -1, -1 else return 0, 0 @@ -3755,9 +3795,9 @@ do local initialrl = 0 - if getid(head) == localpar_code and start_of_par(head) then + if getid(head) == par_code and start_of_par(head) then initialrl = pardirstate(head) - elseif direction == 1 or direction == "TRT" then + elseif direction == righttoleft_code then initialrl = -1 end @@ -3909,7 +3949,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else @@ -3993,7 +4033,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else @@ -4052,7 +4092,7 @@ do local done = false local dirstack = { nil } -- could move outside function but we can have local runs (maybe a few more nils) local start = head - local initialrl = (direction == 1 or direction == "TRT") and -1 or 0 + local initialrl = (direction == righttoleft_code) and -1 or 0 local rlmode = initialrl local rlparmode = initialrl local topstack = 0 @@ -4104,7 +4144,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else |