diff options
Diffstat (limited to 'macros/luatex/latex/spacekern/spacekern.lua')
-rw-r--r-- | macros/luatex/latex/spacekern/spacekern.lua | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/macros/luatex/latex/spacekern/spacekern.lua b/macros/luatex/latex/spacekern/spacekern.lua new file mode 100644 index 0000000000..7ea754d0ab --- /dev/null +++ b/macros/luatex/latex/spacekern/spacekern.lua @@ -0,0 +1,174 @@ +-- Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de + +-- This file may be distributed and/or modified under the +-- conditions of the LaTeX Project Public License, either +-- version 1.3c of this license or (at your option) any later +-- version. The latest version of this license is in + +-- http://www.latex-project.org/lppl.txt + +-- and version 1.3c or later is part of all distributions of +-- LaTeX version 2009/09/24 or later. + +-- Version: 0.1 + +local ID = node.id +local GLYPH = ID ( "glyph" ) +local GLUE = ID ( "glue" ) +local KERN = ID ( "kern" ) +local WI = ID ( "whatsit" ) +local BOUND = ID ( "boundary" ) +local PENALTY = ID ( "penalty" ) +local SWAPPED = table.swapped +local SUBTYPES = node.subtypes +local USERKERN = SWAPPED ( SUBTYPES ("kern") )["userkern"] +local LBPENALTY = SWAPPED ( SUBTYPES ("penalty") )["linebreakpenalty"] +local SPACESKIP = SWAPPED ( SUBTYPES ("glue") )["spaceskip"] +local NEW = node.new +local REM = node.remove +local PREV = node.prev +local NEXT = node.next +local INS_B = node.insert_before +local T_ID = node.traverse_id +local T_GLYPH = node.traverse_glyph +local WIS = node.whatsits() +local userdefined +local pairs = pairs +local FLOOR = math.floor +local GET_FONT = font.getfont +local ATC = luatexbase.add_to_callback + +local no_iw_kern = false + +function spacekern_no_iw_kern () + no_iw_kern = true +end + +local function round ( num, dec ) + return FLOOR ( num * 10^dec + 0.5 ) / 10^dec +end + +for key, value in pairs ( WIS ) do + if value == "user_defined" then + userdefined = key + end +end + +local function find_glyph ( n, d ) + if d ( n ) then + n = d ( n ) + while n.id ~= GLYPH do + if not d ( n ) or n.id == GLUE or n.id == BOUND or ( n.id == KERN and n.subtype == USERKERN ) then return false end + n = d ( n ) + end + else + return false + end + return n +end + +local function make_kern ( head, font, first_glyph, second_glyph, insert_point ) + local tfmdata = GET_FONT ( font ) + if tfmdata.resources then + local resources = tfmdata.resources + if resources.sequences then + local seq = resources.sequences + for _, t in pairs ( seq ) do + if t.steps then + local steps = t.steps + for _, k in pairs ( steps ) do + if k.coverage then + local first_number = true + if k.coverage[first_glyph] then + local glyph_table = k.coverage[first_glyph] + if type ( glyph_table ) == "table" then + for key, value in pairs ( glyph_table ) do + if key == second_glyph and type ( value ) == "number" and first_number and ( k.format == "move" or tfmdata.specification.features.raw[t.name] ) then + if tfmdata.specification.features.raw[t.name] then + first_number = false + end + if PREV ( insert_point ).id == PENALTY then + insert_point = PREV ( insert_point ) + end + INS_B ( head, insert_point, NEW ( KERN ) ) + PREV ( insert_point ).kern = value / tfmdata.units_per_em * tfmdata.size + end + end + end + end + end + end + end + end + end + end +end + +local function check_glyph ( n, d, has_prev_next_glyph, prev_next_glyph ) + if find_glyph ( n, d ) then + prev_next_glyph = find_glyph ( n, d ) + has_prev_next_glyph = true + end + return has_prev_next_glyph, prev_next_glyph +end + +local function make_kerns ( head, n ) + local has_prev_glyph = false + local has_next_glyph = false + local prev_glyph = n + local next_glyph = n + has_prev_glyph, prev_glyph = check_glyph ( n, PREV, has_prev_glyph, prev_glyph ) + has_next_glyph, next_glyph = check_glyph ( n, NEXT, has_next_glyph, next_glyph ) + if has_prev_glyph and prev_glyph.char and prev_glyph.font then + make_kern ( head, prev_glyph.font, prev_glyph.char, 32, n ) + end + if has_next_glyph and next_glyph.char and next_glyph.font then + make_kern ( head, next_glyph.font, 32, next_glyph.char, n ) + end + if not no_iw_kern and has_prev_glyph and has_next_glyph and prev_glyph.char and next_glyph.char and prev_glyph.font and next_glyph.font and ( prev_glyph.font == next_glyph.font ) then + make_kern ( head, prev_glyph.font, prev_glyph.char, next_glyph.char, n ) + end +end + +local function make_glues_and_kerns ( head ) + for n in T_ID ( GLUE, head ) do + make_kerns ( head, n ) + end + for n in T_GLYPH ( head ) do + if n.char and n.char == 59 and ( not find_glyph ( n, PREV ) or find_glyph ( n, PREV ).char ~= 59 ) then + if find_glyph ( n, NEXT ) then + local next_glyph = n + next_glyph = find_glyph ( n, NEXT ) + if next_glyph.char and next_glyph.char == 59 then + REM ( head, next_glyph ) + local SIZE = 0 + if n.font then + local tfmdata = GET_FONT ( n.font ) + if tfmdata.size then + SIZE = tfmdata.size + end + end + INS_B ( head, n, NEW ( GLUE ) ) + local glue_node = PREV ( n ) + glue_node.subtype = SPACESKIP + glue_node.width = round ( SIZE * .16667, 0 ) + local has_next_glyph = false + if find_glyph ( n, NEXT ) then + next_glyph = find_glyph ( n, NEXT ) + has_next_glyph = true + end + if has_next_glyph and next_glyph.char and next_glyph.char == 59 then + INS_B ( head, glue_node, NEW ( PENALTY ) ) + PREV ( glue_node ).subtype = LBPENALTY + PREV ( glue_node ).penalty = 10000 + REM ( head, next_glyph ) + end + REM ( head, n ) + make_kerns ( head, glue_node ) + end + end + end + end +end + +ATC ( "ligaturing", make_glues_and_kerns, "kern between words and against space", 1 )
\ No newline at end of file |