diff options
| author | Philipp Gesang <megas.kapaneus@gmail.com> | 2013-04-09 12:59:53 +0200 | 
|---|---|---|
| committer | Philipp Gesang <megas.kapaneus@gmail.com> | 2013-04-09 12:59:53 +0200 | 
| commit | 65481c5210c2bb8137ed8fddbbcc42dcb3a002bc (patch) | |
| tree | f915fec88ed52f6a00bdad0cb49e7944640ea3b6 | |
| parent | ed2b905f3f19b8e92b2e3d750f9c3f3250327a01 (diff) | |
| download | luaotfload-65481c5210c2bb8137ed8fddbbcc42dcb3a002bc.tar.gz | |
update fonts-def
| -rw-r--r-- | otfl-fonts-def.lua | 459 | 
1 files changed, 58 insertions, 401 deletions
| diff --git a/otfl-fonts-def.lua b/otfl-fonts-def.lua index 96de480..0c2f0db 100644 --- a/otfl-fonts-def.lua +++ b/otfl-fonts-def.lua @@ -1,440 +1,97 @@ -if not modules then modules = { } end modules ['font-def'] = { +if not modules then modules = { } end modules ['luatex-font-def'] = {      version   = 1.001, -    comment   = "companion to font-ini.mkiv", +    comment   = "companion to luatex-*.tex",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",      copyright = "PRAGMA ADE / ConTeXt Development Team",      license   = "see context related readme files"  } -local concat = table.concat -local format, gmatch, match, find, lower, gsub = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub -local tostring, next = tostring, next -local lpegmatch = lpeg.match - -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) - -trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading") -trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*") - -local report_defining = logs.reporter("fonts","defining") - ---[[ldx-- -<p>Here we deal with defining fonts. We do so by intercepting the -default loader that only handles <l n='tfm'/>.</p> ---ldx]]-- - -local fonts         = fonts -local fontdata      = fonts.hashes.identifiers -local readers       = fonts.readers -local definers      = fonts.definers -local specifiers    = fonts.specifiers -local constructors  = fonts.constructors - -readers.sequence    = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' } -- dfont ttc - -local variants      = allocate() -specifiers.variants = variants - -definers.methods    = definers.methods or { } - -local internalized  = allocate() -- internal tex numbers (private) - - -local loadedfonts   = constructors.loadedfonts -local designsizes   = constructors.designsizes - ---[[ldx-- -<p>We hardly gain anything when we cache the final (pre scaled) -<l n='tfm'/> table. But it can be handy for debugging, so we no -longer carry this code along. Also, we now have quite some reference -to other tables so we would end up with lots of catches.</p> ---ldx]]-- - ---[[ldx-- -<p>We can prefix a font specification by <type>name:</type> or -<type>file:</type>. The first case will result in a lookup in the -synonym table.</p> - -<typing> -[ name: | file: ] identifier [ separator [ specification ] ] -</typing> - -<p>The following function split the font specification into components -and prepares a table that will move along as we proceed.</p> ---ldx]]-- - --- beware, we discard additional specs --- --- method:name method:name(sub) method:name(sub)*spec method:name*spec --- name name(sub) name(sub)*spec name*spec --- name@spec*oeps - -local splitter, splitspecifiers = nil, "" - -local P, C, S, Cc = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc - -local left  = P("(") -local right = P(")") -local colon = P(":") -local space = P(" ") - -definers.defaultlookup = "file" - -local prefixpattern  = P(false) - -local function addspecifier(symbol) -    splitspecifiers     = splitspecifiers .. symbol -    local method        = S(splitspecifiers) -    local lookup        = C(prefixpattern) * colon -    local sub           = left * C(P(1-left-right-method)^1) * right -    local specification = C(method) * C(P(1)^1) -    local name          = C((1-sub-specification)^1) -    splitter = P((lookup + Cc("")) * name * (sub + Cc("")) * (specification + Cc(""))) +if context then +    texio.write_nl("fatal error: this module is not for context") +    os.exit()  end -local function addlookup(str,default) -    prefixpattern = prefixpattern + P(str) -end - -definers.addlookup = addlookup +local fonts = fonts -addlookup("file") -addlookup("name") -addlookup("spec") +-- A bit of tuning for definitions. -local function getspecification(str) -    return lpegmatch(splitter,str) -end +fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload -definers.getspecification = getspecification +-- tricky: we sort of bypass the parser and directly feed all into +-- the sub parser -function definers.registersplit(symbol,action,verbosename) -    addspecifier(symbol) -    variants[symbol] = action -    if verbosename then -        variants[verbosename] = action -    end +function fonts.definers.getspecification(str) +    return "", str, "", ":", str  end -function definers.makespecification(specification,lookup,name,sub,method,detail,size) -    size = size or 655360 -    if trace_defining then -        report_defining("%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s", -            specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-", -            (sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-") -    end -    if not lookup or lookup == "" then -        lookup = definers.defaultlookup -    end -    local t = { -        lookup        = lookup,        -- forced type -        specification = specification, -- full specification -        size          = size,          -- size in scaled points or -1000*n -        name          = name,          -- font or filename -        sub           = sub,           -- subfont (eg in ttc) -        method        = method,        -- specification method -        detail        = detail,        -- specification -        resolved      = "",            -- resolved font name -        forced        = "",            -- forced loader -        features      = { },           -- preprocessed features -    } -    return t -end +-- the generic name parser (different from context!) -function definers.analyze(specification, size) -    -- can be optimized with locals -    local lookup, name, sub, method, detail = getspecification(specification or "") -    return definers.makespecification(specification, lookup, name, sub, method, detail, size) -end +local list = { } ---[[ldx-- -<p>We can resolve the filename using the next function:</p> ---ldx]]-- +local function issome ()    list.lookup = 'name'          end -- xetex mode prefers name (not in context!) +local function isfile ()    list.lookup = 'file'          end +local function isname ()    list.lookup = 'name'          end +local function thename(s)   list.name   = s               end +local function issub  (v)   list.sub    = v               end +local function iscrap (s)   list.crap   = string.lower(s) end +local function iskey  (k,v) list[k]     = v               end +local function istrue (s)   list[s]     = true            end +local function isfalse(s)   list[s]     = false           end -definers.resolvers = definers.resolvers or { } -local resolvers    = definers.resolvers +local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C --- todo: reporter +local spaces     = P(" ")^0 +local namespec   = (1-S("/:("))^0 -- was: (1-S("/: ("))^0 +local crapspec   = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces +local filename_1 = P("file:")/isfile * (namespec/thename) +local filename_2 = P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]") +local fontname_1 = P("name:")/isname * (namespec/thename) +local fontname_2 = P(true)/issome * (namespec/thename) +local sometext   = (R("az","AZ","09") + S("+-."))^1 +local truevalue  = P("+") * spaces * (sometext/istrue) +local falsevalue = P("-") * spaces * (sometext/isfalse) +local keyvalue   = (C(sometext) * spaces * P("=") * spaces * C(sometext))/iskey +local somevalue  = sometext/istrue +local subvalue   = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim +local option     = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces +local options    = P(":") * spaces * (P(";")^0  * option)^0 -function resolvers.file(specification) -    local suffix = file.suffix(specification.name) -    if fonts.formats[suffix] then -        specification.forced = suffix -        specification.name = file.removesuffix(specification.name) -    end -end +local pattern    = (filename_1 + filename_2 + fontname_1 + fontname_2) * subvalue^0 * crapspec^0 * options^0 -function resolvers.name(specification) -    local resolve = fonts.names.resolve -    if resolve then -        local resolved, sub = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions -        if resolved then -            specification.resolved = resolved -            specification.sub      = sub -            local suffix = file.suffix(resolved) -            if fonts.formats[suffix] then -                specification.forced = suffix -                specification.name   = file.removesuffix(resolved) -            else -                specification.name = resolved -            end -        end -    else -        resolvers.file(specification) +local function colonized(specification) -- xetex mode +    list = { } +    lpeg.match(pattern,specification.specification) +    list.crap = nil -- style not supported, maybe some day +    if list.name then +        specification.name = list.name +        list.name = nil      end -end - -function resolvers.spec(specification) -    local resolvespec = fonts.names.resolvespec -    if resolvespec then -        local resolved, sub = resolvespec(specification.name,specification.sub,specification) -- we pass specification for overloaded versions -        if resolved then -            specification.resolved = resolved -            specification.sub      = sub -            specification.forced   = file.extname(resolved) -            specification.name     = file.removesuffix(resolved) -        end -    else -        resolvers.name(specification) +    if list.lookup then +        specification.lookup = list.lookup +        list.lookup = nil      end -end - -function definers.resolve(specification) -    if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash -        local r = resolvers[specification.lookup] -        if r then -            r(specification) -        end -    end -    if specification.forced == "" then -        specification.forced = nil -    else -        specification.forced = specification.forced -    end -    specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification)) -    if specification.sub and specification.sub ~= "" then -        specification.hash = specification.sub .. ' @ ' .. specification.hash +    if list.sub then +        specification.sub = list.sub +        list.sub = nil      end +    specification.features.normal = fonts.handlers.otf.features.normalize(list)      return specification  end ---[[ldx-- -<p>The main read function either uses a forced reader (as determined by -a lookup) or tries to resolve the name using the list of readers.</p> - -<p>We need to cache when possible. We do cache raw tfm data (from <l -n='tfm'/>, <l n='afm'/> or <l n='otf'/>). After that we can cache based -on specificstion (name) and size, that is, <l n='tex'/> only needs a number -for an already loaded fonts. However, it may make sense to cache fonts -before they're scaled as well (store <l n='tfm'/>'s with applied methods -and features). However, there may be a relation between the size and -features (esp in virtual fonts) so let's not do that now.</p> - -<p>Watch out, here we do load a font, but we don't prepare the -specification yet.</p> ---ldx]]-- - --- very experimental: +fonts.definers.registersplit(":",colonized,"cryptic") +fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names] -function definers.applypostprocessors(tfmdata) +function fonts.definers.applypostprocessors(tfmdata)      local postprocessors = tfmdata.postprocessors      if postprocessors then          for i=1,#postprocessors do              local extrahash = postprocessors[i](tfmdata) -- after scaling etc              if type(extrahash) == "string" and extrahash ~= "" then                  -- e.g. a reencoding needs this -                extrahash = gsub(lower(extrahash),"[^a-z]","-") +                extrahash = string.gsub(lower(extrahash),"[^a-z]","-")                  tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)              end          end      end      return tfmdata  end - --- function definers.applypostprocessors(tfmdata) ---     return tfmdata --- end - -local function checkembedding(tfmdata) -    local properties = tfmdata.properties -    local embedding -    if directive_embedall then -        embedding = "full" -    elseif properties and properties.filename and constructors.dontembed[properties.filename] then -        embedding = "no" -    else -        embedding = "subset" -    end -    if properties then -        properties.embedding = embedding -    else -        tfmdata.properties = { embedding = embedding } -    end -    tfmdata.embedding = embedding -end - -function definers.loadfont(specification) -    local hash = constructors.hashinstance(specification) -    local tfmdata = loadedfonts[hash] -- hashes by size ! -    if not tfmdata then -        local forced = specification.forced or "" -        if forced ~= "" then -            local reader = readers[lower(forced)] -            tfmdata = reader and reader(specification) -            if not tfmdata then -                report_defining("forced type %s of %s not found",forced,specification.name) -            end -        else -            local sequence = readers.sequence -- can be overloaded so only a shortcut here -            for s=1,#sequence do -                local reader = sequence[s] -                if readers[reader] then -- we skip not loaded readers -                    if trace_defining then -                        report_defining("trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown") -                    end -                    tfmdata = readers[reader](specification) -                    if tfmdata then -                        break -                    else -                        specification.filename = nil -                    end -                end -            end -        end -        if tfmdata then -            tfmdata = definers.applypostprocessors(tfmdata) -            checkembedding(tfmdata) -- todo: general postprocessor -            loadedfonts[hash] = tfmdata -            designsizes[specification.hash] = tfmdata.parameters.designsize -        end -    end -    if not tfmdata then -        report_defining("font with asked name '%s' is not found using lookup '%s'",specification.name,specification.lookup) -    end -    return tfmdata -end - ---[[ldx-- -<p>For virtual fonts we need a slightly different approach:</p> ---ldx]]-- - -function constructors.readanddefine(name,size) -- no id -- maybe a dummy first -    local specification = definers.analyze(name,size) -    local method = specification.method -    if method and variants[method] then -        specification = variants[method](specification) -    end -    specification = definers.resolve(specification) -    local hash = constructors.hashinstance(specification) -    local id = definers.registered(hash) -    if not id then -        local tfmdata = definers.loadfont(specification) -        if tfmdata then -            tfmdata.properties.hash = hash -            id = font.define(tfmdata) -            definers.register(tfmdata,id) -        else -            id = 0  -- signal -        end -    end -    return fontdata[id], id -end - ---[[ldx-- -<p>So far the specifiers. Now comes the real definer. Here we cache -based on id's. Here we also intercept the virtual font handler. Since -it evolved stepwise I may rewrite this bit (combine code).</p> - -In the previously defined reader (the one resulting in a <l n='tfm'/> -table) we cached the (scaled) instances. Here we cache them again, but -this time based on id. We could combine this in one cache but this does -not gain much. By the way, passing id's back to in the callback was -introduced later in the development.</p> ---ldx]]-- - -local lastdefined  = nil -- we don't want this one to end up in s-tra-02 -local internalized = { } - -function definers.current() -- or maybe current -    return lastdefined -end - -function definers.registered(hash) -    local id = internalized[hash] -    return id, id and fontdata[id] -end - -function definers.register(tfmdata,id) -    if tfmdata and id then -        local hash = tfmdata.properties.hash -        if not internalized[hash] then -            internalized[hash] = id -            if trace_defining then -                report_defining("registering font, id: %s, hash: %s",id or "?",hash or "?") -            end -            fontdata[id] = tfmdata -        end -    end -end - -function definers.read(specification,size,id) -- id can be optional, name can already be table -    statistics.starttiming(fonts) -    if type(specification) == "string" then -        specification = definers.analyze(specification,size) -    end -    local method = specification.method -    if method and variants[method] then -        specification = variants[method](specification) -    end -    specification = definers.resolve(specification) -    local hash = constructors.hashinstance(specification) -    local tfmdata = definers.registered(hash) -- id -    if tfmdata then -        if trace_defining then -            report_defining("already hashed: %s",hash) -        end -    else -        tfmdata = definers.loadfont(specification) -- can be overloaded -        if tfmdata then -            if trace_defining then -                report_defining("loaded and hashed: %s",hash) -            end -        --~ constructors.checkvirtualid(tfmdata) -- interferes -            tfmdata.properties.hash = hash -            if id then -                definers.register(tfmdata,id) -            end -        else -            if trace_defining then -                report_defining("not loaded and hashed: %s",hash) -            end -        end -    end -    lastdefined = tfmdata or id -- todo ! ! ! ! ! -    if not tfmdata then -- or id? -        report_defining( "unknown font %s, loading aborted",specification.name) -    elseif trace_defining and type(tfmdata) == "table" then -        local properties = tfmdata.properties or { } -        local parameters = tfmdata.parameters or { } -        report_defining("using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s", -                       properties.format        or "unknown", -                       id                       or "?", -                       properties.name          or "?", -                       parameters.size          or "default", -                       properties.encodingbytes or "?", -                       properties.encodingname  or "unicode", -                       properties.fullname      or "?", -         file.basename(properties.filename      or "?")) -    end -    statistics.stoptiming(fonts) -    return tfmdata -end - ---[[ldx-- -<p>We overload the <l n='tfm'/> reader.</p> ---ldx]]-- - -callbacks.register('define_font', definers.read, "definition of fonts (tfmdata preparation)") | 
