diff options
Diffstat (limited to 'macros/luatex')
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 Binary files differindex 98eb766816..8166d7f7e9 100644 --- a/macros/luatex/latex/ligtype/ligtype.pdf +++ b/macros/luatex/latex/ligtype/ligtype.pdf 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 Binary files differindex a0ce34f5e5..96d6fb8525 100644 --- a/macros/luatex/latex/showhyphenation/showhyphenation.pdf +++ b/macros/luatex/latex/showhyphenation/showhyphenation.pdf 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 Binary files differindex dc31620858..e6c51a2a99 100644 --- a/macros/luatex/latex/showkerning/showkerning.pdf +++ b/macros/luatex/latex/showkerning/showkerning.pdf 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 Binary files differindex a7c707ce10..d61888c1cc 100644 --- a/macros/luatex/latex/spacekern/spacekern.pdf +++ b/macros/luatex/latex/spacekern/spacekern.pdf 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 |