summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-dvi.lua
blob: b57934fdb6dab0e21ea4b0a1f6b6cc9a22c15b37 (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
-------------------------------------------------------------------------------
--         FILE:  luaotfload-dvi.lua
--  DESCRIPTION:  part of luaotfload / DVI
-------------------------------------------------------------------------------


local ProvidesLuaModule = { 
    name          = "luaotfload-dvi",
    version       = "3.15",       --TAGVERSION
    date          = "2020-09-02", --TAGDATE
    description   = "luaotfload submodule / DVI",
    license       = "GPL v2.0",
    author        = "Marcel Krüger",
    copyright     = "Luaotfload Development Team",  
}

if luatexbase and luatexbase.provides_module then
  luatexbase.provides_module (ProvidesLuaModule)
end  

local getfont = font.getfont
local setfont = node.direct.setfont
local getdisc = node.direct.getdisc
local traverse_glyph = node.direct.traverse_glyph
local traverse_id = node.direct.traverse_id
local uses_font = node.direct.uses_font
local define_font = font.define
local disc_t = node.id'disc'

-- DVI output support
--
-- When writing DVI files, we can't assume that the DVI reader has access to our
-- font dictionaries, so we need an independent representation for our glyphs. The
-- approach we chose in coordination with the dvisvgm author is to create a DVI font
-- name which indicates the font filename and some essential backend parameters
-- (especially otential extend, shrink, embolden, etc. factors) and then use GIDs in
-- the page stream.
--
-- Normally we could easily implement this using virtual fonts, but because we are
-- dealing with DVI output, LuaTeX is not evaluating virtual fonts by itself.
-- So instead, we process the shaped output and replace all glyph nodes with glyph
-- nodes from special fonts which have the characteristics expected brom the DVI reader.

-- mapped_fonts maps fontids from the user to fontids used in the DVI file
local mapped_fonts = setmetatable({}, {__index = function(t, fid)
  local font = getfont(fid)
  local mapped = font.backend_font or false
  t[fid] = mapped
  return mapped
end})

local function process(head, font)
  local mapping = mapped_fonts[font]
  if not mapping then return head end
  local mapped_font = mapping.font
  for n, c, f in traverse_glyph(head) do if f == font then
    local mapped = mapping[c]
    if mapped then setfont(n, mapped_font, mapped) end
  end end
  for n in traverse_id(disc_t, head) do if uses_font(n, font) then
    local pre, post, rep = getdisc(n)
    for n, c, f in traverse_glyph(pre) do if f == font then
      local mapped = mapping[c]
      if mapped then setfont(n, mapped_font, mapped) end
    end end
    for n, c, f in traverse_glyph(post) do if f == font then
      local mapped = mapping[c]
      if mapped then setfont(n, mapped_font, mapped) end
    end end
    for n, c, f in traverse_glyph(rep) do if f == font then
      local mapped = mapping[c]
      if mapped then setfont(n, mapped_font, mapped) end
    end end
  end end
end
local function manipulate(tfmdata, _, dvi_kind)
  if dvi_kind ~= 'dvisvgm' then
    texio.write_nl(string.format('WARNING (luaotfload): Unsupported DVI backend %q, falling back to dvisvgm.', dvi_kind))
  end
  -- Legacy fonts can be written to the DVI file directly
  if 2 ~= (tfmdata.encodingbytes or ((tfmdata.format == 'truetype' or tfmdata.format == 'opentype') and 2 or 1)) then
    return
  end
  local newfont = {}
  for k,v in pairs(tfmdata) do
    newfont[k] = v
  end
  local newchars = {}
  newfont.characters = newchars
  local lookup = {}
  for k,v in pairs(tfmdata.characters) do
    local newchar = {
      width = v.width, -- Only width should really be necessary
      height = v.height,
      depth = v.depth,
    }
    newchars[v.index or k] = newchar
    lookup[k] = v.index or k
  end
  newfont.checksum = string.unpack('>I4', 'LuaF') -- Use a magic checksum such that the reader
                                                  -- can uniquely identify these fonts.
  local name = '[' .. newfont.name .. ']:' -- TODO: Why .name? I would have expected .filename
  if newfont.subfont and newfont.subfont ~= 1 then
    name = name .. 'index=' .. tostring(math.tointeger(newfont.subfont-1)) .. ';'
  end
  if newfont.extend and newfont.extend ~= 1000 then
    name = name .. 'extend=' .. tostring(math.tointeger(math.round(newfont.extend*65.536))) .. ';'
  end
  if newfont.slant and newfont.slant ~= 0 then
    name = name .. 'slant=' .. tostring(math.tointeger(math.round(newfont.slant*65.536))) .. ';'
  end
  if newfont.mode == 2 and newfont.width and newfont.width ~= 0 then
    name = name .. 'embolden=' .. tostring(math.tointeger(math.round(newfont.width*65.78176))) .. ';'
  end
  newfont.name = name:sub(1,-2) -- Stri th trailing : or ;
  tfmdata.backend_font = lookup
  lookup.font = define_font(newfont)
end

fonts.constructors.features.otf.register {
  name = "dvifont",
  default = "dvisvgm",
  manipulators = {
    node = manipulate,
    base = manipulate,
  },
  processors = {
    node = process,
    base = process,
  },
}