diff options
| author | Marius <mariausol@gmail.com> | 2013-10-05 00:40:31 +0300 | 
|---|---|---|
| committer | Marius <mariausol@gmail.com> | 2013-10-05 00:40:31 +0300 | 
| commit | 3b2e97139b40df9c0308de41fb619cfad7dc6f18 (patch) | |
| tree | f85782e0609559dbe29232b51a15612b2a8e58ec /tex | |
| parent | a90bcf0dcd9265b64b65b1f874b39f4c75553137 (diff) | |
| download | context-3b2e97139b40df9c0308de41fb619cfad7dc6f18.tar.gz | |
beta 2013.10.04 23:41
Diffstat (limited to 'tex')
29 files changed, 1102 insertions, 447 deletions
diff --git a/tex/context/base/chem-str.mkiv b/tex/context/base/chem-str.mkiv index 9c31a3c14..d9ec1842b 100644 --- a/tex/context/base/chem-str.mkiv +++ b/tex/context/base/chem-str.mkiv @@ -317,16 +317,21 @@  % special macros (probably needs some more work) -\let\chem_box_visual\ruledhbox -\let\chem_box_visual\hbox -\let\chem_box_normal\hbox +\let\chem_box_normal_yes\hbox +\let\chem_box_visual_yes\hbox +\let\chem_box_visual_nop\relax + +\installtextracker +  {chemistry.boxes} +  {\let\chem_box_visual_yes\ruledhbox \let\chem_box_visual_nop\ruledhbox} +  {\let\chem_box_visual_yes\hbox      \let\chem_box_visual_nop\relax    }  \def\chem_top_construct#1#2#3#4%    {\hbox\bgroup     \setstrut -   \setbox\scratchboxone\chem_box_visual{\strut#3}% -   \setbox\scratchboxtwo\chem_box_visual{\strut\molecule{#4}}% -   \setbox\scratchboxone\chem_box_normal{\raise\dimexpr\dp\scratchboxone+\ht\scratchboxtwo\relax\hbox to \wd\scratchboxtwo{#1\box\scratchboxone#2}}% +   \setbox\scratchboxone\chem_box_visual_yes{\strut#3}% +   \setbox\scratchboxtwo\chem_box_visual_yes{\strut\molecule{#4}}% +   \setbox\scratchboxone\chem_box_normal_yes{\raise\dimexpr\dp\scratchboxone+\ht\scratchboxtwo\relax\hbox to \wd\scratchboxtwo{#1\box\scratchboxone#2}}%     \smashbox\scratchboxone     \box\scratchboxone     \box\scratchboxtwo @@ -335,9 +340,9 @@  \def\chem_bottom_construct#1#2#3#4%    {\hbox\bgroup     \setstrut -   \setbox\scratchboxone\chem_box_visual{\strut#3}% -   \setbox\scratchboxtwo\chem_box_visual{\strut\molecule{#4}}% -   \setbox\scratchboxone\chem_box_normal{\lower\dimexpr\dp\scratchboxtwo+\ht\scratchboxone\relax\hbox to \wd\scratchboxtwo{#1\box\scratchboxone#2}}% +   \setbox\scratchboxone\chem_box_visual_yes{\strut#3}% +   \setbox\scratchboxtwo\chem_box_visual_yes{\strut\molecule{#4}}% +   \setbox\scratchboxone\chem_box_normal_yes{\lower\dimexpr\dp\scratchboxtwo+\ht\scratchboxone\relax\hbox to \wd\scratchboxtwo{#1\box\scratchboxone#2}}%     \smashbox\scratchboxone     \box\scratchboxone     \box\scratchboxtwo @@ -346,15 +351,15 @@  \unexpanded\def\chemicalleft#1#2% redundant boxes thanks to visual    {\hbox\bgroup     \setstrut -   \llap{\chem_box_visual{\strut#1}}% -   \chem_box_visual{\strut#2}% +   \llap{\chem_box_visual_nop{\strut#1}}% +   \chem_box_visual_nop{\strut#2}%     \egroup}  \unexpanded\def\chemicalright#1#2% redundant boxes thanks to visual    {\hbox\bgroup     \setstrut -   \chem_box_visual{\strut#2}% -   \rlap{\chem_box_visual{\strut#1}}% +   \chem_box_visual_yes{\strut#2}% +   \rlap{\chem_box_visual_nop{\strut#1}}%     \egroup}  \unexpanded\def\chemicaltop            {\chem_top_construct    \hss   \hss  } @@ -390,7 +395,7 @@    {\dontleavehmode     \begingroup     \usechemicalstyleandcolor\c!style\c!color -   \chem_box_visual to \fontcharwd\font`C\bgroup +   \chem_box_visual_yes to \fontcharwd\font`C\bgroup       \setstrut\strut       #1\molecule{#3}#2%     \egroup @@ -401,7 +406,7 @@     \begingroup     \scratchcounter\normalmathstyle     \usechemicalstyleandcolor\c!style\c!color -   \chem_box_visual to \fontcharwd\font`C\bgroup +   \chem_box_visual_yes to \fontcharwd\font`C\bgroup       \setstrut\strut       #1\mathematics{\tf\triggermathstyle\scratchcounter\molecule{#3}}#2%     \egroup @@ -602,6 +607,9 @@  \definechemicalsymbol[d:gives]       [\rightarrowfill]          % \chem_arrow_construct\xrightarrow  \definechemicalsymbol[d:equilibrium] [\rightoverleftarrowfill]  % \chem_arrow_construct\xrightoverleftarrow  \definechemicalsymbol[d:mesomeric]   [\leftarrowfill]           % \chem_arrow_construct\xleftrightarrow +\definechemicalsymbol[d:single]      [\chemicalbondrule] +\definechemicalsymbol[d:double]      [\hbox{\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}] +\definechemicalsymbol[d:triple]      [\hbox{\chemicalbondrule\hskip-1em\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}]  \definechemicalsymbol[d:opencomplex] [\mathematics{\Bigg[}]     % not yet ok  \definechemicalsymbol[d:closecomplex][\mathematics{\Bigg]}]     % not yet ok @@ -611,6 +619,9 @@  \definechemicalsymbol[d:GIVES]       [{\chemicalsymbol[d:gives]}]  \definechemicalsymbol[d:EQUILIBRIUM] [{\chemicalsymbol[d:equilibrium]}]  \definechemicalsymbol[d:MESOMERIC]   [{\chemicalsymbol[d:mesomeric]}] +\definechemicalsymbol[d:SINGLE]      [{\chemicalsymbol[d:single]}] +\definechemicalsymbol[d:DOUBLE]      [{\chemicalsymbol[d:double]}] +\definechemicalsymbol[d:TRIPLE]      [{\chemicalsymbol[d:triple]}]  \definechemicalsymbol[d:OPENCOMPLEX] [{\chemicalsymbol[d:opencomplex]}]  \definechemicalsymbol[d:CLOSECOMPLEX][{\chemicalsymbol[d:closecomplex]}] diff --git a/tex/context/base/cont-log.mkiv b/tex/context/base/cont-log.mkiv index 5d4133143..99e08450b 100644 --- a/tex/context/base/cont-log.mkiv +++ b/tex/context/base/cont-log.mkiv @@ -126,11 +126,16 @@     \setMFPfont META\syst_logos_meta_hyphen FONT%     \endgroup} +% \unexpanded\def\MetaPost +%   {\dontleavehmode +%    \begingroup +%    \setMFPfont META\syst_logos_meta_hyphen POST% +%    \endgroup} +% +% As decided on the ConText Meeting 2013 the logo has been simplified: +  \unexpanded\def\MetaPost -  {\dontleavehmode -   \begingroup -   \setMFPfont META\syst_logos_meta_hyphen POST% -   \endgroup} +  {MetaPost}  \unexpanded\def\MetaFun    {MetaFun} diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index c1008d722..d16bba5da 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2013.10.01 20:08} +\newcontextversion{2013.10.04 23:41}  %D This file is loaded at runtime, thereby providing an excellent place for  %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex e62eb1541..3e1cf4ec0 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 674f8a2bf..78e7c73d3 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -25,7 +25,7 @@  %D up and the dependencies are more consistent.  \edef\contextformat {\jobname} -\edef\contextversion{2013.10.01 20:08} +\edef\contextversion{2013.10.04 23:41}  \edef\contextkind   {beta}  %D For those who want to use this: @@ -162,7 +162,7 @@  \loadmarkfile{supp-ran}  \loadmarkfile{supp-mat} -\loadmarkfile{spac-cha} +%loadmarkfile{spac-cha} % obsolete  %loadmarkfile{supp-num} % obsolete  \loadmarkfile{typo-ini} @@ -324,19 +324,6 @@  \loadmarkfile{strc-bkm} % bookmarks -\loadmarkfile{tabl-com} -\loadmarkfile{tabl-pln} - -\loadmarkfile{tabl-tab} % thrd-tab stripped and merged - -\loadmarkfile{tabl-tbl} -\loadmarkfile{tabl-ntb} -\loadmarkfile{tabl-nte} -\loadmarkfile{tabl-ltb} -\loadmarkfile{tabl-tsp} -\loadmkvifile{tabl-xtb} -\loadmarkfile{tabl-mis} -  \loadmarkfile{java-ini}  \loadmkvifile{scrn-fld} @@ -364,6 +351,21 @@  \loadmkvifile{font-aux}  \loadmkvifile{font-sel} +\loadmarkfile{typo-tal} + +\loadmarkfile{tabl-com} +\loadmarkfile{tabl-pln} + +\loadmarkfile{tabl-tab} % thrd-tab stripped and merged + +\loadmarkfile{tabl-tbl} +\loadmarkfile{tabl-ntb} +\loadmarkfile{tabl-nte} +\loadmarkfile{tabl-ltb} +\loadmarkfile{tabl-tsp} +\loadmkvifile{tabl-xtb} +\loadmarkfile{tabl-mis} +  \loadmarkfile{typo-lan}  \loadmarkfile{lxml-css} diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index feefac338..6c3402683 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -34,6 +34,7 @@ local trace_designsize    = false  trackers.register("fonts.designsize", functio  local trace_usage         = false  trackers.register("fonts.usage",      function(v) trace_usage      = v end)  local trace_mapfiles      = false  trackers.register("fonts.mapfiles",   function(v) trace_mapfiles   = v end)  local trace_automode      = false  trackers.register("fonts.automode",   function(v) trace_automode   = v end) +local trace_merge         = false  trackers.register("fonts.merge",      function(v) trace_merge      = v end)  local report_features     = logs.reporter("fonts","features")  local report_cummulative  = logs.reporter("fonts","cummulative") @@ -122,7 +123,11 @@ end  -- this will move elsewhere ... -utilities.strings.formatters.add(formatters,"font:name",    [["'"..file.basename(%s.properties.name).."'"]]) +function fonts.helpers.name(tfmdata) +    return file.basename(type(tfmdata) == "number" and properties[tfmdata].name or tfmdata.properties.name) +end + +utilities.strings.formatters.add(formatters,"font:name",    [["'"..fonts.helpers.name(%s).."'"]])  utilities.strings.formatters.add(formatters,"font:features",[["'"..table.sequenced(%s," ",true).."'"]])  -- ... like font-sfm or so @@ -165,10 +170,24 @@ commands.resetnullfont = definers.resetnullfont  -- so we never enter the loop then; we can store the defaults in the tma  -- file (features.gpos.mkmk = 1 etc) -local needsnodemode = { -    gpos_mark2mark     = true, -    gpos_mark2base     = true, -    gpos_mark2ligature = true, +local needsnodemode = { -- we will have node mode by default anyway + -- gsub_single              = true, +    gsub_multiple            = true, + -- gsub_alternate           = true, + -- gsub_ligature            = true, +    gsub_context             = true, +    gsub_contextchain        = true, +    gsub_reversecontextchain = true, + -- chainsub                 = true, + -- reversesub               = true, +    gpos_mark2base           = true, +    gpos_mark2ligature       = true, +    gpos_mark2mark           = true, +    gpos_cursive             = true, + -- gpos_single              = true, + -- gpos_pair                = true, +    gpos_context             = true, +    gpos_contextchain        = true,  }  otftables.scripts.auto = "automatic fallback to latn when no dflt present" @@ -206,6 +225,8 @@ local function checkedscript(tfmdata,resources,features)      return script  end +-- basemode combined with dynamics is somewhat tricky +  local function checkedmode(tfmdata,resources,features)      local sequences = resources.sequences      if sequences and #sequences > 0 then @@ -248,6 +269,9 @@ local function checkedmode(tfmdata,resources,features)              end          end      end +    if trace_automode then +        report_defining("forcing mode base, font %!font:name!",tfmdata) +    end      features.mode = "base" -- new, or is this wrong?      return "base"  end @@ -548,6 +572,9 @@ local function mergecontextfeatures(currentname,extraname,how,mergedname) -- str              for k, v in next, extra do                  mergedfeatures[k] = v              end +            if trace_merge then +                report_features("merge %a, method %a, current %|T, extra %|T, result %|T",mergedname,"add",current or { },extra,mergedfeatures) +            end          elseif how == "-" then              if current then                  for k, v in next, current do @@ -560,10 +587,16 @@ local function mergecontextfeatures(currentname,extraname,how,mergedname) -- str                      mergedfeatures[k] = false                  end              end +            if trace_merge then +                report_features("merge %a, method %a, current %|T, extra %|T, result %|T",mergedname,"subtract",current or { },extra,mergedfeatures) +            end          else -- =              for k, v in next, extra do                  mergedfeatures[k] = v              end +            if trace_merge then +                report_features("merge %a, method %a, result %|T",mergedname,"replace",mergedfeatures) +            end          end          local number = #numbers + 1          mergedfeatures.number = number @@ -1001,7 +1034,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature          -- resolved (when designsize is used):          local size = fontdata[tfmdata].parameters.size or 0          setsomefontsize(size .. "sp") -texsetcount("scaledfontsize",size) +        texsetcount("scaledfontsize",size)          lastfontid = tfmdata      else          -- setting the extra characters will move elsewhere @@ -1028,7 +1061,7 @@ texsetcount("scaledfontsize",size)          -- resolved (when designsize is used):          local size = tfmdata.parameters.size or 655360          setsomefontsize(size .. "sp") -texsetcount("scaledfontsize",size) +        texsetcount("scaledfontsize",size)          lastfontid = id      end      if trace_defining then diff --git a/tex/context/base/font-fea.mkvi b/tex/context/base/font-fea.mkvi index c1e051621..777c6e3ca 100644 --- a/tex/context/base/font-fea.mkvi +++ b/tex/context/base/font-fea.mkvi @@ -164,7 +164,7 @@  \let\doaddfeature        \font_feature_add_nop       % low level faster ones  \let\dosubtractfeature   \font_feature_subtract_nop  \let\doreplacefeature    \font_feature_replace_nop -\let\doreserandaddfeature\font_feature_reset_add_nop +\let\doresetandaddfeature\font_feature_reset_add_nop  \unexpanded\def\font_feature_add    {\ifnum\c_font_feature_state=\plusone @@ -330,4 +330,12 @@  \ctxcommand{registerlanguagefeatures()} +% also new + +\unexpanded\def\useaddfontfeatureparameter#1% faster local variant +  {\edef\m_font_feature_asked{#1\c!features}% +   \ifx\m_font_feature_asked\empty\else +     \font_feature_add +   \fi} +  \protect \endinput diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua index 284714261..7f8bb91d1 100644 --- a/tex/context/base/font-gds.lua +++ b/tex/context/base/font-gds.lua @@ -833,28 +833,33 @@ registerotffeature {      }  } --- kern hackery +-- kern hackery: +-- +-- yes  : use goodies table +-- auto : assume features to be set (often ccmp only) -local function setkeptligatures(tfmdata,scheme) -    local goodies = tfmdata.goodies -    if goodies then -        for i=1,#goodies do -            local g = goodies[i] -            local letterspacing = g.letterspacing -            if letterspacing then -                local keptligatures = letterspacing.keptligatures -                if keptligatures then -                    local unicodes = tfmdata.resources.unicodes -                    local hash = { } -                    for k, v in next, keptligatures do -                        local u = unicodes[k] -                        if u then -                            hash[u] = true -                        else -                            -- error: unknown name +local function setkeepligatures(tfmdata,value) +    if not tfmdata.properties.keptligatures then +        local goodies = tfmdata.goodies +        if goodies then +            for i=1,#goodies do +                local g = goodies[i] +                local letterspacing = g.letterspacing +                if letterspacing then +                    local keptligatures = letterspacing.keptligatures +                    if keptligatures then +                        local unicodes = tfmdata.resources.unicodes +                        local hash = { } +                        for k, v in next, keptligatures do +                            local u = unicodes[k] +                            if u then +                                hash[u] = true +                            else +                                -- error: unknown name +                            end                          end +                        tfmdata.properties.keptligatures = hash                      end -                    tfmdata.properties.keptligatures = hash                  end              end          end @@ -862,11 +867,10 @@ local function setkeptligatures(tfmdata,scheme)  end  registerotffeature { -    name         = "keptligatures", -    description  = "kept ligatures in letterspacing", -    default      = true, +    name         = "keepligatures", +    description  = "keep ligatures in letterspacing",      initializers = { -        base = setkeptligatures, -        node = setkeptligatures, +        base = setkeepligatures, +        node = setkeepligatures,      }  } diff --git a/tex/context/base/font-hsh.lua b/tex/context/base/font-hsh.lua index a18f78cab..773cc2b69 100644 --- a/tex/context/base/font-hsh.lua +++ b/tex/context/base/font-hsh.lua @@ -29,6 +29,7 @@ local spaces        = hashes.spaces       or allocate()  local quads         = hashes.quads        or allocate() -- maybe also spacedata  local xheights      = hashes.xheights     or allocate()  local csnames       = hashes.csnames      or allocate() -- namedata +local features      = hashes.features     or allocate()  local marks         = hashes.marks        or allocate()  local italics       = hashes.italics      or allocate()  local lastmathids   = hashes.lastmathids  or allocate() @@ -44,6 +45,7 @@ hashes.spaces       = spaces  hashes.quads        = quads                 hashes.emwidths  = quads  hashes.xheights     = xheights              hashes.exheights = xheights  hashes.csnames      = csnames +hashes.features     = features  hashes.marks        = marks  hashes.italics      = italics  hashes.lastmathids  = lastmathids @@ -138,6 +140,17 @@ setmetatableindex(resources, function(t,k)      end  end) +setmetatableindex(features, function(t,k) +    if k == true then +        return features[currentfont()] +    else +        local shared = identifiers[k].shared +        local features = shared and shared.features or { } +        t[k] = features +        return features +    end +end) +  local nospacing = {      width   = 0,      stretch = 0, diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index 64323ddcf..3733d51c2 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -20,7 +20,7 @@ if not modules then modules = { } end modules ['font-otn'] = {  -- todo:  -- --- kerning is probably not yet ok for latin around dics nodes +-- kerning is probably not yet ok for latin around dics nodes (interesting challenge)  -- extension infrastructure (for usage out of context)  -- sorting features according to vendors/renderers  -- alternative loop quitters @@ -31,7 +31,8 @@ if not modules then modules = { } end modules ['font-otn'] = {  -- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)  -- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests)  -- remove some optimizations (when I have a faster machine) - +-- +-- maybe redo the lot some way (more context specific)  --[[ldx--  <p>This module is a bit more split up that I'd like but since we also want to test @@ -187,6 +188,7 @@ local default            = "dflt"  local nodecodes          = nodes.nodecodes  local whatcodes          = nodes.whatcodes  local glyphcodes         = nodes.glyphcodes +local disccodes          = nodes.disccodes  local glyph_code         = nodecodes.glyph  local glue_code          = nodecodes.glue @@ -197,6 +199,8 @@ local math_code          = nodecodes.math  local dir_code           = whatcodes.dir  local localpar_code      = whatcodes.localpar +local discretionary_code = disccodes.discretionary +  local ligature_code      = glyphcodes.ligature  local privateattribute   = attributes.private @@ -502,13 +506,18 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives      end  end -local function multiple_glyphs(head,start,multiple) -- marks ? +local function multiple_glyphs(head,start,multiple,ignoremarks)      local nofmultiples = #multiple      if nofmultiples > 0 then          start.char = multiple[1]          if nofmultiples > 1 then              local sn = start.next              for k=2,nofmultiples do -- todo: use insert_node +-- untested: +-- +-- while ignoremarks and marks[sn.char] then +--     local sn = sn.next +-- end                  local n = copy_node(start) -- ignore components                  n.char = multiple[k]                  n.next = sn @@ -545,11 +554,11 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence      return head, start, true  end -function handlers.gsub_multiple(head,start,kind,lookupname,multiple) +function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)      if trace_multiples then          logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))      end -    return multiple_glyphs(head,start,multiple) +    return multiple_glyphs(head,start,multiple,sequence.flags[1])  end  function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) @@ -905,7 +914,6 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)                  prev = snext                  snext = snext.next              else -                local krn = kerns[nextchar]                  if not krn then                      -- skip                  elseif type(krn) == "table" then @@ -1026,35 +1034,35 @@ single lookup case. The efficiency of the replacements can be improved by deleti  as less as needed but that would also make the code even more messy.</p>  --ldx]]-- -local function delete_till_stop(start,stop,ignoremarks) -- keeps start -    local n = 1 -    if start == stop then -        -- done -    elseif ignoremarks then -        repeat -- start x x m x x stop => start m -            local next = start.next -            if not marks[next.char] then -                local components = next.components -                if components then -- probably not needed -                    flush_node_list(components) -                end -                delete_node(start,next) -            end -            n = n + 1 -        until next == stop -    else -- start x x x stop => start -        repeat -            local next = start.next -            local components = next.components -            if components then -- probably not needed -                flush_node_list(components) -            end -            delete_node(start,next) -            n = n + 1 -        until next == stop -    end -    return n -end +-- local function delete_till_stop(head,start,stop,ignoremarks) -- keeps start +--     local n = 1 +--     if start == stop then +--         -- done +--     elseif ignoremarks then +--         repeat -- start x x m x x stop => start m +--             local next = start.next +--             if not marks[next.char] then +--                 local components = next.components +--                 if components then -- probably not needed +--                     flush_node_list(components) +--                 end +--                 head = delete_node(head,next) +--             end +--             n = n + 1 +--         until next == stop +--     else -- start x x x stop => start +--         repeat +--             local next = start.next +--             local components = next.components +--             if components then -- probably not needed +--                 flush_node_list(components) +--             end +--             head = delete_node(head,next) +--             n = n + 1 +--         until next == stop +--     end +--     return head, n +-- end  --[[ldx--  <p>Here we replace start by a single variant, First we delete the rest of the @@ -1108,7 +1116,7 @@ the match.</p>  --ldx]]--  function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) -    delete_till_stop(start,stop) -- we could pass ignoremarks as #3 .. + -- local head, n = delete_till_stop(head,start,stop)      local startchar = start.char      local subtables = currentlookup.subtables      local lookupname = subtables[1] @@ -1127,7 +1135,7 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,              if trace_multiples then                  logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))              end -            return multiple_glyphs(head,start,replacements) +            return multiple_glyphs(head,start,replacements,currentlookup.flags[1])          end      end      return head, start, false @@ -1550,10 +1558,11 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo      return head, start, false  end +chainmores.gpos_single = chainprocs.gpos_single -- okay? +  -- when machines become faster i will make a shared function  function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) ---    logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))      local snext = start.next      if snext then          local startchar = start.char @@ -1623,6 +1632,8 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look      return head, start, false  end +chainmores.gpos_pair = chainprocs.gpos_pair -- okay? +  -- what pointer to return, spec says stop  -- to be discussed ... is bidi changer a space?  -- elseif char == zwnj and sequence[n][32] then -- brrr @@ -1865,7 +1876,11 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq                      if chainlookup then                          local cp = chainprocs[chainlookup.type]                          if cp then -                            head, start, done = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) +                            local ok +                            head, start, ok = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) +                            if ok then +                                done = true +                            end                          else                              logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)                          end @@ -1892,22 +1907,28 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq                              end                          end                          local chainlookupname = chainlookups[i] -                        local chainlookup = lookuptable[chainlookupname] -- can be false (n matches, <n replacement) -                        local cp = chainlookup and chainmores[chainlookup.type] -                        if cp then -                            local ok, n -                            head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) -                            -- messy since last can be changed ! -                            if ok then -                                done = true -                                -- skip next one(s) if ligature -                                i = i + (n or 1) -                            else +                        local chainlookup = lookuptable[chainlookupname] +                        if not chainlookup then +                            -- okay, n matches, < n replacements +                            i = i + 1 +                        else +                            local cp = chainmores[chainlookup.type] +                            if not cp then +                                -- actually an error +                                logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)                                  i = i + 1 +                            else +                                local ok, n +                                head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) +                                -- messy since last can be changed ! +                                if ok then +                                    done = true +                                    -- skip next one(s) if ligature +                                    i = i + (n or 1) +                                else +                                    i = i + 1 +                                end                              end -                        else -                         -- is valid -                            i = i + 1                          end                          if start then                              start = start.next @@ -2081,6 +2102,15 @@ end  -- there will be a new direction parser (pre-parsed etc) +-- less bytecode: 290 -> 254 +-- +-- attr = attr or false +-- +-- local a = getattr(start,0) +-- if (a == attr and (not attribute or getattr(start,a_state) == attribute)) or (not attribute or getattr(start,a_state) == attribute) then +--     -- the action +-- end +  local function featuresprocessor(head,font,attr)      local lookuphash = lookuphashes[font] -- we can also check sequences here @@ -2185,6 +2215,44 @@ local function featuresprocessor(head,font,attr)                  if not lookupcache then -- also check for empty cache                      report_missing_cache(typ,lookupname)                  else + +                    local function subrun(start) +                        -- mostly for gsub, gpos would demand a more clever approach +                        local head = start +                        local done = false +                        while start do +                            local id = start.id +                            if id == glyph_code and start.font == font and start.subtype <256 then +                                local a = start[0] +                                if a then +                                    a = (a == attr) and (not attribute or start[a_state] == attribute) +                                else +                                    a = not attribute or start[a_state] == attribute +                                end +                                if a then +                                    local lookupmatch = lookupcache[start.char] +                                    if lookupmatch then +                                        -- sequence kan weg +                                        local ok +                                        head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) +                                        if ok then +                                            done = true +                                        end +                                    end +                                    if start then start = start.next end +                                else +                                    start = start.next +                                end +                            else +                                start = start.next +                            end +                        end +                        if done then +                            success = true +                            return head +                        end +                    end +                      while start do                          local id = start.id                          if id == glyph_code then @@ -2212,6 +2280,26 @@ local function featuresprocessor(head,font,attr)                              else                                  start = start.next                              end +                        elseif id == disc_code then +                            -- mostly for gsub +                            if start.subtype == discretionary_code then +                                local pre = start.pre +                                if pre then +                                    local new = subrun(pre) +                                    if new then start.pre = new end +                                end +                                local post = start.post +                                if post then +                                    local new = subrun(post) +                                    if new then start.post = new end +                                end +                                local replace = start.replace +                                if replace then +                                    local new = subrun(replace) +                                    if new then start.replace = new end +                                end +                            end +                            start = start.next                          elseif id == whatsit_code then -- will be function                              local subtype = start.subtype                              if subtype == dir_code then @@ -2242,6 +2330,7 @@ local function featuresprocessor(head,font,attr)                                  else                                      rlparmode = 0                                  end +                                -- one might wonder if the par dir should be looked at, so we might as well drop the next line                                  rlmode = rlparmode                                  if trace_directions then                                      report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) @@ -2256,6 +2345,56 @@ local function featuresprocessor(head,font,attr)                      end                  end              else + +                local function subrun(start) +                    -- mostly for gsub, gpos would demand a more clever approach +                    local head = start +                    local done = false +                    while start do +                        local id = start.id +                        if id == glyph_code and start.id == font and start.subtype <256 then +                            local a = start[0] +                            if a then +                                a = (a == attr) and (not attribute or start[a_state] == attribute) +                            else +                                a = not attribute or start[a_state] == attribute +                            end +                            if a then +                                for i=1,ns do +                                    local lookupname = subtables[i] +                                    local lookupcache = lookuphash[lookupname] +                                    if lookupcache then +                                        local lookupmatch = lookupcache[start.char] +                                        if lookupmatch then +                                            -- we could move all code inline but that makes things even more unreadable +                                            local ok +                                            head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) +                                            if ok then +                                                done = true +                                                break +                                            elseif not start then +                                                -- don't ask why ... shouldn't happen +                                                break +                                            end +                                        end +                                    else +                                        report_missing_cache(typ,lookupname) +                                    end +                                end +                                if start then start = start.next end +                            else +                                start = start.next +                            end +                        else +                            start = start.next +                        end +                    end +                    if done then +                        success = true +                        return head +                    end +                end +                  while start do                      local id = start.id                      if id == glyph_code then @@ -2295,6 +2434,26 @@ local function featuresprocessor(head,font,attr)                          else                              start = start.next                          end +                    elseif id == disc_code then +                        -- mostly for gsub +                        if start.subtype == discretionary_code then +                            local pre = start.pre +                            if pre then +                                local new = subrun(pre) +                                if new then start.pre = new end +                            end +                            local post = start.post +                            if post then +                                local new = subrun(post) +                                if new then start.post = new end +                            end +                            local replace = start.replace +                            if replace then +                                local new = subrun(replace) +                                if new then start.replace = new end +                            end +                        end +                        start = start.next                      elseif id == whatsit_code then                          local subtype = start.subtype                          if subtype == dir_code then diff --git a/tex/context/base/font-pre.mkiv b/tex/context/base/font-pre.mkiv index 63c0858d4..75f42f8f5 100644 --- a/tex/context/base/font-pre.mkiv +++ b/tex/context/base/font-pre.mkiv @@ -17,13 +17,15 @@  %D A basic set of features is defined here. +% beware, base mode + dynamics can give weird effects +  % rlig ccmp  \definefontfeature    [always] -  [mode=auto, -   script=auto, -   kern=yes, +  [mode=node,    % we had 'auto', but let's try 'node' for a while and see what the impact is +   script=auto,  % on speed; 'base' just doesn't play well with dynamics; some day we can even +   kern=yes,     % consider skipping the base passes when no base mode is used     mark=yes,     mkmk=yes,     curs=yes] @@ -61,6 +63,15 @@     tlig=yes,     trep=yes] +\definefontfeature +  [letterspacing] +  [liga=no, +   rlig=no, +   clig=no, +   dlig=no, +   ccmp=yes, +   keepligatures=auto] +  \definefontfeature % can be used for type1 fonts    [complete]    [always] diff --git a/tex/context/base/mult-def.mkiv b/tex/context/base/mult-def.mkiv index fc17ee475..0c52d5a92 100644 --- a/tex/context/base/mult-def.mkiv +++ b/tex/context/base/mult-def.mkiv @@ -99,6 +99,7 @@  \def\c!NL               {NL}  \ifdefined\v!kerncharacters\else \def\v!kerncharacters{kerncharacters} \fi % no time now for translations should be a e! actually +\ifdefined\v!letterspacing \else \def\v!letterspacing {letterspacing}  \fi % no time now for translations should be a e! actually  \ifdefined\v!stretched     \else \def\v!stretched     {stretched}      \fi  \ifdefined\v!vulgarfraction\else \def\v!vulgarfraction{vulgarfraction} \fi  \ifdefined\v!block         \else \def\v!block         {block}          \fi diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua index f74f27e7c..2f59d513c 100644 --- a/tex/context/base/node-fnt.lua +++ b/tex/context/base/node-fnt.lua @@ -30,6 +30,7 @@ local nodecodes         = nodes.nodecodes  local handlers          = nodes.handlers  local glyph_code        = nodecodes.glyph +local disc_code         = nodecodes.disc  local setmetatableindex = table.setmetatableindex @@ -91,11 +92,18 @@ end)  fonts.hashes.setdynamics = setfontdynamics  fonts.hashes.processes   = fontprocesses +-- if we forget about basemode we don't need to test too much here and we can consider running +-- over sub-ranges .. this involves a bit more initializations but who cares .. in that case we +-- also need to use the stop criterium (we already use head too) ... we cannot use traverse +-- then, so i'll test it on some local clone first ... the only pitfall is changed directions +-- inside a run which means that we need to keep track of this which in turn complicates matters +-- in a way i don't like +  function handlers.characters(head)      -- either next or not, but definitely no already processed list      starttiming(nodes) -        local usedfonts, attrfonts = { }, { } -        local a, u, prevfont, prevattr, done = 0, 0, nil, 0, false +    local usedfonts, attrfonts = { }, { } +    local a, u, prevfont, prevattr, done = 0, 0, nil, 0, false      if trace_fontrun then          run = run + 1          report_fonts() @@ -107,9 +115,11 @@ function handlers.characters(head)              if id == glyph_code then                  local font = n.font                  local attr = n[0] or 0 -                report_fonts("font %03i, dynamic %03i, glyph %s",font,attr,utf.char(n.char)) +                report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,n.char) +            elseif id == disc_code then +                report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n))              else -                report_fonts("[%s]",nodecodes[n.id]) +                report_fonts("[%s]",nodecodes[id])              end              n = n.next          end @@ -209,7 +219,6 @@ function handlers.characters(head)      return head, true  end -  --     local formatters = string.formatters  --     local function make(processors,font,attribute) diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua index 4cefc1906..9fe979e93 100644 --- a/tex/context/base/node-tra.lua +++ b/tex/context/base/node-tra.lua @@ -18,8 +18,6 @@ local clock = os.gettimeofday or os.clock -- should go in environment  local report_nodes = logs.reporter("nodes","tracing") -nodes = nodes or { } -  local nodes, node, context = nodes, node, context  local texgetattribute  = tex.getattribute @@ -53,7 +51,7 @@ local glue_code        = nodecodes.glue  local kern_code        = nodecodes.kern  local rule_code        = nodecodes.rule  local whatsit_code     = nodecodes.whatsit -local spec_code        = nodecodes.glue_spec +local gluespec_code    = nodecodes.gluespec  local localpar_code    = whatcodes.localpar  local dir_code         = whatcodes.dir @@ -260,16 +258,19 @@ local function listtoutf(h,joiner,textonly,last)      while h do          local id = h.id          if id == glyph_code then -- always true -            w[#w+1] = utfchar(h.char) +            local c = h.char +            w[#w+1] = c >= 0 and utfchar(c) or formatters["<%i>"](c)              if joiner then                  w[#w+1] = joiner              end          elseif id == disc_code then -            local pre, rep, pos = h.pre, h.replace, h.post +            local pre = h.pre +            local pos = h.post +            local rep = h.replace              w[#w+1] = formatters["[%s|%s|%s]"] (                  pre and listtoutf(pre,joiner,textonly) or "", -                rep and listtoutf(rep,joiner,textonly) or "", -                mid and listtoutf(mid,joiner,textonly) or "" +                pos and listtoutf(pos,joiner,textonly) or "", +                rep and listtoutf(rep,joiner,textonly) or ""              )          elseif textonly then              if id == glue_code and h.spec and h.spec.width > 0 then @@ -353,7 +354,7 @@ local function numbertodimen(d,unit,fmt,strip)      if id == glue_code then          d = d.spec      end -    if not d or not d.id == spec_code then +    if not d or not d.id == gluespec_code then          local str = formatters[fmt](0,unit)          return strip and lpegmatch(stripper,str) or str      end diff --git a/tex/context/base/phys-dim.lua b/tex/context/base/phys-dim.lua index 24d0b9231..e40d1eabb 100644 --- a/tex/context/base/phys-dim.lua +++ b/tex/context/base/phys-dim.lua @@ -384,13 +384,15 @@ local long_operators = {  local long_suffixes = { -    Linear  = "linear", -    Square  = "square", -    Cubic   = "cubic", -    Inverse = "inverse", -    ILinear = "ilinear", -    ISquare = "isquare", -    ICubic  = "icubic", +    Linear     = "linear", +    Square     = "square", +    Cubic      = "cubic", +    Quadratic  = "quadratic", +    Inverse    = "inverse", +    ILinear    = "ilinear", +    ISquare    = "isquare", +    ICubic     = "icubic", +    IQuadratic = "iquadratic",  } @@ -457,23 +459,29 @@ local short_suffixes = { -- maybe just raw digit match      ["1"]   = "linear",      ["2"]   = "square",      ["3"]   = "cubic", +    ["4"]   = "quadratic",      ["+1"]  = "linear",      ["+2"]  = "square",      ["+3"]  = "cubic", +    ["+4"]  = "quadratic",      ["-1"]  = "inverse",      ["-1"]  = "ilinear",      ["-2"]  = "isquare",      ["-3"]  = "icubic", +    ["-4"]  = "iquadratic",      ["^1"]  = "linear",      ["^2"]  = "square",      ["^3"]  = "cubic", +    ["^4"]  = "quadratic",      ["^+1"] = "linear",      ["^+2"] = "square",      ["^+3"] = "cubic", +    ["^+4"] = "quadratic",      ["^-1"] = "inverse",      ["^-1"] = "ilinear",      ["^-2"] = "isquare",      ["^-3"] = "icubic", +    ["^-4"] = "iquadratic",  }  local symbol_units = { @@ -638,13 +646,15 @@ labels.operators = allocate {  }  labels.suffixes = allocate { -    linear  = { labels = { en = [[1]]  } }, -    square  = { labels = { en = [[2]]  } }, -    cubic   = { labels = { en = [[3]]  } }, -    inverse = { labels = { en = [[-1]] } }, -    ilinear = { labels = { en = [[-1]] } }, -    isquare = { labels = { en = [[-2]] } }, -    icubic  = { labels = { en = [[-3]] } }, +    linear     = { labels = { en = [[1]]  } }, +    square     = { labels = { en = [[2]]  } }, +    cubic      = { labels = { en = [[3]]  } }, +    quadratic  = { labels = { en = [[4]]  } }, +    inverse    = { labels = { en = [[-1]] } }, +    ilinear    = { labels = { en = [[-1]] } }, +    isquare    = { labels = { en = [[-2]] } }, +    icubic     = { labels = { en = [[-3]] } }, +    iquadratic = { labels = { en = [[-4]]  } },  }  local function dimpus(p,u,s) diff --git a/tex/context/base/s-fonts-vectors.lua b/tex/context/base/s-fonts-vectors.lua index 1bac0ae8b..af8042f84 100644 --- a/tex/context/base/s-fonts-vectors.lua +++ b/tex/context/base/s-fonts-vectors.lua @@ -20,7 +20,7 @@ function moduledata.fonts.protrusions.showvector(specification)      local vector = vectors[specification.name or "?"]      if vector then          context.blank() -        context.startcolumns { n = specification.columns or 3 } +        context.startcolumns { n = specification.columns or 3, balance="yes"  }              context.starttabulate { "|T||cw(.5em)||" }                  for unicode, values in table.sortedhash(vector) do                      NC() context("%U",unicode) @@ -65,7 +65,7 @@ function moduledata.fonts.expansions.showvector(specification)      local vector = vectors[specification.name or "?"]      if vector then          context.blank() -        context.startcolumns { n = specification.columns or 3 } +        context.startcolumns { n = specification.columns or 3, balance="yes"  }              context.starttabulate { "|T|cw(.5em)||" }                  for unicode, value in table.sortedhash(vector) do                      NC() context("%U",unicode) diff --git a/tex/context/base/spac-cha.mkiv b/tex/context/base/spac-cha.mkiv deleted file mode 100644 index a07c8f198..000000000 --- a/tex/context/base/spac-cha.mkiv +++ /dev/null @@ -1,191 +0,0 @@ -%D \module -%D   [       file=spac-cha,   % was supp-ali, -%D        version=2012.06.08, % 2000.04.17, -%D          title=\CONTEXT\ Spacing Macros, -%D       subtitle=Character Alignment, -%D         author=Hans Hagen, -%D           date=\currentdate, -%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -%D Yet undocumented but nevertheless used. - -% 0 = centered -% 1 = left  in before -% 2 = right in before -% 3 = left  in after -% 4 = right in after - -\unprotect - -% \starttabulate[|cg{.}|cg{,}|cg{,}|] -% \NC period     \NC comma      \NC comma   \NC\NR -% \NG 100.000,00 \NG 100.000,00 \NG 100,00  \NC\NR -% \NG 10.000,00  \NG 10.000,00  \NG 1000,00 \NC\NR -% \NG 100,00     \NG 100,00     \NG 10,00   \NC\NR -% \NG 100,00     \NG 100,00     \NG 10,00   \NC\NR -% \NG 10\\       \NG 10\\       \NG 0,00    \NC\NR -% \NG 10         \NG 10         \NG 0,00    \NC\NR -% \NG 10         \NG 10         \NG 0,00    \NC\NR -% \stoptabulate - -% We gain not much by luafication and actually make things worse. - -\chardef\characteralignmentmode\plusfour -\chardef\characteralignmentslot\plusone - -\let\afterassignwidth \!!zeropoint -\let\beforeassignwidth\!!zeropoint - -\def\alignmentcharacter{.} - -\newdimen\d_supp_charalign_width -\newtoks \t_supp_charalign_list - -\let\alignmentclass\s!default % can be used to handle multiple mixed ones - -\installcorenamespace{characteralign} - -\unexpanded\def\supp_charalign_push -  {\ifcsname\??characteralign\alignmentclass\endcsname\else -     \normalexpanded{\global\t_supp_charalign_list{\the\t_supp_charalign_list\supp_charalign_do{\alignmentclass}}}% -   \fi -   \setxvalue{\??characteralign\alignmentclass}{\supp_charalign_do -     {\afterassignwidth}{\beforeassignwidth}{\alignmentcharacter}}} - -\unexpanded\def\supp_charalign_pop_do#1#2#3% -  {\def\afterassignwidth  {#1}% -   \def\beforeassignwidth {#2}% -   \def\alignmentcharacter{#3}} - -\unexpanded\def\supp_charalign_pop -  {\let\supp_charalign_do\supp_charalign_pop_do -   \executeifdefined{\??characteralign\alignmentclass}\donothing} - -\unexpanded\def\supp_charalign_reset_do#1% -  {\global\letbeundefined{\??characteralign#1}} % global ! - -\unexpanded\def\resetcharacteralign -  {\let\supp_charalign_do\supp_charalign_reset_do -   \the\t_supp_charalign_list -   \global\t_supp_charalign_list\emptytoks} - -\unexpanded\def\supp_charalign_firstpass_one#1#2% -  {\supp_charalign_pop -   \let\\\empty -   \setbox\scratchbox\hbox{#1}% -   \d_supp_charalign_width\wd\scratchbox -   \setbox\scratchbox\emptyhbox -   \supp_charalign_check#2#1\relax\relax -   \scratchdimen-\wd\scratchbox -   \setbox\scratchbox\hbox{\ignorespaces#2\unskip}% -   \advance\scratchdimen \wd\scratchbox -   \ifdim\scratchdimen>\beforeassignwidth\relax -     \edef\beforeassignwidth{\the\scratchdimen}% -   \fi -   \ifdim\scratchdimen=\zeropoint -     \setbox\scratchbox\hbox{\ignorespaces#2\unskip}% -     \scratchdimen\wd\scratchbox -     \ifcase\characteralignmentmode -       % do nothing -     \else\ifnum\characteralignmentmode<\plusthree -       \advance\scratchdimen\d_supp_charalign_width\relax -       \ifdim\scratchdimen>\beforeassignwidth\relax -         \edef\beforeassignwidth{\the\scratchdimen}% -       \fi -     \else -       \ifdim\scratchdimen>\afterassignwidth\relax -         \edef\afterassignwidth{\the\scratchdimen}% -       \fi -     \fi\fi -   \fi -   \supp_charalign_push} - -\unexpanded\def\supp_charalign_firstpass_two#1#2#3% -  {\ifx#2\relax -     \setbox\scratchbox\hbox{\ignorespaces#1\unskip}% -     \ifdim\wd\scratchbox>\afterassignwidth -       \edef\afterassignwidth{\the\wd\scratchbox}% -     \fi -   \else -     \supp_charalign_check#2#3\relax\relax -   \fi} - -\unexpanded\def\supp_charalign_secondpass_one#1#2% -  {\supp_charalign_pop -   \let\\\empty % beware, no grouping -   \setbox\scratchbox\hbox{#1}% -   \d_supp_charalign_width\wd\scratchbox -   \setbox\scratchbox\emptyhbox -   % new 12,34 vs 10\\ where 10 aligns on 12 if #1 = , -   \ifcase\characteralignmentslot -     \supp_charalign_check#2#1\relax\relax -     \scratchdimen\wd\scratchbox -     \setbox\scratchbox\hbox{\ignorespaces##1\unskip}% -   \else -     \def\\{#1}% -     \normalexpanded{\supp_charalign_check#2#1\relax\relax}% -     \scratchdimen\wd\scratchbox -     \setbox\scratchbox\hbox{\def\\{\hphantom{#1}}\ignorespaces#2\unskip}% -   \fi -   \noindent -   \ifdim\scratchdimen=\wd\scratchbox -     \ifcase\characteralignmentmode -       \box\scratchbox -     \else -       \hbox -         {\dontcomplain -          \hbox to \beforeassignwidth -            {\ifcase\characteralignmentmode\or -               \box\scratchbox\hss -             \or -               \hss\box\scratchbox\hskip\d_supp_charalign_width -             \or -               \hss\rlap{\box\scratchbox}% -             \or -               \hss\rlap{\hbox to \afterassignwidth{\hss\box\scratchbox}}% -             \fi}% -          \hskip\afterassignwidth}% -     \fi -   \else -     \hbox -       {\hbox to \beforeassignwidth -          {\hss\box\scratchbox\hskip-\scratchdimen}% -        \hskip\afterassignwidth}% -   \fi} - -\unexpanded\def\supp_charalign_secondpass_two#1#2#3% -  {\ifx#2\relax -     \setbox\scratchbox\hbox{\ignorespaces#1\unskip}% -   \else -     \supp_charalign_check#2#3\relax\relax -   \fi} - -\unexpanded\def\supp_charalign_firstpass#1% -  {\unexpanded\def\checkalignment                    ##1{\supp_charalign_firstpass_one{#1}{##1}}% -   \unexpanded\def\supp_charalign_check##1#1##2##3\relax{\supp_charalign_firstpass_two{##1}{##2}{##3}}} - -\unexpanded\def\supp_charalign_secondpass#1% -  {\unexpanded\def\checkalignment                    ##1{\supp_charalign_secondpass_one{#1}{##1}}% -   \unexpanded\def\supp_charalign_check##1#1##2##3\relax{\supp_charalign_secondpass_two{##1}{##2}{##3}}} - -\unexpanded\def\setfirstpasscharacteralign -  {\supp_charalign_pop -   \normalexpanded{\supp_charalign_firstpass{\alignmentcharacter}}} - -\unexpanded\def\setsecondpasscharacteralign -  {\supp_charalign_pop -   \normalexpanded{\supp_charalign_secondpass{\alignmentcharacter}}} - -\unexpanded\def\startcharacteralign#1\stopcharacteralign -  {\bgroup -   \setfirstpasscharacteralign #1% -   \setsecondpasscharacteralign#1% -   \egroup} - -\let\stopcharacteralign\relax - -\protect \endinput diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex 2f5997597..9a9480dcf 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.log b/tex/context/base/status-lua.log index f2a3738c2..0e63fe31a 100644 --- a/tex/context/base/status-lua.log +++ b/tex/context/base/status-lua.log @@ -1,6 +1,6 @@  (cont-yes.mkiv -ConTeXt  ver: 2013.10.01 20:08 MKIV beta  fmt: 2013.10.1  int: english/english +ConTeXt  ver: 2013.10.04 23:41 MKIV beta  fmt: 2013.10.4  int: english/english  system          > 'cont-new.mkiv' loaded  (cont-new.mkiv) diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua index 349c34cdc..caa7dc16c 100644 --- a/tex/context/base/status-mkiv.lua +++ b/tex/context/base/status-mkiv.lua @@ -1261,6 +1261,12 @@ return {    },    {     category = "mkiv", +   filename = "typo-tal", +   loading  = "always", +   status   = "okay", +  }, +  { +   category = "mkiv",     comment  = "somewhat weird",     filename = "tabl-com",     loading  = "always", @@ -1492,12 +1498,6 @@ return {    },    {     category = "mkiv", -   filename = "spac-cha", -   loading  = "always", -   status   = "okay", -  }, -  { -   category = "mkiv",     comment  = "work in progress",     filename = "blob-ini",     loading  = "always", @@ -4805,6 +4805,12 @@ return {     status   = "todo",    },    { +   category = "mkiv", +   filename = "typo-tal", +   loading  = "typo-tal", +   status   = "okay", +  }, +  {     category = "lua",     filename = "typo-itc",     status   = "todo", diff --git a/tex/context/base/tabl-ntb.mkiv b/tex/context/base/tabl-ntb.mkiv index 57134cb53..242c3d6fe 100644 --- a/tex/context/base/tabl-ntb.mkiv +++ b/tex/context/base/tabl-ntb.mkiv @@ -1517,18 +1517,29 @@          {\scratchdimen\tabl_ntb_get_wid\recurselevel\relax           [\recurselevel:\the\scratchdimen]}}} +% \def\tabl_ntb_char_align +%   {\doifelse{\naturaltablelocalparameter\c!aligncharacter}\v!yes +%      \tabl_ntb_char_align_indeed\gobbletwoarguments} + +% \def\tabl_ntb_char_align_indeed#1#2#3% row column data +%   {\edef\alignmentclass{#2}% +%    \edef\alignmentcharacter{\naturaltablelocalparameter\c!alignmentcharacter}% +%    \ifcase\c_tabl_tbl_pass\or +%      \setfirstpasscharacteralign\checkalignment{#3}% {\strut#2\unskip}% +%    \fi % force hsize, so always a second +%    \setsecondpasscharacteralign \checkalignment{#3}% {\strut#2\unskip}% +%    \ignorespaces} +  \def\tabl_ntb_char_align    {\doifelse{\naturaltablelocalparameter\c!aligncharacter}\v!yes -     \tabl_ntb_char_align_indeed\gobbleoneargument} +     \tabl_ntb_char_align_indeed +     \gobbletwoarguments} -\def\tabl_ntb_char_align_indeed#1#2% column data -  {\edef\alignmentclass{#1}% -   \edef\alignmentcharacter{\naturaltablelocalparameter\c!alignmentcharacter}% -   \ifcase\c_tabl_tbl_pass\or -     \setfirstpasscharacteralign\checkalignment{#2}% {\strut#2\unskip}% -   \fi % force hsize, so always a second -   \setsecondpasscharacteralign \checkalignment{#2}% {\strut#2\unskip}% -   \ignorespaces} +\def\tabl_ntb_char_align_indeed#1#2% row column +  {\ifcase\c_tabl_tbl_pass \or +     \setcharacteralign{#2}{\naturaltablelocalparameter\c!alignmentcharacter}% +   \fi +   \signalcharacteralign{#2}{#1}}  \unexpanded\def\tabl_ntb_cell_process_a#1#2[#3]#4% grouping added ! ! !    {\bgroup @@ -1539,7 +1550,7 @@          \tabl_ntb_set_dis{#2}{\the\scratchdimen}%        \fi        \setupcurrentnaturaltablelocal[#3,\c!background=,\c!frame=\v!off]% 25% faster -      \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#2}{#4}\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}}% +      \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}}%     \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax     \ifdim\wd\scratchbox>\scratchdimen       \ifsqueezeTBLspan @@ -1625,7 +1636,7 @@        \fi      \fi      \normalexpanded{\tabl_ntb_cell_process_b_c{\ifdim\scratchdimen>\zeropoint \c!width=\the\scratchdimen\fi}}% -      {#1}{#2}[#3]{\tabl_ntb_char_align{#2}{#4}}} +      {#1}{#2}[#3]{\tabl_ntb_char_align{#1}{#2}#4}}  \unexpanded\def\tabl_ntb_cell_process_c    {\tabl_ntb_cell_process_b_c{}} @@ -1634,7 +1645,7 @@    {\tabl_ntb_setup_cell{#1}{#2}%     \bgroup     \setupcurrentnaturaltablelocal[#3,\c!width=\d_tabl_ntb_width,\c!background=,\c!frame=\v!off]% 25% faster -   \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#2}{#4}\tabl_ntb_cell_stop}% +   \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}%     \egroup}  \unexpanded\def\tabl_ntb_cell_process_e#1#2[#3]#4% @@ -1647,7 +1658,7 @@        \else          \setupcurrentnaturaltablelocal[\c!color=,\c!width=\d_tabl_ntb_width,\c!height=\d_tabl_ntb_height]%        \fi -      \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#2}{#4}\tabl_ntb_cell_stop}}% +      \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}%     \hskip\tabl_ntb_get_dis{#2}}  \setupTABLE diff --git a/tex/context/base/tabl-tbl.mkiv b/tex/context/base/tabl-tbl.mkiv index f04c45e18..fa2417712 100644 --- a/tex/context/base/tabl-tbl.mkiv +++ b/tex/context/base/tabl-tbl.mkiv @@ -232,7 +232,6 @@  \unexpanded\def\tolerantTABLEbreaktrue   {\settrue \c_tabl_tabulate_tolerant_break} % used in styles !  \unexpanded\def\handletabulatepbreakfalse{\setfalse\c_tabl_tabulate_handlepbreak  } % depricated -\installcorenamespace{tabulatealign}  \installcorenamespace{tabulatebox}  \installcorenamespace{tabulatesetup}  \installcorenamespace{tabulatehook} @@ -297,14 +296,6 @@  % [|lg{.}|] => \NG 12.34 \NC -\def\tabl_tabulate_charalign#1 % space delimited ! (will be redone in lua) -  {\edef\alignmentclass{\the\c_tabl_tabulate_column}% -   \edef\alignmentcharacter{\csname\??tabulatealign\the\c_tabl_tabulate_column\endcsname}% -   \ifcase\c_tabl_tabulate_pass\or -     \setfirstpasscharacteralign\checkalignment{#1}% -   \fi % force hsize -   \setsecondpasscharacteralign\checkalignment{#1}} -  \def\tabl_tabulate_nobreak_inject_tracer    {\red % maybe use the fast color switcher here     \hrule\s!height.5\linewidth\s!depth.5\linewidth @@ -425,6 +416,8 @@  \let\tabl_tabulate_hook_b\donothing  \let\tabl_tabulate_hook_e\donothing +\let\tabl_tabulate_hook_g\donothing +  \def\tabl_tabulate_set_preamble_step#1#2% only makes sense for many tabulates    {\normalexpanded{\t_tabl_tabulate_preamble{\the\t_tabl_tabulate_preamble          \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness @@ -440,6 +433,7 @@          \tabl_tabulate_color_side_both          \global\c_tabl_tabulate_colorspan\zerocount          \global\c_tabl_tabulate_column\constantnumber\c_tabl_tabulate_columns +        \tabl_tabulate_hook_g          \tabl_tabulate_setups_check % unexpandable          \tabl_tabulate_hook_check   % unexpandable          \ifzeropt\d_tabl_tabulate_width @@ -624,10 +618,22 @@    {\setvalue{\??tabulatehook\the\c_tabl_tabulate_columns}{#1}%     \tabl_tabulate_set_preamble} +% begin of character align plugin + +\newconditional\c_tabl_auto_align_mode % reset later + +\def\tabl_tabulate_hook_g % partly expanded +  {\ifconditional\c_tabl_auto_align_mode +     \signalcharacteralign\c_tabl_tabulate_column{\c_tabl_tabulate_noflines+\plusone}% +   \fi} +  \def\tabl_tabulate_set_align#1% -  {\setvalue{\??tabulatealign\the\c_tabl_tabulate_columns}{#1}% +  {\global\settrue\c_tabl_auto_align_mode +   \setcharacteralign\c_tabl_tabulate_columns{#1}%     \tabl_tabulate_set_preamble} +% end of character align plugin +  \def\tabl_tabulate_set_before#1%    {\t_tabl_tabulate_before{#1}%     \tabl_tabulate_set_preamble} @@ -759,6 +765,7 @@     \global\let\m_tabl_tabulate_text_color\empty     \global\let\m_tabl_tabulate_vrule_color\empty     \global\c_tabl_tabulate_colorspan\zerocount +   \global\setfalse\c_tabl_auto_align_mode     \global\advance\c_tabl_tabulate_columns\plusone     \expandafter\let\csname\??tabulatesetup\the\c_tabl_tabulate_columns\endcsname\donothing % here ?     \edef\currenttabulationtrulespec{#1}% @@ -768,7 +775,7 @@       \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default       \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command     \fi -   \tabl_tabulate_set_preamble#2\relax\relax % permits i without n +      \tabl_tabulate_set_preamble#2\relax\relax % permits i without n     \ifcase\c_tabl_tabulate_modus\relax       \tabl_tabulate_set_width_normal     \or % fixed width @@ -845,8 +852,7 @@  \let\tabl_tabulate_hook\tabl_tabulate_hook_nop -\def\tabl_tabulate_hook_yes {\csname\??tabulatehook \the\c_tabl_tabulate_column\endcsname} -\def\tabl_tabulate_align_yes{\csname\??tabulatealign\the\c_tabl_tabulate_column\endcsname} % to be used +\def\tabl_tabulate_hook_yes{\csname\??tabulatehook\the\c_tabl_tabulate_column\endcsname}  \def\tabl_tabulate_pheight_reset    {\global\c_tabl_tabulate_plines_min\plusone @@ -1696,7 +1702,8 @@  \unexpanded\def\tabl_tabulate_RQ_first{\tabl_tabulate_column_equal \plusone}  \unexpanded\def\tabl_tabulate_HQ_first{\tabl_tabulate_column_equal \plustwo} -\unexpanded\def\tabl_tabulate_NG_first{\NC\tabl_tabulate_charalign} +%unexpanded\def\tabl_tabulate_NG_first{\NC\tabl_tabulate_charalign} +\unexpanded\def\tabl_tabulate_NG_first{\NC}  \unexpanded\def\tabl_tabulate_NN_first{\NC\tabl_tabulate_digits} % new, undocumented, test first  \unexpanded\def\tabl_tabulate_ND_first{\NC\tabl_tabulate_digits} % same, for old times sake diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua index 9c7e7ce63..51aa550cb 100644 --- a/tex/context/base/task-ini.lua +++ b/tex/context/base/task-ini.lua @@ -27,6 +27,7 @@ appendaction("processors",   "normalizers", "typesetters.characters.handler")  appendaction("processors",   "normalizers", "fonts.collections.process")                         -- disabled  appendaction("processors",   "normalizers", "fonts.checkers.missing")                            -- disabled +appendaction("processors",   "characters",  "typesetters.characteralign.handler")                -- disabled  appendaction("processors",   "characters",  "scripts.autofontfeature.handler")  appendaction("processors",   "characters",  "scripts.splitters.handler")                         -- disabled  appendaction("processors",   "characters",  "typesetters.cleaners.handler")                      -- disabled @@ -119,6 +120,7 @@ appendaction("vboxbuilders","normalizers","typesetters.checkers.handler")  -- speedup: only kick in when used +disableaction("processors",  "typesetters.characteralign.handler")  disableaction("processors",  "scripts.autofontfeature.handler")  disableaction("processors",  "scripts.splitters.handler")  disableaction("processors",  "scripts.injectors.handler") -- was enabled diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua index 20d08fcce..dc8bcc5e7 100644 --- a/tex/context/base/trac-vis.lua +++ b/tex/context/base/trac-vis.lua @@ -34,10 +34,8 @@ local formatters = string.formatters  -- todo: inline concat (more efficient)  local nodecodes           = nodes.nodecodes -local disc_code           = nodecodes.disc  local kern_code           = nodecodes.kern  local glyph_code          = nodecodes.glyph -local disc_code           = nodecodes.disc  local hlist_code          = nodecodes.hlist  local vlist_code          = nodecodes.vlist  local glue_code           = nodecodes.glue diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua index 2fc3ff13e..cd531f108 100644 --- a/tex/context/base/typo-krn.lua +++ b/tex/context/base/typo-krn.lua @@ -57,8 +57,14 @@ local quaddata           = fonthashes.quads  local markdata           = fonthashes.marks  local fontproperties     = fonthashes.properties  local fontdescriptions   = fonthashes.descriptions +local fontfeatures       = fonthashes.features + +local tracers            = nodes.tracers +local setcolor           = tracers.colors.set +local resetcolor         = tracers.colors.reset  local v_max              = interfaces.variables.max +local v_auto             = interfaces.variables.auto  typesetters              = typesetters or { }  local typesetters        = typesetters @@ -67,13 +73,15 @@ typesetters.kerns        = typesetters.kerns or { }  local kerns              = typesetters.kerns  local report             = logs.reporter("kerns") -local trace_ligatures    = trackers.register("typesetters.kerns.ligatures",function(v) trace_ligatures = v end) +local trace_ligatures    = false  trackers.register("typesetters.kerns.ligatures",function(v) trace_ligatures = v end)  kerns.mapping            = kerns.mapping or { }  kerns.factors            = kerns.factors or { }  local a_kerns            = attributes.private("kern")  local a_fontkern         = attributes.private('fontkern') +local contextsetups      = fonts.specifiers.contextsetups +  storage.register("typesetters/kerns/mapping", kerns.mapping, "typesetters.kerns.mapping")  storage.register("typesetters/kerns/factors", kerns.factors, "typesetters.kerns.factors") @@ -92,20 +100,62 @@ local gluefactor = 4 -- assumes quad = .5 enspace  kerns.keepligature = false -- just for fun (todo: control setting with key/value)  kerns.keeptogether = false -- just for fun (todo: control setting with key/value) +-- red   : kept by dynamic feature +-- green : kept by static feature +-- blue  : keep by goodie +  function kerns.keepligature(n) -- might become default      local f = n.font -    local c = n.char -    local k = fontproperties[f].keptligatures +    local a = n[0] or 0      if trace_ligatures then -        -- mostly for identifying names as they get reported +        local c = n.char          local d = fontdescriptions[f][c].name +        if a > 0 and contextsetups[a].keepligatures == v_auto then +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","dynamic","keepligatures") +            setcolor(n,"darkred") +            return true +        end +        local k = fontfeatures[f].keepligatures +        if k == v_auto then +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","static","keepligatures") +            setcolor(n,"darkgreen") +            return true +        end +        if not k then +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"split","static","keepligatures") +            resetcolor(n) +            return false +        end +        local k = fontproperties[f].keptligatures +        if not k then +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","no") +            resetcolor(n) +            return false +        end          if k and k[c] then -            report("font %s, glyph %a, slot %X -> kept ligature",f,d,c) +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"kept","by") +            setcolor(n,"darkblue")              return true          else -            report("font %s, glyph %a, slot %X -> split ligature",f,d,c) +            report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","by") +            resetcolor(n) +            return false          end      else +        if a > 0 and contextsetups[a].keepligatures == v_auto then +            return true +        end +        local k = fontfeatures[f].keepligatures +        if k == v_auto then +            return true +        end +        if not k then +            return false +        end +        local k = fontproperties[f].keptligatures +        if not k then +            return false +        end          if k and k[c] then              return true          end @@ -136,7 +186,7 @@ local function spec_injector(fillup,width,stretch,shrink)      end  end --- needs checking ... base mode / node mode +-- needs checking ... base mode / node mode -- also use insert_before/after etc  local function do_process(head,force) -- todo: glue so that we can fully stretch      local start, done, lastfont = head, false, nil diff --git a/tex/context/base/typo-krn.mkiv b/tex/context/base/typo-krn.mkiv index a47bd2ac5..3522c02fc 100644 --- a/tex/context/base/typo-krn.mkiv +++ b/tex/context/base/typo-krn.mkiv @@ -40,6 +40,7 @@  \def\typo_kerning_set    {\usecharacterkerningstyleandcolor\c!style\c!color % goodie, maybe also strut +   \useaddfontfeatureparameter\characterkerningparameter     \ctxcommand{setcharacterkerning("\characterkerningparameter\c!factor")}}  \unexpanded\def\resetcharacterkerning % fast one @@ -62,29 +63,55 @@  %D then we always would get a command defined which is not beforehand  %D a good idea. -\definecharacterkerning [\v!kerncharacters] [\c!factor=.125] -  % Here we need to keep the groupedcommand solution as it is  % used as modifier. -\unexpanded\def\kerncharacters -  {\doifnextoptionalelse\typo_kerning_apply_yes\typo_kerning_apply_nop} +% \definecharacterkerning [\v!kerncharacters] [\c!factor=.125] +% \definecharacterkerning [\v!letterspacing ] [\v!kerncharacters] [\c!features=letterspacing] +% +% \unexpanded\def\kerncharacters +%   {\doifnextoptionalelse\typo_kerning_apply_yes\typo_kerning_apply_nop} +% +% \def\typo_kerning_apply_yes[#1]% +%   {\groupedcommand{\typo_kerning_apply_yes_indeed{#1}}\donothing} +% +% \def\typo_kerning_apply_nop +%   {\groupedcommand\typo_kerning_apply_nop_indeed\donothing} +% +% \def\typo_kerning_apply_yes_indeed#1% +%   {\let\currentcharacterkerning\v!kerncharacters +%    \setupcurrentcharacterkerning[\c!factor=#1]% +%    \typo_kerning_set} +% +% \def\typo_kerning_apply_nop_indeed +%   {\let\currentcharacterkerning\v!kerncharacters +%    \typo_kerning_set} -\def\typo_kerning_apply_yes[#1]% -  {\groupedcommand{\typo_kerning_apply_yes_indeed{#1}}\donothing} +\appendtoks +  \setuevalue{\currentcharacterkerning}% +    {\doifnextoptionalelse +       {\typo_kerning_apply_yes{\currentcharacterkerning}}% +       {\typo_kerning_apply_nop{\currentcharacterkerning}}} +\to \everydefinecharacterkerning + +\unexpanded\def\typo_kerning_apply_yes#1[#2]% +  {\groupedcommand{\typo_kerning_apply_yes_indeed{#1}{#2}}\donothing} -\def\typo_kerning_apply_nop -  {\groupedcommand\typo_kerning_apply_nop_indeed\donothing} +\unexpanded\def\typo_kerning_apply_nop#1% +  {\groupedcommand{\typo_kerning_apply_nop_indeed{#1}}\donothing} -\def\typo_kerning_apply_yes_indeed#1% -  {\let\currentcharacterkerning\v!kerncharacters -   \setupcurrentcharacterkerning[\c!factor=#1]% +\def\typo_kerning_apply_yes_indeed#1#2% +  {\edef\currentcharacterkerning{#1}% +   \setupcurrentcharacterkerning[\c!factor=#2]%     \typo_kerning_set} -\def\typo_kerning_apply_nop_indeed -  {\let\currentcharacterkerning\v!kerncharacters +\def\typo_kerning_apply_nop_indeed#1% +  {\edef\currentcharacterkerning{#1}%     \typo_kerning_set} +\definecharacterkerning [\v!kerncharacters] [\c!factor=.125] +\definecharacterkerning [\v!letterspacing ] [\v!kerncharacters] [\c!features=letterspacing] +  %D \macros  %D   {stretched}  %D @@ -133,6 +160,7 @@     \fi     \bgroup     \usecharacterkerningstyleandcolor\c!style\c!color +   \useaddfontfeatureparameter\characterkerningparameter     \typo_kerning_set     #2%     \egroup diff --git a/tex/context/base/typo-tal.lua b/tex/context/base/typo-tal.lua new file mode 100644 index 000000000..3df8dd00a --- /dev/null +++ b/tex/context/base/typo-tal.lua @@ -0,0 +1,265 @@ +if not modules then modules = { } end modules ['typo-tal'] = { +    version   = 1.001, +    comment   = "companion to typo-tal.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- I'll make it a bit more efficient and provide named instances too. + +local next, type = next, type +local div = math.div +local utfbyte = utf.byte + +local nodecodes            = nodes.nodecodes +local glyph_code           = nodecodes.glyph +local glue_code            = nodecodes.glue + +local fontcharacters       = fonts.hashes.characters +local categories           = characters.categories -- nd + +local insert_node_before   = nodes.insert_before +local insert_node_after    = nodes.insert_after +local traverse_list_by_id  = nodes.traverse_id +local dimensions_of_list   = nodes.dimensions +local first_glyph          = nodes.first_glyph + +local nodepool             = nodes.pool +local new_kern             = nodepool.kern +local new_gluespec         = nodepool.gluespec + +local tracers              = nodes.tracers +local setcolor             = tracers.colors.set +local tracedrule           = tracers.pool.nodes.rule + +local characteralign       = { } +typesetters.characteralign = characteralign + +local trace_split          = false  trackers.register("typesetters.characteralign", function(v) trace_split = true end) +local report               = logs.reporter("aligning") + +local a_characteralign     = attributes.private("characteralign") +local a_character          = attributes.private("characters") + +local enabled              = false + +local datasets             = false + +local comma                = 0x002C +local period               = 0x002E +local punctuationspace     = 0x2008 + +local validseparators = { +    [comma]            = true, +    [period]           = true, +    [punctuationspace] = true, +} + +local validsigns = { +    [0x002B] = 0x002B, -- plus +    [0x002D] = 0x2212, -- hyphen +    [0x00B1] = 0x00B1, -- plusminus +    [0x2212] = 0x2212, -- minus +    [0x2213] = 0x2213, -- minusplus +} + +local function traced_kern(w) +    return tracedrule(w,nil,nil,"darkgray") +end + +function characteralign.handler(head,where) +    if not datasets then +        return head, false +    end +    local first = first_glyph(head) -- we could do that once +    if not first then +        return head, false +    end +    local a = first[a_characteralign] +    if not a or a == 0 then +        return head, false +    end +    local column    = div(a,100) +    local row       = a % 100 +    local dataset   = datasets and datasets[column] or setcharacteralign(column) +    local separator = dataset.separator +    local list      = dataset.list +    local b_start   = nil +    local b_stop    = nil +    local a_start   = nil +    local a_stop    = nil +    local c         = nil +    local current   = first +    local sign      = nil +    -- we can think of constraints +    while current do +        local id = current.id +        if id == glyph_code then +            local char = current.char +            if char == separator then +                c = current +                if trace_split then +                    setcolor(current,"darkred") +                end +            elseif categories[char] == "nd" or validseparators[char] then +                if c then +                    if not a_start then +                        a_start = current +                    end +                    a_stop = current +                    if trace_split then +                        setcolor(current,"darkgreen") +                    end +                else +                    if not b_start then +                        if sign then +                            b_start = sign +                            local new = validsigns[sign.char] +                            if char == new or not fontcharacters[sign.font][new] then +                                if trace_split then +                                    setcolor(sign,"darkyellow") +                                end +                            else +                                sign.char = new +                                if trace_split then +                                    setcolor(sign,"darkmagenta") +                                end +                            end +                            sign = nil +                        else +                            b_start = current +                        end +                    end +                    b_stop = current +                    if trace_split then +                        setcolor(current,"darkblue") +                    end +                end +            elseif not b_start then +                sign = validsigns[char] and current +            end +        elseif (b_start or a_start) and id == glue_code then +            -- somewhat inefficient  +            local next = current.next +            local prev = current.prev +            if next and prev and next.id == glyph_code and prev.id == glyph_code then -- too much checking +                local width = fontcharacters[b_start.font][period].width +             -- local spec = current.spec +             -- nodes.free(spec) -- hm, we leak but not that many specs +                current.spec = new_gluespec(width) +                current[a_character] = punctuationspace +            end +        end +        current = current.next +    end +    local entry = list[row] +    if entry then +        if not dataset.collected then +         -- print("[maxbefore] [maxafter]") +            local maxbefore = 0 +            local maxafter  = 0 +            for k, v in next, list do +                local before = v.before +                local after  = v.after +                if before and before > maxbefore then +                    maxbefore = before +                end +                if after and after > maxafter then +                    maxafter = after +                end +            end +            dataset.maxafter  = maxafter +            dataset.maxbefore = maxbefore +            dataset.collected = true +        end +        local maxafter  = dataset.maxafter +        local maxbefore = dataset.maxbefore +        local before    = entry.before or 0 +        local after     = entry.after  or 0 +        local new_kern = trace_split and traced_kern or new_kern +        if b_start then +            if before < maxbefore then +                head = insert_node_before(head,b_start,new_kern(maxbefore-before)) +            end +            if not c then +             -- print("[before]") +                local width = fontcharacters[b_stop.font][separator].width +                insert_node_after(head,b_stop,new_kern(maxafter+width)) +            elseif a_start then +             -- print("[before] [separator] [after]") +                if after < maxafter then +                    insert_node_after(head,a_stop,new_kern(maxafter-after)) +                end +            else +             -- print("[before] [separator]") +                if maxafter > 0 then +                    insert_node_after(head,c,new_kern(maxafter)) +                end +            end +        elseif a_start then +            if c then +             -- print("[separator] [after]") +                if maxbefore > 0 then +                    head = insert_node_before(head,c,new_kern(maxbefore)) +                end +            else +             -- print("[after]") +                local width = fontcharacters[b_stop.font][separator].width +                head = insert_node_before(head,a_start,new_kern(maxbefore+width)) +            end +            if after < maxafter then +                insert_node_after(head,a_stop,new_kern(maxafter-after)) +            end +        elseif c then +         -- print("[separator]") +            if maxbefore > 0 then +                head = insert_node_before(head,c,new_kern(maxbefore)) +            end +            if maxafter > 0 then +                insert_node_after(head,c,new_kern(maxafter)) +            end +        end +    else +        entry = { +            before = b_start and dimensions_of_list(b_start,b_stop.next) or 0, +            after  = a_start and dimensions_of_list(a_start,a_stop.next) or 0, +        } +        list[row] = entry +    end +    return head, true +end + +function setcharacteralign(column,separator) +    if not enabled then +        nodes.tasks.enableaction("processors","typesetters.characteralign.handler") +        enabled = true +    end +    if not datasets then +        datasets = { } +    end +    local dataset = datasets[column] -- we can use a metatable +    if not dataset then +        dataset = { +            separator = separator and utfbyte(separator) or comma, +            list      = { }, +            maxafter  = 0, +            maxbefore = 0, +            collected = false, +        } +        datasets[column] = dataset +        used = true +    end +    return dataset +end + +local function resetcharacteralign() +    datasets = false +end + +characteralign.setcharacteralign   = setcharacteralign +characteralign.resetcharacteralign = resetcharacteralign + +commands.setcharacteralign         = setcharacteralign +commands.resetcharacteralign       = resetcharacteralign + diff --git a/tex/context/base/typo-tal.mkiv b/tex/context/base/typo-tal.mkiv new file mode 100644 index 000000000..f67eadc49 --- /dev/null +++ b/tex/context/base/typo-tal.mkiv @@ -0,0 +1,112 @@ +%D \module +%D   [       file=typo-tal, % spac-cha (2012.06.08) supp-ali (2000.04.17) +%D        version=2013.10.04, +%D          title=\CONTEXT\ Typesetting Macros, +%D       subtitle=Character Alignment, +%D         author=Hans Hagen, +%D           date=\currentdate, +%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Typesetting Macros / Character Alignment} + +%D This module replaces the \MKII\ character alignment code which hooked into +%D table mechanisms but used parsing. In fact, this might be one of these cases +%D where a \TEX\ based solution is faster, but a \LUA\ one a bit more robust. +%D Anyway, as I had to fix something (to fit the newer table mechanisms) I +%D decided to go the mixed route, a rather easy going effort in the aftermath of +%D the 2013 \CONTEXT\ meeting. + +\unprotect + +\registerctxluafile{typo-tal}{1.001} + +\definesystemattribute[characteralign][public] + +%D This mechanism is mostly meant for tables: +%D +%D \startbuffer +%D \starttabulate[|l|g{,}|r|] +%D     \NC test \NC 1.234.456,99 \NC \NC test \NR +%D     \NC test \NC   234.456,9  \NC \NC test \NR +%D     \NC test \NC   234.456    \NC \NC test \NR +%D     \NC test \NC       456    \NC \NC test \NR +%D     \NC test \NC \bf whatever \NC \NC test \NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer \blank \getbuffer \blank + +%D \startbuffer +%D \bTABLE +%D     \bTR \bTD[aligncharacter=yes] €                      1,1     \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €                     11,11    \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] € 12\punctuationspace111,11    \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €                 12 111,11    \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €              1.234.451,22222 \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €                234.451,2     \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €                234.451       \eTD \eTR +%D     \bTR \bTD[aligncharacter=yes] €                    451       \eTD \eTR +%D     \bTR \bTD                     \bf some text                  \eTD \eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \blank \getbuffer \blank + +\unexpanded\def\signalcharacteralign#1#2{\attribute\characteralignattribute=\numexpr#1*\plushundred+#2\relax} +\unexpanded\def\setcharacteralign   #1#2{\ctxcommand{setcharacteralign(\number#1,"#2")}} +\unexpanded\def\resetcharacteralign     {\ctxcommand{resetcharacteralign()}} + +%D Mostly downward compatible: +%D +%D \startbuffer +%D \startcharacteralign +%D     \checkcharacteralign{123.456,78} +%D     \checkcharacteralign{456} +%D     \checkcharacteralign{23.456} +%D     \checkcharacteralign{78,9} +%D \stopcharacteralign +%D \stopbuffer +%D +%D \typebuffer \blank \getbuffer \blank + +\def\alignmentcharacter{,} + +\unexpanded\def\typo_charalign_pass_one +  {\advance\scratchcounter\plusone +   \setbox\scratchbox\typo_charalign_pass} + +\unexpanded\def\typo_charalign_pass_two +  {\advance\scratchcounter\plusone +   \typo_charalign_pass} + +\def\typo_charalign_pass +  {\hbox\bgroup\signalcharacteralign\plusone\scratchcounter\let\next} + +\unexpanded\def\startcharacteralign#1\stopcharacteralign +  {\bgroup +   \setcharacteralign\plusone\alignmentcharacter +   \begingroup +     \scratchcounter\zerocount +     \let\checkcharacteralign\typo_charalign_pass_one +     \settrialtypesetting +     #1\relax +   \endgroup +   \begingroup +     \scratchcounter\zerocount +     \let\checkcharacteralign\typo_charalign_pass_two +     #1\relax +   \endgroup +   \resetcharacteralign +   \egroup} + +\let\stopcharacteralign \relax +\let\checkcharacteralign\gobbleoneargument + +\def\setfirstpasscharacteralign {\let\checkcharacteralign\gobbleoneargument} +\def\setsecondpasscharacteralign{\let\checkcharacteralign\firstofoneargument} + +\endinput diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index ef78f0ef8..2912a1c31 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@  -- merged file : luatex-fonts-merged.lua  -- parent file : luatex-fonts.lua --- merge date  : 10/01/13 20:08:43 +-- merge date  : 10/04/13 23:41:38  do -- begin closure to overcome local limits and interference @@ -9666,6 +9666,7 @@ local default="dflt"  local nodecodes=nodes.nodecodes  local whatcodes=nodes.whatcodes  local glyphcodes=nodes.glyphcodes +local disccodes=nodes.disccodes  local glyph_code=nodecodes.glyph  local glue_code=nodecodes.glue  local disc_code=nodecodes.disc @@ -9673,6 +9674,7 @@ local whatsit_code=nodecodes.whatsit  local math_code=nodecodes.math  local dir_code=whatcodes.dir  local localpar_code=whatcodes.localpar +local discretionary_code=disccodes.discretionary  local ligature_code=glyphcodes.ligature  local privateattribute=attributes.private  local a_state=privateattribute('state') @@ -9920,13 +9922,13 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives      end    end  end -local function multiple_glyphs(head,start,multiple)  +local function multiple_glyphs(head,start,multiple,ignoremarks)    local nofmultiples=#multiple    if nofmultiples>0 then      setfield(start,"char",multiple[1])      if nofmultiples>1 then        local sn=getnext(start) -      for k=2,nofmultiples do  +      for k=2,nofmultiples do          local n=copy_node(start)           setfield(n,"char",multiple[k])          setfield(n,"next",sn) @@ -9961,11 +9963,11 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence    end    return head,start,true  end -function handlers.gsub_multiple(head,start,kind,lookupname,multiple) +function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)    if trace_multiples then      logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(getchar(start)),gref(multiple))    end -  return multiple_glyphs(head,start,multiple) +  return multiple_glyphs(head,start,multiple,sequence.flags[1])  end  function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)    local s,stop,discfound=getnext(start),nil,false @@ -10299,7 +10301,6 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)          prev=snext          snext=getnext(snext)        else -        local krn=kerns[nextchar]          if not krn then          elseif type(krn)=="table" then            if lookuptype=="pair" then  @@ -10372,34 +10373,6 @@ function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,loo      return head,start,false    end  end -local function delete_till_stop(start,stop,ignoremarks)  -  local n=1 -  if start==stop then -  elseif ignoremarks then -    repeat  -      local next=getnext(start) -      if not marks[getchar(next)] then -        local components=getfield(next,"components") -        if components then  -          flush_node_list(components) -        end -        delete_node(start,next) -      end -      n=n+1 -    until next==stop -  else  -    repeat -      local next=getnext(start) -      local components=getfield(next,"components") -      if components then  -        flush_node_list(components) -      end -      delete_node(start,next) -      n=n+1 -    until next==stop -  end -  return n -end  function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)    local current=start    local subtables=currentlookup.subtables @@ -10439,7 +10412,6 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo  end  chainmores.gsub_single=chainprocs.gsub_single  function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) -  delete_till_stop(start,stop)     local startchar=getchar(start)    local subtables=currentlookup.subtables    local lookupname=subtables[1] @@ -10458,7 +10430,7 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,        if trace_multiples then          logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))        end -      return multiple_glyphs(head,start,replacements) +      return multiple_glyphs(head,start,replacements,currentlookup.flags[1])      end    end    return head,start,false @@ -10842,6 +10814,7 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo    end    return head,start,false  end +chainmores.gpos_single=chainprocs.gpos_single  function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)    local snext=getnext(start)    if snext then @@ -10910,6 +10883,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look    end    return head,start,false  end +chainmores.gpos_pair=chainprocs.gpos_pair  local function show_skip(kind,chainname,char,ck,class)    if ck[9] then      logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) @@ -11126,7 +11100,11 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq            if chainlookup then              local cp=chainprocs[chainlookup.type]              if cp then -              head,start,done=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) +              local ok +              head,start,ok=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) +              if ok then +                done=true +              end              else                logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)              end @@ -11153,19 +11131,24 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq                end              end              local chainlookupname=chainlookups[i] -            local chainlookup=lookuptable[chainlookupname]  -            local cp=chainlookup and chainmores[chainlookup.type] -            if cp then -              local ok,n -              head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) -              if ok then -                done=true -                i=i+(n or 1) -              else +            local chainlookup=lookuptable[chainlookupname] +            if not chainlookup then +              i=i+1 +            else +              local cp=chainmores[chainlookup.type] +              if not cp then +                logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)                  i=i+1 +              else +                local ok,n +                head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) +                if ok then +                  done=true +                  i=i+(n or 1) +                else +                  i=i+1 +                end                end -            else -              i=i+1              end              if start then                start=getnext(start) @@ -11375,6 +11358,40 @@ local function featuresprocessor(head,font,attr)          if not lookupcache then             report_missing_cache(typ,lookupname)          else +          local function subrun(start) +            local head=start +            local done=false +            while start do +              local id=getid(start) +              if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then +                local a=getattr(start,0) +                if a then +                  a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) +                else +                  a=not attribute or getattr(start,a_state)==attribute +                end +                if a then +                  local lookupmatch=lookupcache[getchar(start)] +                  if lookupmatch then +                    local ok +                    head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) +                    if ok then +                      done=true +                    end +                  end +                  if start then start=getnext(start) end +                else +                  start=getnext(start) +                end +              else +                start=getnext(start) +              end +            end +            if done then +              success=true +              return head +            end +          end            while start do              local id=getid(start)              if id==glyph_code then @@ -11401,6 +11418,25 @@ local function featuresprocessor(head,font,attr)                else                  start=getnext(start)                end +            elseif id==disc_code then +              if getsubtype(start)==discretionary_code then +                local pre=getfield(start,"pre") +                if pre then +                  local new=subrun(pre) +                  if new then setfield(start,"pre",new) end +                end +                local post=getfield(start,"post") +                if post then +                  local new=subrun(post) +                  if new then setfield(start,"post",new) end +                end +                local replace=getfield(start,"replace") +                if replace then +                  local new=subrun(replace) +                  if new then setfield(start,"replace",new) end +                end +              end +              start=getnext(start)              elseif id==whatsit_code then                 local subtype=getsubtype(start)                if subtype==dir_code then @@ -11445,6 +11481,51 @@ local function featuresprocessor(head,font,attr)            end          end        else +        local function subrun(start) +          local head=start +          local done=false +          while start do +            local id=getid(start) +            if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then +              local a=getattr(start,0) +              if a then +                a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) +              else +                a=not attribute or getattr(start,a_state)==attribute +              end +              if a then +                for i=1,ns do +                  local lookupname=subtables[i] +                  local lookupcache=lookuphash[lookupname] +                  if lookupcache then +                    local lookupmatch=lookupcache[getchar(start)] +                    if lookupmatch then +                      local ok +                      head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) +                      if ok then +                        done=true +                        break +                      elseif not start then +                        break +                      end +                    end +                  else +                    report_missing_cache(typ,lookupname) +                  end +                end +                if start then start=getnext(start) end +              else +                start=getnext(start) +              end +            else +              start=getnext(start) +            end +          end +          if done then +            success=true +            return head +          end +        end          while start do            local id=getid(start)            if id==glyph_code then @@ -11482,6 +11563,25 @@ local function featuresprocessor(head,font,attr)              else                start=getnext(start)              end +          elseif id==disc_code then +            if getsubtype(start)==discretionary_code then +              local pre=getfield(start,"pre") +              if pre then +                local new=subrun(pre) +                if new then setfield(start,"pre",new) end +              end +              local post=getfield(start,"post") +              if post then +                local new=subrun(post) +                if new then setfield(start,"post",new) end +              end +              local replace=getfield(start,"replace") +              if replace then +                local new=subrun(replace) +                if new then setfield(start,"replace",new) end +              end +            end +            start=getnext(start)            elseif id==whatsit_code then              local subtype=getsubtype(start)              if subtype==dir_code then  | 
