diff options
| author | Philipp Gesang <phg42.2a@gmail.com> | 2013-05-19 20:08:26 +0200 | 
|---|---|---|
| committer | Philipp Gesang <phg42.2a@gmail.com> | 2013-05-19 20:08:26 +0200 | 
| commit | 1489b66525103c3762ac1f3dea63214db01a798c (patch) | |
| tree | 09cf00bfefa18dffb2579530565aaae9f4a7f815 | |
| parent | bb65ba28ea757225f9bb5707c631e8444db5954e (diff) | |
| download | luaotfload-1489b66525103c3762ac1f3dea63214db01a798c.tar.gz | |
add font-dependent letterspacing
| -rw-r--r-- | luaotfload-letterspace.lua | 254 | 
1 files changed, 254 insertions, 0 deletions
| diff --git a/luaotfload-letterspace.lua b/luaotfload-letterspace.lua new file mode 100644 index 0000000..fabf62b --- /dev/null +++ b/luaotfload-letterspace.lua @@ -0,0 +1,254 @@ +if not modules then modules = { } end modules ['typo-krn'] = { +    version   = 1.001, +    comment   = "companion to typo-krn.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +local next               = next +local nodes, node, fonts = nodes, node, fonts + +local find_node_tail     = node.tail or node.slide +local free_node          = node.free +local free_nodelist      = node.flush_list +local copy_node          = node.copy +local copy_nodelist      = node.copy_list +local insert_node_before = node.insert_before +local insert_node_after  = node.insert_after + +local nodepool           = nodes.pool +local tasks              = nodes.tasks + +local new_kern           = nodepool.kern +local new_glue           = nodepool.glue + +local nodecodes          = nodes.nodecodes +local kerncodes          = nodes.kerncodes +local skipcodes          = nodes.skipcodes + +local glyph_code         = nodecodes.glyph +local kern_code          = nodecodes.kern +local disc_code          = nodecodes.disc +local glue_code          = nodecodes.glue +local hlist_code         = nodecodes.hlist +local vlist_code         = nodecodes.vlist +local math_code          = nodecodes.math + +local kerning_code       = kerncodes.kerning +local userkern_code      = kerncodes.userkern + +local fonthashes         = fonts.hashes +local chardata           = fonthashes.characters +local quaddata           = fonthashes.quads + +typesetters              = typesetters or { } +local typesetters        = typesetters + +typesetters.kernfont     = typesetters.kernfont or { } +local kernfont           = typesetters.kernfont + +kernfont.keepligature    = false +kernfont.keeptogether    = false + +local kern_injector = function (fillup,kern) +  if fillup then +    local g = new_glue(kern) +    local s = g.spec +    s.stretch = kern +    s.stretch_order = 1 +    return g +  else +    return new_kern(kern) +  end +end + +local kernfactors = { } --- fontid -> factor + +local kerncharacters +kerncharacters = function (head) +  local start, done   = head, false +  local lastfont      = nil +  local keepligature  = kernfont.keepligature --- function +  local keeptogether  = kernfont.keeptogether --- function +  local fillup        = false + +  local identifiers   = fonthashes.identifiers +  local kernfactors   = kernfactors + +  while start do +    local attr = start[attribute] +    local id = start.id +    if id == glyph_code then + +      --- 1) look up kern factor (slow, but cached rudimentarily) +      local krn +      local fontid = start.font +      do +        krn = kernfactors[fontid] +        if not krn then +          local tfmdata = identifiers[fontid] +          if not tfmdata then -- unsafe +            tfmdata = font.fonts[fontid] +          end +          if tfmdata then +            fontproperties = tfmdata.properties +            if fontproperties then +              krn = fontproperties.kerncharacters +            end +          end +          kernfactors[fontid] = krn +        end +        if not krn or krn == 0 then +          goto nextnode +        end +      end + +      if krn == "max" then +        krn = .25 +        fillup = true +      else +        fillup = false +      end + +      lastfont = fontid +      local c = start.components + +      if c then +        if keepligature and keepligature(start) then +          -- keep 'm +        else +          c = kerncharacters (c) +          local s = start +          local p, n = s.prev, s.next +          local tail = find_node_tail(c) +          if p then +            p.next = c +            c.prev = p +          else +            head = c +          end +          if n then +            n.prev = tail +          end +          tail.next = n +          start = c +          s.components = nil +          -- we now leak nodes ! +          --  free_node(s) +          done = true +        end +      end -- kern ligature + +      local prev = start.prev +      if prev then +        local pid = prev.id + +        if not pid then +          -- nothing +        elseif pid == kern_code then +          if prev.subtype == kerning_code or prev[a_fontkern] then +            if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then -- we could also pass start +              -- keep 'm +            else +              -- not yet ok, as injected kerns can be overlays (from node-inj.lua) +              prev.subtype = userkern_code +              prev.kern = prev.kern + quaddata[lastfont]*krn -- here +              done = true +            end +          end +        elseif pid == glyph_code then +          if prev.font == lastfont then +            local prevchar, lastchar = prev.char, start.char +            if keeptogether and keeptogether(prev,start) then +              -- keep 'm +            elseif identifiers[lastfont] then +              local kerns = chardata[lastfont][prevchar].kerns +              local kern = kerns and kerns[lastchar] or 0 +              krn = kern + quaddata[lastfont]*krn -- here +              insert_node_before(head,start,kern_injector(fillup,krn)) +              done = true +            end +          else +            krn = quaddata[lastfont]*krn -- here +            insert_node_before(head,start,kern_injector(fillup,krn)) +            done = true +          end + +        elseif pid == disc_code then +          -- a bit too complicated, we can best not copy and just calculate +          -- but we could have multiple glyphs involved so ... +          local disc = prev -- disc +          local pre, post, replace = disc.pre, disc.post, disc.replace +          local prv, nxt = disc.prev, disc.next + +          if pre and prv then -- must pair with start.prev +            -- this one happens in most cases +            local before = copy_node(prv) +            pre.prev = before +            before.next = pre +            before.prev = nil +            pre = kerncharacters (before) +            pre = pre.next +            pre.prev = nil +            disc.pre = pre +            free_node(before) +          end + +          if post and nxt then  -- must pair with start +            local after = copy_node(nxt) +            local tail = find_node_tail(post) +            tail.next = after +            after.prev = tail +            after.next = nil +            post = kerncharacters (post) +            tail.next = nil +            disc.post = post +            free_node(after) +          end + +          if replace and prv and nxt then -- must pair with start and start.prev +            local before = copy_node(prv) +            local after = copy_node(nxt) +            local tail = find_node_tail(replace) +            replace.prev = before +            before.next = replace +            before.prev = nil +            tail.next = after +            after.prev = tail +            after.next = nil +            replace = kerncharacters (before) +            replace = replace.next +            replace.prev = nil +            after.prev.next = nil +            disc.replace = replace +            free_node(after) +            free_node(before) +          elseif identifiers[lastfont] then +            if prv and prv.id == glyph_code and prv.font == lastfont then +              local prevchar, lastchar = prv.char, start.char +              local kerns = chardata[lastfont][prevchar].kerns +              local kern = kerns and kerns[lastchar] or 0 +              krn = kern + quaddata[lastfont]*krn -- here +            else +              krn = quaddata[lastfont]*krn -- here +            end +            disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue +          end + +        end +      end +    end + +    ::nextnode:: +    if start then +      start = start.next +    end +  end +  return head, done +end + +kernfont.handler = kerncharacters + +--- vim:sw=2:ts=2:expandtab + | 
