diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/scrp-ini.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/scrp-ini.lua | 448 |
1 files changed, 272 insertions, 176 deletions
diff --git a/Master/texmf-dist/tex/context/base/scrp-ini.lua b/Master/texmf-dist/tex/context/base/scrp-ini.lua index e55dc0780ea..c375e2ec3d7 100644 --- a/Master/texmf-dist/tex/context/base/scrp-ini.lua +++ b/Master/texmf-dist/tex/context/base/scrp-ini.lua @@ -16,173 +16,182 @@ local trace_injections = false trackers.register("scripts.injections", function local report_preprocessing = logs.reporter("scripts","preprocessing") -local allocate = utilities.storage.allocate - -local set_attribute = node.set_attribute -local has_attribute = node.has_attribute -local first_glyph = node.first_glyph or node.first_character -local traverse_id = node.traverse_id - -local texsetattribute = tex.setattribute - -local nodecodes = nodes.nodecodes -local unsetvalue = attributes.unsetvalue - -local glyph_code = nodecodes.glyph -local glue_code = nodecodes.glue - -local a_preproc = attributes.private('preproc') -local a_prestat = attributes.private('prestat') - -local fontdata = fonts.hashes.identifiers - -local setnodecolor = nodes.tracers.colors.set - -scripts = scripts or { } -local scripts = scripts - -scripts.hash = scripts.hash or { } -local hash = scripts.hash - -local handlers = allocate() -scripts.handlers = handlers - -storage.register("scripts/hash", hash, "scripts.hash") - -if not next(hash) then -- this might move to char-def - - hash = { -- no local - -- - -- half width opening parenthesis - [0x0028] = "half_width_open", - [0x005B] = "half_width_open", - [0x007B] = "half_width_open", - [0x2018] = "half_width_open", -- ‘ - [0x201C] = "half_width_open", -- “ - -- - -- full width opening parenthesis - -- - [0x3008] = "full_width_open", -- 〈 Left book quote - [0x300A] = "full_width_open", -- 《 Left double book quote - [0x300C] = "full_width_open", -- 「 left quote - [0x300E] = "full_width_open", -- 『 left double quote - [0x3010] = "full_width_open", -- 【 left double book quote - [0x3014] = "full_width_open", -- 〔 left book quote - [0x3016] = "full_width_open", --〖 left double book quote - [0x3018] = "full_width_open", -- left tortoise bracket - [0x301A] = "full_width_open", -- left square bracket - [0x301D] = "full_width_open", -- reverse double prime qm - [0xFF08] = "full_width_open", -- ( left parenthesis - [0xFF3B] = "full_width_open", -- [ left square brackets - [0xFF5B] = "full_width_open", -- { left curve bracket - -- - -- half width closing parenthesis - [0x0029] = "half_width_close", - [0x005D] = "half_width_close", - [0x007D] = "half_width_close", - [0x2019] = "half_width_close", -- ’ right quote, right - [0x201D] = "half_width_close", -- ” right double quote - -- - -- full width closing parenthesis - -- - [0x3009] = "full_width_close", -- 〉 book quote - [0x300B] = "full_width_close", -- 》 double book quote - [0x300D] = "full_width_close", -- 」 right quote, right - [0x300F] = "full_width_close", -- 』 right double quote - [0x3011] = "full_width_close", -- 】 right double book quote - [0x3015] = "full_width_close", -- 〕 right book quote - [0x3017] = "full_width_close", -- 〗 right double book quote - [0x3019] = "full_width_close", -- right tortoise bracket - [0x301B] = "full_width_close", -- right square bracket - [0x301E] = "full_width_close", -- double prime qm - [0x301F] = "full_width_close", -- low double prime qm - [0xFF09] = "full_width_close", -- ) right parenthesis - [0xFF3D] = "full_width_close", -- ] right square brackets - [0xFF5D] = "full_width_close", -- } right curve brackets - - [0xFF62] = "half_width_open", -- left corner bracket - [0xFF63] = "half_width_close", -- right corner bracket - -- - -- vertical opening vertical - -- - -- 0xFE35, 0xFE37, 0xFE39, 0xFE3B, 0xFE3D, 0xFE3F, 0xFE41, 0xFE43, 0xFE47, - -- - -- vertical closing - -- - -- 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42, 0xFE44, 0xFE48, - -- - -- half width opening punctuation - -- - -- <empty> - -- - -- full width opening punctuation - -- - -- 0x2236, -- ∶ - -- 0xFF0C, -- , - -- - -- half width closing punctuation_hw - -- - [0x0021] = "half_width_close", -- ! - [0x002C] = "half_width_close", -- , - [0x002E] = "half_width_close", -- . - [0x003A] = "half_width_close", -- : - [0x003B] = "half_width_close", -- ; - [0x003F] = "half_width_close", -- ? - [0xFF61] = "half_width_close", -- hw full stop - -- - -- full width closing punctuation - [0x3001] = "full_width_close", -- 、 - [0x3002] = "full_width_close", -- 。 - [0xFF0C] = "full_width_close", -- , - [0xFF0E] = "full_width_close", -- . - -- depends on font - [0xFF01] = "full_width_close", -- ! - [0xFF1F] = "full_width_close", -- ? - -- - [0xFF1A] = "full_width_punct", -- : - [0xFF1B] = "full_width_punct", -- ; - -- non starter - -- - [0x3005] = "non_starter", [0x3041] = "non_starter", [0x3043] = "non_starter", [0x3045] = "non_starter", [0x3047] = "non_starter", - [0x3049] = "non_starter", [0x3063] = "non_starter", [0x3083] = "non_starter", [0x3085] = "non_starter", [0x3087] = "non_starter", - [0x308E] = "non_starter", [0x3095] = "non_starter", [0x3096] = "non_starter", [0x309B] = "non_starter", [0x309C] = "non_starter", - [0x309D] = "non_starter", [0x309E] = "non_starter", [0x30A0] = "non_starter", [0x30A1] = "non_starter", [0x30A3] = "non_starter", - [0x30A5] = "non_starter", [0x30A7] = "non_starter", [0x30A9] = "non_starter", [0x30C3] = "non_starter", [0x30E3] = "non_starter", - [0x30E5] = "non_starter", [0x30E7] = "non_starter", [0x30EE] = "non_starter", [0x30F5] = "non_starter", [0x30F6] = "non_starter", - [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31F0] = "non_starter", [0x31F1] = "non_starter", - [0x30F2] = "non_starter", [0x30F3] = "non_starter", [0x30F4] = "non_starter", [0x31F5] = "non_starter", [0x31F6] = "non_starter", - [0x30F7] = "non_starter", [0x30F8] = "non_starter", [0x30F9] = "non_starter", [0x31FA] = "non_starter", [0x31FB] = "non_starter", - [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31FF] = "non_starter", - -- - -- hyphenation - -- - [0x2026] = "hyphen", -- … ellipsis - [0x2014] = "hyphen", -- — hyphen - } - - for i=0x03040,0x030FF do if not hash[i] then hash[i] = "katakana" end end -- had tag 'chinese' - for i=0x031F0,0x031FF do if not hash[i] then hash[i] = "katakana" end end -- had tag 'chinese' - for i=0x032D0,0x032FE do if not hash[i] then hash[i] = "katakana" end end -- had tag 'chinese' - for i=0x03400,0x04DFF do if not hash[i] then hash[i] = "chinese" end end - for i=0x04E00,0x09FFF do if not hash[i] then hash[i] = "chinese" end end - for i=0x0F900,0x0FAFF do if not hash[i] then hash[i] = "chinese" end end - for i=0x0FF00,0x0FFEF do if not hash[i] then hash[i] = "katakana" end end -- had tag 'chinese' - for i=0x20000,0x2A6DF do if not hash[i] then hash[i] = "chinese" end end - for i=0x2F800,0x2FA1F do if not hash[i] then hash[i] = "chinese" end end - for i=0x0AC00,0x0D7A3 do if not hash[i] then hash[i] = "korean" end end - for i=0x01100,0x0115F do if not hash[i] then hash[i] = "jamo_initial" end end - for i=0x01160,0x011A7 do if not hash[i] then hash[i] = "jamo_medial" end end - for i=0x011A8,0x011FF do if not hash[i] then hash[i] = "jamo_final" end end - - for i=0x01200,0x0139F do hash[i] = "ethiopic_syllable" end - - hash[0x01361] = "ethiopic_word" - hash[0x01362] = "ethiopic_sentence" - - scripts.hash = hash +local utfchar = utf.char + +local first_glyph = node.first_glyph or node.first_character +local traverse_id = node.traverse_id + +local texsetattribute = tex.setattribute + +local nodecodes = nodes.nodecodes +local unsetvalue = attributes.unsetvalue + +local glyph_code = nodecodes.glyph +local glue_code = nodecodes.glue + +local a_preproc = attributes.private('preproc') +local a_prestat = attributes.private('prestat') + +local fontdata = fonts.hashes.identifiers +local allocate = utilities.storage.allocate +local setnodecolor = nodes.tracers.colors.set +local setmetatableindex = table.setmetatableindex + +scripts = scripts or { } +local scripts = scripts + +scripts.hash = scripts.hash or { } +local hash = scripts.hash + +local handlers = allocate() +scripts.handlers = handlers + +local hash = { -- we could put these presets in char-def.lua + -- + -- half width opening parenthesis + -- + [0x0028] = "half_width_open", + [0x005B] = "half_width_open", + [0x007B] = "half_width_open", + [0x2018] = "half_width_open", -- ‘ + [0x201C] = "half_width_open", -- “ + -- + -- full width opening parenthesis + -- + [0x3008] = "full_width_open", -- 〈 Left book quote + [0x300A] = "full_width_open", -- 《 Left double book quote + [0x300C] = "full_width_open", -- 「 left quote + [0x300E] = "full_width_open", -- 『 left double quote + [0x3010] = "full_width_open", -- 【 left double book quote + [0x3014] = "full_width_open", -- 〔 left book quote + [0x3016] = "full_width_open", --〖 left double book quote + [0x3018] = "full_width_open", -- left tortoise bracket + [0x301A] = "full_width_open", -- left square bracket + [0x301D] = "full_width_open", -- reverse double prime qm + [0xFF08] = "full_width_open", -- ( left parenthesis + [0xFF3B] = "full_width_open", -- [ left square brackets + [0xFF5B] = "full_width_open", -- { left curve bracket + -- + -- half width closing parenthesis + -- + [0x0029] = "half_width_close", + [0x005D] = "half_width_close", + [0x007D] = "half_width_close", + [0x2019] = "half_width_close", -- ’ right quote, right + [0x201D] = "half_width_close", -- ” right double quote + -- + -- full width closing parenthesis + -- + [0x3009] = "full_width_close", -- 〉 book quote + [0x300B] = "full_width_close", -- 》 double book quote + [0x300D] = "full_width_close", -- 」 right quote, right + [0x300F] = "full_width_close", -- 』 right double quote + [0x3011] = "full_width_close", -- 】 right double book quote + [0x3015] = "full_width_close", -- 〕 right book quote + [0x3017] = "full_width_close", -- 〗 right double book quote + [0x3019] = "full_width_close", -- right tortoise bracket + [0x301B] = "full_width_close", -- right square bracket + [0x301E] = "full_width_close", -- double prime qm + [0x301F] = "full_width_close", -- low double prime qm + [0xFF09] = "full_width_close", -- ) right parenthesis + [0xFF3D] = "full_width_close", -- ] right square brackets + [0xFF5D] = "full_width_close", -- } right curve brackets + -- + [0xFF62] = "half_width_open", -- left corner bracket + [0xFF63] = "half_width_close", -- right corner bracket + -- + -- vertical opening vertical + -- + -- 0xFE35, 0xFE37, 0xFE39, 0xFE3B, 0xFE3D, 0xFE3F, 0xFE41, 0xFE43, 0xFE47, + -- + -- vertical closing + -- + -- 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42, 0xFE44, 0xFE48, + -- + -- half width opening punctuation + -- + -- <empty> + -- + -- full width opening punctuation + -- + -- 0x2236, -- ∶ + -- 0xFF0C, -- , + -- + -- half width closing punctuation_hw + -- + [0x0021] = "half_width_close", -- ! + [0x002C] = "half_width_close", -- , + [0x002E] = "half_width_close", -- . + [0x003A] = "half_width_close", -- : + [0x003B] = "half_width_close", -- ; + [0x003F] = "half_width_close", -- ? + [0xFF61] = "half_width_close", -- hw full stop + -- + -- full width closing punctuation + -- + [0x3001] = "full_width_close", -- 、 + [0x3002] = "full_width_close", -- 。 + [0xFF0C] = "full_width_close", -- , + [0xFF0E] = "full_width_close", -- + -- + -- depends on font + -- + [0xFF01] = "full_width_close", -- ! + [0xFF1F] = "full_width_close", -- ? + -- + [0xFF1A] = "full_width_punct", -- : + [0xFF1B] = "full_width_punct", -- ; + -- + -- non starter + -- + [0x3005] = "non_starter", [0x3041] = "non_starter", [0x3043] = "non_starter", [0x3045] = "non_starter", [0x3047] = "non_starter", + [0x3049] = "non_starter", [0x3063] = "non_starter", [0x3083] = "non_starter", [0x3085] = "non_starter", [0x3087] = "non_starter", + [0x308E] = "non_starter", [0x3095] = "non_starter", [0x3096] = "non_starter", [0x309B] = "non_starter", [0x309C] = "non_starter", + [0x309D] = "non_starter", [0x309E] = "non_starter", [0x30A0] = "non_starter", [0x30A1] = "non_starter", [0x30A3] = "non_starter", + [0x30A5] = "non_starter", [0x30A7] = "non_starter", [0x30A9] = "non_starter", [0x30C3] = "non_starter", [0x30E3] = "non_starter", + [0x30E5] = "non_starter", [0x30E7] = "non_starter", [0x30EE] = "non_starter", [0x30F5] = "non_starter", [0x30F6] = "non_starter", + [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31F0] = "non_starter", [0x31F1] = "non_starter", + [0x30F2] = "non_starter", [0x30F3] = "non_starter", [0x30F4] = "non_starter", [0x31F5] = "non_starter", [0x31F6] = "non_starter", + [0x30F7] = "non_starter", [0x30F8] = "non_starter", [0x30F9] = "non_starter", [0x31FA] = "non_starter", [0x31FB] = "non_starter", + [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31FF] = "non_starter", + -- + -- hyphenation + -- + [0x2026] = "hyphen", -- … ellipsis + [0x2014] = "hyphen", -- — hyphen + -- + [0x1361] = "ethiopic_word", + [0x1362] = "ethiopic_sentence", + -- +} +local function provide(t,k) + local v + if not tonumber(k) then v = false + elseif (k >= 0x03040 and k <= 0x030FF) + or (k >= 0x031F0 and k <= 0x031FF) + or (k >= 0x032D0 and k <= 0x032FE) + or (k >= 0x0FF00 and k <= 0x0FFEF) then v = "katakana" + elseif (k >= 0x03400 and k <= 0x04DFF) + or (k >= 0x04E00 and k <= 0x09FFF) + or (k >= 0x0F900 and k <= 0x0FAFF) + or (k >= 0x20000 and k <= 0x2A6DF) + or (k >= 0x2F800 and k <= 0x2FA1F) then v = "chinese" + elseif (k >= 0x0AC00 and k <= 0x0D7A3) then v = "korean" + elseif (k >= 0x01100 and k <= 0x0115F) then v = "jamo_initial" + elseif (k >= 0x01160 and k <= 0x011A7) then v = "jamo_medial" + elseif (k >= 0x011A8 and k <= 0x011FF) then v = "jamo_final" + elseif (k >= 0x01200 and k <= 0x0139F) then v = "ethiopic_syllable" + else v = false + end + t[k] = v + return v end +setmetatableindex(hash,provide) + +scripts.hash = hash + local numbertodataset = allocate() local numbertohandler = allocate() @@ -208,11 +217,11 @@ function scripts.installmethod(handler) local attributes = { } local datasets = handler.datasets if not datasets or not datasets.default then - report_preprocessing("missing (default) dataset in script '%s'",name) + report_preprocessing("missing (default) dataset in script %a",name) datasets.default = { } -- slower but an error anyway end for k, v in next, datasets do - table.setmetatableindex(v,defaults) + setmetatableindex(v,defaults) end setmetatable(attributes, { __index = function(t,k) @@ -248,7 +257,7 @@ function scripts.installdataset(specification) -- global overload if p then defaultset = p else - report_preprocessing("dataset, unknown parent '%s' for method '%s'",parent,method) + report_preprocessing("dataset, unknown parent %a for method %a",parent,method) end end setmetatable(dataset,defaultset) @@ -261,13 +270,13 @@ function scripts.installdataset(specification) -- global overload datasets[name] = dataset end else - report_preprocessing("dataset, no default for method '%s'",method) + report_preprocessing("dataset, no default for method %a",method) end else - report_preprocessing("dataset, no datasets for method '%s'",method) + report_preprocessing("dataset, no datasets for method %a",method) end else - report_preprocessing("dataset, no method '%s'",method) + report_preprocessing("dataset, no method %a",method) end else report_preprocessing("dataset, invalid specification") -- maybe report table @@ -336,7 +345,7 @@ scripts.numbertocategory = numbertocategory local function colorize(start,stop) for n in traverse_id(glyph_code,start) do - local kind = numbertocategory[has_attribute(n,a_prestat)] + local kind = numbertocategory[n[a_prestat]] if kind then local ac = scriptcolors[kind] if ac then @@ -368,7 +377,7 @@ end -- we can have a fonts.hashes.originals function scripts.preprocess(head) - local start = first_glyph(head) + local start = first_glyph(head) -- we already have glyphs here (subtype 1) if not start then return head, false else @@ -377,7 +386,7 @@ function scripts.preprocess(head) while start do local id = start.id if id == glyph_code then - local a = has_attribute(start,a_preproc) + local a = start[a_preproc] if a then if a ~= last_a then if first then @@ -415,15 +424,15 @@ function scripts.preprocess(head) end local h = hash[c] if h then - set_attribute(start,a_prestat,categorytonumber[h]) + start[a_prestat] = categorytonumber[h] if not first then first, last = start, start else last = start end - -- if cjk == "chinese" or cjk == "korean" then -- we need to prevent too much ( ) processing + -- if cjk == "chinese" or cjk == "korean" then -- we need to prevent too much ( ) processing ok = true - -- end + -- end elseif first then if ok then if trace_analyzing then @@ -492,3 +501,90 @@ function scripts.preprocess(head) return head, done end end + +-- new plugin: + +local registercontext = fonts.specifiers.registercontext +local mergecontext = fonts.specifiers.mergecontext + +local otfscripts = characters.otfscripts + +local report_scripts = logs.reporter("scripts","auto feature") +local trace_scripts = false trackers.register("scripts.autofeature",function(v) trace_scripts = v end) + +local autofontfeature = scripts.autofontfeature or { } +scripts.autofontfeature = autofontfeature + +local cache_yes = { } +local cache_nop = { } + +setmetatableindex(cache_yes,function(t,k) local v = { } t[k] = v return v end) +setmetatableindex(cache_nop,function(t,k) local v = { } t[k] = v return v end) + +-- beware: we need to tag a done (otherwise too many extra instances ... but how +-- often unpack? wait till we have a bitmap +-- +-- we can consider merging this in handlers.characters(head) at some point as there +-- already check for the dynamic attribute so it saves a pass, however, then we also +-- need to check for a_preproc there which nils the benefit +-- +-- we can consider cheating: set all glyphs in a word as the first one but it's not +-- playing nice + +function autofontfeature.handler(head) + for n in traverse_id(glyph_code,head) do + -- if n[a_preproc] then + -- -- already tagged by script feature, maybe some day adapt + -- else + local char = n.char + local script = otfscripts[char] + if script then + local dynamic = n[0] or 0 + local font = n.font + if dynamic > 0 then + local slot = cache_yes[font] + local attr = slot[script] + if not attr then + attr = mergecontext(dynamic,name,2) + slot[script] = attr + if trace_scripts then + report_scripts("script: %s, trigger %C, dynamic: %a, variant: %a",script,char,attr,"extended") + end + end + if attr ~= 0 then + n[0] = attr + -- maybe set preproc when associated + end + else + local slot = cache_nop[font] + local attr = slot[script] + if not attr then + attr = registercontext(font,script,2) + slot[script] = attr + if trace_scripts then + report_scripts("script: %s, trigger %C, dynamic: %s, variant: %a",script,char,attr,"normal") + end + end + if attr ~= 0 then + n[0] = attr + -- maybe set preproc when associated + end + end + end + -- end + end + return head +end + +function autofontfeature.enable() + report_scripts("globally enabled") + nodes.tasks.enableaction("processors","scripts.autofontfeature.handler") +end + +function autofontfeature.disable() + report_scripts("globally disabled") + nodes.tasks.disableaction("processors","scripts.autofontfeature.handler") +end + +commands.enableautofontscript = autofontfeature.enable +commands.disableautofontscript = autofontfeature.disable |