diff options
70 files changed, 6991 insertions, 779 deletions
diff --git a/doc/context/documents/general/manuals/canbedone-periods.pdf b/doc/context/documents/general/manuals/canbedone-periods.pdf Binary files differnew file mode 100644 index 000000000..0a292735d --- /dev/null +++ b/doc/context/documents/general/manuals/canbedone-periods.pdf diff --git a/doc/context/sources/general/manuals/canbedone/canbedone-periods.tex b/doc/context/sources/general/manuals/canbedone/canbedone-periods.tex new file mode 100644 index 000000000..3ddb4545c --- /dev/null +++ b/doc/context/sources/general/manuals/canbedone/canbedone-periods.tex @@ -0,0 +1,157 @@ +% language=us runpath=texruns:manuals/canbedone + +\environment canbedone-style + +% \showframe + +\startdocument + [title=periods, + color=middlered] + +\startsectionlevel[title=Introduction] + +When the \TEX\ program showed up there were not many fonts that could be used so +it came with its own fonts and because the number of slots in the encoding was +limited (first to 127, later to 255) there was no space characters. It was not +needed anyway because the engine uses a model of glue between words. So, instead +of fixed spacing, \TEX\ uses flexible spacing. In addition to what is normally +considered a word space, spacing is also determined by the so called space factor +of characters preceding spaces. But, especially after abbreviations with periods +you might want something different depending on the usage of the period. Here we +discuss how that can be done. + +\stopsectionlevel + +\startsectionlevel[title=Font related spacing] + +Spacing is controlled by the amount specified in the font in the so called +font dimensions. In \CONTEXT\ these can be accessed via macros: + +\starttabulate[||c|c|c|c|] +\BC \NC \tf normal space + \NC \bf bold space + \NC \it italic space + \NC \bi bolditalic space \NC \NR +\NC \tex{interwordspace} \NC {\tf \expandafter}\the\interwordspace + \NC {\bf \expandafter}\the\interwordspace + \NC {\it \expandafter}\the\interwordspace + \NC {\bi \expandafter}\the\interwordspace \NC \NR +\NC \tex{interwordstretch} \NC {\tf \expandafter}\the\interwordstretch + \NC {\bf \expandafter}\the\interwordstretch + \NC {\it \expandafter}\the\interwordstretch + \NC {\bi \expandafter}\the\interwordstretch \NC \NR +\NC \tex{interwordshrink} \NC {\tf \expandafter}\the\interwordshrink + \NC {\it \expandafter}\the\interwordshrink + \NC {\bi \expandafter}\the\interwordshrink + \NC {\bf \expandafter}\the\interwordshrink \NC \NR +\stoptabulate + +The differences in the three components are subtle but often of no concern to the +user. Stretch and shrink kicks in when we align the left and right edge, +otherwise they are basically ignored. These spacing properties are very specific +for \TEX\ fonts, they don't come with for instance \OPENTYPE\ fonts. There we +derive the stretch and shrink from the regular font space (\UNICODE\ slot U+00020 +or \ASCII\ value 32). + +A user can tweak the interword spacing with \type {\spaceskip} and \type +{\xspaceskip} which works together with the \type {\spacefactor} and (character +specific)\type {\sfcode} values. And as it is somewhat hard to explain the +details involved I just refer to Chapter~25 (Spacing) of \TEX\ by Topic. + +\stopsectionlevel + +\startsectionlevel[title=Spacing after periods] + +For this manual it's only important to know that the space factors influence the +spacing after uppercase letters and punctuation and the later aspect is what this +is about. + +\startbuffer[a] +\frenchspacing This is a t.e.s.t. for periods. Does it work? +\vskip-.8\lineheight +\nonfrenchspacing \blue This is a t.e.s.t. for periods. Does it work? +\stopbuffer + +\startbuffer[b] +\frenchspacing This is a t.e.s.t.\ for periods. Does it work? +\vskip-.8\lineheight +\nonfrenchspacing \green This is a t.e.s.t.\ for periods. Does it work? +\stopbuffer + +\startbuffer[c] +\frenchspacing This is a t.e.s.t\fsp. for periods. Does it work? +\vskip-.8\lineheight +\nonfrenchspacing \red This is a t.e.s.t\fsp. for periods. Does it work? +\stopbuffer + +\startbuffer[d] +\setperiodkerning[zerospaceperiods] +\frenchspacing This is a t.e.s.t. for periods. Does it work? +\vskip-.8\lineheight +\nonfrenchspacing \red This is a t.e.s.t. for periods. Does it work? +\stopbuffer + +\typebuffer[a] \start \forgetall \resetperiodkerning \getbuffer[a] \stop + +You will notice that the spacing after \type {t.e.s.t.} is as flexible as +the space after \type {periods.} but what if you don't want that? There are +several ways to influence the following space: + +\typebuffer[b] \start \forgetall \resetperiodkerning \getbuffer[b] \stop + +The \type {\fsp} macro looks ahead and adapts the space factor: + +\typebuffer[c] \start \forgetall \resetperiodkerning \getbuffer[c] \stop + +\stopsectionlevel + +\startsectionlevel[title=Automation] + +Where the manual (explicit) making sure we get spacing right is quite +robust and predictable a user might be willing to delegate the task to +\CONTEXT, and here is the trick: + +\typebuffer[d] \start \forgetall \resetperiodkerning \getbuffer[d] \stop + +This features has been present from mid 2017 but I admit that till now I never +used it. Reasons are that it makes no sense to adapt existing documents and when +a text is for instance meant for a user group journal too, you cannot expect this +automatic feature to be present in the macro package used for typesetting it. But +maybe it's time to change that policy. I also admit that I seldom have this +situation, probably the only few cases are abbreviations like \type {e.g.} (for +example) and \type {c.q.} (casu quo). + +There are a few predefined period kerning variants and you can define more if you +want: + +\starttyping +\defineperiodkerning [zerospaceperiods] [factor=0] +\defineperiodkerning [smallspaceperiods] [factor=.25] +\defineperiodkerning [halfspaceperiods] [factor=.5] +\stoptyping + +\startbuffer[e] +\setperiodkerning[zerospaceperiods] +\frenchspacing How about c.q. and e.g. within a sentence? +\vskip-.8\lineheight +\nonfrenchspacing \red How about c.q. and e.g. within a sentence? +\stopbuffer + +\typebuffer[e] \start \forgetall \getbuffer[e] \stop + +Of course one needs to keep an eye on the results because one never knows if the +heuristics are flawed. And if needed it can be improved. + +\stopsectionlevel + +\startsectionlevel[title=Todo] + +{\em more spacing related features} + +% optionalspace +% autoinsertspace +% ~ + +\stopsectionlevel + +\stopdocument diff --git a/doc/context/sources/general/manuals/canbedone/canbedone-style.tex b/doc/context/sources/general/manuals/canbedone/canbedone-style.tex new file mode 100644 index 000000000..bbcb6b46a --- /dev/null +++ b/doc/context/sources/general/manuals/canbedone/canbedone-style.tex @@ -0,0 +1,142 @@ +% language=us runpath=texruns:manuals/canbedone + +% I started this series in June 2023 when I found for the n\high{th} time that we +% already had a feature that users requested in the mailing list, but that I had +% completely forgotten about it being around for about 6 years. + +\startenvironment canbedone-style + +\usemodule[abbreviations-logos] +\usemodule[scite] + +\setvariables + [document] + [title=No Title, + author=No Author, + color=NoColor] + +\setupbodyfont + [dejavu,11pt] + +\setuplayout + [width=middle, + height=middle, + backspace=2cm, + topspace=15mm] + +\setupwhitespace + [big] + +\setuphead + [chapter] + [style=\bfc, + color=darkgray] + +\setuphead + [section] + [style=\bfb, + %page=right, + color=darkgray] + +\setuphead + [subsection] + [style=\bfa, + color=darkgray] + +\setuplist + [chapter] + [style=bold] + +\setupfootertexts + [section] % [\documentvariable{title}] + +\setupfooter + [style=bold, + color=darkgray] + +\startuseMPgraphic{titlepage} + fill Page + withcolor "\documentvariable{color}" ; + + numeric d ; d := 2mm ; + + picture p ; p := textext.llft("!") ; + p := p + rotatedaround(llcorner p, 30) % different from lowlevel + xysized (.1PaperWidth-2d,.1PaperHeight-2d) + shifted (.1PaperWidth- d,.1PaperHeight -d) + shifted (d,-2d) % different from lowlevel + ; + + draw image ( + for i = 0 step .1 PaperWidth until PaperWidth : + for j = 0 step .1 PaperHeight until PaperHeight : + draw p shifted (i,j) ; + endfor ; + endfor ; + ) withcolor .4resolvedcolor("middlegray") ; % different from lowlevel + + draw textext.d("\strut it can be done") + xsized (.8PaperWidth) + shifted center topboundary Page + shifted -(0,.2PaperHeight) + withcolor "white" ; + % draw textext.d("\strut YES") + draw textext.d("\strut \TeX") + xsized (.4PaperWidth) + shifted center topboundary Page + shifted -(0,.4PaperHeight) + withcolor "white" ; + draw textext.d("\strut\documentvariable{title}") + ysized 3cm + shifted center bottomboundary Page + shifted (0,.1PaperHeight) + withcolor "white" ; +\stopuseMPgraphic + +\definesectionlevels + [default] + [%{chapter,title}, + {section,subject}, + {subsection,subsubject}, + {subsubsection,subsubsubject}, + {subsubsubsection,subsubsubject}, + {subsubsubsubsection,subsubsubject}] + +\startsetups document:start + + \startMPpage + StartPage; + \includeMPgraphic{titlepage} ; + StopPage; + \stopMPpage + + \page + + \startsubjectlevel[title=Contents] + \placelist[chapter,section] [criterium=previous] + \stopsubjectlevel + +\stopsetups + +\startsetups document:stop + +\testpage[6] + +%startsubjectlevel[title=Colofon] +\startsectionlevel[title=Colofon,number=no,saveinlist=no] + + \starttabulate + \NC Author \NC Hans Hagen \NC \NR + \NC \CONTEXT \NC \contextversion \NC \NR + \NC \LUAMETATEX \NC \texengineversion \NC \NR + \NC Support \NC www.pragma-ade.com \NC \NR + \NC \NC contextgarden.net \NC \NR + \stoptabulate + +\stopsectionlevel +%stopsubjectlevel + +\stopsetups + +\stopenvironment diff --git a/doc/context/sources/general/manuals/canbedone/canbedone.tex b/doc/context/sources/general/manuals/canbedone/canbedone.tex new file mode 100644 index 000000000..6a2442f63 --- /dev/null +++ b/doc/context/sources/general/manuals/canbedone/canbedone.tex @@ -0,0 +1,29 @@ +% language=us runpath=texruns:manuals/canbedone + +\environment canbedone-style + +%D This is a bit if a cheat. The can be done manuals are independent but I want an +%D overview document on the website. Therefore we use sectionlevels in the documents +%D that we we then overload here (we push the chapter level in front). +%D +%D This style is mostly the same as the low level style. + +\starttext + + \definesectionlevels + [default] + [{chapter,title}, + {section,subject}, + {subsection,subsubject}, + {subsubsection,subsubsubject}, + {subsubsubsection,subsubsubject}, + {subsubsubsubsection,subsubsubject}] + + \startdocument[title=canbedone,color=middlegray] + \stopdocument + + \startsectionlevel[title=Periods] \component [canbedone-periods] \stopsectionlevel + +\stoptext + + diff --git a/doc/context/sources/general/manuals/lowlevel/lowlevel-macros.tex b/doc/context/sources/general/manuals/lowlevel/lowlevel-macros.tex index 00a438781..83e43818f 100644 --- a/doc/context/sources/general/manuals/lowlevel/lowlevel-macros.tex +++ b/doc/context/sources/general/manuals/lowlevel/lowlevel-macros.tex @@ -924,6 +924,17 @@ the hexadecimal numbers makes sense. It is unlikely that the core of \CONTEXT\ will use this option but sometimes at the user level it can be handy. The penalty in terms of performance can be neglected. +\starttyping[option=TEX] +\tolerant\def\foo#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=% + {(#1)(#2)(#3)(#4)(#5)(#6)(#7)(#8)(#9)(#A)(#B)(#C)(#D)(#E)(#F)} + +\foo{1}{2} +\stoptyping + +In the previous example we have 15 optional arguments where braces are mandate +(otherwise we the scanner happily scoops up what follows which for sure gives some +error). + \stopsectionlevel \startsectionlevel[title=Constants] diff --git a/doc/context/sources/general/manuals/lowlevel/lowlevel.tex b/doc/context/sources/general/manuals/lowlevel/lowlevel.tex index 10057b999..2d6898835 100644 --- a/doc/context/sources/general/manuals/lowlevel/lowlevel.tex +++ b/doc/context/sources/general/manuals/lowlevel/lowlevel.tex @@ -20,6 +20,8 @@ \startdocument[title=lowlevel,color=middlegray] \stopdocument + % this list is incomplete + \startsectionlevel[title=Conditionals] \component [lowlevel-conditionals] \stopsectionlevel \startsectionlevel[title=Boxes] \component [lowlevel-boxes] \stopsectionlevel \startsectionlevel[title=Expansion] \component [lowlevel-expansion] \stopsectionlevel @@ -35,6 +37,8 @@ \startsectionlevel[title=Inserts] \component [lowlevel-inserts] \stopsectionlevel \startsectionlevel[title=Localboxes] \component [lowlevel-localboxes] \stopsectionlevel \startsectionlevel[title=Loops] \component [lowlevel-loops] \stopsectionlevel + \startsectionlevel[title=Tokens] \component [lowlevel-tokens] \stopsectionlevel + \startsectionlevel[title=Buffers] \component [lowlevel-buffers] \stopsectionlevel \stoptext diff --git a/metapost/context/base/mpxl/mp-lmtx.mpxl b/metapost/context/base/mpxl/mp-lmtx.mpxl index edbc44bd2..e2a5b6fd1 100644 --- a/metapost/context/base/mpxl/mp-lmtx.mpxl +++ b/metapost/context/base/mpxl/mp-lmtx.mpxl @@ -662,7 +662,7 @@ vardef lmt_do_function = swap := getparameter "reverse" ; shape := getparameter "shape" ; close := getparameter "close" ; -axis := getparameter "axis" ; + axis := getparameter "axis" ; p := image ( if (getparametercount "functions") > 0 : for s = 1 upto getparametercount "functions" : @@ -1017,6 +1017,8 @@ presetparameters "chart" [ trace = false, showlabels = true, showlegend = true, + showvalues = false, + showaxis = false, center = false, samples = { }, @@ -1036,6 +1038,16 @@ presetparameters "chart" [ labelfraction = 0.8, labelcolor = "", + axisstyle = "", + axiscolor = "", + axisformat = "", + axislinewidth = mm/5, + axislinecolor = "", + + valuestyle = "", + valuecolor = "", + valueformat = "", + backgroundcolor = "", drawcolor = "white", fillcolors = { % use color palet @@ -1086,30 +1098,59 @@ def lmt_chart_bar = applyparameters "chart:bar" "lmt_do_chart_bar" def lmt_do_chart_start (expr what) = pushparameters what ; - save width, height, depth, distance, threshold, linewidth, linegap, labelgap, labelfraction, value, nofsamples, nofsamplesets ; - save fillcolor, linecolor, drawcolor, labelcolor, labelstyle, labelformat, labelstrut, labelanchor, colormode ; - string fillcolor, linecolor, drawcolor, labelcolor, labelstyle, labelformat, labelstrut, labelanchor, colormode ; + save width, height, depth, distance, + threshold, + linewidth, linegap, + value, nofsamples, nofsamplesets, + fillcolor, linecolor, drawcolor, + labelcolor, labelstyle, labelformat, labelgap, labelfraction, labelstrut, labelanchor, + axiscolor, axisstyle, axisformat, axisgap, axislinewidth, axislinecolor, + valuecolor, valuestyle, valueformat, valuegap, + colormode ; + string fillcolor, linecolor, drawcolor, + labelcolor, labelstyle, labelformat, labelstrut, labelanchor, + axiscolor, axisstyle, axisformat, axislinecolor, + valuecolor, valuestyle, valueformat, + colormode ; if hasparameter "sampleset" : setluaparameter what "samples" (getparameter "sampleset") ; fi ; - threshold := getparameter "threshold" ; - linewidth := getparameter "linewidth" ; - height := getparameter "height" ; - depth := max(getparameter "originsize", (getparameter "innerradius"), 8*linewidth) ; - width := getparameter "width" ; - distance := getparameter "distance" ; - linegap := getparameterdefault "linegap" linewidth ; - drawcolor := getparameter "drawcolor" ; - colormode := getparameter "colormode" ; - labelcolor := getparameter "labelcolor" ; - labelgap := getparameter "labeloffset" ; - labelstyle := getparameter "labelstyle" ; - labelformat := getparameter "labelformat" ; - labelstrut := getparameter "labelstrut" ; - labelanchor := getparameter "labelanchor" ; + + threshold := getparameter "threshold" ; + colormode := getparameter "colormode" ; + + linewidth := getparameter "linewidth" ; + linegap := getparameterdefault "linegap" linewidth ; + + height := getparameter "height" ; + depth := max(getparameter "originsize", (getparameter "innerradius"), 8*linewidth) ; + width := getparameter "width" ; + distance := getparameter "distance" ; + + drawcolor := getparameter "drawcolor" ; + + labelcolor := getparameter "labelcolor" ; + labelstyle := getparameter "labelstyle" ; + labelformat := getparameter "labelformat" ; + labelgap := getparameter "labeloffset" ; + labelstrut := getparameter "labelstrut" ; + labelanchor := getparameter "labelanchor" ; labelfraction := getparameter "labelfraction" ; + + axiscolor := getparameter "axiscolor" ; + axisstyle := getparameter "axisstyle" ; + axisformat := getparameter "axisformat" ; + axisgap := getparameter "axisoffset" ; + axislinewidth := getparameter "axislinewidth" ; + axislinecolor := getparameter "axislinecolor" ; + + valuecolor := getparameter "valuecolor" ; + valuestyle := getparameter "valuestyle" ; + valueformat := getparameter "valueformat" ; + valuegap := getparameter "valueoffset" ; + nofsamplesets := getparametercount "samples" ; - nofsamples := getmaxparametercount "samples" ; + nofsamples := getmaxparametercount "samples" ; enddef ; def lmt_do_chart_stop = diff --git a/source/luametatex/source/lua/lmtnodelib.c b/source/luametatex/source/lua/lmtnodelib.c index 6a07e3454..72b9918e4 100644 --- a/source/luametatex/source/lua/lmtnodelib.c +++ b/source/luametatex/source/lua/lmtnodelib.c @@ -5321,15 +5321,19 @@ static int nodelib_direct_patchattributes(lua_State *L) return 0; } +/* firstnode attributeid [nodetype] */ + static int nodelib_direct_findattribute(lua_State *L) /* returns attr value and node */ { halfword c = nodelib_valid_direct_from_index(L, 1); if (c) { halfword i = lmt_tohalfword(L, 2); + halfword t = lmt_optinteger(L, 3, -1); while (c) { - if (tex_nodetype_has_attributes(node_type(c))) { + if ((t < 0 || node_type(c) == t) && tex_nodetype_has_attributes(node_type(c))) { halfword p = node_attr(c); if (p) { + /* we could skip if the previous value is the same and didn't match */ p = node_next(p); while (p) { if (attribute_index(p) == i) { @@ -5757,6 +5761,8 @@ static int nodelib_direct_traversechar(lua_State *L) } } +/* maybe a variant that checks for an attribute */ + static int nodelib_direct_aux_next_glyph(lua_State *L) { halfword t; diff --git a/source/luametatex/source/lua/lmttokenlib.c b/source/luametatex/source/lua/lmttokenlib.c index dcd17b53e..5259a1478 100644 --- a/source/luametatex/source/lua/lmttokenlib.c +++ b/source/luametatex/source/lua/lmttokenlib.c @@ -3797,6 +3797,7 @@ int lmt_function_call_by_category(int slot, int property, halfword *value) } case lua_value_integer_code: { + /* expects valid integer, no double */ *value = lua_type(L, -1) == LUA_TNUMBER ? lmt_tohalfword(L, -1) : 0; if (*value < - max_integer) { *value = max_integer; @@ -3807,6 +3808,7 @@ int lmt_function_call_by_category(int slot, int property, halfword *value) } case lua_value_cardinal_code: { + /* expects valid integer, no double */ lua_Unsigned u = lua_type(L, -1) == LUA_TNUMBER ? (lua_Unsigned) lua_tointeger(L, -1) : 0; if (u > max_cardinal) { u = max_cardinal; @@ -3820,7 +3822,8 @@ int lmt_function_call_by_category(int slot, int property, halfword *value) } case lua_value_dimension_code: { - *value = lua_type(L, -1) == LUA_TNUMBER ? lmt_tohalfword(L, -1) : 0; + /* accepts double and rounds it */ + *value = lua_type(L, -1) == LUA_TNUMBER ? lmt_roundnumber(L, -1) : 0; if (*value < - max_dimen) { *value = max_dimen; } else if (*value > max_dimen) { diff --git a/source/luametatex/source/luametatex.h b/source/luametatex/source/luametatex.h index c26810396..19175a487 100644 --- a/source/luametatex/source/luametatex.h +++ b/source/luametatex/source/luametatex.h @@ -76,12 +76,15 @@ 2.09.35 : near the end of 2021 (so close to the 2.10 release date) 2.09.55 : in July 2022 (the official release of the new math engine) 2.10.00 : a few days before the ctx 2022 meeting (starting September 19) - 2.10.01 : mid October 2022 + 2.10.01 : mid October 2022 (some more upgrades of the math engine) + 2.10.05 : late January 2023 At some point the \CONTEXT\ group will be responsible for guaranteeing that the official version is what comes with \CONTEXT\ and that long term support and stabilty is guaranteed and that no feature creep or messing up happens. We'll see. + Hans Hagen + */ # include "tex/textypes.h" @@ -89,7 +92,7 @@ # define luametatex_version 210 # define luametatex_revision 06 # define luametatex_version_string "2.10.06" -# define luametatex_development_id 20230126 +# define luametatex_development_id 20230209 # define luametatex_name_camelcase "LuaMetaTeX" # define luametatex_name_lowercase "luametatex" diff --git a/source/luametatex/source/tex/texmlist.c b/source/luametatex/source/tex/texmlist.c index d7c37e47a..8409f8df3 100644 --- a/source/luametatex/source/tex/texmlist.c +++ b/source/luametatex/source/tex/texmlist.c @@ -6361,7 +6361,7 @@ static void tex_mlist_to_hlist_preroll_radicals(mliststate *state) } else if (radical_height(current) < 0) { box_height(body) += radical_height(current); if (box_height(body) < 0) { - box_height(body) += 0; + box_height(body) = 0; } } else if (radical_height(current)) { box_height(body) = radical_height(current); @@ -6371,7 +6371,7 @@ static void tex_mlist_to_hlist_preroll_radicals(mliststate *state) } else if (radical_depth(current) < 0) { box_depth(body) += radical_depth(current); if (box_depth(body) < 0) { - box_depth(body) += 0; + box_depth(body) = 0; } } else if (radical_depth(current)) { box_depth(body) = radical_depth(current); diff --git a/source/luametatex/source/tex/texscanning.c b/source/luametatex/source/tex/texscanning.c index 08d5cdaa0..23fc29d1c 100644 --- a/source/luametatex/source/tex/texscanning.c +++ b/source/luametatex/source/tex/texscanning.c @@ -3550,7 +3550,7 @@ static void tex_aux_too_many_parameters_error(void) { tex_handle_error( normal_error_type, - "You already have nine parameters", + "You already have 15 parameters", "I'm going to ignore the # sign you just used, as well the token that followed it.\n" /*tex That last bit was added in the TeX 2021 buglet fix round. */ ); @@ -3607,7 +3607,9 @@ static void tex_aux_illegal_parameter_in_body_error(void) \stoptyping */ -inline static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfword *hash_brace) +/* There is no real gain and we get a 1K larger binary: */ /* inline */ + +static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfword *hash_brace) { halfword h = *p; while (1) { @@ -3633,9 +3635,9 @@ inline static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfwo *p = tex_store_new_token(*p, cur_tok); *p = tex_store_new_token(*p, end_match_token); set_token_preamble(h, 1); - set_token_parameters(h, *counter - zero_token); + set_token_parameters(h, *counter); return 1; - } else if (*counter == F_token_l) { + } else if (*counter == 0xF) { tex_aux_too_many_parameters_error(); } else { switch (cur_tok) { @@ -3688,17 +3690,21 @@ inline static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfwo cur_tok = par_command_match_token; break; default: - ++*counter; - if (cur_tok != *counter) { - if (cur_tok >= A_token_l && cur_tok <= F_token_l) { - *counter += gap_match_count; + if (cur_tok >= one_token && cur_tok <= nine_token) { + ++*counter; + if ((cur_tok - other_token - '0') == *counter) { + cur_tok += match_token - other_token ; + break; + } + } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) { + ++*counter; + if ((cur_tok - letter_token - 'A' - gap_match_count) == *counter) { cur_tok += match_token - letter_token; break; - } else { - tex_aux_parameters_order_error(); } } - cur_tok += match_token - other_token; + tex_aux_parameters_order_error(); + cur_tok = match_token; /* zero */ break; } } @@ -3710,7 +3716,7 @@ inline static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfwo if (h != *p) { *p = tex_store_new_token(*p, end_match_token); set_token_preamble(h, 1); - set_token_parameters(h, *counter - zero_token); + set_token_parameters(h, *counter); } if (cur_cmd == right_brace_cmd) { ++lmt_input_state.align_state; @@ -3724,7 +3730,7 @@ inline static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfwo halfword tex_scan_macro_normal(void) { halfword hash_brace = 0; - halfword counter = zero_token; + halfword counter = 0; halfword result = get_reference_token(); halfword p = result; lmt_input_state.scanner_status = scanner_is_defining; @@ -3748,16 +3754,22 @@ halfword tex_scan_macro_normal(void) tex_get_token(); if (cur_cmd == parameter_cmd) { /*tex Keep the |#|. */ - } else if (cur_tok <= zero_token || cur_tok > counter) { - if (cur_tok >= A_token_l && cur_tok <= F_token_l) { - cur_tok = token_val(parameter_reference_cmd, cur_chr - '0' - gap_match_count); + } else { + halfword n; + if (cur_tok >= one_token && cur_tok <= nine_token) { + n = cur_chr - '0'; + } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) { + n = cur_chr - '0' - gap_match_count; + } else { + n = counter + 1; + } + if (n <= counter) { + cur_tok = token_val(parameter_reference_cmd, n); } else { tex_aux_illegal_parameter_in_body_error(); cur_tok = s; } - } else { - cur_tok = token_val(parameter_reference_cmd, cur_chr - '0'); - } + } } else if (cur_cmd == prefix_cmd && cur_chr == enforced_code && (! overload_mode_par || lmt_main_state.run_state != production_state)) { /* todo cur_tok == let_aliased_token */ cur_tok = token_val(prefix_cmd, always_code); } @@ -3777,7 +3789,7 @@ halfword tex_scan_macro_normal(void) halfword tex_scan_macro_expand(void) { halfword hash_brace = 0; - halfword counter = zero_token; + halfword counter = 0; halfword result = get_reference_token(); halfword p = result; lmt_input_state.scanner_status = scanner_is_defining; @@ -3830,15 +3842,21 @@ halfword tex_scan_macro_expand(void) tex_get_x_token(); if (cur_cmd == parameter_cmd) { /*tex Keep the |#|. */ - } else if (cur_tok <= zero_token || cur_tok > counter) { - if (cur_tok >= A_token_l && cur_tok <= F_token_l) { - cur_tok = token_val(parameter_reference_cmd, cur_chr - '0' - gap_match_count); + } else { + halfword n; + if (cur_tok >= one_token && cur_tok <= nine_token) { + n = cur_chr - '0'; + } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) { + n = cur_chr - '0' - gap_match_count; + } else { + n = counter + 1; + } + if (n <= counter) { + cur_tok = token_val(parameter_reference_cmd, n); } else { tex_aux_illegal_parameter_in_body_error(); cur_tok = s; } - } else { - cur_tok = token_val(parameter_reference_cmd, cur_chr - '0'); } goto APPENDTOKEN; } diff --git a/source/luametatex/source/tex/textoken.h b/source/luametatex/source/tex/textoken.h index 345c04c23..20885ee66 100644 --- a/source/luametatex/source/tex/textoken.h +++ b/source/luametatex/source/tex/textoken.h @@ -213,6 +213,7 @@ extern token_state_info lmt_token_state; # define left_parent_token (other_token + '(') # define right_parent_token (other_token + ')') # define zero_token (other_token + '0') /*tex zero, the smallest digit */ +# define one_token (other_token + '1') # define five_token (other_token + '5') # define seven_token (other_token + '7') # define nine_token (other_token + '9') /*tex zero, the smallest digit */ diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index c61c97d8a..736e64033 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2023.02.07 19:02} +\newcontextversion{2023.02.14 17:41} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index b62aa3a85..3337f07f0 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2023.02.07 19:02} +\edef\contextversion{2023.02.14 17:41} %D For those who want to use this: diff --git a/tex/context/base/mkiv/buff-ini.lua b/tex/context/base/mkiv/buff-ini.lua index 9af76f72e..f23344eda 100644 --- a/tex/context/base/mkiv/buff-ini.lua +++ b/tex/context/base/mkiv/buff-ini.lua @@ -816,7 +816,7 @@ local function getbuffermkvi(name) -- rather direct ! ctx_viafile(resolvers.macros.preprocessed(getcontent(name)),formatters["buffer.%s.mkiv"](validstring(name,"noname"))) end -local function gettexbuffer(name) +local function getbuffertex(name) local buffer = name and cache[name] if buffer and buffer.data ~= "" then ctx_pushcatcodetable() @@ -831,15 +831,15 @@ local function gettexbuffer(name) end end -buffers.get = getbuffer -buffers.getmkiv = getbuffermkiv -buffers.gettexbuffer = gettexbuffer -buffers.run = runbuffer +buffers.get = getbuffer +buffers.getmkvi = getbuffermkvi +buffers.gettex = getbuffertex +buffers.run = runbuffer implement { name = "getbufferctxlua", actions = loadcontent, arguments = "string" } implement { name = "getbuffer", actions = getbuffer, arguments = "string" } implement { name = "getbuffermkvi", actions = getbuffermkvi, arguments = "string" } -implement { name = "gettexbuffer", actions = gettexbuffer, arguments = "string" } +implement { name = "getbuffertex", actions = getbuffertex, arguments = "string" } interfaces.implement { name = "getbuffercontent", diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index d524240e6..b525836df 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2023.02.07 19:02} +\newcontextversion{2023.02.14 17:41} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 1e3ce084e..a5e343291 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -49,7 +49,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2023.02.07 19:02} +\edef\contextversion{2023.02.14 17:41} %D Kind of special: diff --git a/tex/context/base/mkiv/regi-ini.lua b/tex/context/base/mkiv/regi-ini.lua index 8d4f2bfd5..2a3b2caaf 100644 --- a/tex/context/base/mkiv/regi-ini.lua +++ b/tex/context/base/mkiv/regi-ini.lua @@ -16,7 +16,6 @@ runtime.</p> local commands, context = commands, context - local tostring = tostring local utfchar = utf.char local P, Cs, Cc, lpegmatch = lpeg.P, lpeg.Cs, lpeg.Cc, lpeg.match diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex cf4d8480a..70fe4d224 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex 258228978..9540ac450 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/tabl-xtb.mkvi b/tex/context/base/mkiv/tabl-xtb.mkvi index 3f3ef4be3..c340efdfa 100644 --- a/tex/context/base/mkiv/tabl-xtb.mkvi +++ b/tex/context/base/mkiv/tabl-xtb.mkvi @@ -267,7 +267,7 @@ }% else whitespace mess \def\tabl_x_get_buffer - {\clf_gettexbuffer{\tabl_x_current_buffer}} + {\clf_getbuffertex{\tabl_x_current_buffer}} \let\tabl_x_start_row_yes \relax \let\tabl_x_start_row_nop \relax diff --git a/tex/context/base/mkxl/back-imp-lua.mkxl b/tex/context/base/mkxl/back-imp-lua.mkxl index db26657ef..641123842 100644 --- a/tex/context/base/mkxl/back-imp-lua.mkxl +++ b/tex/context/base/mkxl/back-imp-lua.mkxl @@ -11,6 +11,6 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\registerctxluafile{back-imp-lua}{autosuffix,optimize} +\registerctxluafile{back-imp-lua}{autosuffix} \endinput diff --git a/tex/context/base/mkxl/back-imp-mps.mkxl b/tex/context/base/mkxl/back-imp-mps.mkxl index 45dde7e36..bda053706 100644 --- a/tex/context/base/mkxl/back-imp-mps.mkxl +++ b/tex/context/base/mkxl/back-imp-mps.mkxl @@ -11,6 +11,6 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\registerctxluafile{back-imp-mps}{autosuffix,optimize} +\registerctxluafile{back-imp-mps}{autosuffix} \endinput diff --git a/tex/context/base/mkxl/buff-ini.lmt b/tex/context/base/mkxl/buff-ini.lmt index 1d4722531..9f5535638 100644 --- a/tex/context/base/mkxl/buff-ini.lmt +++ b/tex/context/base/mkxl/buff-ini.lmt @@ -88,12 +88,19 @@ local buffers = buffers local cache = { } local function erase(name) - cache[name] = nil + if not name or name == "" then + cache[""] = false -- nil + else + local list = settings_to_array(name) + for i=1,#list do + cache[list[i]] = false -- nil + end + end end local assign do - -- Ther eis no gain in an immediate concatenating lpeg + -- There is no gain in an immediate concatenating lpeg local action = whitespace^0 * C(P("+")^1 + P("*")) * whitespace^0 local equal = whitespace^0 * patterns.equal * whitespace^0 @@ -708,12 +715,17 @@ local function runbuffer(name,encapsulate,runnername,suffixes) end local f_getbuffer = formatters["buffer.%s"] +local defaultlist = { "" } local function getbuffer(name) - local str = getcontent(name) - if str ~= "" then - -- characters.showstring(str) - ctx_viafile(str,f_getbuffer(validstring(name,"noname"))) + local list = name and name ~= "" and settings_to_array(name) or defaultlist + for i=1,#list do + local buf = list[i] + local str = getcontent(buf) + if str ~= "" then + -- characters.showstring(str) + ctx_viafile(str,f_getbuffer(validstring(buf,"noname"))) + end end end @@ -721,7 +733,7 @@ local function getbuffermkvi(name) -- rather direct ! ctx_viafile(resolvers.macros.preprocessed(getcontent(name)),formatters["buffer.%s.mkiv"](validstring(name,"noname"))) end -local function gettexbuffer(name) +local function getbuffertex(name) local buffer = name and cache[name] if buffer and buffer.data ~= "" then ctx_pushcatcodetable() @@ -736,15 +748,16 @@ local function gettexbuffer(name) end end -buffers.get = getbuffer -buffers.getmkiv = getbuffermkiv -buffers.gettexbuffer = gettexbuffer -buffers.run = runbuffer +buffers.get = getbuffer +buffers.getmkvi = getbuffermkvi +buffers.gettex = getbuffertex +buffers.getctxlua = loadcontent +buffers.run = runbuffer -implement { name = "getbufferctxlua", actions = loadcontent, arguments = "string" } -implement { name = "getbuffer", actions = getbuffer, arguments = "string" } -implement { name = "getbuffermkvi", actions = getbuffermkvi, arguments = "string" } -implement { name = "gettexbuffer", actions = gettexbuffer, arguments = "string" } +implement { name = "getbufferctxlua", actions = loadcontent, arguments = "argument" } +implement { name = "getbuffer", actions = getbuffer, arguments = "argument" } +implement { name = "getbuffermkvi", actions = getbuffermkvi, arguments = "argument" } +implement { name = "getbuffertex", actions = getbuffertex, arguments = "argument" } interfaces.implement { name = "getbuffercontent", diff --git a/tex/context/base/mkxl/buff-ini.mkxl b/tex/context/base/mkxl/buff-ini.mkxl index d192a01ea..0bc4d665f 100644 --- a/tex/context/base/mkxl/buff-ini.mkxl +++ b/tex/context/base/mkxl/buff-ini.mkxl @@ -107,9 +107,9 @@ \permanent\tolerant\protected\def\setbuffer[#1]#:#2\endbuffer % seldom used so we just pass #2 {\clf_assignbuffer{#1}{\detokenize{#2}}\catcodetable\relax} -% beware, never adapt the global buffer settings, actually we might introduce +% Beware, never adapt the global buffer settings, actually we might introduce % a broken parent chain for this purpose but on the other hand it's not that -% different from framed cum suis +% different from framed cum suis. \installcorenamespace{buffer} @@ -143,35 +143,40 @@ \permanent\def\thebuffernumber #1{\namedbufferparameter{#1}\c!number} \permanent\def\thedefinedbuffer#1{def-\namedbufferparameter{#1}\c!number} -\permanent\tolerant\protected\def\getbuffer[#1]% [name] +\permanent\def\getbufferdata[#1]% expandable + {\clf_getbuffer{#1}} + +\permanent\tolerant\protected\def\getbuffer[#1]% [namelist] {\namedbufferparameter\empty\c!before\relax - \doifelsenothing{#1} - {\buff_get_stored_indeed\empty} - {\processcommalist[#1]\buff_get_stored_indeed}% + \clf_getbuffer{#1}% \namedbufferparameter\empty\c!after\relax} \protected\def\buff_get_stored#1#2% {\namedbufferparameter{#1}\c!before\relax - \buff_get_stored_indeed{#2}% + \clf_getbuffer{#2}% \namedbufferparameter{#1}\c!after\relax} -\protected\def\buff_get_stored_indeed#1% - {\clf_getbuffer{#1}} +\aliased\let\rawbuffer\clf_getbuffer % expandable \permanent\protected\def\getdefinedbuffer[#1]% {\buff_get_stored{#1}{\thedefinedbuffer{#1}}}% -\permanent\tolerant\protected\def\inlinebuffer[#1]% [name] - {\doifelsenothing{#1} - {\buff_get_stored_inline_indeed\empty} - {\processcommalist[#1]\buff_get_stored_inline_indeed}} +% We had this: +% +% \permanent\tolerant\protected\def\inlinebuffer[#1]% [name] +% {\doifelsenothing{#1} +% {\buff_get_stored_inline_indeed\empty} +% {\processcommalist[#1]\buff_get_stored_inline_indeed}} +% +% \protected\def\buff_get_stored_inline_indeed#1% +% {\ignorespaces\clf_getbuffer{#1}\removeunwantedspaces} +% +% but it makes no sense to ignore spaces in between and we now do the +% list at the \LUA\ end anyway: -\protected\def\buff_get_stored_inline_indeed#1% +\permanent\tolerant\protected\def\inlinebuffer[#1]% [name] {\ignorespaces\clf_getbuffer{#1}\removeunwantedspaces} -\permanent\def\rawbuffer#1% expandable - {\clf_getbuffer{#1}} - \definebuffer [\v!hiding] @@ -180,20 +185,14 @@ [\c!before=, \c!after=] -\permanent\protected\protected\def\processTEXbuffer[#1]% keep case, maybe also lower - {\pushcatcodetable - \catcodetable\ctxcatcodes % \setcatcodetable - \buff_get_stored_indeed{#1}% - \popcatcodetable} - -% only mkiv: -% -% \startbuffer[x] -% x -% \stopbuffer -% -% \savebuffer[x] [temp] % gets name: jobname-temp.tmp -% \savebufferinfile[x][temp.log] % gets name: temp.log +%D \starttyping +%D \startbuffer[x] +%D x y z +%D \stopbuffer +%D +%D \savebuffer[x] [temp] % gets name: jobname-temp.tmp +%D \savebufferinfile[x][temp.log] % gets name: temp.log +%D \stoptyping \installcorenamespace{savebuffer} \installcorenamespace{savebuffercounter} @@ -242,6 +241,9 @@ %D \stoptext %D \stoptyping +% We can keep the counter at the lua end and explicitly reset it when we +% save. + \appendtoks \ifcsname\e!stop\currentsavebuffer\endcsname\else \definebuffer[\currentsavebuffer]% @@ -272,8 +274,15 @@ % % \ctxluabuffer[what] \ctxluabuffer -\permanent\tolerant\protected\def\ctxluabuffer[#1]{\clf_getbufferctxlua{#1}} % todo: use public implementor -\permanent\tolerant\protected\def\mkvibuffer [#1]{\clf_getbuffermkvi {#1}} % todo: use public implementor +\permanent\tolerant\protected\def\processTEXbuffer[#1]#;#=% keep case, maybe also lower + {\pushcatcodetable + \catcodetable\ctxcatcodes % \setcatcodetable + \clf_getbuffer{#1#2}% + \popcatcodetable} + +\permanent\tolerant\protected\def\ctxluabuffer[#1]#;#={\clf_getbufferctxlua{#1#2}} % todo: use public implementor +\permanent\tolerant\protected\def\mkvibuffer [#1]#;#={\clf_getbuffermkvi {#1#2}} % todo: use public implementor +\permanent\tolerant\protected\def\texbuffer [#1]#;#={\clf_getbuffertex {#1#2}} % todo: use public implementor % maybe still used elsewhere @@ -281,10 +290,6 @@ \aliased\let\dostartbuffer\grabbufferdata % for old times sake, this will go away -% new (expandable): - -\permanent\def\getbufferdata[#1]{\buff_get_stored_indeed{#1}} - % low level helper (for math manual): % \showboxinbuffer{temp}<boxnumber><detail> % defined in lua, detail cf \shownodedetails 0|1|2 diff --git a/tex/context/base/mkxl/buff-ver.mkxl b/tex/context/base/mkxl/buff-ver.mkxl index 461807162..8c42694a3 100644 --- a/tex/context/base/mkxl/buff-ver.mkxl +++ b/tex/context/base/mkxl/buff-ver.mkxl @@ -31,7 +31,6 @@ \installcorenamespace{typinglines} \installcorenamespace{typingspace} -\installcorenamespace{typingblank} % needs checking ... used? \newtoks\everyinitializeverbatim @@ -58,14 +57,6 @@ \defcsname\??typingspace\v!fixed \endcsname{\enforced\let\obeyedspace\specialfixedspace} \defcsname\??typingspace\v!character \endcsname{\enforced\chardef\obeyedspace\spaceasciicode} -\defcsname\??typingblank\v!standard \endcsname{\s_spac_whitespace_parskip} -\defcsname\??typingblank\v!small \endcsname{\smallskipamount} -\defcsname\??typingblank\v!medium \endcsname{\medskipamount} -\defcsname\??typingblank\v!big \endcsname{\bigskipamount} -\defcsname\??typingblank\v!halfline \endcsname{.5\baselineskip} -\defcsname\??typingblank\v!line \endcsname{\baselineskip} -\defcsname\??typingblank\v!none \endcsname{\zeropoint} - \protected\def\buff_verbatim_obey_hyphens {} @@ -109,12 +100,10 @@ \def\buff_verbatim_initialize_typing_one {\usebodyfontparameter\typingparameter - \scratchskip\typingparameter\c!oddmargin\relax - \ifzeropt\scratchskip \else + \ifzerodim\typingparameter\c!oddmargin\else \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed \fi - \scratchskip\typingparameter\c!evenmargin\relax - \ifzeropt\scratchskip \else + \ifzerodim\typingparameter\c!evenmargin\else \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed \fi \ifrelax\buff_verbatim_set_line_margin @@ -289,8 +278,8 @@ \futureexpand\bgroup\buff_verbatim_type_a\buff_verbatim_type_one} \def\buff_verbatim_type_one - {\catcode`<=\othercatcode % old precaution - \catcode`>=\othercatcode % old precaution + {\catcode\lessthanasciicode\othercatcode % old precaution + \catcode\morethanasciicode\othercatcode % old precaution \futureexpandis<\buff_verbatim_type_b\buff_verbatim_type_c} \def\buff_verbatim_type_three @@ -461,10 +450,10 @@ \futureexpandis[\buff_verbatim_typing_start_yes\buff_verbatim_typing_start_nop} \def\buff_verbatim_typing_start_yes[#1]% - {\ifcondition\validassignment{#1}% + {\ifhastok={#1}% \setupcurrenttyping[#1]% - \else - \doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}% + \orelse\ifcstok{#1}\v!continue + \lettypingparameter\c!continue\v!yes \fi \typingparameter\c!before\relax % moved down \startpacked[\v!blank]% % moved down diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl index 9a267bc5f..667b2bc6d 100644 --- a/tex/context/base/mkxl/cont-new.mkxl +++ b/tex/context/base/mkxl/cont-new.mkxl @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2023.02.07 19:02} +\newcontextversion{2023.02.14 17:41} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl index 143c67ffb..b0539ce74 100644 --- a/tex/context/base/mkxl/context.mkxl +++ b/tex/context/base/mkxl/context.mkxl @@ -29,7 +29,7 @@ %D {YYYY.MM.DD HH:MM} format. \immutable\edef\contextformat {\jobname} -\immutable\edef\contextversion{2023.02.07 19:02} +\immutable\edef\contextversion{2023.02.14 17:41} %overloadmode 1 % check frozen / warning %overloadmode 2 % check frozen / error @@ -642,8 +642,16 @@ \errorstopmode \dump \endinput -% These lua files are (still) shared with mkiv amd some are large and -% rather generic. However there are some that can be improved in lmtx. +% Some lua files are (still) shared with mkiv amd some are large and rather +% generic. However there are some that can be improved in lmtx. At some point +% we will definitely freeze mkiv and then use lmt files for futher development +% of lmtx. We also no longer use the macro feature to replace 5.3 compatible +% function calls by native 5.4 features as lmt files assume 5.4 anyway. This +% makes format generation a little faster (not that it's that slow). It might \ +% take a while before we dealt with all of them because I'll also clean them +% up a bit when doing. +% +% % luat-bas.mkxl l-macro-imp-optimize % this will go away % c:/data/develop/context/sources/attr-eff.lua % c:/data/develop/context/sources/attr-mkr.lua @@ -689,6 +697,8 @@ % c:/data/develop/context/sources/core-dat.lua % c:/data/develop/context/sources/core-two.lua +% data... + % c:/data/develop/context/sources/file-ini.lua % c:/data/develop/context/sources/file-lib.lua % c:/data/develop/context/sources/file-res.lua @@ -697,14 +707,11 @@ % c:/data/develop/context/sources/font-afk.lua % c:/data/develop/context/sources/font-agl.lua % c:/data/develop/context/sources/font-aux.lua -% c:/data/develop/context/sources/font-cff.lua % c:/data/develop/context/sources/font-cid.lua % c:/data/develop/context/sources/font-enc.lua % c:/data/develop/context/sources/font-log.lua % c:/data/develop/context/sources/font-lua.lua % not realy used, more a demo -% c:/data/develop/context/sources/font-map.lua % c:/data/develop/context/sources/font-nod.lua % some trace helpers -% c:/data/develop/context/sources/font-onr.lua % type one afm/pfb % c:/data/develop/context/sources/font-osd.lua % c:/data/develop/context/sources/font-otc.lua % c:/data/develop/context/sources/font-oth.lua @@ -720,7 +727,6 @@ % c:/data/develop/context/sources/font-sol.lua % c:/data/develop/context/sources/font-syn.lua % identification code % c:/data/develop/context/sources/font-trt.lua -% c:/data/develop/context/sources/font-ttf.lua % c:/data/develop/context/sources/font-web.lua % proof of concept, never used % c:/data/develop/context/sources/font-imp-combining.lua % shared, like typescript @@ -753,8 +759,6 @@ % c:/data/develop/context/sources/lang-txt.lua % these are data files % c:/data/develop/context/sources/lang-wrd.lua -% c:/data/develop/context/sources/libs-ini.lua % will become lmt - % c:/data/develop/context/sources/luat-exe.lua % c:/data/develop/context/sources/luat-iop.lua % c:/data/develop/context/sources/luat-mac.lua % will become lmt @@ -790,7 +794,7 @@ % c:/data/develop/context/sources/phys-dim.lua -% c:/data/develop/context/sources/publ-aut.lua +% c:/data/develop/context/sources/publ-aut.lua % shared % c:/data/develop/context/sources/publ-dat.lua % c:/data/develop/context/sources/publ-fnd.lua % c:/data/develop/context/sources/publ-inc.lua @@ -802,8 +806,6 @@ % c:/data/develop/context/sources/publ-tra.lua % c:/data/develop/context/sources/publ-usr.lua -% c:/data/develop/context/sources/regi-ini.lua - % c:/data/develop/context/sources/scrn-but.lua % c:/data/develop/context/sources/scrn-fld.lua % c:/data/develop/context/sources/scrn-hlp.lua @@ -838,13 +840,11 @@ % c:/data/develop/context/sources/trac-par.lua % c:/data/develop/context/sources/trac-tex.lua -% c:/data/develop/context/sources/typo-cln.lua +% c:/data/develop/context/sources/typo-cln.lua -- wrong name for what it does % c:/data/develop/context/sources/typo-dha.lua % c:/data/develop/context/sources/typo-fkr.lua % c:/data/develop/context/sources/typo-inj.lua -% c:/data/develop/context/sources/typo-lan.lua % c:/data/develop/context/sources/typo-man.lua -% c:/data/develop/context/sources/typo-pnc.lua % c:/data/develop/context/sources/typo-prc.lua % c:/data/develop/context/sources/typo-rep.lua diff --git a/tex/context/base/mkxl/data-vir.lmt b/tex/context/base/mkxl/data-vir.lmt new file mode 100644 index 000000000..b78211fc9 --- /dev/null +++ b/tex/context/base/mkxl/data-vir.lmt @@ -0,0 +1,104 @@ +if not modules then modules = { } end modules ['data-vir'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type = type +local formatters = string.formatters + +local trace_virtual = false +local report_virtual = logs.reporter("resolvers","virtual") + +trackers.register("resolvers.locating", function(v) trace_virtual = v end) +trackers.register("resolvers.virtual", function(v) trace_virtual = v end) + +local resolvers = resolvers +local savers = resolvers.savers +local cleaners = resolvers.cleaners + +local data = { } +local n = 0 -- hm, number can be query +local f_virtual_n = formatters["virtual://%s.%s"] +local f_virtual_y = formatters["virtual://%s-%s.%s"] + +function savers.virtual(specification,content,suffix) + n = n + 1 -- one number for all namespaces + local path = type(specification) == "table" and specification.path or specification + if type(path) ~= "string" or path == "" then + path = "virtualfile" + end + local filename = suffix and f_virtual_y(path,n,suffix) or f_virtual_n(path,n) + if trace_virtual then + report_virtual("saver: file %a saved",filename) + end + data[filename] = content + return filename +end + +function cleaners.virtual(filename) + data[filename] = nil +end + +local finders = resolvers.finders +local notfound = finders.notfound + +function finders.virtual(specification) + local original = specification.original + local d = data[original] + if d then + if trace_virtual then + report_virtual("finder: file %a found",original) + end + return original + else + if trace_virtual then + report_virtual("finder: unknown file %a",original) + end + return notfound() + end +end + +local openers = resolvers.openers +local notfound = openers.notfound +local textopener = openers.helpers.textopener + +function openers.virtual(specification) + local original = specification.original + local d = data[original] + if d then + if trace_virtual then + report_virtual("opener: file %a opened",original) + end + data[original] = nil -- when we comment this we can have error messages + -- With utf-8 we signal that no regime is to be applied! + -- characters.showstring(d) + return textopener("virtual",original,d,"utf-8") + else + if trace_virtual then + report_virtual("opener: file %a not found",original) + end + return notfound() + end +end + +local loaders = resolvers.loaders +local notfound = loaders.notfound + +function loaders.virtual(specification) + local original = specification.original + local d = data[original] + if d then + if trace_virtual then + report_virtual("loader: file %a loaded",original) + end + data[original] = nil + return true, d, #d + end + if trace_virtual then + report_virtual("loader: file %a not loaded",original) + end + return notfound() +end diff --git a/tex/context/base/mkxl/file-ini.mklx b/tex/context/base/mkxl/file-ini.mklx index 106536eea..7c4645a9a 100644 --- a/tex/context/base/mkxl/file-ini.mklx +++ b/tex/context/base/mkxl/file-ini.mklx @@ -99,11 +99,11 @@ \the\everystartreadingfile \pushcatcodetable % saveguard \setcatcodetable\ctxcatcodes - \clf_pushregime}% temporarily this way + \pushregime}% temporarily this way \permanent\protected\def\stopreadingfile - {\popcatcodetable % saveguard - \clf_popregime % temporarily this way + {\popcatcodetable % saveguard + \popregime % temporarily this way \the\everystopreadingfile \global\advanceby\readingfilelevel\minusone} diff --git a/tex/context/base/mkxl/font-cff.lmt b/tex/context/base/mkxl/font-cff.lmt new file mode 100644 index 000000000..dc5f98382 --- /dev/null +++ b/tex/context/base/mkxl/font-cff.lmt @@ -0,0 +1,2788 @@ +if not modules then modules = { } end modules ['font-cff'] = { + version = 1.001, + optimize = true, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: option.outlines +-- todo: option.boundingbox +-- per charstring (less memory) + +-- This is a heavy one as it is a rather packed format. We don't need al the information +-- now but we might need it later (who know what magic we can do with metapost). So at +-- some point this might become a module. We just follow Adobe Technical Notes #5176 and +-- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX but +-- it's not the easiest source to read (and doesn't cover cff2). + +-- For now we save the segments in a list of segments with the operator last in an entry +-- because that reflects the original. But it might make more sense to use a single array +-- per segment. For pdf a simple concat works ok, but for other purposes a operator first +-- flush is nicer. +-- +-- In retrospect I could have looked into the backend code of LuaTeX but it never +-- occurred to me that parsing charstrings was needed there (which has to to +-- with merging subroutines and flattening, not so much with calculations.) On +-- the other hand, we can now feed back cff2 stuff. + +local next, type, tonumber, rawget = next, type, tonumber, rawget +local byte, char, gmatch, sub = string.byte, string.char, string.gmatch, string.sub +local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack +local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max +local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct +local lpegmatch = lpeg.match +local formatters = string.formatters +local bytetable = string.bytetable +----- rshift, band, extract = bit32.rshift, bit32.band, bit32.extract + +local readers = fonts.handlers.otf.readers +local streamreader = readers.streamreader + +local readstring = streamreader.readstring +local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer +local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer +local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer +local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer +local setposition = streamreader.setposition +local getposition = streamreader.getposition +local readbytetable = streamreader.readbytetable + +directives.register("fonts.streamreader",function() + + streamreader = utilities.streams + + readstring = streamreader.readstring + readbyte = streamreader.readcardinal1 + readushort = streamreader.readcardinal2 + readuint = streamreader.readcardinal3 + readulong = streamreader.readcardinal4 + setposition = streamreader.setposition + getposition = streamreader.getposition + readbytetable = streamreader.readbytetable + +end) + +local setmetatableindex = table.setmetatableindex + +local trace_charstrings = false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings = v end) +local report = logs.reporter("otf reader","cff") + +local parsedictionaries +local parsecharstring +local parsecharstrings +local resetcharstrings +local parseprivates +local startparsing +local stopparsing + +local defaultstrings = { [0] = -- taken from ff + ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", + "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", + "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", + "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", + "sterling", "fraction", "yen", "florin", "section", "currency", + "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", + "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", + "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", + "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", + "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", + "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", + "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", + "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", + "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", + "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", + "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", + "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", + "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", + "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", + "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", + "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", + "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", + "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", + "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", + "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", + "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", + "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", + "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", + "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", + "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", + "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", + "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", + "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", + "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", + "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", + "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", + "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", + "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", + "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", + "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", + "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", + "oneinferior", "twoinferior", "threeinferior", "fourinferior", + "fiveinferior", "sixinferior", "seveninferior", "eightinferior", + "nineinferior", "centinferior", "dollarinferior", "periodinferior", + "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", + "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", + "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", + "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", + "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", + "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", + "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", + "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", + "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold", +} + +local standardnames = { [0] = -- needed for seac + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, + "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", + "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", + "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", + "z", "braceleft", "bar", "braceright", "asciitilde", false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, "exclamdown", + "cent", "sterling", "fraction", "yen", "florin", "section", "currency", + "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", + "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl", + "periodcentered", false, "paragraph", "bullet", "quotesinglbase", + "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", + false, "questiondown", false, "grave", "acute", "circumflex", "tilde", + "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false, + "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, "AE", false, "ordfeminine", false, false, false, false, "Lslash", + "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae", + false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe", + "germandbls", false, false, false, false +} + +local cffreaders = { + readbyte, + readushort, + readuint, + readulong, +} + +directives.register("fonts.streamreader",function() + cffreaders = { + readbyte, + readushort, + readuint, + readulong, + } +end) + +-- The header contains information about its own size. + +local function readheader(f) + local offset = getposition(f) + local major = readbyte(f) + local header = { + offset = offset, + major = major, + minor = readbyte(f), + size = readbyte(f), -- headersize + } + if major == 1 then + header.dsize = readbyte(f) -- list of dict offsets + elseif major == 2 then + header.dsize = readushort(f) -- topdict size + else + -- I'm probably no longer around by then and we use AI's to + -- handle this kind of stuff, if we typeset documents at all. + end + setposition(f,offset+header.size) + return header +end + +-- The indexes all look the same, so we share a loader. We could pass a handler +-- and run over the array but why bother, we only have a few uses. + +local function readlengths(f,longcount) + local count = longcount and readulong(f) or readushort(f) + if count == 0 then + return { } + end + local osize = readbyte(f) + local read = cffreaders[osize] + if not read then + report("bad offset size: %i",osize) + return { } + end + local lengths = { } + local previous = read(f) + for i=1,count do + local offset = read(f) + local length = offset - previous + if length < 0 then + report("bad offset: %i",length) + length = 0 + end + lengths[i] = length + previous = offset + end + return lengths +end + +-- There can be subfonts so names is an array. However, in our case it's always +-- one font. The same is true for the top dictionaries. Watch how we only load +-- the dictionary string as for interpretation we need to have the strings loaded +-- as well. + +local function readfontnames(f) + local names = readlengths(f) + for i=1,#names do + names[i] = readstring(f,names[i]) + end + return names +end + +local function readtopdictionaries(f) + local dictionaries = readlengths(f) + for i=1,#dictionaries do + dictionaries[i] = readstring(f,dictionaries[i]) + end + return dictionaries +end + +-- Strings are added to a list of standard strings so we start the font specific +-- one with an offset. Strings are shared so we have one table. + +local function readstrings(f) + local lengths = readlengths(f) + local strings = setmetatableindex({ }, defaultstrings) + local index = #defaultstrings + for i=1,#lengths do + index = index + 1 + strings[index] = readstring(f,lengths[i]) + end + return strings +end + +-- Parsing the dictionaries is delayed till we have the strings loaded. The parser +-- is stack based so the operands come before the operator (like in postscript). + +-- local function delta(t) +-- local n = #t +-- if n > 1 then +-- local p = t[1] +-- for i=2,n do +-- local c = t[i] +-- t[i] = c + p +-- p = c +-- end +-- end +-- end + +do + + -- We use a closure so that we don't need to pass too much around. For cff2 we can + -- at some point use a simple version as there is less. + + local stack = { } + local top = 0 + local result = { } + local strings = { } + + local p_single = + P("\00") / function() + result.version = strings[stack[top]] or "unset" + top = 0 + end + + P("\01") / function() + result.notice = strings[stack[top]] or "unset" + top = 0 + end + + P("\02") / function() + result.fullname = strings[stack[top]] or "unset" + top = 0 + end + + P("\03") / function() + result.familyname = strings[stack[top]] or "unset" + top = 0 + end + + P("\04") / function() + result.weight = strings[stack[top]] or "unset" + top = 0 + end + + P("\05") / function() + result.fontbbox = { unpack(stack,1,4) } + top = 0 + end + + P("\06") / function() + result.bluevalues = { unpack(stack,1,top) } + top = 0 + end + + P("\07") / function() + result.otherblues = { unpack(stack,1,top) } + top = 0 + end + + P("\08") / function() + result.familyblues = { unpack(stack,1,top) } + top = 0 + end + + P("\09") / function() + result.familyotherblues = { unpack(stack,1,top) } + top = 0 + end + + P("\10") / function() + result.stdhw = stack[top] + top = 0 + end + + P("\11") / function() + result.stdvw = stack[top] + top = 0 + end + + P("\13") / function() + result.uniqueid = stack[top] + top = 0 + end + + P("\14") / function() + result.xuid = concat(stack,"",1,top) + top = 0 + end + + P("\15") / function() + result.charset = stack[top] + top = 0 + end + + P("\16") / function() + result.encoding = stack[top] + top = 0 + end + + P("\17") / function() -- valid cff2 + result.charstrings = stack[top] + top = 0 + end + + P("\18") / function() + result.private = { + size = stack[top-1], + offset = stack[top], + } + top = 0 + end + + P("\19") / function() + result.subroutines = stack[top] + top = 0 -- new, forgotten ? + end + + P("\20") / function() + result.defaultwidthx = stack[top] + top = 0 -- new, forgotten ? + end + + P("\21") / function() + result.nominalwidthx = stack[top] + top = 0 -- new, forgotten ? + end + -- + P("\22") / function() -- reserved + -- end + -- + P("\23") / function() -- reserved + -- end + + P("\24") / function() -- new in cff2 + result.vstore = stack[top] + top = 0 + end + + P("\25") / function() -- new in cff2 + result.maxstack = stack[top] + top = 0 + end + -- + P("\26") / function() -- reserved + -- end + -- + P("\27") / function() -- reserved + -- end + + local p_double = P("\12") * ( + P("\00") / function() + result.copyright = stack[top] + top = 0 + end + + P("\01") / function() + result.monospaced = stack[top] == 1 and true or false -- isfixedpitch + top = 0 + end + + P("\02") / function() + result.italicangle = stack[top] + top = 0 + end + + P("\03") / function() + result.underlineposition = stack[top] + top = 0 + end + + P("\04") / function() + result.underlinethickness = stack[top] + top = 0 + end + + P("\05") / function() + result.painttype = stack[top] + top = 0 + end + + P("\06") / function() + result.charstringtype = stack[top] + top = 0 + end + + P("\07") / function() -- valid cff2 + result.fontmatrix = { unpack(stack,1,6) } + top = 0 + end + + P("\08") / function() + result.strokewidth = stack[top] + top = 0 + end + + P("\09") / function() + result.bluescale = stack[top] + top = 0 + end + + P("\10") / function() + result.blueshift = stack[top] + top = 0 + end + + P("\11") / function() + result.bluefuzz = stack[top] + top = 0 + end + + P("\12") / function() + result.stemsnaph = { unpack(stack,1,top) } + top = 0 + end + + P("\13") / function() + result.stemsnapv = { unpack(stack,1,top) } + top = 0 + end + + P("\20") / function() + result.syntheticbase = stack[top] + top = 0 + end + + P("\21") / function() + result.postscript = strings[stack[top]] or "unset" + top = 0 + end + + P("\22") / function() + result.basefontname = strings[stack[top]] or "unset" + top = 0 + end + + P("\21") / function() + result.basefontblend = stack[top] + top = 0 + end + + P("\30") / function() + result.cid.registry = strings[stack[top-2]] or "unset" + result.cid.ordering = strings[stack[top-1]] or "unset" + result.cid.supplement = stack[top] + top = 0 + end + + P("\31") / function() + result.cid.fontversion = stack[top] + top = 0 + end + + P("\32") / function() + result.cid.fontrevision= stack[top] + top = 0 + end + + P("\33") / function() + result.cid.fonttype = stack[top] + top = 0 + end + + P("\34") / function() + result.cid.count = stack[top] + top = 0 + end + + P("\35") / function() + result.cid.uidbase = stack[top] + top = 0 + end + + P("\36") / function() -- valid cff2 + result.cid.fdarray = stack[top] + top = 0 + end + + P("\37") / function() -- valid cff2 + result.cid.fdselect = stack[top] + top = 0 + end + + P("\38") / function() + result.cid.fontname = strings[stack[top]] or "unset" + top = 0 + end + ) + + -- Some lpeg fun ... a first variant split the byte and made a new string but + -- the second variant is much faster. Not that it matters much as we don't see + -- such numbers often. + + local remap_1 = { + ["\x00"] = "00", ["\x01"] = "01", ["\x02"] = "02", ["\x03"] = "03", ["\x04"] = "04", ["\x05"] = "05", ["\x06"] = "06", ["\x07"] = "07", ["\x08"] = "08", ["\x09"] = "09", ["\x0A"] = "0.", ["\x0B"] = "0E", ["\x0C"] = "0E-", ["\x0D"] = "0", ["\x0E"] = "0-", ["\x0F"] = "0", + ["\x10"] = "10", ["\x11"] = "11", ["\x12"] = "12", ["\x13"] = "13", ["\x14"] = "14", ["\x15"] = "15", ["\x16"] = "16", ["\x17"] = "17", ["\x18"] = "18", ["\x19"] = "19", ["\x1A"] = "1.", ["\x1B"] = "1E", ["\x1C"] = "1E-", ["\x1D"] = "1", ["\x1E"] = "1-", ["\x1F"] = "1", + ["\x20"] = "20", ["\x21"] = "21", ["\x22"] = "22", ["\x23"] = "23", ["\x24"] = "24", ["\x25"] = "25", ["\x26"] = "26", ["\x27"] = "27", ["\x28"] = "28", ["\x29"] = "29", ["\x2A"] = "2.", ["\x2B"] = "2E", ["\x2C"] = "2E-", ["\x2D"] = "2", ["\x2E"] = "2-", ["\x2F"] = "2", + ["\x30"] = "30", ["\x31"] = "31", ["\x32"] = "32", ["\x33"] = "33", ["\x34"] = "34", ["\x35"] = "35", ["\x36"] = "36", ["\x37"] = "37", ["\x38"] = "38", ["\x39"] = "39", ["\x3A"] = "3.", ["\x3B"] = "3E", ["\x3C"] = "3E-", ["\x3D"] = "3", ["\x3E"] = "3-", ["\x3F"] = "3", + ["\x40"] = "40", ["\x41"] = "41", ["\x42"] = "42", ["\x43"] = "43", ["\x44"] = "44", ["\x45"] = "45", ["\x46"] = "46", ["\x47"] = "47", ["\x48"] = "48", ["\x49"] = "49", ["\x4A"] = "4.", ["\x4B"] = "4E", ["\x4C"] = "4E-", ["\x4D"] = "4", ["\x4E"] = "4-", ["\x4F"] = "4", + ["\x50"] = "50", ["\x51"] = "51", ["\x52"] = "52", ["\x53"] = "53", ["\x54"] = "54", ["\x55"] = "55", ["\x56"] = "56", ["\x57"] = "57", ["\x58"] = "58", ["\x59"] = "59", ["\x5A"] = "5.", ["\x5B"] = "5E", ["\x5C"] = "5E-", ["\x5D"] = "5", ["\x5E"] = "5-", ["\x5F"] = "5", + ["\x60"] = "60", ["\x61"] = "61", ["\x62"] = "62", ["\x63"] = "63", ["\x64"] = "64", ["\x65"] = "65", ["\x66"] = "66", ["\x67"] = "67", ["\x68"] = "68", ["\x69"] = "69", ["\x6A"] = "6.", ["\x6B"] = "6E", ["\x6C"] = "6E-", ["\x6D"] = "6", ["\x6E"] = "6-", ["\x6F"] = "6", + ["\x70"] = "70", ["\x71"] = "71", ["\x72"] = "72", ["\x73"] = "73", ["\x74"] = "74", ["\x75"] = "75", ["\x76"] = "76", ["\x77"] = "77", ["\x78"] = "78", ["\x79"] = "79", ["\x7A"] = "7.", ["\x7B"] = "7E", ["\x7C"] = "7E-", ["\x7D"] = "7", ["\x7E"] = "7-", ["\x7F"] = "7", + ["\x80"] = "80", ["\x81"] = "81", ["\x82"] = "82", ["\x83"] = "83", ["\x84"] = "84", ["\x85"] = "85", ["\x86"] = "86", ["\x87"] = "87", ["\x88"] = "88", ["\x89"] = "89", ["\x8A"] = "8.", ["\x8B"] = "8E", ["\x8C"] = "8E-", ["\x8D"] = "8", ["\x8E"] = "8-", ["\x8F"] = "8", + ["\x90"] = "90", ["\x91"] = "91", ["\x92"] = "92", ["\x93"] = "93", ["\x94"] = "94", ["\x95"] = "95", ["\x96"] = "96", ["\x97"] = "97", ["\x98"] = "98", ["\x99"] = "99", ["\x9A"] = "9.", ["\x9B"] = "9E", ["\x9C"] = "9E-", ["\x9D"] = "9", ["\x9E"] = "9-", ["\x9F"] = "9", + ["\xA0"] = ".0", ["\xA1"] = ".1", ["\xA2"] = ".2", ["\xA3"] = ".3", ["\xA4"] = ".4", ["\xA5"] = ".5", ["\xA6"] = ".6", ["\xA7"] = ".7", ["\xA8"] = ".8", ["\xA9"] = ".9", ["\xAA"] = "..", ["\xAB"] = ".E", ["\xAC"] = ".E-", ["\xAD"] = ".", ["\xAE"] = ".-", ["\xAF"] = ".", + ["\xB0"] = "E0", ["\xB1"] = "E1", ["\xB2"] = "E2", ["\xB3"] = "E3", ["\xB4"] = "E4", ["\xB5"] = "E5", ["\xB6"] = "E6", ["\xB7"] = "E7", ["\xB8"] = "E8", ["\xB9"] = "E9", ["\xBA"] = "E.", ["\xBB"] = "EE", ["\xBC"] = "EE-", ["\xBD"] = "E", ["\xBE"] = "E-", ["\xBF"] = "E", + ["\xC0"] = "E-0", ["\xC1"] = "E-1", ["\xC2"] = "E-2", ["\xC3"] = "E-3", ["\xC4"] = "E-4", ["\xC5"] = "E-5", ["\xC6"] = "E-6", ["\xC7"] = "E-7", ["\xC8"] = "E-8", ["\xC9"] = "E-9", ["\xCA"] = "E-.", ["\xCB"] = "E-E", ["\xCC"] = "E-E-", ["\xCD"] = "E-", ["\xCE"] = "E--", ["\xCF"] = "E-", + ["\xD0"] = "-0", ["\xD1"] = "-1", ["\xD2"] = "-2", ["\xD3"] = "-3", ["\xD4"] = "-4", ["\xD5"] = "-5", ["\xD6"] = "-6", ["\xD7"] = "-7", ["\xD8"] = "-8", ["\xD9"] = "-9", ["\xDA"] = "-.", ["\xDB"] = "-E", ["\xDC"] = "-E-", ["\xDD"] = "-", ["\xDE"] = "--", ["\xDF"] = "-", + } + local remap_2 = { + ["\x0F"] = "0", ["\x1F"] = "1", ["\x2F"] = "2", ["\x3F"] = "3", ["\x4F"] = "4", + ["\x5F"] = "5", ["\x6F"] = "6", ["\x7F"] = "7", ["\x8F"] = "8", ["\x9F"] = "9", + } + + local p_last_1 = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF") + local p_last_2 = R("\xF0\xFF") + + -- tricky, we don't want to append last + + -- local p_nibbles = P("\30") * Cs(((1-p_last)/remap)^0 * (P(1)/remap)) / function(n) + local p_nibbles = P("\30") * Cs(((1-(p_last_1+p_last_2))/remap_1)^0 * (p_last_1/remap_2 + p_last_2/"")) / function(n) + -- 0-9=digit a=. b=E c=E- d=reserved e=- f=finish + top = top + 1 + stack[top] = tonumber(n) or 0 + end + + local p_byte = C(R("\32\246")) / function(b0) + -- -107 .. +107 + top = top + 1 + stack[top] = byte(b0) - 139 + end + + local p_positive = C(R("\247\250")) * C(1) / function(b0,b1) + -- +108 .. +1131 + top = top + 1 + stack[top] = (byte(b0)-247)*256 + byte(b1) + 108 + end + + local p_negative = C(R("\251\254")) * C(1) / function(b0,b1) + -- -1131 .. -108 + top = top + 1 + stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108 + end + + -- local p_float = P("\255") * C(1) * C(1) * C(1) * C(1) / function(b0,b1,b2,b3) + -- top = top + 1 + -- stack[top] = 0 + -- end + + local p_short = P("\28") * C(1) * C(1) / function(b1,b2) + -- -32768 .. +32767 : b1<<8 | b2 + top = top + 1 + local n = 0x100 * byte(b1) + byte(b2) + if n >= 0x8000 then + stack[top] = n - 0xFFFF - 1 + else + stack[top] = n + end + end + + local p_long = P("\29") * C(1) * C(1) * C(1) * C(1) / function(b1,b2,b3,b4) + -- -2^31 .. +2^31-1 : b1<<24 | b2<<16 | b3<<8 | b4 + top = top + 1 + local n = 0x1000000 * byte(b1) + 0x10000 * byte(b2) + 0x100 * byte(b3) + byte(b4) + if n >= 0x8000000 then + stack[top] = n - 0xFFFFFFFF - 1 + else + stack[top] = n + end + end + + local p_unsupported = P(1) / function(detail) + top = 0 + end + + local p_dictionary = ( + p_byte + + p_positive + + p_negative + + p_short + + p_long + + p_nibbles + + p_single + + p_double + -- + p_float + + p_unsupported + )^1 + + parsedictionaries = function(data,dictionaries,version) + stack = { } + strings = data.strings + if trace_charstrings then + report("charstring format %a",version) + end + for i=1,#dictionaries do + top = 0 + result = version == "cff" and { + monospaced = false, + italicangle = 0, + underlineposition = -100, + underlinethickness = 50, + painttype = 0, + charstringtype = 2, + fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 }, + fontbbox = { 0, 0, 0, 0 }, + strokewidth = 0, + charset = 0, + encoding = 0, + cid = { + fontversion = 0, + fontrevision = 0, + fonttype = 0, + count = 8720, + } + } or { + charstringtype = 2, + charset = 0, + vstore = 0, + cid = { + -- nothing yet + }, + } + lpegmatch(p_dictionary,dictionaries[i]) + dictionaries[i] = result + end + -- + result = { } + top = 0 + stack = { } + end + + parseprivates = function(data,dictionaries) + stack = { } + strings = data.strings + for i=1,#dictionaries do + local private = dictionaries[i].private + if private and private.data then + top = 0 + result = { + forcebold = false, + languagegroup = 0, + expansionfactor = 0.06, + initialrandomseed = 0, + subroutines = 0, + defaultwidthx = 0, + nominalwidthx = 0, + cid = { + -- actually an error + }, + } + lpegmatch(p_dictionary,private.data) + private.data = result + end + end + result = { } + top = 0 + stack = { } + end + + -- All bezier curves have 6 points with successive pairs relative to + -- the previous pair. Some can be left out and are then copied or zero + -- (optimization). + -- + -- We are not really interested in all the details of a glyph because we + -- only need to calculate the boundingbox. So, todo: a quick no result but + -- calculate only variant. + -- + -- The conversion is straightforward and the specification os clear once + -- you understand that the x and y needs to be updates each step. It's also + -- quite easy to test because in mp a shape will look bad when a few variables + -- are swapped. But still there might be bugs down here because not all + -- variants are seen in a font so far. We are less compact that the ff code + -- because there quite some variants are done in one helper with a lot of + -- testing for states. + + local x = 0 + local y = 0 + local width = false + local lsb = 0 + local result = { } + local r = 0 + local stems = 0 + local globalbias = 0 + local localbias = 0 + local nominalwidth = 0 + local defaultwidth = 0 + local charset = false + local globals = false + local locals = false + local depth = 1 + local xmin = 0 + local xmax = 0 + local ymin = 0 + local ymax = 0 + local checked = false + local keepcurve = false + local version = 2 + local regions = false + local nofregions = 0 + local region = false + local factors = false + local axis = false + local vsindex = 0 + local justpass = false + local seacs = { } + local procidx = nil + + local function showstate(where,i,n) + if i then + local j = i + n - 1 + report("%w%-10s : [%s] step",depth*2+2,where,concat(stack," ",i,j <= top and j or top)) + else + report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) + end + end + + local function showvalue(where,value,showstack) + if showstack then + report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top) + else + report("%w%-10s : %s",depth*2,where,tostring(value)) + end + end + + -- All these indirect calls make this run slower but it's cleaner this way + -- and we cache the result. As we moved the boundingbox code inline we gain + -- some back. I inlined some of then and a bit speed can be gained by more + -- inlining but not that much. + + -- Maybe have several action tables: + -- + -- keep curve / checked + -- keep curve / not checked + -- checked + -- not checked + + local function xymoveto() + if keepcurve then + r = r + 1 + result[r] = { x, y, "m" } + end + if checked then + if x > xmax then xmax = x elseif x < xmin then xmin = x end + if y > ymax then ymax = y elseif y < ymin then ymin = y end + else + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + end + end + + local function xmoveto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "m" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif x > xmax then + xmax = x + elseif x < xmin then + xmin = x + end + end + + local function ymoveto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "m" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif y > ymax then + ymax = y + elseif y < ymin then + ymin = y + end + end + + local function moveto() + if trace_charstrings then + showstate("moveto") + end + top = 0 -- forgotten + xymoveto() + end + + local function xylineto() -- we could inline, no blend + if keepcurve then + r = r + 1 + result[r] = { x, y, "l" } + end + if checked then + if x > xmax then xmax = x elseif x < xmin then xmin = x end + if y > ymax then ymax = y elseif y < ymin then ymin = y end + else + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + end + end + + local function xlineto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "l" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif x > xmax then + xmax = x + elseif x < xmin then + xmin = x + end + end + + local function ylineto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "l" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif y > ymax then + ymax = y + elseif y < ymin then + ymin = y + end + end + + local function xycurveto(x1,y1,x2,y2,x3,y3,i,n) -- called local so no blend here + if trace_charstrings then + showstate("curveto",i,n) + end + if keepcurve then + r = r + 1 + result[r] = { x1, y1, x2, y2, x3, y3, "c" } + end + if checked then + if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end + if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end + else + xmin = x1 + ymin = y1 + xmax = x1 + ymax = y1 + checked = true + end + if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end + if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end + if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end + if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end + end + + local function rmoveto() + if not width then + if top > 2 then + width = stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width = true + end + end + if trace_charstrings then + showstate("rmoveto") + end + x = x + stack[top-1] -- dx1 + y = y + stack[top] -- dy1 + top = 0 + xymoveto() + end + + local function hmoveto() + if not width then + if top > 1 then + width = stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width = true + end + end + if trace_charstrings then + showstate("hmoveto") + end + x = x + stack[top] -- dx1 + top = 0 + xmoveto() + end + + local function vmoveto() + if not width then + if top > 1 then + width = stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width = true + end + end + if trace_charstrings then + showstate("vmoveto") + end + y = y + stack[top] -- dy1 + top = 0 + ymoveto() + end + + local function rlineto() + if trace_charstrings then + showstate("rlineto") + end + for i=1,top,2 do + x = x + stack[i] -- dxa + y = y + stack[i+1] -- dya + xylineto() + end + top = 0 + end + + local function hlineto() -- x (y,x)+ | (x,y)+ + if trace_charstrings then + showstate("hlineto") + end + if top == 1 then + x = x + stack[1] + xlineto() + else + local swap = true + for i=1,top do + if swap then + x = x + stack[i] + xlineto() + swap = false + else + y = y + stack[i] + ylineto() + swap = true + end + end + end + top = 0 + end + + local function vlineto() -- y (x,y)+ | (y,x)+ + if trace_charstrings then + showstate("vlineto") + end + if top == 1 then + y = y + stack[1] + ylineto() + else + local swap = false + for i=1,top do + if swap then + x = x + stack[i] + xlineto() + swap = false + else + y = y + stack[i] + ylineto() + swap = true + end + end + end + top = 0 + end + + local function rrcurveto() + if trace_charstrings then + showstate("rrcurveto") + end +if top == 6 then + local ax = x + stack[1] -- dxa + local ay = y + stack[2] -- dya + local bx = ax + stack[3] -- dxb + local by = ay + stack[4] -- dyb + x = bx + stack[5] -- dxc + y = by + stack[6] -- dyc + xycurveto(ax,ay,bx,by,x,y,1,6) +else +-- print("rr",top==6,top) + for i=1,top,6 do + local ax = x + stack[i] -- dxa + local ay = y + stack[i+1] -- dya + local bx = ax + stack[i+2] -- dxb + local by = ay + stack[i+3] -- dyb + x = bx + stack[i+4] -- dxc + y = by + stack[i+5] -- dyc + xycurveto(ax,ay,bx,by,x,y,i,6) + end +end + top = 0 + end + + local function hhcurveto() + if trace_charstrings then + showstate("hhcurveto") + end + local s = 1 + if top % 2 ~= 0 then + y = y + stack[1] -- dy1 + s = 2 + end +if top == 4 then + local ax = x + stack[1] -- dxa + local ay = y + local bx = ax + stack[2] -- dxb + local by = ay + stack[3] -- dyb + x = bx + stack[4] -- dxc + y = by + xycurveto(ax,ay,bx,by,x,y,1,4) +else + for i=s,top,4 do + local ax = x + stack[i] -- dxa + local ay = y + local bx = ax + stack[i+1] -- dxb + local by = ay + stack[i+2] -- dyb + x = bx + stack[i+3] -- dxc + y = by + xycurveto(ax,ay,bx,by,x,y,i,4) + end +end + top = 0 + end + + local function vvcurveto() + if trace_charstrings then + showstate("vvcurveto") + end + local s = 1 + local d = 0 + if top % 2 ~= 0 then + d = stack[1] -- dx1 + s = 2 + end +if top == 4 then + local ax = x + d + local ay = y + stack[1] -- dya + local bx = ax + stack[2] -- dxb + local by = ay + stack[3] -- dyb + x = bx + y = by + stack[4] -- dyc + xycurveto(ax,ay,bx,by,x,y,1,4) + d = 0 +else + for i=s,top,4 do + local ax = x + d + local ay = y + stack[i] -- dya + local bx = ax + stack[i+1] -- dxb + local by = ay + stack[i+2] -- dyb + x = bx + y = by + stack[i+3] -- dyc + xycurveto(ax,ay,bx,by,x,y,i,4) + d = 0 + end +end + top = 0 + end + + local function xxcurveto(swap) + local last = top % 4 ~= 0 and stack[top] + if last then + top = top - 1 + end +if top == 4 then + local ax, ay, bx, by + if swap then + ax = x + stack[1] + ay = y + bx = ax + stack[2] + by = ay + stack[3] + y = by + stack[4] + if last then + x = bx + last + else + x = bx + end + else + ax = x + ay = y + stack[1] + bx = ax + stack[2] + by = ay + stack[3] + x = bx + stack[4] + if last then + y = by + last + else + y = by + end + end + xycurveto(ax,ay,bx,by,x,y,1 ,4) +else + for i=1,top,4 do + local ax, ay, bx, by + if swap then + ax = x + stack[i] + ay = y + bx = ax + stack[i+1] + by = ay + stack[i+2] + y = by + stack[i+3] + if last and i+3 == top then + x = bx + last + else + x = bx + end + swap = false + else + ax = x + ay = y + stack[i] + bx = ax + stack[i+1] + by = ay + stack[i+2] + x = bx + stack[i+3] + if last and i+3 == top then + y = by + last + else + y = by + end + swap = true + end + xycurveto(ax,ay,bx,by,x,y,i,4) + end +end + top = 0 + end + + local function hvcurveto() + if trace_charstrings then + showstate("hvcurveto") + end + xxcurveto(true) + end + + local function vhcurveto() + if trace_charstrings then + showstate("vhcurveto") + end + xxcurveto(false) + end + + local function rcurveline() + if trace_charstrings then + showstate("rcurveline") + end + for i=1,top-2,6 do + local ax = x + stack[i] -- dxa + local ay = y + stack[i+1] -- dya + local bx = ax + stack[i+2] -- dxb + local by = ay + stack[i+3] -- dyb + x = bx + stack[i+4] -- dxc + y = by + stack[i+5] -- dyc + xycurveto(ax,ay,bx,by,x,y,i,6) + end + x = x + stack[top-1] -- dxc + y = y + stack[top] -- dyc + xylineto() + top = 0 + end + + local function rlinecurve() + if trace_charstrings then + showstate("rlinecurve") + end + if top > 6 then + for i=1,top-6,2 do + x = x + stack[i] + y = y + stack[i+1] + xylineto() + end + end + local ax = x + stack[top-5] + local ay = y + stack[top-4] + local bx = ax + stack[top-3] + local by = ay + stack[top-2] + x = bx + stack[top-1] + y = by + stack[top] + xycurveto(ax,ay,bx,by,x,y) + top = 0 + end + + -- flex is not yet tested! no loop + + local function flex() -- fd not used + if trace_charstrings then + showstate("flex") + end + local ax = x + stack[1] -- dx1 + local ay = y + stack[2] -- dy1 + local bx = ax + stack[3] -- dx2 + local by = ay + stack[4] -- dy2 + local cx = bx + stack[5] -- dx3 + local cy = by + stack[6] -- dy3 + xycurveto(ax,ay,bx,by,cx,cy) + local dx = cx + stack[7] -- dx4 + local dy = cy + stack[8] -- dy4 + local ex = dx + stack[9] -- dx5 + local ey = dy + stack[10] -- dy5 + x = ex + stack[11] -- dx6 + y = ey + stack[12] -- dy6 + xycurveto(dx,dy,ex,ey,x,y) + top = 0 + end + + local function hflex() + if trace_charstrings then + showstate("hflex") + end + local ax = x + stack[1] -- dx1 + local ay = y + local bx = ax + stack[2] -- dx2 + local by = ay + stack[3] -- dy2 + local cx = bx + stack[4] -- dx3 + local cy = by + xycurveto(ax,ay,bx,by,cx,cy) + local dx = cx + stack[5] -- dx4 + local dy = by + local ex = dx + stack[6] -- dx5 + local ey = y + x = ex + stack[7] -- dx6 + xycurveto(dx,dy,ex,ey,x,y) + top = 0 + end + + local function hflex1() + if trace_charstrings then + showstate("hflex1") + end + local ax = x + stack[1] -- dx1 + local ay = y + stack[2] -- dy1 + local bx = ax + stack[3] -- dx2 + local by = ay + stack[4] -- dy2 + local cx = bx + stack[5] -- dx3 + local cy = by + xycurveto(ax,ay,bx,by,cx,cy) + local dx = cx + stack[6] -- dx4 + local dy = by + local ex = dx + stack[7] -- dx5 + local ey = dy + stack[8] -- dy5 + x = ex + stack[9] -- dx6 + xycurveto(dx,dy,ex,ey,x,y) + top = 0 + end + + local function flex1() + if trace_charstrings then + showstate("flex1") + end + local ax = x + stack[1] --dx1 + local ay = y + stack[2] --dy1 + local bx = ax + stack[3] --dx2 + local by = ay + stack[4] --dy2 + local cx = bx + stack[5] --dx3 + local cy = by + stack[6] --dy3 + xycurveto(ax,ay,bx,by,cx,cy) + local dx = cx + stack[7] --dx4 + local dy = cy + stack[8] --dy4 + local ex = dx + stack[9] --dx5 + local ey = dy + stack[10] --dy5 + if abs(ex - x) > abs(ey - y) then -- spec: abs(dx) > abs(dy) + x = ex + stack[11] + else + y = ey + stack[11] + end + xycurveto(dx,dy,ex,ey,x,y) + top = 0 + end + + local function getstem() + if top == 0 then + -- bad + elseif top % 2 ~= 0 then + if width then + remove(stack,1) + else + width = remove(stack,1) + if trace_charstrings then + showvalue("width",width) + end + end + top = top - 1 + end + if trace_charstrings then + showstate("stem") + end + stems = stems + (top // 2) + top = 0 + end + + local function getmask() + if top == 0 then + -- bad + elseif top % 2 ~= 0 then + if width then + remove(stack,1) + else + width = remove(stack,1) + if trace_charstrings then + showvalue("width",width) + end + end + top = top - 1 + end + if trace_charstrings then + showstate(operator == 19 and "hintmark" or "cntrmask") + end + stems = stems + (top // 2) + top = 0 + if stems == 0 then + -- forget about it + elseif stems <= 8 then + return 1 + else + return (stems + 7) // 8 + end + end + + local function unsupported(t) + if trace_charstrings then + showstate("unsupported " .. t) + end + top = 0 + end + + local function unsupportedsub(t) + if trace_charstrings then + showstate("unsupported sub " .. t) + end + top = 0 + end + + -- type 1 (not used in type 2) + + local function getstem3() + if trace_charstrings then + showstate("stem3") + end + top = 0 + end + + local function divide() + if version == "cff" then + local d = stack[top] + top = top - 1 + stack[top] = stack[top] / d + end + end + + local function closepath() + if version == "cff" then + if trace_charstrings then + showstate("closepath") + end + end + top = 0 + end + + local function hsbw() + if version == "cff" then + if trace_charstrings then + showstate("hsbw") + end + lsb = stack[top-1] or 0 + width = stack[top] + end + top = 0 + end + + local function sbw() + if version == "cff" then + if trace_charstrings then + showstate("sbw") + end + lsb = stack[top-3] + width = stack[top-1] + end + top = 0 + end + + -- asb adx ady bchar achar seac (accented characters) + + local function seac() + if version == "cff" then + if trace_charstrings then + showstate("seac") + end + end + top = 0 + end + + -- These are probably used for special cases i.e. call out to the + -- postscript interpreter (p 61 of the spec as well as chapter 8). + -- + -- This needs checking (I have to ask Taco next time we meet.) + + local popped = 3 + local hints = 3 + + -- arg1 ... argn n othersubr# <callothersubr> (on postscript stack) + + local function callothersubr() + if version == "cff" then + if trace_charstrings then + showstate("callothersubr") + end + if stack[top] == hints then + popped = stack[top-2] + else + popped = 3 + end + local t = stack[top-1] + if t then + top = top - (t + 2) + if top < 0 then + top = 0 + end + else + top = 0 + end + else + top = 0 + end + end + + -- <pop> number (from postscript stack) + + local function pop() + if version == "cff" then + if trace_charstrings then + showstate("pop") + end + top = top + 1 + stack[top] = popped + else + top = 0 + end + end + + local function setcurrentpoint() + if version == "cff" then + if trace_charstrings then + showstate("setcurrentpoint (unsupported)") + end + x = x + stack[top-1] + y = y + stack[top] + end + top = 0 + end + + -- So far for unsupported postscript. Now some cff2 magic. As I still need + -- to wrap my head around the rather complex variable font specification + -- with regions and axis, the following approach kind of works but is more + -- some trial and error trick. It's still not clear how much of the complex + -- truetype description applies to cff. Once there are fonts out there we'll + -- get there. (Marcel and friends did some tests with recent cff2 fonts so + -- the code has been adapted accordingly.) + + local reginit = false + + local function updateregions(n) -- n + 1 + if regions then + local current = regions[n+1] or regions[1] + nofregions = #current + if axis and n ~= reginit then + factors = { } + for i=1,nofregions do + local region = current[i] + local s = 1 + for j=1,#axis do + local f = axis[j] + local r = region[j] + local start = r.start + local peak = r.peak + local stop = r.stop + if start > peak or peak > stop then + -- * 1 + elseif start < 0 and stop > 0 and peak ~= 0 then + -- * 1 + elseif peak == 0 then + -- * 1 + elseif f < start or f > stop then + -- * 0 + s = 0 + break + elseif f < peak then + s = s * (f - start) / (peak - start) + elseif f > peak then + s = s * (stop - f) / (stop - peak) + else + -- * 1 + end + end + factors[i] = s + end + end + end + reginit = n + end + + local function setvsindex() + local vsindex = stack[top] + if trace_charstrings then + showstate(formatters["vsindex %i"](vsindex)) + end + updateregions(vsindex) + top = top - 1 + end + + local function blend() + local n = stack[top] + top = top - 1 + if axis then + -- x (r1x,r2x,r3x) + -- (x,y) (r1x,r2x,r3x) (r1y,r2y,r3y) + if trace_charstrings then + local t = top - nofregions * n + local m = t - n + for i=1,n do + local k = m + i + local d = m + n + (i-1)*nofregions + local old = stack[k] + local new = old + for r=1,nofregions do + new = new + stack[d+r] * factors[r] + end + stack[k] = new + showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new)) + end + top = t + elseif n == 1 then + top = top - nofregions + local v = stack[top] + for r=1,nofregions do + v = v + stack[top+r] * factors[r] + end + stack[top] = v + else + top = top - nofregions * n + local d = top + local k = top - n + for i=1,n do + k = k + 1 + local v = stack[k] + for r=1,nofregions do + v = v + stack[d+r] * factors[r] + end + stack[k] = v + d = d + nofregions + end + end + else + top = top - nofregions * n + end + end + + -- Bah, we cannot use a fast lpeg because a hint has an unknown size and a + -- runtime capture cannot handle that well. + + local actions = { [0] = + unsupported, -- 0 + getstem, -- 1 -- hstem + unsupported, -- 2 + getstem, -- 3 -- vstem + vmoveto, -- 4 + rlineto, -- 5 + hlineto, -- 6 + vlineto, -- 7 + rrcurveto, -- 8 + unsupported, -- 9 -- closepath + unsupported, -- 10 -- calllocal, + unsupported, -- 11 -- callreturn, + unsupported, -- 12 -- elsewhere + hsbw, -- 13 -- hsbw (type 1 cff) + unsupported, -- 14 -- endchar, + setvsindex, -- 15 -- cff2 + blend, -- 16 -- cff2 + unsupported, -- 17 + getstem, -- 18 -- hstemhm + getmask, -- 19 -- hintmask + getmask, -- 20 -- cntrmask + rmoveto, -- 21 + hmoveto, -- 22 + getstem, -- 23 -- vstemhm + rcurveline, -- 24 + rlinecurve, -- 25 + vvcurveto, -- 26 + hhcurveto, -- 27 + unsupported, -- 28 -- elsewhere + unsupported, -- 29 -- elsewhere + vhcurveto, -- 30 + hvcurveto, -- 31 + } + + local reverse = { [0] = + "unsupported", + "getstem", + "unsupported", + "getstem", + "vmoveto", + "rlineto", + "hlineto", + "vlineto", + "rrcurveto", + "unsupported", + "unsupported", + "unsupported", + "unsupported", + "hsbw", + "unsupported", + "setvsindex", + "blend", + "unsupported", + "getstem", + "getmask", + "getmask", + "rmoveto", + "hmoveto", + "getstem", + "rcurveline", + "rlinecurve", + "vvcurveto", + "hhcurveto", + "unsupported", + "unsupported", + "vhcurveto", + "hvcurveto", + } + + local subactions = { + -- cff 1 + [000] = dotsection, + [001] = getstem3, + [002] = getstem3, + [006] = seac, + [007] = sbw, + [012] = divide, + [016] = callothersubr, + [017] = pop, + [033] = setcurrentpoint, + -- cff 2 + [034] = hflex, + [035] = flex, + [036] = hflex1, + [037] = flex1, + } + + local chars = setmetatableindex(function (t,k) + local v = char(k) + t[k] = v + return v + end) + + local c_endchar = chars[14] + + -- todo: round in blend + + local encode = { } + local typeone = false + + -- this eventually can become a helper + + setmetatableindex(encode,function(t,i) + for i=-2048,-1130 do + -- t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF) + end + for i=-1131,-108 do + local v = 0xFB00 - i - 108 + -- t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF)) + t[i] = char((v >> 8) & 0xFF,v & 0xFF) + end + for i=-107,107 do + t[i] = chars[i + 139] + end + for i=108,1131 do + local v = 0xF700 + i - 108 + -- t[i] = char(extract(v,8,8),extract(v,0,8)) + t[i] = char((v >> 8) & 0xFF,v & 0xFF) + end + for i=1132,2048 do + -- t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF) + end + setmetatableindex(encode,function(t,k) + -- as we're cff2 we write 16.16-bit signed fixed value + local r = round(k) + local v = rawget(t,r) + if v then + return v + end + local v1 = floor(k) + local v2 = floor((k - v1) * 0x10000) + -- return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8)) + return char(255,(v1 >> 8) & 0xFF,v1 & 0xFF,(v2 >> 8) & 0xFF,v2 & 0xFF) + end) + return t[i] + end) + + readers.cffencoder = encode + + local function p_setvsindex() + local vsindex = stack[top] + updateregions(vsindex) + top = top - 1 + end + + local function p_blend() + -- leaves n values on stack + local n = stack[top] + top = top - 1 + if not axis then + -- fatal error + elseif n == 1 then + top = top - nofregions + local v = stack[top] + for r=1,nofregions do + v = v + stack[top+r] * factors[r] + end + stack[top] = round(v) + else + top = top - nofregions * n + local d = top + local k = top - n + for i=1,n do + k = k + 1 + local v = stack[k] + for r=1,nofregions do + v = v + stack[d+r] * factors[r] + end + stack[k] = round(v) + d = d + nofregions + end + end + end + + local function p_getstem() + local n = 0 + if top % 2 ~= 0 then + n = 1 + end + if top > n then + stems = stems + ((top - n) // 2) + end + end + + local function p_getmask() + local n = 0 + if top % 2 ~= 0 then + n = 1 + end + if top > n then + stems = stems + ((top - n) // 2) + end + if stems == 0 then + return 0 + elseif stems <= 8 then + return 1 + else + return (stems + 7) // 8 + end + end + + -- end of experiment + + local process + + local function call(scope,list,bias) -- ,process) + depth = depth + 1 + if top == 0 then + showstate(formatters["unknown %s call %s, case %s"](scope,"?",1)) + top = 0 + else + local index = stack[top] + bias + top = top - 1 + if trace_charstrings then + showvalue(scope,index,true) + end + local tab = list[index] + if tab then + process(tab) + else + showstate(formatters["unknown %s call %s, case %s"](scope,index,2)) + top = 0 + end + end + depth = depth - 1 + end + + -- precompiling and reuse is much slower than redoing the calls + + process = function(tab) + local i = 1 + local n = #tab + while i <= n do + local t = tab[i] + if t >= 32 then + top = top + 1 + if t <= 246 then + -- -107 .. +107 + stack[top] = t - 139 + i = i + 1 + elseif t <= 250 then + -- +108 .. +1131 + -- stack[top] = (t-247)*256 + tab[i+1] + 108 + -- stack[top] = t*256 - 247*256 + tab[i+1] + 108 + stack[top] = t*256 - 63124 + tab[i+1] + i = i + 2 + elseif t <= 254 then + -- -1131 .. -108 + -- stack[top] = -(t-251)*256 - tab[i+1] - 108 + -- stack[top] = -t*256 + 251*256 - tab[i+1] - 108 + stack[top] = -t*256 + 64148 - tab[i+1] + i = i + 2 + elseif typeone then + local n = 0x1000000 * tab[i+1] + 0x10000 * tab[i+2] + 0x100 * tab[i+3] + tab[i+4] + if n >= 0x8000000 then + n = n - 0xFFFFFFFF - 1 + end + stack[top] = n + i = i + 5 + else + local n1 = 0x100 * tab[i+1] + tab[i+2] + local n2 = 0x100 * tab[i+3] + tab[i+4] + if n1 >= 0x8000 then + n1 = n1 - 0x10000 + end + stack[top] = n1 + n2/0xFFFF + i = i + 5 + end + elseif t == 28 then + -- -32768 .. +32767 : b1<<8 | b2 + top = top + 1 + local n = 0x100 * tab[i+1] + tab[i+2] + if n >= 0x8000 then + -- stack[top] = n - 0xFFFF - 1 + stack[top] = n - 0x10000 + else + stack[top] = n + end + i = i + 3 + elseif t == 11 then -- not in cff2 + if trace_charstrings then + showstate("return") + end + return + elseif t == 10 then + call("local",locals,localbias) -- ,process) + i = i + 1 + elseif t == 14 then -- not in cff2 + if width then + -- okay + elseif top > 0 then + width = stack[1] + if trace_charstrings then + showvalue("width",width) + end + else + width = true + end + if trace_charstrings then + showstate("endchar") + end + return + elseif t == 29 then + call("global",globals,globalbias) -- ,process) + i = i + 1 + elseif t == 12 then + i = i + 1 + local t = tab[i] + if justpass then + if t >= 34 and t <= 37 then -- flexes + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + r = r + 1 ; result[r] = chars[12] + r = r + 1 ; result[r] = chars[t] + top = 0 + elseif t == 6 then + seacs[procidx] = { + asb = stack[1], + adx = stack[2], + ady = stack[3], + base = stack[4], + accent = stack[5], + width = width, + lsb = lsb, + } + top = 0 + else + local a = subactions[t] + if a then + a(t) + else + top = 0 + end + end + else + local a = subactions[t] + if a then + a(t) + else + if trace_charstrings then + showvalue("<subaction>",t) + end + top = 0 + end + end + i = i + 1 + elseif justpass then + -- todo: local a = passactions + if t == 15 then + p_setvsindex() + i = i + 1 + elseif t == 16 then + local s = p_blend() or 0 + i = i + s + 1 + -- cff 1: (when cff2 strip them) + elseif t == 1 or t == 3 or t == 18 or operation == 23 then + p_getstem() -- at the start + if version == "cff" then +-- if true then + if top > 0 then + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + top = 0 + end + r = r + 1 ; result[r] = chars[t] + else + top = 0 + end + i = i + 1 + -- cff 1: (when cff2 strip them) + elseif t == 19 or t == 20 then + local s = p_getmask() or 0 -- after the stems +-- if version == "cff" then + if true then + if top > 0 then + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + top = 0 + end + r = r + 1 ; result[r] = chars[t] + for j=1,s do + i = i + 1 + r = r + 1 ; result[r] = chars[tab[i]] + end + else + i = i + s + top = 0 + end + i = i + 1 + -- cff 1: closepath + elseif t == 9 then + top = 0 + i = i + 1 + elseif t == 13 then + hsbw() +-- if version == "cff" then + if true then + -- we do a moveto over lsb + r = r + 1 ; result[r] = encode[lsb] + r = r + 1 ; result[r] = chars[22] + else + -- lsb is supposed to be zero + end + i = i + 1 + else + if trace_charstrings then + showstate(reverse[t] or "<action>") + end + if top > 0 then + -- if t == 8 and top > 42 then + if t == 8 and top > 48 then + -- let's assume this only happens for rrcurveto .. the other ones would need some more + -- complex handling (cff2 stuff) + -- + -- dx1 dy1 (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) (dy1+dy2+dy3) rcurveto. + local n = 0 + for i=1,top do + -- if n == 42 then + if n == 48 then +-- local zero = encode[0] +-- local res3 = result[r-3] +-- local res2 = result[r-2] +-- local res1 = result[r-1] +-- local res0 = result[r] +-- result[r-3] = zero +-- result[r-2] = zero + r = r + 1 ; result[r] = chars[t] +-- r = r + 1 ; result[r] = zero +-- r = r + 1 ; result[r] = zero +-- r = r + 1 ; result[r] = res3 +-- r = r + 1 ; result[r] = res2 +-- r = r + 1 ; result[r] = res1 +-- r = r + 1 ; result[r] = res0 + n = 1 + else + n = n + 1 + end + r = r + 1 ; result[r] = encode[stack[i]] + end + else + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + end + top = 0 + end + r = r + 1 ; result[r] = chars[t] + i = i + 1 + end + else + local a = actions[t] + if a then + local s = a(t) + if s then + i = i + s + 1 + else + i = i + 1 + end + else + if trace_charstrings then + showstate(reverse[t] or "<action>") + end + top = 0 + i = i + 1 + end + end + end + end + + -- local function calculatebounds(segments,x,y) + -- local nofsegments = #segments + -- if nofsegments == 0 then + -- return { x, y, x, y } + -- else + -- local xmin = 10000 + -- local xmax = -10000 + -- local ymin = 10000 + -- local ymax = -10000 + -- if x < xmin then xmin = x end + -- if x > xmax then xmax = x end + -- if y < ymin then ymin = y end + -- if y > ymax then ymax = y end + -- -- we now have a reasonable start so we could + -- -- simplify the next checks + -- for i=1,nofsegments do + -- local s = segments[i] + -- local x = s[1] + -- local y = s[2] + -- if x < xmin then xmin = x end + -- if x > xmax then xmax = x end + -- if y < ymin then ymin = y end + -- if y > ymax then ymax = y end + -- if s[#s] == "c" then -- "curveto" + -- local x = s[3] + -- local y = s[4] + -- if x < xmin then xmin = x elseif x > xmax then xmax = x end + -- if y < ymin then ymin = y elseif y > ymax then ymax = y end + -- local x = s[5] + -- local y = s[6] + -- if x < xmin then xmin = x elseif x > xmax then xmax = x end + -- if y < ymin then ymin = y elseif y > ymax then ymax = y end + -- end + -- end + -- return { round(xmin), round(ymin), round(xmax), round(ymax) } -- doesn't make ceil more sense + -- end + -- end + + local function setbias(globals,locals,nobias) + if nobias then + return 0, 0 + else + local g = #globals + local l = #locals + return + ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1, + ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1 + end + end + + local function processshape(glyphs,tab,index,hack) + + if not tab then + glyphs[index] = { + boundingbox = { 0, 0, 0, 0 }, + width = 0, + name = charset and charset[index] or nil, + } + return + end + + tab = bytetable(tab) + + x = 0 + y = 0 + width = false + lsb = 0 + r = 0 + top = 0 + stems = 0 + result = { } -- we could reuse it when only boundingbox calculations are needed + popped = 3 + procidx = index + + xmin = 0 + xmax = 0 + ymin = 0 + ymax = 0 + checked = false + if trace_charstrings then + report("glyph: %i",index) + report("data : % t",tab) + end + + if regions then + updateregions(vsindex) + end + + process(tab) + if hack then + return x, y + end + + local boundingbox = { + round(xmin), + round(ymin), + round(xmax), + round(ymax), + } + + if width == true or width == false then + width = defaultwidth + else + width = nominalwidth + width + end + + local glyph = glyphs[index] -- can be autodefined in otr + if justpass then + r = r + 1 + result[r] = c_endchar + local stream = concat(result) +result = nil + -- if trace_charstrings then + -- report("vdata: %s",stream) + -- end + if glyph then + glyph.stream = stream + glyph.width = width + else + glyphs[index] = { stream = stream, width = width } + end + elseif glyph then + glyph.segments = keepcurve ~= false and result or nil + glyph.boundingbox = boundingbox + if not glyph.width then + glyph.width = width + end + if charset and not glyph.name then + glyph.name = charset[index] + end + -- glyph.sidebearing = 0 -- todo + elseif keepcurve then + glyphs[index] = { + segments = result, + boundingbox = boundingbox, + width = width, + name = charset and charset[index] or nil, + -- sidebearing = 0, + } +result = nil + else + glyphs[index] = { + boundingbox = boundingbox, + width = width, + name = charset and charset[index] or nil, + } + end + if trace_charstrings then + report("width : %s",tostring(width)) + report("boundingbox: % t",boundingbox) + end + + end + + startparsing = function(fontdata,data,streams) + reginit = false + axis = false + regions = data.regions + justpass = streams == true + popped = 3 + seacs = { } + if regions then + -- this was: + -- regions = { regions } -- needs checking + -- and is now (MFC): + regions = { } + local deltas = data.deltas + for i = 1, #deltas do + regions[i] = deltas[i].regions + end + axis = data.factors or false + end + end + + stopparsing = function(fontdata,data) + stack = { } + glyphs = false + result = { } + top = 0 + locals = false + globals = false + strings = false + popped = 3 + seacs = { } + end + + local function setwidths(private) + if not private then + return 0, 0 + end + local privatedata = private.data + if not privatedata then + return 0, 0 + end + return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0 + end + + parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone) + + local dictionary = data.dictionaries[1] + local charstrings = dictionary.charstrings + + keepcurve = doshapes + version = tversion + typeone = istypeone or false + strings = data.strings + globals = data.routines or { } + locals = dictionary.subroutines or { } + charset = dictionary.charset + vsindex = dictionary.vsindex or 0 + + local glyphs = glphs or { } + + globalbias, localbias = setbias(globals,locals,nobias) + nominalwidth, defaultwidth = setwidths(dictionary.private) + + if charstrings then + startparsing(fontdata,data,streams) + for index=1,#charstrings do + processshape(glyphs,charstrings[index],index-1) + end + if justpass and next(seacs) then + -- old type 1 stuff ... seacs + local charset = data.dictionaries[1].charset + if charset then + local lookup = table.swapped(charset) + for index, v in next, seacs do + local bindex = lookup[standardnames[v.base]] + local aindex = lookup[standardnames[v.accent]] + local bglyph = bindex and glyphs[bindex] + local aglyph = aindex and glyphs[aindex] + if bglyph and aglyph then + -- this is a real ugly hack but we seldom enter this branch (e.g. old lbr) + local jp = justpass + justpass = false + local x, y = processshape(glyphs,charstrings[bindex+1],bindex,true) + justpass = jp + -- + local base = bglyph.stream + local accent = aglyph.stream + local moveto = encode[-x-v.asb+v.adx] .. chars[22] + .. encode[-y +v.ady] .. chars[ 4] + -- prune an endchar + base = sub(base,1,#base-1) + -- combine them + glyphs[index].stream = base .. moveto .. accent + end + end + end + end + stopparsing(fontdata,data) + else + report("no charstrings") + end + return glyphs + end + + parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams) + + keepcurve = doshapes + version = tversion + strings = data.strings + globals = data.routines or { } + locals = dictionary.subroutines or { } + charset = false + vsindex = dictionary.vsindex or 0 + + local glyphs = glphs or { } + + justpass = streams == true + seacs = { } + + globalbias, localbias = setbias(globals,locals,nobias) + nominalwidth, defaultwidth = setwidths(dictionary.private) + + processshape(glyphs,tab,index-1) + + return glyphs[index] + end + +end + +local function readglobals(f,data,version) + local routines = readlengths(f,version == "cff2") + for i=1,#routines do + routines[i] = readbytetable(f,routines[i]) + end + data.routines = routines +end + +local function readencodings(f,data) + data.encodings = { } +end + +local function readcharsets(f,data,dictionary) + local header = data.header + local strings = data.strings + local nofglyphs = data.nofglyphs + local charsetoffset = dictionary.charset + if charsetoffset and charsetoffset ~= 0 then + setposition(f,header.offset+charsetoffset) + local format = readbyte(f) + local charset = { [0] = ".notdef" } + dictionary.charset = charset + if format == 0 then + for i=1,nofglyphs do + charset[i] = strings[readushort(f)] + end + elseif format == 1 or format == 2 then + local readcount = format == 1 and readbyte or readushort + local i = 1 + while i <= nofglyphs do + local sid = readushort(f) + local n = readcount(f) + for s=sid,sid+n do + charset[i] = strings[s] + i = i + 1 + if i > nofglyphs then + break + end + end + end + else + report("cff parser: unsupported charset format %a",format) + end + else + dictionary.nocharset = true + dictionary.charset = nil + end +end + +local function readprivates(f,data) + local header = data.header + local dictionaries = data.dictionaries + local private = dictionaries[1].private + if private then + setposition(f,header.offset+private.offset) + private.data = readstring(f,private.size) + end +end + +local function readlocals(f,data,dictionary,version) + local header = data.header + local private = dictionary.private + if private then + local subroutineoffset = private.data.subroutines + if subroutineoffset ~= 0 then + setposition(f,header.offset+private.offset+subroutineoffset) + local subroutines = readlengths(f,version == "cff2") + for i=1,#subroutines do + subroutines[i] = readbytetable(f,subroutines[i]) + end + dictionary.subroutines = subroutines + private.data.subroutines = nil + else + dictionary.subroutines = { } + end + else + dictionary.subroutines = { } + end +end + +-- These charstrings are little programs and described in: Technical Note #5177. A truetype +-- font has only one dictionary. + +local function readcharstrings(f,data,version) + local header = data.header + local dictionaries = data.dictionaries + local dictionary = dictionaries[1] + local stringtype = dictionary.charstringtype + local offset = dictionary.charstrings + if type(offset) ~= "number" then + -- weird + elseif stringtype == 2 then + setposition(f,header.offset+offset) + -- could be a metatable .. delayed loading + local charstrings = readlengths(f,version=="cff2") + local nofglyphs = #charstrings + for i=1,nofglyphs do + charstrings[i] = readstring(f,charstrings[i]) + end + data.nofglyphs = nofglyphs + dictionary.charstrings = charstrings + else + report("unsupported charstr type %i",stringtype) + data.nofglyphs = 0 + dictionary.charstrings = { } + end +end + +-- cid (maybe do this stepwise so less mem) -- share with above + +local function readcidprivates(f,data) + local header = data.header + local dictionaries = data.dictionaries[1].cid.dictionaries + for i=1,#dictionaries do + local dictionary = dictionaries[i] + local private = dictionary.private + if private then + setposition(f,header.offset+private.offset) + private.data = readstring(f,private.size) + end + end + parseprivates(data,dictionaries) +end + +readers.parsecharstrings = parsecharstrings -- used in font-onr.lua (type 1) + +local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) + local dictionaries = data.dictionaries + local dictionary = dictionaries[1] + local cid = not dictionary.private and dictionary.cid + readglobals(f,data,version) + readcharstrings(f,data,version) + if version == "cff2" then + dictionary.charset = nil + else + readencodings(f,data) + readcharsets(f,data,dictionary) + end + if cid then + local fdarray = cid.fdarray + if fdarray then + setposition(f,data.header.offset + fdarray) + local dictionaries = readlengths(f,version=="cff2") + local nofdictionaries = #dictionaries + if nofdictionaries > 0 then + for i=1,nofdictionaries do + dictionaries[i] = readstring(f,dictionaries[i]) + end + parsedictionaries(data,dictionaries) + dictionary.private = dictionaries[1].private + if nofdictionaries > 1 then + report("ignoring dictionaries > 1 in cid font") + end + end + end + end + readprivates(f,data) + parseprivates(data,data.dictionaries) + readlocals(f,data,dictionary,version) + startparsing(fontdata,data,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false) + stopparsing(fontdata,data) +end + +local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) + local header = data.header + local dictionaries = data.dictionaries + local dictionary = dictionaries[1] + local cid = dictionary.cid + local cidselect = cid and cid.fdselect + readglobals(f,data,version) + readcharstrings(f,data,version) + if version ~= "cff2" then + readencodings(f,data) + end + local charstrings = dictionary.charstrings + local fdindex = { } + local nofglyphs = data.nofglyphs + local maxindex = -1 + setposition(f,header.offset+cidselect) + local format = readbyte(f) + if format == 1 then + for i=0,nofglyphs do -- notdef included (needs checking) + local index = readbyte(f) + fdindex[i] = index + if index > maxindex then + maxindex = index + end + end + elseif format == 3 then + local nofranges = readushort(f) + local first = readushort(f) + local index = readbyte(f) + while true do + local last = readushort(f) + if index > maxindex then + maxindex = index + end + for i=first,last do + fdindex[i] = index + end + if last >= nofglyphs then + break + else + first = last + 1 + index = readbyte(f) + end + end + else + report("unsupported fd index format %i",format) + end + -- hm, always + if maxindex >= 0 then + local cidarray = cid.fdarray + if cidarray then + setposition(f,header.offset+cidarray) + local dictionaries = readlengths(f,version == "cff2") + if #dictionaries > 0 then + for i=1,#dictionaries do + dictionaries[i] = readstring(f,dictionaries[i]) + end + parsedictionaries(data,dictionaries) + cid.dictionaries = dictionaries + readcidprivates(f,data) + for i=1,#dictionaries do + readlocals(f,data,dictionaries[i],version) + end + startparsing(fontdata,data,streams) + for i=1,#charstrings do + local dictionary = dictionaries[fdindex[i]+1] + if dictionary then + parsecharstring(fontdata,data,dictionary,charstrings[i],glyphs,i,doshapes,version,streams) + else + -- report("no dictionary for %a : %a => %a",version,i,fdindex[i]+1) + end + -- charstrings[i] = false + end + stopparsing(fontdata,data) + else + report("no cid dictionaries") + end + else + report("no cid array") + end + end +end + +local gotodatatable = readers.helpers.gotodatatable + +local function cleanup(data,dictionaries) + -- for i=1,#dictionaries do + -- local d = dictionaries[i] + -- d.subroutines = nil + -- end + -- data.strings = nil + -- if data then + -- data.charstrings = nil + -- data.routines = nil + -- end +end + +function readers.cff(f,fontdata,specification) + local tableoffset = gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs) + if tableoffset then + local header = readheader(f) + if header.major ~= 1 then + report("only version %s is supported for table %a",1,"cff") + return + end + local glyphs = fontdata.glyphs + local names = readfontnames(f) + local dictionaries = readtopdictionaries(f) + local strings = readstrings(f) + local data = { + header = header, + names = names, + dictionaries = dictionaries, + strings = strings, + nofglyphs = fontdata.nofglyphs, + } + -- + parsedictionaries(data,dictionaries,"cff") + -- + local dic = dictionaries[1] + local cid = dic.cid + -- + local cffinfo = { + familyname = dic.familyname, + fullname = dic.fullname, + boundingbox = dic.boundingbox, + weight = dic.weight, + italicangle = dic.italicangle, + underlineposition = dic.underlineposition, + underlinethickness = dic.underlinethickness, + defaultwidth = dic.defaultwidthx, + nominalwidth = dic.nominalwidthx, + monospaced = dic.monospaced, + } + fontdata.cidinfo = cid and { + registry = cid.registry, + ordering = cid.ordering, + supplement = cid.supplement, + } + fontdata.cffinfo = cffinfo + -- + local all = specification.shapes or specification.streams or false + if specification.glyphs or all then + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams) + else + readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams) + end + end + local private = dic.private + if private then + local data = private.data + if type(data) == "table" then + cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth + cffinfo.bluevalues = data.bluevalues + cffinfo.otherblues = data.otherblues + cffinfo.familyblues = data.familyblues + cffinfo.familyotherblues = data.familyotherblues + cffinfo.bluescale = data.bluescale + cffinfo.blueshift = data.blueshift + cffinfo.bluefuzz = data.bluefuzz + cffinfo.stdhw = data.stdhw + cffinfo.stdvw = data.stdvw + cffinfo.stemsnaph = data.stemsnaph + cffinfo.stemsnapv = data.stemsnapv + end + end + cleanup(data,dictionaries) + end +end + +function readers.cff2(f,fontdata,specification) + local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs) + if tableoffset then + local header = readheader(f) + if header.major ~= 2 then + report("only version %s is supported for table %a",2,"cff2") + return + end + local glyphs = fontdata.glyphs + local dictionaries = { readstring(f,header.dsize) } + local data = { + header = header, + dictionaries = dictionaries, + nofglyphs = fontdata.nofglyphs, + } + -- + parsedictionaries(data,dictionaries,"cff2") + -- + local offset = dictionaries[1].vstore + if offset > 0 then + local storeoffset = dictionaries[1].vstore + data.header.offset + 2 -- cff has a preceding size field + local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors) + -- + data.regions = regions + data.deltas = deltas + else + data.regions = { } + data.deltas = { } + end + data.factors = specification.factors + -- + local cid = data.dictionaries[1].cid + local all = specification.shapes or specification.streams or false + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams) + else + readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams) + end + cleanup(data,dictionaries) + end +end + +-- temporary helper needed for checking backend patches + +-- function readers.cffcheck(filename) +-- local f = io.open(filename,"rb") +-- if f then +-- local fontdata = { +-- glyphs = { }, +-- } +-- local header = readheader(f) +-- if header.major ~= 1 then +-- report("only version %s is supported for table %a",1,"cff") +-- return +-- end +-- local names = readfontnames(f) +-- local dictionaries = readtopdictionaries(f) +-- local strings = readstrings(f) +-- local glyphs = { } +-- local data = { +-- header = header, +-- names = names, +-- dictionaries = dictionaries, +-- strings = strings, +-- glyphs = glyphs, +-- nofglyphs = 0, +-- } +-- -- +-- parsedictionaries(data,dictionaries,"cff") +-- -- +-- local cid = data.dictionaries[1].cid +-- if cid and cid.fdselect then +-- readfdselect(f,fontdata,data,glyphs,false) +-- else +-- readnoselect(f,fontdata,data,glyphs,false) +-- end +-- return data +-- end +-- end diff --git a/tex/context/base/mkxl/font-dsp.lmt b/tex/context/base/mkxl/font-dsp.lmt index 1b54bf463..a1bf6f641 100644 --- a/tex/context/base/mkxl/font-dsp.lmt +++ b/tex/context/base/mkxl/font-dsp.lmt @@ -56,11 +56,6 @@ if not modules then modules = { } end modules ['font-dsp'] = { -- less code. After all there are often not that many demanding features. local next, type, tonumber = next, type, tonumber -local band = bit32.band -local extract = bit32.extract -local bor = bit32.bor -local lshift = bit32.lshift -local rshift = bit32.rshift local gsub = string.gsub local lower = string.lower local sub = string.sub @@ -298,7 +293,7 @@ local lookupnames = { -- local lookupstate = setmetatableindex(function(t,k) -- local v = { } -- for kk, vv in next, lookupbits do --- if band(k,kk) ~= 0 then +-- if (k & kk) ~= 0 then -- v[vv] = true -- end -- end @@ -308,10 +303,10 @@ local lookupnames = { local lookupflags = setmetatableindex(function(t,k) local v = { - band(k,0x0008) ~= 0 and true or false, -- ignoremarks - band(k,0x0004) ~= 0 and true or false, -- ignoreligatures - band(k,0x0002) ~= 0 and true or false, -- ignorebaseglyphs - band(k,0x0001) ~= 0 and true or false, -- r2l + (k & 0x0008) ~= 0 and true or false, -- ignoremarks + (k & 0x0004) ~= 0 and true or false, -- ignoreligatures + (k & 0x0002) ~= 0 and true or false, -- ignorebaseglyphs + (k & 0x0001) ~= 0 and true or false, -- r2l } t[k] = v return v @@ -751,16 +746,17 @@ local function readposition(f,format,mainoffset,getdelta) -- .... -- end -- - local x = band(format,0x1) ~= 0 and readshort(f) or 0 -- x placement - local y = band(format,0x2) ~= 0 and readshort(f) or 0 -- y placement - local h = band(format,0x4) ~= 0 and readshort(f) or 0 -- h advance - local v = band(format,0x8) ~= 0 and readshort(f) or 0 -- v advance + local x = (format & 0x1) ~= 0 and readshort(f) or 0 -- x placement + local y = (format & 0x2) ~= 0 and readshort(f) or 0 -- y placement + local h = (format & 0x4) ~= 0 and readshort(f) or 0 -- h advance + local v = (format & 0x8) ~= 0 and readshort(f) or 0 -- v advance if format >= 0x10 then - local X = band(format,0x10) ~= 0 and skipshort(f) or 0 - local Y = band(format,0x20) ~= 0 and skipshort(f) or 0 - local H = band(format,0x40) ~= 0 and skipshort(f) or 0 - local V = band(format,0x80) ~= 0 and skipshort(f) or 0 - local s = skips[extract(format,4,4)] + local X = (format & 0x10) ~= 0 and skipshort(f) or 0 + local Y = (format & 0x20) ~= 0 and skipshort(f) or 0 + local H = (format & 0x40) ~= 0 and skipshort(f) or 0 + local V = (format & 0x80) ~= 0 and skipshort(f) or 0 + -- local s = skips[extract(format,4,4)] + local s = skips[(format >> 4) & 0xF] if s > 0 then skipshort(f,s) end @@ -2159,11 +2155,12 @@ do subtables[j] = offset + readushort(f) -- we can probably put lookupoffset here end -- which one wins? - local markclass = band(flagbits,0x0010) ~= 0 -- usemarkfilteringset + local markclass = (flagbits & 0x0010) ~= 0 -- usemarkfilteringset if markclass then markclass = readushort(f) -- + 1 end - local markset = rshift(flagbits,8) + -- local markset = rshift(flagbits,8) + local markset = (flagbits >> 8) & 0xFFFFFFFF if markset > 0 then markclass = markset -- + 1 end @@ -2607,7 +2604,8 @@ do local length = readushort(f) local coverage = readushort(f) -- bit 8-15 of coverage: format 0 or 2 - local format = rshift(coverage,8) -- is this ok + -- local format = rshift(coverage,8) -- is this ok + local format = (coverage >> 8) & 0xFFFFFFFF -- is this ok if format == 0 then local nofpairs = readushort(f) local searchrange = readushort(f) @@ -3051,7 +3049,7 @@ local function readmathvariants(f,fontdata,offset) advance = readushort(f), } local flags = readushort(f) - if band(flags,0x0001) ~= 0 then + if (flags & 0x0001) ~= 0 then p.extender = 1 -- true end parts[i] = p @@ -4533,16 +4531,19 @@ local function calculate(f,fontdata,specification,offset,field,regions,deltas,no setposition(f,offset) local format = readushort(f) -- todo: check local mapcount = readushort(f) - local entrysize = rshift(band(format,0x0030),4) + 1 - local nofinnerbits = band(format,0x000F) + 1 -- n of inner bits - local innermask = lshift(1,nofinnerbits) - 1 + -- local entrysize = rshift(band(format,0x0030),4) + 1 + local entrysize = (((format & 0x0030) >> 4) & 0xFFFFFFFF) + 1 + local nofinnerbits = (format & 0x000F) + 1 -- n of inner bits + -- local innermask = lshift(1,nofinnerbits) - 1 + local innermask = (1 << nofinnerbits) - 1 local readcardinal = read_cardinal[entrysize] -- 1 upto 4 bytes local innerindex = { } -- size is mapcount local outerindex = { } -- size is mapcount for i=0,mapcount-1 do local mapdata = readcardinal(f) - outerindex[i] = rshift(mapdata,nofinnerbits) - innerindex[i] = band(mapdata,innermask) + -- outerindex[i] = rshift(mapdata,nofinnerbits) + outerindex[i] = (mapdata >> nofinnerbits) & 0xFFFFFFFF + innerindex[i] = (mapdata & innermask) end -- use last entry when no match i setvariabledata(fontdata,"hvarwidths",true) diff --git a/tex/context/base/mkxl/font-lib.mklx b/tex/context/base/mkxl/font-lib.mklx index cf6b51102..6caf1daf8 100644 --- a/tex/context/base/mkxl/font-lib.mklx +++ b/tex/context/base/mkxl/font-lib.mklx @@ -35,30 +35,29 @@ \registerctxluafile{font-fmp}{autosuffix} \registerctxluafile{font-agl}{} % if needed we can comment this and delay loading \registerctxluafile{font-cid}{} % cid maps -\registerctxluafile{font-map}{optimize} +\registerctxluafile{font-map}{} % helpers -\registerctxluafile{font-otr}{optimize} % opentype fontloader +\registerctxluafile{font-otr}{} % opentype fontloader \registerctxluafile{font-web}{} % opentype fontloader -\registerctxluafile{font-cff}{optimize} % quadratic outlines -\registerctxluafile{font-ttf}{optimize} % cubic outlines -\registerctxluafile{font-dsp}{autosuffix,optimize} +\registerctxluafile{font-cff}{autosuffix} % quadratic outlines +\registerctxluafile{font-ttf}{autosuffix} % cubic outlines +\registerctxluafile{font-dsp}{autosuffix} \registerctxluafile{font-hsh}{autosuffix} % hashes used by context \registerctxluafile{font-vfc}{autosuffix} \registerctxluafile{font-prv}{} % needs hashes \registerctxluafile{font-vir}{} -\registerctxluafile{font-nod}{optimize} +\registerctxluafile{font-nod}{} \registerctxluafile{font-oti}{} % otf initialization \registerctxluafile{font-ott}{} % otf tables (first) \registerctxluafile{font-otl}{autosuffix} \registerctxluafile{font-oto}{} -\registerctxluafile{font-otj}{autosuffix,optimize} +\registerctxluafile{font-otj}{autosuffix} \registerctxluafile{font-oup}{} \registerctxluafile{font-ota}{autosuffix} -%registerctxluafile{font-ots-pre-scale}{autosuffix,optimize} -\registerctxluafile{font-ots}{autosuffix,optimize} -\registerctxluafile{font-otd}{autosuffix,optimize} +\registerctxluafile{font-ots}{autosuffix} +\registerctxluafile{font-otd}{autosuffix} \registerctxluafile{font-otc}{} \registerctxluafile{font-oth}{} % \doifelsefileexists{font-osd-new.lmt}{ @@ -71,15 +70,15 @@ % we use otf code for type one -\registerctxluafile{font-onr}{autosuffix,optimize} -\registerctxluafile{font-one}{autosuffix,optimize} +\registerctxluafile{font-onr}{autosuffix} +\registerctxluafile{font-one}{autosuffix} \registerctxluafile{font-afk}{} \registerctxluafile{font-txt}{autosuffix} % tfm -\registerctxluafile{font-tpk}{autosuffix,optimize} +\registerctxluafile{font-tpk}{autosuffix} \registerctxluafile{font-tfm}{autosuffix} % name database diff --git a/tex/context/base/mkxl/font-map.lmt b/tex/context/base/mkxl/font-map.lmt new file mode 100644 index 000000000..be1321384 --- /dev/null +++ b/tex/context/base/mkxl/font-map.lmt @@ -0,0 +1,518 @@ +if not modules then modules = { } end modules ['font-map'] = { + version = 1.001, + optimize = true, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local tonumber, next, type = tonumber, next, type + +local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower +local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match +local formatters = string.formatters +local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys + +local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end) +local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_mapping = v end) + +local report_fonts = logs.reporter("fonts","loading") -- not otf only + +-- force_ligatures was true for a while so that these emoji's with bad names work too + +local force_ligatures = false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures = v end) + +local fonts = fonts or { } +local mappings = fonts.mappings or { } +fonts.mappings = mappings + +local allocate = utilities.storage.allocate + +local hex = R("AF","af","09") +local hexfour = (hex*hex*hex^-2) / function(s) return tonumber(s,16) end +local hexsix = (hex*hex*hex^-4) / function(s) return tonumber(s,16) end +local dec = (R("09")^1) / tonumber +local period = P(".") +local unicode = (P("uni") + P("UNI")) * (hexfour * (period + P(-1)) * Cc(false) + Ct(hexfour^1) * Cc(true)) -- base planes +local ucode = (P("u") + P("U") ) * (hexsix * (period + P(-1)) * Cc(false) + Ct(hexsix ^1) * Cc(true)) -- extended +local index = P("index") * dec * Cc(false) + +local parser = unicode + ucode + index +local parsers = { } + +local function makenameparser(str) + if not str or str == "" then + return parser + else + local p = parsers[str] + if not p then + p = P(str) * period * dec * Cc(false) + parsers[str] = p + end + return p + end +end + +local f_single = formatters["%04X"] +local f_double = formatters["%04X%04X"] +local s_unknown = "FFFD" + +local function tounicode16(unicode) + if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then + return f_single(unicode) + elseif unicode >= 0x00E000 and unicode <= 0x00F8FF then + return s_unknown + elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFF then + return s_unknown + elseif unicode >= 0x100000 and unicode <= 0x10FFFF then + return s_unknown + elseif unicode >= 0x00D800 and unicode <= 0x00DFFF then + return s_unknown + else + unicode = unicode - 0x10000 + return f_double((k//0x400)+0xD800,unicode%0x400+0xDC00) + end +end + +local function tounicode16sequence(unicodes) + local t = { } + for l=1,#unicodes do + local u = unicodes[l] + if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then + t[l] = f_single(u) + elseif unicode >= 0x00E000 and unicode <= 0x00F8FF then + t[l] = s_unknown + elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFF then + t[l] = s_unknown + elseif unicode >= 0x100000 and unicode <= 0x10FFFF then + t[l] = s_unknown + -- elseif unicode >= 0x00D800 and unicode <= 0x00DFFF then + elseif unicode >= 0x00D7FF and unicode <= 0x00DFFF then + t[l] = s_unknown + else + u = u - 0x10000 + t[l] = f_double((k//0x400)+0xD800,u%0x400+0xDC00) + end + end + return concat(t) +end + + +local hash = { } +local conc = { } + +table.setmetatableindex(hash,function(t,k) + local v + if k < 0xD7FF or (k > 0xDFFF and k <= 0xFFFF) then + v = f_single(k) + else + local k = k - 0x10000 + v = f_double((k//0x400)+0xD800,k%0x400+0xDC00) + end + t[k] = v + return v +end) + +local function tounicode(k) + if type(k) == "table" then + local n = #k + for l=1,n do + conc[l] = hash[k[l]] + end + return concat(conc,"",1,n) + elseif k >= 0x00E000 and k <= 0x00F8FF then + return s_unknown + elseif k >= 0x0F0000 and k <= 0x0FFFFF then + return s_unknown + elseif k >= 0x100000 and k <= 0x10FFFF then + return s_unknown + -- elseif k >= 0x00D800 and k <= 0x00DFFF then + elseif k >= 0x00D7FF and k <= 0x00DFFF then + return s_unknown + else + return hash[k] + end +end + +local function fromunicode16(str) + if #str == 4 then + return tonumber(str,16) + else + local l, r = match(str,"(....)(....)") + return 0x10000 + (tonumber(l,16)-0xD800)*0x400 + tonumber(r,16) - 0xDC00 + end +end + +-- Slightly slower: +-- +-- local p = C(4) * (C(4)^-1) / function(l,r) +-- if r then +-- return (tonumber(l,16))*0x400 + tonumber(r,16) - 0xDC00 +-- else +-- return tonumber(l,16) +-- end +-- end +-- +-- local function fromunicode16(str) +-- return lpegmatch(p,str) +-- end + +mappings.makenameparser = makenameparser +mappings.tounicode = tounicode +mappings.tounicode16 = tounicode16 +mappings.tounicode16sequence = tounicode16sequence +mappings.fromunicode16 = fromunicode16 + +-- mozilla emoji has bad lig names: name = gsub(name,"(u[a-f0-9_]+)%-([a-f0-9_]+)","%1_%2") + +local ligseparator = P("_") +local varseparator = P(".") +local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * C((1 - ligseparator - varseparator)^1))^0) + +-- maybe: ff fi fl ffi ffl => f_f f_i f_l f_f_i f_f_l + +-- local function test(name) +-- local split = lpegmatch(namesplitter,name) +-- print(string.formatters["%s: [% t]"](name,split)) +-- end + +-- test("i.f_") +-- test("this") +-- test("this.that") +-- test("japan1.123") +-- test("such_so_more") +-- test("such_so_more.that") + +-- to be completed .. for fonts that use unicodes for ligatures which +-- is a actually a bad thing and should be avoided in the first place + +do + + local overloads = { + IJ = { name = "I_J", unicode = { 0x49, 0x4A }, mess = 0x0132 }, + ij = { name = "i_j", unicode = { 0x69, 0x6A }, mess = 0x0133 }, + ff = { name = "f_f", unicode = { 0x66, 0x66 }, mess = 0xFB00 }, + fi = { name = "f_i", unicode = { 0x66, 0x69 }, mess = 0xFB01 }, + fl = { name = "f_l", unicode = { 0x66, 0x6C }, mess = 0xFB02 }, + ffi = { name = "f_f_i", unicode = { 0x66, 0x66, 0x69 }, mess = 0xFB03 }, + ffl = { name = "f_f_l", unicode = { 0x66, 0x66, 0x6C }, mess = 0xFB04 }, + fj = { name = "f_j", unicode = { 0x66, 0x6A } }, + fk = { name = "f_k", unicode = { 0x66, 0x6B } }, + + -- endash = { name = "endash", unicode = 0x2013, mess = 0x2013 }, + -- emdash = { name = "emdash", unicode = 0x2014, mess = 0x2014 }, + } + + local o = allocate { } + + for k, v in next, overloads do + local name = v.name + local mess = v.mess + if name then + o[name] = v + end + if mess then + o[mess] = v + end + o[k] = v + end + + mappings.overloads = o + +end + +function mappings.addtounicode(data,filename,checklookups,forceligatures) + local resources = data.resources + local unicodes = resources.unicodes + if not unicodes then + if trace_mapping then + report_fonts("no unicode list, quitting tounicode for %a",filename) + end + return + end + local properties = data.properties + local descriptions = data.descriptions + local overloads = mappings.overloads + -- we need to move this code + unicodes['space'] = unicodes['space'] or 32 + unicodes['hyphen'] = unicodes['hyphen'] or 45 + unicodes['zwj'] = unicodes['zwj'] or 0x200D + unicodes['zwnj'] = unicodes['zwnj'] or 0x200C + -- + local private = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF + local unicodevector = fonts.encodings.agl.unicodes or { } -- loaded runtime in context + local contextvector = fonts.encodings.agl.ctxcodes or { } -- loaded runtime in context + local missing = { } + local nofmissing = 0 + local oparser = nil + local cidnames = nil + local cidcodes = nil + local cidinfo = properties.cidinfo + local usedmap = cidinfo and fonts.cid.getmap(cidinfo) + local uparser = makenameparser() -- hm, every time? + if usedmap then + oparser = usedmap and makenameparser(cidinfo.ordering) + cidnames = usedmap.names + cidcodes = usedmap.unicodes + end + local ns = 0 + local nl = 0 + -- + -- in order to avoid differences between runs due to hash randomization we + -- run over a sorted list + -- + local dlist = sortedkeys(descriptions) + -- + -- for du, glyph in next, descriptions do + for i=1,#dlist do + local du = dlist[i] + local glyph = descriptions[du] + local name = glyph.name + if name then + local overload = overloads[name] or overloads[du] + if overload then + -- get rid of weird ligatures + -- glyph.name = overload.name + glyph.unicode = overload.unicode + else + local gu = glyph.unicode -- can already be set (number or table) + if not gu or gu == -1 or du >= private or (du >= 0xE000 and du <= 0xF8FF) or du == 0xFFFE or du == 0xFFFF then + local unicode = unicodevector[name] or contextvector[name] + if unicode then + glyph.unicode = unicode + ns = ns + 1 + end + -- cidmap heuristics, beware, there is no guarantee for a match unless + -- the chain resolves + if (not unicode) and usedmap then + local foundindex = lpegmatch(oparser,name) + if foundindex then + unicode = cidcodes[foundindex] -- name to number + if unicode then + glyph.unicode = unicode + ns = ns + 1 + else + local reference = cidnames[foundindex] -- number to name + if reference then + local foundindex = lpegmatch(oparser,reference) + if foundindex then + unicode = cidcodes[foundindex] + if unicode then + glyph.unicode = unicode + ns = ns + 1 + end + end + if not unicode or unicode == "" then + local foundcodes, multiple = lpegmatch(uparser,reference) + if foundcodes then + glyph.unicode = foundcodes + if multiple then + nl = nl + 1 + unicode = true + else + ns = ns + 1 + unicode = foundcodes + end + end + end + end + end + end + end + -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_ + -- + -- It is not trivial to find a solution that suits all fonts. We tried several alternatives + -- and this one seems to work reasonable also with fonts that use less standardized naming + -- schemes. The extra private test is tested by KE and seems to work okay with non-typical + -- fonts as well. + -- + if not unicode or unicode == "" then + local split = lpegmatch(namesplitter,name) + local nsplit = split and #split or 0 -- add if + if nsplit == 0 then + -- skip + elseif nsplit == 1 then + local base = split[1] + local u = unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + -- skip + elseif type(u) == "table" then + -- unlikely + if u[1] < private then + unicode = u + glyph.unicode = unicode + end + elseif u < private then + unicode = u + glyph.unicode = unicode + end + else + local t = { } + local n = 0 + for l=1,nsplit do + local base = split[l] + local u = unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + break + elseif type(u) == "table" then + if u[1] >= private then + break + end + n = n + 1 + t[n] = u[1] + else + if u >= private then + break + end + n = n + 1 + t[n] = u + end + end + if n > 0 then + if n == 1 then + unicode = t[1] + else + unicode = t + end + glyph.unicode = unicode + end + end + nl = nl + 1 + end + -- last resort (we might need to catch private here as well) + if not unicode or unicode == "" then + local foundcodes, multiple = lpegmatch(uparser,name) + if foundcodes then + glyph.unicode = foundcodes + if multiple then + nl = nl + 1 + unicode = true + else + ns = ns + 1 + unicode = foundcodes + end + end + end + -- check using substitutes and alternates + local r = overloads[unicode] + if r then + unicode = r.unicode + glyph.unicode = unicode + end + -- + if not unicode then + missing[du] = true + nofmissing = nofmissing + 1 + end + else + -- maybe a message or so + end + end + else + local overload = overloads[du] + if overload then + glyph.unicode = overload.unicode + elseif not glyph.unicode then + missing[du] = true + nofmissing = nofmissing + 1 + end + end + end + if type(checklookups) == "function" then + checklookups(data,missing,nofmissing) + end + + local unicoded = 0 + local collected = fonts.handlers.otf.readers.getcomponents(data) -- neglectable overhead + + local function resolve(glyph,u) + local n = #u + for i=1,n do + if u[i] > private then + n = 0 + break + end + end + if n > 0 then + if n > 1 then + glyph.unicode = u + else + glyph.unicode = u[1] + end + unicoded = unicoded + 1 + end + end + + if not collected then + -- move on + elseif forceligatures or force_ligatures then + for i=1,#dlist do + local du = dlist[i] + if du >= private or (du >= 0xE000 and du <= 0xF8FF) then + local u = collected[du] -- always tables + if u then + resolve(descriptions[du],u) + end + end + end + else + for i=1,#dlist do + local du = dlist[i] + if du >= private or (du >= 0xE000 and du <= 0xF8FF) then + local glyph = descriptions[du] + if glyph.class == "ligature" and not glyph.unicode then + local u = collected[du] -- always tables + if u then + resolve(glyph,u) + end + end + end + end + end + + if trace_mapping and unicoded > 0 then + report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded) + end + if trace_mapping then + -- for unic, glyph in sortedhash(descriptions) do + for i=1,#dlist do + local du = dlist[i] + local glyph = descriptions[du] + local name = glyph.name or "-" + local index = glyph.index or 0 + local unicode = glyph.unicode + if unicode then + if type(unicode) == "table" then + local unicodes = { } + for i=1,#unicode do + unicodes[i] = formatters("%U",unicode[i]) + end + report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,du,unicodes) + else + report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,du,unicode) + end + else + report_fonts("internal slot %U, name %a, unicode %U",index,name,du) + end + end + end + if trace_loading and (ns > 0 or nl > 0) then + report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns) + end +end + +-- local parser = makenameparser("Japan1") +-- local parser = makenameparser() +-- local function test(str) +-- local b, a = lpegmatch(parser,str) +-- print((a and table.serialize(b)) or b) +-- end +-- test("a.sc") +-- test("a") +-- test("uni1234") +-- test("uni1234.xx") +-- test("uni12349876") +-- test("u123400987600") +-- test("index1234") +-- test("Japan1.123") diff --git a/tex/context/base/mkxl/font-onr.lmt b/tex/context/base/mkxl/font-onr.lmt index 2c18f6e89..d28c247df 100644 --- a/tex/context/base/mkxl/font-onr.lmt +++ b/tex/context/base/mkxl/font-onr.lmt @@ -26,7 +26,7 @@ local next, type, tonumber, rawset = next, type, tonumber, rawset local match, lower, gsub, strip, find = string.match, string.lower, string.gsub, string.strip, string.find local char, byte, sub = string.char, string.byte, string.sub local abs = math.abs -local bxor, rshift = bit32.bxor, bit32.rshift +----- bxor, rshift = bit32.bxor, bit32.rshift local P, S, R, V, Cmt, C, Ct, Cs, Carg, Cf, Cg, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.V, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg, lpeg.Cf, lpeg.Cg, lpeg.Cc local lpegmatch, patterns = lpeg.match, lpeg.patterns @@ -68,8 +68,10 @@ do local function step(c) local cipher = byte(c) - local plain = bxor(cipher,rshift(r,8)) - r = ((cipher + r) * c1 + c2) % 65536 + -- local plain = bxor(cipher,rshift(r,8)) + local plain = (cipher ~ ((r >> 8) & 0xFFFFFFFF)) + -- r = ((cipher + r) * c1 + c2) % 65536 + r = ((cipher + r) * c1 + c2) % 0x10000 return char(plain) end diff --git a/tex/context/base/mkxl/font-tpk.lmt b/tex/context/base/mkxl/font-tpk.lmt index d265433c5..fc6789402 100644 --- a/tex/context/base/mkxl/font-tpk.lmt +++ b/tex/context/base/mkxl/font-tpk.lmt @@ -13,8 +13,8 @@ if not modules then modules = { } end modules ['font-tpk'] = { -- luatex. All do things a bit more luaish and errors are of course mine. local next = next -local extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift -local idiv = number.idiv +----- extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift +----- idiv = number.idiv local char = string.char local concat, insert, remove, copy = table.concat, table.insert, table.remove, table.copy local tobitstring = number.tobitstring @@ -67,20 +67,22 @@ do if bitweight == 0 then bitweight = 16 inputbyte = readbyte(s) - return extract(inputbyte,4,4) + -- return extract(inputbyte,4,4) + return (inputbyte >> 4) & 0xF else bitweight = 0 - return band(inputbyte,15) + return inputbyte & 15 end end local function getbit() -- can be inlined - bitweight = rshift(bitweight,1) + -- bitweight = rshift(bitweight,1) + bitweight = (bitweight >> 1) & 0xFFFFFFFF if bitweight == 0 then -- actually we can check for 1 inputbyte = readbyte(s) bitweight = 128 end - return band(inputbyte,bitweight) + return inputbyte & bitweight end local function pkpackednum() @@ -130,8 +132,8 @@ do local function handlehuge(i,j) while i ~= 0 do - j = lshift(j,4) + getnyb() - -- j = extract(j,8,4) + getnyb() + -- j = lshift(j,4) + getnyb() + j = ((j << 4) & 0xFFFFFFFF) + getnyb() i = i - 1 end remainder = j - 15 + (13 - dynf) * 16 + dynf @@ -153,14 +155,14 @@ do local ysize = glyph.ysize local word = 0 local wordweight = 0 - local wordwidth = idiv(xsize + 15,16) + local wordwidth = (xsize + 15) // 16 local rowsleft = 0 - local turnon = band(flagbyte,8) == 8 and true or false + local turnon = (flagbyte & 8) == 8 and true or false local hbit = 0 local count = 0 -- realfunc = pkpackednum - dynf = idiv(flagbyte,16) + dynf = flagbyte // 16 -- if dynf == 14 then bitweight = 0 @@ -171,7 +173,8 @@ do if getbit() ~= 0 then word = word + wordweight end - wordweight = rshift(wordweight,1) + -- wordweight = rshift(wordweight,1) + wordweight = (wordweight >> 1) & 0xFFFFFFFF if wordweight == 0 then r = r + 1 raster[r] = word @@ -247,8 +250,8 @@ do local rr = { } local r = 0 local s = 0 - local cw = idiv(xsize+ 7, 8) - local rw = idiv(xsize+15,16) + local cw = (xsize+ 7) // 8 + local rw = (xsize+15) // 16 local extra = 2 * rw == cw local b for y=1,ysize do @@ -261,7 +264,8 @@ do if extra then r = r + 1 ; rr[r] = tobitstring(b,16,16) else - r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw) + -- r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw) + r = r + 1 ; rr[r] = tobitstring((b >> (8+(8-cw))) &~ (-1 << cw),cw,cw) end result[y] = concat(rr) end @@ -304,20 +308,23 @@ Q]] ] local result = { } local r = 0 local s = 0 - local cw = idiv(xsize+ 7, 8) - local rw = idiv(xsize+15,16) + local cw = (xsize+ 7) // 8 + local rw = (xsize+15) // 16 local extra = 2 * rw == cw local b for y=1,ysize do for x=1,rw-1 do s = s + 1 ; b = stream[s] - r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + -- r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + r = r + 1 ; result[r] = char((b >> 8) & 0xFF,b & 0xFF) end s = s + 1 ; b = stream[s] if extra then - r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + -- r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + r = r + 1 ; result[r] = char((b >> 8) & 0xFF,b & 0xFF) else - r = r + 1 ; result[r] = char(extract(b,8,8)) + -- r = r + 1 ; result[r] = char(extract(b,8,8)) + r = r + 1 ; result[r] = char((b >> 8) & 0xFF) end end return template(width,llx,lly,urx,ury,xdpi,ydpi,llx,lly,xsize,ysize,result), width @@ -346,10 +353,10 @@ Q]] ] while true do local flagbyte = readcardinal1(s) if flagbyte < 240 then - local c = band(flagbyte,7) + local c = flagbyte & 7 local length, index, width, pixels, xsize, ysize, xoffset, yoffset if c >= 0 and c <= 3 then - length = band(flagbyte,7) * 256 + readcardinal1(s) - 3 + length = (flagbyte & 7) * 256 + readcardinal1(s) - 3 index = readcardinal1(s) width = readinteger3(s) pixels = readcardinal1(s) @@ -364,7 +371,7 @@ Q]] ] yoffset = yoffset - 256 end elseif c >= 4 and c <= 6 then - length = band(flagbyte,3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4 + length = (flagbyte & 3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4 index = readcardinal1(s) width = readinteger3(s) pixels = readcardinal2(s) @@ -587,8 +594,9 @@ do end local checksum = readcardinal4(s) local designsize = readcardinal2(s) - designsize = designsize * 256 + readcardinal1(s) - designsize = designsize * 16 + rshift(readcardinal1(s),4) + designsize = designsize * 256 + readcardinal1(s) + -- designsize = designsize * 16 + rshift(readcardinal1(s),4) + designsize = designsize * 16 + (readcardinal1(s) >> 4) if designsize < 0xFFFF then return someerror("weird designsize") end @@ -596,15 +604,17 @@ do local alpha = 16 local z = designsize while z >= 040000000 do - z = rshift(z,1) + -- z = rshift(z,1) + z = (z >> 1) & 0xFFFFFFFF alpha = alpha + alpha end - local beta = idiv(256,alpha) + local beta = 256 // alpha alpha = alpha * z -- local function readscaled() local a, b, c, d = readbytes(s,4) - local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta) + -- local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta) + local n = (((((((d * z) >> 8) & 0xFFFFFFFF) + c * z) >> 8) & 0xFFFFFFFF) + b * z) // beta if a == 0 then return n elseif a == 255 then @@ -619,7 +629,8 @@ do if a > 127 then a = a - 256 end - return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4) + -- return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4) + return a * 0xFFFFF + b * 0xFFF + c * 0xF + ((d >> 4) & 0xFFFFFFFF) end -- while lh > 2 do -- can be one-liner @@ -775,11 +786,15 @@ do else width = readcardinal1(s) height = readcardinal1(s) - depth = extract(height,0,4) - height = extract(height,4,4) + -- depth = extract(height,0,4) + depth = height & 0xF + -- height = extract(height,4,4) + height = (height >> 4) & 0xF italic = readcardinal1(s) - tag = extract(italic,0,2) - italic = extract(italic,2,6) + -- tag = extract(italic,0,2) + tag = italic & 0x03 + -- italic = extract(italic,2,6) + italic = (italic >> 2) & 0xFF remainder = readcardinal1(s) end if width == 0 then @@ -964,7 +979,7 @@ do local function scaled2() local a, b = readbytes(s,2) - local sw = idiv(b*z,beta) + local sw = (b*z) // beta if a == 0 then return sw elseif a == 255 then @@ -976,7 +991,8 @@ do local function scaled3() local a, b, c = readbytes(s,3) - local sw = idiv(rshift(c*z,8)+b*z,beta) + -- local sw = idiv(rshift(c*z,8)+b*z,beta) + local sw = ((((c * z) >> 8) & 0xFFFFFFFF) + b * z) // beta if a == 0 then return sw elseif a == 255 then @@ -988,7 +1004,8 @@ do local function scaled4() local a, b, c, d = readbytes(s,4) - local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta) + -- local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta) + local sw = (((((d * z) >> 8) & 0xFFFFFFFF + (c * z)) >> 8) & 0xFFFFFFFF + b * z) // beta if a == 0 then return sw elseif a == 255 then @@ -1162,17 +1179,18 @@ do end local header = readstring(s,readcardinal1(s)) local checksum = readcardinal4(s) - local designsize = idiv(readcardinal4(s),16) + local designsize = readcardinal4(s) // 16 local fonts = data and data.fonts or { } local glyphs = data and data.glyphs or { } -- alpha = 16 z = designsize while z >= 040000000 do - z = rshift(z,1) + -- z = rshift(z,1) + z = (z >> 1) & 0xFFFFFFFF alpha = alpha + alpha end - beta = idiv(256,alpha) + beta = 256 // alpha alpha = alpha * z -- cmd = readcardinal1(s) @@ -1191,7 +1209,7 @@ do end local checksum = skipbytes(s,4) local size = scaled4() - local designsize = idiv(readcardinal4(s),16) + local designsize = readcardinal4(s) // 16 local pathlen = readcardinal1(s) local namelen = readcardinal1(s) local path = readstring(s,pathlen) @@ -1267,7 +1285,7 @@ do local vffile = resolvers.findbinfile(vfname,"ovf") if tfmfile and tfmfile ~= "" then if size < 0 then - size = idiv(65536 * -size,100) + size = (65536 * -size) // 100 end local data = readers.loadtfm(tfmfile) if data.error then diff --git a/tex/context/base/mkxl/font-ttf.lmt b/tex/context/base/mkxl/font-ttf.lmt new file mode 100644 index 000000000..fa0e3c494 --- /dev/null +++ b/tex/context/base/mkxl/font-ttf.lmt @@ -0,0 +1,1496 @@ +if not modules then modules = { } end modules ['font-ttf'] = { + version = 1.001, + optimize = true, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This version is different from previous in the sense that we no longer store +-- contours but keep points and contours (endpoints) separate for a while +-- because later on we need to apply deltas and that is easier on a list of +-- points. + +-- The code is a bit messy. I looked at the ff code but it's messy too. It has +-- to do with the fact that we need to look at points on the curve and control +-- points in between. This also means that we start at point 2 and have to look +-- at point 1 when we're at the end. We still use a ps like storage with the +-- operator last in an entry. It's typical code that evolves stepwise till a +-- point of no comprehension. + +-- For deltas we need a rather complex loop over points that can have holes and +-- be less than nofpoints and even can have duplicates and also the x and y value +-- lists can be shorter than etc. I need fonts in order to complete this simply +-- because I need to visualize in order to understand (what the standard tries +-- to explain). + +-- 0 point then none applied +-- 1 points then applied to all +-- otherwise inferred deltas using nearest +-- if no lower point then use highest referenced point +-- if no higher point then use lowest referenced point +-- factor = (target-left)/(right-left) +-- delta = (1-factor)*left + factor * right + +local next, type, unpack = next, type, unpack +----- band, rshift = bit32.band, bit32.rshift +local sqrt, round, abs, min, max = math.sqrt, math.round, math.abs, math.min, math.max +local char, rep = string.char, string.rep +local concat = table.concat +local setmetatableindex = table.setmetatableindex + +local report = logs.reporter("otf reader","ttf") + +local trace_deltas = false + +local readers = fonts.handlers.otf.readers +local streamreader = readers.streamreader + +local setposition = streamreader.setposition +local getposition = streamreader.getposition +local skipbytes = streamreader.skip +local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer +local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer +local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer +local readchar = streamreader.readinteger1 -- 8-bit signed integer +local readshort = streamreader.readinteger2 -- 16-bit signed integer +local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14) +local readinteger = streamreader.readinteger1 +local readcardinaltable = streamreader.readcardinaltable +local readintegertable = streamreader.readintegertable + +directives.register("fonts.streamreader",function() + + streamreader = utilities.streams + + setposition = streamreader.setposition + getposition = streamreader.getposition + skipbytes = streamreader.skip + readbyte = streamreader.readcardinal1 + readushort = streamreader.readcardinal2 + readulong = streamreader.readcardinal4 + readchar = streamreader.readinteger1 + readshort = streamreader.readinteger2 + read2dot14 = streamreader.read2dot14 + readinteger = streamreader.readinteger1 + readcardinaltable = streamreader.readcardinaltable + readintegertable = streamreader.readintegertable + +end) + +local short = 2 +local ushort = 2 +local ulong = 4 + +local helpers = readers.helpers +local gotodatatable = helpers.gotodatatable + +local function mergecomposites(glyphs,shapes) + + -- todo : deltas + + local function merge(index,shape,components) + local contours = { } + local points = { } + local nofcontours = 0 + local nofpoints = 0 + local offset = 0 + local deltas = shape.deltas + for i=1,#components do + local component = components[i] + local subindex = component.index + local subshape = shapes[subindex] + local subcontours = subshape.contours + local subpoints = subshape.points + if not subcontours then + local subcomponents = subshape.components + if subcomponents then + subcontours, subpoints = merge(subindex,subshape,subcomponents) + end + end + if subpoints then + local matrix = component.matrix + local xscale = matrix[1] + local xrotate = matrix[2] + local yrotate = matrix[3] + local yscale = matrix[4] + local xoffset = matrix[5] + local yoffset = matrix[6] + local count = #subpoints + if xscale == 1 and yscale == 1 and xrotate == 0 and yrotate == 0 then + for i=1,count do + local p = subpoints[i] + nofpoints = nofpoints + 1 + points[nofpoints] = { + p[1] + xoffset, + p[2] + yoffset, + p[3] + } + end + else + for i=1,count do + local p = subpoints[i] + local x = p[1] + local y = p[2] + nofpoints = nofpoints + 1 + points[nofpoints] = { + -- unifractur : u n + -- seguiemj : 0x270E 0x2710 + xscale * x + xrotate * y + xoffset, + yscale * y + yrotate * x + yoffset, +-- xscale * x + yrotate * y + xoffset, +-- xrotate * x + yscale * y + yoffset, + p[3] + } + end + end + local subcount = #subcontours + if subcount == 1 then + nofcontours = nofcontours + 1 + contours[nofcontours] = offset + subcontours[1] + else + for i=1,#subcontours do + nofcontours = nofcontours + 1 + contours[nofcontours] = offset + subcontours[i] + end + end + offset = offset + count + else + report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex) + end + end + shape.points = points -- todo : phantom points + shape.contours = contours + shape.components = nil + return contours, points + end + + for index=0,#glyphs do + local shape = shapes[index] + if shape then + local components = shape.components + if components then + merge(index,shape,components) + end + end + end + +end + +local function readnothing(f) + return { + type = "nothing", + } +end + +-- begin of converter + +local function curveto(m_x,m_y,l_x,l_y,r_x,r_y) -- todo: inline this + return + l_x + 2/3 *(m_x-l_x), l_y + 2/3 *(m_y-l_y), + r_x + 2/3 *(m_x-r_x), r_y + 2/3 *(m_y-r_y), + r_x, r_y, "c" +end + +-- We could omit the operator which saves some 10%: +-- +-- #2=lineto #4=quadratic #6=cubic #3=moveto (with "m") +-- +-- This is tricky ... something to do with phantom points .. however, the hvar +-- and vvar tables should take care of the width .. the test font doesn't have +-- those so here we go then (we need a flag for hvar). +-- +-- h-advance left-side-bearing v-advance top-side-bearing +-- +-- We had two loops (going backward) but can do it in one loop .. but maybe we +-- should only accept fonts with proper hvar tables. + +-- dowidth is kind of hack ... fonts are not always ok wrt these extra points + +local xv = { } -- we share this cache +local yv = { } -- we share this cache + +local function applyaxis(glyph,shape,deltas,dowidth) + local points = shape.points + if points then + local nofpoints = #points + local dw = 0 + local dl = 0 + for i=1,#deltas do + local deltaset = deltas[i] + local xvalues = deltaset.xvalues + local yvalues = deltaset.yvalues + if xvalues and yvalues then + local dpoints = deltaset.points + local factor = deltaset.factor + if dpoints then + local cnt = #dpoints + if dowidth then + cnt = cnt - 4 + end + if cnt > 0 then + -- Not the most efficient solution but we seldom do this. We + -- actually need to avoid the extra points here but I'll deal + -- with that when needed. + local contours = shape.contours + local nofcontours = #contours + local first = 1 + local firstindex = 1 + for contour=1,nofcontours do + local last = contours[contour] + if last >= first then + local lastindex = cnt + if firstindex < cnt then + for currentindex=firstindex,cnt do + local found = dpoints[currentindex] + if found <= first then + firstindex = currentindex + end + if found == last then + lastindex = currentindex + break + elseif found > last then + -- \definefontfeature[book][default][axis={weight=800}] + -- \definefont[testfont][file:Commissioner-vf-test.ttf*book] + -- \testfont EΘÄΞ + while lastindex > 1 and dpoints[lastindex] > last do + lastindex = lastindex - 1 + end + -- + break + end + end + end + -- print("unicode: ",glyph.unicode or "?") + -- print("contour: ",first,contour,last) + -- print("index : ",firstindex,lastindex,cnt) + -- print("points : ",dpoints[firstindex],dpoints[lastindex]) + local function find(i) + local prv = lastindex + for j=firstindex,lastindex do + local nxt = dpoints[j] -- we could save this lookup when we return it + if nxt == i then + return false, j, false + elseif nxt > i then + return prv, false, j + end + prv = j + end + return prv, false, firstindex + end + -- We need the first and last points untouched so we first + -- collect data. + for point=first,last do + local d1, d2, d3 = find(point) + local p2 = points[point] + if d2 then + xv[point] = xvalues[d2] + yv[point] = yvalues[d2] + else + local n1 = dpoints[d1] + local n3 = dpoints[d3] + -- Some day I need to figure out these extra points but + -- I'll wait till the standard is more clear and fonts + -- become better (ntg-context: fraunces.ttf > abcdef). + if n1 > nofpoints then + n1 = nofpoints + end + if n3 > nofpoints then + n3 = nofpoints + end + -- + local p1 = points[n1] + local p3 = points[n3] + local p1x = p1[1] + local p2x = p2[1] + local p3x = p3[1] + local p1y = p1[2] + local p2y = p2[2] + local p3y = p3[2] + local x1 = xvalues[d1] + local y1 = yvalues[d1] + local x3 = xvalues[d3] + local y3 = yvalues[d3] + -- + local fx + local fy + -- + if p1x == p3x then + if x1 == x3 then + fx = x1 + else + fx = 0 + end + elseif p2x <= min(p1x,p3x) then + if p1x < p3x then + fx = x1 + else + fx = x3 + end + elseif p2x >= max(p1x,p3x) then + if p1x > p3x then + fx = x1 + else + fx = x3 + end + else + fx = (p2x - p1x)/(p3x - p1x) +-- fx = round(fx) + fx = (1 - fx) * x1 + fx * x3 + end + -- + if p1y == p3y then + if y1 == y3 then + fy = y1 + else + fy = 0 + end + elseif p2y <= min(p1y,p3y) then + if p1y < p3y then + fy = y1 + else + fy = y3 + end + elseif p2y >= max(p1y,p3y) then + if p1y > p3y then + fy = y1 + else + fy = y3 + end + else + fy = (p2y - p1y)/(p3y - p1y) +-- fy = round(fy) + fy = (1 - fy) * y1 + fy * y3 + end + -- -- maybe: + -- if p1y ~= p3y then + -- fy = (p2y - p1y)/(p3y - p1y) + -- fy = (1 - fy) * y1 + fy * y3 + -- elseif abs(p1y-p2y) < abs(p3y-p2y) then + -- fy = y1 + -- else + -- fy = y3 + -- end + -- + xv[point] = fx + yv[point] = fy + end + end + if lastindex < cnt then + firstindex = lastindex + 1 + end + end + first = last + 1 + end + + for i=1,nofpoints do + local pi = points[i] + local fx = xv[i] + local fy = yv[i] + if fx ~= 0 then + pi[1] = pi[1] + factor * fx + end + if fy ~= 0 then + pi[2] = pi[2] + factor * fy + end + end + else + report("bad deltapoint data, maybe a missing hvar table") + end + else + for i=1,nofpoints do + local p = points[i] + local x = xvalues[i] + if x then + local y = yvalues[i] + if x ~= 0 then + p[1] = p[1] + factor * x + end + if y ~= 0 then + p[2] = p[2] + factor * y + end + else + break + end + end + end + if dowidth then + local h = nofpoints + 2 -- weird, the example font seems to have left first + local l = nofpoints + 1 + ----- v = nofpoints + 3 + ----- t = nofpoints + 4 + local x = xvalues[h] + if x then + dw = dw + factor * x + end + local x = xvalues[l] + if x then + dl = dl + factor * x + end + end + end + end + -- for i=1,nofpoints do + -- local p = points[i] + -- p[1] = round(p[1]) + -- p[2] = round(p[2]) + -- end + if dowidth then + local width = glyph.width or 0 + -- local lsb = glyph.lsb or 0 + glyph.width = width + dw - dl + end + else + report("no points for glyph %a",glyph.name) + end +end + +-- round or not ? + +-- local quadratic = true -- both methods work, todo: install a directive +local quadratic = false + +local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox overhead +-- for index=1,#glyphs do + for index=0,#glyphs-1 do + local shape = shapes[index] + if shape then + local glyph = glyphs[index] + local contours = shape.contours + local points = shape.points + if contours then + local nofcontours = #contours + local segments = { } + local nofsegments = 0 + glyph.segments = segments + if nofcontours > 0 then + local px = 0 + local py = 0 + local first = 1 + for i=1,nofcontours do + local last = contours[i] + if last >= first then + local first_pt = points[first] + local first_on = first_pt[3] + -- todo no new tables but reuse lineto and quadratic + if first == last then + first_pt[3] = "m" -- "moveto" + nofsegments = nofsegments + 1 + segments[nofsegments] = first_pt + else -- maybe also treat n == 2 special + local first_on = first_pt[3] + local last_pt = points[last] + local last_on = last_pt[3] + local start = 1 + local control_pt = false + if first_on then + start = 2 + else + if last_on then + first_pt = last_pt + else + first_pt = { (first_pt[1]+last_pt[1])/2, (first_pt[2]+last_pt[2])/2, false } + end + control_pt = first_pt + end + local x = first_pt[1] + local y = first_pt[2] + if not done then + xmin = x + ymin = y + xmax = x + ymax = y + done = true + end + nofsegments = nofsegments + 1 + segments[nofsegments] = { x, y, "m" } -- "moveto" + if not quadratic then + px = x + py = y + end + local previous_pt = first_pt + for i=first,last do + local current_pt = points[i] + local current_on = current_pt[3] + local previous_on = previous_pt[3] + if previous_on then + if current_on then + -- both normal points + local x, y = current_pt[1], current_pt[2] + nofsegments = nofsegments + 1 + segments[nofsegments] = { x, y, "l" } -- "lineto" + if not quadratic then + px, py = x, y + end + else + control_pt = current_pt + end + elseif current_on then + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = current_pt[2] + nofsegments = nofsegments + 1 + if quadratic then + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + else + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + end + control_pt = false + else + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = control_pt[2] + nofsegments = nofsegments + 1 + if quadratic then + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + else + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + end + control_pt = current_pt + end + previous_pt = current_pt + end + if first_pt == last_pt then + -- we're already done, probably a simple curve + else + nofsegments = nofsegments + 1 + local x2 = first_pt[1] + local y2 = first_pt[2] + if not control_pt then + segments[nofsegments] = { x2, y2, "l" } -- "lineto" + elseif quadratic then + local x1 = control_pt[1] + local y1 = control_pt[2] + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + else + local x1 = control_pt[1] + local y1 = control_pt[2] + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + -- px, py = x2, y2 + end + end + end + end + first = last + 1 + end + end + end + end + end +end + +local function contours2outlines_shaped(glyphs,shapes,keepcurve) +-- for index=1,#glyphs do + for index=0,#glyphs-1 do + local shape = shapes[index] + if shape then + local glyph = glyphs[index] + local contours = shape.contours + local points = shape.points + if contours then + local nofcontours = #contours + local segments = keepcurve and { } or nil + local nofsegments = 0 + if keepcurve then + glyph.segments = segments + end + if nofcontours > 0 then + local xmin, ymin, xmax, ymax, done = 0, 0, 0, 0, false + local px, py = 0, 0 -- we could use these in calculations which saves a copy + local first = 1 + for i=1,nofcontours do + local last = contours[i] + if last >= first then + local first_pt = points[first] + local first_on = first_pt[3] + -- todo no new tables but reuse lineto and quadratic + if first == last then + -- this can influence the boundingbox + if keepcurve then + first_pt[3] = "m" -- "moveto" + nofsegments = nofsegments + 1 + segments[nofsegments] = first_pt + end + else -- maybe also treat n == 2 special + local first_on = first_pt[3] + local last_pt = points[last] + local last_on = last_pt[3] + local start = 1 + local control_pt = false + if first_on then + start = 2 + else + if last_on then + first_pt = last_pt + else + first_pt = { (first_pt[1]+last_pt[1])/2, (first_pt[2]+last_pt[2])/2, false } + end + control_pt = first_pt + end + local x = first_pt[1] + local y = first_pt[2] + if not done then + xmin, ymin, xmax, ymax = x, y, x, y + done = true + else + if x < xmin then xmin = x elseif x > xmax then xmax = x end + if y < ymin then ymin = y elseif y > ymax then ymax = y end + end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x, y, "m" } -- "moveto" + end + if not quadratic then + px = x + py = y + end + local previous_pt = first_pt + for i=first,last do + local current_pt = points[i] + local current_on = current_pt[3] + local previous_on = previous_pt[3] + if previous_on then + if current_on then + -- both normal points + local x = current_pt[1] + local y = current_pt[2] + if x < xmin then xmin = x elseif x > xmax then xmax = x end + if y < ymin then ymin = y elseif y > ymax then ymax = y end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x, y, "l" } -- "lineto" + end + if not quadratic then + px = x + py = y + end + else + control_pt = current_pt + end + elseif current_on then + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = current_pt[2] + if quadratic then + if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end + if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + end + else + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end + if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end + if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end + if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end + if px < xmin then xmin = px elseif px > xmax then xmax = px end + if py < ymin then ymin = py elseif py > ymax then ymax = py end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + end + end + control_pt = false + else + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = control_pt[2] + if quadratic then + if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end + if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + end + else + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end + if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end + if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end + if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end + if px < xmin then xmin = px elseif px > xmax then xmax = px end + if py < ymin then ymin = py elseif py > ymax then ymax = py end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + end + end + control_pt = current_pt + end + previous_pt = current_pt + end + if first_pt == last_pt then + -- we're already done, probably a simple curve + elseif not control_pt then + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { first_pt[1], first_pt[2], "l" } -- "lineto" + end + else + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = first_pt[1] + local y2 = first_pt[2] + if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end + if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end + if quadratic then + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" + end + else + x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) + if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end + if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end + if px < xmin then xmin = px elseif px > xmax then xmax = px end + if py < ymin then ymin = py elseif py > ymax then ymax = py end + if keepcurve then + nofsegments = nofsegments + 1 + segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" + end + -- px, py = x2, y2 + end + end + end + end + first = last + 1 + end + -- See readers.hvar where we set the delta lsb as well as the adapted + -- width. At this point we do know the boundingbox's llx. The xmax is + -- not that relevant. It needs more testing! + -- + xmin = glyph.boundingbox[1] + -- + local dlsb = glyph.dlsb + if dlsb then + xmin = xmin + dlsb + glyph.dlsb = nil -- save space + end + -- + glyph.boundingbox = { round(xmin), round(ymin), round(xmax), round(ymax) } + end + end + end + end +end + +-- optimize for zero + +local c_zero = char(0) +local s_zero = char(0,0) + +-- local shorthash = setmetatableindex(function(t,k) +-- -- t[k] = char(band(rshift(k,8),0xFF),band(k,0xFF)) return t[k] +-- t[k] = char((k >> 8) & 0xFF,k & 0xFF) return t[k] +-- end) + +local function toushort(n) + -- return char(band(rshift(n,8),0xFF),band(n,0xFF)) + return char((n >> 8) & 0xFF,n & 0xFF) + -- return shorthash[n] +end + +local function toshort(n) + if n < 0 then + n = n + 0x10000 + end + -- return char(band(rshift(n,8),0xFF),band(n,0xFF)) + return char((n >> 8) & 0xFF,n & 0xFF) + -- return shorthash[n] +end + +-- todo: we can reuse result, xpoints and ypoints + +local chars = setmetatableindex(function(t,k) + for i=0,255 do local v = char(i) t[i] = v end return t[k] +end) + +local function repackpoints(glyphs,shapes) + local noboundingbox = { 0, 0, 0, 0 } + local result = { } -- reused + local xpoints = { } -- reused + local ypoints = { } -- reused + for index=0,#glyphs do + local shape = shapes[index] + if shape then + local r = 0 + local glyph = glyphs[index] + local contours = shape.contours + local nofcontours = contours and #contours or 0 + local boundingbox = glyph.boundingbox or noboundingbox + r = r + 1 result[r] = toshort(nofcontours) + r = r + 1 result[r] = toshort(boundingbox[1]) -- xmin + r = r + 1 result[r] = toshort(boundingbox[2]) -- ymin + r = r + 1 result[r] = toshort(boundingbox[3]) -- xmax + r = r + 1 result[r] = toshort(boundingbox[4]) -- ymax + if nofcontours > 0 then + for i=1,nofcontours do + r = r + 1 result[r] = toshort(contours[i]-1) + end + r = r + 1 result[r] = s_zero -- no instructions + local points = shape.points + local currentx = 0 + local currenty = 0 + -- local xpoints = { } + -- local ypoints = { } + local x = 0 + local y = 0 + local lastflag = nil + local nofflags = 0 + for i=1,#points do + local pt = points[i] + local px = pt[1] + local py = pt[2] + local fl = pt[3] and 0x01 or 0x00 + if px == currentx then + fl = fl + 0x10 + else + local dx = round(px - currentx) + x = x + 1 + if dx < -255 or dx > 255 then + xpoints[x] = toshort(dx) + elseif dx < 0 then + fl = fl + 0x02 + -- xpoints[x] = char(-dx) + xpoints[x] = chars[-dx] + elseif dx > 0 then + fl = fl + 0x12 + -- xpoints[x] = char(dx) + xpoints[x] = chars[dx] + else + fl = fl + 0x02 + xpoints[x] = c_zero + end + end + if py == currenty then + fl = fl + 0x20 + else + local dy = round(py - currenty) + y = y + 1 + if dy < -255 or dy > 255 then + ypoints[y] = toshort(dy) + elseif dy < 0 then + fl = fl + 0x04 + -- ypoints[y] = char(-dy) + ypoints[y] = chars[-dy] + elseif dy > 0 then + fl = fl + 0x24 + -- ypoints[y] = char(dy) + ypoints[y] = chars[dy] + else + fl = fl + 0x04 + ypoints[y] = c_zero + end + end + currentx = px + currenty = py + if lastflag == fl then + if nofflags == 255 then + -- This happens in koeieletters! + lastflag = lastflag + 0x08 + r = r + 1 result[r] = char(lastflag,nofflags-1) + nofflags = 1 + lastflag = fl + else + nofflags = nofflags + 1 + end + else -- if > 255 + if nofflags == 1 then + -- r = r + 1 result[r] = char(lastflag) + r = r + 1 result[r] = chars[lastflag] + elseif nofflags == 2 then + r = r + 1 result[r] = char(lastflag,lastflag) + elseif nofflags > 2 then + lastflag = lastflag + 0x08 + r = r + 1 result[r] = char(lastflag,nofflags-1) + end + nofflags = 1 + lastflag = fl + end + end + if nofflags == 1 then + -- r = r + 1 result[r] = char(lastflag) + r = r + 1 result[r] = chars[lastflag] + elseif nofflags == 2 then + r = r + 1 result[r] = char(lastflag,lastflag) + elseif nofflags > 2 then + lastflag = lastflag + 0x08 + r = r + 1 result[r] = char(lastflag,nofflags-1) + end + -- r = r + 1 result[r] = concat(xpoints) + -- r = r + 1 result[r] = concat(ypoints) + r = r + 1 result[r] = concat(xpoints,"",1,x) + r = r + 1 result[r] = concat(ypoints,"",1,y) + end + -- can be helper or delegated to user + local stream = concat(result,"",1,r) + local length = #stream + local padding = ((length+3) // 4) * 4 - length + if padding > 0 then + -- stream = stream .. rep("\0",padding) -- can be a repeater + if padding == 1 then + padding = "\0" + elseif padding == 2 then + padding = "\0\0" + else + padding = "\0\0\0" + end + padding = stream .. padding + end + glyph.stream = stream + end + end +end + +-- end of converter + +local flags = { } + +local function readglyph(f,nofcontours) -- read deltas here, saves space + local points = { } + -- local instructions = { } + local contours = { } -- readintegertable(f,nofcontours,short) + for i=1,nofcontours do + contours[i] = readshort(f) + 1 + end + local nofpoints = contours[nofcontours] + local nofinstructions = readushort(f) + skipbytes(f,nofinstructions) + -- because flags can repeat we don't know the amount ... in fact this is + -- not that efficient (small files but more mem) + local i = 1 + while i <= nofpoints do + local flag = readbyte(f) + flags[i] = flag + if (flag & 0x08) ~= 0 then + local n = readbyte(f) + if n == 1 then + i = i + 1 + flags[i] = flag + else + for j=1,n do + i = i + 1 + flags[i] = flag + end + end + end + i = i + 1 + end + -- first come the x coordinates, and next the y coordinates and they + -- can be repeated + local x = 0 + for i=1,nofpoints do + local flag = flags[i] + -- local short = (flag & 0x02) ~= 0 + -- local same = (flag & 0x10) ~= 0 + if (flag & 0x02) ~= 0 then + if (flag & 0x10) ~= 0 then + x = x + readbyte(f) + else + x = x - readbyte(f) + end + elseif (flag & 0x10) ~= 0 then + -- copy + else + x = x + readshort(f) + end + points[i] = { x, 0, (flag & 0x01) ~= 0 } + end + local y = 0 + for i=1,nofpoints do + local flag = flags[i] + -- local short = (flag & 0x04) ~= 0 + -- local same = (flag & 0x20) ~= 0 + if (flag & 0x04) ~= 0 then + if (flag & 0x20) ~= 0 then + y = y + readbyte(f) + else + y = y - readbyte(f) + end + elseif (flag & 0x20) ~= 0 then + -- copy + else + y = y + readshort(f) + end + points[i][2] = y + end + return { + type = "glyph", + points = points, + contours = contours, + nofpoints = nofpoints, + } +end + +local function readcomposite(f) + local components = { } + local nofcomponents = 0 + local instructions = false + while true do + local flags = readushort(f) + local index = readushort(f) + ----- f_words = (flags & 0x0001) ~= 0 + local f_xyarg = (flags & 0x0002) ~= 0 + ----- f_round = (flags & 0x0006) ~= 0 -- 2 + 4 + ----- f_scale = (flags & 0x0008) ~= 0 + ----- f_reserved = (flags & 0x0010) ~= 0 + ----- f_more = (flags & 0x0020) ~= 0 + ----- f_xyscale = (flags & 0x0040) ~= 0 + ----- f_matrix = (flags & 0x0080) ~= 0 + ----- f_instruct = (flags & 0x0100) ~= 0 + ----- f_usemine = (flags & 0x0200) ~= 0 + ----- f_overlap = (flags & 0x0400) ~= 0 + local f_offset = (flags & 0x0800) ~= 0 + ----- f_uoffset = (flags & 0x1000) ~= 0 + local xscale = 1 + local xrotate = 0 + local yrotate = 0 + local yscale = 1 + local xoffset = 0 + local yoffset = 0 + local base = false + local reference = false + if f_xyarg then + if (flags & 0x0001) ~= 0 then -- f_words + xoffset = readshort(f) + yoffset = readshort(f) + else + xoffset = readchar(f) -- signed byte, stupid name + yoffset = readchar(f) -- signed byte, stupid name + end + else + if (flags & 0x0001) ~= 0 then -- f_words + base = readshort(f) + reference = readshort(f) + else + base = readchar(f) -- signed byte, stupid name + reference = readchar(f) -- signed byte, stupid name + end + end + if (flags & 0x0008) ~= 0 then -- f_scale + xscale = read2dot14(f) + yscale = xscale + if f_xyarg and f_offset then + xoffset = xoffset * xscale + yoffset = yoffset * yscale + end + elseif (flags & 0x0040) ~= 0 then -- f_xyscale + xscale = read2dot14(f) + yscale = read2dot14(f) + if f_xyarg and f_offset then + xoffset = xoffset * xscale + yoffset = yoffset * yscale + end + elseif (flags & 0x0080) ~= 0 then -- f_matrix + xscale = read2dot14(f) -- xxpart + xrotate = read2dot14(f) -- yxpart + yrotate = read2dot14(f) -- xypart + yscale = read2dot14(f) -- yypart + if f_xyarg and f_offset then + xoffset = xoffset * sqrt(xscale ^2 + yrotate^2) -- was xrotate + yoffset = yoffset * sqrt(xrotate^2 + yscale ^2) -- was yrotate + end + end + nofcomponents = nofcomponents + 1 + components[nofcomponents] = { + index = index, + usemine = (flags & 0x0200) ~= 0, -- f_usemine + round = (flags & 0x0006) ~= 0, -- f_round, + base = base, + reference = reference, + matrix = { xscale, xrotate, yrotate, yscale, xoffset, yoffset }, + } + if (flags & 0x0100) ~= 0 then + instructions = true + end + if (flags & 0x0020) == 0 then -- f_more + break + end + end + return { + type = "composite", + components = components, + } +end + +-- function readers.cff(f,offset,glyphs,doshapes) -- false == no shapes (nil or true otherwise) + +-- The glyf table depends on the loca table. We have one entry to much +-- in the locations table (the last one is a dummy) because we need to +-- calculate the size of a glyph blob from the delta, although we not +-- need it in our usage (yet). We can remove the locations table when +-- we're done (todo: cleanup finalizer). + +function readers.loca(f,fontdata,specification) + if specification.glyphs then + local datatable = fontdata.tables.loca + if datatable then + -- locations are relative to the glypdata table (glyf) + local offset = fontdata.tables.glyf.offset + local format = fontdata.fontheader.indextolocformat + local profile = fontdata.maximumprofile + local nofglyphs = profile and profile.nofglyphs + local locations = { } + setposition(f,datatable.offset) + if format == 1 then + if not nofglyphs then + nofglyphs = (datatable.length // 4) - 1 + end + for i=0,nofglyphs do + locations[i] = offset + readulong(f) + end + fontdata.nofglyphs = nofglyphs + else + if not nofglyphs then + nofglyphs = (datatable.length // 2) - 1 + end + for i=0,nofglyphs do + locations[i] = offset + readushort(f) * 2 + end + end + fontdata.nofglyphs = nofglyphs + fontdata.locations = locations + end + end +end + +function readers.glyf(f,fontdata,specification) -- part goes to cff module + local tableoffset = gotodatatable(f,fontdata,"glyf",specification.glyphs) + if tableoffset then + local locations = fontdata.locations + if locations then + local glyphs = fontdata.glyphs + local nofglyphs = fontdata.nofglyphs + local filesize = fontdata.filesize + local nothing = { 0, 0, 0, 0 } + local shapes = { } + local loadshapes = specification.shapes or specification.instance or specification.streams + for index=0,nofglyphs-1 do + local location = locations[index] + local length = locations[index+1] - location + if location >= filesize then + report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1) + fontdata.nofglyphs = index - 1 + fontdata.badfont = true + break + elseif length > 0 then + setposition(f,location) + local nofcontours = readshort(f) + glyphs[index].boundingbox = { + readshort(f), -- xmin + readshort(f), -- ymin + readshort(f), -- xmax + readshort(f), -- ymax + } + if not loadshapes then + -- save space + elseif nofcontours == 0 then + shapes[index] = readnothing(f) + elseif nofcontours > 0 then + shapes[index] = readglyph(f,nofcontours) + else + shapes[index] = readcomposite(f,nofcontours) + end + else + if loadshapes then + shapes[index] = readnothing(f) + end + glyphs[index].boundingbox = nothing + end + end + if loadshapes then + if readers.gvar then + readers.gvar(f,fontdata,specification,glyphs,shapes) + end + mergecomposites(glyphs,shapes) + if specification.instance then + if specification.streams then + repackpoints(glyphs,shapes) + else + contours2outlines_shaped(glyphs,shapes,specification.shapes) + end + elseif specification.shapes then + if specification.streams then + repackpoints(glyphs,shapes) + else + contours2outlines_normal(glyphs,shapes) + end + elseif specification.streams then + repackpoints(glyphs,shapes) + end + end + end + end +end + +-- gvar is a bit crazy format and one can really wonder if the bit-jugling obscurity +-- is still needed in these days .. cff is much nicer with these blends while the ttf +-- coding variant looks quite horrible + +local function readtuplerecord(f,nofaxis) + local record = { } + for i=1,nofaxis do + record[i] = read2dot14(f) + end + return record +end + +-- (1) the first is a real point the rest deltas +-- (2) points can be present more than once (multiple deltas then) + +local function readpoints(f) + local count = readbyte(f) + if count == 0 then + -- second byte not used, deltas for all point numbers + return nil, 0 -- todo + else + if count < 128 then + -- no second byte, use count + elseif (count & 0x80) ~= 0 then + count = (count & 0x7F) * 256 + readbyte(f) + else + -- bad news + end + local points = { } + local p = 0 + local n = 1 -- indices + while p < count do + local control = readbyte(f) + local runreader = (control & 0x80) ~= 0 and readushort or readbyte + local runlength = (control & 0x7F) + for i=1,runlength+1 do + n = n + runreader(f) + p = p + 1 + points[p] = n + end + end + return points, p + end +end + +local function readdeltas(f,nofpoints) + local deltas = { } + local p = 0 + while nofpoints > 0 do + local control = readbyte(f) + if control then + local allzero = (control & 0x80) ~= 0 + local runlength = (control & 0x3F) + 1 + if allzero then + for i=1,runlength do + p = p + 1 + deltas[p] = 0 + end + else + local runreader = (control & 0x40) ~= 0 and readshort or readinteger + for i=1,runlength do + p = p + 1 + deltas[p] = runreader(f) + end + end + nofpoints = nofpoints - runlength + else + -- it happens + break + end + end + -- saves space + if p > 0 then + return deltas + else + -- forget about all zeros + end +end + +function readers.gvar(f,fontdata,specification,glyphdata,shapedata) + -- this is one of the messiest tables + local instance = specification.instance + if not instance then + return + end + local factors = specification.factors + if not factors then + return + end + local tableoffset = gotodatatable(f,fontdata,"gvar",specification.variable or specification.shapes) + if tableoffset then + local version = readulong(f) -- 1.0 + local nofaxis = readushort(f) + local noftuples = readushort(f) + local tupleoffset = tableoffset + readulong(f) + local nofglyphs = readushort(f) + local flags = readushort(f) + local dataoffset = tableoffset + readulong(f) + local data = { } + local tuples = { } + local glyphdata = fontdata.glyphs + local dowidth = not fontdata.variabledata.hvarwidths + -- there is one more offset (so that one can calculate the size i suppose) + -- so we could test for overflows but we simply assume sane font files + if (flags & 0x0001) ~= 0 then + for i=1,nofglyphs+1 do + data[i] = dataoffset + readulong(f) + end + else + for i=1,nofglyphs+1 do + data[i] = dataoffset + 2*readushort(f) + end + end + -- + if noftuples > 0 then + setposition(f,tupleoffset) + for i=1,noftuples do + tuples[i] = readtuplerecord(f,nofaxis) + end + end + local nextoffset = false + local startoffset = data[1] + for i=1,nofglyphs do -- hm one more cf spec + nextoffset = data[i+1] + local glyph = glyphdata[i-1] + local name = trace_deltas and glyph.name + if startoffset == nextoffset then + if name then + report("no deltas for glyph %a",name) + end + else + local shape = shapedata[i-1] -- todo 0 + if not shape then + if name then + report("no shape for glyph %a",name) + end + else + lastoffset = startoffset + setposition(f,startoffset) + local flags = readushort(f) + local count = (flags & 0x0FFF) + local offset = startoffset + readushort(f) -- to serialized + local deltas = { } + local allpoints = (shape.nofpoints or 0) -- + 1 + local shared = false + local nofshared = 0 + if (flags & 0x8000) ~= 0 then -- has shared points + -- go to the packed stream (get them once) + local current = getposition(f) + setposition(f,offset) + shared, nofshared = readpoints(f) + offset = getposition(f) + setposition(f,current) + -- and back to the table + end + for j=1,count do + local size = readushort(f) -- check + local flags = readushort(f) + local index = (flags & 0x0FFF) + local haspeak = (flags & 0x8000) ~= 0 + local intermediate = (flags & 0x4000) ~= 0 + local private = (flags & 0x2000) ~= 0 + local peak = nil + local start = nil + local stop = nil + local xvalues = nil + local yvalues = nil + local points = shared -- we default to shared + local nofpoints = nofshared -- we default to shared + -- local advance = 4 + if haspeak then + peak = readtuplerecord(f,nofaxis) + -- advance = advance + 2*nofaxis + else + if index+1 > #tuples then + report("error, bad tuple index",index) + end + peak = tuples[index+1] -- hm, needs checking, only peak? + end + if intermediate then + start = readtuplerecord(f,nofaxis) + stop = readtuplerecord(f,nofaxis) + -- advance = advance + 4*nofaxis + end + -- get the deltas + if size > 0 then + local current = getposition(f) + -- goto the packed stream + setposition(f,offset) + if private then + points, nofpoints = readpoints(f) + end -- else + if nofpoints == 0 then + nofpoints = allpoints + 4 + end + if nofpoints > 0 then + -- a nice test is to do only one + xvalues = readdeltas(f,nofpoints) + yvalues = readdeltas(f,nofpoints) + end + -- resync offset + offset = offset + size + -- back to the table + setposition(f,current) + end + if not xvalues and not yvalues then + points = nil + end + local s = 1 + for i=1,nofaxis do + local f = factors[i] + local peak = peak and peak [i] or 0 + -- local start = start and start[i] or 0 + -- local stop = stop and stop [i] or 0 + local start = start and start[i] or (peak < 0 and peak or 0) + local stop = stop and stop [i] or (peak > 0 and peak or 0) -- or 1 ? +-- local stop = stop and stop [i] or (peak > 0 and peak or 1) -- or 1 ? + -- do we really need these tests ... can't we assume sane values + if start > peak or peak > stop then + -- * 1 + elseif start < 0 and stop > 0 and peak ~= 0 then + -- * 1 + elseif peak == 0 then + -- * 1 + elseif f < start or f > stop then + -- * 0 + s = 0 + break + elseif f < peak then + s = s * (f - start) / (peak - start) + elseif f > peak then + s = s * (stop - f) / (stop - peak) + else + -- * 1 + end + end + if s == 0 then + if name then + report("no deltas applied for glyph %a",name) + end + else + deltas[#deltas+1] = { + factor = s, + points = points, + xvalues = xvalues, + yvalues = yvalues, + } + end + end + if shape.type == "glyph" then + applyaxis(glyph,shape,deltas,dowidth) + else + -- todo: args_are_xy_values mess .. i have to be really bored + -- and motivated to deal with it + shape.deltas = deltas + end + end + end + startoffset = nextoffset + end + end +end diff --git a/tex/context/base/mkxl/libs-ini.lmt b/tex/context/base/mkxl/libs-ini.lmt new file mode 100644 index 000000000..4ce0e8e50 --- /dev/null +++ b/tex/context/base/mkxl/libs-ini.lmt @@ -0,0 +1,206 @@ +if not modules then modules = { } end modules ['libs-ini'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is a loader for optional libraries in luametatex with context lmtx. It's +-- kind of experimental. We also use a different locator than in mkiv because we +-- don't support loading lua libraries and swiglibs any more. Of course one can try +-- the regular lua loaders but we just assume that a user then knows what (s)he is +-- doing. At some point this variant will divert more from the original loader +-- file 'libs-ini.lua'. + +local type, unpack = type, unpack +local find = string.find + +-- here we implement the resolver + +local nameonly = file.nameonly +local joinfile = file.join +local addsuffix = file.addsuffix +local qualifiedpath = file.is_qualified_path + +local isfile = lfs.isfile + +local findfile = resolvers.findfile +local expandpaths = resolvers.expandedpathlistfromvariable + +local report = logs.reporter("resolvers","libraries") +local trace = false +local silent = false + +trackers.register("resolvers.lib", function(v) trace = v end) +trackers.register("resolvers.lib.silent", function(v) silent = v end) + +local function findlib(required) -- todo: cache + local suffix = os.libsuffix or "so" + if not qualifiedpath(required) then + local list = directives.value("system.librarynames" ) + local only = nameonly(required) + if type(list) == "table" then + list = list[only] + if type(list) ~= "table" then + list = { only } + end + else + list = { only } + end + if trace then + report("using lookup list for library %a: % | t",only,list) + end + for i=1,#list do + local name = list[i] + local found = findfile(name,"lib") + if not found or found == "" then + found = findfile(addsuffix(name,suffix),"lib") + end + if found and found ~= "" then + if trace then + report("library %a resolved via %a path to %a",name,"tds lib",found) + end + return found + end + end + if expandpaths then + local list = expandpaths("PATH") + local base = addsuffix(only,suffix) + for i=1,#list do + local full = joinfile(list[i],base) + local found = isfile(full) and full + if found and found ~= "" then + if trace then + report("library %a resolved via %a path to %a",full,"system",found) + end + return found + end + end + end + elseif isfile(addsuffix(required,suffix)) then + if trace then + report("library with qualified name %a %sfound",required,"") + end + return required + else + if trace then + report("library with qualified name %a %sfound",required,"not ") + end + end + return false +end + +local foundlibraries = table.setmetatableindex(function(t,k) + local v = findlib(k) + t[k] = v + return v +end) + +function resolvers.findlib(required) + return foundlibraries[required] +end + +-- here we implement the loader + +local libraries = { } +resolvers.libraries = libraries + +local report = logs.reporter("optional") + +if optional then optional.loaded = { } end + +function libraries.validoptional(name) + local thelib = optional and optional[name] + if not thelib then + -- forget about it, no message here + elseif thelib.initialize then + return thelib + else + report("invalid optional library %a",libname) + end +end + +function libraries.optionalloaded(name,libnames) + local thelib = optional and optional[name] + if not thelib then + report("no optional %a library found",name) + else + local thelib_initialize = thelib.initialize + if not thelib_initialize then + report("invalid optional library %a",name) + else + if type(libnames) == "string" then + libnames = { libnames } + end + if type(libnames) == "table" then + for i=1,#libnames do + local libname = libnames[i] + local filename = foundlibraries[libname] + if filename and filename ~= "" then + libnames[i] = filename + else + report("unable to locate library %a",libname) + return + end + end + local initialized = thelib_initialize(unpack(libnames)) + if not initialized then + report("unable to initialize library '% + t'",libnames) + elseif not silent then + report("using library '% + t'",libnames) + end + return initialized + end + end + end +end + +-- local patterns = { +-- "libs-imp-%s.mkxl", +-- "libs-imp-%s.mklx", +-- } +-- +-- local function action(name,foundname) +-- -- could be one command +-- context.startreadingfile() +-- context.input(foundname) +-- context.stopreadingfile() +-- end +-- +-- interfaces.implement { +-- name = "uselibrary", +-- arguments = "string" +-- actions = function(name) +-- resolvers.uselibrary { +-- category = "color definition", +-- name = name, +-- patterns = patterns, +-- action = action, +-- onlyonce = true, +-- } +-- end +-- } + +-- We overload the standard 'require' function. Because we're in LuaMetaTeX we are +-- more likely to find 'lmt' files when we deal with the TeX and MetaPost part but +-- user files likely have the 'lua' suffix. + +do + + local dofile = dofile + local savedrequire = require + + function require(name,version) + if find(name,"%.lua$") or find(name,"%.lmt$") then + local m = dofile(findfile(name)) + if m then + package.loaded[name] = m + return m + end + else + return savedrequire(name) + end + end + +end diff --git a/tex/context/base/mkxl/libs-ini.mkxl b/tex/context/base/mkxl/libs-ini.mkxl index ef24536bf..bc1fe92e0 100644 --- a/tex/context/base/mkxl/libs-ini.mkxl +++ b/tex/context/base/mkxl/libs-ini.mkxl @@ -11,12 +11,12 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\registerctxluafile{libs-ini}{} % shared with mkiv +\registerctxluafile{libs-ini}{autosuffix} % These are used by the graphic converters: -\registerctxluafile{libs-imp-curl}{autosuffix} -\registerctxluafile{libs-imp-ghostscript}{autosuffix} +\registerctxluafile{libs-imp-curl} {autosuffix} +\registerctxluafile{libs-imp-ghostscript} {autosuffix} \registerctxluafile{libs-imp-graphicsmagick}{autosuffix} % These are loaded on demand: diff --git a/tex/context/base/mkxl/luat-lib.mkxl b/tex/context/base/mkxl/luat-lib.mkxl index 7ad29e29e..cb161cafa 100644 --- a/tex/context/base/mkxl/luat-lib.mkxl +++ b/tex/context/base/mkxl/luat-lib.mkxl @@ -61,7 +61,7 @@ \registerctxluafile{data-pre}{} % after data-res \registerctxluafile{data-bin}{} % before data-tex \registerctxluafile{data-tex}{} % after data-pre -\registerctxluafile{data-vir}{} +\registerctxluafile{data-vir}{autosuffix} \registerctxluafile{data-zip}{} \registerctxluafile{data-dec}{} \registerctxluafile{data-tar}{} diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt index faa0d2ae5..19a43ce87 100644 --- a/tex/context/base/mkxl/math-act.lmt +++ b/tex/context/base/mkxl/math-act.lmt @@ -321,7 +321,7 @@ mathtweaks.subsets = { p = { 0x1D45D }, dotless = { 0x00049, 0x0004A, 0x00131, 0x00237, 0x1D6A4, 0x1D6A5 }, integrals = { 0x0222B, 0x0222C, 0x0222D, 0x0222E, 0x0222F, 0x02230, 0x02231, 0x02232, 0x02233, 0x02A0B, 0x02A0C, 0x02A0D, 0x02A0E, 0x02A0F, 0x02A10, 0x02A11, 0x02A12, 0x02A13, 0x02A14, 0x02A15, 0x02A16, 0x02A17, 0x02A18, 0x02A19, 0x02A1A, 0x02A1B, 0x02A1C, 0x02320, 0x02321 }, - horizontalfences = { 0x023B4, 0x023B5, 0x023DC, 0x023DD, 0x023DE, 0x023DF, 0x023E0, 0x023E1 }, -- not really used + horizontalfences = { 0x0203E, 0x023B4, 0x023B5, 0x023DC, 0x023DD, 0x023DE, 0x023DF, 0x023E0, 0x023E1 }, -- not really used } local function getalso(target,original) @@ -1844,7 +1844,8 @@ do parts = { { advance = width, ["end"] = step, glyph = 0x203E, start = 0 }, { advance = width, ["end"] = 0, glyph = 0x203E, start = step, extender = 1 }, - } + }, + partsorientation = "horizontal", } -- characters[0x0332] = characters[0x203E] @@ -1872,7 +1873,8 @@ do { advance = thickness, glyph = tpiece, ["end"] = 0, start = half }, { advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 }, { advance = thickness, glyph = tpiece, ["end"] = half, start = 0 }, - } + }, + partsorientation = "horizontal", } end if not characters[0x23B5] then @@ -1893,7 +1895,8 @@ do { advance = thickness, glyph = bpiece, ["end"] = 0, start = half }, { advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 }, { advance = thickness, glyph = bpiece, ["end"] = half, start = 0 }, - } + }, + partsorientation = "horizontal", } end -- @@ -1932,7 +1935,8 @@ do end if chardata and (force or overloads[unicode] == false or not chardata.parts) then if not list then - chardata.parts = nil -- when we test + -- chardata.parts = nil -- when we test + chardata.parts = { { glyph = unicode } } else local overload = overloads[unicode] local parts = { } @@ -2030,6 +2034,7 @@ do [0x21CB] = centered, -- leftrightharpoons [0x21CC] = centered, -- rightleftharpoons [0x21C4] = centered, -- rightoverleftarrow + [0x21C6] = centered, -- leftoverrightarrow [0x21A6] = centered, -- mapsto -- [0x203E] = { slackslack, { left = slack, right = slack, extensible = true } }, -- bar diff --git a/tex/context/base/mkxl/math-rad.mklx b/tex/context/base/mkxl/math-rad.mklx index 645d32740..cb3cdb0a8 100644 --- a/tex/context/base/mkxl/math-rad.mklx +++ b/tex/context/base/mkxl/math-rad.mklx @@ -26,7 +26,7 @@ % \def\rootradical{\Uroot 0 "221A } % can be done in char-def % \def\surdradical{\Uradical 0 "221A } % can be done in char-def -\protected\def\sqrt{\doifelsenextoptionalcs\rootwithdegree\rootwithoutdegree} % will be redefined +% \protected\def\sqrt{\doifelsenextoptionalcs\rootwithdegree\rootwithoutdegree} % will be redefined % \permanent\protected\def\styledrootradical#1#2% so that \text works ok ... \rootradical behaves somewhat weird % {\normalexpanded{\math_radical_common @@ -39,8 +39,8 @@ % \permanent\protected\def\styledrootradical#1#2% so that \text works ok ... \rootradical behaves somewhat weird % {\Uroot style \normalmathstyle "0 "221A {#1}{#2}} -\permanent\protected\def\rootwithdegree[#1]{\math_radical_common{#1}} -\permanent\protected\def\rootwithoutdegree {\math_radical_common {}} +% \permanent\protected\def\rootwithdegree[#1]{\math_radical_common{#1}} +% \permanent\protected\def\rootwithoutdegree {\math_radical_common {}} %D Even older stuff: @@ -79,6 +79,20 @@ %D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par %D $ \sqrt[3]{5} {\RR\sqrt[3]{5}} \sqrt[3]{5} $\par %D \stoptyping +%D +%D And: +%D +%D \starttyping +%D \definemathradical[lsqrt][strut=yes] +%D \definemathradical[msqrt][strut=math] +%D \definemathradical[xsqrt][height=3ex,depth=2ex] +%D +%D $\sqrt[strut=no][3]{y}$ +%D $\sqrt[strut=no,n=5]{y}$ +%D $\sqrt[strut=no,n=5][6]{y}$ +%D $\sqrt[strut=math]{y}$ +%D $\sqrt[3]{y}$ +%D \stoptyping \installcorenamespace{mathradical} \installcorenamespace{mathradicalalternative} @@ -117,9 +131,14 @@ \tolerant\protected\def\math_radical_handle#tag#*[#settings]#*[#degree]#:#body% {\begingroup \edef\currentmathradical{#tag}% - \ifparameter#degree\or - \edef\currentmathradicaldegree{#degree}% + \ifhastok={#settings}% + \lettonothing\currentmathradicaldegree \setupcurrentmathradical[#settings]% + \ifparameter#degree\or + \edef\currentmathradicaldegree{#degree}% + \else + \edef\currentmathradicaldegree{\mathradicalparameter\c!n}% + \fi \else \edef\currentmathradicaldegree{#settings}% \fi @@ -253,7 +272,12 @@ \fi \endgroup} -\definemathradical[sqrt][mp=minifun::math:radical:default] +\pushoverloadmode + +\definemathradical[root][mp=minifun::math:radical:default] +\definemathradical[sqrt][root] + +\popoverloadmode % \setupmathradical[sqrt][alternative=normal,color=darkblue] % \setupmathradical[sqrt][alternative=mp,color=darkgreen] diff --git a/tex/context/base/mkxl/math-stc.mklx b/tex/context/base/mkxl/math-stc.mklx index 952fba6c6..5922fb116 100644 --- a/tex/context/base/mkxl/math-stc.mklx +++ b/tex/context/base/mkxl/math-stc.mklx @@ -98,19 +98,30 @@ \fi \hss}} -\def\math_stackers_regular - {\mathstylehbox{\usemathstackerscolorparameter\c!color - \hskip\d_math_stackers_offset_l - \Umathaccent\zerocount\zerocount\scratchunicode - {\hskip\dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}% - \hskip\d_math_stackers_offset_r - }} +% \def\math_stackers_regular +% {\mathstylehbox{\usemathstackerscolorparameter\c!color +% \hskip\d_math_stackers_offset_l +% \Umathaccent\zerocount\zerocount\scratchunicode +% {\hskip\dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}% +% \hskip\d_math_stackers_offset_r +% }} + +% \def\math_stackers_stretch % we don't have that one yet +% {\mathstylehbox{\usemathstackerscolorparameter\c!color +% \hskip\d_math_stackers_offset_l +% \Umathaccent\zerocount\zerocount\scratchunicode +% {\hskip\dimexpr\hsize-\d_math_stackers_offset_l-\d_math_stackers_offset_r}% +% \hskip\d_math_stackers_offset_r +% }} -\def\math_stackers_stretch % we don't have that one yet +\def\math_stackers_regular {\mathstylehbox{\usemathstackerscolorparameter\c!color \hskip\d_math_stackers_offset_l - \Umathaccent\zerocount\zerocount\scratchunicode - {\hskip\dimexpr\hsize-\d_math_stackers_offset_l-\d_math_stackers_offset_r}% + \Uhextensible + middle + width \dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r\relax + \zerocount\scratchunicode + \relax \hskip\d_math_stackers_offset_r }} @@ -410,6 +421,9 @@ \setbox\scratchboxthree\csname\??mathstackersalternative\p_alternative\endcsname \dostoptagged \fi + \ifdim\wd\scratchboxthree>\scratchwidth + \scratchwidth\wd\scratchboxthree + \fi % \ifdim\wd\scratchboxone<\scratchwidth \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% unhboxing makes leaders work @@ -1192,8 +1206,6 @@ \definemathextensible [\v!chemistry] [crightoverleftarrow] ["21C4] \definemathextensible [\v!chemistry] [cleftoverrightarrow] ["21C6] -% for the moment: - \def\math_stackers_hacked_fill#1#2#3% {\mathematics {\begingroup @@ -1203,35 +1215,37 @@ \thinmuskip \zeromuskip \tinymuskip \zeromuskip \pettymuskip \zeromuskip - #1% - \mkern-7\onemuskip - \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill - \mkern-7\onemuskip - #3% + \ifrelax#1% + \cleaders\mathstylehbox{#2}\hfill + \else + #1% + \mkern-7\onemuskip + \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill + \mkern-7\onemuskip + #3% + \fi \endgroup}} -% These will become characters defined in math-act. - -\immutable\protected\def\rightarrowfill {\math_stackers_hacked_fill \relbar \relbar \rightarrow} -\immutable\protected\def\leftarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \relbar } -\immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \ctxdoublearrowfillleftend\ctxdoublearrowfillmiddlepart\ctxdoublearrowfillrightend} -\immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \ctxdoublearrowfillrightend\ctxdoublearrowfillmiddlepart\ctxdoublearrowfillleftend} -\immutable\protected\def\equalfill {\math_stackers_hacked_fill \Relbar \Relbar \Relbar} -\immutable\protected\def\Rightarrowfill {\math_stackers_hacked_fill \Relbar \Relbar \Rightarrow} -\immutable\protected\def\Leftarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Relbar} -\immutable\protected\def\Leftrightarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Rightarrow} -\immutable\protected\def\leftrightarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \rightarrow} -\immutable\protected\def\mapstofill {\math_stackers_hacked_fill{\mapstochar\relbar} \relbar \rightarrow} -\immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar \relbar \twoheadrightarrow} -\immutable\protected\def\twoheadleftarrowfill {\math_stackers_hacked_fill \twoheadleftarrow \relbar \relbar} -\immutable\protected\def\rightharpoondownfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoondown} -\immutable\protected\def\rightharpoonupfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoonup} -\immutable\protected\def\leftharpoondownfill {\math_stackers_hacked_fill \leftharpoondown \relbar \relbar} -\immutable\protected\def\leftharpoonupfill {\math_stackers_hacked_fill \leftharpoonup \relbar \relbar} -\immutable\protected\def\hookleftfill {\math_stackers_hacked_fill \leftarrow \relbar {\relbar\joinrel\rhook}} -\immutable\protected\def\hookrightfill {\math_stackers_hacked_fill{\lhook\joinrel\relbar} \relbar \rightarrow} -\immutable\protected\def\relfill {\math_stackers_hacked_fill \relbar \relbar \relbar} -\immutable\protected\def\triplerelfill {\math_stackers_hacked_fill \equiv \equiv \equiv} +\immutable\protected\def\rightarrowfill {\math_stackers_hacked_fill \relbar \relbar \rightarrow} +\immutable\protected\def\leftarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \relbar} +\immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \relax \crightoverleftarrow \relax} +\immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \relax \cleftoverrightarrow \relax} +\immutable\protected\def\equalfill {\math_stackers_hacked_fill \Relbar \Relbar \Relbar} +\immutable\protected\def\Rightarrowfill {\math_stackers_hacked_fill \Relbar \Relbar \Rightarrow} +\immutable\protected\def\Leftarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Relbar} +\immutable\protected\def\Leftrightarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Rightarrow} +\immutable\protected\def\leftrightarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \rightarrow} +\immutable\protected\def\mapstofill {\math_stackers_hacked_fill{\mapstochar\relbar} \relbar \rightarrow} +\immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar \relbar \twoheadrightarrow} +\immutable\protected\def\twoheadleftarrowfill {\math_stackers_hacked_fill \twoheadleftarrow \relbar \relbar} +\immutable\protected\def\rightharpoondownfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoondown} +\immutable\protected\def\rightharpoonupfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoonup} +\immutable\protected\def\leftharpoondownfill {\math_stackers_hacked_fill \leftharpoondown \relbar \relbar} +\immutable\protected\def\leftharpoonupfill {\math_stackers_hacked_fill \leftharpoonup \relbar \relbar} +\immutable\protected\def\hookleftfill {\math_stackers_hacked_fill \leftarrow \relbar {\relbar\joinrel\rhook}} +\immutable\protected\def\hookrightfill {\math_stackers_hacked_fill{\lhook\joinrel\relbar}\relbar \rightarrow} +\immutable\protected\def\relfill {\math_stackers_hacked_fill \relbar \relbar \relbar} +\immutable\protected\def\triplerelfill {\math_stackers_hacked_fill \equiv \equiv \equiv} %D For the moment (needs checking): diff --git a/tex/context/base/mkxl/math-ttv.lmt b/tex/context/base/mkxl/math-ttv.lmt index 06e934dcd..e33a23478 100644 --- a/tex/context/base/mkxl/math-ttv.lmt +++ b/tex/context/base/mkxl/math-ttv.lmt @@ -152,6 +152,11 @@ mathencodings["tex-mr-missing"] = { [0x02236] = 0x3A, -- colon } +mathencodings["tex-ex-braces"] = { + [0x0007B] = 0x7B, -- {, braceleftbig + [0x0007D] = 0x7D, -- }, bracerightbig +} + mathencodings["tex-mi"] = { [0x1D6E4] = 0x00, -- Gamma [0x1D6E5] = 0x01, -- Delta @@ -463,275 +468,275 @@ mathencodings["tex-sy"] = { [0xFE325] = 0x30, -- prime 0x02032 } --- The names in masm10.enc can be trusted best and are shown in the first --- column, while in the second column we show the tex/ams names. As usual --- it costs hours to figure out such a table. - -mathencodings["tex-ma"] = { - [0x022A1] = 0x00, -- squaredot \boxdot - [0x0229E] = 0x01, -- squareplus \boxplus - [0x022A0] = 0x02, -- squaremultiply \boxtimes - [0x025A1] = 0x03, -- square \square \Box - [0x025A0] = 0x04, -- squaresolid \blacksquare - [0x025AA] = 0x05, -- squaresmallsolid \centerdot - [0x022C4] = 0x06, -- diamond \Diamond \lozenge - [0x02666] = 0x07, -- diamondsolid \blacklozenge - [0x021BB] = 0x08, -- clockwise \circlearrowright - [0x021BA] = 0x09, -- anticlockwise \circlearrowleft - [0x021CC] = 0x0A, -- harpoonleftright \rightleftharpoons - [0x021CB] = 0x0B, -- harpoonrightleft \leftrightharpoons - [0x0229F] = 0x0C, -- squareminus \boxminus - [0x022A9] = 0x0D, -- forces \Vdash - [0x022AA] = 0x0E, -- forcesbar \Vvdash - [0x022A8] = 0x0F, -- satisfies \vDash - [0x021A0] = 0x10, -- dblarrowheadright \twoheadrightarrow - [0x0219E] = 0x11, -- dblarrowheadleft \twoheadleftarrow - [0x021C7] = 0x12, -- dblarrowleft \leftleftarrows - [0x021C9] = 0x13, -- dblarrowright \rightrightarrows - [0x021C8] = 0x14, -- dblarrowup \upuparrows - [0x021CA] = 0x15, -- dblarrowdwn \downdownarrows - [0x021BE] = 0x16, -- harpoonupright \upharpoonright \restriction - [0x021C2] = 0x17, -- harpoondownright \downharpoonright - [0x021BF] = 0x18, -- harpoonupleft \upharpoonleft - [0x021C3] = 0x19, -- harpoondownleft \downharpoonleft - [0x021A3] = 0x1A, -- arrowtailright \rightarrowtail - [0x021A2] = 0x1B, -- arrowtailleft \leftarrowtail - [0x021C6] = 0x1C, -- arrowparrleftright \leftrightarrows --- [0x021C5] = 0x00, -- \updownarrows (missing in lm) - [0x021C4] = 0x1D, -- arrowparrrightleft \rightleftarrows - [0x021B0] = 0x1E, -- shiftleft \Lsh - [0x021B1] = 0x1F, -- shiftright \Rsh - [0x021DD] = 0x20, -- squiggleright \leadsto \rightsquigarrow - [0x021AD] = 0x21, -- squiggleleftright \leftrightsquigarrow - [0x021AB] = 0x22, -- curlyleft \looparrowleft - [0x021AC] = 0x23, -- curlyright \looparrowright - [0x02257] = 0x24, -- circleequal \circeq - [0x0227F] = 0x25, -- followsorequal \succsim - [0x02273] = 0x26, -- greaterorsimilar \gtrsim - [0x02A86] = 0x27, -- greaterorapproxeql \gtrapprox - [0x022B8] = 0x28, -- multimap \multimap - [0x02234] = 0x29, -- therefore \therefore - [0x02235] = 0x2A, -- because \because - [0x02251] = 0x2B, -- equalsdots \Doteq \doteqdot - [0x0225C] = 0x2C, -- defines \triangleq - [0x0227E] = 0x2D, -- precedesorequal \precsim - [0x02272] = 0x2E, -- lessorsimilar \lesssim - [0x02A85] = 0x2F, -- lessorapproxeql \lessapprox - [0x02A95] = 0x30, -- equalorless \eqslantless - [0x02A96] = 0x31, -- equalorgreater \eqslantgtr - [0x022DE] = 0x32, -- equalorprecedes \curlyeqprec - [0x022DF] = 0x33, -- equalorfollows \curlyeqsucc - [0x0227C] = 0x34, -- precedesorcurly \preccurlyeq - [0x02266] = 0x35, -- lessdblequal \leqq - [0x02A7D] = 0x36, -- lessorequalslant \leqslant - [0x02276] = 0x37, -- lessorgreater \lessgtr - [0x02035] = 0x38, -- primereverse \backprime - -- [0x0] = 0x39, -- axisshort \dabar - [0x02253] = 0x3A, -- equaldotrightleft \risingdotseq - [0x02252] = 0x3B, -- equaldotleftright \fallingdotseq - [0x0227D] = 0x3C, -- followsorcurly \succcurlyeq - [0x02267] = 0x3D, -- greaterdblequal \geqq - [0x02A7E] = 0x3E, -- greaterorequalslant \geqslant - [0x02277] = 0x3F, -- greaterorless \gtrless - [0x0228F] = 0x40, -- squareimage \sqsubset - [0x02290] = 0x41, -- squareoriginal \sqsupset - -- wrong: see ** - -- [0x022B3] = 0x42, -- triangleright \rhd \vartriangleright - -- [0x022B2] = 0x43, -- triangleleft \lhd \vartriangleleft - -- cf lm - [0x022B5] = 0x44, -- trianglerightequal \unrhd \trianglerighteq - [0x022B4] = 0x45, -- triangleleftequal \unlhd \trianglelefteq - -- - [0x02605] = 0x46, -- star \bigstar - [0x0226C] = 0x47, -- between \between - [0x025BC] = 0x48, -- triangledownsld \blacktriangledown - [0x025B6] = 0x49, -- trianglerightsld \blacktriangleright - [0x025C0] = 0x4A, -- triangleleftsld \blacktriangleleft - -- [0x0] = 0x4B, -- arrowaxisright - -- [0x0] = 0x4C, -- arrowaxisleft - [0x025B2] = 0x4D, -- triangle \triangleup \vartriangle - [0x025B2] = 0x4E, -- trianglesolid \blacktriangle - [0x025BD] = 0x4F, -- triangleinv \triangledown - [0x02256] = 0x50, -- ringinequal \eqcirc - [0x022DA] = 0x51, -- lessequalgreater \lesseqgtr - [0x022DB] = 0x52, -- greaterlessequal \gtreqless - [0x02A8B] = 0x53, -- lessdbleqlgreater \lesseqqgtr - [0x02A8C] = 0x54, -- greaterdbleqlless \gtreqqless - [0x000A5] = 0x55, -- Yen \yen - [0x021DB] = 0x56, -- arrowtripleright \Rrightarrow - [0x021DA] = 0x57, -- arrowtripleleft \Lleftarrow - [0x02713] = 0x58, -- check \checkmark - [0x022BB] = 0x59, -- orunderscore \veebar - [0x022BC] = 0x5A, -- nand \barwedge - [0x02306] = 0x5B, -- perpcorrespond \doublebarwedge - [0x02220] = 0x5C, -- angle \angle - [0x02221] = 0x5D, -- measuredangle \measuredangle - [0x02222] = 0x5E, -- sphericalangle \sphericalangle - -- [0x0] = 0x5F, -- proportional \varpropto - -- [0x0] = 0x60, -- smile \smallsmile - -- [0x0] = 0x61, -- frown \smallfrown - [0x022D0] = 0x62, -- subsetdbl \Subset - [0x022D1] = 0x63, -- supersetdbl \Supset - [0x022D3] = 0x64, -- uniondbl \doublecup \Cup - [0x022D2] = 0x65, -- intersectiondbl \doublecap \Cap - [0x022CF] = 0x66, -- uprise \curlywedge - [0x022CE] = 0x67, -- downfall \curlyvee - [0x022CB] = 0x68, -- multiopenleft \leftthreetimes - [0x022CC] = 0x69, -- multiopenright \rightthreetimes - [0x02AC5] = 0x6A, -- subsetdblequal \subseteqq - [0x02AC6] = 0x6B, -- supersetdblequal \supseteqq - [0x0224F] = 0x6C, -- difference \bumpeq - [0x0224E] = 0x6D, -- geomequivalent \Bumpeq - [0x022D8] = 0x6E, -- muchless \lll \llless - [0x022D9] = 0x6F, -- muchgreater \ggg \gggtr - [0x0231C] = 0x70, -- rightanglenw \ulcorner - [0x0231D] = 0x71, -- rightanglene \urcorner - [0x024C7] = 0x72, -- circleR \circledR - [0x024C8] = 0x73, -- circleS \circledS - [0x022D4] = 0x74, -- fork \pitchfork - [0x02214] = 0x75, -- dotplus \dotplus - [0x0223D] = 0x76, -- revsimilar \backsim - [0x022CD] = 0x77, -- revasymptequal \backsimeq -- AM: Check this! I mapped it to simeq. - [0x0231E] = 0x78, -- rightanglesw \llcorner - [0x0231F] = 0x79, -- rightanglese \lrcorner - [0x02720] = 0x7A, -- maltesecross \maltese - [0x02201] = 0x7B, -- complement \complement - [0x022BA] = 0x7C, -- intercal \intercal - [0x0229A] = 0x7D, -- circlering \circledcirc - [0x0229B] = 0x7E, -- circleasterisk \circledast - [0x0229D] = 0x7F, -- circleminus \circleddash -} - -mathencodings["tex-mb"] = { - -- [0x0] = 0x00, -- lessornotequal \lvertneqq - -- [0x0] = 0x01, -- greaterornotequal \gvertneqq - [0x02270] = 0x02, -- notlessequal \nleq - [0x02271] = 0x03, -- notgreaterequal \ngeq - [0x0226E] = 0x04, -- notless \nless - [0x0226F] = 0x05, -- notgreater \ngtr - [0x02280] = 0x06, -- notprecedes \nprec - [0x02281] = 0x07, -- notfollows \nsucc - [0x02268] = 0x08, -- lessornotdbleql \lneqq - [0x02269] = 0x09, -- greaterornotdbleql \gneqq - -- [0x0] = 0x0A, -- notlessorslnteql \nleqslant - -- [0x0] = 0x0B, -- notgreaterorslnteql \ngeqslant - [0x02A87] = 0x0C, -- lessnotequal \lneq - [0x02A88] = 0x0D, -- greaternotequal \gneq - -- [0x0] = 0x0E, -- notprecedesoreql \npreceq - -- [0x0] = 0x0F, -- notfollowsoreql \nsucceq - [0x022E8] = 0x10, -- precedeornoteqvlnt \precnsim - [0x022E9] = 0x11, -- followornoteqvlnt \succnsim - [0x022E6] = 0x12, -- lessornotsimilar \lnsim - [0x022E7] = 0x13, -- greaterornotsimilar \gnsim - -- [0x0] = 0x14, -- notlessdblequal \nleqq - -- [0x0] = 0x15, -- notgreaterdblequal \ngeqq - [0x02AB5] = 0x16, -- precedenotslnteql \precneqq - [0x02AB6] = 0x17, -- follownotslnteql \succneqq - [0x02AB9] = 0x18, -- precedenotdbleqv \precnapprox - [0x02ABA] = 0x19, -- follownotdbleqv \succnapprox - [0x02A89] = 0x1A, -- lessnotdblequal \lnapprox - [0x02A8A] = 0x1B, -- greaternotdblequal \gnapprox - [0x02241] = 0x1C, -- notsimilar \nsim - [0x02247] = 0x1D, -- notapproxequal \ncong - -- [0x0] = 0x1E, -- upslope \diagup - -- [0x0] = 0x1F, -- downslope \diagdown - -- [0x0] = 0x20, -- notsubsetoreql \varsubsetneq - -- [0x0] = 0x21, -- notsupersetoreql \varsupsetneq - -- [0x0] = 0x22, -- notsubsetordbleql \nsubseteqq - -- [0x0] = 0x23, -- notsupersetordbleql \nsupseteqq - [0x02ACB] = 0x24, -- subsetornotdbleql \subsetneqq - [0x02ACC] = 0x25, -- supersetornotdbleql \supsetneqq - -- [0x0] = 0x26, -- subsetornoteql \varsubsetneqq - -- [0x0] = 0x27, -- supersetornoteql \varsupsetneqq - [0x0228A] = 0x28, -- subsetnoteql \subsetneq - [0x0228B] = 0x29, -- supersetnoteql \supsetneq - [0x02288] = 0x2A, -- notsubseteql \nsubseteq - [0x02289] = 0x2B, -- notsuperseteql \nsupseteq - [0x02226] = 0x2C, -- notparallel \nparallel - [0x02224] = 0x2D, -- notbar \nmid \ndivides - -- [0x0] = 0x2E, -- notshortbar \nshortmid - -- [0x0] = 0x2F, -- notshortparallel \nshortparallel - [0x022AC] = 0x30, -- notturnstile \nvdash - [0x022AE] = 0x31, -- notforces \nVdash - [0x022AD] = 0x32, -- notsatisfies \nvDash - [0x022AF] = 0x33, -- notforcesextra \nVDash - [0x022ED] = 0x34, -- nottriangeqlright \ntrianglerighteq - [0x022EC] = 0x35, -- nottriangeqlleft \ntrianglelefteq - [0x022EA] = 0x36, -- nottriangleleft \ntriangleleft - [0x022EB] = 0x37, -- nottriangleright \ntriangleright - [0x0219A] = 0x38, -- notarrowleft \nleftarrow - [0x0219B] = 0x39, -- notarrowright \nrightarrow - [0x021CD] = 0x3A, -- notdblarrowleft \nLeftarrow - [0x021CF] = 0x3B, -- notdblarrowright \nRightarrow - [0x021CE] = 0x3C, -- notdblarrowboth \nLeftrightarrow - [0x021AE] = 0x3D, -- notarrowboth \nleftrightarrow - [0x022C7] = 0x3E, -- dividemultiply \divideontimes - [0x02300] = 0x3F, -- diametersign \varnothing - [0x02204] = 0x40, -- notexistential \nexists - [0x1D538] = 0x41, -- A (blackboard A) - [0x1D539] = 0x42, -- B - [0x02102] = 0x43, -- C - [0x1D53B] = 0x44, -- D - [0x1D53C] = 0x45, -- E - [0x1D53D] = 0x46, -- F - [0x1D53E] = 0x47, -- G - [0x0210D] = 0x48, -- H - [0x1D540] = 0x49, -- I - [0x1D541] = 0x4A, -- J - [0x1D542] = 0x4B, -- K - [0x1D543] = 0x4C, -- L - [0x1D544] = 0x4D, -- M - [0x02115] = 0x4E, -- N - [0x1D546] = 0x4F, -- O - [0x02119] = 0x50, -- P - [0x0211A] = 0x51, -- Q - [0x0211D] = 0x52, -- R - [0x1D54A] = 0x53, -- S - [0x1D54B] = 0x54, -- T - [0x1D54C] = 0x55, -- U - [0x1D54D] = 0x56, -- V - [0x1D54E] = 0x57, -- W - [0x1D54F] = 0x58, -- X - [0x1D550] = 0x59, -- Y - [0x02124] = 0x5A, -- Z (blackboard Z) - [0x02132] = 0x60, -- finv \Finv - [0x02141] = 0x61, -- fmir \Game - -- [0x0] = 0x62, tildewide - -- [0x0] = 0x63, tildewider - -- [0x0] = 0x64, Finv - -- [0x0] = 0x65, Gmir - [0x02127] = 0x66, -- Omegainv \mho - [0x000F0] = 0x67, -- eth \eth - [0x02242] = 0x68, -- equalorsimilar \eqsim - [0x02136] = 0x69, -- beth \beth - [0x02137] = 0x6A, -- gimel \gimel - [0x02138] = 0x6B, -- daleth \daleth - [0x022D6] = 0x6C, -- lessdot \lessdot - [0x022D7] = 0x6D, -- greaterdot \gtrdot - [0x022C9] = 0x6E, -- multicloseleft \ltimes - [0x022CA] = 0x6F, -- multicloseright \rtimes - -- [0x0] = 0x70, -- barshort \shortmid - -- [0x0] = 0x71, -- parallelshort \shortparallel - -- [0x02216] = 0x72, -- integerdivide \smallsetminus (2216 already part of tex-sy - -- [0x0] = 0x73, -- similar \thicksim - -- [0x0] = 0x74, -- approxequal \thickapprox - [0x0224A] = 0x75, -- approxorequal \approxeq - [0x02AB8] = 0x76, -- followsorequal \succapprox - [0x02AB7] = 0x77, -- precedesorequal \precapprox - [0x021B6] = 0x78, -- archleftdown \curvearrowleft - [0x021B7] = 0x79, -- archrightdown \curvearrowright - [0x003DC] = 0x7A, -- Digamma \digamma - [0x003F0] = 0x7B, -- kappa \varkappa - [0x1D55C] = 0x7C, -- k \Bbbk (blackboard k) - [0x0210F] = 0x7D, -- planckover2pi \hslash % 0x7D - [0x00127] = 0x7E, -- planckover2pi1 \hbar % 0x7E - [0x003F6] = 0x7F, -- epsiloninv \backepsilon -} - -mathencodings["tex-mc"] = { - -- this file has no tfm so it gets mapped in the private space - [0xFE324] = "mapsfromchar", -} +-- -- The names in masm10.enc can be trusted best and are shown in the first +-- -- column, while in the second column we show the tex/ams names. As usual +-- -- it costs hours to figure out such a table. +-- +-- mathencodings["tex-ma"] = { +-- [0x022A1] = 0x00, -- squaredot \boxdot +-- [0x0229E] = 0x01, -- squareplus \boxplus +-- [0x022A0] = 0x02, -- squaremultiply \boxtimes +-- [0x025A1] = 0x03, -- square \square \Box +-- [0x025A0] = 0x04, -- squaresolid \blacksquare +-- [0x025AA] = 0x05, -- squaresmallsolid \centerdot +-- [0x022C4] = 0x06, -- diamond \Diamond \lozenge +-- [0x02666] = 0x07, -- diamondsolid \blacklozenge +-- [0x021BB] = 0x08, -- clockwise \circlearrowright +-- [0x021BA] = 0x09, -- anticlockwise \circlearrowleft +-- [0x021CC] = 0x0A, -- harpoonleftright \rightleftharpoons +-- [0x021CB] = 0x0B, -- harpoonrightleft \leftrightharpoons +-- [0x0229F] = 0x0C, -- squareminus \boxminus +-- [0x022A9] = 0x0D, -- forces \Vdash +-- [0x022AA] = 0x0E, -- forcesbar \Vvdash +-- [0x022A8] = 0x0F, -- satisfies \vDash +-- [0x021A0] = 0x10, -- dblarrowheadright \twoheadrightarrow +-- [0x0219E] = 0x11, -- dblarrowheadleft \twoheadleftarrow +-- [0x021C7] = 0x12, -- dblarrowleft \leftleftarrows +-- [0x021C9] = 0x13, -- dblarrowright \rightrightarrows +-- [0x021C8] = 0x14, -- dblarrowup \upuparrows +-- [0x021CA] = 0x15, -- dblarrowdwn \downdownarrows +-- [0x021BE] = 0x16, -- harpoonupright \upharpoonright \restriction +-- [0x021C2] = 0x17, -- harpoondownright \downharpoonright +-- [0x021BF] = 0x18, -- harpoonupleft \upharpoonleft +-- [0x021C3] = 0x19, -- harpoondownleft \downharpoonleft +-- [0x021A3] = 0x1A, -- arrowtailright \rightarrowtail +-- [0x021A2] = 0x1B, -- arrowtailleft \leftarrowtail +-- [0x021C6] = 0x1C, -- arrowparrleftright \leftrightarrows +-- -- [0x021C5] = 0x00, -- \updownarrows (missing in lm) +-- [0x021C4] = 0x1D, -- arrowparrrightleft \rightleftarrows +-- [0x021B0] = 0x1E, -- shiftleft \Lsh +-- [0x021B1] = 0x1F, -- shiftright \Rsh +-- [0x021DD] = 0x20, -- squiggleright \leadsto \rightsquigarrow +-- [0x021AD] = 0x21, -- squiggleleftright \leftrightsquigarrow +-- [0x021AB] = 0x22, -- curlyleft \looparrowleft +-- [0x021AC] = 0x23, -- curlyright \looparrowright +-- [0x02257] = 0x24, -- circleequal \circeq +-- [0x0227F] = 0x25, -- followsorequal \succsim +-- [0x02273] = 0x26, -- greaterorsimilar \gtrsim +-- [0x02A86] = 0x27, -- greaterorapproxeql \gtrapprox +-- [0x022B8] = 0x28, -- multimap \multimap +-- [0x02234] = 0x29, -- therefore \therefore +-- [0x02235] = 0x2A, -- because \because +-- [0x02251] = 0x2B, -- equalsdots \Doteq \doteqdot +-- [0x0225C] = 0x2C, -- defines \triangleq +-- [0x0227E] = 0x2D, -- precedesorequal \precsim +-- [0x02272] = 0x2E, -- lessorsimilar \lesssim +-- [0x02A85] = 0x2F, -- lessorapproxeql \lessapprox +-- [0x02A95] = 0x30, -- equalorless \eqslantless +-- [0x02A96] = 0x31, -- equalorgreater \eqslantgtr +-- [0x022DE] = 0x32, -- equalorprecedes \curlyeqprec +-- [0x022DF] = 0x33, -- equalorfollows \curlyeqsucc +-- [0x0227C] = 0x34, -- precedesorcurly \preccurlyeq +-- [0x02266] = 0x35, -- lessdblequal \leqq +-- [0x02A7D] = 0x36, -- lessorequalslant \leqslant +-- [0x02276] = 0x37, -- lessorgreater \lessgtr +-- [0x02035] = 0x38, -- primereverse \backprime +-- -- [0x0] = 0x39, -- axisshort \dabar +-- [0x02253] = 0x3A, -- equaldotrightleft \risingdotseq +-- [0x02252] = 0x3B, -- equaldotleftright \fallingdotseq +-- [0x0227D] = 0x3C, -- followsorcurly \succcurlyeq +-- [0x02267] = 0x3D, -- greaterdblequal \geqq +-- [0x02A7E] = 0x3E, -- greaterorequalslant \geqslant +-- [0x02277] = 0x3F, -- greaterorless \gtrless +-- [0x0228F] = 0x40, -- squareimage \sqsubset +-- [0x02290] = 0x41, -- squareoriginal \sqsupset +-- -- wrong: see ** +-- -- [0x022B3] = 0x42, -- triangleright \rhd \vartriangleright +-- -- [0x022B2] = 0x43, -- triangleleft \lhd \vartriangleleft +-- -- cf lm +-- [0x022B5] = 0x44, -- trianglerightequal \unrhd \trianglerighteq +-- [0x022B4] = 0x45, -- triangleleftequal \unlhd \trianglelefteq +-- -- +-- [0x02605] = 0x46, -- star \bigstar +-- [0x0226C] = 0x47, -- between \between +-- [0x025BC] = 0x48, -- triangledownsld \blacktriangledown +-- [0x025B6] = 0x49, -- trianglerightsld \blacktriangleright +-- [0x025C0] = 0x4A, -- triangleleftsld \blacktriangleleft +-- -- [0x0] = 0x4B, -- arrowaxisright +-- -- [0x0] = 0x4C, -- arrowaxisleft +-- [0x025B2] = 0x4D, -- triangle \triangleup \vartriangle +-- [0x025B2] = 0x4E, -- trianglesolid \blacktriangle +-- [0x025BD] = 0x4F, -- triangleinv \triangledown +-- [0x02256] = 0x50, -- ringinequal \eqcirc +-- [0x022DA] = 0x51, -- lessequalgreater \lesseqgtr +-- [0x022DB] = 0x52, -- greaterlessequal \gtreqless +-- [0x02A8B] = 0x53, -- lessdbleqlgreater \lesseqqgtr +-- [0x02A8C] = 0x54, -- greaterdbleqlless \gtreqqless +-- [0x000A5] = 0x55, -- Yen \yen +-- [0x021DB] = 0x56, -- arrowtripleright \Rrightarrow +-- [0x021DA] = 0x57, -- arrowtripleleft \Lleftarrow +-- [0x02713] = 0x58, -- check \checkmark +-- [0x022BB] = 0x59, -- orunderscore \veebar +-- [0x022BC] = 0x5A, -- nand \barwedge +-- [0x02306] = 0x5B, -- perpcorrespond \doublebarwedge +-- [0x02220] = 0x5C, -- angle \angle +-- [0x02221] = 0x5D, -- measuredangle \measuredangle +-- [0x02222] = 0x5E, -- sphericalangle \sphericalangle +-- -- [0x0] = 0x5F, -- proportional \varpropto +-- -- [0x0] = 0x60, -- smile \smallsmile +-- -- [0x0] = 0x61, -- frown \smallfrown +-- [0x022D0] = 0x62, -- subsetdbl \Subset +-- [0x022D1] = 0x63, -- supersetdbl \Supset +-- [0x022D3] = 0x64, -- uniondbl \doublecup \Cup +-- [0x022D2] = 0x65, -- intersectiondbl \doublecap \Cap +-- [0x022CF] = 0x66, -- uprise \curlywedge +-- [0x022CE] = 0x67, -- downfall \curlyvee +-- [0x022CB] = 0x68, -- multiopenleft \leftthreetimes +-- [0x022CC] = 0x69, -- multiopenright \rightthreetimes +-- [0x02AC5] = 0x6A, -- subsetdblequal \subseteqq +-- [0x02AC6] = 0x6B, -- supersetdblequal \supseteqq +-- [0x0224F] = 0x6C, -- difference \bumpeq +-- [0x0224E] = 0x6D, -- geomequivalent \Bumpeq +-- [0x022D8] = 0x6E, -- muchless \lll \llless +-- [0x022D9] = 0x6F, -- muchgreater \ggg \gggtr +-- [0x0231C] = 0x70, -- rightanglenw \ulcorner +-- [0x0231D] = 0x71, -- rightanglene \urcorner +-- [0x024C7] = 0x72, -- circleR \circledR +-- [0x024C8] = 0x73, -- circleS \circledS +-- [0x022D4] = 0x74, -- fork \pitchfork +-- [0x02214] = 0x75, -- dotplus \dotplus +-- [0x0223D] = 0x76, -- revsimilar \backsim +-- [0x022CD] = 0x77, -- revasymptequal \backsimeq -- AM: Check this! I mapped it to simeq. +-- [0x0231E] = 0x78, -- rightanglesw \llcorner +-- [0x0231F] = 0x79, -- rightanglese \lrcorner +-- [0x02720] = 0x7A, -- maltesecross \maltese +-- [0x02201] = 0x7B, -- complement \complement +-- [0x022BA] = 0x7C, -- intercal \intercal +-- [0x0229A] = 0x7D, -- circlering \circledcirc +-- [0x0229B] = 0x7E, -- circleasterisk \circledast +-- [0x0229D] = 0x7F, -- circleminus \circleddash +-- } +-- +-- mathencodings["tex-mb"] = { +-- -- [0x0] = 0x00, -- lessornotequal \lvertneqq +-- -- [0x0] = 0x01, -- greaterornotequal \gvertneqq +-- [0x02270] = 0x02, -- notlessequal \nleq +-- [0x02271] = 0x03, -- notgreaterequal \ngeq +-- [0x0226E] = 0x04, -- notless \nless +-- [0x0226F] = 0x05, -- notgreater \ngtr +-- [0x02280] = 0x06, -- notprecedes \nprec +-- [0x02281] = 0x07, -- notfollows \nsucc +-- [0x02268] = 0x08, -- lessornotdbleql \lneqq +-- [0x02269] = 0x09, -- greaterornotdbleql \gneqq +-- -- [0x0] = 0x0A, -- notlessorslnteql \nleqslant +-- -- [0x0] = 0x0B, -- notgreaterorslnteql \ngeqslant +-- [0x02A87] = 0x0C, -- lessnotequal \lneq +-- [0x02A88] = 0x0D, -- greaternotequal \gneq +-- -- [0x0] = 0x0E, -- notprecedesoreql \npreceq +-- -- [0x0] = 0x0F, -- notfollowsoreql \nsucceq +-- [0x022E8] = 0x10, -- precedeornoteqvlnt \precnsim +-- [0x022E9] = 0x11, -- followornoteqvlnt \succnsim +-- [0x022E6] = 0x12, -- lessornotsimilar \lnsim +-- [0x022E7] = 0x13, -- greaterornotsimilar \gnsim +-- -- [0x0] = 0x14, -- notlessdblequal \nleqq +-- -- [0x0] = 0x15, -- notgreaterdblequal \ngeqq +-- [0x02AB5] = 0x16, -- precedenotslnteql \precneqq +-- [0x02AB6] = 0x17, -- follownotslnteql \succneqq +-- [0x02AB9] = 0x18, -- precedenotdbleqv \precnapprox +-- [0x02ABA] = 0x19, -- follownotdbleqv \succnapprox +-- [0x02A89] = 0x1A, -- lessnotdblequal \lnapprox +-- [0x02A8A] = 0x1B, -- greaternotdblequal \gnapprox +-- [0x02241] = 0x1C, -- notsimilar \nsim +-- [0x02247] = 0x1D, -- notapproxequal \ncong +-- -- [0x0] = 0x1E, -- upslope \diagup +-- -- [0x0] = 0x1F, -- downslope \diagdown +-- -- [0x0] = 0x20, -- notsubsetoreql \varsubsetneq +-- -- [0x0] = 0x21, -- notsupersetoreql \varsupsetneq +-- -- [0x0] = 0x22, -- notsubsetordbleql \nsubseteqq +-- -- [0x0] = 0x23, -- notsupersetordbleql \nsupseteqq +-- [0x02ACB] = 0x24, -- subsetornotdbleql \subsetneqq +-- [0x02ACC] = 0x25, -- supersetornotdbleql \supsetneqq +-- -- [0x0] = 0x26, -- subsetornoteql \varsubsetneqq +-- -- [0x0] = 0x27, -- supersetornoteql \varsupsetneqq +-- [0x0228A] = 0x28, -- subsetnoteql \subsetneq +-- [0x0228B] = 0x29, -- supersetnoteql \supsetneq +-- [0x02288] = 0x2A, -- notsubseteql \nsubseteq +-- [0x02289] = 0x2B, -- notsuperseteql \nsupseteq +-- [0x02226] = 0x2C, -- notparallel \nparallel +-- [0x02224] = 0x2D, -- notbar \nmid \ndivides +-- -- [0x0] = 0x2E, -- notshortbar \nshortmid +-- -- [0x0] = 0x2F, -- notshortparallel \nshortparallel +-- [0x022AC] = 0x30, -- notturnstile \nvdash +-- [0x022AE] = 0x31, -- notforces \nVdash +-- [0x022AD] = 0x32, -- notsatisfies \nvDash +-- [0x022AF] = 0x33, -- notforcesextra \nVDash +-- [0x022ED] = 0x34, -- nottriangeqlright \ntrianglerighteq +-- [0x022EC] = 0x35, -- nottriangeqlleft \ntrianglelefteq +-- [0x022EA] = 0x36, -- nottriangleleft \ntriangleleft +-- [0x022EB] = 0x37, -- nottriangleright \ntriangleright +-- [0x0219A] = 0x38, -- notarrowleft \nleftarrow +-- [0x0219B] = 0x39, -- notarrowright \nrightarrow +-- [0x021CD] = 0x3A, -- notdblarrowleft \nLeftarrow +-- [0x021CF] = 0x3B, -- notdblarrowright \nRightarrow +-- [0x021CE] = 0x3C, -- notdblarrowboth \nLeftrightarrow +-- [0x021AE] = 0x3D, -- notarrowboth \nleftrightarrow +-- [0x022C7] = 0x3E, -- dividemultiply \divideontimes +-- [0x02300] = 0x3F, -- diametersign \varnothing +-- [0x02204] = 0x40, -- notexistential \nexists +-- [0x1D538] = 0x41, -- A (blackboard A) +-- [0x1D539] = 0x42, -- B +-- [0x02102] = 0x43, -- C +-- [0x1D53B] = 0x44, -- D +-- [0x1D53C] = 0x45, -- E +-- [0x1D53D] = 0x46, -- F +-- [0x1D53E] = 0x47, -- G +-- [0x0210D] = 0x48, -- H +-- [0x1D540] = 0x49, -- I +-- [0x1D541] = 0x4A, -- J +-- [0x1D542] = 0x4B, -- K +-- [0x1D543] = 0x4C, -- L +-- [0x1D544] = 0x4D, -- M +-- [0x02115] = 0x4E, -- N +-- [0x1D546] = 0x4F, -- O +-- [0x02119] = 0x50, -- P +-- [0x0211A] = 0x51, -- Q +-- [0x0211D] = 0x52, -- R +-- [0x1D54A] = 0x53, -- S +-- [0x1D54B] = 0x54, -- T +-- [0x1D54C] = 0x55, -- U +-- [0x1D54D] = 0x56, -- V +-- [0x1D54E] = 0x57, -- W +-- [0x1D54F] = 0x58, -- X +-- [0x1D550] = 0x59, -- Y +-- [0x02124] = 0x5A, -- Z (blackboard Z) +-- [0x02132] = 0x60, -- finv \Finv +-- [0x02141] = 0x61, -- fmir \Game +-- -- [0x0] = 0x62, tildewide +-- -- [0x0] = 0x63, tildewider +-- -- [0x0] = 0x64, Finv +-- -- [0x0] = 0x65, Gmir +-- [0x02127] = 0x66, -- Omegainv \mho +-- [0x000F0] = 0x67, -- eth \eth +-- [0x02242] = 0x68, -- equalorsimilar \eqsim +-- [0x02136] = 0x69, -- beth \beth +-- [0x02137] = 0x6A, -- gimel \gimel +-- [0x02138] = 0x6B, -- daleth \daleth +-- [0x022D6] = 0x6C, -- lessdot \lessdot +-- [0x022D7] = 0x6D, -- greaterdot \gtrdot +-- [0x022C9] = 0x6E, -- multicloseleft \ltimes +-- [0x022CA] = 0x6F, -- multicloseright \rtimes +-- -- [0x0] = 0x70, -- barshort \shortmid +-- -- [0x0] = 0x71, -- parallelshort \shortparallel +-- -- [0x02216] = 0x72, -- integerdivide \smallsetminus (2216 already part of tex-sy +-- -- [0x0] = 0x73, -- similar \thicksim +-- -- [0x0] = 0x74, -- approxequal \thickapprox +-- [0x0224A] = 0x75, -- approxorequal \approxeq +-- [0x02AB8] = 0x76, -- followsorequal \succapprox +-- [0x02AB7] = 0x77, -- precedesorequal \precapprox +-- [0x021B6] = 0x78, -- archleftdown \curvearrowleft +-- [0x021B7] = 0x79, -- archrightdown \curvearrowright +-- [0x003DC] = 0x7A, -- Digamma \digamma +-- [0x003F0] = 0x7B, -- kappa \varkappa +-- [0x1D55C] = 0x7C, -- k \Bbbk (blackboard k) +-- [0x0210F] = 0x7D, -- planckover2pi \hslash % 0x7D +-- [0x00127] = 0x7E, -- planckover2pi1 \hbar % 0x7E +-- [0x003F6] = 0x7F, -- epsiloninv \backepsilon +-- } +-- +-- mathencodings["tex-mc"] = { +-- -- this file has no tfm so it gets mapped in the private space +-- [0xFE324] = "mapsfromchar", +-- } mathencodings["tex-fraktur"] = { -- [0x1D504] = 0x41, -- A (fraktur A) diff --git a/tex/context/base/mkxl/math-vfu.lmt b/tex/context/base/mkxl/math-vfu.lmt index 53988036c..bdd5de103 100644 --- a/tex/context/base/mkxl/math-vfu.lmt +++ b/tex/context/base/mkxl/math-vfu.lmt @@ -936,9 +936,12 @@ function vfmath.define(specification,set,goodies) local skewchar = ss.skewchar local backmap = ss.backmap local badones = ss.badones + local ignore = ss.ignore local done = { } local extras = { } - if not backmap then + if backmap == false then + -- backmap = { } + elseif not backmap then backmap = { } for unicode, character in next, fc do backmap[character.order or character.index or unicode] = unicode @@ -969,11 +972,16 @@ function vfmath.define(specification,set,goodies) rv[unicode] = true end else - local u = mathematics.gaps[unicode] or unicode - local t = virtualize(s,uni,fci,skewchar,tonumber(badones and badones[fci.name or ""]),mathparameters,u,fp) - done[uni] = t - characters[unicode] = t - fci.unicode = u + local name = fci.name or "" + if ignore and ignore[name] then + -- get rid of ugly slanted antykwa { } + else + local u = mathematics.gaps[unicode] or unicode + local t = virtualize(s,uni,fci,skewchar,tonumber(badones and badones[name]),mathparameters,u,fp) + done[uni] = t + characters[unicode] = t + fci.unicode = u + end end end if isextension then diff --git a/tex/context/base/mkxl/node-bck.mkxl b/tex/context/base/mkxl/node-bck.mkxl index 357180710..4ee2b0fa9 100644 --- a/tex/context/base/mkxl/node-bck.mkxl +++ b/tex/context/base/mkxl/node-bck.mkxl @@ -19,7 +19,7 @@ \unprotect -\registerctxluafile{node-bck}{autosuffix,optimize} +\registerctxluafile{node-bck}{autosuffix} % \backgroundvbox[green] {\input tufte } \par % \backgroundvbox[blue] {\input ward } \par diff --git a/tex/context/base/mkxl/node-fin.mkxl b/tex/context/base/mkxl/node-fin.mkxl index c0ad58f7d..aef7eea58 100644 --- a/tex/context/base/mkxl/node-fin.mkxl +++ b/tex/context/base/mkxl/node-fin.mkxl @@ -15,8 +15,8 @@ \unprotect -\registerctxluafile{node-shp}{autosuffix,optimize} -\registerctxluafile{node-fin}{autosuffix,optimize} +\registerctxluafile{node-shp}{autosuffix} +\registerctxluafile{node-fin}{autosuffix} \permanent\protected\def\finalizeobjectbox #1{\clf_finalizebox#1\relax} \permanent\protected\def\finalizeshipoutbox#1{\clf_finalizebox#1\relax} diff --git a/tex/context/base/mkxl/node-rul.mkxl b/tex/context/base/mkxl/node-rul.mkxl index 5253c8008..04c0e0dc3 100644 --- a/tex/context/base/mkxl/node-rul.mkxl +++ b/tex/context/base/mkxl/node-rul.mkxl @@ -85,7 +85,7 @@ \mutable\lettonothing\m_rule_option \mutable\lettonothing\m_rule_color -\registerctxluafile{node-rul}{autosuffix,optimize} +\registerctxluafile{node-rul}{autosuffix} \installcorenamespace{bar} \installcorenamespace{barstack} diff --git a/tex/context/base/mkxl/pack-rul.mkxl b/tex/context/base/mkxl/pack-rul.mkxl index 9c25cbf05..36b4fc7b0 100644 --- a/tex/context/base/mkxl/pack-rul.mkxl +++ b/tex/context/base/mkxl/pack-rul.mkxl @@ -25,7 +25,7 @@ \newdimension\framedmaxwidth \newdimension\framedaveragewidth -\registerctxluafile{pack-rul}{autosuffix,optimize} +\registerctxluafile{pack-rul}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/regi-ini.lmt b/tex/context/base/mkxl/regi-ini.lmt new file mode 100644 index 000000000..c0cd4f1c8 --- /dev/null +++ b/tex/context/base/mkxl/regi-ini.lmt @@ -0,0 +1,367 @@ +if not modules then modules = { } end modules ['regi-ini'] = { + version = 1.001, + comment = "companion to regi-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ldx-- +<p>Regimes take care of converting the input characters into +<l n='utf'/> sequences. The conversion tables are loaded at +runtime.</p> +--ldx]]-- + +local tostring = tostring +local utfchar = utf.char +local P, Cs, Cc, lpegmatch = lpeg.P, lpeg.Cs, lpeg.Cc, lpeg.match +local char, gsub, format, gmatch, byte, match, lower = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match, string.lower +local next = next +local insert, remove, fastcopy = table.insert, table.remove, table.fastcopy +local concat = table.concat +local totable = string.totable + +local allocate = utilities.storage.allocate +local sequencers = utilities.sequencers +local textlineactions = resolvers.openers.helpers.textlineactions +local setmetatableindex = table.setmetatableindex + +-- We will hook regime handling code into the input methods. + +local trace_translating = false trackers.register("regimes.translating", function(v) trace_translating = v end) + +local report_loading = logs.reporter("regimes","loading") +local report_translating = logs.reporter("regimes","translating") + +regimes = regimes or { } +local regimes = regimes + +local mapping = allocate { + utf = false +} + +local backmapping = allocate { +} + +-- regimes.mapping = mapping + +local synonyms = { -- backward compatibility list + + ["windows-1250"] = "cp1250", + ["windows-1251"] = "cp1251", + ["windows-1252"] = "cp1252", + ["windows-1253"] = "cp1253", + ["windows-1254"] = "cp1254", + ["windows-1255"] = "cp1255", + ["windows-1256"] = "cp1256", + ["windows-1257"] = "cp1257", + ["windows-1258"] = "cp1258", + + ["il1"] = "8859-1", + ["il2"] = "8859-2", + ["il3"] = "8859-3", + ["il4"] = "8859-4", + ["il5"] = "8859-9", + ["il6"] = "8859-10", + ["il7"] = "8859-13", + ["il8"] = "8859-14", + ["il9"] = "8859-15", + ["il10"] = "8859-16", + + ["iso-8859-1"] = "8859-1", + ["iso-8859-2"] = "8859-2", + ["iso-8859-3"] = "8859-3", + ["iso-8859-4"] = "8859-4", + ["iso-8859-9"] = "8859-9", + ["iso-8859-10"] = "8859-10", + ["iso-8859-13"] = "8859-13", + ["iso-8859-14"] = "8859-14", + ["iso-8859-15"] = "8859-15", + ["iso-8859-16"] = "8859-16", + + ["latin1"] = "8859-1", + ["latin2"] = "8859-2", + ["latin3"] = "8859-3", + ["latin4"] = "8859-4", + ["latin5"] = "8859-9", + ["latin6"] = "8859-10", + ["latin7"] = "8859-13", + ["latin8"] = "8859-14", + ["latin9"] = "8859-15", + ["latin10"] = "8859-16", + + ["utf-8"] = "utf", + ["utf8"] = "utf", + [""] = "utf", + + ["windows"] = "cp1252", + + ["pdf"] = "pdfdoc", + + ["437"] = "ibm", +} + +local currentregime = "utf" + +local function loadregime(mapping,regime) + regime = lower(tostring(regime)) + regime = synonyms[regime] or synonyms["windows-"..regime] or regime + local name = resolvers.findfile(format("regi-%s.lua",regime)) or "" + local data = name ~= "" and dofile(name) + if data then + vector = { } + for eightbit, unicode in next, data do + vector[char(eightbit)] = utfchar(unicode) + end + report_loading("vector %a is loaded",regime) + else + vector = false + report_loading("vector %a is unknown",regime) + end + mapping[regime] = vector + return vector +end + +local function loadreverse(t,k) + local t = { } + local m = mapping[k] + if m then + for k, v in next, m do + t[v] = k + end + end + backmapping[k] = t + return t +end + +setmetatableindex(mapping, loadregime) +setmetatableindex(backmapping,loadreverse) + +regimes.mapping = mapping +regimes.backmapping = backmapping + +local function fromregime(regime,line) + if line and #line > 0 then + -- local map = mapping[regime and synonyms[regime] or regime or currentregime] + local map = mapping[regime or currentregime] + if map then + line = gsub(line,".",map) + end + end + return line +end + +local cache = { } -- if really needed we can copy vectors and hash defaults + +setmetatableindex(cache, function(t,k) + local v = { remappers = { } } + t[k] = v + return v +end) + +local function toregime(vector,str,default) -- toregime('8859-1',"abcde Ä","?") + local d = default or "?" + local c = cache[vector].remappers + local r = c[d] + if not r then + local t = fastcopy(backmapping[vector]) + -- r = utf.remapper(t) -- not good for defaults here + local pattern = Cs((lpeg.utfchartabletopattern(t)/t + lpeg.patterns.utf8character/d + P(1)/d)^0) + r = function(str) + if not str or str == "" then + return "" + else + return lpegmatch(pattern,str) + end + end + c[d] = r + end + return r(str) +end + +local function disable() + currentregime = "utf" + sequencers.disableaction(textlineactions,"regimes.process") + return currentregime +end + +local function enable(regime) + regime = synonyms[regime] or regime + if mapping[regime] == false then + disable() + else + currentregime = regime + sequencers.enableaction(textlineactions,"regimes.process") + end + return currentregime +end + +regimes.toregime = toregime +regimes.fromregime = fromregime +regimes.translate = function(str,regime) return fromregime(regime,str) end +regimes.enable = enable +regimes.disable = disable + +-- The following function can be used when we want to make sure that utf gets passed +-- unharmed. This is needed for modules. + +local level = 0 + +function regimes.process(str,filename,currentline,noflines,coding) + if level == 0 and coding ~= "utf-8" then + str = fromregime(currentregime,str) + if trace_translating then + report_translating("utf: %s",str) + end + end + return str +end + +local function push() + level = level + 1 + if trace_translating then + report_translating("pushing level %s",level) + end +end + +local function pop() + if level > 0 then + if trace_translating then + report_translating("popping level %s",level) + end + level = level - 1 + end +end + +regimes.push = push +regimes.pop = pop + +function regimes.list() + local name = resolvers.findfile(format("regi-ini.lua",regime)) or "" + local okay = { } + if name then + local list = dir.glob(file.join(file.dirname(name),"regi-*.lua")) + for i=1,#list do + local name = list[i] + if name ~= "regi-ini.lua" then + okay[#okay+1] = match(name,"regi%-(.-)%.lua") + end + table.sort(okay) + end + end + return okay +end + +sequencers.prependaction(textlineactions,"system","regimes.process") +sequencers.disableaction(textlineactions,"regimes.process") + +-- Next we provide some hacks. Unfortunately we run into crappy encoded (read: +-- mixed) encoded xml files that have these ë ä ö ü sequences instead of ë ä ö ü +-- etc. + +local patterns = { } + +function regimes.cleanup(regime,str) + if not str or str == "" then + return str + end + local p = patterns[regime] + if p == nil then + regime = regime and synonyms[regime] or regime or currentregime + local vector = regime ~= "utf" and regime ~= "utf-8" and mapping[regime] + if vector then + local mapping = { } + for k, v in next, vector do + local split = totable(v) + for i=1,#split do + split[i] = utfchar(byte(split[i])) + end + split = concat(split) + if v ~= split then + mapping[split] = v + end + end + p = Cs((lpeg.utfchartabletopattern(mapping)/mapping+P(1))^0) + else + p = false + end + patterns[regime] = p + end + return p and lpegmatch(p,str) or str +end + +-- local old = [[test ë ä ö ü crap]] +-- local new = regimes.cleanup("cp1252",old) +-- report_translating("%s -> %s",old,new) +-- local old = "Pozn" .. char(0xE1) .. "mky" +-- local new = fromregime("cp1250",old) +-- report_translating("%s -> %s",old,new) + +-- interface (might move to regi-tex.lua) + +if interfaces then + + local implement = interfaces.implement + local setmacro = interfaces.setmacro + + implement { + name = "enableregime", + public = true, + protected = true, + arguments = "optional", + actions = function(regime) setmacro("currentregime",enable(regime)) end + } + + implement { + name = "disableregime", + public = true, + protected = true, + actions = function() setmacro("currentregime",disable()) end + } + + implement { + name = "pushregime", + public = true, + protected = true, + actions = push + } + + implement { + name = "popregime", + public = true, + protected = true, + actions = pop + } + + local stack = { } + + implement { + name = "startregime", + public = true, + protected = true, + arguments = "optional", + actions = function(regime) + insert(stack,currentregime) + if trace_translating then + report_translating("start using %a",regime) + end + setmacro("currentregime",enable(regime)) + end + } + + implement { + name = "stopregime", + public = true, + protected = true, + actions = function() + if #stack > 0 then + local regime = remove(stack) + if trace_translating then + report_translating("stop using %a",regime) + end + setmacro("currentregime",enable(regime)) + end + end + } + +end diff --git a/tex/context/base/mkxl/regi-ini.mkxl b/tex/context/base/mkxl/regi-ini.mkxl index 8ba7edc42..da5bdf081 100644 --- a/tex/context/base/mkxl/regi-ini.mkxl +++ b/tex/context/base/mkxl/regi-ini.mkxl @@ -11,13 +11,14 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\registerctxluafile{regi-ini}{} +\registerctxluafile{regi-ini}{autosuffix} \unprotect %D \macros %D {enableregime,disableregime, %D startregime,stopregime, +%D pushregime, popregime, %D currentregime} %D %D Beware, the enable and disable commands are global switches, so best use the @@ -25,13 +26,15 @@ \mutable\lettonothing\currentregime -\permanent\protected\def\enableregime[#1]{\clf_enableregime{#1}} -\permanent\protected\def\disableregime {\clf_disableregime} -\permanent\protected\def\startregime [#1]{\clf_startregime{#1}} -\permanent\protected\def\stopregime {\clf_stopregime} - -% only for diagnostics: - -% \def\codepagename#1{\cldcontext{os.tocodepage("#1")}} +%D These are defined at the \LUA\ end: +%D +%D \starttyping +%D \enableregime[#1] +%D \disableregime +%D \startregime [#1] +%D \stopregime +%D \pushregime +%D \popregime +%D \stoptyping \protect \endinput diff --git a/tex/context/base/mkxl/spac-ali.mkxl b/tex/context/base/mkxl/spac-ali.mkxl index c7d2fb657..f5b0e2fb8 100644 --- a/tex/context/base/mkxl/spac-ali.mkxl +++ b/tex/context/base/mkxl/spac-ali.mkxl @@ -19,7 +19,7 @@ %D variants. Starting at the last day of 2011 both methods are merged into one and %D caching has been added, which makes switching twice as fast. -\registerctxluafile{spac-ali}{autosuffix,optimize} +\registerctxluafile{spac-ali}{autosuffix} % Used once so ... replace it or use if more frequently ... diff --git a/tex/context/base/mkxl/spac-chr.mkxl b/tex/context/base/mkxl/spac-chr.mkxl index 346bc2183..ef63b2b82 100644 --- a/tex/context/base/mkxl/spac-chr.mkxl +++ b/tex/context/base/mkxl/spac-chr.mkxl @@ -15,7 +15,7 @@ \unprotect -\registerctxluafile{spac-chr}{autosuffix,optimize} +\registerctxluafile{spac-chr}{autosuffix} \definesystemattribute[characters][public] diff --git a/tex/context/base/mkxl/spac-hor.mkxl b/tex/context/base/mkxl/spac-hor.mkxl index 017a94d5b..3c4fd1eb4 100644 --- a/tex/context/base/mkxl/spac-hor.mkxl +++ b/tex/context/base/mkxl/spac-hor.mkxl @@ -400,13 +400,19 @@ % test test\fsp. test % beats frenchspacing +% \permanent\protected\def\fsp#1% fixed space puncuation +% {\begingroup +% \ifchknum`#1\or +% \sfcode`#1\plusthousand +% \fi +% #1% +% \endgroup} + \permanent\protected\def\fsp#1% fixed space puncuation - {\begingroup + {#1% \ifchknum`#1\or - \sfcode`#1\plusthousand - \fi - #1% - \endgroup} + \spacefactor\plusthousand + \fi} %D Here's a tweak .. if needed one can configure it in the configuration %D so that initialization happens more efficient. diff --git a/tex/context/base/mkxl/spac-ver.mkxl b/tex/context/base/mkxl/spac-ver.mkxl index 807ecfcd3..640d493b9 100644 --- a/tex/context/base/mkxl/spac-ver.mkxl +++ b/tex/context/base/mkxl/spac-ver.mkxl @@ -20,7 +20,7 @@ \newdimen \bodyfontstrutdepth \newgluespec\globalbodyfontlineheight % why a skip -\newdimen \globalbodyfontstrutheight +\newdimen \globalbodyfontstrutheight \newdimen \globalbodyfontstrutdepth \newgluespec \s_spac_vspacing_predefined @@ -31,7 +31,7 @@ % \overloaded\let\strutdp \undefined \newdimen\strutdp % \overloaded\let\struthtdp\undefined \newdimen\struthtdp -\registerctxluafile{spac-ver}{autosuffix,optimize} +\registerctxluafile{spac-ver}{autosuffix} % todo: use usernodes ? diff --git a/tex/context/base/mkxl/strc-flt.mklx b/tex/context/base/mkxl/strc-flt.mklx index 1f2aeaae5..55b825fe1 100644 --- a/tex/context/base/mkxl/strc-flt.mklx +++ b/tex/context/base/mkxl/strc-flt.mklx @@ -527,6 +527,53 @@ \fi \fi} +\def\strc_floats_apply_caption_command + {\setbox\b_strc_floats_caption\hbox\bgroup + %\unless\ifcstok{\floatcaptionparameter\c!command}\emptytoks + \floatcaptionparameter\c!command{\box\b_strc_floats_caption}% + %\orunless\ifcstok{\floatcaptionparameter\c!deeptextcommand}\emptytoks + % \floatcaptionparameter\c!deeptextcommand{\unvbox\b_strc_floats_caption}% + %\else + % \box\b_strc_floats_caption + %\fi + \egroup} + +%D Some trickery (example by MS): +%D +%D \starttyping +%D \defineframed +%D [MyCaptionFramed] +%D [align={lohi,flushleft}, +%D width=fit, +%D frame=off, +%D strut=no, +%D topframe=on, +%D loffset=1em, +%D toffset=0.25\lineheight] +%D +%D \starttexdefinition protected MyCaption #1 +%D \MyCaptionFramed { +%D % we ignore #1 as we want to unpack +%D \unvbox\floatcaptionbox +%D } +%D \stoptexdefinition +%D +%D \definefloat[pagefloat][pagefloats][graphic] +%D +%D \setupfloat +%D [pagefloat] +%D [default={page,header,footer}] +%D +%D \setupcaption +%D [pagefloat] +%D [location={top,inner}, +%D align=inner, +%D command=\MyCaption, +%D spaceinbetween=nowhite] +%D \stoptyping + +\permanent\protected\def\floatcaptionbox{\b_strc_floats_caption} + %D We can do this ... %D %D \starttyping @@ -1683,8 +1730,7 @@ % todo: installable maken, variant/method=auto vs macro \strc_floats_prepare_page_caption %\page_backgrounds_add_local_to_box\b_strc_floats_content - \setbox\b_strc_floats_caption\hbox % text - {\floatcaptionparameter\c!command{\box\b_strc_floats_caption}}% + \strc_floats_apply_caption_command \strc_floats_set_caption_dimensions\b_strc_floats_caption %\moveboxontogrid\b_strc_floats_caption{\floatcaptionparameter\c!grid}\d_strc_floats_caption_height %\page_backgrounds_add_local_to_box\b_strc_floats_caption @@ -2355,7 +2401,7 @@ \else \strc_floats_check_caption_content \strc_floats_prepare_side_caption - \setbox\b_strc_floats_caption\hbox{\floatcaptionparameter\c!command{\box\b_strc_floats_caption}}% \hpack ? + \strc_floats_apply_caption_command %\moveboxontogrid\b_strc_floats_caption{\floatcaptionparameter\c!grid}\d_strc_floats_caption_height %\page_backgrounds_add_local_to_box\b_strc_floats_caption \strc_floats_build_side_box diff --git a/tex/context/base/mkxl/strc-lst.lmt b/tex/context/base/mkxl/strc-lst.lmt index 67e06520c..703e580d7 100644 --- a/tex/context/base/mkxl/strc-lst.lmt +++ b/tex/context/base/mkxl/strc-lst.lmt @@ -853,17 +853,46 @@ filters[v_component] = function(specification) return result end +-- filters[v_product] = function(specification) +-- local reference = specification.reference +-- if reference and reference ~= "" then +-- -- local utilitydata = job.loadother(reference,true) +-- local fullname = file.replacesuffix(reference,"tuc") +-- if lfs.isfile(fullname) then +-- local utilitydata = job.loadother(fullname) +-- if utilitydata then +-- local collected = utilitydata.structures.lists.collected or { } +-- setmetatableindex(collected,{ external = reference }) +-- return collected +-- end +-- end +-- end +-- return { } +-- end + filters[v_product] = function(specification) local reference = specification.reference if reference and reference ~= "" then --- local utilitydata = job.loadother(reference,true) + -- local utilitydata = job.loadother(reference,true) local fullname = file.replacesuffix(reference,"tuc") if lfs.isfile(fullname) then local utilitydata = job.loadother(fullname) if utilitydata then local collected = utilitydata.structures.lists.collected or { } setmetatableindex(collected,{ external = reference }) - return collected + local result = { } + local nofresult = 0 + local all = specification.all + local names = specification.names + for i=1,#collected do + local v = collected[i] + local m = v.metadata + if m and names[m.name] or all then + nofresult = nofresult + 1 + result[nofresult] = v + end + end + return result end end end diff --git a/tex/context/base/mkxl/strc-ref.mklx b/tex/context/base/mkxl/strc-ref.mklx index de8cd29e1..e7073b36d 100644 --- a/tex/context/base/mkxl/strc-ref.mklx +++ b/tex/context/base/mkxl/strc-ref.mklx @@ -37,7 +37,7 @@ \registerctxluafile{strc-rsc}{autosuffix} \registerctxluafile{strc-ref}{autosuffix} -\registerctxluafile{node-ref}{autosuffix,optimize} +\registerctxluafile{node-ref}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/supp-box.mkxl b/tex/context/base/mkxl/supp-box.mkxl index 802815416..710a4892e 100644 --- a/tex/context/base/mkxl/supp-box.mkxl +++ b/tex/context/base/mkxl/supp-box.mkxl @@ -34,7 +34,7 @@ \newdimension\lastnaturalboxht \newdimension\lastnaturalboxdp -\registerctxluafile{supp-box}{autosuffix,optimize} +\registerctxluafile{supp-box}{autosuffix} % \fixupboxesmode\plusone % gone: is now the default diff --git a/tex/context/base/mkxl/tabl-xtb.mklx b/tex/context/base/mkxl/tabl-xtb.mklx index 84755cc1c..f7121dc58 100644 --- a/tex/context/base/mkxl/tabl-xtb.mklx +++ b/tex/context/base/mkxl/tabl-xtb.mklx @@ -252,7 +252,7 @@ }% else whitespace mess \def\tabl_x_get_buffer - {\clf_gettexbuffer{\tabl_x_current_buffer}} + {\clf_getbuffertex{\tabl_x_current_buffer}} \let\tabl_x_start_row_yes \relax \let\tabl_x_start_row_nop \relax diff --git a/tex/context/base/mkxl/type-set.mkxl b/tex/context/base/mkxl/type-set.mkxl index 2425d8538..5b83f287e 100644 --- a/tex/context/base/mkxl/type-set.mkxl +++ b/tex/context/base/mkxl/type-set.mkxl @@ -176,8 +176,8 @@ \definefilesynonym [type-imp-kurier-medium.mkiv] [type-imp-kurier.mkiv] \definefilesynonym [type-imp-kurier-heavy.mkiv] [type-imp-kurier.mkiv] -\definefilesynonym [type-imp-antykwa-torunska-light.mkiv] [type-imp-antykwa.mkiv] -\definefilesynonym [type-imp-antykwa-torunska-cond.mkiv] [type-imp-antykwa.mkiv] -\definefilesynonym [type-imp-antykwa-torunska-lightcond.mkiv] [type-imp-antykwa.mkiv] +\definefilesynonym [type-imp-antykwa-light.mkiv] [type-imp-antykwa.mkiv] +\definefilesynonym [type-imp-antykwa-cond.mkiv] [type-imp-antykwa.mkiv] +\definefilesynonym [type-imp-antykwa-lightcond.mkiv] [type-imp-antykwa.mkiv] \protect \endinput diff --git a/tex/context/base/mkxl/typo-lan.lmt b/tex/context/base/mkxl/typo-lan.lmt new file mode 100644 index 000000000..21aead80c --- /dev/null +++ b/tex/context/base/mkxl/typo-lan.lmt @@ -0,0 +1,89 @@ +if not modules then modules = { } end modules ['typo-lan'] = { + version = 1.001, + comment = "companion to typo-lan.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type, next = type, next + +local currentfont = font.current +local setmetatableindex = table.setmetatableindex +local utfbyte = utf.byte + +local hashes = fonts.hashes +local fontdata = hashes.characters +local emwidths = hashes.emwidths + +local frequencies = languages.frequencies or { } +languages.frequencies = frequencies + +local frequencydata = { } +local frequencyfile = string.formatters["lang-frq-%s.lua"] +local frequencycache = { } + +setmetatableindex(frequencydata, function(t,language) + local fullname = resolvers.findfile(frequencyfile(language)) + local v = fullname ~= "" and dofile(fullname) + if not v or not v.frequencies then + v = t.en + end + t[language] = v + return v +end) + +setmetatableindex(frequencycache, function(t,language) + local dataset = frequencydata[language] + local frequencies = dataset.frequencies + if not frequencies then + return t.en + end + local v = { } + setmetatableindex(v, function(t,font) + local average = emwidths[font] / 2 + if frequencies then + local characters = fontdata[font] + local sum, tot = 0, 0 + for k, v in next, frequencies do + local character = characters[k] -- characters[type(k) == "number" and k or utfbyte(k)] + tot = tot + v + sum = sum + v * (character and character.width or average) + end + average = sum / tot -- widths + end + t[font] = average + return average + end) + t[language] = v + return v +end) + +function frequencies.getdata(language) + return frequencydata[language] +end + +function frequencies.averagecharwidth(language,font) + return frequencycache[language or "en"][font or currentfont()] +end + +-- Just because we can, we also have a setter ... + +local dimension_value = tokens.values.dimension +local scanstring = tokens.scanners.string +local scandimension = tokens.scanners.dimension + +interfaces.implement { + name = "languagecharwidth", + public = true, + usage = "value", + actions = function(what) + local language = scanstring() + local font = currentfont() + if what == "value" then + return dimension_value, frequencycache[language][font] or 0 + else + frequencycache[language][font] = scandimension(false,false,true) + end + end, +} diff --git a/tex/context/base/mkxl/typo-lan.mkxl b/tex/context/base/mkxl/typo-lan.mkxl index 9d137f5a5..7fc2a7b46 100644 --- a/tex/context/base/mkxl/typo-lan.mkxl +++ b/tex/context/base/mkxl/typo-lan.mkxl @@ -15,10 +15,10 @@ \unprotect -\registerctxluafile{typo-lan}{} +\registerctxluafile{typo-lan}{autosuffix} %D \macros -%D {averagecharwidth, charwidthlanguage} +%D {languagecharwidth, averagecharwidth, charwidthlanguage} %D %D This is a more \MKIV-ish variant of lang-frq.mkiv. The methods are gone as one %D doesn't need the tables for them. The main macro is \type {\averagecharwidth} @@ -26,39 +26,41 @@ %D %D I finally decided to reimplement this as I needed it for a manual (which is often %D a reason for such a rewrite). With some inspiring Porcupine Tree in the -%D background it's not the worst thing to do. +%D background it's not the worst thing to do. The \LMTX\ variant is a bit more +%D flexible as it can also set, not that someone will notice. \mutable\def\charwidthlanguage{\currentmainlanguage} -\permanent\def\averagecharwidth {\dimexpr\clf_averagecharwidth{\charwidthlanguage}\scaledpoint\relax} -\permanent\def\languagecharwidth#1{\dimexpr\clf_averagecharwidth{#1}\scaledpoint\relax} - -\protect - -\continueifinputfile{typo-lan.mkiv} - -\setuplayout[backspace=4cm] - -\showframe - -\starttext - -\startbuffer - -\mainlanguage[en] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par -\mainlanguage[de] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par -\mainlanguage[nl] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par - -\stopbuffer - -\getbuffer \blank - -\switchtobodyfont[pagella] - -\getbuffer \blank - -\switchtobodyfont[tt,8pt] - -\getbuffer - -\stoptext +% \languagecharwidth{language} is defined at the lua end + +\permanent\def\averagecharwidth{\languagecharwidth{\charwidthlanguage}} + +\protect \endinput + +% \setuplayout[backspace=4cm] +% +% \showframe +% +% \starttext +% +% \startbuffer +% +% \mainlanguage[en] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par +% \mainlanguage[de] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par +% \mainlanguage[nl] \hsize65\averagecharwidth \normalexpanded{\inleft{\the\hsize}} \input ward \par +% +% \languagecharwidth{de}=\languagecharwidth{en} +% +% \stopbuffer +% +% \getbuffer \blank +% +% \switchtobodyfont[pagella] +% +% \getbuffer \blank +% +% \switchtobodyfont[tt,8pt] +% +% \getbuffer +% +% \stoptext diff --git a/tex/context/base/mkxl/typo-pnc.lmt b/tex/context/base/mkxl/typo-pnc.lmt new file mode 100644 index 000000000..090cbb5b6 --- /dev/null +++ b/tex/context/base/mkxl/typo-pnc.lmt @@ -0,0 +1,170 @@ +if not modules then modules = { } end modules ['typo-pnc'] = { + version = 1.001, + comment = "companion to typo-pnc.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local nodes = nodes +local fonts = fonts + +local enableaction = nodes.tasks.enableaction + +local nuts = nodes.nuts +local tonut = nodes.tonut + +local nodecodes = nodes.nodecodes +local gluecodes = nodes.gluecodes +local glyph_code = nodecodes.glyph +local glue_code = nodecodes.glue +local spaceskip_code = gluecodes.spaceskip + +local new_kern = nuts.pool.kern +local insertafter = nuts.insertafter + +local nextglyph = nuts.traversers.glyph + +local getchar = nuts.getchar +local getfont = nuts.getfont +local getboth = nuts.getboth +local getnext = nuts.getnext +local getattr = nuts.getattr +local getid = nuts.getid +local getsubtype = nuts.getsubtype +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth +local findattribute = nuts.findattribute + +local glyph_code = nodes.nodecodes.glyph + +local parameters = fonts.hashes.parameters +local categories = characters.categories + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local period = 0x2E +local factor = 0.5 + +-- alternative: tex.getlccode and tex.getuccode + +typesetters = typesetters or { } +local typesetters = typesetters + +local periodkerns = typesetters.periodkerns or { } +typesetters.periodkerns = periodkerns + +local report = logs.reporter("period kerns") +local trace = false + +trackers.register("typesetters.periodkerns",function(v) trace = v end) + +periodkerns.mapping = periodkerns.mapping or { } +periodkerns.factors = periodkerns.factors or { } +local a_periodkern = attributes.private("periodkern") + +storage.register("typesetters/periodkerns/mapping", periodkerns.mapping, "typesetters.periodkerns.mapping") +storage.register("typesetters/periodkerns/factors", periodkerns.factors, "typesetters.periodkerns.factors") + +local mapping = periodkerns.mapping +local factors = periodkerns.factors + +function periodkerns.handler(head) + local _, start = findattribute(head,a_periodkern,glyph_code) + if start then + for current, char, font in nextglyph, start do + if char == period then + local a = getattr(current,a_periodkern) + if a then + local factor = mapping[a] + if factor then + local prev, next = getboth(current) + if prev and next and getid(prev) == glyph_code and getid(next) == glyph_code then + local pchar = getchar(prev) + local pcode = categories[pchar] + if pcode == "lu" or pcode == "ll" then + local nchar = getchar(next) + local ncode = categories[nchar] + if ncode == "lu" or ncode == "ll" then + local next2 = getnext(next) + if next2 and getid(next2) == glyph_code and getchar(next2) == period then + -- A.B. + local fontspace, inserted + if factor ~= 0 then + fontspace = parameters[getfont(current)].space -- can be sped up + inserted = factor * fontspace + insertafter(head,current,new_kern(inserted)) + if trace then + report("inserting space at %C . [%p] %C .",pchar,inserted,nchar) + end + end + local next3 = getnext(next2) + if next3 and getid(next3) == glue_code and getsubtype(next3) == spaceskip_code then + local width = getwidth(next3) + local space = fontspace or parameters[getfont(current)].space -- can be sped up + if width > space then -- space + extraspace + local next4 = getnext(next3) + if next4 and getid(next4) == glyph_code then + local fchar = getchar(next4) + if categories[fchar] ~= "lu" then + -- A.B.<glue>X + if trace then + if inserted then + report("reverting space at %C . [%p] %C . [%p->%p] %C",pchar,inserted,nchar,width,space,fchar) + else + report("reverting space at %C . %C . [%p->%p] %C",pchar,nchar,width,space,fchar) + end + end + setwidth(next3,space) + else + if trace then + if inserted then + report("keeping space at %C . [%p] %C . [%p] %C",pchar,inserted,nchar,width,fchar) + else + report("keeping space at %C . %C . [%p] %C",pchar,nchar,width,fchar) + end + end + end + end + end + end + end + end + end + end + end + end + end + end + end + return head +end + +local enabled = false + +function periodkerns.set(factor) + factor = tonumber(factor) or 0 + if not enabled then + enableaction("processors","typesetters.periodkerns.handler") + enabled = true + end + local a = factors[factor] + if not a then + a = #mapping + 1 + factors[factors], mapping[a] = a, factor + end + factor = a + texsetattribute(a_periodkern,factor) + return factor +end + +-- interface + +interfaces.implement { + name = "setperiodkerning", + actions = periodkerns.set, + arguments = "string" +} + + diff --git a/tex/context/base/mkxl/typo-pnc.mkxl b/tex/context/base/mkxl/typo-pnc.mkxl index b5b1a17d6..aceab2685 100644 --- a/tex/context/base/mkxl/typo-pnc.mkxl +++ b/tex/context/base/mkxl/typo-pnc.mkxl @@ -19,7 +19,7 @@ % with "foo e.g.\ bar" so let's see if we can automate that and at the same time % inject spaces between the snippets. It gets boring writing this kind of code. -\registerctxluafile{typo-pnc}{} +\registerctxluafile{typo-pnc}{autosuffix} \definesystemattribute[periodkern][public,global] diff --git a/tex/context/fonts/mkiv/antykwa-math.lfg b/tex/context/fonts/mkiv/antykwa-math.lfg index fe259e909..3c34d7af0 100644 --- a/tex/context/fonts/mkiv/antykwa-math.lfg +++ b/tex/context/fonts/mkiv/antykwa-math.lfg @@ -19,6 +19,12 @@ local badones = { coproductdisplay = .25, } +local uglyones = { + braceleft = true, + braceright = true, +} + + return { name = "antykwa-math", version = "1.00", @@ -42,7 +48,8 @@ return { { name = "mi-anttri.tfm", vector = "tex-it", skewchar=0x7F }, { name = "mi-anttbi.tfm", vector = "tex-bi", skewchar=0x7F }, { name = "rm-anttb.tfm", vector = "tex-bf", skewchar=0x7F }, - { name = "sy-anttrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, + { name = "sy-anttrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true, ignore = uglyones }, + { name = "file:AntykwaTorunska-Regular", vector = "tex-ex-braces", backmap = false }, { name = "ex-anttr.tfm", vector = "tex-ex", extension = true, badones = badones }, }, ["antykwa-light-math"] = { @@ -53,7 +60,8 @@ return { { name = "mi-anttli.tfm", vector = "tex-it", skewchar=0x7F }, { name = "mi-anttri.tfm", vector = "tex-bi", skewchar=0x7F }, { name = "rm-anttr.tfm", vector = "tex-bf", skewchar=0x7F }, - { name = "sy-anttlz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, + { name = "sy-anttlz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true, ignore = uglyones }, + { name = "file:AntykwaTorunskaLight-Regular", vector = "tex-ex-braces", backmap = false }, { name = "ex-anttl.tfm", vector = "tex-ex", extension = true, badones = badones }, }, ["antykwa-cond-math"] = { @@ -64,7 +72,8 @@ return { { name = "mi-anttcri.tfm", vector = "tex-it", skewchar=0x7F }, { name = "mi-anttcbi.tfm", vector = "tex-bi", skewchar=0x7F }, { name = "rm-anttcb.tfm", vector = "tex-bf", skewchar=0x7F }, - { name = "sy-anttcrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, + { name = "sy-anttcrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true, ignore = uglyones }, + { name = "file:AntykwaTorunskaCond-Regular", vector = "tex-ex-braces", backmap = false }, { name = "ex-anttcr.tfm", vector = "tex-ex", extension = true, badones = badones }, }, ["antykwa-lightcond-math"] = { @@ -75,7 +84,8 @@ return { { name = "mi-anttcli.tfm", vector = "tex-it", skewchar=0x7F }, { name = "mi-anttcri.tfm", vector = "tex-bi", skewchar=0x7F }, { name = "rm-anttcr.tfm", vector = "tex-bf", skewchar=0x7F }, - { name = "sy-anttclz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, + { name = "sy-anttclz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true, ignore = uglyones }, + { name = "file:AntykwaTorunskaCondLight-Regular", vector = "tex-ex-braces", backmap = false }, { name = "ex-anttcl.tfm", vector = "tex-ex", extension = true, badones = badones }, } } diff --git a/tex/context/fonts/mkiv/bonum-math.lfg b/tex/context/fonts/mkiv/bonum-math.lfg index e3fd4119d..56262eb32 100644 --- a/tex/context/fonts/mkiv/bonum-math.lfg +++ b/tex/context/fonts/mkiv/bonum-math.lfg @@ -139,6 +139,16 @@ return { ["0x221A.parts.bottom"] = { location = "left", hfactor = .1, vfactor = 1.15 }, } }, + { + tweak = "dimensions", + list = { + -- [0x007D] = { topright = -0.05, bottomright = -0.05 }, -- right brace variants + ["0x7C"] = { width = 1.4, xoffset=0.2 }, -- vertical bar + -- ["0x7C.variants.*"] = { width = 1, extend = 2.4 }, -- vertical bar + -- ["0x7C.parts.top"] = { , }, -- vertical bar + -- ["0x7C.parts.bottom"] = { bottomright = -0.15 }, -- vertical bar + }, + }, { tweak = "fixaccents", @@ -277,7 +287,7 @@ return { }, { tweak = "addbars", - advance = 0.275, + advance = 0.475, }, { tweak = "addactuarian", diff --git a/tex/context/fonts/mkiv/type-imp-antykwa.mkiv b/tex/context/fonts/mkiv/type-imp-antykwa.mkiv index 15a2f39b6..6ad747307 100644 --- a/tex/context/fonts/mkiv/type-imp-antykwa.mkiv +++ b/tex/context/fonts/mkiv/type-imp-antykwa.mkiv @@ -34,7 +34,7 @@ \definefontsynonym [AntykwaTorunska-Light] [\s!file:AntykwaTorunskaLight-Regular] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-LightItalic] [\s!file:AntykwaTorunskaLight-Italic] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-Medium] [\s!file:AntykwaTorunskaMed-Regular] [\s!features=\s!default] - \definefontsynonym [AntykwaTorunska-MedItalic] [\s!file:AntykwaTorunskaMed-Italic] [\s!features=\s!default] + \definefontsynonym [AntykwaTorunska-MediumItalic] [\s!file:AntykwaTorunskaMed-Italic] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-CondRegular] [\s!file:AntykwaTorunskaCond-Regular] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-CondItalic] [\s!file:AntykwaTorunskaCond-Italic] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-CondBold] [\s!file:AntykwaTorunskaCond-Bold] [\s!features=\s!default] @@ -42,24 +42,7 @@ \definefontsynonym [AntykwaTorunska-CondLight] [\s!file:AntykwaTorunskaCondLight-Regular] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-CondLightItalic] [\s!file:AntykwaTorunskaCondLight-Italic] [\s!features=\s!default] \definefontsynonym [AntykwaTorunska-CondMedium] [\s!file:AntykwaTorunskaCondMed-Regular] [\s!features=\s!default] - \definefontsynonym [AntykwaTorunska-CondMedItalic] [\s!file:AntykwaTorunskaCondMed-Italic] [\s!features=\s!default] - - \definefontsynonym [AntykwaTorunska-Cap] [\s!file:AntykwaTorunska-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-ItalicCap] [\s!file:AntykwaTorunska-Italic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-BoldCap] [\s!file:AntykwaTorunska-Bold] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-BoldItalicCap] [\s!file:AntykwaTorunska-BoldItalic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-LightCap] [\s!file:AntykwaTorunskaLight-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-LightItalicCap] [\s!file:AntykwaTorunskaLight-Italic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-MediumCap] [\s!file:AntykwaTorunskaMed-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-MedItalicCap] [\s!file:AntykwaTorunskaMed-Italic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondCap] [\s!file:AntykwaTorunskaCond-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondItalicCap] [\s!file:AntykwaTorunskaCond-Italic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondBoldCap] [\s!file:AntykwaTorunskaCond-Bold] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondBoldItalicCap] [\s!file:AntykwaTorunskaCond-BoldItalic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondLightCap] [\s!file:AntykwaTorunskaCondLight-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondLightItalicCap][\s!file:AntykwaTorunskaCondLight-Italic] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondMediumCap] [\s!file:AntykwaTorunskaCondMed-Regular] [\s!features=\s!smallcaps] - \definefontsynonym [AntykwaTorunska-CondMedItalicCap] [\s!file:AntykwaTorunskaCondMed-Italic] [\s!features=\s!smallcaps] + \definefontsynonym [AntykwaTorunska-CondMediumItalic] [\s!file:AntykwaTorunskaCondMed-Italic] [\s!features=\s!default] \stoptypescript \starttypescript [\s!math][antykwa,antykwa-torunska][\s!all] @@ -89,7 +72,6 @@ \definefontsynonym [\s!SerifSlanted] [AntykwaTorunska-Italic] \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-BoldItalic] \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-BoldItalic] - \definefontsynonym [\s!SerifCaps] [AntykwaTorunska-Cap] \stoptypescript \starttypescript [\s!serif] [antykwa-light,antykwa-torunska-light] [\s!name] @@ -97,9 +79,8 @@ \definefontsynonym [\s!SerifBold] [AntykwaTorunska-Medium] \definefontsynonym [\s!SerifItalic] [AntykwaTorunska-LightItalic] \definefontsynonym [\s!SerifSlanted] [AntykwaTorunska-LightItalic] - \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-MedItalic] - \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-MedItalic] - \definefontsynonym [\s!SerifCaps] [AntykwaTorunska-LightCap] + \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-MediumItalic] + \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-MediumItalic] \stoptypescript \starttypescript [\s!serif] [antykwa-cond,antykwa-torunska-cond] [\s!name] @@ -109,7 +90,6 @@ \definefontsynonym [\s!SerifSlanted] [AntykwaTorunska-CondItalic] \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-CondBoldItalic] \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-CondBoldItalic] - \definefontsynonym [\s!SerifCaps] [AntykwaTorunska-CondCap] \stoptypescript \starttypescript [\s!serif] [antykwa-lightcond,antykwa-torunska-lightcond] [\s!name] @@ -117,117 +97,8 @@ \definefontsynonym [\s!SerifBold] [AntykwaTorunska-CondMedium] \definefontsynonym [\s!SerifItalic] [AntykwaTorunska-CondLightItalic] \definefontsynonym [\s!SerifSlanted] [AntykwaTorunska-CondLightItalic] - \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [\s!SerifCaps] [AntykwaTorunska-CondLightCap] - \stoptypescript - - \starttypescript [\s!serif] [antykwa,antykwa-torunska] [\s!name] - \definefontsynonym [SerifRegular] [Serif] - \definefontsynonym [SerifRegularCaps] [AntykwaTorunska-Cap] - \definefontsynonym [SerifBoldCaps] [AntykwaTorunska-BoldCap] - \definefontsynonym [SerifItalicCaps] [AntykwaTorunska-ItalicCap] - \definefontsynonym [SerifSlantedCaps] [AntykwaTorunska-ItalicCap] - \definefontsynonym [SerifBoldItalicCaps] [AntykwaTorunska-BoldItalicCap] - \definefontsynonym [SerifBoldSlantedCaps] [AntykwaTorunska-BoldItalicCap] - \definefontsynonym [SerifCapsCaps] [AntykwaTorunska-Cap] - - \definefontsynonym [SerifRegularLight] [AntykwaTorunska-Light] - \definefontsynonym [SerifBoldLight] [AntykwaTorunska-Medium] - \definefontsynonym [SerifItalicLight] [AntykwaTorunska-LightItalic] - \definefontsynonym [SerifSlantedLight] [AntykwaTorunska-LightItalic] - \definefontsynonym [SerifBoldItalicLight] [AntykwaTorunska-MedItalic] - \definefontsynonym [SerifBoldSlantedLight] [AntykwaTorunska-MedItalic] - \definefontsynonym [SerifCapsLight] [AntykwaTorunska-LightCap] - - \definefontsynonym [SerifRegularCond] [AntykwaTorunska-CondRegular] - \definefontsynonym [SerifBoldCond] [AntykwaTorunska-CondBold] - \definefontsynonym [SerifItalicCond] [AntykwaTorunska-CondItalic] - \definefontsynonym [SerifSlantedCond] [AntykwaTorunska-CondItalic] - \definefontsynonym [SerifBoldItalicCond] [AntykwaTorunska-CondBoldItalic] - \definefontsynonym [SerifBoldSlantedCond] [AntykwaTorunska-CondBoldItalic] - \definefontsynonym [SerifCapsCond] [AntykwaTorunska-CondCap] - \stoptypescript - - \starttypescript [\s!serif] [antykwa-light,antykwa-torunska-light] [\s!name] - \definefontsynonym [SerifRegular] [Serif] - \definefontsynonym [SerifRegularCaps] [AntykwaTorunska-LightCap] - \definefontsynonym [SerifBoldCaps] [AntykwaTorunska-MediumCap] - \definefontsynonym [SerifItalicCaps] [AntykwaTorunska-LightItalicCap] - \definefontsynonym [SerifSlantedCaps] [AntykwaTorunska-LightItalicCap] - \definefontsynonym [SerifBoldItalicCaps] [AntykwaTorunska-MedItalicCap] - \definefontsynonym [SerifBoldSlantedCaps] [AntykwaTorunska-MedItalicCap] - \definefontsynonym [SerifCapsCaps] [AntykwaTorunska-LightCap] - - \definefontsynonym [SerifRegularDark] [AntykwaTorunska-Regular] - \definefontsynonym [SerifBoldDark] [AntykwaTorunska-Bold] - \definefontsynonym [SerifItalicDark] [AntykwaTorunska-Italic] - \definefontsynonym [SerifSlantedDark] [AntykwaTorunska-Italic] - \definefontsynonym [SerifBoldItalicDark] [AntykwaTorunska-BoldItalic] - \definefontsynonym [SerifBoldSlantedDark] [AntykwaTorunska-BoldItalic] - \definefontsynonym [SerifCapsDark] [AntykwaTorunska-Cap] - - \definefontsynonym [SerifRegularCond] [AntykwaTorunska-CondLight] - \definefontsynonym [SerifBoldCond] [AntykwaTorunska-CondMedium] - \definefontsynonym [SerifItalicCond] [AntykwaTorunska-CondLightItalic] - \definefontsynonym [SerifSlantedCond] [AntykwaTorunska-CondLightItalic] - \definefontsynonym [SerifBoldItalicCond] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [SerifBoldSlantedCond] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [SerifCapsCond] [AntykwaTorunska-CondLightCap] - \stoptypescript - - \starttypescript [\s!serif] [antykwa-cond,antykwa-torunska-cond] [\s!name] - \definefontsynonym [SerifRegular] [Serif] - \definefontsynonym [SerifRegularCaps] [AntykwaTorunska-CondCap] - \definefontsynonym [SerifBoldCaps] [AntykwaTorunska-CondBoldCap] - \definefontsynonym [SerifItalicCaps] [AntykwaTorunska-CondItalicCap] - \definefontsynonym [SerifSlantedCaps] [AntykwaTorunska-CondItalicCap] - \definefontsynonym [SerifBoldItalicCaps] [AntykwaTorunska-CondBoldItalicCap] - \definefontsynonym [SerifBoldSlantedCaps] [AntykwaTorunska-CondBoldItalicCap] - \definefontsynonym [SerifCapsCaps] [AntykwaTorunska-CondCap] - - \definefontsynonym [SerifRegularLight] [AntykwaTorunska-CondLight] - \definefontsynonym [SerifBoldLight] [AntykwaTorunska-CondMedium] - \definefontsynonym [SerifItalicLight] [AntykwaTorunska-CondLightItalic] - \definefontsynonym [SerifSlantedLight] [AntykwaTorunska-CondLightItalic] - \definefontsynonym [SerifBoldItalicLight] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [SerifBoldSlantedLight] [AntykwaTorunska-CondMedItalic] - \definefontsynonym [SerifCapsLight] [AntykwaTorunska-CondLightCap] - - \definefontsynonym [SerifRegularExp] [AntykwaTorunska-Regular] - \definefontsynonym [SerifBoldExp] [AntykwaTorunska-Bold] - \definefontsynonym [SerifItalicExp] [AntykwaTorunska-Italic] - \definefontsynonym [SerifSlantedExp] [AntykwaTorunska-Italic] - \definefontsynonym [SerifBoldItalicExp] [AntykwaTorunska-BoldItalic] - \definefontsynonym [SerifBoldSlantedExp] [AntykwaTorunska-BoldItalic] - \definefontsynonym [SerifCapsExp] [AntykwaTorunska-Cap] - \stoptypescript - - \starttypescript [\s!serif] [antykwa-lightcond,antykwa-torunska-lightcond] [\s!name] - \definefontsynonym [SerifRegular] [Serif] - \definefontsynonym [SerifRegularCaps] [AntykwaTorunska-CondLightCap] - \definefontsynonym [SerifBoldCaps] [AntykwaTorunska-CondMediumCap] - \definefontsynonym [SerifItalicCaps] [AntykwaTorunska-CondLightItalicCap] - \definefontsynonym [SerifSlantedCaps] [AntykwaTorunska-CondLightItalicCap] - \definefontsynonym [SerifBoldItalicCaps] [AntykwaTorunska-CondMedItalicCap] - \definefontsynonym [SerifBoldSlantedCaps] [AntykwaTorunska-CondMedItalicCap] - \definefontsynonym [SerifCapsCaps] [AntykwaTorunska-CondLightCap] - - \definefontsynonym [SerifRegularDark] [AntykwaTorunska-CondRegular] - \definefontsynonym [SerifBoldDark] [AntykwaTorunska-CondBold] - \definefontsynonym [SerifItalicDark] [AntykwaTorunska-CondItalic] - \definefontsynonym [SerifSlantedDark] [AntykwaTorunska-CondItalic] - \definefontsynonym [SerifBoldItalicDark] [AntykwaTorunska-CondBoldItalic] - \definefontsynonym [SerifBoldSlantedDark] [AntykwaTorunska-CondBoldItalic] - \definefontsynonym [SerifCapsDark] [AntykwaTorunska-CondCap] - - \definefontsynonym [SerifRegularExp] [AntykwaTorunska-Light] - \definefontsynonym [SerifBoldExp] [AntykwaTorunska-Medium] - \definefontsynonym [SerifItalicExp] [AntykwaTorunska-LightItalic] - \definefontsynonym [SerifSlantedExp] [AntykwaTorunska-LightItalic] - \definefontsynonym [SerifBoldItalicExp] [AntykwaTorunska-MedItalic] - \definefontsynonym [SerifBoldSlantedExp] [AntykwaTorunska-MedItalic] - \definefontsynonym [SerifCapsExp] [AntykwaTorunska-LightCap] + \definefontsynonym [\s!SerifBoldItalic] [AntykwaTorunska-CondMediumItalic] + \definefontsynonym [\s!SerifBoldSlanted] [AntykwaTorunska-CondMediumItalic] \stoptypescript \stoptypescriptcollection diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 9618051bd..aaf99ed45 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 2023-02-07 19:02 +-- merge date : 2023-02-14 17:41 do -- begin closure to overcome local limits and interference |