diff options
Diffstat (limited to 'macros/luatex/generic')
27 files changed, 2449 insertions, 683 deletions
diff --git a/macros/luatex/generic/luamplib/Makefile b/macros/luatex/generic/luamplib/Makefile index f4d638764e..f41c9a6339 100644 --- a/macros/luatex/generic/luamplib/Makefile +++ b/macros/luatex/generic/luamplib/Makefile @@ -36,7 +36,7 @@ world: all ctan .PHONY: all doc unpack ctan tds check world %.pdf: %.dtx - latexmk -lualatex -recorder- -silent $< >/dev/null + @texfot --quiet --tee=/dev/null --ignore "^Overfull" --ignore "^Underfull" lualatex -recorder $< $(UNPACKED): $(DTX) luatex -interaction=batchmode $< >/dev/null diff --git a/macros/luatex/generic/luamplib/NEWS b/macros/luatex/generic/luamplib/NEWS index f0dd1cf2f4..9cd7c57171 100644 --- a/macros/luatex/generic/luamplib/NEWS +++ b/macros/luatex/generic/luamplib/NEWS @@ -1,5 +1,77 @@ History of the luamplib package +2024/05/24 2.31.1 + * fix bugs in outlinetext routine + * improve rule treatment in graphictext + +2024/05/21 2.31.0 + * provide a new metapost operator 'mpliboutlinetext', which mimicks + metafun's 'outlinetext'. The syntax is the same as metafun's. (#133) + +2024/05/10 2.30.0 + * provide a new metapost operator 'mplibglyph', which returns a metapost + picture containing outline paths of a glyph in opentype, truetype or type1 + fonts. When a type1 font is specified, metapost primitive 'glyph' will be + called. In the syntax as follows, subfont number is zero based. + + mplibglyph 50 of \fontid\font % slot 50 of current font + mplibglyph 50 of "cmr10" % type1 font + mplibglyph "Q" of "TU/TeXGyrePagella(0)/m/n/10" % font csname + mplibglyph "똠" of "NotoSansCJKkr-Regular.otf" % raw filename + mplibglyph "Q" of "Times.ttc(2)" % subfont number + mplibglyph "똠" of "SourceHanSansK-VF.otf[Regular]" % instance name + + * provide a new metapost command 'mplibdrawglyph'. In contrast to metapost's + 'draw' command, this one fills paths of a picture according to the Nonzero + Winding Number Rule. + + * in 'mplibgraphictext', option 'scale' is deprecated and now a synonym of + 'scaled'. In DVI mode, unicode-math package is needed for math formula + graphictext. + +2024/05/01 2.29.0 + + * provide new TeX macros to reduce typing toil. + + \mpfig ... \endmpfig is roughly the abbreviation of + \begin{mplibcode}[@mpfig] + beginfig(0) + token list declared by \everymplib[@mpfig] + ... + token list declared by \everyendmplib[@mpfig] + endfig; + \end{mplibcode} + + \mpfig* ... \endmpfig is roughly the abbreviation of + \begin{mplibcode}[@mpfig] + ... + \end{mplibcode} + + These macros are protected and unexpandable. + In these macros \mpliblegacybehavior{false} is forcibly declared. + As both share the same instance name, MetaPost codes are inherited among them. + The instance name (default: @mpfig) can be changed by redefining `\mpfiginstancename'. + + * instance names are allowed in plain TeX as well. The syntax is: + + \mplibcode[name] ... \endmplibcode + \everymplib[name]{ ... } + \everyendmplib[name]{ ... } + + These macros are now protected and unexpandable. + + * provide new MetaPost operators `mplibtexcolor' and `mplibrgbtexcolor' + which convert TeX color expressions to MetaPost color expressions. + The latter one forces rgb model results (#112). For instance, + + mplibtexcolor "olive" % => (0, 0, 1, 0.5) + mplibrgbtexcolor "olive" % => (0.5, 0.5, 0) + + As spot colors are always forced to cmyk or rgb model, it is not + recommended to use these operators for them. + + * write down MetaPost messages into the log file + 2024/04/25 2.28.2 * direction of figure box is explicitly declared as TLT (#129) * figure box materials are emitted in one go at the end of the figure @@ -72,11 +144,11 @@ 2024/03/01 2.26.0 * when \mplibcachedir{<dir>} is not set, default cache directory will be in the following order: - $TEXMFVAR/luamplib_cache - $TEXMF_OUTPUT_DIRECTORY/luamplib_cache - ./luamplib_cache - $TEXMFOUTPUT/luamplib_cache - . + $TEXMFVAR/luamplib_cache + $TEXMF_OUTPUT_DIRECTORY/luamplib_cache + ./luamplib_cache + $TEXMFOUTPUT/luamplib_cache + . 2024/01/25 2.25.3 * protect "..." even if textextlabel is disabled (revert part of v2.25.0) diff --git a/macros/luatex/generic/luamplib/luamplib.dtx b/macros/luatex/generic/luamplib/luamplib.dtx index 283120c622..eb5ec196dd 100644 --- a/macros/luatex/generic/luamplib/luamplib.dtx +++ b/macros/luatex/generic/luamplib/luamplib.dtx @@ -85,7 +85,7 @@ See source file '\inFileName' for licencing and contact information. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{luamplib.drv}% - [2024/04/25 v2.28.2 Interface for using the mplib library]% + [2024/05/24 v2.31.1 Interface for using the mplib library]% \documentclass{ltxdoc} \usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -112,7 +112,7 @@ See source file '\inFileName' for licencing and contact information. ItalicFont = {Linux Libertine O Italic}, SlantedFont = {Linux Libertine O Italic}, ]{Linux Libertine O} -\setmonofont[Ligatures=TeX,Scale=MatchLowercase]{InconsolataN} +\setmonofont[Scale=MatchLowercase]{InconsolataN} %setsansfont[Ligatures=TeX]{Linux Biolinum O} \setsansfont[Ligatures=TeX,Scale=MatchLowercase]{Iwona Medium} %setmathfont{XITS Math} @@ -153,7 +153,7 @@ See source file '\inFileName' for licencing and contact information. % \author{Hans Hagen, Taco Hoekwater, Elie Roux, Philipp Gesang and Kim Dohyun\\ % Maintainer: LuaLaTeX Maintainers --- % Support: \email{lualatex-dev@tug.org}} -% \date{2024/04/25 v2.28.2} +% \date{2024/05/24 v2.31.1} % % \maketitle % @@ -209,6 +209,41 @@ See source file '\inFileName' for licencing and contact information. % setting. (Actually these commands redefine |\prependtomplibbox|. You % can define this command with anything suitable before a box.) % +% \paragraph{\cs{mpfig} \ldots\ \cs{endmpfig}} +% Since v2.29 we provide unexpandable \TeX\ macros |\mpfig ... \endmpfig| and its starred version +% |\mpfig* ... \endmpfig| to save typing toil. +% The first is roughly the same as follows: +% \begin{verbatim} +% \begin{mplibcode}[@mpfig] +% beginfig(0) +% token list declared by \everymplib[@mpfig] +% ... +% token list declared by \everyendmplib[@mpfig] +% endfig; +% \end{mplibcode} +% \end{verbatim} +% and the starred version is roughly the same as follows: +% \begin{verbatim} +% \begin{mplibcode}[@mpfig] +% ... +% \end{mplibcode} +% \end{verbatim} +% In these macros |\mpliblegacybehavior{disable}| (see below) +% is forcibly declared. +% And as both share the same instance name, metapost codes are inherited among them. +% A simple example: +% \begin{verbatim} +% \mpfig* input boxes \endmpfig +% \everymplib[@mpfig]{ drawoptions(withcolor .5[red,white]); } +% \mpfig circleit.a(btex Box 1 etex); drawboxed(a); \endmpfig +% \end{verbatim} +% The instance name (default: |@mpfig|) can be changed by redefining +% \cs{mpfiginstancename}, after which a new MPlib instance will start and +% code inheritance too will begin anew. |\let\mpfiginstancename\empty| will +% prevent code inheritance if |\mplibcodeinherit{true}| (see below) is not declared.\footnote{% +% As for user setting values, |enable|, |true|, |yes| are identical, and +% |disable|, |false|, |no| are identical.} +% % \paragraph{\cs{mpliblegacybehavior\{enable\}}} % By default, |\mpliblegacybehavior{enable}| is already declared, % in which case @@ -326,9 +361,10 @@ See source file '\inFileName' for licencing and contact information. % each code chunks being treated as an independent instance, and never % affected by previous code chunks. % -% \paragraph{Separate instances for \LaTeX{} environment} +% \paragraph{Separate instances for \LaTeX{} and plain \TeX} % v2.22 has added the support for several named MetaPost instances % in \LaTeX{} |mplibcode| environment. +% (And since v2.29 plain \TeX\ users can use this functionality as well.) % Syntax is like so: % \begin{verbatim} % \begin{mplibcode}[instanceName] @@ -378,7 +414,8 @@ See source file '\inFileName' for licencing and contact information. % \endmplibcode % \end{verbatim} % Generally speaking, it is recommended to turn |mplibglobaltextext| -% always on, because it has the advantage of more efficient processing. +% always on, because it has the advantage of reusing metapost pictures +% among code chunks. % But everything has its downside: it will waste more memory resources. % % \paragraph{\cs{mplibverbatim}} @@ -423,26 +460,105 @@ See source file '\inFileName' for licencing and contact information. % As backslashes (|\|) should be escaped by users, it would be easier to use % slashes (|/|) instead. % +% \paragraph{\texttt{mplibtexcolor}, \texttt{mplibrgbtexcolor}} +% |mplibtexcolor| is a metapost operator that converts a \TeX\ color expression +% to a MetaPost color expression. For instance: +% \begin{verbatim} +% color col; +% col := mplibtexcolor "olive!50"; +% \end{verbatim} +% The result may vary in its color model (gray/rgb/cmyk) +% according to the given \TeX\ color. (Spot colors are forced to +% cmyk model, so this operator is not recommended for spot colors.) +% Therefore the example shown above would raise a metapost error: +% |cmykcolor col;| should have been declared. +% By contrast, |mplibrgbtexcolor| always returns rgb model expressions. +% % \paragraph{\texttt{mplibgraphictext}} % For some amusement, luamplib provides its own metapost operator % |mplibgraphictext|, the effect of which is similar to that of % \ConTeXt's |graphictext|. However syntax is somewhat different. % \begin{verbatim} -% mplibgraphictext "Funny" -% fakebold 2.3 scale 3 % fontspec options -% drawcolor .7blue fillcolor "red!50" % color expressions +% mplibgraphictext "Funny" +% fakebold 2.3 % fontspec option +% drawcolor .7blue fillcolor "red!50" % color expressions % \end{verbatim} -% |fakebold|, |scale|, |drawcolor| and |fillcolor| are optional; -% default values are |2|, |1|, |"black"| and |"white"| respectively. +% |fakebold|, |drawcolor| and |fillcolor| are optional; +% default values are |2|, |"black"| and |"white"| respectively. % When color expressions are given as string, they are regarded as % xcolor's or l3color's expressions (this is the same with shading colors). +% From v2.30, |scale| option is deprecated and is now a synonym of |scaled|. % All from |mplibgraphictext| to the end of sentence will compose an % anonymous |picture|, which can be drawn or assigned to a variable. % Incidentally, |withdrawcolor| and |withfillcolor| are synonyms of % |drawcolor| and |fillcolor|, hopefully to be compatible with |graphictext|. % \textsc{n.b.} Because luamplib's current implementation is quite different % from the \ConTeXt's, there are some limitations such that you can't -% apply shading (gradient colors) to the text. +% apply shading (gradient colors) to the text (But see below). +% In DVI mode, |unicode-math| package is needed for math formula graphictext, +% as we cannot embolden type1 fonts in DVI mode. +% +% \paragraph{\texttt{mplibglyph}, \texttt{mplibdrawglyph}} +% From v2.30, we provide a new metapost operator |mplibglyph|, which returns a metapost picture +% containing outline paths of a glyph in opentype, truetype or type1 fonts. +% When a type1 font is specified, metapost primitive |glyph| will be called. +% \begin{verbatim} +% mplibglyph 50 of \fontid\font % slot 50 of current font +% mplibglyph "Q" of "TU/TeXGyrePagella(0)/m/n/10" % font csname +% mplibglyph "Q" of "texgyrepagella-regular.otf" % raw filename +% mplibglyph "Q" of "Times.ttc(2)" % subfont number +% mplibglyph "Q" of "SourceHanSansK-VF.otf[Regular]" % instance name +% \end{verbatim} +% Both arguments before and after of ``|of|'' can be either a number or a string. +% Number arguments are regarded as a glyph slot (GID) and a font id number, repectively. +% String argument at the left side is regarded as a glyph name in the font or a unicode character. +% String argument at the right side is regarded as a \TeX\ font csname (without backslash) or +% the raw filename of a font. When it is a font filename, a number within parentheses +% after the filename denotes a +% subfont number (starting from zero) of a TTC font; a string within brackets denotes +% an instance name of a variable font. +% +% The returned picture will be quite similar to the result of |glyph| primitive in its structure. +% So, metapost's |draw| command will fill the inner path of the picture with background color. +% In contrast, |mplibdrawglyph| command fills the paths according to the Nonzero Winding +% Number Rule. As a result, for instance, the area surrounded by inner path of ``O'' +% will remain transparent. +% +% We can adapt the method used in |mplibdrawglyph| to multiple pictures as if they were +% components of one and the same picture. An example: +% \begin{verbatim} +% \mplibsetformat{metafun} +% \mpfig +% picture Q, u, e; +% Q := mplibglyph "Q" of "Times.ttc(2)" scaled .15; +% u := mplibglyph "u" of "Times.ttc(2)" scaled .15 shifted lrcorner Q; +% e := mplibglyph "e" of "Times.ttc(2)" scaled .15 shifted lrcorner u; +% +% i:=0; +% totallen := length Q + length u + length e; +% for pic=Q, u, e: +% for item within pic: +% i:=i+1; +% fill pathpart item +% if i < totallen: withpostscript "collect"; fi +% endfor +% endfor +% withshademethod "linear" +% withshadedirection (0.5,2.5) +% withshadecolors (.7red,.7yellow); +% \endmpfig +% \end{verbatim} +% +% \paragraph{\texttt{mpliboutlinetext}} +% From v2.31, we provide a new metapost operator |mpliboutlinetext|, which mimicks +% metafun's |outlinetext|. So the syntax is the same as metafun's. See the metafun +% manual \textsection\,8.7 (|texdoc metafun|). A simple example: +% \begin{verbatim} +% draw mpliboutlinetext.b ("$\sqrt{2+\alpha}$") +% (withcolor \mpcolor{red!50}) +% (withpen pencircle scaled .2 withcolor red) +% scaled 2 ; +% \end{verbatim} % % \paragraph{About figure box metrics} % Notice that, after each figure is processed, macro \cs{MPwidth} stores @@ -476,8 +592,8 @@ See source file '\inFileName' for licencing and contact information. luatexbase.provides_module { name = "luamplib", - version = "2.28.2", - date = "2024/04/25", + version = "2.31.1", + date = "2024/05/24", description = "Lua package to typeset Metapost with LuaTeX's MPLib.", } @@ -538,6 +654,7 @@ luamplib.showlog = luamplib.showlog or false % \ConTeXt. Provide a few ``shortcuts'' expected by the imported code. % \begin{macrocode} local tableconcat = table.concat +local tableinsert = table.insert local texsprint = tex.sprint local texgettoks = tex.gettoks local texgetbox = tex.getbox @@ -606,7 +723,7 @@ luamplibtime = luamplibtime and lfsattributes(luamplibtime,"modification") local currenttime = os.time() -local outputdir +local outputdir, cachedir if lfstouch then for i,v in ipairs{'TEXMFVAR','TEXMF_OUTPUT_DIRECTORY','.','TEXMFOUTPUT'} do local var = i == 3 and v or kpse.var_value(v) @@ -626,7 +743,6 @@ if lfstouch then end end outputdir = outputdir or '.' - function luamplib.getcachedir(dir) dir = dir:gsub("##","#") dir = dir:gsub("^~", @@ -634,7 +750,7 @@ function luamplib.getcachedir(dir) if lfstouch and dir then if lfsisdir(dir) then if is_writable(dir) then - luamplib.cachedir = dir + cachedir = dir else warn("Directory '%s' is not writable!", dir) end @@ -701,9 +817,8 @@ local verbatimtex_etex = name_b.."verbatimtex"..name_e.."%s*(.-)%s*"..name_b.."e local function replaceinputmpfile (name,file) local ofmodify = lfsattributes(file,"modification") if not ofmodify then return file end - local cachedir = luamplib.cachedir or outputdir local newfile = name:gsub("%W","_") - newfile = cachedir .."/luamplib_input_"..newfile + newfile = format("%s/luamplib_input_%s", cachedir or outputdir, newfile) if newfile and luamplibtime then local nf = lfsattributes(newfile) if nf and nf.mode == "file" and @@ -719,7 +834,6 @@ local function replaceinputmpfile (name,file) local data = fh:read("*all"); fh:close() % \end{macrocode} -% % ``|etex|'' must be followed by a space or semicolon as specified in % \LuaTeX\ manual, which is not the case of standalone MetaPost though. % \begin{macrocode} @@ -767,7 +881,7 @@ local special_ftype = { enc = "enc files", } -local function finder(name, mode, ftype) +function luamplib.finder (name, mode, ftype) if mode == "w" then if name and name ~= "mpout.log" then kpse.record_output_file(name) -- recorder @@ -789,7 +903,6 @@ local function finder(name, mode, ftype) return file end end -luamplib.finder = finder % \end{macrocode} % @@ -811,19 +924,17 @@ local preamble = [[ % though we cannot support |metafun| format fully. % \begin{macrocode} local currentformat = "plain" -local function setformat (name) +function luamplib.setformat (name) currentformat = name end -luamplib.setformat = setformat % \end{macrocode} % % v2.9 has introduced the concept of ``code inherit'' % \begin{macrocode} luamplib.codeinherit = false - local mplibinstances = {} -local instancename +local has_instancename = false local function reporterror (result, prevlog) if not result then @@ -831,7 +942,6 @@ local function reporterror (result, prevlog) else local t, e, l = result.term, result.error, result.log % \end{macrocode} -% % log has more information than term, so log first (2021/08/02) % \begin{macrocode} local log = l or t or "no-term" @@ -850,7 +960,6 @@ local function reporterror (result, prevlog) elseif prevlog then log = prevlog..log % \end{macrocode} -% % v2.6.1: now luamplib does not disregard |show| command, % even when |luamplib.showlog| is false. Incidentally, % it does not raise error but just prints an info, @@ -873,7 +982,6 @@ local function luamplibload (name) ini_version = true, find_file = luamplib.finder, % \end{macrocode} -% % Make use of |make_text| and |run_script|, which will co-operate % with \LuaTeX's |tex.runtoks|. And we % provide |numbersystem| option since v2.4. Default value ``|scaled|'' @@ -889,14 +997,13 @@ local function luamplibload (name) extensions = 1, } % \end{macrocode} -% % Append our own MetaPost preamble to the preamble above. % \begin{macrocode} local preamble = tableconcat{ format(preamble, replacesuffix(name,"mp")), - luamplib.mplibcodepreamble, - luamplib.legacy_verbatimtex and luamplib.legacyverbatimtexpreamble or "", - luamplib.textextlabel and luamplib.textextlabelpreamble or "", + luamplib.preambles.mplibcode, + luamplib.legacy_verbatimtex and luamplib.preambles.legacyverbatimtex or "", + luamplib.textextlabel and luamplib.preambles.textextlabel or "", } local result, log if not mpx then @@ -913,9 +1020,8 @@ end % Here, excute each |mplibcode| data, % ie |\begin{mplibcode} ... \end{mplibcode}|. % \begin{macrocode} -local function process (data) +local function process (data, instancename) % \end{macrocode} -% % The workaround of issue \#70 seems to be unnecessary, as we use % |make_text| now. % \begin{verbatim} @@ -927,6 +1033,7 @@ local function process (data) local currfmt if instancename and instancename ~= "" then currfmt = instancename + has_instancename = true else currfmt = tableconcat{ currentformat, @@ -934,12 +1041,10 @@ local function process (data) tostring(luamplib.textextlabel), tostring(luamplib.legacy_verbatimtex), } + has_instancename = false end local mpx = mplibinstances[currfmt] - local standalone = false - if currfmt ~= instancename then - standalone = not luamplib.codeinherit - end + local standalone = not (has_instancename or luamplib.codeinherit) if mpx and standalone then mpx:finish() end @@ -1006,10 +1111,7 @@ end % Boxes of an instance will also be global, so that % their tex boxes can be shared among instances of the same name. % \begin{macrocode} -local texboxes = { - locals = {}, localid = 4096, - globals = {}, globalid = 0, -} +local texboxes = { globalid = 0, localid = 4096 } % \end{macrocode} % For conversion of |sp| to |bp|. % \begin{macrocode} @@ -1021,32 +1123,21 @@ withprescript "mplibtexboxid=%i:%f:%f")' local function process_tex_text (str) if str then - local boxtable, global - if instancename and instancename ~= "" - or luamplib.globaltextext or luamplib.codeinherit then - boxtable, global = texboxes.globals, "\\global" + local global = (has_instancename or luamplib.globaltextext or luamplib.codeinherit) + and "\\global" or "" + local tex_box_id + if global == "" then + tex_box_id = texboxes.localid + 1 + texboxes.localid = tex_box_id else - boxtable, global = texboxes.locals, "" - end - local tex_box_id = boxtable[str] - local box = tex_box_id and texgetbox(tex_box_id) - if not box then - if global == "" then - tex_box_id = texboxes.localid + 1 - texboxes.localid = tex_box_id - else - local boxid = texboxes.globalid + 1 - texboxes.globalid = boxid - run_tex_code(format( - [[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid)) - tex_box_id = tex.getcount'allocationnumber' - end - if str:find"^[%s%w%{%}%$%^%_]*$" then -- the same cs may expand differently - boxtable[str] = tex_box_id - end - run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str)) - box = texgetbox(tex_box_id) + local boxid = texboxes.globalid + 1 + texboxes.globalid = boxid + run_tex_code(format( + [[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid)) + tex_box_id = tex.getcount'allocationnumber' end + run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str)) + local box = texgetbox(tex_box_id) local wd = box.width / factor local ht = box.height / factor local dp = box.depth / factor @@ -1091,7 +1182,7 @@ if colfmt == "l3color" then end local ccexplat = luatexbase.registernumber"luamplibcctabexplat" -local function process_color (str, kind) +local function process_color (str) if str then if not str:find("%b{}") then str = format("{%s}",str) @@ -1112,117 +1203,16 @@ local function process_color (str, kind) end end end - if myfmt == mplibcolorfmt.l3color and (kind == "fill" or kind == "draw") then return str end run_tex_code(myfmt:format(str), ccexplat or catat11) local t = texgettoks"mplibtmptoks" if not pdfmode and not t:find"^pdf" then t = t:gsub("%a+ (.+)","pdf:bc [%1]") end - if kind then return t end - return format('1 withprescript "MPlibOverrideColor=%s"', t) + return format('1 withprescript "mpliboverridecolor=%s"', t) end return "" end -local function colorsplit (res) - local t, tt = { }, res:gsub("[%[%]]",""):explode() - local be = tt[1]:find"^%d" and 1 or 2 - for i=be, #tt do - if tt[i]:find"^%a" then break end - t[#t+1] = tt[i] - end - return t -end - -luamplib.outlinecolor = function (str, filldraw) - local nn = filldraw == "fill" and 'fn:=' or 'dn:=' - local cc = filldraw == "fill" and 'fc:=' or 'dc:=' - local res = process_color(str, filldraw) - if res:match"{(.+)}" == str then - return format('%s"n"; %s"%s";', nn,cc,str) - end - local t = colorsplit(res) - local md = #t == 1 and 'gray' or #t == 3 and 'rgb' or #t == 4 and 'cmyk' - return format('%s"nn"; %s"%s}{%s";', nn, cc, md, tableconcat(t,',')) -end - -luamplib.shadecolor = function (str) - local res = process_color(str, "shade") - if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only -% \end{macrocode} -% An example of spot color shading: -% \begin{verbatim} -% \documentclass{article} -% \usepackage{luamplib} -% \mplibsetformat{metafun} -% \ExplSyntaxOn -% \color_model_new:nnn { pantone3005 } -% { Separation } -% { name = PANTONE~3005~U , -% alternative-model = cmyk , -% alternative-values = {1, 0.56, 0, 0} -% } -% \color_set:nnn{spotA}{pantone3005}{1} -% \color_set:nnn{spotB}{pantone3005}{0.6} -% \color_model_new:nnn { pantone1215 } -% { Separation } -% { name = PANTONE~1215~U , -% alternative-model = cmyk , -% alternative-values = {0, 0.15, 0.51, 0} -% } -% \color_set:nnn{spotC}{pantone1215}{1} -% \color_model_new:nnn { pantone2040 } -% { Separation } -% { name = PANTONE~2040~U , -% alternative-model = cmyk , -% alternative-values = {0, 0.28, 0.21, 0.04} -% } -% \color_set:nnn{spotD}{pantone2040}{1} -% \ExplSyntaxOff -% \begin{document} -% \begin{mplibcode} -% beginfig(1) -% fill unitsquare xyscaled (\mpdim\textwidth,1cm) -% withshademethod "linear" -% withshadevector (0,1) -% withshadestep ( -% withshadefraction .5 -% withshadecolors ("spotB","spotC") -% ) -% withshadestep ( -% withshadefraction 1 -% withshadecolors ("spotC","spotD") -% ) -% ; -% endfig; -% \end{mplibcode} -% \end{document} -% \end{verbatim} -% \begin{macrocode} - run_tex_code({ - [[\color_export:nnN{]], str, [[}{backend}\mplib_@tempa]], - },ccexplat) - local name = get_macro'mplib_@tempa':match'{(.-)}{.+}' - local t, obj = res:explode() - if pdfmode then - obj = t[1]:match"^/(.+)" - if ltx.pdf and ltx.pdf.object_id then - obj = format("%s 0 R", ltx.pdf.object_id(obj)) - else - run_tex_code({ - [[\edef\mplib_@tempa{\pdf_object_ref:n{]], obj, "}}", - },ccexplat) - obj = get_macro'mplib_@tempa' - end - else - obj = t[2] - end - local value = t[3]:match"%[(.-)%]" or t[3] - return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name) - end - return colorsplit(res) -end - % \end{macrocode} % % for \cs{mpdim} or |mplibdimen| @@ -1259,11 +1249,6 @@ local tex_code_pre_mplib = {} luamplib.figid = 1 luamplib.in_the_fig = false -local function legacy_mplibcode_reset () - tex_code_pre_mplib = {} - luamplib.figid = 1 -end - local function process_verbatimtex_prefig (str) if str then tex_code_pre_mplib[luamplib.figid] = str @@ -1297,7 +1282,6 @@ mp.mf_path_reset = mp.mf_path_reset or function() end mp.mf_finish_saving_data = mp.mf_finish_saving_data or function() end mp.report = mp.report or info - % \end{macrocode} % % metafun 2021-03-09 changes crashes luamplib. @@ -1403,9 +1387,675 @@ end % \end{macrocode} % +% luamplib's metapost color operators +% \begin{macrocode} +local function colorsplit (res) + local t, tt = { }, res:gsub("[%[%]]",""):explode() + local be = tt[1]:find"^%d" and 1 or 2 + for i=be, #tt do + if tt[i]:find"^%a" then break end + t[#t+1] = tt[i] + end + return t +end + +luamplib.gettexcolor = function (str, rgb) + local res = process_color(str):match'"mpliboverridecolor=(.+)"' + if res:find" cs " or res:find"@pdf.obj" then + if not rgb then + warn("%s is a spot color. Forced to CMYK", str) + end + run_tex_code({ + "\\color_export:nnN{", + str, + "}{", + rgb and "space-sep-rgb" or "space-sep-cmyk", + "}\\mplib_@tempa", + },ccexplat) + return get_macro"mplib_@tempa":explode() + end + local t = colorsplit(res) + if #t == 3 or not rgb then return t end + if #t == 4 then + return { 1 - math.min(1,t[1]+t[4]), 1 - math.min(1,t[2]+t[4]), 1 - math.min(1,t[3]+t[4]) } + end + return { t[1], t[1], t[1] } +end + +luamplib.shadecolor = function (str) + local res = process_color(str):match'"mpliboverridecolor=(.+)"' + if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only +% \end{macrocode} +% An example of spot color shading: +% \begin{verbatim} +% \documentclass{article} +% \usepackage{luamplib} +% \mplibsetformat{metafun} +% \ExplSyntaxOn +% \color_model_new:nnn { pantone3005 } +% { Separation } +% { name = PANTONE~3005~U , +% alternative-model = cmyk , +% alternative-values = {1, 0.56, 0, 0} +% } +% \color_set:nnn{spotA}{pantone3005}{1} +% \color_set:nnn{spotB}{pantone3005}{0.6} +% \color_model_new:nnn { pantone1215 } +% { Separation } +% { name = PANTONE~1215~U , +% alternative-model = cmyk , +% alternative-values = {0, 0.15, 0.51, 0} +% } +% \color_set:nnn{spotC}{pantone1215}{1} +% \color_model_new:nnn { pantone2040 } +% { Separation } +% { name = PANTONE~2040~U , +% alternative-model = cmyk , +% alternative-values = {0, 0.28, 0.21, 0.04} +% } +% \color_set:nnn{spotD}{pantone2040}{1} +% \ExplSyntaxOff +% \begin{document} +% \begin{mplibcode} +% beginfig(1) +% fill unitsquare xyscaled (\mpdim\textwidth,1cm) +% withshademethod "linear" +% withshadevector (0,1) +% withshadestep ( +% withshadefraction .5 +% withshadecolors ("spotB","spotC") +% ) +% withshadestep ( +% withshadefraction 1 +% withshadecolors ("spotC","spotD") +% ) +% ; +% endfig; +% \end{mplibcode} +% \end{document} +% \end{verbatim} +% \begin{macrocode} + run_tex_code({ + [[\color_export:nnN{]], str, [[}{backend}\mplib_@tempa]], + },ccexplat) + local name = get_macro'mplib_@tempa':match'{(.-)}{.+}' + local t, obj = res:explode() + if pdfmode then + obj = t[1]:match"^/(.+)" + if ltx.pdf and ltx.pdf.object_id then + obj = format("%s 0 R", ltx.pdf.object_id(obj)) + else + run_tex_code({ + [[\edef\mplib_@tempa{\pdf_object_ref:n{]], obj, "}}", + },ccexplat) + obj = get_macro'mplib_@tempa' + end + else + obj = t[2] + end + local value = t[3]:match"%[(.-)%]" or t[3] + return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name) + end + return colorsplit(res) +end + +% \end{macrocode} +% +% luamplib's mplibgraphictext operator +% \begin{macrocode} +local running = -1073741824 +local emboldenfonts = { } +local function getemboldenwidth (curr, fakebold) + local width = emboldenfonts.width + if not width then + local f + local function getglyph(n) + while n do + if n.head then + getglyph(n.head) + elseif n.font and n.font > 0 then + f = n.font; break + end + n = node.getnext(n) + end + end + getglyph(curr) + width = font.getcopy(f or font.current()).size * fakebold / factor * 10 + emboldenfonts.width = width + end + return width +end +local function getrulewhatsit (line, wd, ht, dp) + line, wd, ht, dp = line/1000, wd/factor, ht/factor, dp/factor + local pl + local fmt = "%f w %f %f %f %f re %s" + if pdfmode then + pl = node.new("whatsit","pdf_literal") + pl.mode = 0 + else + fmt = "pdf:content "..fmt + pl = node.new("whatsit","special") + end + pl.data = fmt:format(line, 0, -dp, wd, ht+dp, "B") + local ss = node.new"glue" + node.setglue(ss, 0, 65536, 65536, 2, 2) + pl.next = ss + return pl +end +local function getrulemetric (box, curr, bp) + local wd,ht,dp = curr.width, curr.height, curr.depth + wd = wd == running and box.width or wd + ht = ht == running and box.height or ht + dp = dp == running and box.depth or dp + if bp then + return wd/factor, ht/factor, dp/factor + end + return wd, ht, dp +end +local function embolden (box, curr, fakebold) + local head = curr + while curr do + if curr.head then + curr.head = embolden(curr, curr.head, fakebold) + elseif curr.replace then + curr.replace = embolden(box, curr.replace, fakebold) + elseif curr.leader then + if curr.leader.head then + curr.leader.head = embolden(curr.leader, curr.leader.head, fakebold) + elseif curr.leader.id == node.id"rule" then + local glue = node.effective_glue(curr, box) + local line = getemboldenwidth(curr, fakebold) + local wd,ht,dp = getrulemetric(box, curr.leader) + if box.id == node.id"hlist" then + wd = glue + else + ht, dp = 0, glue + end + local pl = getrulewhatsit(line, wd, ht, dp) + local pack = box.id == node.id"hlist" and node.hpack or node.vpack + local list = pack(pl, glue, "exactly") + head = node.insert_after(head, curr, list) + head, curr = node.remove(head, curr) + end + elseif curr.id == node.id"rule" and curr.subtype == 0 then + local line = getemboldenwidth(curr, fakebold) + local wd,ht,dp = getrulemetric(box, curr) + if box.id == node.id"vlist" then + ht, dp = 0, ht+dp + end + local pl = getrulewhatsit(line, wd, ht, dp) + local list + if box.id == node.id"hlist" then + list = node.hpack(pl, wd, "exactly") + else + list = node.vpack(pl, ht+dp, "exactly") + end + head = node.insert_after(head, curr, list) + head, curr = node.remove(head, curr) + elseif curr.id == node.id"glyph" and curr.font > 0 then + local f = curr.font + local i = emboldenfonts[f] + if not i then + if pdfmode then + local ft = font.getcopy(f) + width = ft.size * fakebold / factor * 10 + emboldenfonts.width = width + ft.mode, ft.width = 2, width + i = font.define(ft) + else + local ft = font.getfont(f) or font.getcopy(f) + if ft.format ~= "opentype" and ft.format ~= "truetype" then + goto skip_type1 + end + local name = ft.name:gsub('"',''):gsub(';$','') + name = format('%s;embolden=%s;',name,fakebold) + _, i = fonts.constructors.readanddefine(name,ft.size) + end + emboldenfonts[f] = i + end + curr.font = i + end + ::skip_type1:: + curr = node.getnext(curr) + end + return head +end +local function graphictextcolor (col, filldraw) + if col:find"^[%d%.:]+$" then + col = col:explode":" + if pdfmode then + local op = #col == 4 and "k" or #col == 3 and "rg" or "g" + col[#col+1] = filldraw == "fill" and op or op:upper() + return tableconcat(col," ") + end + return format("[%s]", tableconcat(col," ")) + end + col = process_color(col):match'"mpliboverridecolor=(.+)"' + if pdfmode then + local t, tt = col:explode(), { } + local b = filldraw == "fill" and 1 or #t/2+1 + local e = b == 1 and #t/2 or #t + for i=b,e do + tt[#tt+1] = t[i] + end + return tableconcat(tt," ") + end + return col:gsub("^.- ","") +end +luamplib.graphictext = function (text, fakebold, fc, dc) + local fmt = process_tex_text(text):sub(1,-2) + local id = tonumber(fmt:match"mplibtexboxid=(%d+):") + local box = texgetbox(id) + box.head = embolden(box, box.head, fakebold) + local fill = graphictextcolor(fc,"fill") + local draw = graphictextcolor(dc,"draw") + local bc = pdfmode and "" or "pdf:bc " + return format('%s withprescript "mpliboverridecolor=%s%s %s")', fmt, bc, fill, draw) +end + +% \end{macrocode} +% +% luamplib's mplibglyph operator +% \begin{macrocode} +local function mperr (str) + return format("hide(errmessage %q)", str) +end +local function getangle (a,b,c) + local r = math.deg(math.atan(c.y-b.y, c.x-b.x) - math.atan(b.y-a.y, b.x-a.x)) + if r > 180 then + r = r - 360 + elseif r < -180 then + r = r + 360 + end + return r +end +local function turning (t) + local r, n = 0, #t + for i=1,2 do + tableinsert(t, t[i]) + end + for i=1,n do + r = r + getangle(t[i], t[i+1], t[i+2]) + end + return r/360 +end +local function glyphimage(t, fmt) + local q,p,r = {{},{}} + for i,v in ipairs(t) do + local cmd = v[#v] + if cmd == "m" then + p = {format('(%s,%s)',v[1],v[2])} + r = {{x=v[1],y=v[2]}} + else + local nt = t[i+1] + local last = not nt or nt[#nt] == "m" + if cmd == "l" then + local pt = t[i-1] + local seco = pt[#pt] == "m" + if (last or seco) and r[1].x == v[1] and r[1].y == v[2] then + else + tableinsert(p, format('--(%s,%s)',v[1],v[2])) + tableinsert(r, {x=v[1],y=v[2]}) + end + if last then + tableinsert(p, '--cycle') + end + elseif cmd == "c" then + tableinsert(p, format('..controls(%s,%s)and(%s,%s)',v[1],v[2],v[3],v[4])) + if last and r[1].x == v[5] and r[1].y == v[6] then + tableinsert(p, '..cycle') + else + tableinsert(p, format('..(%s,%s)',v[5],v[6])) + if last then + tableinsert(p, '--cycle') + end + tableinsert(r, {x=v[5],y=v[6]}) + end + else + return mperr"unknown operator" + end + if last then + tableinsert(q[ turning(r) > 0 and 1 or 2 ], tableconcat(p)) + end + end + end + r = { } + if fmt == "opentype" then + for _,v in ipairs(q[1]) do + tableinsert(r, format('addto currentpicture contour %s;',v)) + end + for _,v in ipairs(q[2]) do + tableinsert(r, format('addto currentpicture contour %s withcolor background;',v)) + end + else + for _,v in ipairs(q[2]) do + tableinsert(r, format('addto currentpicture contour %s;',v)) + end + for _,v in ipairs(q[1]) do + tableinsert(r, format('addto currentpicture contour %s withcolor background;',v)) + end + end + return format('image(%s)', tableconcat(r)) +end +if not table.tofile then require"lualibs-lpeg"; require"lualibs-table"; end +function luamplib.glyph (f, c) + local filename, subfont, instance, kind, shapedata + local fid = tonumber(f) or font.id(f) + if fid > 0 then + local fontdata = font.getfont(fid) or font.getcopy(fid) + filename, subfont, kind = fontdata.filename, fontdata.subfont, fontdata.format + instance = fontdata.specification and fontdata.specification.instance + filename = filename and filename:gsub("^harfloaded:","") + else + local name + f = f:match"^%s*(.+)%s*$" + name, subfont, instance = f:match"(.+)%((%d+)%)%[(.-)%]$" + if not name then + name, instance = f:match"(.+)%[(.-)%]$" -- SourceHanSansK-VF.otf[Heavy] + end + if not name then + name, subfont = f:match"(.+)%((%d+)%)$" -- Times.ttc(2) + end + name = name or f + subfont = (subfont or 0)+1 + instance = instance and instance:lower() + for _,ftype in ipairs{"opentype", "truetype"} do + filename = kpse.find_file(name, ftype.." fonts") + if filename then + kind = ftype; break + end + end + end + if kind ~= "opentype" and kind ~= "truetype" then + f = fid and fid > 0 and tex.fontname(fid) or f + if kpse.find_file(f, "tfm") then + return format("glyph %s of %q", tonumber(c) or format("%q",c), f) + else + return mperr"font not found" + end + end + local time = lfsattributes(filename,"modification") + local k = format("shapes_%s(%s)[%s]", filename, subfont or "", instance or "") + local h = format(string.rep('%02x', 256/8), string.byte(sha2.digest256(k), 1, -1)) + local newname = format("%s/%s.lua", cachedir or outputdir, h) + local newtime = lfsattributes(newname,"modification") or 0 + if time == newtime then + shapedata = require(newname) + end + if not shapedata then + shapedata = fonts and fonts.handlers.otf.readers.loadshapes(filename,subfont,instance) + if not shapedata then return mperr"loadshapes() failed. luaotfload not loaded?" end + table.tofile(newname, shapedata, "return") + lfstouch(newname, time, time) + end + local gid = tonumber(c) + if not gid then + local uni = utf8.codepoint(c) + for i,v in pairs(shapedata.glyphs) do + if c == v.name or uni == v.unicode then + gid = i; break + end + end + end + if not gid then return mperr"cannot get GID (glyph id)" end + local fac = 1000 / (shapedata.units or 1000) + local t = shapedata.glyphs[gid].segments + if not t then return "image(fill fullcircle scaled 0;)" end + for i,v in ipairs(t) do + if type(v) == "table" then + for ii,vv in ipairs(v) do + if type(vv) == "number" then + t[i][ii] = format("%.0f", vv * fac) + end + end + end + end + kind = shapedata.format or kind + return glyphimage(t, kind) +end + +% \end{macrocode} +% +% mpliboutlinetext : based on mkiv's font-mps.lua +% \begin{macrocode} +local rulefmt = "mplibpic[%i]:=image(addto currentpicture contour \z +unitsquare shifted - center unitsquare;) xscaled %f yscaled %f shifted (%f,%f);" +local outline_horz, outline_vert +function outline_vert (res, box, curr, xshift, yshift) + local b2u = box.dir == "LTL" + local dy = (b2u and -box.depth or box.height)/factor + local ody = dy + while curr do + if curr.id == node.id"rule" then + local wd, ht, dp = getrulemetric(box, curr, true) + local hd = ht + dp + if hd ~= 0 then + dy = dy + (b2u and dp or -ht) + if wd ~= 0 and curr.subtype == 0 then + res[#res+1] = rulefmt:format(#res+1, wd, hd, xshift+wd/2, yshift+dy+(ht-dp)/2) + end + dy = dy + (b2u and ht or -dp) + end + elseif curr.id == node.id"glue" then + local vwidth = node.effective_glue(curr,box)/factor + if curr.leader then + local curr, kind = curr.leader, curr.subtype + if curr.id == node.id"rule" then + local wd = getrulemetric(box, curr, true) + if wd ~= 0 then + local hd = vwidth + local dy = dy + (b2u and 0 or -hd) + if hd ~= 0 and curr.subtype == 0 then + res[#res+1] = rulefmt:format(#res+1, wd, hd, xshift+wd/2, yshift+dy+hd/2) + end + end + elseif curr.head then + local hd = (curr.height + curr.depth)/factor + if hd <= vwidth then + local dy, n, iy = dy, 0, 0 + if kind == 100 or kind == 103 then -- todo: gleaders + local ady = abs(ody - dy) + local ndy = math.ceil(ady / hd) * hd + local diff = ndy - ady + n = (vwidth-diff) // hd + dy = dy + (b2u and diff or -diff) + else + n = vwidth // hd + if kind == 101 then + local side = vwidth % hd / 2 + dy = dy + (b2u and side or -side) + elseif kind == 102 then + iy = vwidth % hd / (n+1) + dy = dy + (b2u and iy or -iy) + end + end + dy = dy + (b2u and curr.depth or -curr.height)/factor + hd = b2u and hd or -hd + iy = b2u and iy or -iy + local func = curr.id == node.id"hlist" and outline_horz or outline_vert + for i=1,n do + res = func(res, curr, curr.head, xshift+curr.shift/factor, yshift+dy) + dy = dy + hd + iy + end + end + end + end + dy = dy + (b2u and vwidth or -vwidth) + elseif curr.id == node.id"kern" then + dy = dy + curr.kern/factor * (b2u and 1 or -1) + elseif curr.id == node.id"vlist" then + dy = dy + (b2u and curr.depth or -curr.height)/factor + res = outline_vert(res, curr, curr.head, xshift+curr.shift/factor, yshift+dy) + dy = dy + (b2u and curr.height or -curr.depth)/factor + elseif curr.id == node.id"hlist" then + dy = dy + (b2u and curr.depth or -curr.height)/factor + res = outline_horz(res, curr, curr.head, xshift+curr.shift/factor, yshift+dy) + dy = dy + (b2u and curr.height or -curr.depth)/factor + end + curr = node.getnext(curr) + end + return res +end +function outline_horz (res, box, curr, xshift, yshift, discwd) + local r2l = box.dir == "TRT" + local dx = r2l and (discwd or box.width/factor) or 0 + local dirs = { { dir = r2l, dx = dx } } + while curr do + if curr.id == node.id"dir" then + local sign, dir = curr.dir:match"(.)(...)" + local level, newdir = curr.level, r2l + if sign == "+" then + newdir = dir == "TRT" + if r2l ~= newdir then + local n = node.getnext(curr) + while n do + if n.id == node.id"dir" and n.level+1 == level then break end + n = node.getnext(n) + end + n = n or node.tail(curr) + dx = dx + node.rangedimensions(box, curr, n)/factor * (newdir and 1 or -1) + end + dirs[level] = { dir = r2l, dx = dx } + else + local level = level + 1 + newdir = dirs[level].dir + if r2l ~= newdir then + dx = dirs[level].dx + end + end + r2l = newdir + elseif curr.char and curr.font and curr.font > 0 then + local ft = font.getfont(curr.font) or font.getcopy(curr.font) + local gid = ft.characters[curr.char].index or curr.char + local scale = ft.size / factor / 1000 + local slant = (ft.slant or 0)/1000 + local extend = (ft.extend or 1000)/1000 + local squeeze = (ft.squeeze or 1000)/1000 + local expand = 1 + (curr.expansion_factor or 0)/1000000 + local xscale = scale * extend * expand + local yscale = scale * squeeze + dx = dx - (r2l and curr.width/factor*expand or 0) + local xpos = dx + xshift + (curr.xoffset or 0)/factor + local ypos = yshift + (curr.yoffset or 0)/factor + local image + if ft.format == "opentype" or ft.format == "truetype" then + image = luamplib.glyph(curr.font, gid) + else + local name, scale = ft.name, 1 + local vf = font.read_vf(name, ft.size) + if vf and vf.characters[gid] then + local cmds = vf.characters[gid].commands or {} + for _,v in ipairs(cmds) do + if v[1] == "char" then + gid = v[2] + elseif v[1] == "font" and vf.fonts[v[2]] then + name = vf.fonts[v[2]].name + scale = vf.fonts[v[2]].size / ft.size + end + end + end + image = format("glyph %s of %q scaled %f", gid, name, scale) + end + res[#res+1] = format("mplibpic[%i]:=%s xscaled %f yscaled %f slanted %f shifted (%f,%f);", + #res+1, image, xscale, yscale, slant, xpos, ypos) + dx = dx + (r2l and 0 or curr.width/factor*expand) + elseif curr.replace then + local width = node.dimensions(curr.replace)/factor + dx = dx - (r2l and width or 0) + res = outline_horz(res, box, curr.replace, xshift+dx, yshift, width) + dx = dx + (r2l and 0 or width) + elseif curr.id == node.id"rule" then + local wd, ht, dp = getrulemetric(box, curr, true) + if wd ~= 0 then + local hd = ht + dp + dx = dx - (r2l and wd or 0) + if hd ~= 0 and curr.subtype == 0 then + res[#res+1] = rulefmt:format(#res+1, wd, hd, xshift+dx+wd/2, yshift+(ht-dp)/2) + end + dx = dx + (r2l and 0 or wd) + end + elseif curr.id == node.id"glue" then + local width = node.effective_glue(curr, box)/factor + dx = dx - (r2l and width or 0) + if curr.leader then + local curr, kind = curr.leader, curr.subtype + if curr.id == node.id"rule" then + local wd, ht, dp = getrulemetric(box, curr, true) + local hd = ht + dp + if hd ~= 0 then + wd = width + if wd ~= 0 and curr.subtype == 0 then + res[#res+1] = rulefmt:format(#res+1, wd, hd, xshift+dx+wd/2, yshift+(ht-dp)/2) + end + end + elseif curr.head then + local wd = curr.width/factor + if wd <= width then + local dx = r2l and dx+width or dx + local n, ix = 0, 0 + if kind == 100 or kind == 103 then -- todo: gleaders + local adx = abs(dx-dirs[1].dx) + local ndx = math.ceil(adx / wd) * wd + local diff = ndx - adx + n = (width-diff) // wd + dx = dx + (r2l and -diff-wd or diff) + else + n = width // wd + if kind == 101 then + local side = width % wd /2 + dx = dx + (r2l and -side-wd or side) + elseif kind == 102 then + ix = width % wd / (n+1) + dx = dx + (r2l and -ix-wd or ix) + end + end + wd = r2l and -wd or wd + ix = r2l and -ix or ix + local func = curr.id == node.id"hlist" and outline_horz or outline_vert + for i=1,n do + res = func(res, curr, curr.head, xshift+dx, yshift-curr.shift/factor) + dx = dx + wd + ix + end + end + end + end + dx = dx + (r2l and 0 or width) + elseif curr.id == node.id"kern" then + dx = dx + curr.kern/factor * (r2l and -1 or 1) + elseif curr.id == node.id"math" then + dx = dx + curr.surround/factor * (r2l and -1 or 1) + elseif curr.id == node.id"vlist" then + dx = dx - (r2l and curr.width/factor or 0) + res = outline_vert(res, curr, curr.head, xshift+dx, yshift-curr.shift/factor) + dx = dx + (r2l and 0 or curr.width/factor) + elseif curr.id == node.id"hlist" then + dx = dx - (r2l and curr.width/factor or 0) + res = outline_horz(res, curr, curr.head, xshift+dx, yshift-curr.shift/factor) + dx = dx + (r2l and 0 or curr.width/factor) + end + curr = node.getnext(curr) + end + return res +end +function luamplib.outlinetext (text) + local fmt = process_tex_text(text) + local id = tonumber(fmt:match"mplibtexboxid=(%d+):") + local box = texgetbox(id) + local res = outline_horz({ }, box, box.head, 0, 0) + if #res == 0 then res = { "mplibpic[1]:=image(fill fullcircle scaled 0;);" } end + local t = { } + for i=1, #res do + t[#t+1] = format("addto currentpicture also mplibpic[%i];", i) + end + return tableconcat(res) .. format("mplibpic[0]:=image(%s);", tableconcat(t)) +end + +% \end{macrocode} +% % Our MetaPost preambles % \begin{macrocode} -local mplibcodepreamble = [[ +luamplib.preambles = { + mplibcode = [[ texscriptmode := 2; def rawtextext (expr t) = runscript("luamplibtext{"&t&"}") enddef; def mplibcolor (expr t) = runscript("luamplibcolor{"&t&"}") enddef; @@ -1424,82 +2074,155 @@ if known context_mlib: (1-mfun_labxf@#-mfun_labyf@#)*llcorner p)) fi enddef; - def colordecimals primary c = - if cmykcolor c: - decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c - elseif rgbcolor c: - decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c - elseif string c: - colordecimals resolvedcolor(c) - else: - decimal c - fi - enddef; - def resolvedcolor(expr s) = - runscript("return luamplib.shadecolor('"& s &"')") - enddef; else: vardef textext@# (text t) = rawtextext (t) enddef; + def message expr t = + if string t: runscript("mp.report[=["&t&"]=]") else: errmessage "Not a string" fi + enddef; fi +def resolvedcolor(expr s) = + runscript("return luamplib.shadecolor('"& s &"')") +enddef; +def colordecimals primary c = + if cmykcolor c: + decimal cyanpart c & ":" & decimal magentapart c & ":" & + decimal yellowpart c & ":" & decimal blackpart c + elseif rgbcolor c: + decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c + elseif string c: + if known graphictextpic: c else: colordecimals resolvedcolor(c) fi + else: + decimal c + fi +enddef; def externalfigure primary filename = draw rawtextext("\includegraphics{"& filename &"}") enddef; def TEX = textext enddef; +def mplibtexcolor primary c = + runscript("return luamplib.gettexcolor('"& c &"')") +enddef; +def mplibrgbtexcolor primary c = + runscript("return luamplib.gettexcolor('"& c &"','rgb')") +enddef; def mplibgraphictext primary t = begingroup; mplibgraphictext_ (t) enddef; def mplibgraphictext_ (expr t) text rest = save fakebold, scale, fillcolor, drawcolor, withfillcolor, withdrawcolor, - fb, sc, fc, dc, fn, dn, tpic; - picture tpic; tpic := nullpicture; - numeric fb, sc; string fc, dc, fn, dn; - fb:=2; sc:=1; fc:="white"; dc:="black"; fn:=dn:="n"; + fb, fc, dc, graphictextpic; + picture graphictextpic; graphictextpic := nullpicture; + numeric fb; string fc, dc; fb:=2; fc:="white"; dc:="black"; + let scale = scaled; def fakebold primary c = hide(fb:=c;) enddef; - def scale primary c = hide(sc:=c;) enddef; - def fillcolor primary c = hide( - if string c: - runscript("return luamplib.outlinecolor('"& c &"','fill')") - else: - fn:="nn"; fc:=mpliboutlinecolor_(c); - fi - ) enddef; - def drawcolor primary c = hide( - if string c: - runscript("return luamplib.outlinecolor('"& c &"','draw')") - else: - dn:="nn"; dc:=mpliboutlinecolor_(c); - fi - ) enddef; + def fillcolor primary c = hide(fc:=colordecimals c;) enddef; + def drawcolor primary c = hide(dc:=colordecimals c;) enddef; let withfillcolor = fillcolor; let withdrawcolor = drawcolor; - addto tpic doublepath origin rest; tpic:=nullpicture; + addto graphictextpic doublepath origin rest; graphictextpic:=nullpicture; def fakebold primary c = enddef; - def scale primary c = enddef; - def fillcolor primary c = enddef; - def drawcolor primary c = enddef; + let fillcolor = fakebold; let drawcolor = fakebold; let withfillcolor = fillcolor; let withdrawcolor = drawcolor; - image(draw rawtextext( - "{\addfontfeature{FakeBold="& decimal fb &",Scale="& decimal sc & - "}\csname color_fill:"& fn &"\endcsname{"& fc & - "}\csname color_stroke:"& dn &"\endcsname{"& dc & - "}"& t &"}") rest;) + image(draw runscript("return luamplib.graphictext([===["&t&"]===]," + & decimal fb &",'"& fc &"','"& dc &"')") rest;) endgroup; enddef; -def mpliboutlinecolor_ (expr c) = - if color c: - "rgb}{" & decimal redpart c & "," & decimal greenpart c - & "," & decimal bluepart c - elseif cmykcolor c: - "cmyk}{" & decimal cyanpart c & "," & decimal magentapart c - & "," & decimal yellowpart c & "," & decimal blackpart c - else: - "gray}{" & decimal c - fi +def mplibglyph expr c of f = + runscript ( + "return luamplib.glyph('" + & if numeric f: decimal fi f + & "','" + & if numeric c: decimal fi c + & "')" + ) enddef; -]] -luamplib.mplibcodepreamble = mplibcodepreamble - -local legacyverbatimtexpreamble = [[ +def mplibdrawglyph expr g = + draw image( + save i; numeric i; i:=0; + for item within g: + i := i+1; + fill pathpart item + if i < length g: withpostscript "collect" fi; + endfor + ) +enddef; +def mplib_do_outline_text_set_b (text f) (text d) text r = + def mplib_do_outline_options_f = f enddef; + def mplib_do_outline_options_d = d enddef; + def mplib_do_outline_options_r = r enddef; +enddef; +def mplib_do_outline_text_set_f (text f) text r = + def mplib_do_outline_options_f = f enddef; + def mplib_do_outline_options_r = r enddef; +enddef; +def mplib_do_outline_text_set_d (text d) text r = + def mplib_do_outline_options_d = d enddef; + def mplib_do_outline_options_r = r enddef; +enddef; +def mplib_do_outline_text_set_r (text d) (text f) text r = + def mplib_do_outline_options_d = d enddef; + def mplib_do_outline_options_f = f enddef; + def mplib_do_outline_options_r = r enddef; +enddef; +def mplib_do_outline_text_set_n text r = + def mplib_do_outline_options_r = r enddef; +enddef; +def mplib_do_outline_text_set_p = enddef; +def mplib_fill_outline_text (expr p) = + i:=0; + for item within p: + i:=i+1; + addto currentpicture contour pathpart item + if i < length p: withpostscript "collect"; fi + endfor + mplib_do_outline_options_f; +enddef; +def mplib_draw_outline_text (expr p) = + i:=0; + for item within p: + i:=i+1; + addto currentpicture doublepath pathpart item + if i < length p: withpostscript "collect"; fi + endfor + mplib_do_outline_options_d; +enddef; +vardef mpliboutlinetext@# (expr t) text rest = + save kind; string kind; kind := str @#; + save mplibpic, i; picture mplibpic[]; numeric i; + def mplib_do_outline_options_d = enddef; + def mplib_do_outline_options_f = enddef; + def mplib_do_outline_options_r = enddef; + runscript("return luamplib.outlinetext[===["&t&"]===]"); + image ( addto currentpicture also image ( + if kind = "f": + mplib_do_outline_text_set_f rest; + def mplib_do_outline_options_d = withpen pencircle scaled 0 enddef; + mplib_fill_outline_text (mplibpic0); + elseif kind = "d": + mplib_do_outline_text_set_d rest; + mplib_draw_outline_text (mplibpic0); + elseif kind = "b": + mplib_do_outline_text_set_b rest; + mplib_fill_outline_text (mplibpic0); + mplib_draw_outline_text (mplibpic0); + elseif kind = "u": + mplib_do_outline_text_set_f rest; + mplib_fill_outline_text (mplibpic0); + elseif kind = "r": + mplib_do_outline_text_set_r rest; + mplib_draw_outline_text (mplibpic0); + mplib_fill_outline_text (mplibpic0); + elseif kind = "p": + mplib_do_outline_text_set_p; + mplib_draw_outline_text (mplibpic0); + else: + mplib_do_outline_text_set_n rest; + mplib_fill_outline_text (mplibpic0); + fi; + ) mplib_do_outline_options_r; ) +enddef ; +]], + legacyverbatimtex = [[ def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef; def normalVerbatimTeX (text t) = runscript("luamplibinfig{"&t&"}") enddef; let VerbatimTeX = specialVerbatimTeX; @@ -1509,10 +2232,8 @@ extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;"& "runscript(" &ditto& "if luamplib.in_the_fig then luamplib.figid=luamplib.figid+1 end "& "luamplib.in_the_fig=false" &ditto& ");"; -]] -luamplib.legacyverbatimtexpreamble = legacyverbatimtexpreamble - -local textextlabelpreamble = [[ +]], + textextlabel = [[ primarydef s infont f = rawtextext(s) enddef; def fontsize expr f = begingroup @@ -1521,8 +2242,8 @@ def fontsize expr f = if size = 0: 10pt else: size fi endgroup enddef; -]] -luamplib.textextlabelpreamble = textextlabelpreamble +]], +} % \end{macrocode} % @@ -1556,23 +2277,21 @@ local function unprotect_expansion (str) end end -luamplib.everymplib = { [""] = "" } -luamplib.everyendmplib = { [""] = "" } +luamplib.everymplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end }) +luamplib.everyendmplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end }) -local function process_mplibcode (data, instance) - instancename = instance - texboxes.locals, texboxes.localid = {}, 4096 +function luamplib.process_mplibcode (data, instancename) + texboxes.localid = 4096 % \end{macrocode} -% -% This is needed for legacy behavior regarding |verbatimtex| +% This is needed for legacy behavior % \begin{macrocode} - legacy_mplibcode_reset() + if luamplib.legacy_verbatimtex then + luamplib.figid, tex_code_pre_mplib = 1, {} + end - local everymplib = luamplib.everymplib[instancename] or - luamplib.everymplib[""] - local everyendmplib = luamplib.everyendmplib[instancename] or - luamplib.everyendmplib[""] + local everymplib = luamplib.everymplib[instancename] + local everyendmplib = luamplib.everyendmplib[instancename] data = format("\n%s\n%s\n%s\n",everymplib, data, everyendmplib) :gsub("\r","\n") @@ -1586,7 +2305,6 @@ local function process_mplibcode (data, instance) :gsub(btex_etex, "btex %1 etex ") :gsub(verbatimtex_etex, "verbatimtex %1 etex;") % \end{macrocode} -% % If not |mplibverbatim|, expand |mplibcode| data, % so that users can use \TeX\ codes in it. % It has turned out that no comment sign is allowed. @@ -1605,7 +2323,6 @@ local function process_mplibcode (data, instance) run_tex_code(format("\\mplibtmptoks\\expandafter{\\expanded{%s}}",data)) data = texgettoks"mplibtmptoks" % \end{macrocode} -% % Next line to address issue \#55 % \begin{macrocode} :gsub("##", "#") @@ -1618,9 +2335,8 @@ local function process_mplibcode (data, instance) end) end - process(data) + process(data, instancename) end -luamplib.process_mplibcode = process_mplibcode % \end{macrocode} % @@ -1655,11 +2371,10 @@ local function getobjects(result,figure,f) return figure:objects() end -local function convert(result, flusher) +function luamplib.convert (result, flusher) luamplib.flush(result, flusher) return true -- done end -luamplib.convert = convert local figcontents = { post = { } } local function put2output(a,...) @@ -1820,19 +2535,42 @@ end % \end{macrocode} % -% Colors and Transparency +% Colors +% \begin{macrocode} +local prev_override_color +local function do_preobj_CR(object,prescript) + local override = prescript and prescript.mpliboverridecolor + if override then + if pdfmode then + pdf_literalcode(override) + override = nil + else + put2output("\\special{%s}",override) + prev_override_color = override + end + else + local cs = object.color + if cs and #cs > 0 then + pdf_literalcode(luamplib.colorconverter(cs)) + prev_override_color = nil + elseif not pdfmode then + override = prev_override_color + if override then + put2output("\\special{%s}",override) + end + end + end + return override +end + +% \end{macrocode} +% +% For transparency and shading % \begin{macrocode} local pdfmanagement = is_defined'pdfmanagement_add:nnn' local pdfobjs, pdfetcs = {}, {} pdfetcs.pgfextgs = "pgf@sys@addpdfresource@extgs@plain" -if pdfmode then - pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end - pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end -else - texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}") -end - local function update_pdfobjs (os) local on = pdfobjs[os] if on then @@ -1849,9 +2587,41 @@ local function update_pdfobjs (os) return on,true end +if pdfmode then + pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end + pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end + pdfetcs.initialize_resources = function (name) + local tabname = format("%s_res",name) + pdfetcs[tabname] = { } + if luatexbase.callbacktypes.finish_pdffile then -- ltluatex + local obj = pdf.reserveobj() + pdfetcs.setpageres(format("%s/%s %i 0 R", pdfetcs.getpageres() or "", name, obj)) + luatexbase.add_to_callback("finish_pdffile", function() + pdf.immediateobj(obj, format("<<%s>>", tableconcat(pdfetcs[tabname]))) + end, + format("luamplib.%s.finish_pdffile",name)) + end + end + pdfetcs.fallback_update_resources = function (name, res) + if luatexbase.callbacktypes.finish_pdffile then + local t = pdfetcs[format("%s_res",name)] + t[#t+1] = res + else + local tpr, n = pdfetcs.getpageres() or "", 0 + tpr, n = tpr:gsub(format("/%s<<",name), "%1"..res) + if n == 0 then + tpr = format("%s/%s<<%s>>", tpr, name, res) + end + pdfetcs.setpageres(tpr) + end + end +else + texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}") +end + % \end{macrocode} % -% transparency +% Transparency % \begin{macrocode} local transparancy_modes = { [0] = "Normal", "Normal", "Multiply", "Screen", "Overlay", @@ -1861,75 +2631,42 @@ local transparancy_modes = { [0] = "Normal", "Compatible", } -local function opacity_initialize () - pdfetcs.opacity_res = {} - if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex - local extgstate_obj = pdf.reserveobj() - pdfetcs.setpageres(format("%s/ExtGState %i 0 R",pdfetcs.getpageres() or "",extgstate_obj)) - luatexbase.add_to_callback("finish_pdffile", function() - pdf.immediateobj(extgstate_obj, format("<<%s>>",tableconcat(pdfetcs.opacity_res))) - end, "luamplib.opacity.finish_pdffile") - end -end - local function update_tr_res(mode,opaq) if pdfetcs.pgfloaded == nil then pdfetcs.pgfloaded = is_defined(pdfetcs.pgfextgs) - if not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP@list" then - opacity_initialize() + if pdfmode and not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP@list" then + pdfetcs.initialize_resources"ExtGState" end end local os = format("<</BM /%s/ca %.3f/CA %.3f/AIS false>>",mode,opaq,opaq) local on, new = update_pdfobjs(os) - if new then - if pdfmode then - if pdfmanagement then - texsprint(ccexplat,{ - [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]], - format("{MPlibTr%s}{%s 0 R}", on, on), + if not new then return on end + local key = format("MPlibTr%s", on) + local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on) + if pdfmanagement then + texsprint(ccexplat, + format("\\pdfmanagement_add:nnn{Page/Resources/ExtGState}{%s}{%s}", key, val)) + else + local tr = format("/%s %s", key, val) + if pdfetcs.pgfloaded then + texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr)) + elseif pdfmode then + if is_defined"TRP@list" then + texsprint(catat11,{ + [[\if@filesw\immediate\write\@auxout{]], + [[\string\g@addto@macro\string\TRP@list{]], + tr, + [[}}\fi]], }) - else - local tr = format("/MPlibTr%s %s 0 R",on,on) - if pdfetcs.pgfloaded then - texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr)) - elseif is_defined"TRP@list" then - texsprint(catat11,{ - [[\if@filesw\immediate\write\@auxout{]], - [[\string\g@addto@macro\string\TRP@list{]], - tr, - [[}}\fi]], - }) - if not get_macro"TRP@list":find(tr) then - texsprint(catat11,[[\global\TRP@reruntrue]]) - end - else - if luatexbase.callbacktypes.finish_pdffile then - pdfetcs.opacity_res[#pdfetcs.opacity_res+1] = tr - else - local tpr, n = pdfetcs.getpageres() or "", 0 - tpr, n = tpr:gsub("/ExtGState<<", "%1"..tr) - if n == 0 then - tpr = format("%s/ExtGState<<%s>>", tpr, tr) - end - pdfetcs.setpageres(tpr) - end + if not get_macro"TRP@list":find(tr) then + texsprint(catat11,[[\global\TRP@reruntrue]]) end - end - else - if pdfmanagement then - texsprint(ccexplat,{ - [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]], - format("{MPlibTr%s}{@mplibpdfobj%s}", on, on), - }) else - local tr = format("/MPlibTr%s @mplibpdfobj%s",on,on) - if pdfetcs.pgfloaded then - texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr)) - else - texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr)) - texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}" - end + pdfetcs.fallback_update_resources("ExtGState", tr) end + else + texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr)) + texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}" end end return on @@ -1937,65 +2674,24 @@ end local function do_preobj_TR(prescript) local opaq = prescript and prescript.tr_transparency - local tron_no, troff_no + local tron_no if opaq then local mode = prescript.tr_alternative or 1 mode = transparancy_modes[tonumber(mode)] - troff_no = update_tr_res("Normal", 1) - tron_no = update_tr_res(mode, opaq) + tron_no = update_tr_res(mode, opaq) + start_pdf_code() pdf_literalcode("/MPlibTr%i gs",tron_no) end - return troff_no -end - -% \end{macrocode} -% -% color -% \begin{macrocode} -local prev_override_color -local function do_preobj_CR(object,prescript) - local override = prescript and prescript.MPlibOverrideColor - if override then - if pdfmode then - pdf_literalcode(override) - override = nil - else - put2output("\\special{%s}",override) - prev_override_color = override - end - else - local cs = object.color - if cs and #cs > 0 then - pdf_literalcode(luamplib.colorconverter(cs)) - prev_override_color = nil - elseif not pdfmode then - override = prev_override_color - if override then - put2output("\\special{%s}",override) - end - end - end - return override + return tron_no end % \end{macrocode} % % Shading with |metafun| format. % \begin{macrocode} -local function shading_initialize () - pdfetcs.shading_res = {} - if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex - local shading_obj = pdf.reserveobj() - pdfetcs.setpageres(format("%s/Shading %i 0 R",pdfetcs.getpageres() or "",shading_obj)) - luatexbase.add_to_callback("finish_pdffile", function() - pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(pdfetcs.shading_res))) - end, "luamplib.shading.finish_pdffile") - end -end - local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions) - if not pdfmanagement and not pdfetcs.shading_res then - shading_initialize() + if pdfmode and not pdfmanagement and not pdfetcs.Shading_res then + pdfetcs.initialize_resources"Shading" end local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>" if steps > 1 then @@ -2028,42 +2724,18 @@ local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,st "/Extend [true true]/AntiAlias true>>", } local on, new = update_pdfobjs(os) - if pdfmode then - if new then - if pdfmanagement then - texsprint(ccexplat,{ - [[\pdfmanagement_add:nnn{Page/Resources/Shading}]], - format("{MPlibSh%s}{%s 0 R}", on, on), - }) - else - local res = format("/MPlibSh%s %s 0 R", on, on) - if luatexbase.callbacktypes.finish_pdffile then - pdfetcs.shading_res[#pdfetcs.shading_res+1] = res - else - local pageres = pdfetcs.getpageres() or "" - if not pageres:find("/Shading<<.*>>") then - pageres = pageres.."/Shading<<>>" - end - pageres = pageres:gsub("/Shading<<","%1"..res) - pdfetcs.setpageres(pageres) - end - end - end + if not new then return on end + local key = format("MPlibSh%s", on) + local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on) + if pdfmanagement then + texsprint(ccexplat, + format("\\pdfmanagement_add:nnn{Page/Resources/Shading}{%s}{%s}", key, val)) else - if pdfmanagement then - if new then - texsprint(ccexplat,{ - [[\pdfmanagement_add:nnn{Page/Resources/Shading}]], - format("{MPlibSh%s}{@mplibpdfobj%s}", on, on), - }) - end + local res = format("/%s %s", key, val) + if pdfmode then + pdfetcs.fallback_update_resources("Shading", res) else - if new then - texsprint{ - "\\special{pdf:put @MPlibSh", - format("<</MPlibSh%s @mplibpdfobj%s>>}",on, on), - } - end + texsprint(format("\\special{pdf:put @MPlibSh<<%s>>}", res)) texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}" end end @@ -2082,7 +2754,18 @@ local function color_normalize(ca,cb) end end -pdfetcs.clrspcs = { } +pdfetcs.clrspcs = setmetatable({ }, { __index = function(t,names) + run_tex_code({ + [[\color_model_new:nnn]], + format("{mplibcolorspace_%s}", names:gsub(",","_")), + format("{DeviceN}{names={%s}}", names), + [[\edef\mplib_@tempa{\pdf_object_ref_last:}]], + }, ccexplat) + local colorspace = get_macro'mplib_@tempa' + t[names] = colorspace + return colorspace +end }) + local function do_preobj_SH(object,prescript) local shade_no local sh_type = prescript and prescript.sh_type @@ -2145,7 +2828,7 @@ local function do_preobj_SH(object,prescript) local t = { } for j=1,names[name] do t[#t+1] = 0 end t[#t+1] = value - table.insert(#ca == #cb and ca or cb, t) + tableinsert(#ca == #cb and ca or cb, t) end end for _,t in ipairs{ca,cb} do @@ -2156,20 +2839,7 @@ local function do_preobj_SH(object,prescript) if #names == 1 then colorspace = objref else - local name = tableconcat(names,"-") - local obj = pdfetcs.clrspcs[name] - if obj then - colorspace = obj - else - run_tex_code({ - [[\color_model_new:nnn]], - format("{mplibcolorspace_%s}", name), - format("{DeviceN}{names={%s}}", tableconcat(names,",")), - [[\edef\mplib_@tempa{\pdf_object_ref_last:}]], - }, ccexplat) - colorspace = get_macro'mplib_@tempa' - pdfetcs.clrspcs[name] = colorspace - end + colorspace = pdfetcs.clrspcs[ tableconcat(names,",") ] end else local model = 0 @@ -2213,25 +2883,9 @@ end % \end{macrocode} % -% color stuffs at the end of object -% \begin{macrocode} -local function do_postobj_color(tr,over,sh) - if sh then - pdf_literalcode("W n /MPlibSh%s sh Q",sh) - end - if over then - put2output"\\special{pdf:ec}" - end - if tr then - pdf_literalcode("/MPlibTr%i gs",tr) - end -end - -% \end{macrocode} -% % Finally, flush figures by inserting PDF literals. % \begin{macrocode} -local function flush(result,flusher) +function luamplib.flush (result,flusher) if result then local figures = result.fig if figures then @@ -2245,7 +2899,6 @@ local function flush(result,flusher) local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack if urx < llx then % \end{macrocode} -% % luamplib silently ignores this invalid figure for those % that do not contain |beginfig ... endfig|. (issue \#70) % Original code of ConTeXt general was: @@ -2257,9 +2910,7 @@ local function flush(result,flusher) % \begin{macrocode} else % \end{macrocode} -% For collecting pdf materials and -% for legacy behavior. Insert `pre-fig' \TeX\ code here, and -% prepare a table for `in-fig' codes. +% For legacy behavior, insert `pre-fig' \TeX\ code here. % \begin{macrocode} if tex_code_pre_mplib[f] then put2output(tex_code_pre_mplib[f]) @@ -2273,15 +2924,13 @@ local function flush(result,flusher) local object = objects[o] local objecttype = object.type % \end{macrocode} -% -% The following 7 lines are part of |btex...etex| patch. +% The following 6 lines are part of |btex...etex| patch. % Again, colors are processed at this stage. % \begin{macrocode} local prescript = object.prescript prescript = prescript and script2table(prescript) -- prescript is now a table - local tr_opaq = do_preobj_TR(prescript) - local cr_over = do_preobj_CR(object,prescript) - local shade_no = do_preobj_SH(object,prescript) + local cr_over = do_preobj_CR(object,prescript) -- color + local tr_opaq = do_preobj_TR(prescript) -- opacity if prescript and prescript.mplibtexboxid then put_tex_boxes(object,prescript) elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip @@ -2295,7 +2944,6 @@ local function flush(result,flusher) miterlimit, linecap, linejoin, dashed = -1, -1, -1, false elseif objecttype == "special" then % \end{macrocode} -% % Collect \TeX\ codes that will be executed after flushing. % Legacy behavior. % \begin{macrocode} @@ -2332,6 +2980,11 @@ local function flush(result,flusher) savedhtap[#savedhtap+1] = object.htap or false end else +% \end{macrocode} +% Removed from ConTeXt general: color stuff. +% Added instead : shading stuff +% \begin{macrocode} + local shade_no = do_preobj_SH(object,prescript) -- shading local ml = object.miterlimit if ml and ml ~= miterlimit then miterlimit = ml @@ -2394,8 +3047,7 @@ local function flush(result,flusher) flushnormalpath(path,open) end % \end{macrocode} -% -% Change from ConTeXt general: there was color stuffs. +% Shading seems to conflict with these ops % \begin{macrocode} if not shade_no then -- conflict with shading if objecttype == "fill" then @@ -2447,18 +3099,27 @@ local function flush(result,flusher) stop_pdf_code() end end - end - end % \end{macrocode} -% -% Added to ConTeXt general: color stuff. -% And execute legacy |verbatimtex| code. +% Added to ConTeXt general: post-object color and shading stuff. % \begin{macrocode} - do_postobj_color(tr_opaq,cr_over,shade_no) + if shade_no then -- shading + pdf_literalcode("W n /MPlibSh%s sh Q",shade_no) + end + end + end + if tr_opaq then -- opacity + stop_pdf_code() + end + if cr_over then -- color + put2output"\\special{pdf:ec}" + end end end stop_pdf_code() pdf_stopfigure() +% \end{macrocode} +% output collected materials to PDF, plus legacy |verbatimtex| code. +% \begin{macrocode} for _,v in ipairs(figcontents) do if type(v) == "table" then texsprint"\\mplibtoPDF{"; texsprint(v[1], v[2]); texsprint"}" @@ -2473,9 +3134,8 @@ local function flush(result,flusher) end end end -luamplib.flush = flush -local function colorconverter(cr) +function luamplib.colorconverter (cr) local n = #cr if n == 4 then local c, m, y, k = cr[1], cr[2], cr[3], cr[4] @@ -2488,7 +3148,6 @@ local function colorconverter(cr) return format("%.3f g %.3f G",s,s), "0 g 0 G" end end -luamplib.colorconverter = colorconverter % \end{macrocode} % % \iffalse @@ -2511,7 +3170,7 @@ luamplib.colorconverter = colorconverter \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luamplib} - [2024/04/25 v2.28.2 mplib package for LuaTeX] + [2024/05/24 v2.31.1 mplib package for LuaTeX] \ifx\newluafunction\@undefined \input ltluatex \fi @@ -2549,12 +3208,12 @@ luamplib.colorconverter = colorconverter \ifcsname PackageInfo\endcsname \PackageInfo{luamplib}{only dvipdfmx is supported currently} \else - \write128{luamplib Info: only dvipdfmx is supported currently} + \immediate\write-1{luamplib Info: only dvipdfmx is supported currently} \fi \fi % \end{macrocode} % -% Make |mplibcode| typesetted always in horizontal mode. +% To make |mplibcode| typeset always in horizontal mode. % \begin{macrocode} \def\mplibforcehmode{\let\prependtomplibbox\leavevmode} \def\mplibnoforcehmode{\let\prependtomplibbox\relax} @@ -2575,47 +3234,122 @@ luamplib.colorconverter = colorconverter \def\mplibputtextbox#1{\vbox to 0pt{\vss\hbox to 0pt{\raise\dp#1\copy#1\hss}}} % \end{macrocode} % -% The Plain-specific stuff. +% simple way to use mplib: +% |\mpfig draw fullcircle scaled 10; \endmpfig| % \begin{macrocode} -\unless\ifcsname ver@luamplib.sty\endcsname -\def\mplibcode{% +\def\mpfiginstancename{@mpfig} +\protected\def\mpfig{% \begingroup + \futurelet\nexttok\mplibmpfigbranch +} +\def\mplibmpfigbranch{% + \ifx *\nexttok + \expandafter\mplibprempfig + \else + \expandafter\mplibmainmpfig + \fi +} +\def\mplibmainmpfig{% \begingroup \mplibsetupcatcodes - \mplibdocode + \mplibdomainmpfig } -\long\def\mplibdocode#1\endmplibcode{% +\long\def\mplibdomainmpfig#1\endmpfig{% \endgroup - \directlua{luamplib.process_mplibcode([===[\unexpanded{#1}]===],"")}% + \directlua{ + local legacy = luamplib.legacy_verbatimtex + local everympfig = luamplib.everymplib["\mpfiginstancename"] or "" + local everyendmpfig = luamplib.everyendmplib["\mpfiginstancename"] or "" + luamplib.legacy_verbatimtex = false + luamplib.everymplib["\mpfiginstancename"] = "" + luamplib.everyendmplib["\mpfiginstancename"] = "" + luamplib.process_mplibcode( + "beginfig(0) "..everympfig.." "..[===[\unexpanded{#1}]===].." "..everyendmpfig.." endfig;", + "\mpfiginstancename") + luamplib.legacy_verbatimtex = legacy + luamplib.everymplib["\mpfiginstancename"] = everympfig + luamplib.everyendmplib["\mpfiginstancename"] = everyendmpfig + }% \endgroup } -\else -% \end{macrocode} -% -% The \LaTeX-specific part: a new environment. -% \begin{macrocode} -\newenvironment{mplibcode}[1][]{% - \global\def\currentmpinstancename{#1}% - \mplibtmptoks{}\ltxdomplibcode -}{} -\def\ltxdomplibcode{% +\def\mplibprempfig#1{% \begingroup \mplibsetupcatcodes - \ltxdomplibcodeindeed + \mplibdoprempfig } -\def\mplib@mplibcode{mplibcode} -\long\def\ltxdomplibcodeindeed#1\end#2{% +\long\def\mplibdoprempfig#1\endmpfig{% + \endgroup + \directlua{ + local legacy = luamplib.legacy_verbatimtex + local everympfig = luamplib.everymplib["\mpfiginstancename"] + local everyendmpfig = luamplib.everyendmplib["\mpfiginstancename"] + luamplib.legacy_verbatimtex = false + luamplib.everymplib["\mpfiginstancename"] = "" + luamplib.everyendmplib["\mpfiginstancename"] = "" + luamplib.process_mplibcode([===[\unexpanded{#1}]===],"\mpfiginstancename") + luamplib.legacy_verbatimtex = legacy + luamplib.everymplib["\mpfiginstancename"] = everympfig + luamplib.everyendmplib["\mpfiginstancename"] = everyendmpfig + }% \endgroup - \mplibtmptoks\expandafter{\the\mplibtmptoks#1}% - \def\mplibtemp@a{#2}% - \ifx\mplib@mplibcode\mplibtemp@a - \directlua{luamplib.process_mplibcode([===[\the\mplibtmptoks]===],"\currentmpinstancename")}% - \end{mplibcode}% - \else - \mplibtmptoks\expandafter{\the\mplibtmptoks\end{#2}}% - \expandafter\ltxdomplibcode - \fi } +\protected\def\endmpfig{endmpfig} +% \end{macrocode} +% +% The Plain-specific stuff. +% \begin{macrocode} +\unless\ifcsname ver@luamplib.sty\endcsname + \def\mplibcodegetinstancename[#1]{\gdef\currentmpinstancename{#1}\mplibcodeindeed} + \protected\def\mplibcode{% + \begingroup + \futurelet\nexttok\mplibcodebranch + } + \def\mplibcodebranch{% + \ifx [\nexttok + \expandafter\mplibcodegetinstancename + \else + \global\let\currentmpinstancename\empty + \expandafter\mplibcodeindeed + \fi + } + \def\mplibcodeindeed{% + \begingroup + \mplibsetupcatcodes + \mplibdocode + } + \long\def\mplibdocode#1\endmplibcode{% + \endgroup + \directlua{luamplib.process_mplibcode([===[\unexpanded{#1}]===],"\currentmpinstancename")}% + \endgroup + } + \protected\def\endmplibcode{endmplibcode} +\else +% \end{macrocode} +% +% The \LaTeX-specific part: a new environment. +% \begin{macrocode} + \newenvironment{mplibcode}[1][]{% + \global\def\currentmpinstancename{#1}% + \mplibtmptoks{}\ltxdomplibcode + }{} + \def\ltxdomplibcode{% + \begingroup + \mplibsetupcatcodes + \ltxdomplibcodeindeed + } + \def\mplib@mplibcode{mplibcode} + \long\def\ltxdomplibcodeindeed#1\end#2{% + \endgroup + \mplibtmptoks\expandafter{\the\mplibtmptoks#1}% + \def\mplibtemp@a{#2}% + \ifx\mplib@mplibcode\mplibtemp@a + \directlua{luamplib.process_mplibcode([===[\the\mplibtmptoks]===],"\currentmpinstancename")}% + \end{mplibcode}% + \else + \mplibtmptoks\expandafter{\the\mplibtmptoks\end{#2}}% + \expandafter\ltxdomplibcode + \fi + } \fi % \end{macrocode} % @@ -2652,17 +3386,17 @@ luamplib.colorconverter = colorconverter % |luamplib.every(end)mplib| tables % % \begin{macrocode} -\protected\def\everymplib{% - \begingroup - \mplibsetupcatcodes - \mplibdoeverymplib -} -\protected\def\everyendmplib{% - \begingroup - \mplibsetupcatcodes - \mplibdoeveryendmplib -} \ifcsname ver@luamplib.sty\endcsname + \protected\def\everymplib{% + \begingroup + \mplibsetupcatcodes + \mplibdoeverymplib + } + \protected\def\everyendmplib{% + \begingroup + \mplibsetupcatcodes + \mplibdoeveryendmplib + } \newcommand\mplibdoeverymplib[2][]{% \endgroup \directlua{ @@ -2676,16 +3410,29 @@ luamplib.colorconverter = colorconverter }% } \else + \def\mplibgetinstancename[#1]{\def\currentmpinstancename{#1}} + \protected\def\everymplib#1#{% + \ifx\empty#1\empty \mplibgetinstancename[]\else \mplibgetinstancename#1\fi + \begingroup + \mplibsetupcatcodes + \mplibdoeverymplib + } \long\def\mplibdoeverymplib#1{% \endgroup \directlua{ - luamplib.everymplib[""] = [===[\unexpanded{#1}]===] + luamplib.everymplib["\currentmpinstancename"] = [===[\unexpanded{#1}]===] }% } + \protected\def\everyendmplib#1#{% + \ifx\empty#1\empty \mplibgetinstancename[]\else \mplibgetinstancename#1\fi + \begingroup + \mplibsetupcatcodes + \mplibdoeveryendmplib + } \long\def\mplibdoeveryendmplib#1{% \endgroup \directlua{ - luamplib.everyendmplib[""] = [===[\unexpanded{#1}]===] + luamplib.everyendmplib["\currentmpinstancename"] = [===[\unexpanded{#1}]===] }% } \fi diff --git a/macros/luatex/generic/luamplib/luamplib.pdf b/macros/luatex/generic/luamplib/luamplib.pdf Binary files differindex 6d410a4c26..9db810d360 100644 --- a/macros/luatex/generic/luamplib/luamplib.pdf +++ b/macros/luatex/generic/luamplib/luamplib.pdf diff --git a/macros/luatex/generic/luamplib/test-luamplib-latex.tex b/macros/luatex/generic/luamplib/test-luamplib-latex.tex index a077f67736..fd5cb6fe00 100644 --- a/macros/luatex/generic/luamplib/test-luamplib-latex.tex +++ b/macros/luatex/generic/luamplib/test-luamplib-latex.tex @@ -1,5 +1,9 @@ %\DocumentMetadata{ uncompress } -\documentclass{article} +\ifnum\outputmode > 0 + \documentclass{article} +\else + \documentclass[dvipdfmx]{article} +\fi \usepackage{fontspec} \setmainfont{latin modern roman} \usepackage{luamplib} @@ -171,15 +175,16 @@ diameter:\Dia bp.% \par \begin{mplibcode} beginfig(1) -draw mplibgraphictext "\bfseries Funny" - fakebold 2 scale 2 % fontspec options - drawcolor "blue" fillcolor "red!50" % l3color expressions - scaled 2 rotated 30 ; + draw mplibgraphictext "\bfseries Funny$\sqrt{2}$" + fakebold 2 % fontspec option + drawcolor blue fillcolor "red!50" % l3color expression + scaled 3 rotated 30 ; picture p; p:=mplibgraphictext "\bfseries\itshape xyz"; draw p scaled 3 shifted (40,0); endfig; \end{mplibcode}% +\par \mplibsetformat{metafun}% \begin{mplibcode} beginfig(1) @@ -197,6 +202,36 @@ fill unitsquare xyscaled (\mpdim\textwidth,1cm) ; endfig; \end{mplibcode}% +\leavevmode +\mpfig +picture Q, u, e; +Q := mplibglyph "Q" of "texgyrepagella-bolditalic.otf" scaled .1; +u := mplibglyph "u" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner Q; +e := mplibglyph "e" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner u; +i:=0; +totallen := length Q + length u + length e; +for pic=Q, u, e: + for item within pic: + i:=i+1; + fill pathpart item + if i < totallen: withpostscript "collect"; fi + endfor +endfor + withshademethod "linear" + withshadedirection (0.5,2.5) + withshadecolors (.7red,.7yellow) + ; +\endmpfig +\everymplib[@mpfig]{ drawoptions(withcolor mplibrgbtexcolor "olive"); }% +\mpfig* input boxes \endmpfig +\mpfig circleit.a(btex\tracingcommands0 Box 1 etex); drawboxed(a); \endmpfig +\def\mpfiginstancename{mympfig}% +\mpfig +draw mpliboutlinetext.b ("$\sqrt{2+\alpha}$") + (withcolor .6[red,white]) + (withpen pencircle scaled .2 withcolor red) + scaled 4 ; +\endmpfig \tracingcommands0 \vskip 2\baselineskip diff --git a/macros/luatex/generic/luamplib/test-luamplib-plain.tex b/macros/luatex/generic/luamplib/test-luamplib-plain.tex index 20773b280f..61ea9e8ae7 100644 --- a/macros/luatex/generic/luamplib/test-luamplib-plain.tex +++ b/macros/luatex/generic/luamplib/test-luamplib-plain.tex @@ -1,6 +1,7 @@ +\input luaotfload.sty \input miniltx \input color -\definecolor{orange}{rgb}{1,0.5,0} +\definecolor{orange}{cmyk}{0,.5,1,0} \input luamplib.sty \mpliblegacybehavior{true}% \everymplib{ beginfig(0); }\everyendmplib{ endfig; } @@ -163,4 +164,123 @@ diameter:\Dia bp.% rotatedlabel.top(textext("Rotated!"), origin, 45); endfig; \endmplibcode +\par +\mplibcode +beginfig(1) % in dvi mode, not work for type1 font +draw mplibgraphictext "\bf Funny$\sqrt{2}$" + fakebold 2 % fontspec option + drawcolor blue fillcolor .5[red,white] + scaled 3 rotated 30 ; +picture p; +p:=mplibgraphictext "\it xyz" + fillcolor .7white; +draw p scaled 3 shifted (40,0); +endfig; +\endmplibcode +\par +\mplibsetformat{metafun}% +\mplibcode +beginfig(1) +fill unitsquare xyscaled (\mpdim\hsize, 1cm) + withshademethod "linear" + withshadevector (0,1) + withshadestep ( + withshadefraction .5 + withshadecolors (red,blue) + ) + withshadestep ( + withshadefraction 1 + withshadecolors (blue,green) + ) + ; +endfig; +\endmplibcode +\leavevmode +\mpfig +picture Q, u, e; +Q := mplibglyph "Q" of "texgyrepagella-bolditalic.otf" scaled .1; +u := mplibglyph "u" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner Q; +e := mplibglyph "e" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner u; +i:=0; +totallen := length Q + length u + length e; +for pic=Q, u, e: + for item within pic: + i:=i+1; + fill pathpart item + if i < totallen: withpostscript "collect"; fi + endfor +endfor + withshademethod "linear" + withshadedirection (0.5,2.5) + withshadecolors (.7red,.7yellow) + ; +\endmpfig +\everymplib[@mpfig]{ drawoptions(withcolor mplibrgbtexcolor"orange"); }% +\mpfig* input boxes \endmpfig +\mpfig circleit.a(btex\tracingcommands0 Box 1 etex); drawboxed(a); \endmpfig +\def\mpfiginstancename{mympfig}% +\mpfig +draw mpliboutlinetext.b ("$\sqrt{2+\alpha}$") + (withcolor .6[red,white]) + (withpen pencircle scaled .2 withcolor red) + scaled 4 ; +\endmpfig +\tracingcommands0 + +\vskip 2\baselineskip +\mplibcodeinherit{disable} +\everymplib[instanceOne]{beginfig(1);} +\everyendmplib[instanceOne]{endfig;} + +\mplibcode[instanceOne] + picture TeX; + TeX := btex \TeX etex; +a := 1cm; +draw fullcircle scaled a; +draw btex a circle with $d=a$ etex shifted (a,0); +draw TeX; +\endmplibcode +Current instance name is: \currentmpinstancename \vskip 2\baselineskip + +\mplibcode[instanceTwo] +beginfig(1); +if not known a: + draw btex code is not inherited from an instance with a different name etex; +else: + errmessage("Variable was inherited from a different instance"); +fi; +endfig; +\endmplibcode +Current instance name is: \currentmpinstancename \vskip 2\baselineskip + +\mplibcode +beginfig(1); +if not known a: + draw btex code is not inherited if instance name is not listed etex; +else: + errmessage("Variable was inherited from a different instance"); +fi; +a := 1cm; +endfig; +\endmplibcode +Current instance name is: \currentmpinstancename (should be empty) \vskip 2\baselineskip + +\mplibcode +beginfig(1); +if not known a: + draw btex code is not inherited if mplibcodeinherit is disabled and instance name is not explicitly set etex; +else: + errmessage("Variable was inherited when code inheritance is turned off and instance name is not set"); +fi; +endfig; +\endmplibcode +Current instance name is: \currentmpinstancename (should be empty) \vskip 2\baselineskip + +\mplibcode[instanceOne] +draw unitsquare scaled a; +draw btex a square with side $=a$, inherited from the same instance etex shifted (3/2a, 1/2a); + draw TeX; +\endmplibcode +Current instance name is: \currentmpinstancename \vskip 2\baselineskip + \bye diff --git a/macros/luatex/generic/luatexja/COPYING b/macros/luatex/generic/luatexja/COPYING index 610a7b62b2..b82ffc50fe 100644 --- a/macros/luatex/generic/luatexja/COPYING +++ b/macros/luatex/generic/luatexja/COPYING @@ -1,4 +1,4 @@ -Copyright (c) 2011--2023 The LuaTeX-ja project, All rights reserved. +Copyright (c) 2011--2024 The LuaTeX-ja project, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/macros/luatex/generic/luatexja/README b/macros/luatex/generic/luatexja/README index 4e48f6c82f..9224c83b0b 100644 --- a/macros/luatex/generic/luatexja/README +++ b/macros/luatex/generic/luatexja/README @@ -1,6 +1,6 @@ -The LuaTeX-ja Package 20240219.0 +The LuaTeX-ja Package 20240514.0 -------------------------------- -Copyright (c) 2011--2023 The LuaTeX-ja project +Copyright (c) 2011--2024 The LuaTeX-ja project License: modified BSD (see COPYING) LuaTeX-ja is a macro package for typesetting Japanese documents with LuaTeX. @@ -24,7 +24,8 @@ Installation - LuaTeX 1.10.0 (or later) - luaotfload (v3.1 or later recommended) - adobemapping (Adobe CMap files) - - LaTeX2e 2020-02-02 patch level 5 or later (if you want to use with LaTeX) + - LaTeX2e 2021-06-01 or later (if you want to use with LaTeX) + - l3kernel about 2023-10-10 or later - etoolbox package - ltxcmds package, pdftexcmds package - filehook package, atbegshi package (for LaTeX2e 2020-02-02) @@ -32,7 +33,7 @@ Installation - Harano Aji fonts (https://github.com/trueroad/HaranoAjiFonts) more specifically, HaranoAjiMincho-Regular and HaranoAjiGothic-Medium - Using LuaTeX-ja with LuaHBTeX is not well tested. + Using LuaTeX-ja with Harfbuzz is not well tested. One might be able to typeset documents without an error, but with some unwanted results. @@ -41,7 +42,7 @@ Installation 2. If you must/want to install manually: a. Download the source archive from CTAN, - or tagged as 20240219.0 in the Git repository by + or tagged as 20240514.0 in the Git repository by <https://github.com/luatexja/luatexja/archive/refs/tags/$VER.zip> b. Extract the archive and process following three files by LuaLaTeX @@ -91,4 +92,4 @@ Notes This file and ltj-kinsoku.lua are not used anymore. (Do not remove ltj-kinsoku.tex.) -Last commit date: Mon Feb 19 19:11:46 2024 +0900 +Last commit date: Tue May 14 19:12:05 2024 +0900 diff --git a/macros/luatex/generic/luatexja/doc/luatexja-en.pdf b/macros/luatex/generic/luatexja/doc/luatexja-en.pdf Binary files differindex 547c5f9b46..de28e1d279 100644 --- a/macros/luatex/generic/luatexja/doc/luatexja-en.pdf +++ b/macros/luatex/generic/luatexja/doc/luatexja-en.pdf diff --git a/macros/luatex/generic/luatexja/doc/luatexja-ja.pdf b/macros/luatex/generic/luatexja/doc/luatexja-ja.pdf Binary files differindex 3dc1d9a8d7..49a8a6feef 100644 --- a/macros/luatex/generic/luatexja/doc/luatexja-ja.pdf +++ b/macros/luatex/generic/luatexja/doc/luatexja-ja.pdf diff --git a/macros/luatex/generic/luatexja/doc/luatexja.dtx b/macros/luatex/generic/luatexja/doc/luatexja.dtx index dace65c689..b550dc58d4 100644 --- a/macros/luatex/generic/luatexja/doc/luatexja.dtx +++ b/macros/luatex/generic/luatexja/doc/luatexja.dtx @@ -648,14 +648,9 @@ and \emph{Japanese fonts} for fonts used in \textbf{JAchar}. %<ja> (DVI出力(\cs{outputmode=0})は対応していない.) \item recent \href{https://github.com/latex3/luaotfload}{\Pkg{luaotfload}} (v3.1 or later recommended) \item \Pkg{adobemapping} (Adobe cmap and pdfmapping files) -\item \LaTeXe\ 2020-02-02 patch level 5 or later -%<en> (if you want to use \LuaTeX-ja with \LaTeXe) -%<ja> (\LaTeXe 下で\LuaTeX-jaを使う場合) \item \href{https://github.com/josephwright/etoolbox/}{\Pkg{etoolbox}} %<en> (if you want to use \LuaTeX-ja with \LaTeXe) %<ja> (\LaTeXe 下で\LuaTeX-jaを使う場合) -\item \Pkg{everysel} (only for \LaTeXe\ 2020-02-02~and~2020-10-01) -\item \Pkg{filehook}, \Pkg{atbegshi} (only for \LaTeXe\ 2020-02-02) \item \Pkg{ltxcmds}, \Pkg{pdftexcmds} \item \href{https://github.com/wspr/fontspec/}{\Pkg{fontspec}} v2.7c (or later) %<*en> diff --git a/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29c.sty b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29c.sty new file mode 100644 index 0000000000..1415cee127 --- /dev/null +++ b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29c.sty @@ -0,0 +1,415 @@ +% +% luatexja-fontspec-29c.sty +% + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{luatexja-fontspec-29c}[2024-05-05 fontspec support of LuaTeX-ja] +\RequirePackage{l3keys2e} +\ExplSyntaxOn + +%%%%%%%% Change Japanese font family by \rmfamily or not +\bool_if:NT \__ltj_fontspec_match_bool { + \renewcommand\jttdefault{\gtdefault} + \@ltj@match@familytrue +} +%%%%%%%% Messages +\msg_new:nnn {luatexja-fontspec} {addjfontfeatures-ignored} +{ + \string\addjfontfeature (s)~ ignored;\\ + it~ cannot~ be~ used~ with~ a~ font~ that~ wasn't~ selected~ by~ luatexja-fontspec. +} + +\msg_new:nnn {luatexja-fontspec} {altfont-ignored-by-norange} +{ + ignored~ sublist~ `#1'~ in~ AltFont~ (no~ range~ is~ specified). +} + +\msg_new:nnn {luatexja-fontspec} {altfont-ignored-by-rangeonly} +{ + ignored~ sublist~ `#1'~ in~ AltFont~ (only~ range~ is~ specified). +} + +\cs_generate_variant:Nn \prg_new_conditional:Nnn {Nnx} + +%%%%%%%% Internal control sequences +%% Each CS is ltj_fontspec version that corresponds to original CS of fontspec. +\cs_new:Nn \__ltj_fontspec_define_option:nn { + \__fontspec_keys_define_code:nnn {fontspec} {#1} {#2} +} +\cs_new:Nn \__ltj_fontspec_define_preparse_external:nn { + \__fontspec_keys_define_code:nnn {fontspec-preparse-external} {#1} {#2} +} +\cs_new:Nn \__ltj_fontspec_define_altfont_option:nn { + \__fontspec_keys_define_code:nnn {fontspec-ltjaltfont} {#1} {#2} +} + +%% Alternate Fonts +%% Spec: AltFont = { +%% ... +%% { Range = <range>, <font features> }, +%% { Range = <range>, Font = <font name>, <font features> }, +%% { Range = <range>, Font = <font name> }, +%% ... +%% } +\tl_new:N \l__ltj_fontspec_altname_tl +\tl_new:N \l__ltj_fontspec_altrange_tl +\clist_new:N \l__ltj_fontspec_altfont_clist +\clist_new:N \l__ltj_fontspec_altfont_leftover_clist +\int_new:N \g__ltj_fontspec_altnumber_int + +\__ltj_fontspec_define_altfont_option:nn {Range} { + \tl_set:Nn \l__ltj_fontspec_altrange_tl {#1} +} +\__ltj_fontspec_define_altfont_option:nn {Font} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_altname_tl {#1} +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {AltFont} { + \clist_put_right:Nn \l__ltj_fontspec_altfont_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {YokoFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_yoko_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {TateFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_tate_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {TateFont} { + \tl_if_empty:nF {#1} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_fontname_tate_tl {#1} + } +} +%% +\clist_new:N \l__ltj_fontspec_fontfeat_yoko_clist +\clist_new:N \l__ltj_fontspec_fontfeat_tate_clist +\tl_new:N \l__ltj_fontspec_fontname_tate_tl + +\cs_new:Npn \__ltj_fontspec_DeclareFontFamily #1 #2 #3 { + \DeclareKanjiFamily {JY3} {#2} {#3} + \DeclareKanjiFamily {JT3} {#2} {#3} +} + +%% save and restore global variable +\tl_new:N \g__ltj_fontspec_kanji_nfss_family_tl +\tl_new:N \g__ltj_fontspec_orig_nfss_family_tl +\seq_new:N \l__ltj_fontspec_kanji_bf_series_seq +\seq_new:N \l__ltj_fontspec_orig_bf_series_seq +\clist_new:N \g__ltj_fontspec_kanji_default_fontopts_clist +\clist_new:N \g__ltj_fontspec_orig_default_fontopts_clist + +\cs_new:Nn \__ltj_set_global_variable_for_kanji: { + \tl_gset_eq:NN \g__ltj_fontspec_orig_nfss_family_tl \g__fontspec_nfss_family_tl + \tl_gset_eq:NN \g__fontspec_nfss_family_tl \g__ltj_fontspec_kanji_nfss_family_tl + \seq_set_eq:NN \l__ltj_fontspec_orig_bf_series_seq \l__fontspec_bf_series_seq + \seq_set_eq:NN \l__fontspec_bf_series_seq \l__ltj_fontspec_kanji_bf_series_seq + %\seq_gclear:N \g__fontspec_bf_series_seq + \clist_set_eq:NN \g__ltj_fontspec_orig_default_fontopts_clist \g__fontspec_default_fontopts_clist + \clist_set_eq:NN \g__fontspec_default_fontopts_clist \g__ltj_fontspec_kanji_default_fontopts_clist +} + +\cs_new:Nn \__ltj_restore_global_variable: { + \tl_gset_eq:NN \g__ltj_fontspec_kanji_nfss_family_tl \g__fontspec_nfss_family_tl + \tl_gset_eq:NN \g__fontspec_nfss_family_tl \g__ltj_fontspec_orig_nfss_family_tl + \seq_set_eq:NN \l__ltj_fontspec_kanji_bf_series_seq \l__fontspec_bf_series_seq + \seq_set_eq:NN \l__fontspec_bf_series_seq \l__ltj_fontspec_orig_bf_series_seq + \clist_set_eq:NN \g__ltj_fontspec_kanji_default_fontopts_clist \g__fontspec_default_fontopts_clist + \clist_set_eq:NN \g__fontspec_default_fontopts_clist \g__ltj_fontspec_orig_default_fontopts_clist +} + +\cs_set_eq:NN \__ltj_orig_fontspec_select_font_family:nn \__fontspec_select_font_family:nn +\cs_new_protected:Nn \__ltj_fontspec_select_font_family:nn { + \group_begin: + \__ltj_fontspec_define_option:nn {NoEmbed} {} + \__ltj_fontspec_define_option:nn {AltFont} { + \clist_put_right:Nn \l__ltj_fontspec_altfont_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {CID} { + \__fontspec_update_featstr:n {cid=##1} + } + \__ltj_fontspec_define_option:nn {Kanjiskip} { + \str_if_eq:eeTF {false} { \str_lower_case:n { ##1 } }{ + \__fontspec_update_featstr:n {-ltjksp} + } { + \__fontspec_update_featstr:n {+ltjksp} + } + } + \__ltj_fontspec_define_option:nn {JFM} { + \__fontspec_update_featstr:n {jfm=##1} + } + % vary by shape + \__ltj_fontspec_define_option:nn {YokoFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_yoko_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {TateFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_tate_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {TateFont} + { + \tl_if_empty:nF {##1} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_fontname_tate_tl {##1} + } + } + \__ltj_fontspec_define_option:nn {JFM-var} { + \__fontspec_update_featstr:n {jfmvar=##1} + } + \__ltj_fontspec_define_preparse_external:nn {NoEmbed} { + \cs_set:Npn \__fontspec_fontname_wrap:n ##1 {psft:##1} + } + + %% Omit the warning message + %% "OpenType feature 'Kerning=Off' (-kern) not available ..." + \keys_define:nn {fontspec-opentype} { + Kerning/Off.code:n=\__fontspec_update_featstr:n {-kern} + } + \clist_set:Ne \g__fontspec_default_fontopts_clist { + YokoFeatures = { JFM=\ltj@stdyokojfm }, TateFeatures = { JFM=\ltj@stdtatejfm }, + Scale=\Cjascale, Kerning=Off, Script=CJK, + \g__ltj_fontspec_kanji_default_fontopts_clist + } + \prop_set_eq:NN \g__fontspec_fontopts_prop \g__ltj_fontspec_fontopts_prop + \cs_set_eq:NN \__fontspec_make_font_shapes:Nnnnn \__ltj_fontspec_make_font_shapes:Nnnnn + \cs_set_eq:NN \DeclareFontFamily \__ltj_fontspec_DeclareFontFamily + \tl_set:Nn \g_fontspec_encoding_tl {JY3} + \__ltj_orig_fontspec_select_font_family:nn{#1}{#2} + + \cs_gset:Npx \__ltj_fontspec_aftergroup { + \exp_not:N \tl_set:Nn \exp_not:N \l_fontspec_family_tl { \l_fontspec_family_tl } + } + \aftergroup \__ltj_fontspec_aftergroup + \group_end: +} + +%% declare_shape + +\cs_new:Nn \__ltj_fontspec_declare_shape_yoko:nnnn { + \__ltj_fontspec_declare_shape_aux:nnnnnn {#1} {#2} {#3} {#4} { JY3 } { \l__ltj_fontspec_fontfeat_yoko_clist } +} +\cs_new:Nn \__ltj_fontspec_declare_shape_tate:nnnn { + \__ltj_fontspec_declare_shape_aux:nnnnnn {#1} {#2} {#3} {#4} { JT3 } { \l__ltj_fontspec_fontfeat_tate_clist } +} +\cs_new:Nn \__ltj_fontspec_declare_shape:nnnn { + \__ltj_fontspec_declare_shape_yoko:nnnn {#1} {#2} {#3} {#4} + \__ltj_fontspec_declare_shape_tate:nnnn {#1} {#2} {#3} {#4} +} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape:nnnn {nnxx} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape_yoko:nnnn {nnxx} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape_tate:nnnn {nnxx} + +\cs_new:Nn \__ltj_fontspec_declare_shape_aux:nnnnnn +{ + \tl_build_begin:N \l__fontspec_nfss_tl + \tl_build_begin:N \l__fontspec_nfss_sc_tl + \tl_set_eq:NN \l__fontspec_saved_fontname_tl \l_fontspec_fontname_tl + + \tl_set:Nn \g_fontspec_encoding_tl {#5} + \tl_set:Nn \g__fontspec_nfss_enc_tl {#5} + \exp_args:Ne \clist_map_inline:nn {#4} + { \__ltj_fontspec_setup_single_size:nnn {#3} {#6} {##1} } + \tl_build_end:N \l__fontspec_nfss_tl + \tl_build_end:N \l__fontspec_nfss_sc_tl + + \bool_set_true:N \l__fontspec_nosc_bool + \__fontspec_declare_shapes_normal:nn {#1} {#2} + \__fontspec_declare_shape_slanted:nn {#1} {#2} +} + +\cs_new:Nn \__ltj_fontspec_setup_single_size:nnn +{ + \tl_clear:N \l__fontspec_size_tl + \tl_set_eq:NN \l__fontspec_sizedfont_tl \l__fontspec_saved_fontname_tl % in case not spec'ed + + \keys_set_known:neN {fontspec-sizing} { \exp_after:wN \use:n #3 } + \l__fontspec_sizing_leftover_clist + \tl_if_empty:NT \l__fontspec_size_tl { \__fontspec_error:n {no-size-info} } + + \str_if_eq:eeTF { \g__fontspec_nfss_enc_tl } { JY3 } { + % "normal" + \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__fontspec_sizedfont_tl} + } { + \tl_if_empty:NTF \l__ltj_fontspec_fontname_tate_tl + { \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__fontspec_sizedfont_tl} } + { \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__ltj_fontspec_fontname_tate_tl} } + } + \__fontspec_setup_nfss:Nnnn \l__fontspec_nfss_tl {#1} {#2} {} +} + +\cs_new:Nn \__ltj_fontspec_set_family:Nnn { + \__ltj_set_global_variable_for_kanji: + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_fontspec_select_font_family:nn + \__ltj_orig_fontspec_set_family:Nnn #1 {#2} {#3} + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_orig_fontspec_select_font_family:nn + \__ltj_restore_global_variable: +} +\cs_set_eq:NN \__ltj_orig_fontspec_set_family:Nnn \fontspec_set_family:Nnn +\cs_set_eq:NN \__ltj_orig_fontspec_make_font_shapes:Nnnnn \__fontspec_make_font_shapes:Nnnnn +\cs_set_eq:NN \__ltj_fontspec_orig_DeclareFontShape \DeclareFontShape + +\cs_new:Nn \__ltj_fontspec_make_font_shapes:Nnnnn { + \group_begin: + %% 基底フォント + \cs_set_eq:NN \__fontspec_font_set:Nnn \use_none:nnn + \cs_set_eq:NN \__fontspec_font_if_null:NT \use_none:nn + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape:nnxx + \__ltj_orig_fontspec_make_font_shapes:Nnnnn {#1} {#2} {#3} {#4} {#5} + %% + \__ltj_fontspec_make_font_shapes_alt:Nnnnnn {#1}{#2}{#3} + {#4, \l__ltj_fontspec_fontfeat_yoko_clist}{#5} {JY3 } + \__ltj_fontspec_make_font_shapes_alt:Nnnnnn {#1}{#2}{#3} + {#4, \l__ltj_fontspec_fontfeat_tate_clist}{#5} {JT3} + \group_end: + } + +%%% Altfont 内部処理部 +\cs_new:Nn \__ltj_fontspec_make_font_shapes_alt:Nnnnnn { + \group_begin: + \str_if_eq:eeTF { #6 } { JY3 } { + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape_yoko:nnxx + }{ + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape_tate:nnxx + } + \keys_set_known:nn {fontspec-ltjaltfont-reparse} { #4 } + \clist_if_empty:NF \l__ltj_fontspec_altfont_clist { + \int_gzero:N \g__ltj_fontspec_altnumber_int + \clist_map_inline:Nn \l__ltj_fontspec_altfont_clist { + \tl_clear:N \l__ltj_fontspec_altrange_tl + \tl_set:Nn \l__ltj_fontspec_altname_tl { #1 } + \tl_set:Nn \l_tmpa_tl { #1 } + + \keys_set_known:neN {fontspec-ltjaltfont} { \exp_after:wN \use:n ##1 } + \l__ltj_fontspec_altfont_leftover_clist + \keys_set_known:nn {fontspec-ltjaltfont-reparse} { \exp_after:wN \use:n ##1 } + + \tl_if_empty:NT \l__ltj_fontspec_altrange_tl { + \msg_warning:nnn {luatexja-fontspec} {altfont-ignored-by-norange} { ##1 } + } { + \bool_if:nTF { + \tl_if_eq_p:NN \l__ltj_fontspec_altname_tl \l_tmpa_tl + && + \tl_if_empty_p:N \l__ltj_fontspec_altfont_leftover_clist + } { + \msg_warning:nnn {luatexja-fontspec} {altfont-ignored-by-rangeonly} { ##1 } + } { + \__ltj_orig_fontspec_make_font_shapes:Nnnnn + { \l__ltj_fontspec_altname_tl } {#2} + {#3 _ alt \int_use:N \g__ltj_fontspec_altnumber_int } + {#4, \l__ltj_fontspec_altfont_leftover_clist } + {#5} + \DeclareAlternateKanjiFont + { #6 }{ \g__fontspec_nfss_family_tl }{#2}{#3}% + { #6 }{ \g__fontspec_nfss_family_tl }{#2} + { #3 _alt \int_use:N \g__ltj_fontspec_altnumber_int } + { \l__ltj_fontspec_altrange_tl } + \int_gincr:N \g__ltj_fontspec_altnumber_int + } + } + } + } + \group_end: +} + + +%%%%%%%% User commands +\DeclareDocumentCommand \jfontspec { O{} m O{} } { + \__ltj_fontspec_set_family:Nnn \k@family {#1,#3}{#2} + \selectfont + \ignorespaces +} + +\DeclareDocumentCommand \setmainjfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[mc]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \mcdefault {#1,#3}{#2} + \unless\ifltj@disablejfam + \DeclareSymbolFont{mincho}{JY3}{\mcdefault}{\mddefault}{n} + \SetSymbolFont{mincho}{bold}{JY3}{\mcdefault}{\bfdefault}{n} + \fi + \normalfont +} + +\DeclareDocumentCommand \setsansjfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[gt]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \gtdefault {#1,#3}{#2} + \unless\ifltj@disablejfam + \DeclareMathAlphabet{\mathgt}{JY3}{\gtdefault}{\mddefault}{n} + \fi + \normalfont +} + +\DeclareDocumentCommand \setmonojfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[jtt]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \jttdefault {#1,#3}{#2} + \normalfont +} + +\DeclareDocumentCommand \newjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \newfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} +\DeclareDocumentCommand \renewjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \renewfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} +\DeclareDocumentCommand \setjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \setfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} + +\DeclareDocumentCommand \newjfontface { m O{} m O{} } { + \newjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3} +} + +\prop_new:N \l__ltj_fontspec_tmp_prop +\prop_new:N \g__ltj_fontspec_fontopts_prop +\DeclareDocumentCommand \defaultjfontfeatures { t+ o m } + { + \IfNoValueTF {#2} + { \__ltj_fontspec_set_default_features:nn {#1} {#3} } + { \__ltj_fontspec_set_font_default_features:nnn {#1} {#2} {#3} } + \ignorespaces + } +\cs_new:Nn \__ltj_fontspec_set_default_features:nn + { + \__ltj_set_global_variable_for_kanji: + \__fontspec_set_default_features:nn {#1} {#2} + \__ltj_restore_global_variable: + } +\cs_new:Nn \__ltj_fontspec_set_font_default_features:nnn + { + \prop_set_eq:NN \l__ltj_fontspec_tmp_prop \g__fontspec_fontopts_prop + \prop_set_eq:NN \g__fontspec_fontopts_prop \g__ltj_fontspec_fontopts_prop + \__fontspec_set_font_default_features:nnn {#1} {#2} {#3} + \prop_set_eq:NN \g__ltj_fontspec_fontopts_prop \g__fontspec_fontopts_prop + \prop_set_eq:NN \g__fontspec_fontopts_prop \l__ltj_fontspec_tmp_prop + } + +\DeclareDocumentCommand \addjfontfeatures {m} { + \__ltj_fontspec_if_fontspec_font:TF + { + \__ltj_set_global_variable_for_kanji: + \group_begin: + \tl_set_eq:NN \f@family \k@family + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_fontspec_select_font_family:nn + \addfontfeatures {#1} + \group_end: + \kanjifamily\g__fontspec_nfss_family_tl\selectfont + \__ltj_restore_global_variable: + }{ + \msg_warning:nn {luatexja-fontspec} {addjfontfeatures-ignored} + } + \ignorespaces +} + +\cs_set_eq:NN \addjfontfeature \addjfontfeatures + +\prg_new_conditional:Nnn \__ltj_fontspec_if_fontspec_font: {TF,T,F} +{ + \cs_if_exist:cTF {g__fontspec_fontinfo_ \k@family _prop} \prg_return_true: \prg_return_false: +} + +\endinput diff --git a/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29e.sty b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29e.sty new file mode 100644 index 0000000000..e763d91ad7 --- /dev/null +++ b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec-29e.sty @@ -0,0 +1,415 @@ +% +% luatexja-fontspec-29e.sty +% + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{luatexja-fontspec-29e}[2024-05-14 fontspec support of LuaTeX-ja] +\RequirePackage{l3keys2e} +\ExplSyntaxOn + +%%%%%%%% Change Japanese font family by \rmfamily or not +\bool_if:NT \__ltj_fontspec_match_bool { + \renewcommand\jttdefault{\gtdefault} + \@ltj@match@familytrue +} +%%%%%%%% Messages +\msg_new:nnn {luatexja-fontspec} {addjfontfeatures-ignored} +{ + \string\addjfontfeature (s)~ ignored;\\ + it~ cannot~ be~ used~ with~ a~ font~ that~ wasn't~ selected~ by~ luatexja-fontspec. +} + +\msg_new:nnn {luatexja-fontspec} {altfont-ignored-by-norange} +{ + ignored~ sublist~ `#1'~ in~ AltFont~ (no~ range~ is~ specified). +} + +\msg_new:nnn {luatexja-fontspec} {altfont-ignored-by-rangeonly} +{ + ignored~ sublist~ `#1'~ in~ AltFont~ (only~ range~ is~ specified). +} + +\cs_generate_variant:Nn \prg_new_conditional:Nnn {Nnx} + +%%%%%%%% Internal control sequences +%% Each CS is ltj_fontspec version that corresponds to original CS of fontspec. +\cs_new:Nn \__ltj_fontspec_define_option:nn { + \__fontspec_keys_define_code:nnn {fontspec} {#1} {#2} +} +\cs_new:Nn \__ltj_fontspec_define_preparse_external:nn { + \__fontspec_keys_define_code:nnn {fontspec-preparse-external} {#1} {#2} +} +\cs_new:Nn \__ltj_fontspec_define_altfont_option:nn { + \__fontspec_keys_define_code:nnn {fontspec-ltjaltfont} {#1} {#2} +} + +%% Alternate Fonts +%% Spec: AltFont = { +%% ... +%% { Range = <range>, <font features> }, +%% { Range = <range>, Font = <font name>, <font features> }, +%% { Range = <range>, Font = <font name> }, +%% ... +%% } +\tl_new:N \l__ltj_fontspec_altname_tl +\tl_new:N \l__ltj_fontspec_altrange_tl +\clist_new:N \l__ltj_fontspec_altfont_clist +\clist_new:N \l__ltj_fontspec_altfont_leftover_clist +\int_new:N \g__ltj_fontspec_altnumber_int + +\__ltj_fontspec_define_altfont_option:nn {Range} { + \tl_set:Nn \l__ltj_fontspec_altrange_tl {#1} +} +\__ltj_fontspec_define_altfont_option:nn {Font} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_altname_tl {#1} +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {AltFont} { + \clist_put_right:Nn \l__ltj_fontspec_altfont_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {YokoFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_yoko_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {TateFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_tate_clist { #1 } +} +\__fontspec_keys_define_code:nnn {fontspec-ltjaltfont-reparse} {TateFont} { + \tl_if_empty:nF {#1} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_fontname_tate_tl {#1} + } +} +%% +\clist_new:N \l__ltj_fontspec_fontfeat_yoko_clist +\clist_new:N \l__ltj_fontspec_fontfeat_tate_clist +\tl_new:N \l__ltj_fontspec_fontname_tate_tl + +\cs_new:Npn \__ltj_fontspec_DeclareFontFamily #1 #2 #3 { + \DeclareKanjiFamily {JY3} {#2} {#3} + \DeclareKanjiFamily {JT3} {#2} {#3} +} + +%% save and restore global variable +\tl_new:N \g__ltj_fontspec_kanji_nfss_family_tl +\tl_new:N \g__ltj_fontspec_orig_nfss_family_tl +\seq_new:N \l__ltj_fontspec_kanji_bf_series_seq +\seq_new:N \l__ltj_fontspec_orig_bf_series_seq +\clist_new:N \g__ltj_fontspec_kanji_default_fontopts_clist +\clist_new:N \g__ltj_fontspec_orig_default_fontopts_clist + +\cs_new:Nn \__ltj_set_global_variable_for_kanji: { + \tl_gset_eq:NN \g__ltj_fontspec_orig_nfss_family_tl \g__fontspec_nfss_family_tl + \tl_gset_eq:NN \g__fontspec_nfss_family_tl \g__ltj_fontspec_kanji_nfss_family_tl + \seq_set_eq:NN \l__ltj_fontspec_orig_bf_series_seq \l__fontspec_bf_series_seq + \seq_set_eq:NN \l__fontspec_bf_series_seq \l__ltj_fontspec_kanji_bf_series_seq + %\seq_gclear:N \g__fontspec_bf_series_seq + \clist_set_eq:NN \g__ltj_fontspec_orig_default_fontopts_clist \g__fontspec_default_fontopts_clist + \clist_set_eq:NN \g__fontspec_default_fontopts_clist \g__ltj_fontspec_kanji_default_fontopts_clist +} + +\cs_new:Nn \__ltj_restore_global_variable: { + \tl_gset_eq:NN \g__ltj_fontspec_kanji_nfss_family_tl \g__fontspec_nfss_family_tl + \tl_gset_eq:NN \g__fontspec_nfss_family_tl \g__ltj_fontspec_orig_nfss_family_tl + \seq_set_eq:NN \l__ltj_fontspec_kanji_bf_series_seq \l__fontspec_bf_series_seq + \seq_set_eq:NN \l__fontspec_bf_series_seq \l__ltj_fontspec_orig_bf_series_seq + \clist_set_eq:NN \g__ltj_fontspec_kanji_default_fontopts_clist \g__fontspec_default_fontopts_clist + \clist_set_eq:NN \g__fontspec_default_fontopts_clist \g__ltj_fontspec_orig_default_fontopts_clist +} + +\cs_set_eq:NN \__ltj_orig_fontspec_select_font_family:nn \__fontspec_select_font_family:nn +\cs_new_protected:Nn \__ltj_fontspec_select_font_family:nn { + \group_begin: + \__ltj_fontspec_define_option:nn {NoEmbed} {} + \__ltj_fontspec_define_option:nn {AltFont} { + \clist_put_right:Nn \l__ltj_fontspec_altfont_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {CID} { + \__fontspec_update_featstr:n {cid=##1} + } + \__ltj_fontspec_define_option:nn {Kanjiskip} { + \str_if_eq:eeTF {false} { \str_lower_case:n { ##1 } }{ + \__fontspec_update_featstr:n {-ltjksp} + } { + \__fontspec_update_featstr:n {+ltjksp} + } + } + \__ltj_fontspec_define_option:nn {JFM} { + \__fontspec_update_featstr:n {jfm=##1} + } + % vary by shape + \__ltj_fontspec_define_option:nn {YokoFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_yoko_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {TateFeatures} { + \clist_put_right:Nn \l__ltj_fontspec_fontfeat_tate_clist { ##1 } + } + \__ltj_fontspec_define_option:nn {TateFont} + { + \tl_if_empty:nF {##1} { + \fontspec_complete_fontname:Nn \l__ltj_fontspec_fontname_tate_tl {##1} + } + } + \__ltj_fontspec_define_option:nn {JFM-var} { + \__fontspec_update_featstr:n {jfmvar=##1} + } + \__ltj_fontspec_define_preparse_external:nn {NoEmbed} { + \cs_set:Npn \__fontspec_fontname_wrap:n ##1 {psft:##1} + } + + %% Omit the warning message + %% "OpenType feature 'Kerning=Off' (-kern) not available ..." + \keys_define:nn {fontspec-opentype} { + Kerning/Off.code:n=\__fontspec_update_featstr:n {-kern} + } + \clist_set:Ne \g__fontspec_default_fontopts_clist { + YokoFeatures = { JFM=\ltj@stdyokojfm }, TateFeatures = { JFM=\ltj@stdtatejfm }, + Scale=\Cjascale, Kerning=Off, Script=CJK, + \g__ltj_fontspec_kanji_default_fontopts_clist + } + \prop_set_eq:NN \g__fontspec_fontopts_prop \g__ltj_fontspec_fontopts_prop + \cs_set_eq:NN \__fontspec_make_font_shapes:Nnnnn \__ltj_fontspec_make_font_shapes:Nnnnn + \cs_set_eq:NN \DeclareFontFamily \__ltj_fontspec_DeclareFontFamily + \tl_set:Nn \g_fontspec_encoding_tl {JY3} + \__ltj_orig_fontspec_select_font_family:nn{#1}{#2} + + \cs_gset:Npx \__ltj_fontspec_aftergroup { + \exp_not:N \tl_set:Nn \exp_not:N \l_fontspec_family_tl { \l_fontspec_family_tl } + } + \aftergroup \__ltj_fontspec_aftergroup + \group_end: +} + +%% declare_shape + +\cs_new:Nn \__ltj_fontspec_declare_shape_yoko:nnnn { + \__ltj_fontspec_declare_shape_aux:nnnnnn {#1} {#2} {#3} {#4} { JY3 } { \l__ltj_fontspec_fontfeat_yoko_clist } +} +\cs_new:Nn \__ltj_fontspec_declare_shape_tate:nnnn { + \__ltj_fontspec_declare_shape_aux:nnnnnn {#1} {#2} {#3} {#4} { JT3 } { \l__ltj_fontspec_fontfeat_tate_clist } +} +\cs_new:Nn \__ltj_fontspec_declare_shape:nnnn { + \__ltj_fontspec_declare_shape_yoko:nnnn {#1} {#2} {#3} {#4} + \__ltj_fontspec_declare_shape_tate:nnnn {#1} {#2} {#3} {#4} +} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape:nnnn {nnxx} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape_yoko:nnnn {nnxx} +\cs_generate_variant:Nn \__ltj_fontspec_declare_shape_tate:nnnn {nnxx} + +\cs_new:Nn \__ltj_fontspec_declare_shape_aux:nnnnnn +{ + \tl_build_begin:N \l__fontspec_nfss_tl + \tl_build_begin:N \l__fontspec_nfss_sc_tl + \tl_set_eq:NN \l__fontspec_saved_fontname_tl \l_fontspec_fontname_tl + + \tl_set:Nn \g_fontspec_encoding_tl {#5} + \tl_set:Nn \g__fontspec_nfss_enc_tl {#5} + \exp_args:Ne \clist_map_inline:nn {#4} + { \__ltj_fontspec_setup_single_size:nn {#3, #6} {##1} } + \tl_build_end:N \l__fontspec_nfss_tl + \tl_build_end:N \l__fontspec_nfss_sc_tl + + \bool_set_true:N \l__fontspec_nosc_bool + \__fontspec_declare_shapes_normal:nn {#1} {#2} + \__fontspec_declare_shape_slanted:nn {#1} {#2} +} + +\cs_new:Nn \__ltj_fontspec_setup_single_size:nn +{ + \tl_clear:N \l__fontspec_size_tl + \tl_set_eq:NN \l__fontspec_sizedfont_tl \l__fontspec_saved_fontname_tl % in case not spec'ed + + \keys_set_known:neN {fontspec-sizing} { \exp_after:wN \use:n #2 } + \l__fontspec_sizing_leftover_clist + \tl_if_empty:NT \l__fontspec_size_tl { \__fontspec_error:n {no-size-info} } + + \str_if_eq:eeTF { \g__fontspec_nfss_enc_tl } { JY3 } { + % "normal" + \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__fontspec_sizedfont_tl} + } { + \tl_if_empty:NTF \l__ltj_fontspec_fontname_tate_tl + { \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__fontspec_sizedfont_tl} } + { \__fontspec_load_fontname:Nn \l_fontspec_fontname_tl {\l__ltj_fontspec_fontname_tate_tl} } + } + \__fontspec_setup_nfss:Nn \l__fontspec_nfss_tl {#1} +} + +\cs_new:Nn \__ltj_fontspec_set_family:Nnn { + \__ltj_set_global_variable_for_kanji: + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_fontspec_select_font_family:nn + \__ltj_orig_fontspec_set_family:Nnn #1 {#2} {#3} + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_orig_fontspec_select_font_family:nn + \__ltj_restore_global_variable: +} +\cs_set_eq:NN \__ltj_orig_fontspec_set_family:Nnn \fontspec_set_family:Nnn +\cs_set_eq:NN \__ltj_orig_fontspec_make_font_shapes:Nnnnn \__fontspec_make_font_shapes:Nnnnn +\cs_set_eq:NN \__ltj_fontspec_orig_DeclareFontShape \DeclareFontShape + +\cs_new:Nn \__ltj_fontspec_make_font_shapes:Nnnnn { + \group_begin: + %% 基底フォント + \cs_set_eq:NN \__fontspec_font_set:Nnn \use_none:nnn + \cs_set_eq:NN \__fontspec_font_if_null:NT \use_none:nn + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape:nnxx + \__ltj_orig_fontspec_make_font_shapes:Nnnnn {#1} {#2} {#3} {#4} {#5} + %% + \__ltj_fontspec_make_font_shapes_alt:Nnnnnn {#1}{#2}{#3} + {#4, \l__ltj_fontspec_fontfeat_yoko_clist}{#5} {JY3 } + \__ltj_fontspec_make_font_shapes_alt:Nnnnnn {#1}{#2}{#3} + {#4, \l__ltj_fontspec_fontfeat_tate_clist}{#5} {JT3} + \group_end: + } + +%%% Altfont 内部処理部 +\cs_new:Nn \__ltj_fontspec_make_font_shapes_alt:Nnnnnn { + \group_begin: + \str_if_eq:eeTF { #6 } { JY3 } { + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape_yoko:nnxx + }{ + \cs_set_eq:NN \__fontspec_declare_shape:nnxx \__ltj_fontspec_declare_shape_tate:nnxx + } + \keys_set_known:nn {fontspec-ltjaltfont-reparse} { #4 } + \clist_if_empty:NF \l__ltj_fontspec_altfont_clist { + \int_gzero:N \g__ltj_fontspec_altnumber_int + \clist_map_inline:Nn \l__ltj_fontspec_altfont_clist { + \tl_clear:N \l__ltj_fontspec_altrange_tl + \tl_set:Nn \l__ltj_fontspec_altname_tl { #1 } + \tl_set:Nn \l_tmpa_tl { #1 } + + \keys_set_known:neN {fontspec-ltjaltfont} { \exp_after:wN \use:n ##1 } + \l__ltj_fontspec_altfont_leftover_clist + \keys_set_known:nn {fontspec-ltjaltfont-reparse} { \exp_after:wN \use:n ##1 } + + \tl_if_empty:NT \l__ltj_fontspec_altrange_tl { + \msg_warning:nnn {luatexja-fontspec} {altfont-ignored-by-norange} { ##1 } + } { + \bool_if:nTF { + \tl_if_eq_p:NN \l__ltj_fontspec_altname_tl \l_tmpa_tl + && + \tl_if_empty_p:N \l__ltj_fontspec_altfont_leftover_clist + } { + \msg_warning:nnn {luatexja-fontspec} {altfont-ignored-by-rangeonly} { ##1 } + } { + \__ltj_orig_fontspec_make_font_shapes:Nnnnn + { \l__ltj_fontspec_altname_tl } {#2} + {#3 _ alt \int_use:N \g__ltj_fontspec_altnumber_int } + {#4, \l__ltj_fontspec_altfont_leftover_clist } + {#5} + \DeclareAlternateKanjiFont + { #6 }{ \g__fontspec_nfss_family_tl }{#2}{#3}% + { #6 }{ \g__fontspec_nfss_family_tl }{#2} + { #3 _alt \int_use:N \g__ltj_fontspec_altnumber_int } + { \l__ltj_fontspec_altrange_tl } + \int_gincr:N \g__ltj_fontspec_altnumber_int + } + } + } + } + \group_end: +} + + +%%%%%%%% User commands +\DeclareDocumentCommand \jfontspec { O{} m O{} } { + \__ltj_fontspec_set_family:Nnn \k@family {#1,#3}{#2} + \selectfont + \ignorespaces +} + +\DeclareDocumentCommand \setmainjfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[mc]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \mcdefault {#1,#3}{#2} + \unless\ifltj@disablejfam + \DeclareSymbolFont{mincho}{JY3}{\mcdefault}{\mddefault}{n} + \SetSymbolFont{mincho}{bold}{JY3}{\mcdefault}{\bfdefault}{n} + \fi + \normalfont +} + +\DeclareDocumentCommand \setsansjfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[gt]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \gtdefault {#1,#3}{#2} + \unless\ifltj@disablejfam + \DeclareMathAlphabet{\mathgt}{JY3}{\gtdefault}{\mddefault}{n} + \fi + \normalfont +} + +\DeclareDocumentCommand \setmonojfont { O{} m O{} } { + \ifdefined\DeclareFontSeriesDefault + \DeclareFontSeriesDefault[jtt]{bf}{\bfdefault} + \fi + \__ltj_fontspec_set_family:Nnn \jttdefault {#1,#3}{#2} + \normalfont +} + +\DeclareDocumentCommand \newjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \newfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} +\DeclareDocumentCommand \renewjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \renewfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} +\DeclareDocumentCommand \setjfontfamily { m O{} m O{} } { + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn + \setfontfamily #1 [#2,#4] {#3} + \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn +} + +\DeclareDocumentCommand \newjfontface { m O{} m O{} } { + \newjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3} +} + +\prop_new:N \l__ltj_fontspec_tmp_prop +\prop_new:N \g__ltj_fontspec_fontopts_prop +\DeclareDocumentCommand \defaultjfontfeatures { t+ o m } + { + \IfNoValueTF {#2} + { \__ltj_fontspec_set_default_features:nn {#1} {#3} } + { \__ltj_fontspec_set_font_default_features:nnn {#1} {#2} {#3} } + \ignorespaces + } +\cs_new:Nn \__ltj_fontspec_set_default_features:nn + { + \__ltj_set_global_variable_for_kanji: + \__fontspec_set_default_features:nn {#1} {#2} + \__ltj_restore_global_variable: + } +\cs_new:Nn \__ltj_fontspec_set_font_default_features:nnn + { + \prop_set_eq:NN \l__ltj_fontspec_tmp_prop \g__fontspec_fontopts_prop + \prop_set_eq:NN \g__fontspec_fontopts_prop \g__ltj_fontspec_fontopts_prop + \__fontspec_set_font_default_features:nnn {#1} {#2} {#3} + \prop_set_eq:NN \g__ltj_fontspec_fontopts_prop \g__fontspec_fontopts_prop + \prop_set_eq:NN \g__fontspec_fontopts_prop \l__ltj_fontspec_tmp_prop + } + +\DeclareDocumentCommand \addjfontfeatures {m} { + \__ltj_fontspec_if_fontspec_font:TF + { + \__ltj_set_global_variable_for_kanji: + \group_begin: + \tl_set_eq:NN \f@family \k@family + \cs_set_eq:NN \__fontspec_select_font_family:nn \__ltj_fontspec_select_font_family:nn + \addfontfeatures {#1} + \group_end: + \kanjifamily\g__fontspec_nfss_family_tl\selectfont + \__ltj_restore_global_variable: + }{ + \msg_warning:nn {luatexja-fontspec} {addjfontfeatures-ignored} + } + \ignorespaces +} + +\cs_set_eq:NN \addjfontfeature \addjfontfeatures + +\prg_new_conditional:Nnn \__ltj_fontspec_if_fontspec_font: {TF,T,F} +{ + \cs_if_exist:cTF {g__fontspec_fontinfo_ \k@family _prop} \prg_return_true: \prg_return_false: +} + +\endinput diff --git a/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec.sty b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec.sty index 19d9952fef..abb2ca986e 100644 --- a/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec.sty +++ b/macros/luatex/generic/luatexja/src/addons/luatexja-fontspec.sty @@ -3,7 +3,7 @@ % \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{luatexja-fontspec}[2020-09-14 fontspec support of LuaTeX-ja] +\ProvidesPackage{luatexja-fontspec}[2024-05-14 fontspec support of LuaTeX-ja] \RequirePackage{l3keys2e,luatexja} \ExplSyntaxOn @@ -28,7 +28,15 @@ \ProcessKeysOptions{ luatexja-fontspec } \RequirePackage{fontspec}[2019/03/15]% v2.7c -\RequirePackage{luatexja-fontspec-27c} % v2.7c +\@ifpackagelater{fontspec}{2024-05-03}{% + \@ifpackagelater{fontspec}{2024-05-10}{% + \RequirePackage{luatexja-fontspec-29e} % v2.9e + }{ + \RequirePackage{luatexja-fontspec-29c} % v2.9c + } +}{ + \RequirePackage{luatexja-fontspec-27c} % v2.7c +} \ExplSyntaxOff %%%%%%%% Now we completely ignore kanjifont definition file. diff --git a/macros/luatex/generic/luatexja/src/addons/luatexja-preset.sty b/macros/luatex/generic/luatexja/src/addons/luatexja-preset.sty index ed2a9084e6..e83a50a615 100644 --- a/macros/luatex/generic/luatexja/src/addons/luatexja-preset.sty +++ b/macros/luatex/generic/luatexja/src/addons/luatexja-preset.sty @@ -1,5 +1,5 @@ % luatexja-preset.sty -\ProvidesPackage{luatexja-preset}[2022-06-19 Japanese font presets] +\ProvidesPackage{luatexja-preset}[2024-03-30 Japanese font presets] \RequirePackage{expl3,l3keys2e} \RequirePackage{luatexja} @@ -57,7 +57,7 @@ } \seq_put_right:Nn \g__ltjpreset_presets_seq { #1 } } -\cs_generate_variant:Nn \ltjpreset_declare_preset:nn {nx} +\cs_generate_variant:Nn \ltjpreset_declare_preset:nn {ne} \cs_new:Nn \__ltjpreset_declare_bool_option:nn { \bool_new:c { g__ltjpreset_#1_bool } \bool_set_false:c { g__ltjpreset_#1_bool } @@ -100,6 +100,7 @@ mc .groups:n = { preset }, mc .value_required:n = true, mc-bx .code:n = \prop_put:Nnn \g__ltjpreset_font_prop { mc-b } {#1}, + mc-bx .groups:n = { preset }, mc-bx .value_required:n = true, gt .code:n = \prop_put:Nnn \g__ltjpreset_font_prop { gt-u } {#1} \prop_put:Nnn \g__ltjpreset_font_prop { gt-d } {#1} @@ -112,6 +113,7 @@ \prop_put:Nnn \g__ltjpreset_font_prop { gt-d } {#1}, gt .groups:n = { preset }, gt .value_required:n = true, gt-m .groups:n = { preset }, gt-m .value_required:n = true, + gt-bx .groups:n = { preset }, gt-bx .value_required:n = true, } \cs_set:Nn \ltjpreset_define_preset_prop:n { \keys_define:nn { luatexja-preset } { @@ -152,7 +154,7 @@ % 小塚 (Adobe) %% Pro -\ltjpreset_declare_preset:nx{kozuka-pro}{ +\ltjpreset_declare_preset:ne{kozuka-pro}{ mc-m = KozMinPro-Regular, mc-b = KozMinPro-Bold, gt-d = KozGoPro-Regular, gt-b = KozGoPro-Bold, gt-u = KozGoPro-Medium, gt-eb = KozGoPro-Heavy, @@ -160,7 +162,7 @@ __custom = false, __office = false, __noembed = false, } %% Pr6 -\ltjpreset_declare_preset:nx{kozuka-pr6}{ +\ltjpreset_declare_preset:ne{kozuka-pr6}{ mc-m = KozMinProVI-Regular, mc-b = KozMinProVI-Bold, gt-d = KozGoProVI-Regular, gt-b = KozGoProVI-Bold, gt-u = KozGoProVI-Medium, gt-eb = KozGoProVI-Heavy, @@ -168,7 +170,7 @@ __custom = false, __office = false, __noembed = false, } %% Pr6N -\ltjpreset_declare_preset:nx{kozuka-pr6n}{ +\ltjpreset_declare_preset:ne{kozuka-pr6n}{ mc-m = KozMinPr6N-Regular, mc-b = KozMinPr6N-Bold, gt-d = KozGoPr6N-Regular, gt-b = KozGoPr6N-Bold, gt-u = KozGoPr6N-Medium, gt-eb = KozGoPr6N-Heavy, @@ -177,14 +179,14 @@ } % ヒラギノ (OSX) -\ltjpreset_declare_preset:nx{hiragino-pro}{ +\ltjpreset_declare_preset:ne{hiragino-pro}{ mc-m = HiraMinPro-W3, mc-b = HiraMinPro-W6, gt-d = HiraKakuPro-W3, gt-b = HiraKakuPro-W6, gt-u = HiraKakuPro-W6, gt-eb = HiraKakuStd-W8, mg-m = HiraMaruPro-W4, mc-l = HiraMinPro-W2, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{hiragino-pron}{ +\ltjpreset_declare_preset:ne{hiragino-pron}{ mc-m = HiraMinProN-W3, mc-b = HiraMinProN-W6, gt-d = HiraKakuProN-W3, gt-b = HiraKakuProN-W6, gt-u = HiraKakuProN-W6, gt-eb = HiraKakuStdN-W8, @@ -193,21 +195,21 @@ } % モリサワ -\ltjpreset_declare_preset:nx{bizud}{ +\ltjpreset_declare_preset:ne{bizud}{ mc = BIZ-UDMinchoM.ttc, gt-d = BIZ-UDGothicR.ttc, gt-b = BIZ-UDGothicB.ttc, gt-u = BIZ-UDGothicR.ttc, gt-eb = BIZ-UDGothicB.ttc, mg-m = BIZ-UDGothicB.ttc, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{morisawa-pro}{ +\ltjpreset_declare_preset:ne{morisawa-pro}{ mc = A-OTF-RyuminPro-Light.otf, mc-b = A-OTF-FutoMinA101Pro-Bold.otf, gt-d = A-OTF-GothicBBBPro-Medium.otf , gt-b = A-OTF-FutoGoB101Pro-Bold.otf, gt-u = A-OTF-GothicBBBPro-Medium.otf , gt-eb = A-OTF-MidashiGoPro-MB31.otf, mg-m = A-OTF-Jun101Pro-Light.otf, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{morisawa-pr6n}{ +\ltjpreset_declare_preset:ne{morisawa-pr6n}{ mc = A-OTF-RyuminPr6N-Light.otf, mc-b = A-OTF-FutoMinA101Pr6N-Bold.otf, gt-d = A-OTF-GothicBBBPr6N-Medium.otf , gt-b = A-OTF-FutoGoB101Pr6N-Bold.otf, gt-u = A-OTF-GothicBBBPr6N-Medium.otf , gt-eb = A-OTF-MidashiGoPr6N-MB31.otf, @@ -216,7 +218,7 @@ } % 游明朝/游ゴシック (Win8.1) -\ltjpreset_declare_preset:nx{yu-win}{ +\ltjpreset_declare_preset:ne{yu-win}{ mc-m = YuMincho-Regular, mc-b = YuMincho-Demibold, gt-d = YuGothic-Regular, gt-b = YuGothic-Bold, gt-u = YuGothic-Regular, gt-eb = YuGothic-Bold, @@ -224,7 +226,7 @@ __custom = false, __office = false, __noembed = false, } % Win10 -\ltjpreset_declare_preset:nx{yu-win10}{ +\ltjpreset_declare_preset:ne{yu-win10}{ mc-m = YuMincho-Regular, mc-b = YuMincho-Demibold, gt-d = YuGothic-Regular, gt-b = YuGothic-Bold, gt-u = YuGothic-Medium, gt-eb = YuGothic-Bold, @@ -234,7 +236,7 @@ % Yu fonts in OSX % according to http://support.apple.com/kb/HT5944 -\ltjpreset_declare_preset:nx{yu-osx}{ +\ltjpreset_declare_preset:ne{yu-osx}{ mc = YuMincho~Medium, mc-b = YuMincho~Demibold, gt-d = YuGothic~Medium, gt-u = YuGothic~Medium, gt-b = YuGothic~Bold, gt-eb = YuGothic~Bold, @@ -243,14 +245,14 @@ } % moga-mobo -\ltjpreset_declare_preset:nx{moga-mobo}{ +\ltjpreset_declare_preset:ne{moga-mobo}{ mc = Moga90Mincho, mc-b = Moga90Mincho~Bold, gt-d = Moga90Gothic, gt-b = Moga90Gothic~Bold, gt-u = Moga90Gothic, gt-eb = Moga90Gothic~Bold, mg-m = Mobo90Gothic, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{moga-mobo-ex}{ +\ltjpreset_declare_preset:ne{moga-mobo-ex}{ mc = MogaEx90Mincho, mc-b = MogaEx90Mincho~Bold, gt-d = MogaEx90Gothic, gt-b = MogaEx90Gothic~Bold, gt-u = MogaEx90Gothic, gt-eb = MogaEx90Gothic~Bold, @@ -259,7 +261,7 @@ } % Ume fones -\ltjpreset_declare_preset:nx{ume}{ +\ltjpreset_declare_preset:ne{ume}{ mc = Ume~Mincho, gt-d = Ume~Gothic, gt-b = Ume~Gothic~O5, gt-u = Ume~Gothic~O5, gt-eb = Ume~Gothic~O5, @@ -268,7 +270,7 @@ } % Source Han {Serif,Sans} -\ltjpreset_declare_preset:nx{sourcehan}{ +\ltjpreset_declare_preset:ne{sourcehan}{ mc-m = Source~Han~Serif~Regular, mc-b = Source~Han~Serif~Bold, gt-d = Source~Han~Sans~Regular, @@ -279,7 +281,7 @@ mc-l = Source~Han~Serif~Light, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{sourcehan-jp}{ +\ltjpreset_declare_preset:ne{sourcehan-jp}{ mc-m = Source~Han~Serif~JP~Regular, mc-b = Source~Han~Serif~JP~Bold, gt-d = Source~Han~Sans~JP~Regular, @@ -290,7 +292,7 @@ mc-l = Source~Han~Serif~JP~Light, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{noto-otc}{ +\ltjpreset_declare_preset:ne{noto-otc}{ mc-m = Noto~Serif~CJK~Regular, mc-b = Noto~Serif~CJK~Bold, gt-d = Noto~Sans~CJK~Regular, @@ -301,7 +303,7 @@ mc-l = Noto~Serif~CJK~Light, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{noto-otf}{ +\ltjpreset_declare_preset:ne{noto-otf}{ mc-m = Noto~Serif~CJK~JP~Regular, mc-b = Noto~Serif~CJK~JP~Bold, gt-d = Noto~Sans~CJK~JP~Regular, @@ -312,10 +314,10 @@ mc-l = Noto~Serif~CJK~JP~Light, __custom = false, __office = false, __noembed = false, } -\ltjpreset_declare_preset:nx{noto}{ +\ltjpreset_declare_preset:ne{noto}{ noto-otf, } -\ltjpreset_declare_preset:nx{noto-jp}{ +\ltjpreset_declare_preset:ne{noto-jp}{ mc-m = Noto~Serif~JP~Regular, mc-b = Noto~Serif~JP~Bold, gt-d = Noto~Sans~JP~Regular, @@ -328,7 +330,7 @@ } % HaranoAji {Mincho, Gothic} -\ltjpreset_declare_preset:nx{haranoaji}{ +\ltjpreset_declare_preset:ne{haranoaji}{ mc-m = HaranoAjiMincho-Regular.otf, mc-b = HaranoAjiMincho-Bold.otf, gt-d = HaranoAjiGothic-Regular.otf, @@ -342,30 +344,30 @@ % ipa, ipaex, ms -\ltjpreset_declare_preset:nx{ipa}{ +\ltjpreset_declare_preset:ne{ipa}{ \__ltjpreset_set_uni:nn { IPAMincho } { IPAGothic } } -\ltjpreset_declare_preset:nx{ipaex}{ +\ltjpreset_declare_preset:ne{ipaex}{ \__ltjpreset_set_uni:nn { IPAExMincho } { IPAExGothic } } -\ltjpreset_declare_preset:nx{ms}{ +\ltjpreset_declare_preset:ne{ms}{ \__ltjpreset_set_uni:nn { MS-Mincho } { MS-Gothic } } % {ipa,ipaex,ms}-dx % Office 付属フォントを利用 -\ltjpreset_declare_preset:nx{ipaex-hg}{ +\ltjpreset_declare_preset:ne{ipaex-hg}{ \__ltjpreset_set_office:nn { IPAExMincho } { IPAExGothic } } -\ltjpreset_declare_preset:nx{ipa-hg}{ +\ltjpreset_declare_preset:ne{ipa-hg}{ \__ltjpreset_set_office:nn { IPAMincho } { IPAGothic } } -\ltjpreset_declare_preset:nx{ms-hg}{ +\ltjpreset_declare_preset:ne{ms-hg}{ \__ltjpreset_set_office:nn { MS-Mincho } { MS-Gothic } } % 非埋込 -\ltjpreset_declare_preset:nx{noembed}{ +\ltjpreset_declare_preset:ne{noembed}{ \__ltjpreset_set_uni:nn { Ryumin-Light } { GothicBBB-Medium }, __custom = false, __office = false, __noembed = true, } @@ -385,12 +387,12 @@ \bool_if:NF \g__ltjpreset_custom_bool { \tl_set:Nn \l_tmpa_tl {, CJKShape=JIS2004 } \tl_if_eq:NNT \l__ltjpreset_kanji_shape_tl \l_tmpa_tl { - \tl_set:Nx \l_tmpb_tl { \prop_item:Nn \g__ltjpreset_font_prop { mc-m } } + \tl_set:Ne \l_tmpb_tl { \prop_item:Nn \g__ltjpreset_font_prop { mc-m } } \tl_if_in:NnT \l_tmpb_tl { Moga90Mincho } { \prop_clear:N \l_tmpa_prop \prop_map_inline:Nn \g__ltjpreset_font_prop { \tl_set:Nn \l_tmpb_tl { ##2 } \tl_remove_all:Nn \l_tmpb_tl {90} - \prop_put:Nnx \l_tmpa_prop { ##1 } { \tl_use:N \l_tmpb_tl } + \prop_put:Nne \l_tmpa_prop { ##1 } { \tl_use:N \l_tmpb_tl } } \prop_set_eq:NN \g__ltjpreset_font_prop \l_tmpa_prop } @@ -398,44 +400,44 @@ \prop_clear:N \l_tmpa_prop \prop_map_inline:Nn \g__ltjpreset_font_prop { \tl_set:Nn \l_tmpb_tl { ##2 } \tl_remove_all:Nn \l_tmpb_tl {90} - \prop_put:Nnx \l_tmpa_prop { ##1 } { \tl_use:N \l_tmpb_tl } + \prop_put:Nne \l_tmpa_prop { ##1 } { \tl_use:N \l_tmpb_tl } } \prop_set_eq:NN \g__ltjpreset_font_prop \l_tmpa_prop } } } %%%% リストからの展開 - \cs_set:Nx \__ltjpreset_font_mc_l: { \prop_item:Nn \g__ltjpreset_font_prop { mc-l } } - \cs_set:Nx \__ltjpreset_font_mc_m: { \prop_item:Nn \g__ltjpreset_font_prop { mc-m } } - \cs_set:Nx \__ltjpreset_font_mc_b: { \prop_item:Nn \g__ltjpreset_font_prop { mc-b } } - \cs_set:Nx \__ltjpreset_font_gt_m: { \prop_item:Nn \g__ltjpreset_font_prop { gt-d } } - \cs_set:Nx \__ltjpreset_font_gt_u: { \prop_item:Nn \g__ltjpreset_font_prop { gt-u } } - \cs_set:Nx \__ltjpreset_font_gt_b: { \prop_item:Nn \g__ltjpreset_font_prop { gt-b } } - \cs_set:Nx \__ltjpreset_font_gt_eb: { \prop_item:Nn \g__ltjpreset_font_prop { gt-eb } } - \cs_set:Nx \__ltjpreset_font_mg_m: { \prop_item:Nn \g__ltjpreset_font_prop { mg-m } } + \cs_set:Ne \__ltjpreset_font_mc_l: { \prop_item:Nn \g__ltjpreset_font_prop { mc-l } } + \cs_set:Ne \__ltjpreset_font_mc_m: { \prop_item:Nn \g__ltjpreset_font_prop { mc-m } } + \cs_set:Ne \__ltjpreset_font_mc_b: { \prop_item:Nn \g__ltjpreset_font_prop { mc-b } } + \cs_set:Ne \__ltjpreset_font_gt_m: { \prop_item:Nn \g__ltjpreset_font_prop { gt-d } } + \cs_set:Ne \__ltjpreset_font_gt_u: { \prop_item:Nn \g__ltjpreset_font_prop { gt-u } } + \cs_set:Ne \__ltjpreset_font_gt_b: { \prop_item:Nn \g__ltjpreset_font_prop { gt-b } } + \cs_set:Ne \__ltjpreset_font_gt_eb: { \prop_item:Nn \g__ltjpreset_font_prop { gt-eb } } + \cs_set:Ne \__ltjpreset_font_mg_m: { \prop_item:Nn \g__ltjpreset_font_prop { mg-m } } %% HG 系フォント + JIS2004/90JIS のときはフォント名を置換 \bool_if:nT { !\g__ltjpreset_custom_bool && \g__ltjpreset_office_bool } { \tl_set:Nn \l_tmpa_tl {, CJKShape=JIS2004 } \tl_if_eq:NNT \l__ltjpreset_kanji_shape_tl \l_tmpa_tl { - \cs_set:Nx \__ltjpreset_font_mc_b: { hgrme04.ttc } - \cs_set:Nx \__ltjpreset_font_gt_b: { hgrge04.ttc } - \cs_set:Nx \__ltjpreset_font_gt_eb: { hgrsgu04.ttc } - \cs_set:Nx \__ltjpreset_font_mg_m: { hgrsmp04.ttf } + \cs_set:Ne \__ltjpreset_font_mc_b: { hgrme04.ttc } + \cs_set:Ne \__ltjpreset_font_gt_b: { hgrge04.ttc } + \cs_set:Ne \__ltjpreset_font_gt_eb: { hgrsgu04.ttc } + \cs_set:Ne \__ltjpreset_font_mg_m: { hgrsmp04.ttf } \cs_set_eq:NN \__ltjpreset_font_gt_m: \__ltjpreset_font_gt_u: % HG ゴシックM のときはそうはいかないので 1 ウェイト時のゴシック体を使う } \tl_set:Nn \l_tmpa_tl {, CJKShape=JIS1990 } \tl_if_eq:NNT \l__ltjpreset_kanji_shape_tl \l_tmpa_tl { - \cs_set:Nx \__ltjpreset_font_mc_b: { hgrme.ttc } - \cs_set:Nx \__ltjpreset_font_gt_b: { hgrge.ttc } - \cs_set:Nx \__ltjpreset_font_gt_eb: { hgrsgu.ttc } - \cs_set:Nx \__ltjpreset_font_mg_m: { hgrsmp.ttf } + \cs_set:Ne \__ltjpreset_font_mc_b: { hgrme.ttc } + \cs_set:Ne \__ltjpreset_font_gt_b: { hgrge.ttc } + \cs_set:Ne \__ltjpreset_font_gt_eb: { hgrsgu.ttc } + \cs_set:Ne \__ltjpreset_font_mg_m: { hgrsmp.ttf } } } % mc/l - \tl_set:Nx \l_tmpa_tl { \__ltjpreset_font_mc_l: } + \tl_set:Ne \l_tmpa_tl { \__ltjpreset_font_mc_l: } \tl_if_empty:NT \l_tmpa_tl {\tl_set:Nn \l_tmpa_tl {~}} - \cs_set:Nx \__ltjpreset_font_mc_l: { + \cs_set:Ne \__ltjpreset_font_mc_l: { \tl_if_blank:nTF \l_tmpa_tl { \__ltjpreset_font_mc_m: } {\tl_use:N \l_tmpa_tl } } %% bold オプションの処理 @@ -479,7 +481,7 @@ \__ltjpreset_wrap_fontname:e { \cs:w __ltjpreset_font_#1_#2: \cs_end: } \font \g__ltjpreset_font_test: = \l__ltjpreset_font_name:\relax \ifx \g__ltjpreset_font_test: \nullfont - \msg_warning:nnxxxx { luatexja-preset }{ no-font } + \msg_warning:nneeee { luatexja-preset }{ no-font } { \cs:w __ltjpreset_font_#1_#2: \cs_end: }{ #1/#2 } { \cs:w __ltjpreset_font_#3_#4: \cs_end: }{ #3/#4 } \cs_gset_eq:cc { __ltjpreset_font_#1_#2: } { __ltjpreset_font_#3_#4: } @@ -520,7 +522,7 @@ } \fp_compare:nNnF \Cjascale = 1 - { \msg_warning:nnx { luatexja-preset }{ scale }{ \Cjascale } } + { \msg_warning:nne { luatexja-preset }{ scale }{ \Cjascale } } % {1: encoding}{2: family}{3: series}{4: shape}{5: fontname}{6: feature}{7: scale} \cs_new:Nn \__ltjpreset_declare_font_shape:nnnnnnn { @@ -589,7 +591,7 @@ } \tl_set:Nn \l_tmpa_tl {, CJKShape=JIS2004 } \tl_if_eq:NNT \l__ltjpreset_kanji_shape_tl \l_tmpa_tl { - \tl_set:Nx \l__ltjpreset_kanji_shape_tl { ;+jp04 } + \tl_set:Ne \l__ltjpreset_kanji_shape_tl { ;+jp04 } } \__ltjpreset_define_family:nnn {mc} {m} {\__ltjpreset_font_mc_m:} \__ltjpreset_define_family:nnn {mc} {bx} {\__ltjpreset_font_mc_b:} @@ -610,7 +612,7 @@ } { \RequirePackage{luatexja-fontspec} % scale - \msg_warning:nnx { luatexja-preset }{ scale }{ \Cjascale } + \msg_warning:nne { luatexja-preset }{ scale }{ \Cjascale } \tl_new:N \l__ltjpreset_add_features_tl \bool_if:NT \g__ltjpreset_expert_bool { @@ -621,7 +623,7 @@ \addjfontfeature{ Kerning=Off } % 実際の fontspec の呼びだし \cs_new:Nn \__ltjpreset_do_fontset: { \group_begin: - \tl_gset:Nx \l__ltjpreset_add_features_tl { + \tl_gset:Ne \l__ltjpreset_add_features_tl { \tl_use:N \l__ltjpreset_kanji_shape_tl, YokoFeatures = { JFM = \tl_use:N \__ltjpreset_use_jfm_yoko_tl }, TateFeatures = { JFM = \tl_use:N \__ltjpreset_use_jfm_tate_tl }, diff --git a/macros/luatex/generic/luatexja/src/ltj-base.lua b/macros/luatex/generic/luatexja/src/ltj-base.lua index 2af3908554..e112dfa374 100644 --- a/macros/luatex/generic/luatexja/src/ltj-base.lua +++ b/macros/luatex/generic/luatexja/src/ltj-base.lua @@ -398,6 +398,19 @@ function ltjb.add_to_callback(name,fun,description,priority) return end +--- fix \e@alloc@luafunction@count (gh:5) +do + local t = lua.get_functions_table() + local m = 0 + local n = tex.getcount('e@alloc@luafunction@count') + for i = 1,math.max(n, #t)+100 do-- I think 100 is sufficient + if t[i] then m = i end + end + if m>n then + tex.setcount('global', 'e@alloc@luafunction@count', m) + end +end + -------------------- mock of debug logger if not ltjb.out_debug then local function no_op() end diff --git a/macros/luatex/generic/luatexja/src/luatexja.sty b/macros/luatex/generic/luatexja/src/luatexja.sty index 164c02d8d3..a54ede6758 100644 --- a/macros/luatex/generic/luatexja/src/luatexja.sty +++ b/macros/luatex/generic/luatexja/src/luatexja.sty @@ -27,7 +27,7 @@ \newif\ifltj@disablejfam %%%% VERSION -\def\LuaTeXjaversion{20240219.0} +\def\LuaTeXjaversion{20240514.0} %% Check if LaTeX is used. \begingroup\expandafter\expandafter\expandafter\endgroup diff --git a/macros/luatex/generic/luatexja/src/patches/lltjp-atbegshi.sty b/macros/luatex/generic/luatexja/src/patches/lltjp-atbegshi.sty index 12605ff11b..202cbf5857 100644 --- a/macros/luatex/generic/luatexja/src/patches/lltjp-atbegshi.sty +++ b/macros/luatex/generic/luatexja/src/patches/lltjp-atbegshi.sty @@ -3,11 +3,10 @@ % \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{lltjp-atbegshi}[2022-08-12 Patching \string\shipout\space hooks for LuaTeX-ja] +\ProvidesPackage{lltjp-atbegshi}[2024-05-14 Patching \string\shipout\space hooks for LuaTeX-ja] % concept: execute all hooks inside yoko direction \vbox -\ifltj@ltfilehook@avail %<*ltshipout>----------------------------------- % \RequirePackage{expl3} @@ -60,77 +59,4 @@ \fi: %</ltshipout>----------------------------------- \ExplSyntaxOff -\expandafter\endinput -\fi -\RequirePackage{atbegshi} -%<*atbegshi>------------------------------------- -% patching atbegshi.sty -%%% following codes are almost copied from -%%% pxatbegshi.sty 2019/09/07 v0.5 (in platex-tools bundle, by H. Yamashita). - -\ifdefined\AtBeginShipoutOriginalShipout - \let\AtBeginShipoutOriginalShipout\ltj@shipout -\fi -\AtBeginShipoutInit -\DeclareRobustCommand \AtBeginDvi [1]{% - \global \setbox \@begindvibox - \vbox{\yoko\unvbox \@begindvibox #1}% -} -%% internal macros are locally effective -\begingroup - -% helpers -%% unique tokens -\def\pxabgs@mark{\pxabgs@mark@} -\def\pxabgs@fin{\pxabgs@fin@} - -%% \pxabgs@patch@cmd\CMD{<orig>}{<new>} -\def\pxabgs@patch@cmd#1#2#3{% - \ifx#1\relax\else - \def\pxabgs@next##1#2##2\pxabgs@mark##3\pxabgs@fin{% - \ifx\pxabgs@mark##3\pxabgs@mark\let#1\relax - \else - \def\pxabgs@fragment{##2}\def#1{##1#3##2}% - \fi}% - \expandafter\pxabgs@next#1\pxabgs@mark#2\pxabgs@mark\pxabgs@fin - \fi -} - -% prepare -\ifdefined\AtBegShi@Output - \let\pxabgs@AtBegShi@Output\AtBegShi@Output -\else\let\pxabgs@AtBegShi@Output\relax\fi -% try first patch -\pxabgs@patch@cmd\pxabgs@AtBegShi@Output - {\let\AtBegShi@OrgProtect\protect}% - {\setbox8\vbox\bgroup\yoko\let\AtBegShi@OrgProtect\protect} -\pxabgs@patch@cmd\pxabgs@AtBegShi@Output - {\AtBeginShipoutOriginalShipout\box\AtBeginShipoutBox}% - {\AtBeginShipoutOriginalShipout\box\AtBeginShipoutBox\egroup\setbox8\box\voidb@x} -\pxabgs@patch@cmd\pxabgs@AtBegShi@Output - {% - \begingroup - \setbox\AtBeginShipoutBox\box\AtBeginShipoutBox - \endgroup - \let\protect\AtBegShi@OrgProtect - }{% - \begingroup - \setbox\AtBeginShipoutBox\box\AtBeginShipoutBox - \endgroup - \let\protect\AtBegShi@OrgProtect - \egroup - } -% commit the change only when successful -\ifx\pxabgs@AtBegShi@Output\relax - \@PackageWarningNoLine{lltjp-atbegshi}{% - Failed in patching \string\AtBegShi@Output.\MessageBreak - This may cause error in tate direction% - } -\else - \global\let\AtBegShi@Output\pxabgs@AtBegShi@Output -\fi - -\endgroup -%% internal macros are no longer effective -%</atbegshi>------------------------------------- \endinput diff --git a/macros/luatex/generic/luatexja/src/patches/lltjp-fontspec.sty b/macros/luatex/generic/luatexja/src/patches/lltjp-fontspec.sty index 589a3c5d6e..d688936c5f 100644 --- a/macros/luatex/generic/luatexja/src/patches/lltjp-fontspec.sty +++ b/macros/luatex/generic/luatexja/src/patches/lltjp-fontspec.sty @@ -35,7 +35,7 @@ { \fontspec_set_family:Nnn \l__fontspec_rmfamily_family_tl {#1} {#2} \tl_set_eq:NN \rmdefault \l__fontspec_rmfamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \rmfamily } { @@ -54,7 +54,7 @@ { \fontspec_set_family:Nnn \l__fontspec_sffamily_family_tl {#1} {#2} \tl_set_eq:NN \sfdefault \l__fontspec_sffamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \sffamily } { @@ -73,7 +73,7 @@ { \fontspec_set_family:Nnn \l__fontspec_ttfamily_family_tl {#1} {#2} \tl_set_eq:NN \ttdefault \l__fontspec_ttfamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \ttfamily } { @@ -94,7 +94,7 @@ { \fontspec_set_family:Nnn \l__fontspec_rmfamily_family_tl {#1} {#2} \tl_set_eq:NN \rmdefault \l__fontspec_rmfamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \rmfamily } { @@ -113,7 +113,7 @@ { \fontspec_set_family:Nnn \l__fontspec_sffamily_family_tl {#1} {#2} \tl_set_eq:NN \sfdefault \l__fontspec_sffamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \sffamily } { @@ -132,7 +132,7 @@ { \fontspec_set_family:Nnn \l__fontspec_ttfamily_family_tl {#1} {#2} \tl_set_eq:NN \ttdefault \l__fontspec_ttfamily_family_tl - \use:x + \use:e { \exp_not:n { \DeclareRobustCommand \ttfamily } { diff --git a/macros/luatex/generic/luatexja/src/patches/lltjp-unicode-math.sty b/macros/luatex/generic/luatexja/src/patches/lltjp-unicode-math.sty index 79ba8cbcf5..bc123e6784 100644 --- a/macros/luatex/generic/luatexja/src/patches/lltjp-unicode-math.sty +++ b/macros/luatex/generic/luatexja/src/patches/lltjp-unicode-math.sty @@ -46,9 +46,9 @@ % ltjsclasses: use lua \cs_new:Nn \lltjp_um_unmag_fsize: { - \cs_gset:Nx \lltjp_um_f@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\f@size)}} - \cs_gset:Nx \lltjp_um_sf@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\sf@size)}} - \cs_gset:Nx \lltjp_um_ssf@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\ssf@size)}} + \cs_gset:Ne \lltjp_um_f@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\f@size)}} + \cs_gset:Ne \lltjp_um_sf@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\sf@size)}} + \cs_gset:Ne \lltjp_um_ssf@size: {\directlua{luatexja.ltjs_unmagnify_fsize(\ssf@size)}} } }{ % bxjscls: use \jsc@preadjust@extract@font diff --git a/macros/luatex/generic/luavlna/README.md b/macros/luatex/generic/luavlna/README.md index 1fe76754d5..aeaf7d2bd0 100644 --- a/macros/luatex/generic/luavlna/README.md +++ b/macros/luatex/generic/luavlna/README.md @@ -1,4 +1,4 @@ -# Luavlna, version 0.1l, 2023-06-21 +# Luavlna, version 0.1m, 2024-05-02 # Introduction diff --git a/macros/luatex/generic/luavlna/luavlna-doc.pdf b/macros/luatex/generic/luavlna/luavlna-doc.pdf Binary files differindex a75499a3c9..7f80b780a7 100644 --- a/macros/luatex/generic/luavlna/luavlna-doc.pdf +++ b/macros/luatex/generic/luavlna/luavlna-doc.pdf diff --git a/macros/luatex/generic/luavlna/luavlna-doc.tex b/macros/luatex/generic/luavlna/luavlna-doc.tex index 470822d4ac..698f46e52d 100644 --- a/macros/luatex/generic/luavlna/luavlna-doc.tex +++ b/macros/luatex/generic/luavlna/luavlna-doc.tex @@ -87,7 +87,7 @@ Podpora iniciál a titulů: M. J. Hegel, Ing. Běháková, Ph.D., Ž. Zíbrt, Ch. Borner. Podpora jednotek: 100,5 MN\cdot{}s, 100.5 kJ, 200 µA, $-1$ dag, -12 MiB, 1 m$^3$/s. +12 MiB. Uvnitř matematiky by mělo být zpracování vypnuté: $k \in \mathbb N$. Pokračujeme v příkladu. @@ -113,7 +113,7 @@ Různé možnosti [v závorkách \textless i jiných znacích Podpora iniciál a titulů: M. J. Hegel, Ing. Běháková, Ph.D., Ž. Zíbrt, Ch. Borner. -Podpora jednotek: 100,5 MN\cdot{}s, 100.5 kJ, 200 µA, $-1$ dag, 12 MiB, 1 m$^3$/s. +Podpora jednotek: 100,5 MN\cdot{}s, 100.5 kJ, 200 µA, $-1$ dag, 12 MiB. Uvnitř matematiky by mělo být zpracování vypnuté: $k \in \mathbb N$. Pokračujeme v příkladu. @@ -298,7 +298,9 @@ File \verb|language.dat| is processed to load language names, aliases and assign local luatex = langno.load_languages(fmt) local t = {} for k, v in pairs(luatex.names) do - t[#t+1]=k + if k and k~="" then + t[#t+1]=k + end end table.sort(t) tex.print(table.concat(t,", ")) diff --git a/macros/luatex/generic/luavlna/luavlna-langno.lua b/macros/luatex/generic/luavlna/luavlna-langno.lua index f703e4328a..7f25d84100 100644 --- a/macros/luatex/generic/luavlna/luavlna-langno.lua +++ b/macros/luatex/generic/luavlna/luavlna-langno.lua @@ -58,7 +58,8 @@ local load_lang_dat = function(start) end local load_lang_dat_lualatex = function() - return load_lang_dat(1) + -- it used to be 1, but it seems that in newer LuaLaTeX versions, we should start at 0 + return load_lang_dat(0) end local load_csplain= function() diff --git a/macros/luatex/generic/luavlna/luavlna.lua b/macros/luatex/generic/luavlna/luavlna.lua index 416ecc5841..3e5f79346f 100644 --- a/macros/luatex/generic/luavlna/luavlna.lua +++ b/macros/luatex/generic/luavlna/luavlna.lua @@ -260,6 +260,15 @@ local is_unit = function(word) return false end +local function handle_unit(word, anchor) + -- insert nbsp between numbers and units + word = cut_off_end_chars(word, false) + if is_unit(word) then + anchor = replace_with_thin_space(anchor) + insert_penalty(anchor.prev) + end +end + local predegrees = Set (require "luavlna-predegrees") local sufdegrees = Set (require "luavlna-sufdegrees") @@ -299,11 +308,7 @@ local function prevent_single_letter (head) if wasnumber then if word ~= "" then wasnumber = false - word = cut_off_end_chars(word, false) - if is_unit(word) then - anchor = replace_with_thin_space(anchor) - insert_penalty(anchor.prev) - end + handle_unit(word, anchor) end elseif is_number(word) then wasnumber = true @@ -356,6 +361,10 @@ local function prevent_single_letter (head) end head = head.next end + -- insert spaces at the end of node list + if wasnumber then + handle_unit(word, anchor) + end return true end diff --git a/macros/luatex/generic/luavlna/luavlna.sty b/macros/luatex/generic/luavlna/luavlna.sty index 9f411c5f9f..b49ef89803 100644 --- a/macros/luatex/generic/luavlna/luavlna.sty +++ b/macros/luatex/generic/luavlna/luavlna.sty @@ -1,4 +1,4 @@ -\ProvidesPackage{luavlna}[2023-06-21 luavlna] +\ProvidesPackage{luavlna}[2024-05-02 luavlna] \ifdefined\directlua\else \PackageWarning{luavlna}{Luavlna needs LuaLaTeX, aborting} diff --git a/macros/luatex/generic/luavlna/luavlna.tex b/macros/luatex/generic/luavlna/luavlna.tex index d678854e9a..ddddf8ab9e 100644 --- a/macros/luatex/generic/luavlna/luavlna.tex +++ b/macros/luatex/generic/luavlna/luavlna.tex @@ -72,10 +72,15 @@ end % we can try to find the language ID from macros first, if it fails % we pass the language name to Lua. it will try to find ID in luanguage.dat and other sources \def\singlecharsgetlang#1{% - \ifcsname lang@#1\endcsname% - \the\csname lang@#1\endcsname% - \else% unknown language macro, let langno library to find it - #1% + \ifcsname l@#1\endcsname% + \the\csname l@#1\endcsname% + \else% + \ifcsname lang@#1\endcsname% + \the\csname lang@#1\endcsname% + \else% + % unknown language macro, let langno library to find it + #1% + \fi% \fi% } |