summaryrefslogtreecommitdiff
path: root/macros/luatex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-07-11 03:00:46 +0000
committerNorbert Preining <norbert@preining.info>2023-07-11 03:00:46 +0000
commit24bb3e3ee10fe79c39e9202be49c62c4d888f4ae (patch)
tree176d5ee37e8ab19ef7d3d91a357f3875c44ebccd /macros/luatex
parentab107e0f744efc9a2173da9b69e53fd83183988a (diff)
CTAN sync 202307110300
Diffstat (limited to 'macros/luatex')
-rw-r--r--macros/luatex/latex/ligtype/README.md2
-rw-r--r--macros/luatex/latex/ligtype/ligtype.lua441
-rw-r--r--macros/luatex/latex/ligtype/ligtype.pdfbin101610 -> 91044 bytes
-rw-r--r--macros/luatex/latex/ligtype/ligtype.sty23
-rw-r--r--macros/luatex/latex/ligtype/ligtype.tex17
-rw-r--r--macros/luatex/latex/showhyphenation/README.md2
-rw-r--r--macros/luatex/latex/showhyphenation/showhyphenation.lua148
-rw-r--r--macros/luatex/latex/showhyphenation/showhyphenation.pdfbin63494 -> 57607 bytes
-rw-r--r--macros/luatex/latex/showhyphenation/showhyphenation.sty4
-rw-r--r--macros/luatex/latex/showhyphenation/showhyphenation.tex22
-rw-r--r--macros/luatex/latex/showkerning/README.md2
-rw-r--r--macros/luatex/latex/showkerning/showkerning.lua163
-rw-r--r--macros/luatex/latex/showkerning/showkerning.pdfbin47132 -> 43172 bytes
-rw-r--r--macros/luatex/latex/showkerning/showkerning.sty4
-rw-r--r--macros/luatex/latex/showkerning/showkerning.tex4
-rw-r--r--macros/luatex/latex/spacekern/README.md2
-rw-r--r--macros/luatex/latex/spacekern/spacekern.lua181
-rw-r--r--macros/luatex/latex/spacekern/spacekern.pdfbin64020 -> 60901 bytes
-rw-r--r--macros/luatex/latex/spacekern/spacekern.sty4
-rw-r--r--macros/luatex/latex/spacekern/spacekern.tex16
20 files changed, 748 insertions, 287 deletions
diff --git a/macros/luatex/latex/ligtype/README.md b/macros/luatex/latex/ligtype/README.md
index dd60e93809..4d62f42bc9 100644
--- a/macros/luatex/latex/ligtype/README.md
+++ b/macros/luatex/latex/ligtype/README.md
@@ -8,7 +8,7 @@ suppression rules. With the help of options and macros it
can be used for other languages as well.
The package requires LuaLaTeX.
-Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de
+Copyright (c) 2022-2023 Thomas Kelkel kelkel@emaileon.de
The files of this package may be distributed and/or
modified under the conditions of the LaTeX Project
diff --git a/macros/luatex/latex/ligtype/ligtype.lua b/macros/luatex/latex/ligtype/ligtype.lua
index 328125f3a4..0ce5e35b59 100644
--- a/macros/luatex/latex/ligtype/ligtype.lua
+++ b/macros/luatex/latex/ligtype/ligtype.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,7 +10,7 @@
-- and version 1.3c or later is part of all distributions of
-- LaTeX version 2009/09/24 or later.
--- Version: 0.1b
+-- Version: 0.3
-- The ligtype package makes use of the German language
-- ligature suppression rules of the selnolig package by
@@ -27,52 +27,84 @@ local DISC = ID ( "disc" )
local GLUE = ID ( "glue" )
local KERN = ID ( "kern" )
local WI = ID ( "whatsit" )
-local BOUND = ID ( "boundary" )
local HLIST = ID ( "hlist" )
local VLIST = ID ( "vlist" )
-local USERKERN = table.swapped ( node.subtypes ("kern") )["userkern"]
+local INS = ID ( "ins" )
+
+local SWAPPED = table.swapped
+local SUBTYPES = node.subtypes
+local WIS = node.whatsits
+local PDF_LITERAL = SWAPPED ( WIS () )["pdf_literal"]
+local USER_DEFINED = SWAPPED ( WIS () )["user_defined"]
+local LEADERS = SWAPPED ( SUBTYPES ("glue") )["leaders"]
+local USERKERN = SWAPPED ( SUBTYPES ("kern") )["userkern"]
+
local NEW = node.new
local REM = node.remove
local PREV = node.prev
local NEXT = node.next
local TAIL = node.tail
-local HAS_GLYPH = node.has_glyph
local INS_B = node.insert_before
local INS_A = node.insert_after
+local HAS_GLYPH = node.has_glyph
local T = node.traverse
local T_GLYPH = node.traverse_glyph
-local WIS = node.whatsits()
-local userdefined
-local pdfliteral
+
local pairs = pairs
+local ipairs = ipairs
local next = next
local type = type
+
local U = unicode.utf8
local CHAR = U.char
-local GSUB = U.gsub
local SUB = U.sub
+local GSUB = U.gsub
local LEN = U.len
local BYTE = U.byte
local FIND = U.find
+local MATCH = U.match
+local LOWER = U.lower
+
local T_INS = table.insert
local T_CC = table.concat
+local SORT = table.sort
+
local FLOOR = math.floor
+
local GET_FONT = font.getfont
+
+local SPRINT = tex.sprint
+
+local LOG = texio.write
+local LOG_LINE = texio.write_nl
+
+local OUTPUT = io.output
+
local ATC = luatexbase.add_to_callback
local RFC = luatexbase.remove_from_callback
+-----
+
local make_marks = false
local no_short_f = false
local all_short_f = false
local no_default = false
+local lig_list = false
+local con_notes = false
local lig_table = {}
+local nolig_list = {}
+local keeplig_list = {}
+local white_list = {}
+local black_list = {}
+local log_sep = "==============================================================================="
-for key, value in pairs ( WIS ) do
- if value == "user_defined" then
- userdefined = key
- elseif value == "pdf_literal" then
- pdfliteral = key
+local function log ( label, output )
+ if not output then
+ output = ""
end
+ LOG ( "\n" .. log_sep )
+ LOG ( label .. output .. "\n" )
+ LOG ( log_sep .. "\n" )
end
function ligtype_no_short_f ()
@@ -87,6 +119,14 @@ function ligtype_no_default ()
no_default = true
end
+function ligtype_lig_list ()
+ lig_list = true
+end
+
+function ligtype_con_notes ()
+ con_notes = true
+end
+
local function to_ascii ( text )
return GSUB ( text, "[äöüß]", "a" )
end
@@ -115,10 +155,27 @@ local function round ( num, dec )
end
local function calc_value ( value )
- value = round ( value / 65536, 3 )
+ value = round ( value / 65781, 3 )
return value
end
+local function file_exists ( name )
+ return os.rename ( name, name ) and true or false
+end
+
+local function import_list ( file_name, list )
+ if file_exists ( file_name ) then
+ for line in io.lines ( file_name ) do
+ list[LOWER ( line )] = true
+ end
+ end
+end
+
+local function get_lists ()
+ import_list ( "lig-whitelist.txt", white_list )
+ import_list ( "lig-blacklist.txt", black_list )
+end
+
local function get_char_bytes ( text, text_len, reverse )
local a = { nil, nil, nil, nil, nil }
for i = 1, text_len do
@@ -131,17 +188,66 @@ local function get_char_bytes ( text, text_len, reverse )
return a
end
-local function find_glyph ( n, d, replace )
- 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 replace = false break end
+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 check_node ( n, d, lig, hlist_bound, hlist_node )
+ local point = n
+ if hlist_bound then
+ point = hlist_node
+ end
+ if n.replace then
+ return find_first_last ( n.replace, GLYPH, d == PREV ), point
+ end
+ if MATCH ( CHAR ( n.char ), "[%a]" ) or con_notes and not lig and ( n.char == 124 or n.char == 166 ) then
+ return n, point
+ end
+ return false
+end
+
+local function find_glyph ( n, d, lig, hlist_check, hlist_node )
+ if n then
+ if hlist_check and ( n.id == GLYPH or n.replace and HAS_GLYPH ( n.replace ) ) then
+ local hlist_bound = not find_glyph ( n, d, lig )
+ return check_node ( n, d, lig, hlist_bound, hlist_node )
+ elseif not hlist_check then
+ if d ( n ) then
n = d ( n )
+ else
+ return false
end
- else
- replace = false
+ end
+ while not ( n.id == GLYPH and n.char or n.replace and HAS_GLYPH ( n.replace ) ) do
+ if not lig and n.id == HLIST and n.head then
+ local point = n.head
+ if d == PREV then
+ point = TAIL ( point )
+ end
+ return find_glyph ( point, d, lig, true, n )
+ end
+ if not hlist_check and ( n.id == GLUE and ( n.stretch > 0 or n.width > 0 ) or n.id == KERN and n.subtype == USERKERN ) or not d ( n ) or n.id == INS or n.id == GLUE and n.subtype == LEADERS then
+ return false
+ end
+ n = d ( n )
+ end
+ return check_node ( n, d, lig )
end
- return n, replace
+ return false
end
local function get_ligs ( head )
@@ -154,17 +260,24 @@ local function get_ligs ( head )
local char_table = {}
for key, _ in pairs ( lig_check ) do
char_table[BYTE ( SUB ( key, 1, 1 ) )] = true
+ if lig_list then
+ if not nolig_list[key] then
+ nolig_list[key] = {}
+ end
+ if not keeplig_list[key] then
+ keeplig_list[key] = {}
+ end
+ end
end
for n in T_GLYPH ( head ) do
if n.char and char_table[n.char] then
if NEXT ( n ) then
local next_chars = { false, false }
local second_glyph
- local success
local next_glyph = n
for i = 1, 2 do
- next_glyph, success = find_glyph ( next_glyph, NEXT, true )
- if success and next_glyph.char then
+ next_glyph = find_glyph ( next_glyph, NEXT, true )
+ if next_glyph and next_glyph.char then
next_chars[i] = next_glyph.char
if i == 1 then
second_glyph = next_glyph
@@ -185,30 +298,66 @@ local function get_ligs ( head )
return ligs
end
-local function check_text ( replace, n, d, string_len, string_chars, plus_boolean )
- if d ( n ) then
- local MOVE = d ( n )
- for i = 1, string_len do
- while MOVE.id ~= GLYPH do
- if not d ( MOVE ) or MOVE.id == GLUE or MOVE.id == BOUND or ( MOVE.id == KERN and MOVE.subtype == USERKERN ) then replace = false break end
- MOVE = d ( MOVE )
+local function check_text ( n, d, string_len, string_chars, plus_boolean )
+ local point = n
+ for i = 1, string_len do
+ local some_node
+ some_node, point = find_glyph ( point, d )
+ if some_node then
+ if con_notes and ( some_node.char == 124 or some_node.char == 166 ) then
+ some_node, point = find_glyph ( point, d )
end
- if ( MOVE.char ~= string_chars[i] and string_chars[i] ~= 43 ) or ( string_chars[i] == 43 and not plus_boolean[MOVE.char] ) then replace = false break end
- if d ( MOVE ) then
- MOVE = d ( MOVE )
- elseif i ~= string_len then replace = false break end
+ if not some_node or some_node.char ~= string_chars[i] and string_chars[i] ~= 43 or string_chars[i] == 43 and not plus_boolean[some_node.char] then
+ return false
+ end
+ else
+ return false
end
- else
- replace = false
end
- return replace
+ return true
+end
+
+local function chars_to_string ( string, chars, reverse )
+ local loop_start = 1
+ local loop_end = LEN ( chars )
+ local loop_it = 1
+ if reverse then
+ loop_start = LEN ( chars )
+ loop_end = 1
+ loop_it = - 1
+ end
+ for i = loop_start, loop_end, loop_it do
+ string = string .. SUB ( chars, i, i )
+ end
+ return string
+end
+
+local function get_word ( word, n, d )
+ local reverse = true
+ local string = ""
+ local glyph_node = n
+ if d == NEXT then
+ string = string .. "|"
+ reverse = false
+ end
+ if glyph_node and glyph_node.char then
+ string = string .. CHAR ( glyph_node.char )
+ end
+ local point = glyph_node
+ while true do
+ if not find_glyph ( point, d ) then break end
+ glyph_node, point = find_glyph ( point, d )
+ if not con_notes or glyph_node.char ~= 124 and glyph_node.char ~= 166 then
+ string = string .. CHAR ( glyph_node.char )
+ end
+ end
+ return chars_to_string ( word, string, reverse )
end
local function no_lig ( nolig, lig, lig_beg, lig_end, text, head, ligs, plus )
local chars = { lig = { nil, nil, nil }, before = { nil, nil, nil, nil, nil }, after = { nil, nil, nil, nil, nil }, plus = { nil, nil, nil, nil, nil, nil, nil, nil, nil } }
local before_lig
local after_lig
- local count = 0
local text_len = LEN ( text )
local before_lig_len = lig_beg - 1
local after_lig_len = text_len - lig_end
@@ -218,7 +367,7 @@ local function no_lig ( nolig, lig, lig_beg, lig_end, text, head, ligs, plus )
chars.before = get_char_bytes ( before_lig, before_lig_len, true )
end
if lig_end < text_len then
- after_lig = SUB ( text, (lig_end + 1), text_len )
+ after_lig = SUB ( text, lig_end + 1, text_len )
chars.after = get_char_bytes ( after_lig, after_lig_len, false )
end
local plus_boolean = { nil, nil, nil, nil, nil, nil, nil, nil, nil }
@@ -231,44 +380,47 @@ local function no_lig ( nolig, lig, lig_beg, lig_end, text, head, ligs, plus )
end
end
for _, value in pairs ( ligs ) do
- count = count + 1
local n
if value.char ~= chars.lig[2] then
- local BEFORE = value
- BEFORE = find_glyph ( BEFORE, PREV, true )
- n = BEFORE
+ n = find_glyph ( value, PREV, true )
else
n = value
end
- if n.char == chars.lig[2] then
- local replace = true
- local prev_glyph = n
- prev_glyph, replace = find_glyph ( prev_glyph, PREV, replace )
- if NEXT ( prev_glyph ) and NEXT ( prev_glyph ).user_id and NEXT ( prev_glyph ).user_id == 289473 and nolig then
- replace = false
- end
- if prev_glyph.char ~= chars.lig[1] then
- replace = false
+ local prev_glyph = find_glyph ( n, PREV, true )
+ if not ( nolig and NEXT ( prev_glyph ) and NEXT ( prev_glyph ).user_id == 289473 ) then
+ local word
+ local word_lc
+ if lig_list then
+ word = get_word ( "", prev_glyph, PREV )
+ word = get_word ( word, NEXT ( prev_glyph ), NEXT )
+ word_lc = LOWER ( word )
end
- if replace then
- if lig_beg > 1 then
- replace = check_text ( replace, prev_glyph, PREV, before_lig_len, chars.before, plus_boolean )
- end
- if lig_end < text_len then
- replace = check_text ( replace, n, NEXT, after_lig_len, chars.after, plus_boolean )
- end
- if replace then
- if nolig then
- INS_A ( head, prev_glyph, NEW ( WI, userdefined ) )
- NEXT ( prev_glyph ).type = 100
- NEXT ( prev_glyph ).user_id = 289473
- else
- if NEXT ( prev_glyph ) and NEXT ( prev_glyph ).user_id == 289473 then
- REM ( head, NEXT ( prev_glyph ) )
+ if ( lig_beg == 1 or check_text ( prev_glyph, PREV, before_lig_len, chars.before, plus_boolean ) ) and ( lig_end == text_len or check_text ( n, NEXT, after_lig_len, chars.after, plus_boolean ) ) then
+ if nolig then
+ INS_A ( head, prev_glyph, NEW ( WI, USER_DEFINED ) )
+ NEXT ( prev_glyph ).type = 100
+ NEXT ( prev_glyph ).user_id = 289473
+ if lig_list then
+ if not white_list[word_lc] and not white_list[GSUB ( word_lc, "|", "·" )] then
+ nolig_list[lig][word_lc] = word
+ end
+ keeplig_list[lig][word_lc] = false
+ end
+ else
+ if NEXT ( prev_glyph ) and NEXT ( prev_glyph ).user_id == 289473 then
+ REM ( head, NEXT ( prev_glyph ) )
+ end
+ if lig_list then
+ nolig_list[lig][word_lc] = false
+ if not black_list[word_lc] and not black_list[GSUB ( word_lc, "|", "·" )] then
+ keeplig_list[lig][word_lc] = word
end
end
end
end
+ if lig_list and keeplig_list[lig][word_lc] == nil and nolig_list[lig][word_lc] == nil and not black_list[word_lc] and not black_list[GSUB ( word_lc, "|", "·" )] then
+ keeplig_list[lig][word_lc] = word
+ end
end
end
end
@@ -314,9 +466,6 @@ local function make_kern ( head )
if glyph_count > 4 then
for n in T ( head ) do
if n.id == WI and n.user_id == 289473 then
- local font_kern = true
- local hyphen_font_kern = true
- local post_lig_font_kern = true
local prev_glyph, lig_post = find_prev_next_glyph ( n, PREV )
local next_glyph = find_prev_next_glyph ( n, NEXT )
local kern_value = 0
@@ -325,7 +474,10 @@ local function make_kern ( head )
local post_lig_kern = 0
if prev_glyph.font then
local tfmdata = GET_FONT ( prev_glyph.font )
- if tfmdata.resources then
+ local second_tfmdata = GET_FONT ( next_glyph.font )
+ local font_id = GSUB ( SUB ( tfmdata.name, 1, FIND ( tfmdata.name, ":" ) - 1 ), "\"", "" )
+ local second_font_id = GSUB ( SUB ( second_tfmdata.name, 1, FIND ( second_tfmdata.name, ":" ) - 1 ), "\"", "" )
+ if tfmdata.resources and font_id == second_font_id then
local resources = tfmdata.resources
if not no_short_f and resources.unicodes then
local uni = resources.unicodes
@@ -335,40 +487,34 @@ local function make_kern ( head )
for key, value in pairs ( uni ) do
if key == "f_f" or key == "uniFB00" then
ff = value
- elseif key == "f_f.short" or key == "f_f.alt" then
+ elseif key == "f_f.short" or key == "f_f.alt" or key == "f_f_short" or key == "f_f.alt01" or key == "f_f.liga-alt" then
ff_short = value
- elseif key == "f.short" or key == "f.alt" then
+ elseif key == "f.short" or key == "f.alt" or key == "f_short" or key == "f.alt01" then
f_short = value
end
end
- if ( prev_glyph.char == 102 ) and f_short then
+ if prev_glyph.char == 102 and f_short then
prev_glyph.char = f_short
- elseif ( prev_glyph.char == ff ) and ff_short then
+ elseif prev_glyph.char == ff and ff_short then
prev_glyph.char = ff_short
end
end
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 and ( k.coverage[prev_glyph.char] or ( lig_post and k.coverage[lig_post.char] ) ) then
+ if k.coverage and ( k.coverage[prev_glyph.char] or lig_post and k.coverage[lig_post.char] ) then
if k.coverage[prev_glyph.char] then
local glyph_table = k.coverage[prev_glyph.char]
if type ( glyph_table ) == "table" then
for key, value in pairs ( glyph_table ) do
- if ( key == next_glyph.char or key == 45 ) and type ( value ) == "number" and ( k.format == "move" or tfmdata.specification.features.raw[t.name] ) then
- if font_kern and key == next_glyph.char then
- kern_value = kern_value + ( value / tfmdata.units_per_em * tfmdata.size )
- if tfmdata.specification.features.raw[t.name] then
- font_kern = false
- end
- elseif hyphen_font_kern and key == 45 then
- hyphen_kern = hyphen_kern + ( value / tfmdata.units_per_em * tfmdata.size )
- if tfmdata.specification.features.raw[t.name] then
- hyphen_font_kern = false
- end
+ if ( key == next_glyph.char or key == 45 ) and type ( value ) == "number" then
+ if key == next_glyph.char then
+ kern_value = kern_value + value / tfmdata.units_per_em * tfmdata.size
+ elseif key == 45 then
+ hyphen_kern = hyphen_kern + value / tfmdata.units_per_em * tfmdata.size
end
end
end
@@ -378,12 +524,9 @@ local function make_kern ( head )
local glyph_table = k.coverage[lig_post.char]
if type ( glyph_table ) == "table" then
for key, value in pairs ( glyph_table ) do
- if ( key == next_glyph.char ) and type ( value ) == "number" and ( k.format == "move" or tfmdata.specification.features.raw[t.name] ) then
- if post_lig_font_kern and key == next_glyph.char then
- post_lig_kern = post_lig_kern + ( value / tfmdata.units_per_em * tfmdata.size )
- if tfmdata.specification.features.raw[t.name] then
- post_lig_font_kern = false
- end
+ if key == next_glyph.char and type ( value ) == "number" then
+ if key == next_glyph.char then
+ post_lig_kern = post_lig_kern + value / tfmdata.units_per_em * tfmdata.size
end
end
end
@@ -446,9 +589,9 @@ local function place_marks ( head )
if font.current() then
size_factor = calc_value ( GET_FONT ( font.current() ).size / 10 )
end
- head = INS_B ( head, n, NEW ( WI, pdfliteral ) )
+ head = INS_B ( head, n, NEW ( WI, PDF_LITERAL ) )
PREV ( n ).mode = 0
- PREV ( n ).data = "q .2 .8 1 rg " .. kern_add .. " 0 m " .. ( kern_add + 2 * size_factor ) .. " " .. -3 * size_factor .. " l " .. ( kern_add - 2 * size_factor ) .. " " .. -3 * size_factor .. " l " .. kern_add .. " 0 l f Q"
+ PREV ( n ).data = "q .2 .8 1 rg " .. kern_add .. " 0 m " .. kern_add + 2 * size_factor .. " " .. -3 * size_factor .. " l " .. kern_add - 2 * size_factor .. " " .. -3 * size_factor .. " l " .. kern_add .. " 0 l f Q"
n.user_id = 848485
end
end
@@ -492,10 +635,13 @@ local function lig_parse ( head )
for i = 1, table_counter do
text_string[#text_string + 1] = text_table[i]
end
- text_string = T_CC (text_string)
+ text_string = T_CC ( text_string )
+ if con_notes then
+ text_string = GSUB ( text_string, "[|¦]", "" )
+ end
local function lt ( nolig, lig, lig_beg, lig_end, text, ligs, plus )
- if FIND ( text_string, text ) then
+ if FIND ( text_string, text ) or lig_list then
no_lig ( nolig, lig, lig_beg, lig_end, text, head, ligs, plus )
end
end
@@ -527,7 +673,6 @@ local function lig_parse ( head )
lt ( false, "ff", 5, 6, "scheffel", ligs["ff"] )
lt ( false, "ff", 4, 5, "cheffizi", ligs["ff"] )
lt ( false, "ff", 4, 5, "cheffé", ligs["ff"] )
- lt ( true, "ff", 4, 5, "cheffl+", ligs["ff"], "aiou" )
lt ( true, "ff", 5, 6, "Dampff", ligs["ff"] )
lt ( true, "ff", 5, 6, "dampff", ligs["ff"] )
lt ( true, "ff", 4, 5, "Dorff+", ligs["ff"], "aäeiloöruü" )
@@ -1271,6 +1416,7 @@ local function lig_parse ( head )
lt ( true, "fl", 3, 4, "üffle", ligs["ffl"] )
lt ( true, "ff", 3, 4, "Auffl", ligs["ffl"] )
lt ( true, "ff", 3, 4, "auffl", ligs["ffl"] )
+ lt ( true, "ff", 4, 5, "cheffl+", ligs["ff"], "aiou" )
lt ( true, "ff", 3, 4, "eiffleck", ligs["ffl"] )
lt ( true, "ff", 1, 2, "fflatter", ligs["ffl"] )
lt ( true, "ff", 1, 2, "ffläch", ligs["ffl"] )
@@ -1608,6 +1754,14 @@ local function no_ligs ( head )
end
end
+function ligtype_no_ligs()
+ ATC ( "ligaturing", no_ligs, "no ligs" )
+end
+
+function ligtype_ligs()
+ RFC ( "ligaturing", "no ligs" )
+end
+
function ligtype_write_ligs ( s )
ATC ( "ligaturing", no_ligs, "no ligs" )
local lig_check = {}
@@ -1621,7 +1775,81 @@ function ligtype_write_ligs ( s )
end
end
local par_end = [[\par\addvspace{\baselineskip}]]
- tex.sprint ( [[\newpage{}\pagestyle{empty}\parindent=0em{}]] .. ligs_string .. par_end .. [[\textbf{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{\textbf{]] .. ligs_string .. [[}}]] .. par_end .. [[{\sffamily{}]] .. ligs_string .. par_end .. [[\textbf{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{\textbf{]] .. ligs_string .. [[}}]] .. par_end .. [[}\newpage{}]] )
+ SPRINT ( [[\newpage{}\pagestyle{empty}\parindent=0em{}]] .. ligs_string .. par_end .. [[\textbf{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{\textbf{]] .. ligs_string .. [[}}]] .. par_end .. [[{\sffamily{}]] .. ligs_string .. par_end .. [[\textbf{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{]] .. ligs_string .. [[}]] .. par_end .. [[\textit{\textbf{]] .. ligs_string .. [[}}]] .. par_end .. [[}\newpage{}]] )
+end
+
+local function process_table ( str_table, order )
+ if #str_table > 0 then
+ if order then
+ SORT ( str_table, function ( a, b ) if a:upper() == b:upper() then return a < b else return a:upper() < b:upper() end end )
+ end
+ else
+ str_table[1] = "None!\n"
+ end
+ return T_CC ( str_table )
+end
+
+local function make_string ( list, order, point )
+ local array = {}
+ for key, value in pairs ( list ) do
+ if value then
+ local string = ""
+ string = string .. "\n"
+ if point then
+ string = string .. GSUB ( value, "|", "·" )
+ else
+ string = string .. value
+ end
+ array[#array + 1] = string
+ end
+ end
+ array = process_table ( array, order )
+ return array
+end
+
+local function make_file ( file_name, content )
+ OUTPUT ( file_name ):write ( content )
+end
+
+local function check_table ( table )
+ for key, value in pairs ( table ) do
+ if value then
+ return true
+ end
+ end
+ return false
+end
+
+local function get_keys_ordered ( table )
+ local table_keys = {}
+ for key in pairs ( table ) do
+ T_INS ( table_keys, key )
+ end
+ SORT ( table_keys )
+ return table_keys
+end
+
+local function make_list ()
+ local nolig_keys = get_keys_ordered ( nolig_list )
+ local keeplig_keys = get_keys_ordered ( keeplig_list )
+ local output_array = {}
+ output_array[#output_array + 1] = "NO LIG\n======"
+ for _, table_key in ipairs ( nolig_keys ) do
+ if check_table ( nolig_list[table_key] ) then
+ output_array[#output_array + 1] = "\n\n" .. table_key .. ":"
+ output_array[#output_array + 1] = make_string ( nolig_list[table_key], true )
+ end
+ end
+ output_array[#output_array + 1] = "\n\nKEEP LIG\n========"
+ for _, table_key in ipairs ( keeplig_keys ) do
+ if check_table ( keeplig_list[table_key] ) then
+ output_array[#output_array + 1] = "\n\n" .. table_key .. ":"
+ output_array[#output_array + 1] = make_string ( keeplig_list[table_key], true, true )
+ end
+ end
+ output_array = T_CC ( output_array )
+ make_file ( tex.jobname .. ".lig", output_array )
+ log ( "\n" .. output_array .. "\n" )
end
function ligtype_make_marks ()
@@ -1634,10 +1862,17 @@ function ligtype_on ()
ATC ( "ligaturing", lig_parse, "make and break ligatures" )
ATC ( "pre_linebreak_filter", make_kern, "make kerns preline" )
ATC ( "hpack_filter", make_kern, "make kerns hpack", 2 )
+ if lig_list then
+ get_lists()
+ ATC ( "wrapup_run", make_list, "make list" )
+ end
end
function ligtype_off ()
RFC ( "ligaturing", "make and break ligatures" )
RFC ( "pre_linebreak_filter", "make kerns preline" )
RFC ( "hpack_filter", "make kerns hpack" )
+ if lig_list then
+ RFC ( "wrapup_run", "make list" )
+ end
end \ No newline at end of file
diff --git a/macros/luatex/latex/ligtype/ligtype.pdf b/macros/luatex/latex/ligtype/ligtype.pdf
index 98eb766816..8166d7f7e9 100644
--- a/macros/luatex/latex/ligtype/ligtype.pdf
+++ b/macros/luatex/latex/ligtype/ligtype.pdf
Binary files differ
diff --git a/macros/luatex/latex/ligtype/ligtype.sty b/macros/luatex/latex/ligtype/ligtype.sty
index 3cf84a67f0..edcfcd0c55 100644
--- a/macros/luatex/latex/ligtype/ligtype.sty
+++ b/macros/luatex/latex/ligtype/ligtype.sty
@@ -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
@@ -19,15 +19,27 @@
% and may be distributed and/or modified under the
% conditions of the LaTeX Project Public License.
-\ProvidesPackage{ligtype}[2022/06/13 v0.1b Comprehensive ligature suppression functionalities]
+\ProvidesPackage{ligtype}[2023/07/08 v0.3 Comprehensive ligature suppression functionalities]
\RequirePackage{ifluatex,luatexbase}
\ifluatex
\directlua{require ( "ligtype.lua" )}
+ \DeclareOption{noshortf}{\directlua{ligtype_no_short_f()}}
+ \DeclareOption{allshortf}{\directlua{ligtype_all_short_f()}}
+ \DeclareOption{makemarks}{\directlua{ligtype_make_marks()}}
+ \DeclareOption{kerntest}{\AtEndDocument{\directlua{ligtype_write_ligs()}}}
+ \DeclareOption{nodefault}{\directlua{ligtype_no_default()}}
+ \DeclareOption{liglist}{\directlua{ligtype_lig_list()}}
+ \DeclareOption{connotes}{\directlua{ligtype_con_notes()}}
+ \ProcessOptions
+
\def\ligtypeon{\directlua{ligtype_on()}}
\def\ligtypeoff{\directlua{ligtype_off()}}
+ \def\noligs{\directlua{ligtype_no_ligs()}}
+ \def\ligs{\directlua{ligtype_ligs()}}
+
\ligtypeon
\newcommand\nolig[2]{%
@@ -40,13 +52,6 @@
ligtype_parse_macro ( "\luatexluaescapestring{#1}", "\luatexluaescapestring{#2}", false )%
}%
}
-
- \DeclareOption{noshortf}{\directlua{ligtype_no_short_f()}}
- \DeclareOption{allshortf}{\directlua{ligtype_all_short_f()}}
- \DeclareOption{makemarks}{\directlua{ligtype_make_marks()}}
- \DeclareOption{kerntest}{\AtEndDocument{\directlua{ligtype_write_ligs()}}}
- \DeclareOption{nodefault}{\directlua{ligtype_no_default()}}
- \ProcessOptions
\else
\errhelp{Compile with LuaLaTeX to be able to use the "ligtype" package.}
\errmessage{Package "ligtype" error: This package requires LuaLaTeX!}
diff --git a/macros/luatex/latex/ligtype/ligtype.tex b/macros/luatex/latex/ligtype/ligtype.tex
index e122531415..ae0a52f855 100644
--- a/macros/luatex/latex/ligtype/ligtype.tex
+++ b/macros/luatex/latex/ligtype/ligtype.tex
@@ -332,6 +332,7 @@ local function make_margin_notes ( head, id, array, counter )
end
first_kern = kern_node.kern
first_width = kern_value
+ head = REM ( head, glyph_node )
end
end
end
@@ -357,13 +358,17 @@ end
\title{The ligtype package\vspace{.25\baselineskip}\\\superlarge{}Comprehensive ligature suppression functionalities}%
\author{\sublarge{}Thomas Kelkel\vspace{-.25\baselineskip}\\\sublarge{}kelkel@emaileon.de\vspace{-.25\baselineskip}}%
-\date{\addfontfeature{LetterSpace=2}\sublarge{}2022/06/13\quad{}v0.1b}%
+\date{\addfontfeature{LetterSpace=2}\sublarge{}2023/07/08\quad{}v0.3}%
\maketitle
\ligtypeoff
+\vspace{-2\baselineskip}
+
\tableofcontents
+\vspace{-\baselineskip}
+
\addvspace{3em}
\hfill\textit{\qq{I don't think you would ever do this in English}}\par
\addvspace{-.25\baselineskip}
@@ -386,7 +391,7 @@ If available, it automatically replaces the f-glyphs of suppressed ligatures wit
\paragraph{Speed}
-It is about ten times faster on a typical document, thanks to its completely different architecture.\fn{This factor increases with the length of the paragraphs. On a 150-page paragraph, \monofn{ligtype} runs about a hundred times faster.}
+It is between ten and twenty times faster on a typical document, thanks to its completely different architecture.\fn{This factor increases with the length of the paragraphs. On a 150-page paragraph, \monofn{ligtype} runs more than a hundred times faster.}
\addvspace{\paragraphbs}
@@ -424,6 +429,12 @@ Options can be loaded by adding them comma separated within square brackets:
\textnote{kerntest}This option prints all glyph combinations that comprise the ligatures \mono{ligtype} is looking for in Regular, Italic, Bold and Italic Bold for both the Roman and the Sans font on the last page of the document. This gives you an overview of all kerning pairs that are relevant when breaking ligatures, and you can inspect the kerning values accordingly.
+\addcontentsline{toc}{subsection}{liglist}
+
+\textnote{liglist}Prints, both in the output and in an external file \mono{[filename].lig,} a sorted list of all kept and broken ligatures.
+
+White- and blacklists can be used in conjunction with this feature. For this \mono{lig-whitelist.txt} and \mono{lig-blacklist.txt} must be provided in the document path. In the whitelist the ligatures to be broken are listed in the blacklist the ligatures to be kept. According to the formatting in the output file, the breaking points are marked with a vertical bar in the whitelist and with a centered period in the blacklist.
+
\addcontentsline{toc}{subsection}{makemarks}
\textnote{makemarks}Marks each point where a ligature was suppressed with a blue triangle below the baseline.
@@ -491,6 +502,6 @@ In general, the truly excellent \mono{selnolig} documentation is highly recommen
\section{License}
-This package is copyright © 2022 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
+This package is copyright © 2022\kern.1em–\kern.1em2023 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
\end{document} \ No newline at end of file
diff --git a/macros/luatex/latex/showhyphenation/README.md b/macros/luatex/latex/showhyphenation/README.md
index 8feb8fb343..69eb1c76a4 100644
--- a/macros/luatex/latex/showhyphenation/README.md
+++ b/macros/luatex/latex/showhyphenation/README.md
@@ -6,7 +6,7 @@ their size adjusts to the font size. By option the markers
can be placed behind or in front of the glyphs.
The package requires LuaLaTeX.
-Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de
+Copyright (c) 2022-2023 Thomas Kelkel kelkel@emaileon.de
The files of this package may be distributed and/or
modified under the conditions of the LaTeX Project
diff --git a/macros/luatex/latex/showhyphenation/showhyphenation.lua b/macros/luatex/latex/showhyphenation/showhyphenation.lua
index 72f964932c..1e4df896c9 100644
--- a/macros/luatex/latex/showhyphenation/showhyphenation.lua
+++ b/macros/luatex/latex/showhyphenation/showhyphenation.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,40 +10,45 @@
-- and version 1.3c or later is part of all distributions of
-- LaTeX version 2009/09/24 or later.
--- Version: 0.1a
-
-local FLOOR = math.floor
-
-local function round ( num, dec )
- return FLOOR ( num * 10^dec + 0.5 ) / 10^dec
-end
+-- Version: 0.3
local ID = node.id
local GLYPH = ID ( "glyph" )
local DISC = ID ( "disc" )
-local KERN = ID ( "kern" )
local GLUE = ID ( "glue" )
+local KERN = ID ( "kern" )
local WI = ID ( "whatsit" )
local HLIST = ID ( "hlist" )
local VLIST = ID ( "vlist" )
-local RIGHTSKIP = table.swapped ( node.subtypes ("glue") )["rightskip"]
+local INS = ID ( "ins" )
+
+local SWAPPED = table.swapped
+local SUBTYPES = node.subtypes
+local WIS = node.whatsits
+local PDF_LITERAL = SWAPPED ( WIS () )["pdf_literal"]
+local LEADERS = SWAPPED ( SUBTYPES ("glue") )["leaders"]
+local RIGHTSKIP = SWAPPED ( SUBTYPES ("glue") )["rightskip"]
+
local NEW = node.new
local COPY = node.copy
local REM = node.remove
local PREV = node.prev
local NEXT = node.next
-local HAS_GLYPH = node.has_glyph
local INS_B = node.insert_before
local INS_A = node.insert_after
+local HAS_GLYPH = node.has_glyph
local T = node.traverse
local T_ID = node.traverse_id
local T_GLYPH = node.traverse_glyph
-local WIS = node.whatsits()
-local pdfliteral
-local pairs = pairs
+
+local FLOOR = math.floor
+
local GET_FONT = font.getfont
+
local ATC = luatexbase.add_to_callback
+-----
+
local make = false
local on_top = false
local DIR = PREV
@@ -67,12 +72,6 @@ end
local in_use = make_not_on_top
-for key, value in pairs ( WIS ) do
- if value == "pdf_literal" then
- pdfliteral = key
- end
-end
-
function showhyphenation_make ()
make = true
end
@@ -86,40 +85,61 @@ function showhyphenation_lime ()
color = ".75 1 .25"
end
+local function round ( num, dec )
+ return FLOOR ( num * 10^dec + 0.5 ) / 10^dec
+end
+
local function calc_value ( value )
- value = round ( value / 65536, 3 )
+ value = round ( value / 65781, 3 )
return value
end
-local function get_x_value ( n, x_value, minus )
+local function get_x_value ( n, x_value, minus, half )
local exp_fac = 1
local f = 1
if minus then
f = - 1
end
+ local ff = 1
+ if half then
+ ff = 0.5
+ end
if n.expansion_factor then
exp_fac = n.expansion_factor / 1000000 + 1
end
if n.id == GLYPH then
x_value = x_value + calc_value ( n.width ) * exp_fac * f
elseif n.id == KERN then
- x_value = x_value + calc_value ( n.kern ) * exp_fac * f
+ x_value = x_value + calc_value ( n.kern ) * exp_fac * f * ff
end
return x_value
end
local line_end_count = 0
-local function find_glyph ( n, d, kern_value )
+local function find_glyph ( n, d, kern_value, linebreak, lig )
local line_end = nil
local ligtype_mark = nil
+ local kern_at_disc = 0
if d ( n ) then
n = d ( n )
- while not ( ( n.id == GLYPH and n.char ~= 45 ) or ( n.id == DISC and n.replace and HAS_GLYPH ( n.replace ) ) ) do
+ while not ( n.id == GLYPH and n.char ~= 45 or n.replace and HAS_GLYPH ( n.replace ) ) do
+ if n.id == GLUE or n.subtype == LEADERS or n.id == INS then
+ return false
+ end
if n.width and not ( n.char and n.char == 45 ) then
kern_value = get_x_value ( n, kern_value ) -- rules, etc.
elseif n.kern then
- kern_value = get_x_value ( n, kern_value ) * 0.5 -- hyphen kern
+ local factor = 1
+ if linebreak or not lig then
+ factor = 0.5 -- hyphen kern
+ kern_at_disc = get_x_value ( n, kern_at_disc ) * factor
+ end
+ kern_value = get_x_value ( n, kern_value ) * factor
+ elseif n.replace then
+ for kern_node in T_ID ( KERN, n.replace ) do
+ kern_value = get_x_value ( kern_node, kern_value )
+ end
end
if n.char == 45 then
line_end = true
@@ -149,7 +169,7 @@ local function find_glyph ( n, d, kern_value )
end
end
end
- return n, kern_value, ligtype_mark
+ return n, kern_value, ligtype_mark, kern_at_disc
end
local function check_linebreak ( n, d )
@@ -158,7 +178,7 @@ local function check_linebreak ( n, d )
n = d ( n )
else break end
end
- if ( n.char == 45 and d == PREV ) or ( n.id == GLUE and n.subtype == RIGHTSKIP and d == NEXT ) then
+ if n.char == 45 and d == PREV or n.id == GLUE and n.subtype == RIGHTSKIP and d == NEXT then
make_not_on_top()
return true
end
@@ -174,22 +194,42 @@ local function hyphenation_points ( head )
local lig_add = 0
local prev_next_kern = 0
local prev_next_kern_lig = 0
+ local pre_kerns = 0
+ local second_pre_glyph = 0
+ local lig = false
if n.replace then
if not HAS_GLYPH ( n.replace ) then
local REPLACE = n.replace
for some_node in T ( REPLACE ) do
- if some_node.kern and not ( check_linebreak ( n, DIR ) ) then
+ if some_node.kern and not check_linebreak ( n, DIR ) then
prev_next_kern_lig = get_x_value ( some_node, prev_next_kern_lig ) * 0.5
end
end
else
+ local gn_counter = 0
+ for glyph_node in T_GLYPH ( n.replace ) do
+ if glyph_node.components then
+ lig = true
+ end
+ end
if n.post then
+ for _ in T_ID ( KERN, n.pre ) do
+ pre_kerns = pre_kerns + 1
+ end
for glyph_node in T_GLYPH ( n.pre ) do
if glyph_node.width then
lig_add = get_x_value ( glyph_node, lig_add )
break -- hyphen!
end
end
+ for glyph_node in T_GLYPH ( n.replace ) do
+ if glyph_node.width then
+ gn_counter = gn_counter + 1
+ if gn_counter == 2 then
+ second_pre_glyph = get_x_value ( glyph_node, second_pre_glyph, true )
+ end
+ end
+ end
if not on_top then
if n.replace.kern then
prev_next_kern_lig = get_x_value ( n.replace, prev_next_kern_lig )
@@ -214,14 +254,56 @@ local function hyphenation_points ( head )
end
end
end
+ if gn_counter > 1 then
+ local counter = 0
+ if not on_top then
+ for kern_node in T_ID ( KERN, n.replace ) do
+ counter = counter + 1
+ if counter > 1 then
+ if pre_kerns > 1 then
+ if pre_kerns > 2 then
+ prev_next_kern_lig = get_x_value ( kern_node, prev_next_kern_lig ) + lig_add
+ else
+ prev_next_kern_lig = get_x_value ( kern_node, prev_next_kern_lig, false, true )
+ end
+ pre_kerns = pre_kerns - 1
+ end
+ end
+ end
+ else
+ for kern_node in T_ID ( KERN, n.replace ) do
+ counter = counter + 1
+ if counter > 1 then
+ if pre_kerns > 1 then
+ if pre_kerns > 2 then
+ prev_next_kern_lig = get_x_value ( kern_node, prev_next_kern_lig, true ) + second_pre_glyph
+ else
+ prev_next_kern_lig = get_x_value ( kern_node, prev_next_kern_lig, true, true )
+ end
+ pre_kerns = pre_kerns - 1
+ end
+ end
+ end
+ end
+ end
end
end
local prev_next_glyph = n
local ligtype_mark = nil
if find_glyph ( prev_next_glyph, DIR, 0 ) then
- prev_next_glyph, prev_next_kern, ligtype_mark = find_glyph ( prev_next_glyph, DIR, 0 )
+ prev_next_glyph, prev_next_kern, ligtype_mark = find_glyph ( prev_next_glyph, DIR, 0, check_linebreak ( n, PREV ) or check_linebreak ( n, NEXT ), lig )
+ end
+ local reverse = PREV
+ if DIR == PREV then
+ reverse = NEXT
+ end
+ if find_glyph ( n, reverse, 0 ) then
+ local _, __, ___, kern_at_disc = find_glyph ( n, reverse, 0, check_linebreak ( n, PREV ) or check_linebreak ( n, NEXT ), lig )
+ if kern_at_disc then
+ prev_next_kern = prev_next_kern + kern_at_disc
+ end
end
- head = AB ( head, prev_next_glyph, NEW ( WI, pdfliteral ) )
+ head = AB ( head, prev_next_glyph, NEW ( WI, PDF_LITERAL ) )
lig_add = lig_add + ( prev_next_kern + prev_next_kern_lig ) * f
DIR ( prev_next_glyph ).mode = 0
local size_factor = 1
@@ -229,8 +311,8 @@ local function hyphenation_points ( head )
size_factor = calc_value ( GET_FONT ( font.current() ).size / 10 )
end
local DATA
- if ( PREV ( n ) and PREV ( n ).user_id and PREV ( n ).user_id == 848485 ) or ligtype_mark then
- DATA = "q " .. ( lig_add - 2 * size_factor ) .. " " .. -3 * size_factor .. " m " .. ( lig_add + 2 * size_factor ) .. " " .. -3 * size_factor .. " l " .. ( lig_add + 2 * size_factor ) .. " " .. -4 * size_factor .. " l " .. ( lig_add - 2 * size_factor ) .. " " .. -4 * size_factor .. " l " .. color .. " rg f Q"
+ if PREV ( n ) and PREV ( n ).user_id and PREV ( n ).user_id == 848485 or ligtype_mark then
+ DATA = "q " .. lig_add - 2 * size_factor .. " " .. -3 * size_factor .. " m " .. lig_add + 2 * size_factor .. " " .. -3 * size_factor .. " l " .. lig_add + 2 * size_factor .. " " .. -4 * size_factor .. " l " .. lig_add - 2 * size_factor .. " " .. -4 * size_factor .. " l " .. color .. " rg f Q"
else
DATA = "q " .. lig_add .. " 0 m " .. lig_add + 2 * size_factor .. " " .. -3 * size_factor .. " l " .. lig_add - 2 * size_factor .. " " .. -3 * size_factor .. " l " .. color .. " rg f Q"
end
diff --git a/macros/luatex/latex/showhyphenation/showhyphenation.pdf b/macros/luatex/latex/showhyphenation/showhyphenation.pdf
index a0ce34f5e5..96d6fb8525 100644
--- a/macros/luatex/latex/showhyphenation/showhyphenation.pdf
+++ b/macros/luatex/latex/showhyphenation/showhyphenation.pdf
Binary files differ
diff --git a/macros/luatex/latex/showhyphenation/showhyphenation.sty b/macros/luatex/latex/showhyphenation/showhyphenation.sty
index ee088450a0..1f6bf2dbae 100644
--- a/macros/luatex/latex/showhyphenation/showhyphenation.sty
+++ b/macros/luatex/latex/showhyphenation/showhyphenation.sty
@@ -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,7 +10,7 @@
% and version 1.3c or later is part of all distributions of
% LaTeX version 2009/09/24 or later.
-\ProvidesPackage{showhyphenation}[2022/06/13 v0.1a Marking of hyphenation points]
+\ProvidesPackage{showhyphenation}[2023/07/08 v0.3 Marking of hyphenation points]
\RequirePackage{ifluatex,luatexbase}
\ifluatex
diff --git a/macros/luatex/latex/showhyphenation/showhyphenation.tex b/macros/luatex/latex/showhyphenation/showhyphenation.tex
index 84dba3622d..e78c820439 100644
--- a/macros/luatex/latex/showhyphenation/showhyphenation.tex
+++ b/macros/luatex/latex/showhyphenation/showhyphenation.tex
@@ -352,30 +352,16 @@ end
\title{The showhyphenation package\vspace{.25\baselineskip}\\\superlarge{}\directlua{luatexbase.remove_from_callback ( "post_linebreak_filter", "show hyphenation points in postline" ) luatexbase.remove_from_callback ( "hpack_filter", "show hyphenation points in hpack" )}Marking of hyphenation points}%
\author{\sublarge{}Thomas Kelkel\vspace{-.25\baselineskip}\\\sublarge{}kelkel@emaileon.de\vspace{-.25\baselineskip}}%
-\date{\addfontfeature{LetterSpace=2}\sublarge{}2022/06/13\quad{}v0.1a}%
+\date{\addfontfeature{LetterSpace=2}\sublarge{}2023/07/08\quad{}v0.3}%
\maketitle
\hyphenation{pack-age}
\section{Introduction}
-This package shows the hyphenation points in the document.% Optionally either by markers below the baseline, or by explicit hyphens in the text.
+This package shows the hyphenation points in the document.
-There is already the \mono{showhyphens} package by Patrick Gundlach, which provides similar functionality. However, the \mono{showhyphenation} package differs by a number of improvements and enhancements:
-
-\paragraph{Visibility}
-
-The size of the markers adjusts to the font size. Furthermore, the markers do not cover the glyphs.
-
-\paragraph{Ligatures}
-
-The markers are correctly placed even within ligatures and there are no issues with kern nodes next to ligatures.
-
-\paragraph{Explicit hyphens}
-
-The \mono{make} option allows the user to have the hyphenation points typeset as explicit hyphens in the text.
-
-%The hyphenation package offers the feature to typeset the hyphenation points as explicit hyphens in the text.
+The size of the markers adjusts to the font size and the markers are correctly placed even within ligatures. There is also an option that allows the user to have the hyphenation points typeset as explicit hyphens in the text.
\section{Basic usage}
@@ -407,6 +393,6 @@ Options can be loaded by adding them comma separated within square brackets:
\section{License}
-This package is copyright © 2022 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
+This package is copyright © 2022\kern.1em–\kern.1em2023 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
\end{document} \ No newline at end of file
diff --git a/macros/luatex/latex/showkerning/README.md b/macros/luatex/latex/showkerning/README.md
index 75e8f5569c..2fc0a6c56e 100644
--- a/macros/luatex/latex/showkerning/README.md
+++ b/macros/luatex/latex/showkerning/README.md
@@ -7,7 +7,7 @@ By option the bars can be placed behind or in front of the
glyphs.
The package requires LuaLaTeX.
-Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de
+Copyright (c) 2022-2023 Thomas Kelkel kelkel@emaileon.de
The files of this package may be distributed and/or
modified under the conditions of the LaTeX Project
diff --git a/macros/luatex/latex/showkerning/showkerning.lua b/macros/luatex/latex/showkerning/showkerning.lua
index 5c7faf3f6a..b298a6fb22 100644
--- a/macros/luatex/latex/showkerning/showkerning.lua
+++ b/macros/luatex/latex/showkerning/showkerning.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,53 +10,41 @@
-- and version 1.3c or later is part of all distributions of
-- LaTeX version 2009/09/24 or later.
--- Version: 0.1
-
-local FLOOR = math.floor
-local ABS = math.abs
-
-local function round ( num, dec )
- return FLOOR ( num * 10^dec + 0.5 ) / 10^dec
-end
+-- Version: 0.3
local ID = node.id
local GLYPH = ID ( "glyph" )
local DISC = ID ( "disc" )
-local KERN = ID ( "kern" )
local GLUE = ID ( "glue" )
-local BOUND = ID ( "boundary" )
+local KERN = ID ( "kern" )
local WI = ID ( "whatsit" )
local HLIST = ID ( "hlist" )
local VLIST = ID ( "vlist" )
-local USERKERN = table.swapped ( node.subtypes ("kern") )["userkern"]
+
+local PDF_LITERAL = table.swapped ( node.whatsits () )["pdf_literal"]
+
local NEW = node.new
-local COPY = node.copy
-local REM = node.remove
local PREV = node.prev
local NEXT = node.next
local TAIL = node.tail
-local HAS_GLYPH = node.has_glyph
local INS_B = node.insert_before
local INS_A = node.insert_after
+local HAS_GLYPH = node.has_glyph
local T = node.traverse
local T_ID = node.traverse_id
-local T_GLYPH = node.traverse_glyph
-local WIS = node.whatsits()
-local pdfliteral
-local pairs = pairs
+
+local FLOOR = math.floor
+local ABS = math.abs
+
local ATC = luatexbase.add_to_callback
+-----
+
local on_top = false
local DIR = PREV
local AB = INS_B
local f = 1
-for key, value in pairs ( WIS ) do
- if value == "pdf_literal" then
- pdfliteral = key
- end
-end
-
function showkerning_on_top ()
on_top = true
DIR = NEXT
@@ -64,16 +52,42 @@ function showkerning_on_top ()
f = - 1
end
+local function round ( num, dec )
+ return FLOOR ( num * 10^dec + 0.5 ) / 10^dec
+end
+
local function calc_value ( value )
- value = round ( value / 65536, 3 )
+ value = round ( value / 65781, 3 )
return value
end
+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 )
+ local kern_value = 0
if d ( n ) then
n = d ( n )
- while n.id ~= GLYPH and not ( n.id == DISC and n.replace and HAS_GLYPH ( n.replace ) ) 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
+ while not ( n.id == GLYPH or n.replace and HAS_GLYPH ( n.replace ) ) do
+ if not d ( n ) then return false end
+ if n.id == GLUE then
+ kern_value = kern_value + n.width
+ end
n = d ( n )
end
else
@@ -81,19 +95,21 @@ local function find_glyph ( n, d )
end
local return_value = n
if n.id == DISC then
- for glyph_node in T_GLYPH ( n.replace ) do
- return_value = glyph_node
+ return_value = find_first_last ( n.replace, GLYPH, d == PREV )
+ for kern_node in T_ID ( KERN, n.replace ) do
+ kern_value = kern_value + kern_node.kern
end
end
- return return_value, n
+ return return_value, n, kern_value
end
local function check_glyph ( n, d, has_prev_next_glyph, prev_next_glyph, insert_prev_next )
+ local kern_value
if find_glyph ( n, d ) then
- prev_next_glyph, insert_prev_next = find_glyph ( n, d )
+ prev_next_glyph, insert_prev_next, kern_value = find_glyph ( n, d )
has_prev_next_glyph = true
end
- return has_prev_next_glyph, prev_next_glyph, insert_prev_next
+ return has_prev_next_glyph, prev_next_glyph, insert_prev_next, kern_value
end
local function get_x_value ( n, x_value )
@@ -101,14 +117,45 @@ local function get_x_value ( n, x_value )
if n.expansion_factor then
exp_fac = n.expansion_factor / 1000000 + 1
end
- if n.id == GLYPH and n.width then
+ if n.width then
x_value = x_value + calc_value ( n.width ) * exp_fac
- elseif n.id == KERN and n.kern then
+ elseif n.kern then
x_value = x_value + calc_value ( n.kern ) * exp_fac
end
return x_value
end
+local function find_kern ( n, d )
+ local kern_value = 0
+ local disc = false
+ if d ( n ) then
+ n = d ( n )
+ while n and not ( n.id == GLYPH or disc ) do
+ if n.id == KERN then
+ kern_value = get_x_value ( n, kern_value )
+ elseif n.replace then
+ local start_point = n.replace
+ if d == PREV then
+ start_point = TAIL ( n.replace )
+ end
+ if start_point.id == KERN then
+ kern_value = get_x_value ( start_point, kern_value )
+ end
+ disc = true
+ end
+ if d ( n ) then
+ n = d ( n )
+ else
+ break
+ end
+ end
+ if not ( kern_value == 0 ) then
+ return kern_value
+ end
+ end
+ return false
+end
+
local function make_rule ( head, n, kern_node, current_head, disc_list )
local color = "0 0 0"
local has_prev_glyph = false
@@ -121,27 +168,44 @@ local function make_rule ( head, n, kern_node, current_head, disc_list )
local x_value = 0
local height = 0
local depth = 0
+ local prev_kern_value = 0
+ local next_kern_value = 0
local thickness = calc_value ( kern_node.kern )
- has_prev_glyph, prev_glyph, insert_prev = check_glyph ( n, PREV, has_prev_glyph, prev_glyph, insert_prev )
- has_next_glyph, next_glyph, insert_next = check_glyph ( n, NEXT, has_next_glyph, next_glyph, insert_next )
+ has_prev_glyph, prev_glyph, insert_prev, prev_kern_value = check_glyph ( n, PREV, has_prev_glyph, prev_glyph, insert_prev )
+ has_next_glyph, next_glyph, insert_next, next_kern_value = check_glyph ( n, NEXT, has_next_glyph, next_glyph, insert_next )
+ if disc_list and not ( TAIL ( current_head ) == kern_node ) and not ( current_head == kern_node ) then
+ has_prev_glyph, prev_glyph, insert_prev, prev_kern_value = check_glyph ( kern_node, PREV, has_prev_glyph, kern_node, kern_node )
+ has_next_glyph, next_glyph, insert_next, next_kern_value = check_glyph ( kern_node, NEXT, has_next_glyph, kern_node, kern_node )
+ end
if not on_top and has_prev_glyph then
insert_point = insert_prev
x_value = get_x_value ( prev_glyph, x_value )
+ x_value = x_value + calc_value ( prev_kern_value )
if disc_list and HAS_GLYPH ( current_head ) and TAIL ( current_head ) == kern_node then
for some_node in T ( current_head ) do
if some_node == TAIL ( current_head ) then break end
x_value = get_x_value ( some_node, x_value )
end
end
- elseif on_top and has_next_glyph then
+ elseif on_top then
insert_point = insert_next
- x_value = get_x_value ( next_glyph, x_value )
+ if has_next_glyph then
+ x_value = get_x_value ( next_glyph, x_value )
+ x_value = x_value + calc_value ( next_kern_value )
+ end
if disc_list and HAS_GLYPH ( current_head ) and current_head == kern_node then
+ local kern_counter = 0
for some_node in T ( current_head ) do
- if some_node ~= current_head then
+ if some_node.id == KERN then
+ kern_counter = kern_counter + 1
+ end
+ if not ( some_node == current_head ) then
x_value = get_x_value ( some_node, x_value )
end
end
+ if find_kern ( n, NEXT ) then
+ x_value = x_value + find_kern ( n, NEXT )
+ end
end
end
if disc_list and HAS_GLYPH ( current_head ) then
@@ -165,19 +229,20 @@ local function make_rule ( head, n, kern_node, current_head, disc_list )
height = calc_value ( next_glyph.height )
depth = calc_value ( next_glyph.depth )
end
- if PREV ( kern_node ) and PREV ( kern_node ).id == KERN then
- thickness = get_x_value ( PREV ( kern_node ), thickness )
- if PREV ( PREV ( kern_node ) ) and PREV ( PREV ( kern_node ) ).id == KERN then
- thickness = get_x_value ( PREV ( PREV ( kern_node ) ), thickness )
- end
+ if find_kern ( n, PREV ) then
+ thickness = thickness + find_kern ( n, PREV )
end
- if ( thickness ~= 0 ) and ( thickness > calc_value ( tex.hsize ) * - 1 ) then
- head = AB ( head, insert_point, NEW ( WI, pdfliteral ) )
+ if thickness ~= 0 and thickness > calc_value ( tex.hsize ) * - 1 then
if thickness > 0 then
color = "0 1 0"
else
color = "1 0 0"
end
+ if disc_list and not ( TAIL ( current_head ) == kern_node ) and not ( current_head == kern_node ) then
+ current_head = AB ( current_head, insert_point, NEW ( WI, PDF_LITERAL ) )
+ else
+ head = AB ( head, insert_point, NEW ( WI, PDF_LITERAL ) )
+ end
x_value = ( x_value + calc_value ( kern_node.expansion_factor ) + thickness * 0.5 ) * f
DIR ( insert_point ).mode = 0
DIR ( insert_point ).data = "q " .. ABS ( thickness ) .. " w " .. x_value .. " " .. - depth .. " m " .. x_value .. " " .. height .. " l " .. color .. " RG S Q"
@@ -189,12 +254,12 @@ local function show_kerns ( head )
for n in T ( head ) do
if n.id == HLIST or n.id == VLIST then
n.head = show_kerns ( n.head )
- elseif n.id == KERN and not ( NEXT ( n ) and NEXT ( n ).id == KERN ) then
+ elseif n.id == KERN and not find_kern ( n, NEXT ) then
head = make_rule ( head, n, n, head, false )
elseif n.replace then
local REPLACE = n.replace
for kern_node in T_ID ( KERN, REPLACE ) do
- if not ( n.subtype == USERKERN ) and not ( NEXT ( kern_node ) and NEXT ( kern_node ).id == KERN ) then
+ if not find_kern ( kern_node, NEXT ) then
head, REPLACE = make_rule ( head , n, kern_node, REPLACE, true )
end
end
diff --git a/macros/luatex/latex/showkerning/showkerning.pdf b/macros/luatex/latex/showkerning/showkerning.pdf
index dc31620858..e6c51a2a99 100644
--- a/macros/luatex/latex/showkerning/showkerning.pdf
+++ b/macros/luatex/latex/showkerning/showkerning.pdf
Binary files differ
diff --git a/macros/luatex/latex/showkerning/showkerning.sty b/macros/luatex/latex/showkerning/showkerning.sty
index 0d5cd0cff9..94bb18df31 100644
--- a/macros/luatex/latex/showkerning/showkerning.sty
+++ b/macros/luatex/latex/showkerning/showkerning.sty
@@ -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,7 +10,7 @@
% and version 1.3c or later is part of all distributions of
% LaTeX version 2009/09/24 or later.
-\ProvidesPackage{showkerning}[2022/04/17 v0.1 Showing kerns in a document]
+\ProvidesPackage{showkerning}[2023/07/08 v0.3 Showing kerns in a document]
\RequirePackage{ifluatex,luatexbase}
\ifluatex
diff --git a/macros/luatex/latex/showkerning/showkerning.tex b/macros/luatex/latex/showkerning/showkerning.tex
index f60d7f2ecf..534acff363 100644
--- a/macros/luatex/latex/showkerning/showkerning.tex
+++ b/macros/luatex/latex/showkerning/showkerning.tex
@@ -364,7 +364,7 @@ end
\title{The showk\kern-.1eme\kern.2emrn\kern-.05emin\kern.1emg package\vspace{.25\baselineskip}\\\superlarge{}\directlua{luatexbase.remove_from_callback ( "post_linebreak_filter", "show kerns in postline" ) luatexbase.remove_from_callback ( "hpack_filter", "show kerns in hpack" ) luatexbase.remove_from_callback ( "post_linebreak_filter", "remove kern" )}Showing kerns in a document}%
\author{\sublarge{}Thomas Kelkel\vspace{-.25\baselineskip}\\\sublarge{}kelkel@emaileon.de\vspace{-.25\baselineskip}}%
-\date{\addfontfeature{LetterSpace=2}\sublarge{}2022/05/31\quad{}v0.1}%
+\date{\addfontfeature{LetterSpace=2}\sublarge{}2023/07/08\quad{}v0.3}%
\maketitle
\thispagestyle{empty}
@@ -395,6 +395,6 @@ To load the package, simply add the following line to the preamble of the docume
\section{License}
-This package is copyright © 2022 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
+This package is copyright © 2022\kern.1em–\kern.1em2023 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
\end{document} \ No newline at end of file
diff --git a/macros/luatex/latex/spacekern/README.md b/macros/luatex/latex/spacekern/README.md
index 6aa24a47bb..d051915ddc 100644
--- a/macros/luatex/latex/spacekern/README.md
+++ b/macros/luatex/latex/spacekern/README.md
@@ -5,7 +5,7 @@ kerning against space are correctly applied.
Second, interword kerning can be applied.
The package requires LuaLaTeX.
-Copyright (c) 2022 Thomas Kelkel kelkel@emaileon.de
+Copyright (c) 2022-2023 Thomas Kelkel kelkel@emaileon.de
The files of this package may be distributed and/or
modified under the conditions of the LaTeX Project
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
diff --git a/macros/luatex/latex/spacekern/spacekern.pdf b/macros/luatex/latex/spacekern/spacekern.pdf
index a7c707ce10..d61888c1cc 100644
--- a/macros/luatex/latex/spacekern/spacekern.pdf
+++ b/macros/luatex/latex/spacekern/spacekern.pdf
Binary files differ
diff --git a/macros/luatex/latex/spacekern/spacekern.sty b/macros/luatex/latex/spacekern/spacekern.sty
index 8cb9153733..b8b0984a72 100644
--- a/macros/luatex/latex/spacekern/spacekern.sty
+++ b/macros/luatex/latex/spacekern/spacekern.sty
@@ -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,7 +10,7 @@
% and version 1.3c or later is part of all distributions of
% LaTeX version 2009/09/24 or later.
-\ProvidesPackage{spacekern}[2022/06/11 v0.1a Kerning between words and against space]
+\ProvidesPackage{spacekern}[2023/07/08 v0.3 Kerning between words and against space]
\RequirePackage{ifluatex,luatexbase}
\ifluatex
diff --git a/macros/luatex/latex/spacekern/spacekern.tex b/macros/luatex/latex/spacekern/spacekern.tex
index 33a1138453..871d0335ee 100644
--- a/macros/luatex/latex/spacekern/spacekern.tex
+++ b/macros/luatex/latex/spacekern/spacekern.tex
@@ -177,10 +177,10 @@ headings=optiontotoc,%
bookmarksopen=true,%
bookmarksopenlevel=0,%
bookmarksnumbered=true,%
- pdftitle={The spacekern package},
- pdfsubject={Kerning between words and against space},
- pdfauthor={Thomas Kelkel},
- pdfkeywords={tex, latex, kerning}
+ pdftitle={The spacekern package},%
+ pdfsubject={Kerning between words and against space},%
+ pdfauthor={Thomas Kelkel},%
+ pdfkeywords={tex, latex, kerning}%
}
\setlength{\parindent}{0pt}
@@ -343,7 +343,7 @@ end
\title{The spacekern package\vspace{.25\baselineskip}\\\superlarge{}Kerning between words and against space}%
\author{\sublarge{}Thomas Kelkel\vspace{-.25\baselineskip}\\\sublarge{}kelkel@emaileon.de\vspace{-.25\baselineskip}}%
-\date{\addfontfeature{LetterSpace=2}\sublarge{}2022/06/11\quad{}v0.1a}%
+\date{\addfontfeature{LetterSpace=2}\sublarge{}2023/07/08\quad{}v0.3}%
\maketitle
\section{Introduction}
@@ -382,11 +382,11 @@ Options can be loaded by adding them comma separated within square brackets:
\section{Shorthands and Macros}
-\addcontentsline{toc}{subsection}{;;}
+\addcontentsline{toc}{subsection}{\semicolon\semicolon}
\textnote{\semicolon\semicolon}Typesets a small breaking space.
-\addcontentsline{toc}{subsection}{;;;}
+\addcontentsline{toc}{subsection}{\semicolon\semicolon\semicolon}
\textnote{\semicolon\semicolon\semicolon}Typesets a small non-breaking space.
@@ -396,6 +396,6 @@ Options can be loaded by adding them comma separated within square brackets:
\section{License}
-This package is copyright © 2022 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
+This package is copyright © 2022\kern.1em–\kern.1em2023 Thomas Kelkel. It 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. This work has the LPPL maintenance status \qq{author maintained}.
\end{document} \ No newline at end of file