1if not modules then modules = { } end modules ['font-otd'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to font-ini.mkiv",
5 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6 copyright = "PRAGMA ADE / ConTeXt Development Team",
7 license = "see context related readme files"
8}
9
10local type = type
11local match = string.match
12local sequenced = table.sequenced
13
14local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
15local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
16
17local report_otf = logs.reporter("fonts","otf loading")
18local report_process = logs.reporter("fonts","otf process")
19
20local allocate = utilities.storage.allocate
21
22local fonts = fonts
23local otf = fonts.handlers.otf
24local hashes = fonts.hashes
25local definers = fonts.definers
26local constructors = fonts.constructors
27local specifiers = fonts.specifiers
28
29local fontidentifiers = hashes.identifiers
30local fontresources = hashes.resources
31local fontproperties = hashes.properties
32local fontdynamics = hashes.dynamics
33
34local contextsetups = specifiers.contextsetups
35local contextnumbers = specifiers.contextnumbers
36local contextmerged = specifiers.contextmerged
37
38local setmetatableindex = table.setmetatableindex
39
40local a_to_script = { }
41local a_to_language = { }
42
43
44
45function otf.setdynamics(font,attribute)
46
47 local features = contextsetups[attribute]
48 if features then
49 local dynamics = fontdynamics[font]
50 dynamic = contextmerged[attribute] or 0
51 local script, language
52 if dynamic == 2 then
53 language = features.language or fontproperties[font].language or "dflt"
54 script = features.script or fontproperties[font].script or "dflt"
55 else
56 language = features.language or "dflt"
57 script = features.script or "dflt"
58 end
59 if script == "auto" then
60
61 script = definers.checkedscript(fontidentifiers[font],fontresources[font],features)
62 end
63 local ds = dynamics[script]
64
65 if not ds then
66 ds = { }
67 dynamics[script] = ds
68 end
69 local dsl = ds[language]
70
71 if not dsl then
72 dsl = { }
73 ds[language] = dsl
74 end
75 local dsla = dsl[attribute]
76 if not dsla then
77 local tfmdata = fontidentifiers[font]
78 a_to_script [attribute] = script
79 a_to_language[attribute] = language
80
81 local properties = tfmdata.properties
82 local shared = tfmdata.shared
83 local s_script = properties.script
84 local s_language = properties.language
85 local s_mode = properties.mode
86 local s_features = shared.features
87 properties.mode = "node"
88 properties.language = language
89 properties.script = script
90 properties.dynamics = true
91 shared.features = { }
92
93 local set = constructors.checkedfeatures("otf",features)
94 set.mode = "node"
95 dsla = otf.setfeatures(tfmdata,set)
96 if trace_dynamics then
97 report_otf("setting dynamics %s: attribute %a, script %a, language %a, set %a",contextnumbers[attribute],attribute,script,language,set)
98 end
99
100 properties.script = s_script
101 properties.language = s_language
102 properties.mode = s_mode
103 shared.features = s_features
104
105 dynamics[script][language][attribute] = dsla
106 elseif trace_dynamics then
107
108 end
109 return dsla
110 end
111end
112
113function otf.scriptandlanguage(tfmdata,attr)
114 local properties = tfmdata.properties
115 if attr and attr > 0 then
116 return a_to_script[attr] or properties.script or "dflt", a_to_language[attr] or properties.language or "dflt"
117 else
118 return properties.script or "dflt", properties.language or "dflt"
119 end
120end
121
122
123
124local autofeatures = fonts.analyzers.features
125local featuretypes = otf.tables.featuretypes
126local defaultscript = otf.features.checkeddefaultscript
127local defaultlanguage = otf.features.checkeddefaultlanguage
128
129local resolved = { }
130local wildcard <const> = "*"
131
132
133
134
135
136local P, C, Cc, lpegmatch = lpeg.P, lpeg.C, lpeg.Cc, lpeg.match
137
138local pattern = P("always") * (P(-1) * Cc(true) + P(":") * C((1-P(-1))^1))
139
140local scriptsets = fonts.specifiers.scriptsets
141
142
143
144local function initialize(sequence,script,language,s_enabled,a_enabled,font,attr,dynamic,ra,autoscript,autolanguage)
145 local features = sequence.features
146 if features then
147 local order = sequence.order
148 if order then
149 local featuretype = featuretypes[sequence.type or "unknown"]
150 local lookupdone = false
151 for i=1,#order do
152 local kind = order[i]
153 local e_e
154 local a_e = a_enabled and a_enabled[kind]
155 if a_e ~= nil then
156 e_e = a_e
157 else
158 e_e = s_enabled and s_enabled[kind]
159 end
160 if e_e then
161 local usedattribute, usedscript, usedlanguage, usedlookup
162 local valid = type(e_e) == "string" and lpegmatch(pattern,e_e)
163 if valid then
164
165 usedattribute = autofeatures[kind] or false
166 usedlanguage = "*"
167 usedscript = "*"
168 usedlookup = { valid, usedattribute, sequence, kind }
169 else
170
171 local scripts = features[kind]
172 local languages = scripts[script] or scripts[wildcard]
173
174 if not languages then
175 local ss = scriptsets[script]
176 if ss then
177 for i=1,#ss do
178 languages = scripts[ss[i]]
179 if languages then
180 break
181 end
182 end
183 end
184 end
185
186 if not languages and autoscript then
187 languages = defaultscript(featuretype,autoscript,scripts)
188 end
189 if languages then
190
191
192
193 if languages[language] then
194 valid = e_e
195 elseif languages[wildcard] then
196 valid = e_e
197 elseif autolanguage and defaultlanguage(featuretype,autolanguage,languages) then
198 valid = e_e
199 end
200 end
201 if valid then
202 usedattribute = autofeatures[kind] or false
203 usedlanguage = language
204 usedscript = script
205 usedlookup = { valid, usedattribute, sequence, kind }
206 end
207 end
208 if not usedlookup then
209
210 elseif lookupdone then
211 if trace_applied then
212 report_process(
213 "font %s, dynamic %a (%a), feature %a, script %a, language %a, lookup %a, value %a, nofsteps %a, lookup already set by %a",
214 font,attr or 0,dynamic,kind,usedscript,usedlanguage,sequence.name,valid,sequence.nofsteps,ra[#ra][4])
215 end
216 else
217 ra[#ra+1] = usedlookup
218 if trace_applied then
219 report_process(
220 "font %s, dynamic %a (%a), feature %a, script %a, language %a, lookup %a, value %a, nofsteps %a",
221 font,attr or 0,dynamic,kind,usedscript,usedlanguage,sequence.name,valid,sequence.nofsteps)
222 else
223 return
224 end
225 lookupdone = true
226 end
227 end
228 end
229 end
230 end
231end
232
233
234
235function otf.dataset(tfmdata,font,attr)
236
237 local script, language, s_enabled, a_enabled, dynamic
238
239 if attr and attr ~= 0 then
240 dynamic = contextmerged[attr] or 0
241
242 local features = contextsetups[attr]
243 a_enabled = features
244 if dynamic == 1 then
245
246 language = features.language or "dflt"
247 script = features.script or "dflt"
248 elseif dynamic == 2 then
249
250 local properties = tfmdata.properties
251 s_enabled = tfmdata.shared.features
252 language = features.language or properties.language or "dflt"
253 script = features.script or properties.script or "dflt"
254 else
255
256 local properties = tfmdata.properties
257 language = properties.language or "dflt"
258 script = properties.script or "dflt"
259 end
260 else
261 local properties = tfmdata.properties
262 language = properties.language or "dflt"
263 script = properties.script or "dflt"
264 s_enabled = tfmdata.shared.features
265 dynamic = 0
266 end
267
268 local res = resolved[font]
269 if not res then
270 res = { }
271 resolved[font] = res
272 end
273 local rs = res[script]
274 if not rs then
275 rs = { }
276 res[script] = rs
277 end
278 local rl = rs[language]
279 if not rl then
280 rl = { }
281 rs[language] = rl
282 end
283 local ra = rl[attr]
284 if ra == nil then
285 ra = {
286
287 }
288 rl[attr] = ra
289 local sequences = tfmdata.shared.reorderedsequences or tfmdata.resources.sequences
290 if sequences then
291 local autoscript = (s_enabled and s_enabled.autoscript ) or (a_enabled and a_enabled.autoscript )
292 local autolanguage = (s_enabled and s_enabled.autolanguage) or (a_enabled and a_enabled.autolanguage)
293 for s=1,#sequences do
294
295 initialize(sequences[s],script,language,s_enabled,a_enabled,font,attr,dynamic,ra,autoscript,autolanguage)
296 end
297 end
298 end
299 return ra
300end
301 |