diff options
Diffstat (limited to 'tex')
30 files changed, 1703 insertions, 329 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index ede175893..d256c24d9 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2017.04.08 12:09} +\newcontextversion{2017.04.16 12:32}  %D This file is loaded at runtime, thereby providing an  %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index cc11308ef..26595dd56 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@  %D your styles an modules.  \edef\contextformat {\jobname} -\edef\contextversion{2017.04.08 12:09} +\edef\contextversion{2017.04.16 12:32}  %D For those who want to use this: diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 3b0c97ff0..0d9ecfdd7 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2017.04.08 12:09} +\newcontextversion{2017.04.16 12:32}  %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/mkiv/cont-run.lua b/tex/context/base/mkiv/cont-run.lua index d9dad3f2d..2225a0fb2 100644 --- a/tex/context/base/mkiv/cont-run.lua +++ b/tex/context/base/mkiv/cont-run.lua @@ -180,6 +180,10 @@ local function processjob()      local suffix    = environment.suffix      local filename  = environment.filename -- hm, not inputfilename ! +    if arguments.synctex then +        directives.enable("system.synctex="..tostring(arguments.synctex)) +    end +      if not filename or filename == "" then          -- skip      elseif suffix == "xml" or arguments.forcexml then diff --git a/tex/context/base/mkiv/cont-run.mkiv b/tex/context/base/mkiv/cont-run.mkiv index fcca7b581..490c6bee2 100644 --- a/tex/context/base/mkiv/cont-run.mkiv +++ b/tex/context/base/mkiv/cont-run.mkiv @@ -15,6 +15,7 @@  \unprotect +\registerctxluafile{node-syn}{1.001}  \registerctxluafile{cont-run}{1.001}  \protect \endinput diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 14f619247..c4446b3dd 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@  %D up and the dependencies are more consistent.  \edef\contextformat {\jobname} -\edef\contextversion{2017.04.08 12:09} +\edef\contextversion{2017.04.16 12:32}  \edef\contextkind   {beta}  %D For those who want to use this: @@ -403,6 +403,7 @@  \loadmarkfile{tabl-ntb}  \loadmarkfile{tabl-nte}  \loadmarkfile{tabl-ltb} +\loadmarkfile{tabl-frm}  \loadmarkfile{tabl-tsp}  \loadmkvifile{tabl-xtb}  \loadmarkfile{tabl-mis} diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 0e64511e2..9e53b2c25 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -156,16 +156,17 @@ end  helpers.name = getfontname +local addformatter = utilities.strings.formatters.add +  if _LUAVERSION < 5.2  then -    formatters.add(formatters,"font:name",    [["'"..fontname(%s).."'"]],          "local fontname  = fonts.helpers.name") -    formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced") +    addformatter(formatters,"font:name",    [["'"..fontname(%s).."'"]],          "local fontname  = fonts.helpers.name") +    addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced")  else -    -- somehow can fail: -    formatters.add(formatters,"font:name",    [["'"..fontname(%s).."'"]],          { fontname  = helpers.name }) -    formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced }) +    addformatter(formatters,"font:name",    [["'"..fontname(%s).."'"]],          { fontname  = helpers.name }) +    addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced })  end @@ -183,12 +184,12 @@ do      local shares = { }      local hashes = { } -local nofinstances = 0 -local instances    = table.setmetatableindex(function(t,k) -    nofinstances = nofinstances + 1 -    t[k] = nofinstances -    return nofinstances -end) +    local nofinstances = 0 +    local instances    = table.setmetatableindex(function(t,k) +        nofinstances = nofinstances + 1 +        t[k] = nofinstances +        return nofinstances +    end)      function constructors.trytosharefont(target,tfmdata)          constructors.noffontsloaded = constructors.noffontsloaded + 1 @@ -347,21 +348,13 @@ otftables.scripts.auto = "automatic fallback to latn when no dflt present"  -- setmetatableindex(otffeatures.descriptions,otftables.features) -local privatefeatures = { -- this can go away -    tlig = true, -    trep = true, -    anum = true, -} -  local function checkedscript(tfmdata,resources,features)      local latn   = false      local script = false      if resources.features then          for g, list in next, resources.features do              for f, scripts in next, list do -                if privatefeatures[f] then -                    -- skip -                elseif scripts.dflt then +                if scripts.dflt then                      script = "dflt"                      break                  elseif scripts.latn then diff --git a/tex/context/base/mkiv/font-def.lua b/tex/context/base/mkiv/font-def.lua index 6765be9d3..c8394badf 100644 --- a/tex/context/base/mkiv/font-def.lua +++ b/tex/context/base/mkiv/font-def.lua @@ -11,8 +11,9 @@ if not modules then modules = { } end modules ['font-def'] = {  local lower, gsub = string.lower, string.gsub  local tostring, next = tostring, next  local lpegmatch = lpeg.match -local suffixonly, removesuffix = file.suffix, file.removesuffix +local suffixonly, removesuffix, basename = file.suffix, file.removesuffix, file.basename  local formatters = string.formatters +local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys  local allocate = utilities.storage.allocate @@ -203,9 +204,9 @@ function resolvers.name(specification)                      features.normal = normal                  end                  normal.instance = instance -if not callbacks.supported.glyph_stream_provider then -    normal.variableshapes = true -- for the moment -end +                if not callbacks.supported.glyph_stream_provider then +                    normal.variableshapes = true -- for the moment +                end              end              --              local suffix = lower(suffixonly(resolved)) @@ -313,6 +314,65 @@ local function checkembedding(tfmdata)      tfmdata.embedding = embedding  end +local function checkfeatures(tfmdata) +    local resources = tfmdata.resources +    local shared    = tfmdata.shared +    if resources and shared then +        local features     = resources.features +        local usedfeatures = shared.features +        if features and usedfeatures then +            local usedlanguage = usedfeatures.language or "dflt" +            local usedscript   = usedfeatures.script or "dflt" +            local function check(what) +                if what then +                    local foundlanguages = { } +                    for feature, scripts in next, what do +                        if usedscript == "auto" or scripts["*"] then +                            -- ok +                        elseif not scripts[usedscript] then +                         -- report_defining("font %!font:name!, feature %a, no script %a", +                         --     tfmdata,feature,usedscript) +                        else +                            for script, languages in next, scripts do +                                if languages["*"] then +                                    -- ok +                                elseif not languages[usedlanguage] then +                                    report_defining("font %!font:name!, feature %a, script %a, no language %a", +                                        tfmdata,feature,script,usedlanguage) +                                end +                            end +                        end +                        for script, languages in next, scripts do +                            for language in next, languages do +                                foundlanguages[language] = true +                            end +                        end +                    end +                    if false then +                        foundlanguages["*"] = nil +                        foundlanguages = sortedkeys(foundlanguages) +                        for feature, scripts in sortedhash(what) do +                            for script, languages in next, scripts do +                                if not languages["*"] then +                                    for i=1,#foundlanguages do +                                        local language = foundlanguages[i] +                                        if not languages[language] then +                                            report_defining("font %!font:name!, feature %a, script %a, no language %a", +                                                tfmdata,feature,script,language) +                                        end +                                    end +                                end +                            end +                        end +                    end +                end +            end +            check(features.gsub) +            check(features.gpos) +        end +    end +end +  function definers.loadfont(specification)      local hash = constructors.hashinstance(specification)      -- todo: also hash by instance / factors @@ -347,6 +407,7 @@ function definers.loadfont(specification)              checkembedding(tfmdata) -- todo: general postprocessor              loadedfonts[hash] = tfmdata              designsizes[specification.hash] = tfmdata.parameters.designsize +            checkfeatures(tfmdata)          end      end      if not tfmdata then @@ -458,7 +519,7 @@ function definers.read(specification,size,id) -- id can be optional, name can al          local parameters = tfmdata.parameters or { }          report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",              properties.format or "unknown", id, properties.name, parameters.size, properties.encodingbytes, -            properties.encodingname, properties.fullname, file.basename(properties.filename)) +            properties.encodingname, properties.fullname, basename(properties.filename))      end      statistics.stoptiming(fonts)      return tfmdata diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index 76bc5912d..d2aea7037 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -3024,6 +3024,195 @@ function readers.svg(f,fontdata,specification)      fontdata.hascolor = true  end +function readers.sbix(f,fontdata,specification) +    local tableoffset = gotodatatable(f,fontdata,"sbix",specification.glyphs) +    if tableoffset then +        local version    = readushort(f) +        local flags      = readushort(f) +        local nofstrikes = readulong(f) +        local strikes    = { } +        local nofglyphs  = fontdata.nofglyphs +        for i=1,nofstrikes do +            strikes[i] = readulong(f) +        end +     -- if true then +            local shapes = { } +            local done   = 0 +            for i=1,nofstrikes do +                local strikeoffset = strikes[i] + tableoffset +                setposition(f,strikeoffset) +                strikes[i] = { +                    ppem   = readushort(f), +                    ppi    = readushort(f), +                    offset = strikeoffset +                } +            end +            -- highest first +            sort(strikes,function(a,b) +                if b.ppem == a.ppem then +                    return b.ppi < a.ppi +                else +                    return b.ppem < a.ppem +                end +            end) +            local glyphs = { } +            for i=1,nofstrikes do +                local strike = strikes[i] +                local strikeppem   = strike.ppem +                local strikeppi    = strike.ppi +                local strikeoffset = strike.offset +                setposition(f,strikeoffset) +                for i=0,nofglyphs do +                    glyphs[i] = readulong(f) +                end +                local glyphoffset = glyphs[0] +                for i=0,nofglyphs-1 do +                    local nextoffset = glyphs[i+1] +                    if not shapes[i] then +                        local datasize = nextoffset - glyphoffset +                        if datasize > 0 then +                            setposition(f,strikeoffset + glyphoffset) +                            shapes[i] = { +                                x    = readshort(f), +                                y    = readshort(f), +                                tag  = readtag(f), -- maybe for tracing +                                data = readstring(f,datasize-8), +                                ppem = strikeppem, -- not used, for tracing +                                ppi  = strikeppi,  -- not used, for tracing +                            } +                            done = done + 1 +                            if done == nofglyphs then +                                break +                            end +                        end +                    end +                    glyphoffset = nextoffset +                end +            end +            fontdata.sbixshapes = shapes +     -- else +     --     for i=1,nofstrikes do +     --         local strikeoffset = strikes[i] + tableoffset +     --         setposition(f,strikeoffset) +     --         local glyphs = { } +     --         strikes[i] = { +     --             ppem   = readushort(f), +     --             ppi    = readushort(f), +     --             glyphs = glyphs, +     --         } +     --         for i=0,nofglyphs do +     --             glyphs[i] = readulong(f) +     --         end +     --         local glyphoffset = glyphs[0] +     --         for i=0,nofglyphs-1 do +     --             local nextoffset = glyphs[i+1] +     --             local datasize   = nextoffset - glyphoffset +     --             if datasize > 0 then +     --                 setposition(f,strikeoffset + glyphoffset) +     --                 glyphs[i] = { +     --                     x    = readshort(f), +     --                     y    = readshort(f), +     --                     tag  = readtag(f), +     --                     data = readstring(f,datasize-8) +     --                 } +     --                 glyphoffset = nextoffset +     --             end +     --         end +     --     end +     --     fontdata.sbixshapes = strikes +     -- end +    end +end + +-- function readers.cblc(f,fontdata,specification) +--     local tableoffset = gotodatatable(f,fontdata,"cblc",specification.glyphs) +--     if tableoffset then +--     end +-- end +-- +-- function readers.cbdt(f,fontdata,specification) +--     local tableoffset = gotodatatable(f,fontdata,"ctdt",specification.glyphs) +--     if tableoffset then +-- +--         local function getmetrics(f) +--             return { +--                 ascender              = readinteger(f), +--                 descender             = readinteger(f), +--                 widthmax              = readcardinal(f), +--                 caretslopedumerator   = readinteger(f), +--                 caretslopedenominator = readinteger(f), +--                 caretoffset           = readinteger(f), +--                 minorigin             = readinteger(f), +--                 minadvance            = readinteger(f), +--                 maxbefore             = readinteger(f), +--                 minafter              = readinteger(f), +--                 pad1                  = readinteger(f), +--                 pad2                  = readinteger(f), +--             } +--         end +-- +--         local majorversion  = readushort(f) +--         local minorversion  = readushort(f) +--         local nofsizetables = readulong(f) +--         local sizetable     = { } +--         for i=1,nofsizetables do +--             sizetable[i] = { +--                 subtables    = readulong(f), +--                 indexsize    = readulong(f), +--                 nofsubtables = readulong(f), +--                 colorref     = readulong(f), +--                 hormetrics   = getmetrics(f), +--                 vermetrics   = getmetrics(f), +--                 firstindex   = readushort(f), +--                 lastindex    = readushort(f), +--                 ppemx        = readbyte(f), +--                 ppemy        = readbyte(f), +--                 bitdepth     = readbyte(f), +--                 flags        = readbyte(f), +--             } +--         end +-- +--         sort(sizetable,function(a,b) +--             if b.ppemx == a.ppemx then +--                 return b.bitdepth < a.bitdepth +--             else +--                 return b.ppemx < a.ppemx +--             end +--         end) +-- +--         local shapes = { } +-- +--         for i=1,nofsizetables do +--             local s = sizetables[i] +--             for j=firstindex,lastindex do +--                 if not shapes[j] then +--                     shapes[j] = { +--                         i +--                     } +--                 end +--             end +--         end +-- +--         inspect(shapes) +-- +--     end +-- end + +-- function readers.ebdt(f,fontdata,specification) +--     if specification.glyphs then +--     end +-- end + +-- function readers.ebsc(f,fontdata,specification) +--     if specification.glyphs then +--     end +-- end + +-- function readers.eblc(f,fontdata,specification) +--     if specification.glyphs then +--     end +-- end +  -- + AVAR : optional  -- + CFF2 : otf outlines  -- - CVAR : ttf hinting, not needed diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index 68d9ac650..2cb0c1eb7 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['font-ocl'] = {  local tostring, next, format = tostring, next, string.format  local round, max = math.round, math.round +local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash  local formatters = string.formatters  local tounicode  = fonts.mappings.tounicode @@ -175,14 +176,8 @@ fonts.handlers.otf.features.register {      }  } -local otfsvg   = otf.svg or { } -otf.svg        = otfsvg -otf.svgenabled = true -  do -    local nofstreams = 0 -   -- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ]   -- local f_getstream = formatters[ [[svg-glyph-%05i]] ] @@ -194,47 +189,125 @@ do   --     end   -- end -    local f_name = formatters[ [[svg-glyph-%05i]] ] -    local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] +    local nofstreams = 0 +    local f_name     = formatters[ [[pdf-glyph-%05i]] ] +    local f_used     = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] +    local hashed     = { } +    local cache      = { } + +    function otf.storepdfdata(pdf) +        local done = hashed[pdf] +        if not done then +            nofstreams = nofstreams + 1 +            local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) +            cache[n] = o -- we need to keep in mem +            done = f_used(n) +            hashed[pdf] = done +        end +        return nil, done, nil +    end -    local cache = { } + -- maybe more efficient but much slower (and we hash already) + -- + -- if context then + -- + --     local storepdfdata = otf.storepdfdata + --     local initialized  = false + -- + --     function otf.storepdfdata(pdf) + --         if not initialized then + --             if resolvers.setmemstream then + --                 local f_setstream = formatters[ [[resolvers.setmemstream("pdf-glyph-%05i",%q,true)]] ] + --                 local f_getstream = formatters[ [[memstream:///pdf-glyph-%05i]] ] + --                 local f_nilstream = formatters[ [[resolvers.resetmemstream("pdf-glyph-%05i",true)]] ] + --                 storepdfdata = function(pdf) + --                     local done  = hashed[pdf] + --                     local set   = nil + --                     local reset = nil + --                     if not done then + --                         nofstreams = nofstreams + 1 + --                         set   = f_setstream(nofstreams,pdf) + --                         done  = f_getstream(nofstreams) + --                         reset = f_nilstream(nofstreams) + --                         hashed[pdf] = done + --                     end + --                     return set, done, reset + --                 end + --                 otf.storepdfdata = storepdfdata + --             end + --             initialized = true + --         end + --         return storepdfdata(pdf) + --     end + -- + -- end -    function otfsvg.storepdfdata(pdf) -        nofstreams = nofstreams + 1 -        local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) -        cache[n] = o -- we need to keep in mem -        return nil, f_used(n), nil -    end +end -    if context then - -        local storepdfdata = otfsvg.storepdfdata -        local initialized  = false - -        function otfsvg.storepdfdata(pdf) -            if not initialized then -                if resolvers.setmemstream then -                    local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ] -                    local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ] -                    local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ] -                    storepdfdata = function(pdf) -                        nofstreams = nofstreams + 1 -                        return -                            f_setstream(nofstreams,pdf), -                            f_getstream(nofstreams), -                            f_nilstream(nofstreams) -                    end -                    otfsvg.storepdfdata = storepdfdata +local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg +    if not tfmdata or not pdfshapes or not kind then +        return +    end +    -- +    local characters = tfmdata.characters +    local properties = tfmdata.properties +    local parameters = tfmdata.parameters +    local hfactor    = parameters.hfactor +    -- +    properties.virtualized = true +    -- +    tfmdata.fonts = { +        { id = 0 } +    } +        -- +    local getactualtext = otf.getactualtext +    local storepdfdata  = otf.storepdfdata +    -- + -- local nop = { "nop" } +    -- +    for unicode, character in sortedhash(characters) do  -- sort is nicer for svg +        local index = character.index +        if index then +            local pdf  = pdfshapes[index] +            local typ  = type(pdf) +            local data = nil +            local dx   = nil +            local dy   = nil +            if typ == "table" then +                data = pdf.data +                dx   = pdf.dx or 0 +                dy   = pdf.dy or 0 +            elseif typ == "string" then +                data = pdf +                dx   = 0 +                dy   = 0 +            end +            if data then +                local setcode, name, nilcode = storepdfdata(data) +                if name then +                    local bt, et = getactualtext(unicode) +                    local wd = character.width  or 0 +                    local ht = character.height or 0 +                    local dp = character.depth  or 0 +                    character.commands = { +                        { "special", "pdf:direct:" .. bt }, +                        { "down", dp + dy * hfactor }, +                        { "right", dx * hfactor }, +                     -- setcode and { "lua", setcode } or nop, +                        { "image", { filename = name, width = wd, height = ht, depth = dp } }, +                     -- nilcode and { "lua", nilcode } or nop, +                        { "special", "pdf:direct:" .. et }, +                    } +                    character[kind] = true                  end -                initialized = true              end -            return storepdfdata(pdf)          end -      end -  end +local otfsvg   = otf.svg or { } +otf.svg         = otfsvg +otf.svgenabled  = true  do @@ -323,7 +396,7 @@ do              end              statistics.stoptiming()              if statistics.elapsedseconds then -                report_svg("svg conversion time %s",statistics.elapsedseconds()) +                report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")              end          end          return pdfshapes @@ -333,17 +406,12 @@ end  local function initializesvg(tfmdata,kind,value) -- hm, always value      if value and otf.svgenabled then -        local characters   = tfmdata.characters -        local descriptions = tfmdata.descriptions -        local properties   = tfmdata.properties -        -- -        local svg       = properties.svg +        local svg       = tfmdata.properties.svg          local hash      = svg and svg.hash          local timestamp = svg and svg.timestamp          if not hash then              return          end -        --          local pdffile   = containers.read(otf.pdfcache,hash)          local pdfshapes = pdffile and pdffile.pdfshapes          if not pdfshapes or pdffile.timestamp ~= timestamp then @@ -355,44 +423,7 @@ local function initializesvg(tfmdata,kind,value) -- hm, always value                  timestamp = timestamp,              })          end -        if not pdfshapes or not next(pdfshapes) then -            return -        end -        -- -        properties.virtualized = true -        tfmdata.fonts = { -            { id = 0 } -        } -        -- -        local getactualtext = otf.getactualtext -        local storepdfdata  = otfsvg.storepdfdata -        -- -        local nop = { "nop" } -        -- -        for unicode, character in next, characters do -            local index = character.index -            if index then -                local pdf = pdfshapes[index] -                if pdf then -                    local setcode, name, nilcode = storepdfdata(pdf) -                    if name then -                        local bt, et = getactualtext(unicode) -                        local wd = character.width  or 0 -                        local ht = character.height or 0 -                        local dp = character.depth  or 0 -                        character.commands = { -                            { "special", "pdf:direct:" .. bt }, -                            { "down", dp }, -                            setcode and { "lua", setcode } or nop, -                            { "image", { filename = name, width = wd, height = ht, depth = dp } }, -                            nilcode and { "lua", nilcode } or nop, -                            { "special", "pdf:direct:" .. et }, -                        } -                        character.svg = true -                    end -                end -            end -        end +        pdftovirtual(tfmdata,pdfshapes,"svg")      end  end @@ -404,3 +435,114 @@ fonts.handlers.otf.features.register {          node = initializesvg,      }  } + +-- This can be done differently e.g. with ffi and gm and we can share code anway. Using +-- batchmode in gm is not faster and as it accumulates we would need to flush all +-- individual shapes. + +local otfsbix   = otf.sbix or { } +otf.sbix        = otfsbix +otf.sbixenabled = true + +do + +    -- for now png but also other bitmap formats + +    local report_sbix = logs.reporter("fonts","sbix conversion") + +    local loaddata   = io.loaddata +    local savedata   = io.savedata +    local remove     = os.remove + +    local runner = sandbox and sandbox.registerrunner { +        name     = "otfsbix", +        program  = "gm", +        template = "convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log", +     -- reporter = report_sbix, +    } + +    if not runner then +        -- +        -- poor mans variant for generic: +        -- +        runner = function() +            return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log") +        end +    end + +    -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from +    -- that file but creating thousands of small files is no fun either. + +    function otfsbix.topdf(sbixshapes) +        local pdfshapes  = { } +        local sbixfile   = "temp-otf-sbix-shape.sbix" +        local pdffile    = "temp-otf-sbix-shape.pdf" +        local nofdone    = 0 +        local indices    = sortedkeys(sbixshapes) -- can be sparse +        local nofindices = #indices +        report_sbix("processing %i sbix containers",nofindices) +        statistics.starttiming() +        for i=1,nofindices do +            local index = indices[i] +            local entry = sbixshapes[index] +            local data  = entry.data +            local x     = entry.x +            local y     = entry.y +            savedata(sbixfile,data) +            runner() +            pdfshapes[index] = { +                x     = x ~= 0 and x or nil, +                y     = y ~= 0 and y or nil, +                data  = loaddata(pdffile), +            } +            nofdone = nofdone + 1 +            if nofdone % 100 == 0 then +                report_sbix("%i shapes processed",nofdone) +            end +        end +        report_sbix("processing %i pdf results",nofindices) +        remove(sbixfile) +        remove(pdffile) +        statistics.stoptiming() +        if statistics.elapsedseconds then +            report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-") +        end +        return pdfshapes +     -- end +    end + +end + +local function initializesbix(tfmdata,kind,value) -- hm, always value +    if value and otf.sbixenabled then +        local sbix      = tfmdata.properties.sbix +        local hash      = sbix and sbix.hash +        local timestamp = sbix and sbix.timestamp +        if not hash then +            return +        end +        local pdffile   = containers.read(otf.pdfcache,hash) +        local pdfshapes = pdffile and pdffile.pdfshapes +        if not pdfshapes or pdffile.timestamp ~= timestamp then +            local sbixfile   = containers.read(otf.sbixcache,hash) +            local sbixshapes = sbixfile and sbixfile.sbixshapes +            pdfshapes = sbixshapes and otfsbix.topdf(sbixshapes) or { } +            containers.write(otf.pdfcache, hash, { +                pdfshapes = pdfshapes, +                timestamp = timestamp, +            }) +        end +        -- +        pdftovirtual(tfmdata,pdfshapes,"sbix") +    end +end + +fonts.handlers.otf.features.register { +    name         = "sbix", +    description  = "sbix glyphs", +    manipulators = { +        base = initializesbix, +        node = initializesbix, +    } +} + diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index bed2adf85..1866591b4 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -10,7 +10,6 @@ local format, insert, sortedkeys, tohash = string.format, table.insert, table.so  local type, next = type, next  local lpegmatch = lpeg.match  local utfbyte, utflen, utfsplit = utf.byte, utf.len, utf.split -local settings_to_array = utilities.parsers.settings_to_array  -- we assume that the other otf stuff is loaded already @@ -1040,6 +1039,9 @@ registerotffeature {      description = 'block certain ligatures',  } +local settings_to_array = utilities.parsers and utilities.parsers.settings_to_array +                       or function(s) return string.split(s,",") end -- for generic +  local function blockligatures(str)      local t = settings_to_array(str) diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index 9e4e255e3..c0b152a5b 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -53,11 +53,13 @@ local fonts               = fonts  local otf                 = fonts.handlers.otf  otf.version               = 3.028 -- beware: also sync font-mis.lua and in mtx-fonts -otf.cache                 = containers.define("fonts", "otl", otf.version, true) -otf.svgcache              = containers.define("fonts", "svg", otf.version, true) -otf.pdfcache              = containers.define("fonts", "pdf", otf.version, true) +otf.cache                 = containers.define("fonts", "otl",  otf.version, true) +otf.svgcache              = containers.define("fonts", "svg",  otf.version, true) +otf.sbixcache             = containers.define("fonts", "sbix", otf.version, true) +otf.pdfcache              = containers.define("fonts", "pdf",  otf.version, true)  otf.svgenabled            = false +otf.sbixenabled           = false  local otfreaders          = otf.readers @@ -127,8 +129,10 @@ function otf.load(filename,sub,instance)          starttiming(otfreaders)          data = otfreaders.loadfont(filename,sub or 1,instance) -- we can pass the number instead (if it comes from a name search)          if data then -            local resources = data.resources -            local svgshapes = resources.svgshapes +            -- todo: make this a plugin +            local resources  = data.resources +            local svgshapes  = resources.svgshapes +            local sbixshapes = resources.sbixshapes              if svgshapes then                  resources.svgshapes = nil                  if otf.svgenabled then @@ -144,6 +148,22 @@ function otf.load(filename,sub,instance)                      }                  end              end +            if sbixshapes then +                resources.sbixshapes = nil +                if otf.sbixenabled then +                    local timestamp = os.date() +                    -- work in progress ... a bit boring to do +                    containers.write(otf.sbixcache,hash, { +                        sbixshapes = sbixshapes, +                        timestamp  = timestamp, +                    }) +                    data.properties.sbix = { +                        hash      = hash, +                        timestamp = timestamp, +                    } +                end +            end +            --              otfreaders.compact(data)              otfreaders.rehash(data,"unicodes")              otfreaders.addunicodetable(data) diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 3935ca735..fcfe6e824 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -133,15 +133,6 @@ end  local tableversion    = 0.004  readers.tableversion  = tableversion  local privateoffset   = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF -local reportedskipped = { } - - -local function reportskippedtable(tag) -    if not reportedskipped[tag] then -        report("loading of table %a skipped (reported once only)",tag) -        reportedskipped[tag] = true -    end -end  -- We have quite some data tables. We are somewhat ff compatible with names but as I used  -- the information from the microsoft site there can be differences. Eventually I might end @@ -720,6 +711,15 @@ local function gotodatatable(f,fontdata,tag,criterium)      end  end +local function reportskippedtable(f,fontdata,tag,criterium) +    if criterium and f then +        local datatable = fontdata.tables[tag] +        if datatable then +            report("loading of table %a skipped",tag) +        end +    end +end +  local function setvariabledata(fontdata,tag,data)      local variabledata = fontdata.variabledata      if variabledata then @@ -729,8 +729,9 @@ local function setvariabledata(fontdata,tag,data)      end  end -helpers.gotodatatable   = gotodatatable -helpers.setvariabledata = setvariabledata +helpers.gotodatatable      = gotodatatable +helpers.setvariabledata    = setvariabledata +helpers.reportskippedtable = reportskippedtable  -- The name table is probably the first one to load. After all this one provides  -- useful information about what we deal with. The complication is that we need @@ -1181,9 +1182,7 @@ readers.vmtx = function(f,fontdata,specification)  end  readers.vorg = function(f,fontdata,specification) -    if specification.glyphs then -     -- reportskippedtable("vorg") -    end +    reportskippedtable(f,fontdata,"vorg",specification.glyphs)  end  -- The post table relates to postscript (printing) but has some relevant properties for other @@ -1254,9 +1253,7 @@ readers.post = function(f,fontdata,specification)  end  readers.cff = function(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("cff") -    end +    reportskippedtable(f,fontdata,"cff",specification.glyphs)  end  -- Not all cmaps make sense .. e.g. dfont is obsolete and probably more are not relevant. Let's see @@ -1745,35 +1742,55 @@ end  -- although we not need it in our usage (yet). We can remove the locations table when we're done.  function readers.loca(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("loca") -    end +    reportskippedtable(f,fontdata,"loca",specification.glyphs)  end  function readers.glyf(f,fontdata,specification) -- part goes to cff module -    if specification.glyphs then -        reportskippedtable("glyf") -    end +    reportskippedtable(f,fontdata,"glyf",specification.glyphs)  end --- Experimental (we need fonts). +-- The MicroSoft variant is pretty clean and is supported (implemented elsewhere) +-- just because I wanted to see how such a font looks like.  function readers.colr(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("colr") -    end +    reportskippedtable(f,fontdata,"colr",specification.glyphs)  end -  function readers.cpal(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("cpal") -    end +    reportskippedtable(f,fontdata,"cpal",specification.glyphs)  end +-- This one is also supported, if only because I could locate a proper font for +-- testing. +  function readers.svg(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("svg") -    end +    reportskippedtable(f,fontdata,"svg",specification.glyphs) +end + +-- There is a font from apple to test the next one. Will there be more? Anyhow, +-- it's relatively easy to support, so I did it. + +function readers.sbix(f,fontdata,specification) +    reportskippedtable(f,fontdata,"sbix",specification.glyphs) +end + +-- I'm only willing to look into the next variant if I see a decent and complete (!) +-- font and more can show up. It makes no sense to waste time on ideas. Okay, the +-- apple font also has these tables. + +function readers.cbdt(f,fontdata,specification) +    reportskippedtable(f,fontdata,"cbdt",specification.glyphs) +end +function readers.cblc(f,fontdata,specification) +    reportskippedtable(f,fontdata,"cblc",specification.glyphs) +end +function readers.ebdt(f,fontdata,specification) +    reportskippedtable(f,fontdata,"ebdt",specification.glyphs) +end +function readers.ebsc(f,fontdata,specification) +    reportskippedtable(f,fontdata,"ebsc",specification.glyphs) +end +function readers.eblc(f,fontdata,specification) +    reportskippedtable(f,fontdata,"eblc",specification.glyphs)  end  -- Here we have a table that we really need for later processing although a more advanced gpos table @@ -1819,27 +1836,19 @@ function readers.kern(f,fontdata,specification)  end  function readers.gdef(f,fontdata,specification) -    if specification.details then -        reportskippedtable("gdef") -    end +    reportskippedtable(f,fontdata,"gdef",specification.details)  end  function readers.gsub(f,fontdata,specification) -    if specification.details then -        reportskippedtable("gsub") -    end +    reportskippedtable(f,fontdata,"gsub",specification.details)  end  function readers.gpos(f,fontdata,specification) -    if specification.details then -        reportskippedtable("gpos") -    end +    reportskippedtable(f,fontdata,"gpos",specification.details)  end  function readers.math(f,fontdata,specification) -    if specification.glyphs then -        reportskippedtable("math") -    end +    reportskippedtable(f,fontdata,"math",specification.details)  end  -- Now comes the loader. The order of reading these matters as we need to know @@ -2109,8 +2118,16 @@ local function readdata(f,offset,specification)      readtable("colr",f,fontdata,specification)      readtable("cpal",f,fontdata,specification) +      readtable("svg" ,f,fontdata,specification) +    readtable("sbix",f,fontdata,specification) + +    readtable("cbdt",f,fontdata,specification) +    readtable("cblc",f,fontdata,specification) +    readtable("ebdt",f,fontdata,specification) +    readtable("eblc",f,fontdata,specification) +      readtable("kern",f,fontdata,specification)      readtable("gsub",f,fontdata,specification)      readtable("gpos",f,fontdata,specification) @@ -2321,6 +2338,7 @@ function readers.loadfont(filename,n,instance)                  mathconstants = fontdata.mathconstants,                  colorpalettes = fontdata.colorpalettes,                  svgshapes     = fontdata.svgshapes, +                sbixshapes    = fontdata.sbixshapes,                  variabledata  = fontdata.variabledata,                  foundtables   = fontdata.foundtables,              }, diff --git a/tex/context/base/mkiv/l-pdfview.lua b/tex/context/base/mkiv/l-pdfview.lua index 6302fd6f6..d2add9188 100644 --- a/tex/context/base/mkiv/l-pdfview.lua +++ b/tex/context/base/mkiv/l-pdfview.lua @@ -44,7 +44,7 @@ if os.type == "windows" then          ['okular']      = [[start "test" okular.exe --unique "%filename%"]],          ['pdfxcview']   = [[start "test" pdfxcview.exe /A "nolock=yes=OpenParameters" "%filename%"]],          ['sumatra']     = [[start "test" sumatrapdf.exe -reuse-instance -bg-color 0xCCCCCC "%filename%"]], -        ['auto']        = [[start "%filename%"]], +        ['auto']        = [[start "" "%filename%"]],      }      closecalls= {          ['default']     = [[pdfclose --file "%filename%"]], @@ -91,7 +91,7 @@ else          ['okular']    = [[okular --unique "%filename%"]],          ['sumatra']   = [[wine "sumatrapdf.exe" -reuse-instance -bg-color 0xCCCCCC "%filename%"]],          ['pdfxcview'] = [[wine "pdfxcview.exe" /A "nolock=yes=OpenParameters" "%filename%"]], -        ['auto']      = [[open "%filename%"]], +        ['auto']      = [[open "%filename%"]], -- linux: xdg-open      }      closecalls= {          ['default']   = [[pdfclose --file "%filename%"]], diff --git a/tex/context/base/mkiv/lang-ini.lua b/tex/context/base/mkiv/lang-ini.lua index 62786d9ab..6de951998 100644 --- a/tex/context/base/mkiv/lang-ini.lua +++ b/tex/context/base/mkiv/lang-ini.lua @@ -46,6 +46,7 @@ local postexhyphenchar = lang.postexhyphenchar -- global per language  local sethjcode        = lang.sethjcode  local uccodes          = characters.uccodes +local lccodes          = characters.lccodes  lang.exceptions        = lang.hyphenation  local new_langage      = lang.new @@ -159,7 +160,7 @@ local function sethjcodes(instance,loaded,what,factor)          --          local function setcode(l)              local u = uccodes[l] -            local s = 1 +            local s = l              if hjcounts then                  local c = hjcounts[l]                  if c then @@ -182,7 +183,7 @@ local function sethjcodes(instance,loaded,what,factor)              h[l] = s              if u ~= l and type(u) == "number" then                  sethjcode(instance,u,s) -                h[u] = s +                h[u] = lccodes[l]              end          end          -- diff --git a/tex/context/base/mkiv/luat-run.lua b/tex/context/base/mkiv/luat-run.lua index d0f894292..372bbcbfa 100644 --- a/tex/context/base/mkiv/luat-run.lua +++ b/tex/context/base/mkiv/luat-run.lua @@ -23,6 +23,10 @@ local report_tempfiles = logs.reporter("resolvers","tempfiles")  luatex       = luatex or { }  local luatex = luatex +if not luatex.synctex then +    luatex.synctex = table.setmetatableindex(function() return function() end end) +end +  local startactions = { }  local stopactions  = { }  local dumpactions  = { } @@ -68,6 +72,7 @@ local function stop_shipout_page()      for i=1,#pageactions do          pageactions[i]()      end +    luatex.synctex.flush()  end  local function report_output_pages() @@ -142,27 +147,6 @@ end  luatex.registerstopactions(luatex.cleanuptempfiles) --- for the moment here - -local report_system = logs.reporter("system") -local synctex       = 0 - -directives.register("system.synctex", function(v) -    synctex = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0 -    if synctex ~= 0 then -        report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(synctex)) -    else -        report_system("synctex functionality is disabled!") -    end -    tex.normalsynctex = synctex -end) - -statistics.register("synctex tracing",function() -    if synctex ~= 0 then -        return "synctex has been enabled (extra log file generated)" -    end -end) -  -- filenames  local types = { @@ -184,6 +168,10 @@ local total = 0  local stack = { }  local all   = false +function luatex.currentfile() +    return stack[#stack] or tex.jobname +end +  local function report_start(left,name)      if not left then          -- skip @@ -200,6 +188,7 @@ local function report_start(left,name)          level = level + 1       -- report_open("%i > %i > %s",level,total,name or "?")          report_open("level %i, order %i, name %a",level,total,name or "?") +        luatex.synctex.setfilename(name)      end  end diff --git a/tex/context/base/mkiv/lxml-aux.lua b/tex/context/base/mkiv/lxml-aux.lua index 9a829795d..ee0909cbf 100644 --- a/tex/context/base/mkiv/lxml-aux.lua +++ b/tex/context/base/mkiv/lxml-aux.lua @@ -762,7 +762,7 @@ local obsolete = xml.obsolete  xml.strip_whitespace           = xml.strip                 obsolete.strip_whitespace      = xml.strip  xml.collect_elements           = xml.collect               obsolete.collect_elements      = xml.collect  xml.delete_element             = xml.delete                obsolete.delete_element        = xml.delete -xml.replace_element            = xml.replace               obsolete.replace_element       = xml.replacet +xml.replace_element            = xml.replace               obsolete.replace_element       = xml.replace  xml.each_element               = xml.each                  obsolete.each_element          = xml.each  xml.process_elements           = xml.process               obsolete.process_elements      = xml.process  xml.insert_element_after       = xml.insertafter           obsolete.insert_element_after  = xml.insertafter diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index ed3c06c28..b23709ff0 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -853,3 +853,11 @@ function nuts.copy_properties(source,target,what)      end      return newprops -- for checking  end + +-- here: + +nodes.set_synctex_line  = node.set_synctex_line +nodes.set_synctex_tag   = node.set_synctex_tag + +nuts.get_synctex_fields = direct.get_synctex_fields +nuts.set_synctex_fields = direct.set_synctex_fields diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua new file mode 100644 index 000000000..31243cd60 --- /dev/null +++ b/tex/context/base/mkiv/node-syn.lua @@ -0,0 +1,501 @@ +if not modules then modules = { } end modules ['node-syn'] = { +    version   = 1.001, +    comment   = "companion to node-ini.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- Because we have these fields in some node that are used by sunctex, I decided (because +-- some users seem to like that feature) to implement a variant that might work out better +-- for ConTeXt. This is experimental code. I don't use it myself so it will take a while +-- to mature. There will be some helpers that one can use in more complex situations like +-- included xml files. +-- +-- It is unclear how the output gets interpreted. For instance, we only need to be able to +-- go back to a place where text is entered, but still we need all that redundant box +-- wrapping. +-- +-- Possible optimizations: pack whole lines. + +local type, rawset = type, rawset +local concat = table.concat +local formatters = string.formatters + +local trace = false  trackers.register("system.syntex.visualize", function(v) trace = v end) + +local nuts               = nodes.nuts +local tonut              = nuts.tonut +local tonode             = nuts.tonode + +local getid              = nuts.getid +local getlist            = nuts.getlist +local setlist            = nuts.setlist +local getnext            = nuts.getnext +local getwhd             = nuts.getwhd +local getwidth           = nuts.getwidth +local getsubtype         = nuts.getsubtype +local getattr            = nuts.getattr + +local nodecodes          = nodes.nodecodes +local kerncodes          = nodes.kerncodes + +local glue_code          = nodecodes.glue +local kern_code          = nodecodes.kern +local kern_disc          = nodecodes.disc +local rule_code          = nodecodes.rule +----- math_code          = nodecodes.math +local hlist_code         = nodecodes.hlist +local vlist_code         = nodecodes.vlist +local glyph_code         = nodecodes.glyph +local fontkern_code      = kerncodes.fontkern + +local insert_before      = nuts.insert_before +local insert_after       = nuts.insert_after + +local nodepool           = nuts.pool +local new_latelua        = nodepool.latelua +local new_rule           = nodepool.rule +local new_hlist          = nodepool.hlist + +local getdimensions      = nuts.dimensions +local getrangedimensions = nuts.rangedimensions + +local a_fontkern         = attributes.private("fontkern") + +local get_synctex_fields = nuts.get_synctex_fields +local set_synctex_fields = nuts.set_synctex_fields +local set_syntex_tag     = nodes.set_synctex_tag + +local getpos             = function() +                               getpos = backends.codeinjections.getpos +                               return getpos() +                           end + +local f_glue             = formatters["g%i,%i:%i,%i"] +local f_glyph            = formatters["x%i,%i:%i,%i"] +local f_kern             = formatters["k%i,%i:%i,%i:%i"] +local f_rule             = formatters["r%i,%i:%i,%i:%i,%i,%i"] +local f_hlist            = formatters["[%i,%i:%i,%i:%i,%i,%i"] +local f_vlist            = formatters["(%i,%i:%i,%i:%i,%i,%i"] +local s_hlist            = "]" +local s_vlist            = ")" +local f_hvoid            = formatters["h%i,%i:%i,%i:%i,%i,%i"] +local f_vvoid            = formatters["v%i,%i:%i,%i:%i,%i,%i"] + +local characters         = fonts.hashes.characters + +local synctex            = { } +luatex.synctex           = synctex + +-- the file name stuff + +local noftags            = 0 +local stnums             = { } +local sttags             = table.setmetatableindex(function(t,name) +    noftags = noftags + 1 +    t[name] = noftags +    stnums[noftags] = name +    return noftags +end) + +function synctex.setfilename(name) +    if set_syntex_tag and name then +        set_syntex_tag(sttags[name]) +    end +end + +function synctex.resetfilename() +    if set_syntex_tag then +        local name = luatex.currentfile() +        if name then +            set_syntex_tag(name) +        end +    end +end + +-- the node stuff + +local result             = { } +local r                  = 0 +local f                  = nil +local nofsheets          = 0 +local nofobjects         = 0 +local last               = 0 +local filesdone          = 0 +local enabled            = false +local compact            = true + +local function writeanchor() +    local size = f:seek("end") +    f:write("!" .. (size-last) .. "\n") +    last = size +end + +local function writefiles() +    local total = #stnums +    if filesdone < total then +        for i=filesdone+1,total do +            f:write("Input:"..i..":"..stnums[i].."\n") +        end +        filesdone = total +    end +end + +local function flushpreamble() +    local jobname = tex.jobname +    stnums[0] = jobname +    f = io.open(file.replacesuffix(jobname,"syncctx"),"w") +    f:write("SyncTeX Version:1\n") +    f:write("Input:0:"..jobname.."\n") +    writefiles() +    f:write("Output:pdf\n") +    f:write("Magnification:1000\n") +    f:write("Unit:1\n") +    f:write("X Offset:0\n") +    f:write("Y Offset:0\n") +    f:write("Content:\n") +    flushpreamble = writefiles +end + +local function flushpostamble() +    writeanchor() +    f:write("Postamble:\n") +    f:write("Count:"..nofobjects.."\n") +    writeanchor() +    f:write("Post scriptum:\n") +    f:close() +    enabled = false +end + +local pageheight = 0 -- todo: set before we do this! + +local function b_hlist(head,current,t,l,w,h,d) +    return insert_before(head,current,new_latelua(function() +        local x, y = getpos() +        r = r + 1 +        result[r] = f_hlist(t,l,x,tex.pageheight-y,w,h,d) +        nofobjects = nofobjects + 1 +    end)) +end + +local function b_vlist(head,current,t,l,w,h,d) +    return insert_before(head,current,new_latelua(function() +        local x, y = getpos() +        r = r + 1 +        result[r] = f_vlist(t,l,x,tex.pageheight-y,w,h,d) +        nofobjects = nofobjects + 1 +    end)) +end + +local function e_hlist(head,current) +    return insert_after(head,current,new_latelua(function() +        r = r + 1 +        result[r] = s_hlist +        nofobjects = nofobjects + 1 +    end)) +end + +local function e_vlist(head,current) +    return insert_after(head,current,new_latelua(function() +        r = r + 1 +        result[r] = s_vlist +        nofobjects = nofobjects + 1 +    end)) +end + +local function x_hlist(head,current,t,l,w,h,d) +    return insert_before(head,current,new_latelua(function() +        local x, y = getpos() +        r = r + 1 +        result[r] = f_hvoid(t,l,x,tex.pageheight-y,w,h,d) +        nofobjects = nofobjects + 1 +    end)) +end + +local function x_vlist(head,current,t,l,w,h,d) +    return insert_before(head,current,new_latelua(function() +        local x, y = getpos() +        r = r + 1 +        result[r] = f_vvoid(t,l,x,tex.pageheight-y,w,h,d) +        nofobjects = nofobjects + 1 +    end)) +end + +-- local function x_glyph(head,current,t,l) +--     return insert_before(head,current,new_latelua(function() +--         local x, y = getpos() +--         r = r + 1 +--         result[r] = f_glyph(t,l,x,tex.pageheight-y) +--         nofobjects = nofobjects + 1 +--     end)) +-- end + +-- local function x_glue(head,current,t,l) +--     return insert_before(head,current,new_latelua(function() +--         local x, y = getpos() +--         r = r + 1 +--         result[r] = f_glue(t,l,x,tex.pageheight-y) +--         nofobjects = nofobjects + 1 +--     end)) +-- end + +-- local function x_kern(head,current,t,l,k) +--     return insert_before(head,current,new_latelua(function() +--         local x, y = getpos() +--         r = r + 1 +--         result[r] = f_kern(t,l,x,tex.pageheight-y,k) +--         nofobjects = nofobjects + 1 +--     end)) +-- end + +-- local function x_rule(head,current,t,l,w,h,d) +--     return insert_before(head,current,new_latelua(function() +--         local x, y = getpos() +--         r = r + 1 +--         result[r] = f_rule(t,l,x,tex.pageheight-y,w,h,d) +--         nofobjects = nofobjects + 1 +--     end)) +-- end + +local function collect(head,t,l) +    local current = head +    while current do +        local id = getid(current) +        if id == glyph_code then +            local first = current +            local last  = current +            while true do +                id = getid(current) +                if id == glyph_code or id == disc_code then +                    last = current +                elseif id == kern_code and (getsubtype(current) == fontkern_code or getattr(current,a_fontkern)) then +                    last = current +                else +                    if id == glue_code then +                        -- we could go on when we're in the same t/l run +                        local tc, lc = get_synctex_fields(current) +                        if tc > 0 then +                            t, l = tc, lc +                        end +                        id = nil -- so no test later on +                    end +                    local w, h, d = getdimensions(first,getnext(last)) +                 -- local w, h, d = getrangedimensions(head,first,getnext(last)) +                    if trace then +                        -- color is already handled so no colors +                        head = insert_before(head,first,new_hlist(new_rule(w,32768,32768))) +                    end +if h < 655360 then +    h = 655360 +end +if d < 327680 then +    d = 327680 +end +                    head = x_hlist(head,first,t,l,w,h,d) +                    break +                end +                current = getnext(current) +                if not current then +                    local w, h, d = getdimensions(first,getnext(last)) +                 -- local w, h, d = getrangedimensions(head,first,getnext(last)) +                    if trace then +                        -- color is already handled so no colors +                        head = insert_before(head,first,new_hlist(new_rule(w,32768,32768))) +                    end +if h < 655360 then +    h = 655360 +end +if d < 327680 then +    d = 327680 +end +                    head = x_hlist(head,first,t,l,w,h,d) +                    return head +                end +            end +        end +        if id == hlist_code then +            local list = getlist(current) +            local tc, lc = get_synctex_fields(current) +            if tc > 0 then +                t, l = tc, lc +            end +            if compact then +                if list then +                    local l = collect(list,t,l) +                    if l ~= list then +                        setlist(current,l) +                    end +                end +            else +                local w, h, d = getwhd(current) +                if w == 0 or (h == 0 and d == 0) then +                    if list then +                        local l = collect(list,t,l) +                        if l ~= list then +                            setlist(current,l) +                        end +                    end +                elseif list then +                 -- head = b_hlist(head,current,t,l,w,h,d) +                    head = b_hlist(head,current,0,0,w,h,d) +                    local l = collect(list,t,l) +                    if l ~= list then +                        setlist(current,l) +                    end +                    head, current = e_hlist(head,current) +                else +                 -- head = x_hlist(head,current,t,l,w,h,d) +                    head = x_hlist(head,current,0,0,w,h,d) +                end +            end +        elseif id == vlist_code then +            local list = getlist(current) +            local tc, lc = get_synctex_fields(current) +            if tc > 0 then +                t, l = tc, lc +            end +            if compact then +                if list then +                    local l = collect(list,t,l) +                    if l ~= list then +                        setlist(current,l) +                    end +                end +            else +                local w, h, d = getwhd(current) +                if w == 0 or (h == 0 and d == 0) then +                    if list then +                        local l = collect(list,t,l) +                        if l ~= list then +                            setlist(current,l) +                        end +                    end +                elseif list then +                 -- head = b_vlist(head,current,t,l,w,h,d) +                    head = b_vlist(head,current,0,0,w,h,d) +                    local l = collect(list,t,l) +                    if l ~= list then +                        setlist(current,l) +                    end +                    head, current = e_vlist(head,current) +                else +                 -- head = x_vlist(head,current,t,l,w,h,d) +                    head = x_vlist(head,current,0,0,w,h,d) +                end +            end +        elseif id == glue_code then +            local tc, lc = get_synctex_fields(current) +            if tc > 0 then +                t, l = tc, lc +            end +         -- head = x_glue(head,current,t,l) +     -- elseif id == kern_code then +     --     local tc, lc = get_synctex_fields(current) +     --     if tc > 0 then +     --         t, l = tc, lc +     --     end +     --  -- local k = getwidth(current) +     --  -- if k ~= 0 then +     --  --     head = x_kern(head,current,t,l,k) +     --  -- end +     -- elseif id == rule_code then +     --     local tc, lc = get_synctex_fields(current) +     --     if tc > 0 then +     --         t, l = tc, lc +     --     end +     --  -- if t > 0 and l > 0 then +     --  -- local w, h, d = getwhd(current) +     --  --     head = x_rule(head,current,t,l,w,h,d) +     --  -- end +        end +        current = getnext(current) +    end +    return head +end + +-- range of same numbers + +function synctex.collect(head) +    if enabled then +        result, r = { }, 0 +        head = collect(tonut(head),0,0) +        return tonode(head), true +    else +        return head, false +    end +end + +-- also no solution for bad first file resolving in sumatra + +function synctex.flush() +    if enabled then +        nofsheets = nofsheets + 1 -- could be realpageno +        flushpreamble() +        writeanchor() +        f:write("{"..nofsheets.."\n") +        if compact then +            f:write(f_vlist(0,0,0,0,tex.pagewidth,tex.pageheight,0)) +            f:write("\n") +        end +        f:write(concat(result,"\n")) +        if compact then +            f:write("\n") +            f:write(s_vlist) +        end +        f:write("\n") +        writeanchor() +        f:write("}"..nofsheets.."\n") +        nofobjects = nofobjects + 2 +        result, r = { }, 0 +    end +end + +function synctex.enable() +    if not enabled and node.set_synctex_mode then +        enabled = true +        node.set_synctex_mode(1) +        tex.normalsynctex = 0 +        nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect") +    end +end + +function synctex.finish() +    if enabled then +        flushpostamble() +    end +end + +-- not the best place + +luatex.registerstopactions(synctex.finish) + +nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") + +-- moved here + +local report_system = logs.reporter("system") +local synctex       = false + +directives.register("system.synctex", function(v) +    if v == "context" then +        luatex.synctex.enable() +        tex.normalsynctex = 0 +        synctex = true +    else +        v = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0 +        tex.normalsynctex = v +        synctex = v ~= 0 +    end +    if synctex then +        report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(v)) +    else +        report_system("synctex functionality is disabled!") +    end +end) + +statistics.register("synctex tracing",function() +    if synctex or tex.normalsynctex ~= 0 then +        return "synctex has been enabled (extra log file generated)" +    end +end) diff --git a/tex/context/base/mkiv/pack-rul.mkiv b/tex/context/base/mkiv/pack-rul.mkiv index ff39200b8..eec7b8cb3 100644 --- a/tex/context/base/mkiv/pack-rul.mkiv +++ b/tex/context/base/mkiv/pack-rul.mkiv @@ -941,7 +941,9 @@  \def\pack_framed_start_framed_nop_indeed[#1]%    {\pack_framed_initialize     \bgroup -   \setupcurrentframed[#1]% here ! +   \iffirstargument +     \setupcurrentframed[#1]% here ! +   \fi     \pack_framed_process_indeed     \bgroup     \ignorespaces} diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 32aee579a..94d382b63 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex ba8f9d5b7..c66f8765b 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/tabl-frm.mkiv b/tex/context/base/mkiv/tabl-frm.mkiv new file mode 100644 index 000000000..639d6f06d --- /dev/null +++ b/tex/context/base/mkiv/tabl-frm.mkiv @@ -0,0 +1,209 @@ +%D \module +%D   [       file=tabl-frm, +%D        version=2017.04.11, +%D          title=\CONTEXT\ Table Macros, +%D       subtitle=Framed Tables, +%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 For Thomas Schmitz who needed 3000 pages long tables. + +\unprotect + +\writestatus{loading}{ConTeXt Table Macros / Framed Tables} + +\installcorenamespace{framedtable} +\installcorenamespace{framedtablerow} +\installcorenamespace{framedtablecolumn} + +\newcount\c_tabl_framed_c +\newcount\c_tabl_framed_r +\newdimen\d_tabl_framed_h +\newdimen\d_tabl_framed_d +\newdimen\b_tabl_framed + +\initializeboxstack\??framedtable + +\defineframed[\??framedtable] +\defineframed[\??framedtablerow][\??framedtable] +\defineframed[\??framedtablecolumn][\??framedtable] + +\setupframed +  [\??framedtable] +  [\c!distance=\zeropoint, +   \c!before=, +   \c!after=, +   \c!inbetween=] + +\setupframed +  [\??framedtablerow] +  [\c!strut=\v!no, +   \c!offset=\v!overlay] + +% \defineframedtable[foo] +% \defineframedtable[bar][foo] + +\unexpanded\def\defineframedtable +  {\dodoubleempty\tabl_framed_define} + +\def\tabl_framed_define[#1][#2]% +  {\ifsecondargument +     \defineframed[\??framedtable#1][\??framedtable#2]% +   \else\iffirstargument +     \defineframed[\??framedtable#1][\??framedtable]% +   \fi\fi} + +% \setupframedtable[foo][...] + +\unexpanded\def\setupframedtable +  {\dodoubleempty\tabl_framed_setup} + +\def\tabl_framed_setup[#1][#2]% +  {\ifsecondargument +     \ifcsname\??framed:\??framedtable#1\endcsname \else +       \defineframed[\??framedtable#1][\??framedtable]% +     \fi +     \setupframed[\??framedtable#1][#2]% +   \else +     \setupframed[\??framedtable][#1]% +   \fi} + +% \setupframedtable[1][...] +% \setupframedtable[foo][1][...] + +\unexpanded\def\setupframedtablerow +  {\dotripleempty\tabl_framed_setup_row} + +\def\tabl_framed_setup_row[#1][#2][#3]% +  {\ifthirdargument +     \ifcsname\??framed:\??framedtable#1\endcsname \else +       \defineframed[\??framedtable#1][\??framedtable]% +     \fi +     \ifcsname\??framed:\??framedtablerow#1:#2\endcsname \else +       \defineframed[\??framedtablerow#1:#2][\??framedtable#1]% +     \fi +     \setupframed[\??framedtablerow#1:#2][#3]% +   \else\ifsecondargument +     \ifcsname\??framed:\??framedtablerow:#1\endcsname \else +       \defineframed[\??framedtablerow:#1][\??framedtable]% +     \fi +     \setupframed[\??framedtablerow:#1][#2]% +   \fi\fi} + +\unexpanded\def\setupframedtablecolumn +  {\dotripleempty\tabl_framed_setup_column} + +\def\tabl_framed_setup_column[#1][#2][#3]% +  {\ifthirdargument +     \ifcsname\??framed:\??framedtable#1\endcsname \else +       \defineframed[\??framedtable#1][\??framedtable]% +     \fi +     \ifcsname\??framed:\??framedtablecolumn#1:#2\endcsname \else +       \defineframed[\??framedtablecolumn#1:#2][\??framedtable#1]% +     \fi +     \setupframed[\??framedtablecolumn#1:#2][#3]% +   \else\ifsecondargument +     \ifcsname\??framed:\??framedtablecolumn:#1\endcsname \else +       \defineframed[\??framedtablecolumn:#1][\??framedtable]% +     \fi +     \setupframed[\??framedtablecolumn:#1][#2]% +   \fi\fi} + +\unexpanded\def\startframedtable +  {\dodoubleempty\tabl_framed_start} + +\unexpanded\def\tabl_framed_start[#1][#2]% +  {\begingroup +   \forgetall +   \doifelseassignment{#1}% +     {\let\currentframedtable\empty +      \setupframed[\??framedtable][#1]}% +     {\edef\currentframedtable{#1}% +      \setupframed[\??framedtable][#2]}% +   \edef\currentframed{\??framedtable\currentframedtable}% +   \c_tabl_framed_r\zerocount +   \d_tabl_framed_d\framedparameter\c!distance +   \framedparameter\c!before} + +\unexpanded\def\stopframedtable +  {\framedparameter\c!after +   \endgroup} + +\unexpanded\def\startframedrow +  {\advance\c_tabl_framed_r\plusone +   \c_tabl_framed_c\zerocount +   \d_tabl_framed_h\zeropoint +   \bgroup +   \edef\currentframed{\number\c_tabl_framed_r}% +   \edef\currentframed +     {\??framedtablerow\currentframedtable +      \ifcsname\??framedtablerow\currentframedtable:\currentframed\endcsname +        :\currentframed +      \else\ifcsname\??framedtablerow\currentframedtable:\v!each\endcsname +        :\v!each +      \fi\fi}% +   \dosingleempty\pack_framed_start_framed_nop_indeed} + +\unexpanded\def\stopframedrow +  {\dofastloopcs\c_tabl_framed_c\tabl_framed_flush_row +   \stopframed +   \nointerlineskip +   \vskip\zeropoint\relax +   \framedparameter\c!inbetween} + +\unexpanded\def\tabl_framed_flush_row +  {\vpack to \d_tabl_framed_h{\flushbox\??framedtable{\number\fastloopindex}\vfill}% +   \ifdim\d_tabl_framed_d=\zeropoint\else\kern\d_tabl_framed_d\fi} + +\unexpanded\def\startframedcell +  {\advance\c_tabl_framed_c\plusone +   \setbox\b_tabl_framed\hpack\bgroup +  %\bgroup +   \edef\currentframed{\number\c_tabl_framed_c}% +   \edef\currentframed +     {\??framedtablecolumn\currentframedtable +      \ifcsname\??framedtablecolumn\currentframedtable:\currentframed\endcsname +        :\currentframed +      \else\ifcsname\??framedtablecolumn\currentframedtable:\v!each\endcsname +        :\v!each +      \fi\fi}% +   \dosingleempty\pack_framed_start_framed_nop_indeed} + +\unexpanded\def\stopframedcell +  {\stopframed +  %\egroup +   \ifdim\ht\b_tabl_framed>\d_tabl_framed_h +     \d_tabl_framed_h\ht\b_tabl_framed +   \fi +   \savebox\??framedtable{\number\c_tabl_framed_c}{\box\b_tabl_framed}} + +\protect \endinput + +\starttext + +\setupframedtablecolumn [1] [width=3cm,background=color,backgroundcolor=red] +\setupframedtablecolumn [2] [width=4cm,background=color,backgroundcolor=green,align=normal] +% \setupframedtablerow [each] [background=color,backgroundcolor=blue,strut=no] +% \setupframedtablerow [each] [strut=no,offset=overlay] + +\startframedtable[inbetween=\kern-0.4pt,distance=-0.4pt] + +\testfeatureonce{10000}{ +% \testfeatureonce{10}{ +    \startframedrow +        \startframedcell%[backgroundcolor=yellow] +        test +        \stopframedcell +        \startframedcell +        test \par test +        \stopframedcell +    \stopframedrow +} +\stopframedtable + +\stoptext diff --git a/tex/context/base/mkiv/tabl-ltb.mkiv b/tex/context/base/mkiv/tabl-ltb.mkiv index b0e3f52e4..3147fa1cc 100644 --- a/tex/context/base/mkiv/tabl-ltb.mkiv +++ b/tex/context/base/mkiv/tabl-ltb.mkiv @@ -474,7 +474,8 @@       \ifconditional\c_tabl_lines_preroll \else         \box\b_tabl_lines_cell         % the columncounter is one ahead ! -       \dorecurse\c_tabl_lines_step{\strut\hfil}% +%        \dorecurse\c_tabl_lines_step{\strut\hfil}% +\strut         \hskip\scratchskip       \fi     \fi} diff --git a/tex/context/base/mkiv/typo-bld.lua b/tex/context/base/mkiv/typo-bld.lua index 04cc4db8d..153218eef 100644 --- a/tex/context/base/mkiv/typo-bld.lua +++ b/tex/context/base/mkiv/typo-bld.lua @@ -37,6 +37,7 @@ local texnest            = tex.nest  local texlists           = tex.lists  local nodes              = nodes +local nodeidstostring    = nodes.idstostring  local nodepool           = nodes.pool  local new_baselineskip   = nodepool.baselineskip  local new_lineskip       = nodepool.lineskip diff --git a/tex/context/base/mkiv/util-sci.lua b/tex/context/base/mkiv/util-sci.lua index 33e520719..e028d2f95 100644 --- a/tex/context/base/mkiv/util-sci.lua +++ b/tex/context/base/mkiv/util-sci.lua @@ -17,7 +17,20 @@ utilities.scite = scite  local report = logs.reporter("scite") -local lexerroot = file.dirname(resolvers.find_file("scite-context-lexer.lua")) +do +    local lexerroot = "c:/data/system/scite/wscite/context/lexers" +    if not lexerroot then +        lexerroot = file.dirname(resolvers.find_file("scite-context-lexer.lua")) +    end +    if lfs.isdir(lexerroot) then +        package.extraluapath(lexerroot) +        package.extraluapath(lexerroot.."/themes") +        package.extraluapath(lexerroot.."/data") +        report("using lexer root %a",lexerroot) +    else +        report("no valid lexer root") +    end +end  local knownlexers  = {      tex  = "tex", mkiv = "tex", mkvi = "tex", mkxi = "tex", mkix = "tex", mkii = "tex", cld  = "tex", @@ -35,20 +48,16 @@ lexer = nil -- main lexer, global (for the moment needed for themes)  local function loadscitelexer()      if not lexer then -        dir.push(lexerroot) -        lexer = dofile("scite-context-lexer.lua") -        dofile("themes/scite-context-theme.lua") -        dir.pop() +        lexer = require("scite-context-lexer") +        require("scite-context-theme") -- uses lexer      end      return lexer  end  local loadedlexers = setmetatableindex(function(t,k)      local l = knownlexers[k] or k -    dir.push(lexerroot)      loadscitelexer()      local v = lexer.load(formatters["scite-context-lexer-%s"](l)) -    dir.pop()      t[l] = v      t[k] = v      return v @@ -58,8 +67,8 @@ scite.loadedlexers   = loadedlexers  scite.knownlexers    = knownlexers  scite.loadscitelexer = loadscitelexer -local f_fore_bold  = formatters['.%s { display: inline ; font-weight: bold   ; color: #%s%s%s ; }'] -local f_fore_none  = formatters['.%s { display: inline ; font-weight: normal ; color: #%s%s%s ; }'] +local f_fore_bold  = formatters['.%s { display: inline ; font-weight: bold   ; color: #%02X%02X%02X ; }'] +local f_fore_none  = formatters['.%s { display: inline ; font-weight: normal ; color: #%02X%02X%02X ; }']  local f_none_bold  = formatters['.%s { display: inline ; font-weight: bold   ; }']  local f_none_none  = formatters['.%s { display: inline ; font-weight: normal ; }']  local f_div_class  = formatters['<div class="%s">%s</div>'] @@ -92,7 +101,7 @@ local function exportcsslexing()      if not css then          loadscitelexer()          local function black(f) -            return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == '00') +            return (#f == 0 and f[1] == 0) or ((f[1] == f[2]) and (f[2] == f[3]) and (f[3] == 0))          end          local result, r = { }, 0          for k, v in table.sortedhash(lexer.context.styles) do @@ -100,17 +109,10 @@ local function exportcsslexing()              local fore = v.fore              r = r + 1              if fore and not black(fore) then -                if bold then -                    result[r] = f_fore_bold(k,fore[1],fore[2],fore[3]) -                else -                    result[r] = f_fore_none(k,fore[1],fore[2],fore[3]) -                end +                local cr, cg, cb = fore[1], fore[2], fore[3] +                result[r] = (bold and f_fore_bold or f_fore_none)(k,cr,cg or cr,cb or cr)              else -                if bold then -                    result[r] = f_none_bold(k) -                else -                    result[r] = f_none_none(k) -                end +                result[r] = (bold and f_none_bold or f_none_none)(k)              end          end          css = concat(result,"\n") diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex ff174700c..5716030ad 100644 --- a/tex/context/interface/mkiv/i-context.pdf +++ b/tex/context/interface/mkiv/i-context.pdf diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf Binary files differindex 90fa626d6..61f901149 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/mkiv/m-scite.mkiv b/tex/context/modules/mkiv/m-scite.mkiv index 256a78b39..a7d9f8b5c 100644 --- a/tex/context/modules/mkiv/m-scite.mkiv +++ b/tex/context/modules/mkiv/m-scite.mkiv @@ -56,7 +56,7 @@ buffers.scite = scite  -- context output: -local f_def_color = formatters["\\definecolor[slxc%s][h=%s%s%s]%%"] +local f_def_color = formatters["\\definecolor[slxc%s][h=%02X%02X%02X]%%"]  local f_fore_none = formatters["\\unexpanded\\def\\slx%s#1{{\\slxc%s#1}}%%"]  local f_fore_bold = formatters["\\unexpanded\\def\\slx%s#1{{\\slxc%s\\bf#1}}%%"]  local f_none_bold = formatters["\\unexpanded\\def\\slx%s#1{{\\bf#1}}%%"] @@ -99,14 +99,14 @@ local function exportcolors()      if not colors then          scite.loadscitelexer()          local function black(f) -            return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == '00') +            return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == 0)          end          local result, r = { f_mapping }, 1          for k, v in table.sortedhash(lexer.context.styles) do              local fore = v.fore              if fore and not black(fore) then                  r = r + 1 -                result[r] = f_def_color(k,fore[1],fore[2],fore[3]) +                result[r] = f_def_color(k,fore[1],fore[2] or fore[1],fore[3] or fore[1])              end          end          r = r + 1 diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 68bcd8007..c671651ef 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 : c:/data/develop/context/sources/luatex-fonts-merged.lua  -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date  : 04/08/17 12:09:31 +-- merge date  : 04/16/17 12:32:21  do -- begin closure to overcome local limits and interference @@ -8171,14 +8171,7 @@ local function readlongdatetime(f)  end  local tableversion=0.004  readers.tableversion=tableversion -local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000  -local reportedskipped={} -local function reportskippedtable(tag) -  if not reportedskipped[tag] then -    report("loading of table %a skipped (reported once only)",tag) -    reportedskipped[tag]=true -  end -end +local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000  local reservednames={ [0]="copyright",    "family",    "subfamily", @@ -8382,6 +8375,14 @@ local function gotodatatable(f,fontdata,tag,criterium)      end    end  end +local function reportskippedtable(f,fontdata,tag,criterium) +  if criterium and f then +    local datatable=fontdata.tables[tag] +    if datatable then +      report("loading of table %a skipped",tag) +    end +  end +end  local function setvariabledata(fontdata,tag,data)    local variabledata=fontdata.variabledata    if variabledata then @@ -8392,6 +8393,7 @@ local function setvariabledata(fontdata,tag,data)  end  helpers.gotodatatable=gotodatatable  helpers.setvariabledata=setvariabledata +helpers.reportskippedtable=reportskippedtable  local platformnames={    postscriptname=true,    fullname=true, @@ -8763,8 +8765,7 @@ readers.vmtx=function(f,fontdata,specification)    end  end  readers.vorg=function(f,fontdata,specification) -  if specification.glyphs then -  end +  reportskippedtable(f,fontdata,"vorg",specification.glyphs)  end  readers.post=function(f,fontdata,specification)    local tableoffset=gotodatatable(f,fontdata,"post",true) @@ -8825,9 +8826,7 @@ readers.post=function(f,fontdata,specification)    end  end  readers.cff=function(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("cff") -  end +  reportskippedtable(f,fontdata,"cff",specification.glyphs)  end  local formatreaders={}  local duplicatestoo=true @@ -9246,29 +9245,37 @@ function readers.cmap(f,fontdata,specification)    end  end  function readers.loca(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("loca") -  end +  reportskippedtable(f,fontdata,"loca",specification.glyphs)  end  function readers.glyf(f,fontdata,specification)  -  if specification.glyphs then -    reportskippedtable("glyf") -  end +  reportskippedtable(f,fontdata,"glyf",specification.glyphs)  end  function readers.colr(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("colr") -  end +  reportskippedtable(f,fontdata,"colr",specification.glyphs)  end  function readers.cpal(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("cpal") -  end +  reportskippedtable(f,fontdata,"cpal",specification.glyphs)  end  function readers.svg(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("svg") -  end +  reportskippedtable(f,fontdata,"svg",specification.glyphs) +end +function readers.sbix(f,fontdata,specification) +  reportskippedtable(f,fontdata,"sbix",specification.glyphs) +end +function readers.cbdt(f,fontdata,specification) +  reportskippedtable(f,fontdata,"cbdt",specification.glyphs) +end +function readers.cblc(f,fontdata,specification) +  reportskippedtable(f,fontdata,"cblc",specification.glyphs) +end +function readers.ebdt(f,fontdata,specification) +  reportskippedtable(f,fontdata,"ebdt",specification.glyphs) +end +function readers.ebsc(f,fontdata,specification) +  reportskippedtable(f,fontdata,"ebsc",specification.glyphs) +end +function readers.eblc(f,fontdata,specification) +  reportskippedtable(f,fontdata,"eblc",specification.glyphs)  end  function readers.kern(f,fontdata,specification)    local tableoffset=gotodatatable(f,fontdata,"kern",specification.kerns) @@ -9308,24 +9315,16 @@ function readers.kern(f,fontdata,specification)    end  end  function readers.gdef(f,fontdata,specification) -  if specification.details then -    reportskippedtable("gdef") -  end +  reportskippedtable(f,fontdata,"gdef",specification.details)  end  function readers.gsub(f,fontdata,specification) -  if specification.details then -    reportskippedtable("gsub") -  end +  reportskippedtable(f,fontdata,"gsub",specification.details)  end  function readers.gpos(f,fontdata,specification) -  if specification.details then -    reportskippedtable("gpos") -  end +  reportskippedtable(f,fontdata,"gpos",specification.details)  end  function readers.math(f,fontdata,specification) -  if specification.glyphs then -    reportskippedtable("math") -  end +  reportskippedtable(f,fontdata,"math",specification.details)  end  local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames)    local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata @@ -9560,6 +9559,11 @@ local function readdata(f,offset,specification)    readtable("colr",f,fontdata,specification)    readtable("cpal",f,fontdata,specification)    readtable("svg",f,fontdata,specification) +  readtable("sbix",f,fontdata,specification) +  readtable("cbdt",f,fontdata,specification) +  readtable("cblc",f,fontdata,specification) +  readtable("ebdt",f,fontdata,specification) +  readtable("eblc",f,fontdata,specification)    readtable("kern",f,fontdata,specification)    readtable("gsub",f,fontdata,specification)    readtable("gpos",f,fontdata,specification) @@ -9753,6 +9757,7 @@ function readers.loadfont(filename,n,instance)          mathconstants=fontdata.mathconstants,          colorpalettes=fontdata.colorpalettes,          svgshapes=fontdata.svgshapes, +        sbixshapes=fontdata.sbixshapes,          variabledata=fontdata.variabledata,          foundtables=fontdata.foundtables,        }, @@ -15269,6 +15274,72 @@ function readers.svg(f,fontdata,specification)    end    fontdata.hascolor=true  end +function readers.sbix(f,fontdata,specification) +  local tableoffset=gotodatatable(f,fontdata,"sbix",specification.glyphs) +  if tableoffset then +    local version=readushort(f) +    local flags=readushort(f) +    local nofstrikes=readulong(f) +    local strikes={} +    local nofglyphs=fontdata.nofglyphs +    for i=1,nofstrikes do +      strikes[i]=readulong(f) +    end +      local shapes={} +      local done=0 +      for i=1,nofstrikes do +        local strikeoffset=strikes[i]+tableoffset +        setposition(f,strikeoffset) +        strikes[i]={ +          ppem=readushort(f), +          ppi=readushort(f), +          offset=strikeoffset +        } +      end +      sort(strikes,function(a,b) +        if b.ppem==a.ppem then +          return b.ppi<a.ppi +        else +          return b.ppem<a.ppem +        end +      end) +      local glyphs={} +      for i=1,nofstrikes do +        local strike=strikes[i] +        local strikeppem=strike.ppem +        local strikeppi=strike.ppi +        local strikeoffset=strike.offset +        setposition(f,strikeoffset) +        for i=0,nofglyphs do +          glyphs[i]=readulong(f) +        end +        local glyphoffset=glyphs[0] +        for i=0,nofglyphs-1 do +          local nextoffset=glyphs[i+1] +          if not shapes[i] then +            local datasize=nextoffset-glyphoffset +            if datasize>0 then +              setposition(f,strikeoffset+glyphoffset) +              shapes[i]={ +                x=readshort(f), +                y=readshort(f), +                tag=readtag(f), +                data=readstring(f,datasize-8), +                ppem=strikeppem, +                ppi=strikeppi, +              } +              done=done+1 +              if done==nofglyphs then +                break +              end +            end +          end +          glyphoffset=nextoffset +        end +      end +      fontdata.sbixshapes=shapes +  end +end  function readers.stat(f,fontdata,specification)    local tableoffset=gotodatatable(f,fontdata,"stat",true)     if tableoffset then @@ -17755,8 +17826,10 @@ local otf=fonts.handlers.otf  otf.version=3.028   otf.cache=containers.define("fonts","otl",otf.version,true)  otf.svgcache=containers.define("fonts","svg",otf.version,true) +otf.sbixcache=containers.define("fonts","sbix",otf.version,true)  otf.pdfcache=containers.define("fonts","pdf",otf.version,true)  otf.svgenabled=false +otf.sbixenabled=false  local otfreaders=otf.readers  local hashes=fonts.hashes  local definers=fonts.definers @@ -17812,6 +17885,7 @@ function otf.load(filename,sub,instance)      if data then        local resources=data.resources        local svgshapes=resources.svgshapes +      local sbixshapes=resources.sbixshapes        if svgshapes then          resources.svgshapes=nil          if otf.svgenabled then @@ -17826,6 +17900,20 @@ function otf.load(filename,sub,instance)            }          end        end +      if sbixshapes then +        resources.sbixshapes=nil +        if otf.sbixenabled then +          local timestamp=os.date() +          containers.write(otf.sbixcache,hash,{ +            sbixshapes=sbixshapes, +            timestamp=timestamp, +          }) +          data.properties.sbix={ +            hash=hash, +            timestamp=timestamp, +          } +        end +      end        otfreaders.compact(data)        otfreaders.rehash(data,"unicodes")        otfreaders.addunicodetable(data) @@ -25817,6 +25905,7 @@ if not modules then modules={} end modules ['font-ocl']={  }  local tostring,next,format=tostring,next,string.format  local round,max=math.round,math.round +local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash  local formatters=string.formatters  local tounicode=fonts.mappings.tounicode  local otf=fonts.handlers.otf @@ -25944,44 +26033,78 @@ fonts.handlers.otf.features.register {      node=initializecolr,    }  } -local otfsvg=otf.svg or {} -otf.svg=otfsvg -otf.svgenabled=true  do    local nofstreams=0 -  local f_name=formatters[ [[svg-glyph-%05i]] ] +  local f_name=formatters[ [[pdf-glyph-%05i]] ]    local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] +  local hashed={}    local cache={} -  function otfsvg.storepdfdata(pdf) -    nofstreams=nofstreams+1 -    local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) -    cache[n]=o  -    return nil,f_used(n),nil +  function otf.storepdfdata(pdf) +    local done=hashed[pdf] +    if not done then +      nofstreams=nofstreams+1 +      local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) +      cache[n]=o  +      done=f_used(n) +      hashed[pdf]=done +    end +    return nil,done,nil    end -  if context then -    local storepdfdata=otfsvg.storepdfdata -    local initialized=false -    function otfsvg.storepdfdata(pdf) -      if not initialized then -        if resolvers.setmemstream then -          local f_setstream=formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ] -          local f_getstream=formatters[ [[memstream:///svg-glyph-%05i]] ] -          local f_nilstream=formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ] -          storepdfdata=function(pdf) -            nofstreams=nofstreams+1 -            return -              f_setstream(nofstreams,pdf), -              f_getstream(nofstreams), -              f_nilstream(nofstreams) -          end -          otfsvg.storepdfdata=storepdfdata +end +local function pdftovirtual(tfmdata,pdfshapes,kind)  +  if not tfmdata or not pdfshapes or not kind then +    return +  end +  local characters=tfmdata.characters +  local properties=tfmdata.properties +  local parameters=tfmdata.parameters +  local hfactor=parameters.hfactor +  properties.virtualized=true +  tfmdata.fonts={ +    { id=0 } +  } +  local getactualtext=otf.getactualtext +  local storepdfdata=otf.storepdfdata +  for unicode,character in sortedhash(characters) do  +    local index=character.index +    if index then +      local pdf=pdfshapes[index] +      local typ=type(pdf) +      local data=nil +      local dx=nil +      local dy=nil +      if typ=="table" then +        data=pdf.data +        dx=pdf.dx or 0 +        dy=pdf.dy or 0 +      elseif typ=="string" then +        data=pdf +        dx=0 +        dy=0 +      end +      if data then +        local setcode,name,nilcode=storepdfdata(data) +        if name then +          local bt,et=getactualtext(unicode) +          local wd=character.width or 0 +          local ht=character.height or 0 +          local dp=character.depth or 0 +          character.commands={ +            { "special","pdf:direct:"..bt }, +            { "down",dp+dy*hfactor }, +            { "right",dx*hfactor }, +            { "image",{ filename=name,width=wd,height=ht,depth=dp } }, +            { "special","pdf:direct:"..et }, +          } +          character[kind]=true          end -        initialized=true        end -      return storepdfdata(pdf)      end    end  end +local otfsvg=otf.svg or {} +otf.svg=otfsvg +otf.svgenabled=true  do    local report_svg=logs.reporter("fonts","svg conversion")    local loaddata=io.loaddata @@ -26054,7 +26177,7 @@ do        end        statistics.stoptiming()        if statistics.elapsedseconds then -        report_svg("svg conversion time %s",statistics.elapsedseconds()) +        report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")        end      end      return pdfshapes @@ -26062,10 +26185,7 @@ do  end  local function initializesvg(tfmdata,kind,value)     if value and otf.svgenabled then -    local characters=tfmdata.characters -    local descriptions=tfmdata.descriptions -    local properties=tfmdata.properties -    local svg=properties.svg +    local svg=tfmdata.properties.svg      local hash=svg and svg.hash      local timestamp=svg and svg.timestamp      if not hash then @@ -26082,40 +26202,7 @@ local function initializesvg(tfmdata,kind,value)          timestamp=timestamp,        })      end -    if not pdfshapes or not next(pdfshapes) then -      return -    end -    properties.virtualized=true -    tfmdata.fonts={ -      { id=0 } -    } -    local getactualtext=otf.getactualtext -    local storepdfdata=otfsvg.storepdfdata -    local nop={ "nop" } -    for unicode,character in next,characters do -      local index=character.index -      if index then -        local pdf=pdfshapes[index] -        if pdf then -          local setcode,name,nilcode=storepdfdata(pdf) -          if name then -            local bt,et=getactualtext(unicode) -            local wd=character.width or 0 -            local ht=character.height or 0 -            local dp=character.depth or 0 -            character.commands={ -              { "special","pdf:direct:"..bt }, -              { "down",dp }, -              setcode and { "lua",setcode } or nop, -              { "image",{ filename=name,width=wd,height=ht,depth=dp } }, -              nilcode and { "lua",nilcode } or nop, -              { "special","pdf:direct:"..et }, -            } -            character.svg=true -          end -        end -      end -    end +    pdftovirtual(tfmdata,pdfshapes,"svg")    end  end  fonts.handlers.otf.features.register { @@ -26126,6 +26213,91 @@ fonts.handlers.otf.features.register {      node=initializesvg,    }  } +local otfsbix=otf.sbix or {} +otf.sbix=otfsbix +otf.sbixenabled=true +do +  local report_sbix=logs.reporter("fonts","sbix conversion") +  local loaddata=io.loaddata +  local savedata=io.savedata +  local remove=os.remove +  local runner=sandbox and sandbox.registerrunner { +    name="otfsbix", +    program="gm", +    template="convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log", +  } +  if not runner then +    runner=function() +      return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log") +    end +  end +  function otfsbix.topdf(sbixshapes) +    local pdfshapes={} +    local sbixfile="temp-otf-sbix-shape.sbix" +    local pdffile="temp-otf-sbix-shape.pdf" +    local nofdone=0 +    local indices=sortedkeys(sbixshapes)  +    local nofindices=#indices +    report_sbix("processing %i sbix containers",nofindices) +    statistics.starttiming() +    for i=1,nofindices do +      local index=indices[i] +      local entry=sbixshapes[index] +      local data=entry.data +      local x=entry.x +      local y=entry.y +      savedata(sbixfile,data) +      runner() +      pdfshapes[index]={ +        x=x~=0 and x or nil, +        y=y~=0 and y or nil, +        data=loaddata(pdffile), +      } +      nofdone=nofdone+1 +      if nofdone%100==0 then +        report_sbix("%i shapes processed",nofdone) +      end +    end +    report_sbix("processing %i pdf results",nofindices) +    remove(sbixfile) +    remove(pdffile) +    statistics.stoptiming() +    if statistics.elapsedseconds then +      report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-") +    end +    return pdfshapes +  end +end +local function initializesbix(tfmdata,kind,value)  +  if value and otf.sbixenabled then +    local sbix=tfmdata.properties.sbix +    local hash=sbix and sbix.hash +    local timestamp=sbix and sbix.timestamp +    if not hash then +      return +    end +    local pdffile=containers.read(otf.pdfcache,hash) +    local pdfshapes=pdffile and pdffile.pdfshapes +    if not pdfshapes or pdffile.timestamp~=timestamp then +      local sbixfile=containers.read(otf.sbixcache,hash) +      local sbixshapes=sbixfile and sbixfile.sbixshapes +      pdfshapes=sbixshapes and otfsbix.topdf(sbixshapes) or {} +      containers.write(otf.pdfcache,hash,{ +        pdfshapes=pdfshapes, +        timestamp=timestamp, +      }) +    end +    pdftovirtual(tfmdata,pdfshapes,"sbix") +  end +end +fonts.handlers.otf.features.register { +  name="sbix", +  description="sbix glyphs", +  manipulators={ +    base=initializesbix, +    node=initializesbix, +  } +}  end -- closure @@ -26142,7 +26314,6 @@ local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkey  local type,next=type,next  local lpegmatch=lpeg.match  local utfbyte,utflen,utfsplit=utf.byte,utf.len,utf.split -local settings_to_array=utilities.parsers.settings_to_array  local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)  local report_otf=logs.reporter("fonts","otf loading")  local fonts=fonts @@ -26974,6 +27145,8 @@ registerotffeature {    name='blockligatures',    description='block certain ligatures',  } +local settings_to_array=utilities.parsers and utilities.parsers.settings_to_array +            or function(s) return string.split(s,",") end   local function blockligatures(str)    local t=settings_to_array(str)    for i=1,#t do @@ -28783,8 +28956,9 @@ if not modules then modules={} end modules ['font-def']={  local lower,gsub=string.lower,string.gsub  local tostring,next=tostring,next  local lpegmatch=lpeg.match -local suffixonly,removesuffix=file.suffix,file.removesuffix +local suffixonly,removesuffix,basename=file.suffix,file.removesuffix,file.basename  local formatters=string.formatters +local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys  local allocate=utilities.storage.allocate  local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)  local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end) @@ -28904,9 +29078,9 @@ function resolvers.name(specification)            features.normal=normal          end          normal.instance=instance -if not callbacks.supported.glyph_stream_provider then -  normal.variableshapes=true  -end +        if not callbacks.supported.glyph_stream_provider then +          normal.variableshapes=true  +        end        end        local suffix=lower(suffixonly(resolved))        if fonts.formats[suffix] then @@ -28985,6 +29159,60 @@ local function checkembedding(tfmdata)    end    tfmdata.embedding=embedding  end +local function checkfeatures(tfmdata) +  local resources=tfmdata.resources +  local shared=tfmdata.shared +  if resources and shared then +    local features=resources.features +    local usedfeatures=shared.features +    if features and usedfeatures then +      local usedlanguage=usedfeatures.language or "dflt" +      local usedscript=usedfeatures.script or "dflt" +      local function check(what) +        if what then +          local foundlanguages={} +          for feature,scripts in next,what do +            if usedscript=="auto" or scripts["*"] then +            elseif not scripts[usedscript] then +            else +              for script,languages in next,scripts do +                if languages["*"] then +                elseif not languages[usedlanguage] then +                  report_defining("font %!font:name!, feature %a, script %a, no language %a", +                    tfmdata,feature,script,usedlanguage) +                end +              end +            end +            for script,languages in next,scripts do +              for language in next,languages do +                foundlanguages[language]=true +              end +            end +          end +          if false then +            foundlanguages["*"]=nil +            foundlanguages=sortedkeys(foundlanguages) +            for feature,scripts in sortedhash(what) do +              for script,languages in next,scripts do +                if not languages["*"] then +                  for i=1,#foundlanguages do +                    local language=foundlanguages[i] +                    if not languages[language] then +                      report_defining("font %!font:name!, feature %a, script %a, no language %a", +                        tfmdata,feature,script,language) +                    end +                  end +                end +              end +            end +          end +        end +      end +      check(features.gsub) +      check(features.gpos) +    end +  end +end  function definers.loadfont(specification)    local hash=constructors.hashinstance(specification)    local tfmdata=loadedfonts[hash]  @@ -29018,6 +29246,7 @@ function definers.loadfont(specification)        checkembedding(tfmdata)         loadedfonts[hash]=tfmdata        designsizes[specification.hash]=tfmdata.parameters.designsize +      checkfeatures(tfmdata)      end    end    if not tfmdata then @@ -29110,7 +29339,7 @@ function definers.read(specification,size,id)      local parameters=tfmdata.parameters or {}      report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",        properties.format or "unknown",id,properties.name,parameters.size,properties.encodingbytes, -      properties.encodingname,properties.fullname,file.basename(properties.filename)) +      properties.encodingname,properties.fullname,basename(properties.filename))    end    statistics.stoptiming(fonts)    return tfmdata  | 
