summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/spacekern/spacekern.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/latex/spacekern/spacekern.lua')
-rw-r--r--macros/luatex/latex/spacekern/spacekern.lua181
1 files changed, 129 insertions, 52 deletions
diff --git a/macros/luatex/latex/spacekern/spacekern.lua b/macros/luatex/latex/spacekern/spacekern.lua
index 442f3845d4..1fd2d5624b 100644
--- a/macros/luatex/latex/spacekern/spacekern.lua
+++ b/macros/luatex/latex/spacekern/spacekern.lua
@@ -1,4 +1,4 @@
--- Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de
+-- Copyright (c) 2022-2023 Thomas Kelkel kelkel@emaileon.de
-- This file may be distributed and/or modified under the
-- conditions of the LaTeX Project Public License, either
@@ -10,34 +10,48 @@
-- and version 1.3c or later is part of all distributions of
-- LaTeX version 2009/09/24 or later.
--- Version: 0.1a
+-- Version: 0.3
local ID = node.id
local GLYPH = ID ( "glyph" )
+local DISC = ID ( "disc" )
local GLUE = ID ( "glue" )
-local KERN = ID ( "kern" )
-local WI = ID ( "whatsit" )
-local BOUND = ID ( "boundary" )
local PENALTY = ID ( "penalty" )
+local HLIST = ID ( "hlist" )
+local INS = ID ( "ins" )
+
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 LEADERS = SWAPPED ( SUBTYPES ("glue") )["leaders"]
+local LBPENALTY = SWAPPED ( SUBTYPES ("penalty") )["linebreakpenalty"]
+
local NEW = node.new
local REM = node.remove
local PREV = node.prev
local NEXT = node.next
+local TAIL = node.tail
local INS_B = node.insert_before
-local T_ID = node.traverse_id
+local HAS_GLYPH = node.has_glyph
+local T = node.traverse
local T_GLYPH = node.traverse_glyph
-local WIS = node.whatsits()
-local userdefined
+
local pairs = pairs
+local type = type
+
+local U = unicode.utf8
+local SUB = U.sub
+local GSUB = U.gsub
+local FIND = U.find
+
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 ()
@@ -48,50 +62,92 @@ 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
+local function find_first_last ( n, node_type, last )
+ local d = NEXT
+ if last then
+ d = PREV
+ n = TAIL ( n )
+ end
+ while true do
+ if n and n.id == node_type then
+ return n
+ end
+ if d ( n ) then
+ n = d ( n )
+ else
+ return false
+ end
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
+local function check_node ( n, space_check, disc_check, last )
+ if n.replace then
+ return find_first_last ( n.replace, GLYPH, last ), space_check, disc_check
+ end
+ return n, space_check, disc_check
+end
+
+local function find_glyph ( n, d, hlist_check, macro )
+ if n then
+ local space_check = false
+ local disc_check = false
+ if hlist_check and ( n.id == GLYPH or n.replace and HAS_GLYPH ( n.replace ) ) then
+ return check_node ( n, space_check, disc_check, d == PREV )
+ elseif not hlist_check then
+ if d ( n ) then
+ n = d ( n )
+ else
+ return false
+ end
+ end
+ while not ( n.id == GLYPH or n.replace and HAS_GLYPH ( n.replace ) ) do
+ if n.id == HLIST and n.head then
+ local point = n.head
+ if d == PREV then
+ point = TAIL ( point )
+ end
+ return find_glyph ( point, d, true, macro )
+ end
+ if not d ( n ) or n.id == INS or macro and n.id == GLUE and n.width == 0 then
+ return false
+ else
+ if n.id == GLUE and n.subtype == SPACESKIP then
+ space_check = n
+ elseif n.subtype == LEADERS or n.id == GLUE and n.stretch > 0 then
+ return false
+ end
+ end
+ if n.id == DISC then
+ disc_check = n
+ end
n = d ( n )
end
- else
- return false
+ return check_node ( n, space_check, disc_check, d == PREV )
end
- return n
+ return false
end
local function make_kern ( head, font, first_glyph, second_glyph, insert_point )
local tfmdata = GET_FONT ( font )
- if tfmdata.resources then
+ if tfmdata and 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
+ if t.steps and ( table.swapped ( t.order )["kern"] or tfmdata.specification.features.raw[t.name] ) 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
+ if k.coverage and 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" then
+ if not ( ( first_glyph == 32 or second_glyph == 32 ) and table.swapped ( t.order )["kern"] ) then
+ insert_point.width = insert_point.width + value / tfmdata.units_per_em * tfmdata.size
+ end
+ if first_glyph == 32 or second_glyph == 32 then
+ insert_point.stretch = insert_point.stretch + value / tfmdata.units_per_em * tfmdata.size * 0.5
+ insert_point.shrink = insert_point.shrink + value / tfmdata.units_per_em * tfmdata.size * 0.33333
end
end
end
@@ -102,6 +158,7 @@ local function make_kern ( head, font, first_glyph, second_glyph, insert_point )
end
end
end
+ return head, disc_node
end
local function check_glyph ( n, d, has_prev_next_glyph, prev_next_glyph )
@@ -120,25 +177,33 @@ local function make_kerns ( head, 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 )
+ head = 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 )
+ head = 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 )
+ 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 then
+ local tfmdata = GET_FONT ( prev_glyph.font )
+ if tfmdata and tfmdata.name then
+ local font_id = GSUB ( SUB ( tfmdata.name, 1, FIND ( tfmdata.name, ":" ) - 1 ), "\"", "" )
+ local second_tfmdata = GET_FONT ( next_glyph.font )
+ if second_tfmdata and second_tfmdata.name then
+ local second_font_id = GSUB ( SUB ( second_tfmdata.name, 1, FIND ( second_tfmdata.name, ":" ) - 1 ), "\"", "" )
+ if font_id == second_font_id then
+ head = make_kern ( head, prev_glyph.font, prev_glyph.char, next_glyph.char, n )
+ end
+ end
+ end
end
+ return head
end
-local function make_glues_and_kerns ( head )
- for n in T_ID ( GLUE, head ) do
- make_kerns ( head, n )
- end
+local function make_short_spaces ( head )
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
+ if find_glyph ( n, NEXT, false, true ) then
local next_glyph = n
- next_glyph = find_glyph ( n, NEXT )
+ next_glyph = find_glyph ( n, NEXT, false, true )
if next_glyph.char and next_glyph.char == 59 then
REM ( head, next_glyph )
local SIZE = 0
@@ -152,9 +217,11 @@ local function make_glues_and_kerns ( head )
local glue_node = PREV ( n )
glue_node.subtype = SPACESKIP
glue_node.width = round ( SIZE * .16667, 0 )
+ glue_node.stretch = glue_node.width * 0.5
+ glue_node.shrink = glue_node.width * 0.33333
local has_next_glyph = false
- if find_glyph ( n, NEXT ) then
- next_glyph = find_glyph ( n, NEXT )
+ if find_glyph ( n, NEXT, false, true ) then
+ next_glyph = find_glyph ( n, NEXT, false, true )
has_next_glyph = true
end
if has_next_glyph and next_glyph.char and next_glyph.char == 59 then
@@ -164,11 +231,21 @@ local function make_glues_and_kerns ( head )
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
+local function make_glues_and_kerns ( head )
+ for n in T ( head ) do
+ if n.id == GLUE and n.subtype == SPACESKIP then
+ head = make_kerns ( head, n )
+ end
+ end
+ return head
+end
+
+ATC ( "ligaturing", make_short_spaces, "make short spaces", 1 )
+ATC ( "pre_linebreak_filter", make_glues_and_kerns, "kern between words and against space preline", 1 )
+ATC ( "hpack_filter", make_glues_and_kerns, "kern between words and against space hpack" ) \ No newline at end of file