summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luaotfload/luaotfload-fallback.lua
blob: 2f010c11d0018a75e62ddaabe09fe8143af248c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
-----------------------------------------------------------------------
--         FILE:  luaotfload-fallback.lua
--  DESCRIPTION:  part of luaotfload / fallback
-----------------------------------------------------------------------

assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") {
    name          = "luaotfload-fallback",
    version       = "3.23",     --TAGVERSION
    date          = "2022-10-03", --TAGDATE
    description   = "luaotfload submodule / fallback",
    license       = "GPL v2.0",
    author        = "Marcel Krüger"
}

local nodenew            = node.direct.new
local getfont            = font.getfont
local setfont            = node.direct.setfont
local getwhd             = node.direct.getwhd
local insert_after       = node.direct.insert_after
local traverse_char      = node.direct.traverse_char
local protect_glyph      = node.direct.protect_glyph
local otffeatures        = fonts.constructors.newfeatures "otf"
-- local normalize          = fonts.handlers.otf.features.normalize
local definers           = fonts.definers
local define_font --     = luaotfload.define_font % This is set when the first font is loaded.

local fallback_table_fontnames = {}

local fallback_table = setmetatable({}, {
  __index = function(t, name)
    local names = fallback_table_fontnames[name]
    if not names then 
      t[name] = false
      return false
    end
    local res = setmetatable({}, {
      __index = function(tt, size)
        local lookup = {}
        for i=#names,1,-1 do
          local f = define_font(names[i] .. ';-fallback', size)
          local fid
          if type(f) == 'table' then
            fid = font.define(f)
            definers.register(f, fid)
          elseif f then
            fid = f
            f = font.getfont(fid)
          end
          lookup[-i] = f -- Needed for multiscript interactions
          for uni, _ in next, f.characters do
            rawset(lookup, uni, fid)
          end
        end
        tt[size] = lookup
        return lookup
      end,
    })
    t[name] = res
    return res
  end,
})

local fallback_lookups = setmetatable({}, {
  __index = function(t, fid)
    local f = font.getfont(fid)
    -- table.tofile('myfont2', f)
    local res = f and f.fallback_lookup or false
    if res then
      res = table.merged(res)
      for uni in next, f.characters do
        rawset(res, uni, nil)
      end
    end
    t[fid] = res
    return res
  end,
})

local function makefallbackfont(tfmdata, _, fallback)
  local t = fallback_table[fallback]
  if not t then error(string.format("Unknown fallback table %s", fallback)) end
  fallback = t[tfmdata.size]
  local fallback_lookup = {}
  tfmdata.fallback_lookup = fallback
end

local glyph_id = node.id'glyph'
-- TODO: inherited fonts (combining accents etc.)
local function dofallback(head, _, _, _, direction)
  head = node.direct.todirect(head)
  local last_fid, last_fallbacks
  for cur, cid, fid in traverse_char(head) do
    if fid ~= last_fid then
      last_fid, last_fallbacks = fid, fallback_lookups[fid]
    end
    if last_fallbacks then
      local new_fid = last_fallbacks[cid]
      if new_fid then
        setfont(cur, new_fid)
      end
    end
  end
end

function luaotfload.add_fallback(name, fonts)
  define_font = define_font or luaotfload.define_font -- Lazy loading because this file get's loaded before define_font is defined
  if fonts == nil then
    fonts = name
    name = #fallback_table_fontnames + 1
  else
    name = name:lower()
  end
  fallback_table_fontnames[name] = fonts
  fallback_table[name] = nil
  return name
end

otffeatures.register {
  name        = "fallback",
  description = "Fill in missing glyphs from other fonts",
  manipulators = {
    node = makefallbackfont,
    plug = makefallbackfont,
  },
  -- processors = { -- processors would be nice, but they are applied
  --                -- too late for our purposes
  --   node = donotdef,
  -- }
}

return {
  process = dofallback,
}
--- vim:sw=2:ts=2:expandtab:tw=71