From 0477f879e2b574ad568732ad03784e5df1952fb7 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Fri, 4 Dec 2020 21:16:33 +0100 Subject: 2020-12-04 20:21:00 --- .../documents/general/manuals/luametatex.pdf | Bin 1294540 -> 1307633 bytes .../manuals/luametatex/luametatex-differences.tex | 72 ++- .../manuals/luametatex/luametatex-enhancements.tex | 62 +- .../general/manuals/luametatex/luametatex-lua.tex | 28 +- .../luametatex/luametatex-modifications.tex | 63 ++- .../manuals/luametatex/luametatex-preamble.tex | 15 +- .../general/manuals/luametatex/luametatex-tex.tex | 24 - .../general/manuals/luametatex/luametatex.tex | 3 + tex/context/base/mkii/cont-new.mkii | 2 +- tex/context/base/mkii/context.mkii | 2 +- tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/context.mkiv | 2 +- tex/context/base/mkiv/status-files.pdf | Bin 26093 -> 26096 bytes tex/context/base/mkiv/status-lua.pdf | Bin 255687 -> 255677 bytes tex/context/base/mkiv/typo-spa.lua | 246 -------- tex/context/base/mkxl/back-out.lmt | 4 +- tex/context/base/mkxl/back-trf.lmt | 8 +- tex/context/base/mkxl/cont-log.mkxl | 2 +- tex/context/base/mkxl/cont-new.mkxl | 2 +- tex/context/base/mkxl/context.mkxl | 2 +- tex/context/base/mkxl/grph-inc.mkxl | 6 - tex/context/base/mkxl/lpdf-lmt.lmt | 7 +- tex/context/base/mkxl/lpdf-tag.lmt | 3 + tex/context/base/mkxl/meta-ini.mkxl | 2 +- tex/context/base/mkxl/node-nut.lmt | 1 + tex/context/base/mkxl/page-bck.mkxl | 4 +- tex/context/base/mkxl/syst-ini.mkxl | 9 +- tex/context/base/mkxl/tabl-tbl.mkxl | 8 +- tex/context/base/mkxl/typo-brk.lmt | 498 ++++++++++++++++ tex/context/base/mkxl/typo-brk.mkxl | 2 +- tex/context/base/mkxl/typo-cap.lmt | 272 +++++---- tex/context/base/mkxl/typo-cap.mkxl | 3 +- tex/context/base/mkxl/typo-dig.lmt | 181 ++++++ tex/context/base/mkxl/typo-dig.mkxl | 2 +- tex/context/base/mkxl/typo-krn.lmt | 630 +++++++++++++++++++++ tex/context/base/mkxl/typo-krn.mkxl | 2 +- tex/context/base/mkxl/typo-pag.lmt | 206 +++++++ tex/context/base/mkxl/typo-pag.mkxl | 2 +- tex/context/base/mkxl/typo-spa.lmt | 255 +++++++++ tex/context/base/mkxl/typo-spa.mkxl | 2 +- tex/context/modules/mkiv/s-magazine-basic.mkiv | 7 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 2 +- 42 files changed, 2111 insertions(+), 532 deletions(-) delete mode 100644 tex/context/base/mkiv/typo-spa.lua create mode 100644 tex/context/base/mkxl/typo-brk.lmt create mode 100644 tex/context/base/mkxl/typo-dig.lmt create mode 100644 tex/context/base/mkxl/typo-krn.lmt create mode 100644 tex/context/base/mkxl/typo-pag.lmt create mode 100644 tex/context/base/mkxl/typo-spa.lmt diff --git a/doc/context/documents/general/manuals/luametatex.pdf b/doc/context/documents/general/manuals/luametatex.pdf index 8c82fe6ee..946f6db26 100644 Binary files a/doc/context/documents/general/manuals/luametatex.pdf and b/doc/context/documents/general/manuals/luametatex.pdf differ diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-differences.tex b/doc/context/sources/general/manuals/luametatex/luametatex-differences.tex index 5b8f7558a..67556a99a 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-differences.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-differences.tex @@ -1,4 +1,4 @@ - % language=uk +% language=uk \environment luametatex-style @@ -10,7 +10,7 @@ As \LUAMETATEX\ is a leaner and meaner \LUATEX, this chapter will discuss what is gone. We start with the primitives that were dropped. \starttabulate[|l|pl|] -\NC fonts \NC \type {\letterspacefont} +\BC fonts \NC \type {\letterspacefont} \type {\copyfont} \type {\expandglyphsinfont} \type {\ignoreligaturesinfont} @@ -18,7 +18,7 @@ what is gone. We start with the primitives that were dropped. \type {\leftghost} \type {\rightghost} \NC \NR -\NC backend \NC \type {\dviextension} +\BC backend \NC \type {\dviextension} \type {\dvivariable } \type {\dvifeedback} \type {\pdfextension} @@ -28,14 +28,14 @@ what is gone. We start with the primitives that were dropped. \type {\draftmode} \type {\outputmode} \NC \NR -\NC dimensions \NC \type {\pageleftoffset} +\BC dimensions \NC \type {\pageleftoffset} \type {\pagerightoffset} \type {\pagetopoffset} \type {\pagebottomoffset} \type {\pageheight} \type {\pagewidth} \NC \NR -\NC resources \NC \type {\saveboxresource} +\BC resources \NC \type {\saveboxresource} \type {\useboxresource} \type {\lastsavedboxresourceindex} \type {\saveimageresource} @@ -43,11 +43,11 @@ what is gone. We start with the primitives that were dropped. \type {\lastsavedimageresourceindex} \type {\lastsavedimageresourcepages} \NC \NR -\NC positioning \NC \type {\savepos} +\BC positioning \NC \type {\savepos} \type {\lastxpos} \type {\lastypos} \NC \NR -\NC directions \NC \type {\textdir} +\BC directions \NC \type {\textdir} \type {\linedir} \type {\mathdir} \type {\pardir} @@ -56,14 +56,14 @@ what is gone. We start with the primitives that were dropped. \type {\pagedirection} \type {\bodydirection} \NC \NR -\NC randomizer \NC \type {\randomseed} +\BC randomizer \NC \type {\randomseed} \type {\setrandomseed} \type {\normaldeviate} \type {\uniformdeviate} \NC \NR -\NC utilities \NC \type {\synctex} +\BC utilities \NC \type {\synctex} \NC \NR -\NC extensions \NC \type {\latelua} +\BC extensions \NC \type {\latelua} \type {\lateluafunction} \type {\openout} \type {\write} @@ -74,7 +74,7 @@ what is gone. We start with the primitives that were dropped. \type {\closein} \type {\ifeof} \NC \NR -\NC control \NC \type {\suppressfontnotfounderror} +\BC control \NC \type {\suppressfontnotfounderror} \type {\suppresslongerror} \type {\suppressprimitiveerror} \type {\suppressmathparerror} @@ -82,10 +82,10 @@ what is gone. We start with the primitives that were dropped. \type {\suppressoutererror} \type {\mathoption} \NC \NR -\NC whatever \NC \type {\primitive} +\BC whatever \NC \type {\primitive} \type {\ifprimitive} \NC \NR -\NC ignored \NC \type {\long} +\BC ignored \NC \type {\long} \type {\outer} \type {\mag} \NC \NR @@ -100,38 +100,41 @@ and they don't work well in \LUATEX\ anyway. We only have two directions left. The primitive related extensions were not that useful and reliable so they have been removed. There are some new variants that will be discussed later. The \type {\outer} and \type {\long} prefixes are gone as they don't make much sense -nowadays and them becoming dummies opened the way to something new, again to be -discussed elsewhere. I don't think that (\CONTEXT) users will notice it. The -\type {\suppress..} features are now default and can't be changed so related -primitives are gone. +nowadays and them becoming dummies opened the way to something new: control +sequence properties that permit protection against as well as controlled +overloading of definitions. I don't think that (\CONTEXT) users will notice these +prefixed being gone. The definition and parsing related \type {\suppress..} +features are now default and can't be changed so related primitives are gone. The \type {\shipout} primitive does no ship out but just erases the content of -the box, if that hasn't happened already in another way. - -The extension primitives relate to the backend (when not immediate) and can be -implemented as part of a backend design using generic whatsits. There is only one -type of whatsit now. In fact we're now closer to original \TEX\ with respect to -the extensions. +the box, if that hasn't happened already in another way. A macropackage should +implement its own backend and related shipout. Talking of backend, the extension +primitives that relate to backends can be implemented as part of a backend design +using generic whatsits. There is only one type of whatsit now. In fact we're now +closer to original \TEX\ with respect to the extensions. The \type {img} library has been removed as it's rather bound to the backend. The \type {slunicode} library is also gone. There are some helpers in the string library that can be used instead and one can write additional \LUA\ code if -needed. There is no longer a \type {pdf} backend library. +needed. There is no longer a \type {pdf} backend library but we have an up to +date \PDF\ parsing library on board. In the \type {node}, \type {tex} and \type {status} library we no longer have helpers and variables that relate to the backend. The \LUAMETATEX\ engine is in -principle \DVI\ and \PDF\ unaware. There are only generic whatsit nodes that can -be used for some management related tasks. For instance you can use them to -implement user nodes. More extensive status information is provided in the -overhauled status library. +principle \DVI\ and \PDF\ unaware. There are, as mentioned, only generic whatsit +nodes that can be used for some management related tasks. For instance you can +use them to implement user nodes. More extensive status information is provided +in the overhauled status library. The margin kern nodes are gone and we now use regular kern nodes for them. As a consequence there are two extra subtypes indicating the injected left or right kern. The glyph field served no real purpose so there was no reason for a special kind of node. -The \KPSE\ library is no longer built|-|in. Because there is no backend, quite -some file related callbacks could go away. The following file related callbacks +The \KPSE\ library is no longer built|-|in, but one can use an external \KPSE\ +library, assuming that it is present on the system, because the engine has a so +called optional library interface to it. Because there is no backend, quite some +file related callbacks could go away. The following file related callbacks remained (till now): \starttyping @@ -152,6 +155,13 @@ gets reallocated. trace_memory \stoptyping +When you use the overload protect mechanisms, a callback can be plugged in to handle +exceptions: + +\starttyping +handle_overload +\stoptyping + The (job) management hooks are kept: \starttyping @@ -187,7 +197,7 @@ ago in \TEX\ engines by command line options. Talking of options, only a few are left. All input goes via \LUA, even the console. We took our time for reaching a stable state in \LUATEX. Among the reasons is the -fact that most was experimented with in \CONTEXT. It took many man|-|years to +fact that most was experimented with in \CONTEXT. It took many years of work to decide what to keep and how to do things. Of course there are places when things can be improved and it might happen in \LUAMETATEX. Contrary to what is sometimes suggested, the \LUATEX|-|\CONTEXT\ \MKIV\ combination (assuming matched versions) diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex b/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex index f4dbfb15d..057fddde4 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex @@ -19,7 +19,7 @@ and there will be no \type {luametatex} variants. This is because we consider \LUAMETATEX\ to be \LUATEX 2\high{+}. Contrary to the \LUATEX\ engine \LUAMETATEX\ enables all its primitives. You can -clone (a selection of) primitives with a different prefix, like: +clone (a selection of) primitives with a different prefix, like this: \starttyping \directlua { tex.enableprimitives('normal',tex.extraprimitives()) } @@ -27,8 +27,11 @@ clone (a selection of) primitives with a different prefix, like: The \type {extraprimitives} function returns the whole list or a subset, specified by one or more keywords \type {core}, \type {tex}, \type {etex} or -\type {luatex}. \footnote {At some point this function might be changed to return -the whole list always}. +\type {luatex}. When you clone all primitives you can also do this: + +\starttyping +\directlua { tex.enableprimitives('normal',true) } +\stoptyping But be aware that the curly braces may not have the proper \prm {catcode} assigned to them at this early time (giving a \quote {Missing number} error), so @@ -42,23 +45,8 @@ it may be needed to put these assignments before the above line: More fine|-|grained primitives control is possible and you can look up the details in \in {section} [luaprimitives]. There are only three kinds of primitives: \type {tex}, \type {etex} and \type {luatex} but a future version -might drop this and no longer make that distinction as it no longer serves -a purpose. - -\stopsubsection - -\startsubsection[title={Experiments}] - -There are a few extensions to the engine regarding the macro machinery. Some are -already well tested but others are (still) experimental. Although they are likely -to stay, their exact behaviour might evolve. Because \LUAMETATEX\ is also used -for experiments, this is not a problem. We can always decide to also add some of -what is discussed here to \LUATEX, but it will happen with a delay. - -There are all kinds of small improvements that might find their way into stock -\LUATEX: a few more helpers, some cleanup of code, etc. We'll see. In any case, -if you play with these before they are declared stable, unexpected side effects -are what you have to accept. +might drop this and no longer make that distinction as it no longer serves a +purpose apart from the fact that it reveals some history. \stopsubsection @@ -231,6 +219,34 @@ Fonts are loaded via \LUA\ and a minimal amount of information is kept at the about what a character (or glyph) number represents (a \UNICODE\ or index) as it only is interested in dimensions. +In \TEX\ the number of registers is 256 and \ETEX\ bumped that to 32K. One reason +for a fixed number is that these registers are fast ways to store data and +therefore are part of the main lookup table (used for data and pointers to data +as well as save and restore housekeeping). In \LUATEX\ the number was bumped to +64K but one can argue that less would also do. In order to keep the default +memory footprint reasonable, in \LUAMETATEX\ the number of languages, fonts and +marks is limited. The size of some tables can be limited by configuration +settings, so they can start out small and grow till configured maximum which is +smaller than the absolute maximum. The following table shows all kind of defaults +as reported by \typ {status.getconstants()}. + +\startluacode + context.starttabulate { "|T|r|" } + for k, v in table.sortedhash(status.getconstants()) do + context.NC() context(k) context.NC() context(v) context.NC() context.NR() + end + context.stoptabulate() +\stopluacode + +Because we have additional ways to store integers, dimensions and glue, we might +actually decide to decrease the maximum of the registers: if 64K is not enough, +and you work around it, then likely 32K might do as well. Also, we have \LUA\ to +store massive amounts of data. One can argue that saving some 1.5MB memory (when +we go halfway) is not worth the effort in a time when you have to close a browser +in order to free the gigabytes it consumes, but there is no reason not to be lean +and mean: a more conservative approach to start with creates headroom for going +wild later. + \stopsubsection \stopsection @@ -276,6 +292,12 @@ language related information, the expansion factor, etc. Now that we have access to these nodes from \LUA\ it makes sense to be able to carry more information with a node and this is where attributes kick in. +It is important to keep in mind that there are situations where nodes get created +in the current context. For instance, when \TEX\ builds a paragraph or page or +constructs math formulas, it does add nodes and giving these the current +attributes makes no sense and can even give weird side effects. In these cases, +the attributes are inherited from neighbouring nodes. + \stopsubsection \startsubsection[title={Attribute registers}] diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-lua.tex b/doc/context/sources/general/manuals/luametatex/luametatex-lua.tex index 803820de1..ed4b269b6 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-lua.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-lua.tex @@ -70,6 +70,20 @@ There are less options than with \LUATEX, because one has to deal with them in \LUA\ anyway. There are no options to enter a safer mode or control executing programs. This can easily be achieved with a startup \LUA\ script. +Next the initialization script is loaded and executed. From within the script, +the entire command line is available in the \LUA\ table \type {arg}, beginning +with \type {arg[0]}, containing the name of the executable. As consequence +warnings about unrecognized options are suppressed. + +Command line processing happens very early on. So early, in fact, that none of +\TEX's initializations have taken place yet. The \LUA\ libraries that don't deal +with \TEX\ are initialized early. + +\LUAMETATEX\ allows some of the command line options to be overridden by reading +values from the \type {texconfig} table at the end of script execution (see the +description of the \type {texconfig} table later on in this document for more +details on which ones exactly). + The value to use for \prm {jobname} is decided as follows: \startitemize @@ -92,20 +106,6 @@ The value to use for \prm {jobname} is decided as follows: \stopitem \stopitemize -Next the initialization script is loaded and executed. From within the script, -the entire command line is available in the \LUA\ table \type {arg}, beginning -with \type {arg[0]}, containing the name of the executable. As consequence -warnings about unrecognized options are suppressed. - -Command line processing happens very early on. So early, in fact, that none of -\TEX's initializations have taken place yet. The \LUA\ libraries that don't deal -with \TEX\ are initialized early. - -\LUAMETATEX\ allows some of the command line options to be overridden by reading -values from the \type {texconfig} table at the end of script execution (see the -description of the \type {texconfig} table later on in this document for more -details on which ones exactly). - So let's summarize this. The handling of what is called jobname is a bit complex. There can be explicit names set on the command line but when not set they can be taken from the \type {texconfig} table. diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-modifications.tex b/doc/context/sources/general/manuals/luametatex/luametatex-modifications.tex index ff401a1ba..cc9fd3b8d 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-modifications.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-modifications.tex @@ -39,9 +39,18 @@ not|-|so|-|expected changes. These are sometimes a side|-|effect of a new (conflicting) feature, or, more often than not, a change necessary to clean up the internal interfaces. These will also be mentioned. +Again we stress that {\em this is not a \TEX\ manual, nor a tutorial}. If you are +unfamiliar with \TEX\ first play a little with a macro package, take a look at +the \TEX\ book, make yourself familiar with the concepts and macro language. That +will likely take days and not hours. Also, many of the new concepts introduced in +\LUATEX\ and \LUAMETATEX\ are explained in documents that come with the \CONTEXT\ +distribution, articles and presentations. It doesn't pay of to repeat that here, +especially not in a time when users often search instead of read from cover to +cover. + \stopsubsection -\startsubsection[title=Changes from \TEX\ 3.1415926] +\startsubsection[title=Changes from \TEX\ 3.1415926...] \topicindex {\TEX} @@ -58,12 +67,14 @@ most still comes from original Knuthian \TEX. But we divert a bit. {languages}, \type {fonts}, \type {libraries}, etc. There are some artifacts of the conversion to \CCODE, but these got (and get) removed stepwise. The documentation, which actually comes from the mix of engines (via so called - change files), is kept as much as possible. Of course we want to stay as - close as possible to the original so that the documentation of the + change files), is a mix of what authors of the engines wove into the source, + and most is of course from Don Knuths original. In \LUAMETATEX\ we try to + stay as close as possible to the original so that the documentation of the fundamentals behind \TEX\ by Don Knuth still applies. However, because we use \CCODE, some documentation is a bit off. Also, most global variables are now collected in structures, but the original names and level of abstraction were - mostly kept. On the other hand, opening up had its impact on the code. + mostly kept. On the other hand, opening up had its impact on the code, so + that makes some documentation a bit off too. Adapting that all will take time. \stopitem \startitem @@ -88,7 +99,8 @@ most still comes from original Knuthian \TEX. But we divert a bit. stack, input levels, the hash table and table of equivalents, etc. now all start out small and are enlarged when needed, where maxima are controlled in the usual way. In principle the initial memory footprint is smaller while at - the same time we can go real large. + the same time we can go real large. Because we have wide memory words some + data (arrays) used for housekeeping could be reorganized a bit. \stopitem \startitem @@ -138,14 +150,6 @@ most still comes from original Knuthian \TEX. But we divert a bit. supporting \OPENTYPE\ math. \stopitem -\startitem - When detailed logging is enabled more detail is output with respect to what - nodes are involved. This is a side effect of the core nodes having more - detailed subtype information. The benefit of more detail wins from any wish - to be byte compatible in the logging. One can always write additional logging - in \LUA. -\stopitem - \stopitemize \stopsubsection @@ -445,6 +449,11 @@ more details anyway. \startsubsection[title=Logging] +When detailed logging is enabled more detail is output with respect to what nodes +are involved. This is a side effect of the core nodes having more detailed +subtype information. The benefit of more detail wins from any wish to be byte +compatible in the logging. One can always write additional logging in \LUA. + The information that goes into the log file can be different from \LUATEX, and might even differ a bit more in the future. The main reason is that inside the engine we have more granularity, which for instance means that we output subtype @@ -465,6 +474,34 @@ that over time system dependencies have been handles with \TEX\ change files, th \stopsubsection +\startsubsection[title=Parsing] + +Token parsers have been upgraded for the sake of \LUA, \type {\csname} handling +has been extended, macro definitions can be more flexible so there code was +adapted, more conditionals also brought some changes. But we build upon the +(reorganized) \TEX\ foundation so the basics can definitely be recognized. + +Because of interfacing in \LUA\ the internal token and node organization has +been normalized (read: we cannot cheat because all is kind of visible). On +the one hand this can come with a performance penalty but that is more than +compensated by extensions, optimized parsers and such. Still the fact that we +are \UTF\ based (32 bit) makes the machinery slower than the 8~bit original. +The reworked \LUAMETATEX\ engine is substantially faster than the \LUATEX\ +predecessor. + +The handling of conditionals has been adapted so that we can have flatter +branches (\type {\orelse} cum suis). This again has some consequences for +parsing. Because parsing alignments is rather interwoven in general parsing and +expansion the handling of related primitives has been slightly adapted (also for +the sake of \LUA\ interfacing) and dealing with \type {\noalign} situations is a +bit more convenient. + +This are just a few of the adaptations and most of this happened stepwise with +testing in the \CONTEXT\ code base. It will be clear that \LUAMETATEX\ is a quite +different extension to the original. You're warned. + +\stopsubsection + \stopsection \stopchapter diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-preamble.tex b/doc/context/sources/general/manuals/luametatex/luametatex-preamble.tex index 1897d0f3e..5a2dae818 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-preamble.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-preamble.tex @@ -81,6 +81,17 @@ see: [par] <=> [hlist] <=> H <=> [kern] <=> i <=> [glue] <=> Th <=> e <=> r <=> e ... \stoptyping +Actually, the above representation is one view, because in \LUAMETATEX\ we can +choose for this: + +\starttyping +[par] <=> [glue] <=> H <=> [kern] <=> i <=> [glue] <=> Th <=> e <=> r <=> e ... +\stoptyping + +where glue (currently fixed) is used instead of an empty hlist (think of a \type +{\hbox}). Options like this are available because want a certain view on these +lists from the \LUA\ end and the result being predicable is part of that. + It's also good to know beforehand that \TEX\ is basically centered around creating paragraphs and pages. The par builder takes a list and breaks it into lines. At some point horizontal blobs are wrapped into vertical ones. Lines are @@ -99,7 +110,9 @@ kick in much \LUA\ code, you will notices that performance drops. Don't blame an bother the authors with performance issues. In \CONTEXT\ over 50\% of the time can be spent in \LUA, but so far we didn't get many complaints about efficiency. Adding more callbacks makes no sense, also because at some point the performance -hit gets too large. There are plenty ways to achieve one goals. +hit gets too large. There are plenty ways to achieve one goals. For that reason: +take remarks about \LUATEX, features, potential, performance etc.\ with a natural +grain of salt. Where plain \TEX\ is basically a basic framework for writing a specific style, macro packages like \CONTEXT\ and \LATEX\ provide the user a whole lot of diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-tex.tex b/doc/context/sources/general/manuals/luametatex/luametatex-tex.tex index 48266aa2e..0ef178526 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-tex.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-tex.tex @@ -102,30 +102,6 @@ mind when preloading files into a bytecode register in \INITEX. \stopsubsection -\startsubsection[title={Chunk name registers}] - -\libindex{name} -\libindex{setluaname} -\libindex{getluaname} - -There is an array of 65536 (0--65535) potential chunk names for use with the -\prm {directlua} and \lpr {latelua} primitives. - -\startfunctioncall -lua.name[ n] = s - s = lua.name[ n] -\stopfunctioncall - -If you want to unset a \LUA\ name, you can assign \type {nil} to it. The function -accessors are: - -\startfunctioncall -lua.setluaname( s, n) - s = lua.getluaname( n) -\stopfunctioncall - -\stopsubsection - \startsubsection[title={Introspection}] \libindex{getstacktop} diff --git a/doc/context/sources/general/manuals/luametatex/luametatex.tex b/doc/context/sources/general/manuals/luametatex/luametatex.tex index a7ece66d8..c75e8ec86 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex.tex @@ -38,6 +38,9 @@ % 20200610 : 258 pages % mingw all in: 10.6 +% 20201204 : 266 pages +% mingw all in: 10.3 + % 20200720 : 258 pages / all in % % mingw : 10.6 (sometimes less) diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index ec7703565..5039c26aa 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{2020.12.03 18:56} +\newcontextversion{2020.12.04 20:19} %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 8ffceb405..8b103d931 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{2020.12.03 18:56} +\edef\contextversion{2020.12.04 20:19} %D For those who want to use this: diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 9483292ec..e77e90e59 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{2020.12.03 18:56} +\newcontextversion{2020.12.04 20:19} %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 0ae1b5027..fd88f9914 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -45,7 +45,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2020.12.03 18:56} +\edef\contextversion{2020.12.04 20:19} %D Kind of special: diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index b6aed6495..22286e42d 100644 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index 29161ec70..844a0c16e 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ diff --git a/tex/context/base/mkiv/typo-spa.lua b/tex/context/base/mkiv/typo-spa.lua deleted file mode 100644 index 78fc22964..000000000 --- a/tex/context/base/mkiv/typo-spa.lua +++ /dev/null @@ -1,246 +0,0 @@ -if not modules then modules = { } end modules ['typo-spa'] = { - version = 1.001, - comment = "companion to typo-spa.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local next, type = next, type - -local trace_spacing = false trackers.register("typesetters.spacing", function(v) trace_spacing = v end) - -local report_spacing = logs.reporter("typesetting","spacing") - -local nodes, fonts, node = nodes, fonts, node - -local fonthashes = fonts.hashes -local quaddata = fonthashes.quads - -local texsetattribute = tex.setattribute -local unsetvalue = attributes.unsetvalue - -local v_reset = interfaces.variables.reset - -local nuts = nodes.nuts - -local getnext = nuts.getnext -local getprev = nuts.getprev -local takeattr = nuts.takeattr -local isglyph = nuts.isglyph - -local insert_node_before = nuts.insert_before -local insert_node_after = nuts.insert_after -local remove_node = nuts.remove -local end_of_math = nuts.end_of_math - -local nodepool = nuts.pool -local new_penalty = nodepool.penalty -local new_glue = nodepool.glue - -local nodecodes = nodes.nodecodes -local math_code = nodecodes.math - -local somespace = nodes.somespace -local somepenalty = nodes.somepenalty - -local enableaction = nodes.tasks.enableaction - -typesetters = typesetters or { } -local typesetters = typesetters - -typesetters.spacings = typesetters.spacings or { } -local spacings = typesetters.spacings - -spacings.mapping = spacings.mapping or { } -spacings.numbers = spacings.numbers or { } - -local a_spacings = attributes.private("spacing") - -storage.register("typesetters/spacings/mapping", spacings.mapping, "typesetters.spacings.mapping") - -local mapping = spacings.mapping -local numbers = spacings.numbers - -for i=1,#mapping do - local m = mapping[i] - numbers[m.name] = m -end - --- todo cache lastattr - -function spacings.handler(head) - local start = head - -- head is always begin of par (whatsit), so we have at least two prev nodes - -- penalty followed by glue - while start do - local char, id = isglyph(start) - if char then - local attr = takeattr(start,a_spacings) - if attr and attr > 0 then - local data = mapping[attr] - if data then - local map = data.characters[char] - if map then - local font = id - local left = map.left - local right = map.right - local alternative = map.alternative - local quad = quaddata[font] - local prev = getprev(start) - if left and left ~= 0 and prev then - local ok = false - local prevprev = getprev(prev) - if alternative == 1 then - local somespace = somespace(prev,true) - if somespace then - local somepenalty = somepenalty(prevprev,10000) - if somepenalty then - if trace_spacing then - report_spacing("removing penalty and space before %C (left)",char) - end - head = remove_node(head,prev,true) - head = remove_node(head,prevprev,true) - else - if trace_spacing then - report_spacing("removing space before %C (left)",char) - end - head = remove_node(head,prev,true) - end - end - ok = true - else - ok = not (somespace(prev,true) and somepenalty(prevprev,true)) or somespace(prev,true) - end - if ok then - if trace_spacing then - report_spacing("inserting penalty and space before %C (left)",char) - end - insert_node_before(head,start,new_penalty(10000)) - insert_node_before(head,start,new_glue(left*quad)) - end - end - local next = getnext(start) - if right and right ~= 0 and next then - local ok = false - local nextnext = getnext(next) - if alternative == 1 then - local somepenalty = somepenalty(next,10000) - if somepenalty then - local somespace = somespace(nextnext,true) - if somespace then - if trace_spacing then - report_spacing("removing penalty and space after %C right",char) - end - head = remove_node(head,next,true) - head = remove_node(head,nextnext,true) - end - else - local somespace = somespace(next,true) - if somespace then - if trace_spacing then - report_spacing("removing space after %C (right)", char) - end - head = remove_node(head,next,true) - end - end - ok = true - else - ok = not (somepenalty(next,10000) and somespace(nextnext,true)) or somespace(next,true) - end - if ok then - if trace_spacing then - report_spacing("inserting penalty and space after %C (right)",char) - end - insert_node_after(head,start,new_glue(right*quad)) - insert_node_after(head,start,new_penalty(10000)) - end - end - end - end - end - elseif id == math_code then - start = end_of_math(start) -- weird, can return nil .. no math end? - end - if start then - start = getnext(start) - end - end - return head -end - -local enabled = false - -function spacings.define(name) - local data = numbers[name] - if data then - -- error - else - local number = #mapping + 1 - local data = { - name = name, - number = number, - characters = { }, - } - mapping[number] = data - numbers[name] = data - end -end - -function spacings.setup(name,char,settings) - local data = numbers[name] - if not data then - -- error - else - data.characters[char] = settings - end -end - -function spacings.set(name) - local n = unsetvalue - if name ~= v_reset then - local data = numbers[name] - if data then - if not enabled then - enableaction("processors","typesetters.spacings.handler") - enabled = true - end - n = data.number or unsetvalue - end - end - texsetattribute(a_spacings,n) -end - -function spacings.reset() - texsetattribute(a_spacings,unsetvalue) -end - --- interface - -local implement = interfaces.implement - -implement { - name = "definecharacterspacing", - actions = spacings.define, - arguments = "string" -} - -implement { - name = "setupcharacterspacing", - actions = spacings.setup, - arguments = { - "string", - "integer", - { - { "left", "number" }, - { "right", "number" }, - { "alternative", "integer" }, - } - } -} - -implement { - name = "setcharacterspacing", - actions = spacings.set, - arguments = "string" -} diff --git a/tex/context/base/mkxl/back-out.lmt b/tex/context/base/mkxl/back-out.lmt index 43fc04d78..fbcb220dc 100644 --- a/tex/context/base/mkxl/back-out.lmt +++ b/tex/context/base/mkxl/back-out.lmt @@ -228,6 +228,8 @@ function nodepool.literal(mode,str) return t end +--- these 3 will move to node-res as they are generic + function nodepool.save() return copynode(savenode) end @@ -238,7 +240,7 @@ end function nodepool.setmatrix(rx,sx,sy,ry,tx,ty) local t = copynode(setmatrixnode) - nodeproperties[t] = { rx, sx, sy, ry, tx, ty } + nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } } return t end diff --git a/tex/context/base/mkxl/back-trf.lmt b/tex/context/base/mkxl/back-trf.lmt index 1586bc440..e3ec0bda3 100644 --- a/tex/context/base/mkxl/back-trf.lmt +++ b/tex/context/base/mkxl/back-trf.lmt @@ -32,10 +32,10 @@ local stack = { } local restore = true -- false updaters.register("backend.update",function() - savenode = nodepool.save - restorenode = nodepool.restore - setmatrixnode = nodepool.setmatrix - literalnode = nodepool.literal -- has to become some nodeinjection + savenode = nodepool.save -- not needed + restorenode = nodepool.restore -- not needed + setmatrixnode = nodepool.setmatrix -- not needed + literalnode = nodepool.literal -- has to become some nodeinjection end) local function stopsomething() diff --git a/tex/context/base/mkxl/cont-log.mkxl b/tex/context/base/mkxl/cont-log.mkxl index 12d0d06de..1bb48f0b2 100644 --- a/tex/context/base/mkxl/cont-log.mkxl +++ b/tex/context/base/mkxl/cont-log.mkxl @@ -194,7 +194,7 @@ \frozen\instance\protected\def\Lua {Lua} \frozen\instance\protected\def\luajitTeX {lua\wordboundary jit\wordboundary\TeX} \frozen\instance\protected\def\luametaTeX{lua\wordboundary meta\wordboundary\TeX} -%frozen\instance\protected\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX} +\frozen\instance\protected\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX} % Adapted from a patch by Mojca: diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl index 12ac9bafd..f56aaae6a 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{2020.12.03 18:56} +\newcontextversion{2020.12.04 20:19} %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 1320962e7..40fca9fd9 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{2020.12.03 18:56} +\immutable\edef\contextversion{2020.12.04 20:19} %overloadmode 1 % check frozen / warning %overloadmode 2 % check frozen / error diff --git a/tex/context/base/mkxl/grph-inc.mkxl b/tex/context/base/mkxl/grph-inc.mkxl index 024db290e..4a6626617 100644 --- a/tex/context/base/mkxl/grph-inc.mkxl +++ b/tex/context/base/mkxl/grph-inc.mkxl @@ -178,12 +178,6 @@ \installcorenamespace{externalfiguredefinition} -% \protected\def\defineexternalfigure -% {\dodoubleargument\grph_include_define} -% -% \def\grph_include_define[#1][#2]% -% {\setvalue{\??externalfiguredefinition#1}{\setupcurrentexternalfigure[#2]}} - \aliased\let\defineexternalfigures\defineexternalfigure % label file parent settings diff --git a/tex/context/base/mkxl/lpdf-lmt.lmt b/tex/context/base/mkxl/lpdf-lmt.lmt index 1cbe033a3..cbad20f09 100644 --- a/tex/context/base/mkxl/lpdf-lmt.lmt +++ b/tex/context/base/mkxl/lpdf-lmt.lmt @@ -812,12 +812,9 @@ local flushsave, flushrestore, flushsetmatrix do flushsetmatrix = function(current,pos_h,pos_v) local p = nodeproperties[current] if p then - local m = matrix + local m = p.matrix if m then - local rx = m.rx - local sx = m.sx - local sy = m.sy - local ry = m.ry + local rx, sx, sy, ry = unpack(m) if not rx then rx = 1 elseif rx == 0 then diff --git a/tex/context/base/mkxl/lpdf-tag.lmt b/tex/context/base/mkxl/lpdf-tag.lmt index 5cc2f5012..4ea92d951 100644 --- a/tex/context/base/mkxl/lpdf-tag.lmt +++ b/tex/context/base/mkxl/lpdf-tag.lmt @@ -425,6 +425,9 @@ end collectranges(head) +-- inspect(taglist) +-- inspect(ranges) + if trace_tags then for i=1,#ranges do local range = ranges[i] diff --git a/tex/context/base/mkxl/meta-ini.mkxl b/tex/context/base/mkxl/meta-ini.mkxl index 4bf9134f9..fbbf95fc8 100644 --- a/tex/context/base/mkxl/meta-ini.mkxl +++ b/tex/context/base/mkxl/meta-ini.mkxl @@ -739,7 +739,7 @@ \meta_enable_include % redundant \global\advance\c_meta_object_counter\plusone \meta_use_box{\number\c_meta_object_counter}\hpack{\meta_process_graphic{#3}}% was vbox, graphic must end up as hbox - \gdefcsname\??mpgraphic#1\endcsname{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}% + \xdefcsname\??mpgraphic#1\endcsname{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}% \csname\??mpgraphic#1\endcsname\empty \endgroup} diff --git a/tex/context/base/mkxl/node-nut.lmt b/tex/context/base/mkxl/node-nut.lmt index 6b9dd803e..38ac5b0aa 100644 --- a/tex/context/base/mkxl/node-nut.lmt +++ b/tex/context/base/mkxl/node-nut.lmt @@ -217,6 +217,7 @@ local nuts = { unprotect_glyph = direct.unprotect_glyph, unprotect_glyphs = direct.unprotect_glyphs, unset_attribute = direct.unset_attribute, + unset_attributes = direct.unset_attributes, usedlist = direct.usedlist, uses_font = direct.uses_font, vpack = direct.vpack, diff --git a/tex/context/base/mkxl/page-bck.mkxl b/tex/context/base/mkxl/page-bck.mkxl index 71036e3e4..5bdeb53fa 100644 --- a/tex/context/base/mkxl/page-bck.mkxl +++ b/tex/context/base/mkxl/page-bck.mkxl @@ -518,7 +518,7 @@ \processcommacommand[#1]\page_backgrounds_setup_step \the\everybackgroundssetup} -\protected\def\page_backgrounds_setup_single[#1][#2][#3]% +\protected\def\page_backgrounds_setup_single[#1][#2][#-]% {\global\settrue\c_page_backgrounds_some \doifelsecommon{#1}\v_page_backgrounds_single_set {\def\page_backgrounds_setup_step##1{\page_backgrounds_setup_and_check{##1}{#2}}% @@ -526,7 +526,7 @@ \the\everybackgroundssetup}% {\page_backgrounds_setup_double[#1][\v_page_backgrounds_common_set][#2]}} -\protected\def\page_backgrounds_setup_basics[#1][#2][#3]% +\protected\def\page_backgrounds_setup_basics[#1][#-][#-]% {\setupframed[\??layoutbackgrounds][#1]% \the\everybackgroundssetup} diff --git a/tex/context/base/mkxl/syst-ini.mkxl b/tex/context/base/mkxl/syst-ini.mkxl index 5e9d55559..57cd20759 100644 --- a/tex/context/base/mkxl/syst-ini.mkxl +++ b/tex/context/base/mkxl/syst-ini.mkxl @@ -138,14 +138,9 @@ %D available; it cannot limit itself to being \TEX\ or \ETEX. It could not do that %D anyway because there are differences (no backend, to mention one). -%D Temp hack ... build bot down: - -%D We create (for now) aliases: - \directlua { - local primitives = tex.extraprimitives() % "tex","etex","luatex" - tex.enableprimitives("normal",primitives) % could default to everything - function tex.enableprimitives() end % so we kind of protect what's there + tex.enableprimitives("normal",true) % we default to everything + function tex.enableprimitives() end % so we kind of protect what's there } \immutable\def\space{ } diff --git a/tex/context/base/mkxl/tabl-tbl.mkxl b/tex/context/base/mkxl/tabl-tbl.mkxl index d46eebe6a..a4e6e6fed 100644 --- a/tex/context/base/mkxl/tabl-tbl.mkxl +++ b/tex/context/base/mkxl/tabl-tbl.mkxl @@ -712,7 +712,7 @@ % \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth % \fi % \tabl_tabulate_set_preamble} -% + \def\tabl_tabulate_set_raggedright {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedright \fi} \def\tabl_tabulate_set_raggedcenter{\ifnum\c_tabl_tabulate_type=\plusone \else\raggedcenter\fi} \def\tabl_tabulate_set_raggedleft {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedleft \fi} @@ -1071,7 +1071,8 @@ \def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header {\ifcsname\??tabulatehead\currenttabulation\endcsname %\expandafter\ifempty\csname\??tabulatehead\currenttabulation\endcsname - \expandafter\ifempty\lastnamedcs + %\expandafter\ifempty\lastnamedcs + \ifempty\lastnamedcs \let\tabl_tabulate_insert_head\empty \else \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content @@ -1080,8 +1081,9 @@ \let\tabl_tabulate_insert_head\empty \fi \ifcsname\??tabulatefoot\currenttabulation\endcsname - \expandafter\ifempty\csname\??tabulatefoot\currenttabulation\endcsname + %\expandafter\ifempty\csname\??tabulatefoot\currenttabulation\endcsname %\expandafter\ifempty\lastnamedcs + \ifempty\lastnamedcs \let\tabl_tabulate_insert_foot\empty \else \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content diff --git a/tex/context/base/mkxl/typo-brk.lmt b/tex/context/base/mkxl/typo-brk.lmt new file mode 100644 index 000000000..8d2fcd147 --- /dev/null +++ b/tex/context/base/mkxl/typo-brk.lmt @@ -0,0 +1,498 @@ +if not modules then modules = { } end modules ['typo-brk'] = { + version = 1.001, + comment = "companion to typo-brk.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- this code dates from the beginning and is kind of experimental; it +-- will be optimized and improved soon + +local next, type, tonumber, tostring = next, type, tonumber, tostring +local utfbyte, utfchar = utf.byte, utf.char +local format = string.format + +local trace_breakpoints = false trackers.register("typesetters.breakpoints", function(v) trace_breakpoints = v end) + +local report_breakpoints = logs.reporter("typesetting","breakpoints") + +local nodes, node = nodes, node + +local settings_to_array = utilities.parsers.settings_to_array + +local nuts = nodes.nuts +local tonut = nuts.tonut + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getboth = nuts.getboth +local getsubtype = nuts.getsubtype +local getfont = nuts.getfont +local getid = nuts.getid +local getattrlist = nuts.getattrlist +local getattr = nuts.getattr +local getlanguage = nuts.getlanguage +local isglyph = nuts.isglyph + +local setattr = nuts.setattr +local setattrlist = nuts.setattrlist +local setlink = nuts.setlink +local setchar = nuts.setchar +local setdisc = nuts.setdisc +local setnext = nuts.setnext +local setprev = nuts.setprev +local setboth = nuts.setboth +local setsubtype = nuts.setsubtype + +local copy_node = nuts.copy_node +local copy_node_list = nuts.copy_list +local flush_node = nuts.flush_node +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local remove_node = nuts.remove +local end_of_math = nuts.end_of_math +local find_attribute = nuts.find_attribute +local unset_attributes = nuts.unset_attributes + +local tonodes = nuts.tonodes + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local nodepool = nuts.pool +local enableaction = nodes.tasks.enableaction + +local v_reset = interfaces.variables.reset +local v_yes = interfaces.variables.yes + +local implement = interfaces.implement + +local new_penalty = nodepool.penalty +local new_glue = nodepool.glue +local new_disc = nodepool.disc +local new_wordboundary = nodepool.wordboundary + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes + +local kern_code = nodecodes.kern +local math_code = nodecodes.math + +local fontkern_code = kerncodes.fontkern +local italickern_code = kerncodes.italiccorrection + +local is_letter = characters.is_letter + +local typesetters = typesetters + +typesetters.breakpoints = typesetters.breakpoints or {} +local breakpoints = typesetters.breakpoints + +breakpoints.mapping = breakpoints.mapping or { } +breakpoints.numbers = breakpoints.numbers or { } + +breakpoints.methods = breakpoints.methods or { } +local methods = breakpoints.methods + +local a_breakpoints = attributes.private("breakpoint") + +storage.register("typesetters/breakpoints/mapping", breakpoints.mapping, "typesetters.breakpoints.mapping") + +local mapping = breakpoints.mapping +local numbers = breakpoints.mapping + +for i=1,#mapping do + local m = mapping[i] + numbers[m.name] = m +end + +-- this needs a cleanup ... maybe make all of them disc nodes + +-- todo: use boundaries + +local function insert_break(head,start,stop,before,after,kern) + if not kern then + local p = new_penalty(before) + local g = new_glue() + setattrlist(p,start) + setattrlist(g,start) + insert_node_before(head,start,p) + insert_node_before(head,start,g) + end + local p = new_penalty(after) + local g = new_glue() + setattrlist(p,start) + setattrlist(g,start) + insert_node_after(head,stop,g) + insert_node_after(head,stop,p) +end + +methods[1] = function(head,start,stop,settings,kern) + local p, n = getboth(stop) + if p and n then + insert_break(head,start,stop,10000,0,kern) + end + return head, stop +end + +methods[6] = function(head,start,stop,settings,kern) + local p = getprev(start) + local n = getnext(stop) + if p and n then + if kern then + insert_break(head,start,stop,10000,0,kern) + else + local l = new_wordboundary() + local d = new_disc() + local r = new_wordboundary() + setattrlist(d,start) -- otherwise basemode is forced and we crash + setlink(p,l,d,r,n) + if start == stop then + setboth(start) + setdisc(d,start,nil,copy_node(start)) + else + setprev(start) + setnext(stop) + setdisc(d,start,nil,copy_node_list(start)) + end + stop = r + end + end + return head, stop +end + +methods[2] = function(head,start) -- ( => (- + local p, n = getboth(start) + if p and n then + local replace + head, start, replace = remove_node(head,start) + local post = copy_node(replace) + local hyphen = copy_node(post) + setchar(hyphen,languages.prehyphenchar(getlanguage(post))) + setlink(post,hyphen) + head, start = insert_node_before(head,start,new_disc(nil,post,replace)) + setattrlist(start,replace) + insert_break(head,start,start,10000,10000) + end + return head, start +end + +methods[3] = function(head,start) -- ) => -) + local p, n = getboth(start) + if p and n then + local replace + head, start, replace = remove_node(head,start) + local pre = copy_node(replace) + local hyphen = copy_node(pre) + setchar(hyphen,languages.prehyphenchar(getlanguage(pre))) + setlink(hyphen,pre) + head, start = insert_node_before(head,start,new_disc(hyphen,nil,replace)) -- so not pre ! + setattrlist(start,tmp) + insert_break(head,start,start,10000,10000) + end + return head, start +end + +methods[4] = function(head,start) -- - => - - - + local p, n = getboth(start) + if p and n then + local tmp + head, start, tmp = remove_node(head,start) + head, start = insert_node_before(head,start,new_disc()) + setattrlist(start,tmp) + setdisc(start,copy_node(tmp),copy_node(tmp),tmp) + insert_break(head,start,start,10000,10000) + end + return head, start +end + +methods[5] = function(head,start,stop,settings) -- x => p q r + local p, n = getboth(start) + if p and n then + local tmp + head, start, tmp = remove_node(head,start) + head, start = insert_node_before(head,start,new_disc()) + local attr = getattrlist(tmp) + local font = getfont(tmp) + local left = settings.left + local right = settings.right + local middle = settings.middle + if left then + left = tonodes(tostring(left),font,attr) + end + if right then + right = tonodes(tostring(right),font,attr) + end + if middle then + middle = tonodes(tostring(middle),font,attr) + end + setdisc(start,left,right,middle) + setattrlist(start,attr) + flush_node(tmp) + insert_break(head,start,start,10000,10000) + end + return head, start +end + +-- we know we have a limited set +-- what if characters are replaced by the font handler +-- do we need to go into disc nodes (or do it as first step but then we need a pre/post font handler) + +function breakpoints.handler(head) + local _, current = find_attribute(head, a_breakpoints) + if current then + local done = false + local attr = nil + local map = nil + local current = head + while current do + local char, id = isglyph(current) + if char then + local a = getattr(current,a_breakpoints) + if a and a > 0 then + if a ~= attr then + local data = mapping[a] + if data then + map = data.characters + else + map = nil + end + attr = a + end + if map then + local cmap = map[char] + if cmap then + -- for now we collect but when found ok we can move the handler here + -- although it saves nothing in terms of performance + local lang = getlanguage(current) + local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[languages.numbers[lang]] or cmap[""]) + if smap then + local skip = smap.skip + local start = current + local stop = current + current = getnext(current) + if skip then + while current do + local c = isglyph(current) + if c == char then + stop = current + current = getnext(current) + else + break + end + end + end + local d = { start, stop, cmap, smap, char } + if done then + done[#done+1] = d + else + done = { d } + end + else + current = getnext(current) + end + else + current = getnext(current) + end + else + current = getnext(current) + end + else + current = getnext(current) + end + elseif id == math_code then + attr = nil + current = end_of_math(current) + if current then + current = getnext(current) + end + else + current = getnext(current) + end + end + if not done then + return head + end + -- we have hits + -- local numbers = languages.numbers + for i=1,#done do + local data = done[i] + local start = data[1] + local stop = data[2] + local cmap = data[3] + local smap = data[4] + -- we do a sanity check for language + -- local lang = getlanguage(start) + -- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) + -- if smap then + local nleft = smap.nleft + local cleft = 0 + local prev = getprev(start) + local kern = nil + while prev and nleft ~= cleft do + local char, id = isglyph(prev) + if char then + if not is_letter[char] then + cleft = -1 + break + end + cleft = cleft + 1 + prev = getprev(prev) + elseif id == kern_code then + local s = getsubtype(prev) + if s == fontkern_code or s == italickern_code then + if cleft == 0 then + kern = prev + prev = getprev(prev) + else + break + end + else + break + end + else + break + end + end + if nleft == cleft then + local nright = smap.nright + local cright = 0 + local next = getnext(stop) -- getnext(start) + while next and nright ~= cright do + local char, id = isglyph(next) + if char then + if not is_letter[char] then + cright = -1 + break + end + if cright == 1 and cmap[char] then + -- let's not make it too messy + break + end + cright = cright + 1 + next = getnext(next) + elseif id == kern_code then + local s = getsubtype(next) + if s == fontkern_code or s == italickern_code then + if cleft == 0 then + next = getnext(next) + else + break + end + else + break + end + else + break + end + end + if nright == cright then + local method = methods[smap.type] + if method then + head, start = method(head,start,stop,smap,kern) + end + end + -- end + end + end + if done then +-- unset_attributes(a_breakpoints, head) + end + end + return head +end + +local enabled = false + +function breakpoints.define(name) + local data = numbers[name] + if data then + -- error + else + local number = #mapping + 1 + local data = { + name = name, + number = number, + characters = { }, + } + mapping[number] = data + numbers[name] = data + end +end + +function breakpoints.setreplacement(name,char,language,settings) + char = utfbyte(char) + local data = numbers[name] + if data then + local characters = data.characters + local cmap = characters[char] + if not cmap then + cmap = { } + characters[char] = cmap + end + local left, right, middle = settings.left, settings.right, settings.middle + cmap[language or ""] = { + type = tonumber(settings.type) or 1, + nleft = tonumber(settings.nleft) or 1, + nright = tonumber(settings.nright) or 1, + left = left ~= "" and left or nil, + right = right ~= "" and right or nil, + middle = middle ~= "" and middle or nil, + skip = settings.range == v_yes, + } -- was { type or 1, before or 1, after or 1 } + end +end + +function breakpoints.set(n) + if n == v_reset then + n = unsetvalue + else + n = mapping[n] + if not n then + n = unsetvalue + else + if not enabled then + if trace_breakpoints then + report_breakpoints("enabling breakpoints handler") + end + enableaction("processors","typesetters.breakpoints.handler") + end + n = n.number + end + end + texsetattribute(a_breakpoints,n) +end + +-- interface + +implement { + name = "definebreakpoints", + actions = breakpoints.define, + arguments = "string" +} + +implement { + name = "definebreakpoint", + actions = breakpoints.setreplacement, + arguments = { + "string", + "string", + "string", + { + { "type", "integer" }, + { "nleft", "integer" }, + { "nright", "integer" }, + { "right" }, + { "left" }, + { "middle" }, + { "range" }, + } + } +} + +implement { + name = "setbreakpoints", + actions = breakpoints.set, + arguments = "string" +} diff --git a/tex/context/base/mkxl/typo-brk.mkxl b/tex/context/base/mkxl/typo-brk.mkxl index 51abc1034..47e5da886 100644 --- a/tex/context/base/mkxl/typo-brk.mkxl +++ b/tex/context/base/mkxl/typo-brk.mkxl @@ -21,7 +21,7 @@ % % -- we might eventually stick to only method 5 -\registerctxluafile{typo-brk}{} +\registerctxluafile{typo-brk}{autosuffix} \definesystemattribute[breakpoint][public,global] diff --git a/tex/context/base/mkxl/typo-cap.lmt b/tex/context/base/mkxl/typo-cap.lmt index c5c91243e..fe7406e76 100644 --- a/tex/context/base/mkxl/typo-cap.lmt +++ b/tex/context/base/mkxl/typo-cap.lmt @@ -19,83 +19,85 @@ local report_casing = logs.reporter("typesetting","casing") local nodes, node = nodes, node -local nuts = nodes.nuts +local nuts = nodes.nuts -local getnext = nuts.getnext -local getid = nuts.getid -local takeattr = nuts.takeattr -local getfont = nuts.getfont -local getsubtype = nuts.getsubtype -local getchar = nuts.getchar -local isglyph = nuts.isglyph -local getdisc = nuts.getdisc +local getnext = nuts.getnext +local getid = nuts.getid +local getattr = nuts.getattr +local getfont = nuts.getfont +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar +local isglyph = nuts.isglyph +local getdisc = nuts.getdisc -local setchar = nuts.setchar -local setfont = nuts.setfont +local setchar = nuts.setchar +local setfont = nuts.setfont -local copy_node = nuts.copy -local end_of_math = nuts.end_of_math -local insert_after = nuts.insert_after -local find_attribute = nuts.find_attribute +local copy_node = nuts.copy +local end_of_math = nuts.end_of_math +local insert_after = nuts.insert_after +local find_attribute = nuts.find_attribute +local unset_attributes = nuts.unset_attributes -local nextglyph = nuts.traversers.glyph +local nextglyph = nuts.traversers.glyph -local nodecodes = nodes.nodecodes -local kerncodes = nodes.kerncodes +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes -local glyph_code = nodecodes.glyph -local kern_code = nodecodes.kern -local disc_code = nodecodes.disc -local math_code = nodecodes.math +local glyph_code = nodecodes.glyph +local kern_code = nodecodes.kern +local disc_code = nodecodes.disc +local math_code = nodecodes.math -local fontkern_code = kerncodes.fontkern +local fontkern_code = kerncodes.fontkern -local enableaction = nodes.tasks.enableaction +local enableaction = nodes.tasks.enableaction -local newkern = nuts.pool.kern +local newkern = nuts.pool.kern -local fonthashes = fonts.hashes -local fontdata = fonthashes.identifiers -local fontchar = fonthashes.characters +local fonthashes = fonts.hashes +local fontdata = fonthashes.identifiers +local fontchar = fonthashes.characters -local currentfont = font.current +local currentfont = font.current -local variables = interfaces.variables -local v_reset = variables.reset +local variables = interfaces.variables +local v_reset = variables.reset -local texsetattribute = tex.setattribute -local unsetvalue = attributes.unsetvalue +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue -typesetters = typesetters or { } -local typesetters = typesetters +typesetters = typesetters or { } +local typesetters = typesetters -typesetters.cases = typesetters.cases or { } -local cases = typesetters.cases +typesetters.cases = typesetters.cases or { } +local cases = typesetters.cases -cases.actions = { } -local actions = cases.actions -local a_cases = attributes.private("case") +cases.actions = { } +local actions = cases.actions +local a_cases = attributes.private("case") -local extract = bit32.extract -local run = 0 -- a trick to make neighbouring ranges work -local blocked = { } +local run = 0 -- a trick to make neighbouring ranges work +local blocked = { } local function set(tag,font) - if run == 0x40 then -- 2^6 - run = 1 - else + if run < 0x7F then run = run + 1 + else + run = 1 end - local a = font * 0x10000 + tag * 0x100 + run + local a = (font << 16) + + (tag << 8) + + (run << 0) blocked[a] = false return a end local function get(a) return - extract(a, 8, 8), -- tag - extract(a,16,12), -- font - extract(a, 0, 8) -- run + (a >> 8) & 0x00FF, -- tag + (a >> 16) & 0xFFFF, -- font + (a >> 0) & 0x00FF -- run end -- a previous implementation used char(0) as placeholder for the larger font, so we needed @@ -279,106 +281,103 @@ register(variables.camel, camel) -- 10 register(variables.cap, variables.capital) -- clone register(variables.Cap, variables.Capital) -- clone --- This can be more clever: when we unset we can actually use the same attr ref if --- needed. Using properties to block further usage is not faster. - -function cases.handler(head) -- not real fast but also not used on much data - local start = head - local lastfont = { } - local lastattr = nil - local count = 0 - local previd = nil - local prev = nil - while start do -- while because start can jump ahead - local id = getid(start) - if id == glyph_code then - local attr = takeattr(start,a_cases) - if attr and attr > 0 and not blocked[attr] then - if attr ~= lastattr then - lastattr = attr - count = 1 - else - count = count + 1 - end - local n, id, m = get(attr) - if lastfont[n] == nil then - lastfont[n] = id - end - local action = actions[n] -- map back to low number - if action then - local quit - start, quit = action(start,attr,lastfont,n,count) - if trace_casing then - report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,quit and "-" or "+") +function cases.handler(head) + local _, start = find_attribute(head, a_cases) + if start then + local lastfont = { } + local lastattr = nil + local count = 0 + local done = false + while start do -- while because start can jump ahead + local id = getid(start) + if id == glyph_code then + local attr = getattr(start,a_cases) + if attr and attr > 0 and not blocked[attr] then + if attr ~= lastattr then + lastattr = attr + count = 1 + else + count = count + 1 end - elseif trace_casing then - report_casing("unknown case trigger %a",n) - end - end - elseif id == disc_code then - local attr = takeattr(start,a_cases) - if attr and attr > 0 and not blocked[attr] then - if attr ~= lastattr then - lastattr = attr - count = 0 - end - local n, id, m = get(attr) - if lastfont[n] == nil then - lastfont[n] = id + local n, id, m = get(attr) + if lastfont[n] == nil then + lastfont[n] = id + end + local action = actions[n] -- map back to low number + if action then + local quit + start, quit = action(start,attr,lastfont,n,count) + if trace_casing then + report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,quit and "-" or "+") + end + elseif trace_casing then + report_casing("unknown case trigger %a",n) + end + done = true end - local action = actions[n] -- map back to low number - if action then - local pre, post, replace = getdisc(start) - if replace then - local cnt = count - for g in nextglyph, replace do - cnt = cnt + 1 - takeattr(g,a_cases) - local h, quit = action(start,attr,lastfont,n,cnt,"replace",g) - if quit then - break + elseif id == disc_code then + local attr = getattr(start,a_cases) + if attr and attr > 0 and not blocked[attr] then + if attr ~= lastattr then + lastattr = attr + count = 0 + end + local n, id, m = get(attr) + if lastfont[n] == nil then + lastfont[n] = id + end + local action = actions[n] -- map back to low number + if action then + local pre, post, replace = getdisc(start) + if replace then + local cnt = count + for g in nextglyph, replace do + cnt = cnt + 1 + getattr(g,a_cases) + local h, quit = action(start,attr,lastfont,n,cnt,"replace",g) + if quit then + break + end end end - end - if pre then - local cnt = count - for g in nextglyph, pre do - cnt = cnt + 1 - takeattr(g,a_cases) - local h, quit = action(start,attr,lastfont,n,cnt,"pre",g) - if quit then - break + if pre then + local cnt = count + for g in nextglyph, pre do + cnt = cnt + 1 + getattr(g,a_cases) + local h, quit = action(start,attr,lastfont,n,cnt,"pre",g) + if quit then + break + end end end - end - if post then - local cnt = count - for g in nextglyph, post do - cnt = cnt + 1 - takeattr(g,a_cases) - local h, quit = action(start,attr,lastfont,n,cnt,"post",g) - if quit then - break + if post then + local cnt = count + for g in nextglyph, post do + cnt = cnt + 1 + getattr(g,a_cases) + local h, quit = action(start,attr,lastfont,n,cnt,"post",g) + if quit then + break + end end end end + count = count + 1 + done = true end - count = count + 1 - end - elseif id == math_code then - start = end_of_math(start) - count = 0 - elseif count > 0 then - if prev_id == kern_code and getsubtype(prev) == fontkern_code then - -- still inside a word ...normally kerns are added later else + if id == math_code then + start = end_of_math(start) + end count = 0 end + if start then + start = getnext(start) + end end - if start then - prev = start - previd = id - start = getnext(start) + if done then + -- unset_attributes(a_cases,head) end end return head @@ -415,6 +414,5 @@ interfaces.implement { -- public = true, -- protected = true, actions = cases.set, --- arguments = { "string" } arguments = { "argument" } } diff --git a/tex/context/base/mkxl/typo-cap.mkxl b/tex/context/base/mkxl/typo-cap.mkxl index 8c0cab502..86f3647dc 100644 --- a/tex/context/base/mkxl/typo-cap.mkxl +++ b/tex/context/base/mkxl/typo-cap.mkxl @@ -18,7 +18,8 @@ %D Maybe we need a more clever system: either command or style mode etc. so %D that we can avoid the grouped mess in a simple style switch. -\registerctxluafile{typo-cap}{autosuffix,optimize} +% \registerctxluafile{typo-cap}{autosuffix,optimize} +\registerctxluafile{typo-cap}{autosuffix} % \definesystemattribute[case][public] % already predefined diff --git a/tex/context/base/mkxl/typo-dig.lmt b/tex/context/base/mkxl/typo-dig.lmt new file mode 100644 index 000000000..7f6663db9 --- /dev/null +++ b/tex/context/base/mkxl/typo-dig.lmt @@ -0,0 +1,181 @@ +if not modules then modules = { } end modules ['typo-dig'] = { + version = 1.001, + optimize = true, + comment = "companion to typo-dig.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- we might consider doing this after the otf pass because now osf do not work +-- out well in node mode. + +local next, type, tonumber = next, type, tonumber +local format, insert = string.format, table.insert +local round, div = math.round, math.div + +local trace_digits = false trackers.register("typesetters.digits", function(v) trace_digits = v end) + +local report_digits = logs.reporter("typesetting","digits") + +local nodes, node = nodes, node + +local nuts = nodes.nuts + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getwidth = nuts.getwidth +local isglyph = nuts.isglyph +local getattr = nuts.getattr + +local setlink = nuts.setlink +local setnext = nuts.setnext +local setprev = nuts.setprev + +local hpack_node = nuts.hpack +local traverse_id = nuts.traverse_id +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local find_attribute = nuts.find_attribute +local unset_attributes = nuts.unset_attributes + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph + +local nodepool = nuts.pool +local enableaction = nodes.tasks.enableaction + +local new_glue = nodepool.glue + +local fonthashes = fonts.hashes +local chardata = fonthashes.characters + +local v_reset = interfaces.variables.reset + +local charbase = characters.data +local getdigitwidth = fonts.helpers.getdigitwidth + +typesetters = typesetters or { } +local typesetters = typesetters + +typesetters.digits = typesetters.digits or { } +local digits = typesetters.digits + +digits.actions = { } +local actions = digits.actions + +local a_digits = attributes.private("digits") + +-- at some point we can manipulate the glyph node so then i need +-- to rewrite this then + +function nodes.aligned(head,start,stop,width,how) + if how == "flushright" or how == "middle" then + head, start = insert_node_before(head,start,new_glue(0,65536,65536)) + end + if how == "flushleft" or how == "middle" then + head, stop = insert_node_after(head,stop,new_glue(0,65536,65536)) + end + local prv = getprev(start) + local nxt = getnext(stop) + setprev(start) + setnext(stop) + local packed = hpack_node(start,width,"exactly") -- no directional mess here, just lr + if prv then + setlink(prv,packed) + end + if nxt then + setlink(packed,nxt) + end + if getprev(packed) then + return head, packed + else + return packed, packed + end +end + +actions[1] = function(head,start,attr) + local char, font = isglyph(start) + local unic = chardata[font][char].unicode or char + if charbase[unic].category == "nd" then -- ignore unic tables + local oldwidth = getwidth(start) + local newwidth = getdigitwidth(font) + if newwidth ~= oldwidth then + if trace_digits then + report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s", + attr%100,div(attr,100),char,unic,newwidth-oldwidth) + end + head, start = nodes.aligned(head,start,start,newwidth,"middle") + return head, start + end + end + return head, start +end + +function digits.handler(head) + local _, start = find_attribute(head, a_digits) + if start then + local current = head + while current do + if getid(current) == glyph_code then + local attr = getattr(current,a_digits) + if attr and attr > 0 then + local action = actions[attr%100] -- map back to low number + if action then + head, current = action(head,current,attr) + elseif trace_digits then + report_digits("unknown digit trigger %a",attr) + end + done = true + end + end + if current then + current = getnext(current) + end + end + if done then + unset_attributes(a_digits, head) + end + end + return head +end + +local m, enabled = 0, false -- a trick to make neighbouring ranges work + +function digits.set(n) -- number or 'reset' + if n == v_reset then + n = unsetvalue + else + n = tonumber(n) + if n then + if not enabled then + enableaction("processors","typesetters.digits.handler") + if trace_digits then + report_digits("enabling digit handler") + end + enabled = true + end + if m == 100 then + m = 1 + else + m = m + 1 + end + n = m * 100 + n + else + n = unsetvalue + end + end + texsetattribute(a_digits,n) +end + +-- interface + +interfaces.implement { + name = "setdigitsmanipulation", + actions = digits.set, + arguments = "string" +} diff --git a/tex/context/base/mkxl/typo-dig.mkxl b/tex/context/base/mkxl/typo-dig.mkxl index 822fa0d34..308ccb66e 100644 --- a/tex/context/base/mkxl/typo-dig.mkxl +++ b/tex/context/base/mkxl/typo-dig.mkxl @@ -15,7 +15,7 @@ \unprotect -\registerctxluafile{typo-dig}{} +\registerctxluafile{typo-dig}{autosuffix} \definesystemattribute[digits][public] diff --git a/tex/context/base/mkxl/typo-krn.lmt b/tex/context/base/mkxl/typo-krn.lmt new file mode 100644 index 000000000..a8ccedccf --- /dev/null +++ b/tex/context/base/mkxl/typo-krn.lmt @@ -0,0 +1,630 @@ +if not modules then modules = { } end modules ['typo-krn'] = { + version = 1.001, + comment = "companion to typo-krn.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- glue is still somewhat suboptimal +-- components: better split on tounicode +-- +-- maybe ignore when properties[n].injections.cursivex (or mark) + +local next, type, tonumber = next, type, tonumber + +local nodes = nodes +local fonts = fonts + +local enableaction = nodes.tasks.enableaction + +local nuts = nodes.nuts +local nodepool = nuts.pool + +-- check what is used + +local find_node_tail = nuts.tail +local flush_node = nuts.flush_node +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local end_of_math = nuts.end_of_math +local copy_node = nuts.copy +local find_attribute = nuts.find_attribute +local unset_attributes = nuts.unset_attributes + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getfont = nuts.getfont +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar +local getdisc = nuts.getdisc +local getglue = nuts.getglue +local getkern = nuts.getkern +local getglyphdata = nuts.getglyphdata + +local isglyph = nuts.isglyph + +local setfield = nuts.setfield +local getattr = nuts.getattr +local setattr = nuts.setattr +local setlink = nuts.setlink +local setdisc = nuts.setdisc +local setglue = nuts.setglue +local setkern = nuts.setkern +local setchar = nuts.setchar +local setglue = nuts.setglue -- todo + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local new_kern = nodepool.kern +local new_glue = nodepool.glue + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes +local gluecodes = nodes.gluecodes +local disccodes = nodes.disccodes +local listcodes = nodes.listcodes + +local glyph_code = nodecodes.glyph +local kern_code = nodecodes.kern +local disc_code = nodecodes.disc +local glue_code = nodecodes.glue +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local math_code = nodecodes.math + +local boxlist_code = listcodes.box +local unknownlist_code = listcodes.unknown + +local discretionarydisc_code = disccodes.discretionary +local automaticdisc_code = disccodes.automatic + +local fontkern_code = kerncodes.fontkern +local userkern_code = kerncodes.userkern + +local userskip_code = gluecodes.userskip +local spaceskip_code = gluecodes.spaceskip +local xspaceskip_code = gluecodes.xspaceskip + +local fonthashes = fonts.hashes +local chardata = fonthashes.characters +local quaddata = fonthashes.quads +local markdata = fonthashes.marks +local fontproperties = fonthashes.properties +local fontdescriptions = fonthashes.descriptions +local fontfeatures = fonthashes.features + +local tracers = nodes.tracers +local setcolor = tracers.colors.set +local resetcolor = tracers.colors.reset + +local v_max = interfaces.variables.max +local v_auto = interfaces.variables.auto + +typesetters = typesetters or { } +local typesetters = typesetters + +local kerns = typesetters.kerns or { } +typesetters.kerns = kerns + +local report = logs.reporter("kerns") +local trace_ligatures = false trackers.register("typesetters.kerns.ligatures", function(v) trace_ligatures = v end) +local trace_ligatures_d = false trackers.register("typesetters.kerns.ligatures.details", function(v) trace_ligatures_d = v end) + +kerns.mapping = kerns.mapping or { } +kerns.factors = kerns.factors or { } +local a_kerns = attributes.private("kern") + +local contextsetups = fonts.specifiers.contextsetups + +storage.register("typesetters/kerns/mapping", kerns.mapping, "typesetters.kerns.mapping") +storage.register("typesetters/kerns/factors", kerns.factors, "typesetters.kerns.factors") + +local mapping = kerns.mapping +local factors = kerns.factors + +-- one must use liga=no and mode=base and kern=yes +-- use more helpers +-- make sure it runs after all others +-- there will be a width adaptor field in nodes so this will change +-- todo: interchar kerns / disc nodes / can be made faster +-- todo: use insert_before etc + +local gluefactor = 4 -- assumes quad = .5 enspace + +-- red : kept by dynamic feature +-- green : kept by static feature +-- blue : keep by goodie + +function kerns.keepligature(n) -- might become default + local f = getfont(n) + local a = getglyphdata(n) or 0 + if trace_ligatures then + local c = getchar(n) + local d = fontdescriptions[f][c].name + if a > 0 and contextsetups[a].keepligatures == v_auto then + if trace_ligatures_d then + report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","dynamic","keepligatures") + end + setcolor(n,"darkred") + return true + end + local k = fontfeatures[f].keepligatures + if k == v_auto then + if trace_ligatures_d then + report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","static","keepligatures") + end + setcolor(n,"darkgreen") + return true + end + if not k then + if trace_ligatures_d then + report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"split","static","keepligatures") + end + resetcolor(n) + return false + end + local k = fontproperties[f].keptligatures + if not k then + report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","no") + resetcolor(n) + return false + end + if k and k[c] then + report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"kept","by") + setcolor(n,"darkblue") + return true + else + report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","by") + resetcolor(n) + return false + end + else + if a > 0 and contextsetups[a].keepligatures == v_auto then + return true + end + local k = fontfeatures[f].keepligatures + if k == v_auto then + return true + end + if not k then + return false + end + local k = fontproperties[f].keptligatures + if not k then + return false + end + if k and k[c] then + return true + end + end +end + +-- can be optimized .. the prev thing .. but hardly worth the effort + +local function kern_injector(fillup,kern) + if fillup then + local g = new_glue(kern) + setfield(g,"stretch",kern) + setfield(g,"stretch_order",1) + return g + else + return new_kern(kern) + end +end + +-- a simple list injector, no components and such .. just disable ligatures in +-- kern mode .. maybe not even hyphenate ... anyway, the next one is for simple +-- sublists .. beware: we can have char -1 + +local function inject_begin(boundary,prev,keeptogether,krn,ok) -- prev is a glyph + local char, id = isglyph(boundary) + if id == kern_code then + if getsubtype(boundary) == fontkern_code then + local inject = true + if keeptogether then + local next = getnext(boundary) + if not next or (getid(next) == glyph_code and keeptogether(prev,next)) then + inject = false + end + end + if inject then + -- not yet ok, as injected kerns can be overlays (from node-inj.lua) + setkern(boundary,getkern(boundary) + quaddata[getfont(prev)]*krn,userkern_code) + return boundary, true + end + end + elseif char then + if keeptogether and keeptogether(boundary,prev) then + -- keep 'm + else + local prevchar = isglyph(prev) + if prevchar and prevchar > 0 then + local font = getfont(boundary) + local data = chardata[font][prevchar] + local kerns = data and data.kerns + local kern = new_kern((kerns and kerns[char] or 0) + quaddata[font]*krn) + setlink(kern,boundary) + return kern, true + end + end + end + return boundary, ok +end + +local function inject_end(boundary,next,keeptogether,krn,ok) + local tail = find_node_tail(boundary) + local char, id = isglyph(tail) + if id == kern_code then + if getsubtype(tail) == fontkern_code then + local inject = true + if keeptogether then + local prev = getprev(tail) + if getid(prev) == glyph_code and keeptogether(prev,two) then + inject = false + end + end + if inject then + -- not yet ok, as injected kerns can be overlays (from node-inj.lua) + setkern(tail,getkern(tail) + quaddata[getfont(next)]*krn,userkern_code) + return boundary, true + end + end + elseif char then + if keeptogether and keeptogether(tail,two) then + -- keep 'm + else + local nextchar = isglyph(tail) + if nextchar and nextchar > 0 then + local font = getfont(tail) + local data = chardata[font][nextchar] + local kerns = data and data.kerns + local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn + setlink(tail,new_kern(kern)) + return boundary, true + end + end + end + return boundary, ok +end + +local function process_list(head,keeptogether,krn,font,okay) + local start = head + local prev = nil + local pid = nil + local kern = 0 + local mark = font and markdata[font] + while start do + local char, id = isglyph(start) + if char then + if not font then + font = id -- getfont(start) + mark = markdata[font] + kern = quaddata[font]*krn + end + if prev then + if mark[char] then + -- skip + elseif pid == kern_code then + if getsubtype(prev) == fontkern_code then + local inject = true + if keeptogether then + local prevprev = getprev(prev) + if getid(prevprev) == glyph_code and keeptogether(prevprev,start) then + inject = false + end + end + if inject then + -- not yet ok, as injected kerns can be overlays (from node-inj.lua) + setkern(prev,getkern(prev) + kern,userkern_code) + okay = true + end + end + elseif pid == glyph_code then + if keeptogether and keeptogether(prev,start) then + -- keep 'm + else + local prevchar = getchar(prev) + local data = chardata[font][prevchar] + local kerns = data and data.kerns + -- if kerns then + -- print("it happens indeed, basemode kerns not yet injected") + -- end + insert_node_before(head,start,new_kern((kerns and kerns[char] or 0) + kern)) + okay = true + end + end + end + end + if start then + prev = start + pid = id + start = getnext(start) + end + end + return head, okay, prev +end + +local function closest_bound(b,get) + b = get(b) + if b and getid(b) ~= glue_code then + while b do + if not getattr(b,a_kerns) then + break + else + local c, f = isglyph(b) + if c then + return b, f + else + b = get(b) + end + end + end + end +end + +function kerns.handler(head) + local _, start = find_attribute(head, a_kerns) + if start then + local lastfont = nil + local keepligature = kerns.keepligature + local keeptogether = kerns.keeptogether + local fillup = false + local bound = false + local prev = nil + local previd = nil + local prevchar = nil + local prevfont = nil + local prevmark = nil + local done = false + while start do + -- fontkerns don't get the attribute but they always sit between glyphs so + -- are always valid bound .. disc nodes also sometimes don't get them + local attr = getattr(start,a_kerns) + if attr and attr > 0 then + local char, id = isglyph(start) + local krn = mapping[attr] + if krn == v_max then + krn = .25 + fillup = true + else + fillup = false + end + if not krn or krn == 0 then + bound = false + elseif char then -- id == glyph_code + local font = id -- more readable + local mark = markdata[font] + if keepligature and keepligature(start) then + -- keep 'm + else + -- beware, these are not kerned so we mighty need a kern only pass + -- maybe some day .. anyway, one should disable ligaturing + local data = chardata[font][char] + if data then + local unicode = data.unicode -- can be cached + if type(unicode) == "table" then + char = unicode[1] + local s = start + setchar(s,char) + for i=2,#unicode do + local n = copy_node(s) + if i == 2 then + setattr(n,a_kerns,attr) -- we took away the attr + end + setchar(n,unicode[i]) + insert_node_after(head,s,n) + s = n + end + end + end + end + if not bound then + -- yet + elseif mark[char] then + -- skip + elseif previd == kern_code then + if getsubtype(prev) == fontkern_code then + local inject = true + if keeptogether then + if previd == glyph_code and keeptogether(prev,start) then + inject = false + end + end + if inject then + -- not yet ok, as injected kerns can be overlays (from node-inj.lua) + setkern(prev,getkern(prev) + quaddata[font]*krn,userkern_code) + end + end + elseif previd == glyph_code then + if prevfont == font then + if keeptogether and keeptogether(prev,start) then + -- keep 'm + else + -- hm, only basemode ... will go away ... + local data = chardata[font][prevchar] + local kerns = data and data.kerns + local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn + insert_node_before(head,start,kern_injector(fillup,kern)) + end + else + insert_node_before(head,start,kern_injector(fillup,quaddata[font]*krn)) + end + end + prev = start + prevchar = char + prevfont = font + prevmark = mark + previd = glyph_code -- id + bound = true + elseif id == disc_code then + local prev, next, pglyph, nglyph -- delayed till needed + local subtype = getsubtype(start) + -- if subtype == automaticdisc_code then + -- -- this is kind of special, as we have already injected the + -- -- previous kern + -- local prev = getprev(start) + -- local pglyph = prev and getid(prev) == glyph_code + -- languages.expand(start,pglyph and prev) + -- -- we can have a different start now + -- elseif subtype ~= discretionarydisc_code then + -- prev = getprev(start) + -- pglyph = prev and getid(prev) == glyph_code + -- languages.expand(start,pglyph and prev) + -- end + local pre, post, replace = getdisc(start) + local indeed = false + if pre then + local okay = false + if not prev then + prev = getprev(start) + pglyph = prev and getid(prev) == glyph_code + end + if pglyph then + pre, okay = inject_begin(pre,prev,keeptogether,krn,okay) + end + pre, okay = process_list(pre,keeptogether,krn,false,okay) + if okay then + indeed = true + end + end + if post then + local okay = false + if not next then + next = getnext(start) + nglyph = next and getid(next) == glyph_code + end + if nglyph then + post, okay = inject_end(post,next,keeptogether,krn,okay) + end + post, okay = process_list(post,keeptogether,krn,false,okay) + if okay then + indeed = true + end + end + if replace then + local okay = false + if not prev then + prev = getprev(start) + pglyph = prev and getid(prev) == glyph_code + end + if pglyph then + replace, okay = inject_begin(replace,prev,keeptogether,krn,okay) + end + if not next then + next = getnext(start) + nglyph = next and getid(next) == glyph_code + end + if nglyph then + replace, okay = inject_end(replace,next,keeptogether,krn,okay) + end + replace, okay = process_list(replace,keeptogether,krn,false,okay) + if okay then + indeed = true + end + elseif prevfont then + replace = new_kern(quaddata[prevfont]*krn) + indeed = true + end + if indeed then + setdisc(start,pre,post,replace) + end + bound = false + elseif id == kern_code then + bound = getsubtype(start) == fontkern_code + prev = start + previd = id + elseif id == glue_code then + local subtype = getsubtype(start) + if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then + local width, stretch, shrink, stretch_order, shrink_order = getglue(start) + if width > 0 then + local w = width + gluefactor * width * krn + stretch = stretch * w / width + shrink = shrink * w / width + if fillup then + stretch = 2 * stretch + shrink = 2 * shrink + stretch_order = 1 + -- shrink_order = 1 ? + end + setglue(start,w,stretch,shrink,stretch_order,shrink_order) + end + end + bound = false + elseif id == hlist_code or id == vlist_code then + local subtype = getsubtype(start) + if subtype == unknownlist_code or subtype == boxlist_code then + -- special case + local b, f = closest_bound(start,getprev) + if b then + insert_node_before(head,start,kern_injector(fillup,quaddata[f]*krn)) + end + local b, f = closest_bound(start,getnext) + if b then + insert_node_after(head,start,kern_injector(fillup,quaddata[f]*krn)) + end + end + bound = false + elseif id == math_code then + start = end_of_math(start) + bound = false + end + if start then + start = getnext(start) + end + done = true + else + local id = getid(start) + if id == kern_code then + bound = getsubtype(start) == fontkern_code + prev = start + previd = id + start = getnext(start) + else + bound = false + start = getnext(start) + end + end + end + if done then + -- unset_attributes(a_kerns, head) + end + end + return head +end + +local enabled = false + +function kerns.set(factor) + if factor ~= v_max then + factor = tonumber(factor) or 0 + end + if factor == v_max or factor ~= 0 then + if not enabled then + enableaction("processors","typesetters.kerns.handler") + enabled = true + end + local a = factors[factor] + if not a then + a = #mapping + 1 + factors[factors], mapping[a] = a, factor + end + factor = a + else + factor = unsetvalue + end + texsetattribute(a_kerns,factor) + return factor +end + +-- interface + +interfaces.implement { + name = "setcharacterkerning", + actions = kerns.set, + arguments = "string" +} + diff --git a/tex/context/base/mkxl/typo-krn.mkxl b/tex/context/base/mkxl/typo-krn.mkxl index b16bdacc4..4c6aea256 100644 --- a/tex/context/base/mkxl/typo-krn.mkxl +++ b/tex/context/base/mkxl/typo-krn.mkxl @@ -15,7 +15,7 @@ \unprotect -\registerctxluafile{typo-krn}{} +\registerctxluafile{typo-krn}{autosuffix} \definesystemattribute[kern][public] diff --git a/tex/context/base/mkxl/typo-pag.lmt b/tex/context/base/mkxl/typo-pag.lmt new file mode 100644 index 000000000..9f8a3a1f4 --- /dev/null +++ b/tex/context/base/mkxl/typo-pag.lmt @@ -0,0 +1,206 @@ +if not modules then modules = { } end modules ['typo-pag'] = { + version = 1.001, + comment = "companion to typo-pag.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + + +builders = builders or { } +local builders = builders + +builders.paragraphs = builders.paragraphs or { } +local parbuilders = builders.paragraphs + +local nodes = nodes +local nodecodes = nodes.nodecodes + +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local glue_code = nodecodes.glue +local kern_code = nodecodes.kern +local penalty_code = nodecodes.penalty + +local unsetvalue = attributes.unsetvalue +local a_keeptogether = attributes.private("keeptogether") + +local nuts = nodes.nuts + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getattr = nuts.getattr +local takeattr = nuts.takeattr +local setattr = nuts.setattr +local getwhd = nuts.getwhd +local getkern = nuts.getkern +local setpenalty = nuts.setpenalty +local getwidth = nuts.getwidth +local getdepth = nuts.getdepth + +local insert_node_after = nuts.insert_after +local new_penalty = nuts.pool.penalty + +local trace_keeptogether = false +local report_keeptogether = logs.reporter("parbuilders","keeptogether") + +local enableaction = nodes.tasks.enableaction + +local cache = { } +local last = 0 +local enabled = false + +trackers.register("parbuilders.keeptogether", function(v) trace_keeptogether = v end) + +-- todo: also support lines = 3 etc (e.g. dropped caps) but how to set that +-- when no hlists are there ? + +function parbuilders.registertogether(line,specification) -- might change + if not specification then + return + end + if not enabled then + enableaction("finalizers","builders.paragraphs.keeptogether") + end + local a = getattr(line,a_keeptogether) + local c = a and cache[a] + if c then + local height = specification.height + local depth = specification.depth + local slack = specification.slack + if height and height > c.height then + c.height = height + end + if depth and depth > c.depth then + c.depth = depth + end + if slack and slack > c.slack then + c.slack = slack + end + else + last = last + 1 + cache[last] = specification + if not specification.height then + specification.height = 0 + end + if not specification.depth then + specification.depth = 0 + end + if not specification.slack then + specification.slack = 0 + end + setattr(line,a_keeptogether,last) + end + if trace_keeptogether then + local a = a or last + local c = cache[a] + local noflines = specification.lineheight + local height = c.height + local depth = c.depth + local slack = c.slack + if not noflines or noflines == 0 then + noflines = "unknown" + else + noflines = math.round((height + depth - slack) / noflines) + end + report_keeptogether("registered, index %s, height %p, depth %p, slack %p, noflines %a",a,height,depth,slack,noflines) + end +end + +local function keeptogether(start,a,specification) + local current = getnext(start) + local previous = start + local total = getdepth(previous) + local slack = specification.slack + local threshold = specification.depth - slack + if trace_keeptogether then + report_keeptogether("%s, index %s, total %p, threshold %p, slack %p","list",a,total,threshold,slack) + end + while current do + local id = getid(current) + if id == vlist_code or id == hlist_code then + local wd, ht, dp = getwhd(current) + total = total + ht + dp + if trace_keeptogether then + report_keeptogether("%s, index %s, total %p, threshold %p","list",a,total,threshold) + end + if total <= threshold then + if getid(previous) == penalty_code then + setpenalty(previous,10000) + else + insert_node_after(head,previous,new_penalty(10000)) + end + else + break + end + elseif id == glue_code then + -- hm, breakpoint, maybe turn this into kern + total = total + getwidth(current) + if trace_keeptogether then + report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold) + end + if total <= threshold then + if getid(previous) == penalty_code then + setpenalty(previous,10000) + else + insert_node_after(head,previous,new_penalty(10000)) + end + else + break + end + elseif id == kern_code then + total = total + getkern(current) + if trace_keeptogether then + report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold) + end + if total <= threshold then + if getid(previous) == penalty_code then + setpenalty(previous,10000) + else + insert_node_after(head,previous,new_penalty(10000)) + end + else + break + end + elseif id == penalty_code then + if total <= threshold then + if getid(previous) == penalty_code then + setpenalty(previous,10000) + end + setpenalty(current,10000) + else + break + end + end + previous = current + current = getnext(current) + end +end + +-- also look at first non glue/kern node e.g for a dropped caps + +-- todo: find_attribute and unset_attributes instead of takeattr + +function parbuilders.keeptogether(head) + local done = false -- can go + local current = head + while current do + if getid(current) == hlist_code then + local a = takeattr(current,a_keeptogether) + if a and a > 0 then + local specification = cache[a] + if specification then + keeptogether(current,a,specification) + -- this is tricky ... we need a better resetter, maybe some + -- injected latelua or a gc method on a property (interesting + -- experiment) + cache[a] = nil + done = true + end + end + end + current = getnext(current) + end + return head, done +end diff --git a/tex/context/base/mkxl/typo-pag.mkxl b/tex/context/base/mkxl/typo-pag.mkxl index 07443eb16..b34ff079b 100644 --- a/tex/context/base/mkxl/typo-pag.mkxl +++ b/tex/context/base/mkxl/typo-pag.mkxl @@ -15,6 +15,6 @@ \unprotect -\registerctxluafile{typo-pag}{} +\registerctxluafile{typo-pag}{autosuffix} \protect \endinput diff --git a/tex/context/base/mkxl/typo-spa.lmt b/tex/context/base/mkxl/typo-spa.lmt new file mode 100644 index 000000000..84dd0696d --- /dev/null +++ b/tex/context/base/mkxl/typo-spa.lmt @@ -0,0 +1,255 @@ +if not modules then modules = { } end modules ['typo-spa'] = { + version = 1.001, + comment = "companion to typo-spa.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type = next, type + +local trace_spacing = false trackers.register("typesetters.spacing", function(v) trace_spacing = v end) + +local report_spacing = logs.reporter("typesetting","spacing") + +local nodes, fonts, node = nodes, fonts, node + +local fonthashes = fonts.hashes +local quaddata = fonthashes.quads + +local texsetattribute = tex.setattribute +local unsetvalue = attributes.unsetvalue + +local v_reset = interfaces.variables.reset + +local nuts = nodes.nuts + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getattr = nuts.getattr +local isglyph = nuts.isglyph + +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local remove_node = nuts.remove +local end_of_math = nuts.end_of_math +local unset_attributes = nuts.unset_attributes +local find_attribute = nuts.find_attribute + +local nodepool = nuts.pool +local new_penalty = nodepool.penalty +local new_glue = nodepool.glue + +local nodecodes = nodes.nodecodes +local math_code = nodecodes.math + +local somespace = nodes.somespace +local somepenalty = nodes.somepenalty + +local enableaction = nodes.tasks.enableaction + +typesetters = typesetters or { } +local typesetters = typesetters + +typesetters.spacings = typesetters.spacings or { } +local spacings = typesetters.spacings + +spacings.mapping = spacings.mapping or { } +spacings.numbers = spacings.numbers or { } + +local a_spacings = attributes.private("spacing") + +storage.register("typesetters/spacings/mapping", spacings.mapping, "typesetters.spacings.mapping") + +local mapping = spacings.mapping +local numbers = spacings.numbers + +for i=1,#mapping do + local m = mapping[i] + numbers[m.name] = m +end + +-- todo cache lastattr + +function spacings.handler(head) + local _, start = find_attribute(head, a_spacings) + if start then + local done = false + -- head is always begin of par (whatsit), so we have at least two prev nodes + -- penalty followed by glue + while start do + local char, id = isglyph(start) + if char then + local attr = getattr(start,a_spacings) + if attr and attr > 0 then + local data = mapping[attr] + if data then + local map = data.characters[char] + if map then + local font = id + local left = map.left + local right = map.right + local alternative = map.alternative + local quad = quaddata[font] + local prev = getprev(start) + if left and left ~= 0 and prev then + local ok = false + local prevprev = getprev(prev) + if alternative == 1 then + local somespace = somespace(prev,true) + if somespace then + local somepenalty = somepenalty(prevprev,10000) + if somepenalty then + if trace_spacing then + report_spacing("removing penalty and space before %C (left)",char) + end + head = remove_node(head,prev,true) + head = remove_node(head,prevprev,true) + else + if trace_spacing then + report_spacing("removing space before %C (left)",char) + end + head = remove_node(head,prev,true) + end + end + ok = true + else + ok = not (somespace(prev,true) and somepenalty(prevprev,true)) or somespace(prev,true) + end + if ok then + if trace_spacing then + report_spacing("inserting penalty and space before %C (left)",char) + end + insert_node_before(head,start,new_penalty(10000)) + insert_node_before(head,start,new_glue(left*quad)) + end + end + local next = getnext(start) + if right and right ~= 0 and next then + local ok = false + local nextnext = getnext(next) + if alternative == 1 then + local somepenalty = somepenalty(next,10000) + if somepenalty then + local somespace = somespace(nextnext,true) + if somespace then + if trace_spacing then + report_spacing("removing penalty and space after %C right",char) + end + head = remove_node(head,next,true) + head = remove_node(head,nextnext,true) + end + else + local somespace = somespace(next,true) + if somespace then + if trace_spacing then + report_spacing("removing space after %C (right)", char) + end + head = remove_node(head,next,true) + end + end + ok = true + else + ok = not (somepenalty(next,10000) and somespace(nextnext,true)) or somespace(next,true) + end + if ok then + if trace_spacing then + report_spacing("inserting penalty and space after %C (right)",char) + end + insert_node_after(head,start,new_glue(right*quad)) + insert_node_after(head,start,new_penalty(10000)) + end + end + end + end + done = true + end + elseif id == math_code then + start = end_of_math(start) -- weird, can return nil .. no math end? + end + if start then + start = getnext(start) + end + end + if done then + -- unset_attributes(a_spacings,head) + end + end + return head +end + +local enabled = false + +function spacings.define(name) + local data = numbers[name] + if data then + -- error + else + local number = #mapping + 1 + local data = { + name = name, + number = number, + characters = { }, + } + mapping[number] = data + numbers[name] = data + end +end + +function spacings.setup(name,char,settings) + local data = numbers[name] + if not data then + -- error + else + data.characters[char] = settings + end +end + +function spacings.set(name) + local n = unsetvalue + if name ~= v_reset then + local data = numbers[name] + if data then + if not enabled then + enableaction("processors","typesetters.spacings.handler") + enabled = true + end + n = data.number or unsetvalue + end + end + texsetattribute(a_spacings,n) +end + +function spacings.reset() + texsetattribute(a_spacings,unsetvalue) +end + +-- interface + +local implement = interfaces.implement + +implement { + name = "definecharacterspacing", + actions = spacings.define, + arguments = "string" +} + +implement { + name = "setupcharacterspacing", + actions = spacings.setup, + arguments = { + "string", + "integer", + { + { "left", "number" }, + { "right", "number" }, + { "alternative", "integer" }, + } + } +} + +implement { + name = "setcharacterspacing", + actions = spacings.set, + arguments = "string" +} diff --git a/tex/context/base/mkxl/typo-spa.mkxl b/tex/context/base/mkxl/typo-spa.mkxl index 4daaac100..42825b022 100644 --- a/tex/context/base/mkxl/typo-spa.mkxl +++ b/tex/context/base/mkxl/typo-spa.mkxl @@ -15,7 +15,7 @@ \unprotect -\registerctxluafile{typo-spa}{} +\registerctxluafile{typo-spa}{autosuffix} \definesystemattribute[spacing][public] diff --git a/tex/context/modules/mkiv/s-magazine-basic.mkiv b/tex/context/modules/mkiv/s-magazine-basic.mkiv index d45fe6f60..c5995162a 100644 --- a/tex/context/modules/mkiv/s-magazine-basic.mkiv +++ b/tex/context/modules/mkiv/s-magazine-basic.mkiv @@ -110,8 +110,9 @@ \doifoddpageelse { \reuseMPgraphic{rightpaper} } { - \reuseMPgraphic{leftpaper}} + \reuseMPgraphic{leftpaper} } + } \stopsetups @@ -459,8 +460,8 @@ \definetyping[xtyping] [style=\ttx] \definetyping[xxtyping][style=\ttxx] -\definetyping[ntyping] \setuptyping[ntyping][style=\narrowtt] -\definetype [ntype] \setuptype [ntype] [style=\narrowtt] +% \definetyping[ntyping] \setuptyping[ntyping][style=\narrowtt] +% \definetype [ntype] \setuptype [ntype] [style=\narrowtt] \setupdocument [main={\doifelsemode{atpragma}{This Way}{My Way}}, diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index b94ad3846..9515034ab 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 : 2020-12-03 18:56 +-- merge date : 2020-12-04 20:19 do -- begin closure to overcome local limits and interference -- cgit v1.2.3