diff options
author | Karl Berry <karl@freefriends.org> | 2023-01-02 21:31:04 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-01-02 21:31:04 +0000 |
commit | b9587c576db3679c338a1d395c182023ff4d711c (patch) | |
tree | d36ea573074a6c7d740f15e323b5ec7720e976bc /Master/texmf-dist | |
parent | 7bde2bb3891ad0c87d05ad80fabb4258dc5b84fb (diff) |
blopentype (2jan23)
git-svn-id: svn://tug.org/texlive/trunk@65441 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r-- | Master/texmf-dist/doc/luatex/blopentype/DEPENDS.txt | 4 | ||||
-rw-r--r-- | Master/texmf-dist/doc/luatex/blopentype/README.md | 37 | ||||
-rw-r--r-- | Master/texmf-dist/doc/luatex/blopentype/blopentype.md | 142 | ||||
-rw-r--r-- | Master/texmf-dist/doc/luatex/blopentype/blottest.pdf | bin | 0 -> 144031 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/luatex/blopentype/blottest.tex | 82 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-base.lua | 88 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-files.tex | 39 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua | 1213 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex | 308 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex | 26 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua | 19 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot.tex | 254 |
12 files changed, 2212 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/luatex/blopentype/DEPENDS.txt b/Master/texmf-dist/doc/luatex/blopentype/DEPENDS.txt new file mode 100644 index 00000000000..46b92da95be --- /dev/null +++ b/Master/texmf-dist/doc/luatex/blopentype/DEPENDS.txt @@ -0,0 +1,4 @@ +# Basic LuaTeX OpenType handler dependencies +texapi +yax +gates diff --git a/Master/texmf-dist/doc/luatex/blopentype/README.md b/Master/texmf-dist/doc/luatex/blopentype/README.md new file mode 100644 index 00000000000..4a0a3930f26 --- /dev/null +++ b/Master/texmf-dist/doc/luatex/blopentype/README.md @@ -0,0 +1,37 @@ +# blopentype +Basic LuaTeX OpenType Handler + +# Description + +In his terse documentation for `PiTeX`, Paul Isambert lists, among the "mandatory PiTeX" files, the following: + +| file name | Description | +|-|-| +| fonts.ptx | Interface for fonts; relies on the next file. | +| fonts.ptxlua | The Lua fontloader; should become independant some day. | +| foundry-settings.lua | Default settings for the fontloader. | + +Well: the day has come, and the fontloader has now become `blopentype`: a *Basic LuaTeX OpenType Handler*. + +The basic code is copied almost verbatim from Isambert's `PiTeX`, save the adoption of the filename extensions `ltm` for *LuaTeX macros*, `lts` for *LuaTeX scripts*, and `blot-sets.lua` for the basic basic settings. +The required dependencies are Isambert packages [texapi](https://ctan.org/pkg/texapi), [YaX](https://ctan.org/pkg/yax) and [Gates](https://ctan.org/pkg/gates), as stated in `DEPENDS.txt`. + +You may find an example of usage in the `blottest.[tex|pdf]` files, and some basic documentation in `blopentype.md`. + +# Bugs and caveats + +The macros are still barely documented, and massively keep the names of their parent (`PiTeX`) package; that may be fixed some day. + +The font database is loaded at `$HOME/texmf/luatex/foundry/readable.txt`; it is not updated automatically after installing new fonts: you have to edit it manually, or else delete/rename(backup) it and rerun LuaTeX to rebuild it. + +The character table for each typeface is stored in the `luatex/foundry` directory as a flat `lua` file; it would be nice to have it compiled as a `luac` file to save some space. + +Good luck, and happy LuaTeXing + +# Authors + +Version 0.0.0 (C) 2022 Paul Isambert (massively) and Luis Rivera (minor surgeon; or rather: kludger). + +LaTeX Project Public License, LPPL Version 1.3c 2008-05-04 or MIT License + +December 28, 2022
\ No newline at end of file diff --git a/Master/texmf-dist/doc/luatex/blopentype/blopentype.md b/Master/texmf-dist/doc/luatex/blopentype/blopentype.md new file mode 100644 index 00000000000..a42d55ec489 --- /dev/null +++ b/Master/texmf-dist/doc/luatex/blopentype/blopentype.md @@ -0,0 +1,142 @@ +# Basic LuaTeX OpenType Handler Minimal User Guide + +As for version 0.0.0 December 2022 + +Fonts (fonts.ltm and fonts.lts) +================================== + +The fontloader uses gates, but only superficially. They won't be +documented here. + +To load a given font, you define it in YaX syntax with the `\setfont` command. + +```\setfont <command>:<attributes>``` + +Sets <command> to call the font described in <attributes>; all defaults +to the values of the `metafont` parameter. If `<command>` is `\mainfont`, +as the name of the main font for the document, the font is called at once; +any other `\command` requires explicit calls. + +You may thing of `\setfont <command>` as similar to DEKTeX's `\font\cmr10 at 12pt` +or whatever font definition, but now the call is to an array of font attributes. + +`name` +The family name of the font; e.g. Palatino Linotype for the main text of +this document. + +`size (dimension)` +The size of the font. + +`small (dimension)` +The size of the font when \small is called. Can be a relative value by +prefixing it with "-" or "+", in which case it is set relative to ?size. + +`verysmall (dimension)` +The size (possibly relative) for \verysmall. + +`big (dimension)` +The size (possibly relative) for \big. + +`verybig (dimension)` +The size (possibly relative) for \verybig. + +`bold (font modifier)` +The modifier used for the bold version of the font, without the leading slash; +!metafont sets it to "Bold". + +`italic (font modifier)` +Same as !bold for the italic version; set to "Italic" by !metafont. + +`math (true or false)` +If true, math fonts will be created. + +`features` +Well, err, font features... + +`slant (angle)` +The slant applied to the font to create a fake italic. + +`slantsc (angle)` +The slant applied to the font to create fake italic smallcaps; if not +given, defaults to ?slant. + +There's actually much more going under the hood, but "font.ptxlua" (the +font loader itself) is a work in progress, and undocumented. + +# Font change commands + +The same macros as in plain TeX can be used, except they're cumulative, +i.e. "\it\bf" switches to a bold italic. +`<text>` in the specification should be group delimited with braces. + +`\it` +Switches to italics. + +`\rm` +Switches to roman. + +`\bf` +Switches to bold. + +`\rg` +Switches to regular weight. + +`\sc` +Switches to small capitals. + +`\lc` +Switches to lower case (i.e. not small caps). + +`\ital <text>` +Typesets <text> in italics. + +`\bold <text>` +Typesets <text> in bold. + +`\scap <text>` +Typesets <text> in small caps. + +`\rom <text>` +Typesets <text> in roman. + +`\emph <text>` +Typesets <text> in italics or roman, depending on whether the current +font is roman or italics, respectively. + +`\underline <text>` +Underlines <text>. Wow. + +`\small` +Switches to small font. + +`\verysmall` +Switches to very small font. + +`\big` +Switches to big font. + +`\verybig` +Got it? + +`\normalsize` +Switches to default size. + +`\smaller` +Switches to the font smaller than the current one (e.g. \normalsize if +you're currently using \big). + +`\bigger` +Same as \smaller, the other way around. + +`\color <color><text>` +Typesets <text> with <color>, which should be a triplet "R G B" with +each value between 0 and 1. + +# See also + +Documentation for [YaX](https://ctan.org/pkg/yax) for the YaX syntax to set up the fonts. + +Good luck and happy LuaTeXing, + +Luis Rivera + diff --git a/Master/texmf-dist/doc/luatex/blopentype/blottest.pdf b/Master/texmf-dist/doc/luatex/blopentype/blottest.pdf Binary files differnew file mode 100644 index 00000000000..d5d3f2d9040 --- /dev/null +++ b/Master/texmf-dist/doc/luatex/blopentype/blottest.pdf diff --git a/Master/texmf-dist/doc/luatex/blopentype/blottest.tex b/Master/texmf-dist/doc/luatex/blopentype/blottest.tex new file mode 100644 index 00000000000..83d93d5547e --- /dev/null +++ b/Master/texmf-dist/doc/luatex/blopentype/blottest.tex @@ -0,0 +1,82 @@ +\input blot +\pdfpageheight 12 true in +\vsize10in + +\hsize6.5in +\footline{} + +\setfont\mainfont : + name = "Palatino Linotype" + size = 12pt + big = +2pt + +\baselineskip=1.5\baselineskip + +\patterns{1τ} + +\bf Two statements by Lincoln + +\rg + +Address delivered at the dedication of the cemetery at Gettysburg. + +November 19, 1863. + +Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. + +But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth. + +—Abraham Lincoln + +\vskip\baselineskip + +Executive Mansion, + +Washington, Nov. 21, 1864. + +Dear Madam, + +I have been shown in the files of the War Department a statement of the Adjutant General of Massachusetts that you are the mother of five sons who have died gloriously on the field of battle. + +I feel how weak and fruitless must be any words of mine which should attempt to beguile you from the grief of a loss so overwhelming. But I cannot refrain from tendering to you the consolation that may be found in the thanks of the Republic they died to save. + +I pray that our Heavenly Father may assuage the anguish of your bereavement, and leave you only the cherished memory of the loved and lost, and the solemn pride that must be yours to have laid so costly a sacrifice upon the altar of Freedom. + +Yours, very sincerely and respectfully, + +A. Lincoln. + +Mrs. [Lydia Parker] Bixby. + +[Boston, MA] + +\vskip\baselineskip + +% \vfill\break + +\bf Some sound advice from Marcus Aurelius's \emph{τὰ πρός σεαυτόν}. + +\rg +Ὅ τί ποτε τοῦτό εἰμι, σαρκία ἐστὶ καὶ πνευμάτιον καὶ τὸ ἡγεμονικόν. τῶν μὲν σαρκίων καταφρόνησον˙ λύθρος καὶ ὀστάρια καὶ κροκύφαντος, ἐκ νεύρων, φλεβίων, ἀρτηριῶν πλεγμάτιον. θέασαι δὲ καὶ τὸ πνεῦμα ὁποῖόν τί ἐστιν˙ ἄνεμος, οὐδὲ ἀεὶ τὸ αὐτό, ἀλλὰ πάσης ὥρας ἐξεμούμενον καὶ πάλιν ῥοφούμενον. τρίτον οὖν ἐστι τὸ ἡγεμονικόν. \emph{ἄφες τὰ βιβλία}˙ μηκέτι σπῶ˙ οὐ δέδοται. ἀλλ ὡς ἤδη ἀποθνῄσκων ὧδε ἐπινοήθητι˙ γέρων εἶ˙ μηκέτι τοῦτο ἐάσῃς δουλεῦσαι, μηκέτι καθ ὁρμὴν ἀκοινώνητον νευροσπαστηθῆναι, μηκέτι τὸ εἱμαρμένον ἢ παρὸν δυσχερᾶναι ἢ μέλλον ὑπιδέσθαι. + +Τὰ τῶν θεῶν προνοίας μεστά. τὰ τῆς τύχης οὐκ ἄνευ φύσεως ἢ συγκλώσεως καὶ ἐπιπλοκῆς τῶν προνοίᾳ διοικουμένων. πάντα ἐκεῖθεν ῥεῖ˙ πρόσεστι δὲ τὸ ἀναγκαῖον καὶ τὸ τῷ ὅλῳ κόσμῳ συμφέρον, οǷ μέρος εἶ. παντὶ δὲ φύσεως μέρει ἀγαθόν, ὃ φέρει ἡ τοῦ ὅλου φύσις καὶ ὃ ἐκείνης ἐστὶ σωστικόν. σῴζουσι δὲ κόσμον, ὥσπερ αἱ τῶν στοιχείων, οὕτως καὶ αἱ τῶν συγκριμάτων μεταβολαί. \emph{ταῦτά σοι ἀρκείτω˙ ἀεὶ δόγματα ἔστω. τὴν δὲ τῶν βιβλίων δίψαν ῥῖψον, ἵνα μὴ γογγύζων ἀποθάνῃς, ἀλλὰ ἵλεως ἀληθῶς καὶ ἀπὸ καρδίας εὐχάριστος τοῖς θεοῖς}. + +\vskip\baselineskip + +\it In case that was all Greek to you, then rather read: + +\rm + +Кио айн ми финфине естас, ми консистас де карно, ла спиро кай ла анимо. \emph{Форĵету виайн либройн}. Не есту дистрата - тио не естас пермесата; сед квазаŭ ви ям мортас, абомену ла карнон. Ĝи естас ненио кром санго, остетой кай рето де нервой, артериой кай вейной. Припенсу анкаŭ ла спирон. Киа материо естас ĝи? Аеро, киу не ĉиам естас ла сама, сед дум уну моменто естас вомата кай инспирата. До ла триан атентигу, ла анимон. Компрену, ке ви естас олдуло. Екде нун ви нек алласу, ке виа анимо фариĝас славон, нек алласу, ке ви каптиĝас де контраŭсоциай атакой, нек суферу де виа цирцумстанцаро нек тиму ла естонтецон. + +Кио девенас де ла диой, пленас э провиденцо. Кио девенас де ŝанцо естас парто де натуро кай интертексатас кун тиой, киой девенас де провиденцо. Де провиденцо флуас ĉиой. Ĉиой екзистас про утило кай про тио, ке ĝи естас плей бона пор ла универсо, де киу ви естас парто. Кио естас бона пор ла тута универсо, кай кио субтенас ла натурон де ла универсо, анкаŭ естас бона пор парто де ла универсо. \emph{Есту контента кун тиуй максимой. Сед ĉесу соифи пор либрой пор ке ви алвену мортон не мурмуранте сед вере, транквиле кай данкеме ал ла диой ел виа анимо}. + +\bye + +Kio ajn mi finfine estas, mi konsistas de karno, la spiro kaj la animo. \emph{Forĵetu viajn librojn}. Ne estu distrata - tio ne estas permesata; sed kvazaŭ vi jam mortas, abomenu la karnon. Ĝi estas nenio krom sango, ostetoj kaj reto de nervoj, arterioj kaj vejnoj. Pripensu ankaŭ la spiron. Kia materio estas ĝi? Aero, kiu ne ĉiam estas la sama, sed dum unu momento estas vomata kaj inspirata. Do la trian atentigu, la animon. Komprenu, ke vi estas oldulo. Ekde nun vi nek allasu, ke via animo fariĝas slavon, nek allasu, ke vi kaptiĝas de kontraŭsociaj atakoj, nek suferu de via circumstancaro nek timu la estontecon. + +Kio devenas de la dioj, plenas je providenco. Kio devenas de ŝanco estas parto de naturo kaj interteksatas kun tioj, kioj devenas de providenco. De providenco fluas ĉioj. Ĉioj ekzistas pro utilo kaj pro tio, ke ĝi estas plej bona por la universo, de kiu vi estas parto. Kio estas bona por la tuta universo, kaj kio subtenas la naturon de la universo, ankaŭ estas bona por parto de la universo. \emph{Estu kontenta kun tiuj maksimoj. Sed ĉesu soifi por libroj por ke vi alvenu morton ne murmurante sed vere, trankvile kaj dankeme al la dioj el via animo}. + +\bye
\ No newline at end of file diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua new file mode 100644 index 00000000000..ef933ee0888 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua @@ -0,0 +1,88 @@ +require"gates.lua" + +pitex = gates.new("pitex") +pitex.misc = gates.new("pitex.misc") + +function pitex.log (message, ...) + texio.write_nl(string.format("\n" .. message .. "\n", ...)) +end +function pitex.error (...) + tex.error ("! PiTeX error: " .. string.format(...) .. ".") +end + +pitex.callback = gates.new("pitex.callback") + +-- Creates a gate with a callback's name and put it in that callback, if not +-- already there. Adds the subgate(s). +function pitex.callback.register (c, f) + if pitex.callback.type(c) == 2 then + pitex.callback.add(f, c) + else + pitex.callback.list{c} + pitex.callback.add(f, c) + callback.register(c, pitex.callback.execute[c]) + end +end + +-- Latin1 to UTF-8. +local char = unicode.utf8.char +local function convert_char (ch) +-- return char(string.byte(ch)) +end +function pitex.callback.convert (buf) + return string.gsub(buf,".",convert_char) +end + +pitex.callback.register("process_input_buffer", "convert") + +function remove_conversion () + pitex.callback.close("convert", "process_input_buffer") +end +function restore_conversion () + pitex.callback.open("convert", "process_input_buffer") +end + +--[[ + +require("nodeinspector") +new_inspection = nodeinspector.new_inspection + +local french_highmarks = { + string.byte("?"), + string.byte("!"), + string.byte(":"), + string.byte(";"), + } +local french_marks = { + string.byte("?"), + string.byte("!"), + string.byte(":"), + string.byte(";"), + string.byte(","), + string.byte("."), + string.byte("("), + string.byte("["), + string.byte("{"), + } + +local function french_punctuation (head, ...) + for _, glue in ipairs(arg) do + if glue.id == 10 then + head = node.remove(head, glue) + node.free(glue) + end + end + local kern = node.new(11, 1) + kern.kern = tex.sp(".15em") + node.insert_after(head, arg[1], kern) +end + +pitex.callback.french_punctuation = new_inspection( + french_punctuation, + {{id = 37, _char = french_marks}, {true, id = 37, char = french_highmarks}}, + {{id = 10, subtype = 0}, {id = 11, subtype = 0}}) + +pitex.callback.register("kerning", "french_punctuation") +pitex.callback.original_kerning = node.kerning +pitex.callback.register("kerning", "original_kerning") +--]]
\ No newline at end of file diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex new file mode 100644 index 00000000000..212b05fc076 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex @@ -0,0 +1,39 @@ +\newread\ptx@temp_read +\def\iffile{% + \ifnext[ + {\ptx@iffile} + {\ptx@iffile[]}% + } +\def\ptx@iffile[#1]#2{% + \directlua{ + local f = kpse.find_file("\luaescapestring{#2}"\reverse\iffemptystring{#1}{, "#1"}) + local x = f and "firstoftwo" or "secondoftwo" + tex.print(\the\texcatcodes, "\noexpand\\" .. x) + }% + } +\long\def\ifffile{% + \ifnext[ + {\ptx@ifffile} + {\ptx@ifffile[]}% + } +\long\def\ptx@ifffile[#1]#2#3{% + \iffile[#1]{#2}{#3}{}% + } + +\long\def\inputfileor{% + \ifnext[ + {\ptx@inputfileor} + {\ptx@inputfileor[]}% + } +\long\def\ptx@inputfileor[#1]#2{% + \iffile[#1]{#2}{\input{#2}\relax}% + } + +\newwrite\ptx@auxfile +\def\ptx@write_toaux{% + \ifnext* + {\gobbleoneand{\write\ptx@auxfile}} + {\immediate\write\ptx@auxfile}% + } + +\let\writeout\ptx@write_toaux diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua new file mode 100644 index 00000000000..638f83e984e --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua @@ -0,0 +1,1213 @@ +-- *** UTILITY FUNCTIONS *** +local function get_locals (tab) + local tb = {} + for lib, keys in pairs(tab) do + keys = string.explode(keys) + for _, k in ipairs(keys) do + tb[k] = _G[lib][k] + end + end + return tb +end + +-- str +-- string manipulation +local str = get_locals {string = "explode gsub match format lower upper"} + +-- Removes space at the beginning and end and conflates multiple spaces. +function str.trim (s) + s = str.match(s, "^%s*(.-)%s*$") + s = str.gsub(s, "%s+", " ") + return s +end + +-- Extracts a pattern from a string, i.e. removes it and returns it. +-- If "full", then the entire pattern is removed, not only the captures. +function str.extract (s, pat, full) + local cap = str.match(s, pat) + if cap then + if full then + s = str.gsub(s, pat, "") + else + s = str.gsub(s, cap, "") + end + end + return cap, s +end +-- /str + + +-- lp +-- advanced string manipulation +lpeg.locale(lpeg) +local lp = get_locals {lpeg = "match P C S Ct V alnum"} +lp.space = lpeg.space^0 +-- /lp + + +-- tab +-- table manipulation +local tab = get_locals {table = "insert remove sort"} + +-- Adds val to tab, creating it if necessary. +function tab.update (tb, val) + tb = tb or {} + tab.insert(tb, val) + return tb +end + +-- Adds subtable (empty, or val) to tb at entry key, unless it already exists. +function tab.subtable (tb, key, val) + tb[key] = tb[key] or val or {} +end + +-- Writes a table to an extenal file. +local function write_key (key, ind) + return ind .. '["' .. key .. '"] = ' +end + +function tab.write (tb, f, ind) + for a, b in pairs (tb) do + if type(a) == "string" then + a = '"' .. a .. '"' + end + a = "[" .. a .. "]" + if type(b) == "table" then + f:write(ind, a, " = {") + tab.write(b, f, ind .. " ") + f:write(ind, "},") + else + if type(b) == "boolean" then + b = b and "true" or "false" + elseif type(b) == "string" then + b = '"' .. b .. '"' + end + f:write(ind, a, " = ", b, ",") + end + end +end + +-- Returns a full copy of a table. Not copying of metatables necessary for the +-- moment. +function tab.copy (tb) + local t = {} + for k, v in pairs (tb) do + if type(v) == "table" then + v = tab.copy(v) + end + t[k] = v + end + return t +end + +-- Sorts two tables containing modifiers (Italic, etc.). +function tab.sortmods (a, b) + local A, B = "", "" + for _, x in ipairs (a) do + A = A .. " " .. x + end + for _, x in ipairs (b) do + B = B .. " " .. x + end + return A < B +end + +-- Turns an array into a hash. +function tab.tohash(tb) + local t = {} + for _, k in ipairs(tb) do + t[k] = true + end + return t +end +-- /tab + +-- lfs +-- files etc. +local lfs = get_locals {lfs = "dir isdir isfile mkdir", kpse = "expand_var show_path find_file"} + +-- Returns anything after the last dot, i.e. an extension. +function lfs.extension (s) + return str.lower(str.match(s, "%.([^%.]*)$")) +end + +local extensions = { + otf = "opentype", + ttf = "truetype", + ttc = "truetype", +} +function lfs.type (s) + return extensions[lfs.extension(s)] +end + +local kpse_extensions = { + otf = "opentype fonts", + ttf = "truetype fonts", + ttc = "truetype fonts", +} +function lfs.kpse (s) + return kpse_extensions[lfs.extension(s)] +end + +-- Returns anything after the last slash, i.e. a pathless file. +function lfs.nopath (f) + return str.match(f, "[^/]*$") +end + +-- Creates a directory; the arguments are the successive subdirectories. +function lfs.ensure_dir (...) + local arg, path = {...} + for _, d in ipairs(arg) do + if path then + path = path .. "/" .. d + else + path = d + end + path = str.gsub(path, "//", "/") + if not lfs.isdir(path) then + lfs.mkdir(path) + end + end + return path +end + +-- Turns "foo/blahblah/../" into "foo/" (such going into and leaving +-- directories happens with kpse). Also puts everything to lowercase. +function lfs.smooth_file (f) + f = str.gsub(f, "/.-/%.%./", "/") + f = str.gsub(f, "^%a", str.lower) + return f +end +-- /lfs + + +-- wri +-- messages +local wri, write_nl = {}, texio.write_nl + +function wri.report (s, ...) +-- write_nl(str.format(s, unpack(arg))) +end + +function wri.error (s, ...) +-- tex.error(str.format(s, unpack(arg))) +end +-- /wri + + +-- various +-- the last one is, of course, not the least +local io = get_locals {io = "open lines"} +local os = get_locals {os = "date"} +local num = get_locals {math = "abs tan rad floor pi", tex = "sp"} +local fl = get_locals {fontloader = "open close to_table info", font = "read_tfm"} +-- /various + + +-- *** END OF UTILITY FUNCTIONS *** + + + +--- *** CREATING THE LIBRARY *** --- +local settings +if lfs.find_file"blot-sets.lua" then + settings = require"blot-sets.lua" +else + settings = {normal = {}, features = {}} +end +local font_families = {} +local normal_names = {} +for _, name in ipairs(settings.normal) do + normal_names[name] = true +end +local local_path = lfs.expand_var("$TEXMFHOME") +local foundry_path = lfs.ensure_dir (local_path, "tex", "luatex", "foundry") +-- local local_path = lfs.expand_var("$TEXMFHOME") +-- local foundry_path = lfs.ensure_dir (local_path, "fonts", "truetype", "public", "gfs") +local library_file = foundry_path .. "/" .. "readable.txt" +-- local library_file = "c:/texlive/texmf-local/tex/plain/pitex/readable.txt" +-- local library_file = "readable.txt" + +-- Analyze a font file and return a name and a table +-- with modifiers. +local function extract_font (file, names) + local fi, subname + -- Trying to open a font in ttc, using the names returned by fontloader.info + if names then + local name = names.fullname + if name then + fi = fl.open (file, name) + end + if not fi then + name = names.fontname + if name then + fi = fl.open + end + if not fi then + fl.error("Can't open %s", file) + return + end + end + subname = name + else + fi = fl.open(file) + end + -- Getting the most precise information. Not necessarily the best + -- solution, but since the user can modify the library, it's not so bad. + local fam, name = fi.names[1].names.preffamilyname or fi.names[1].names.family or fi.familyname, fi.fontname + local spec = fi.names[1].names.prefmodifiers or fi.names[1].names.subfamily or "" + local subfam, _spec + local t = { [0] = file } + -- Removing mods like Regular, Book, etc. + for name in pairs(normal_names) do + spec = str.gsub(spec, name, "") + end + if subname then + tab.insert(t, "[font = " .. subname .. "]") + end + if spec ~= "" then + spec = str.explode(spec) + for _, s in ipairs(spec) do + tab.insert(t, s) + end + end + fl.close(fi) + return fam, t +end + +-- Searches directories for font files, and pass them to +-- extract_font. The fonts are collected in a table. +-- The fonts_done table is updated when the library is read, +-- so when a font is missing and one needs to recheck files, +-- only those that arent in the libraries are considered. +local fonts_done = {} +local function check_fonts (rep, tb) + for f in lfs.dir (rep) do + if f ~= "." and f ~= ".." then + f = str.gsub(rep, "/$", "") .. "/" .. f + if lfs.isdir(f) then + check_fonts(f, tb) + elseif lfs.isfile(f) and not fonts_done[lfs.nopath(f)] then + local e = lfs.extension(f) + if e == "ttf" or e == "otf" then + local fam, file = extract_font(f) + if fam then + tab.subtable(tb, fam) + tab.insert(tb[fam], file) + end + elseif e == "ttc" then + local info = fl.info(f) + for _, i in ipairs(info) do + local fam, file = extract_font(f, i) + if fam then + tab.subtable(tb, fam) + tab.insert(tb[fam], file) + end + end + end + end + end + end +end + +-- Writes the library to an external file. +-- Type is "a" if what's going on is recheck_fonts. +local function write_lib (fams, file, type) + local read_table = {} + for fam, tb in pairs(fams) do + tab.insert(read_table, fam) + for _, ttb in ipairs(tb) do + tab.sort(ttb) + end + tab.sort(tb, tab.sortmods) + end + tab.sort(read_table) + local readable = io.open(file, type) + for n, fam in ipairs(read_table) do + local log + if type == "a" then + log = true + if n == 1 then + wri.report("\nAdding new font(s):") + readable:write("\n\n% Added automatically " .. os.date() .. "\n\n") + end + wri.report(fam) + end + readable:write(fam .. " :") + for n, f in ipairs(fams[fam]) do + log = log and " " + readable:write("\n ") + for _, t in ipairs(f) do + log = log and log .. " " .. t + readable:write(" " .. t) + end + log = log and log .. " " .. '"' .. f[0] .. '"' + readable:write(" " .. '"' .. lfs.nopath(f[0]) .. '",') + if log then wri.report(log) end + if n == #fams[fam] then + readable:write("\n\n") + end + end + end + readable:close() +end + + +-- If there is no library, we create it. +local font_paths = lfs.show_path("opentype fonts") +font_paths = str.gsub(font_paths, "\\", "/") +font_paths = str.gsub(font_paths, "/+", "/") +font_paths = str.gsub(font_paths, "!!", "") +font_paths = str.explode(font_paths, ";+") + +if not lfs.find_file(library_file) then + wri.report("I must create the library; please wait, that can take some time.") + for _, rep in ipairs(font_paths) do + check_fonts(rep, font_families) + end + write_lib(font_families, library_file, "w") +end + +-- Reads the library file, turning it into a table. +local explode_semicolon = lp.P{ + lp.Ct(lp.V"data"^1), + data = lp.C(((1 - lp.S";[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S";" + -1), + } +local explode_comma = lp.P{ + lp.Ct(lp.V"data"^1), + data = lp.C(((1 - lp.S",[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S"," + -1), + } + +local function load_library (lib) + local LIB = "" + local lib_file = lfs.find_file(lib) + if not lib_file then + wri.error("I can't find library %s.", lib) + return + end + + for l in io.lines(lib_file) do + if not str.match(l, "^%s*%%") then + if str.match(l, "^%s*$") then + LIB = LIB .. ";" + else + LIB = LIB .. " " .. l + end + end + end + LIB = str.gsub(LIB, ";%s*;", ";;") + LIB = str.gsub(LIB, ";+", ";") + LIB = str.gsub(LIB, "^;", "") + LIB = str.gsub(LIB, "%s+", " ") + + LIB = lp.match(explode_semicolon, LIB) + + local newlib = {} + for _, t in ipairs(LIB) do + local fam, files = str.match(t, "(.-):(.*)") + local current_mods + if files then + files = lp.match(explode_comma, files) + fam = str.explode(fam, ",") + local root + for n, f in ipairs (fam) do + f = str.trim(f) + if n == 1 then + root = f + if type(newlib[f]) == "string" then + wri.error("Name `%s' is already used as an alias for `%s'; it is now overwritten to denote a family", f, newlib[f]) + newlib[f] = {} + else + newlib[f] = newlib[f] or {} + end + else + if newlib[f] then + wri.error("The name `%s' is already used. I ignore it as an alias for `%s'", f, root) + else + newlib[f] = root + end + end + end + for _, f in ipairs(files) do + local reset + reset, f = str.extract(f, "^%.%.", true) + if reset then current_mods = nil end + local mods, file, feats = str.match(f, '([^"]*)"(.*)"') + if mods then + fonts_done[lfs.nopath(file)] = true + feats, mods = str.extract(mods, "%[([^%]]-)]", true) + mods = str.explode(mods) + if current_mods then + for _, t in ipairs(current_mods) do + tab.insert(mods, t) + end + if current_mods.feats then + feats = feats or "" + feats = current_mods.feats .. "," .. feats + end + end + local sizes, real_mods = {}, {} + for n, s in ipairs(mods) do + if tonumber(s) then + tab.insert(sizes, tonumber(s)) + else + tab.insert(real_mods, s) + end + end + sizes = #sizes > 0 and sizes or {0} + tab.sort(real_mods) + local T = newlib[root] + for _, t in ipairs(real_mods) do + t = str.trim(t) + if t ~= "" then + T[t] = T[t] or {} + T = T[t] + end + end + T.__files = T.__files or {} + for _, s in ipairs(sizes) do + T.__files[s] = {str.trim(file), feats} + end + else + feats, mods = str.extract(f, "%[([^%]]-)]", true) + if current_mods then + for _, mod in ipairs(str.explode(mods)) do + tab.insert(current_mods, mod) + end + if feats then + current_mods.feats = current_mods.feats and current_mods.feats .. "," .. feats or feats + end + else + current_mods = str.explode(mods) + current_mods.feats = feats + end + end + end + end + end + return newlib +end + +local library = {} +library.default = load_library(library_file) + +-- Same as above, but used when rechecking (if a font isn't found in libraries). +local function recheck_fonts () + local tb = {} + for _, rep in ipairs(font_paths) do + check_fonts(rep, tb) + end + write_lib(tb, library_file, "a") + library.default = load_library(library_file) +end + + +-- This is public. +function new_library (lib) + local l = load_library(lib) + if l then + tab.insert(library, l) + end +end + +--- *** END OF LIBRARY MANAGEMENT *** --- + + + +--- *** FONT CREATION *** --- + + +-- Creates a new substitution for trep. +local function add_sub (f, num, sub) + num, sub = f.map.map[num], f.map.map[sub] + if f.glyphs[num] and f.glyphs[sub] then + local x = f.glyphs[num] + tab.subtable(x, "lookups") + x.lookups.tex_trep = { { type = "substitution", specification = {variant = f.glyphs[sub].name} } } + end +end + +-- Creates a new ligature for tlig. +local function add_lig (f, lig, ...) + lig = f.map.map[lig] + if lig then + arg = {...} + local components + for _, c in ipairs(arg) do + c = f.map.map[c] + c = c and f.glyphs[c] + if c then + c = c.name + components = components and components .. " " .. c or c + else + components = nil + break + end + end + if components then + local x = f.glyphs[lig] + tab.subtable(x, "lookups") + tab.subtable(x.lookups, "tex_tlig") + tab.insert(x.lookups.tex_tlig, { type = "ligature", + specification = {char = x.name, components = components} }) + end + end +end + +-- Loops over all the constitutents of ligatures, creating intermediary +-- ligatures if necessary. E.g. "f f i" is broken into: +-- f + f = ff.lig +-- ff.lig + i = ffi.lig +-- Then when loading the font if the intermediary ligatures do not exist +-- (e.g. "1/" in "1 / 4") a phantom character is added to the font; which might +-- be dangerous (e.g. "1/" will create a node without character if no "4" follows). +-- The ".lig" suffix is arbitrary but all glyphs marked as ligatures are also registered +-- with such a name, so if there's an "f f" ligature in a font, no matter its name, "ff.lig" +-- will point to it. +local function ligature (comp, tb, phantoms) + local i = str.gsub(comp[1], "%.lig$", "") .. comp[2] .. ".lig" + phantoms[i] = true + tab.insert(tb.all_ligs, i) + tab.subtable(tb, comp[1]) + tb[comp[1]][comp[2]] = { char = i, type = 0 } -- The type could be something else. + tab.remove(comp, 1) + tab.remove(comp, 1) + if #comp > 0 then + tab.insert(comp, 1, i) + ligature(comp, tb, phantoms) + end +end + +local function get_lookups (t, lookup_table) + if t then + for _, tb in pairs(t) do + local _tb = { tags = {} } + if tb.features then + for _, feats in pairs(tb.features) do + local _tag = {} + if feats.scripts then + for _, scr in pairs(feats.scripts) do + _tag[scr.script] = {} + for _, lang in pairs(scr.langs) do + tab.insert (_tag[scr.script], str.trim(lang)) + end + end + end + for _, sub in pairs(tb.subtables) do + tab.insert(_tb, sub.name) + end + _tb.tags[feats.tag] = _tag + end + end + if tb.name then + local tp = tb.type or "no_type" + tab.subtable(lookup_table, tp) + lookup_table[tp][tb.name] = _tb + end + end + end +end + +function create_font (filename, extension, path, subfont, write) + + local data = fl.open(filename, subfont) + fontfile = fl.to_table(data) + fl.close(data) + + local lookups = {} + + local name_touni = { } + local max_char = 0 + for chr, gly in pairs(fontfile.map.map) do + max_char = chr > max_char and chr or max_char + -- Some glyphs have the same name in some fonts, + -- e.g. the several hyphens. + local name = fontfile.glyphs[gly].name + while name_touni[name] do + name = name .. "_" + end + name_touni[name] = chr + end + + if fontfile.gsub then + tab.insert(fontfile.gsub, + { type = "gsub_single", + name = "tex_trep", + subtables = { {name = "tex_trep"} }, + features = { { tag = "trep"} } }) + tab.insert(fontfile.gsub, + { type = "gsub_ligature", + name = "tex_tlig", + subtables = { {name = "tex_tlig"} }, + features = { { tag = "tlig"} } }) + for _, tb in ipairs(fontfile.gsub) do + for __, ttb in ipairs(tb.subtables) do + if tb.type == "gsub_contextchain" then + lookups[tb.name] = lookups[tb.name] or { type = tb.type } + tab.insert(lookups[tb.name], ttb.name) + end + lookups[ttb.name] = { type = tb.type } + lookups["-" .. ttb.name] = { type = tb.type } + end + end + end + + if fontfile.gpos then + for _, tb in ipairs(fontfile.gpos) do + for __, ttb in ipairs(tb.subtables) do + lookups[ttb.name] = { type = tb.type } + lookups["-" .. ttb.name] = { type = tb.type } + end + end + end + + if fontfile.kerns then + for _, class in ipairs(fontfile.kerns) do + local max = 0 + for a in pairs (class.seconds) do + max = max < a and a or max + end + if type(class.lookup) == "string" then + lookups[class.lookup] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max} + else + for _, lk in ipairs(class.lookup) do + lookups[lk] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max} + end + end + end + end + + add_sub(fontfile, 96, 8216) -- ` to quoteleft + add_sub(fontfile, 39, 8217) -- ' to apostrophe (quoteright) + + add_lig(fontfile, 8220, 8216, 8216) -- quoteleft + quoteleft to quotedblleft + add_lig(fontfile, 8221, 8217, 8217) -- quoteright + quoteright to quotedblright + add_lig(fontfile, 8211, 45, 45) -- -- to endash + add_lig(fontfile, 8212, 8211, 45) -- --- (i.e. endash + -) to emdash + add_lig(fontfile, 161, 63, 96) -- ?` to inverted question mark + add_lig(fontfile, 161, 63, 8216) -- The same, with `turned to quoteleft. + add_lig(fontfile, 191, 33, 96) -- !` to inverted exclamation mark + add_lig(fontfile, 191, 33, 8216) -- Idem. + + local characters, phantom_ligatures = {}, {} + for chr, gly in pairs(fontfile.map.map) do + local glyph, char = fontfile.glyphs[gly], {} + + char.index = gly + char.name = glyph.name + char.width = glyph.width + if glyph.boundingbox then + char.depth = -glyph.boundingbox[2] + char.height = glyph.boundingbox[4] + end + if glyph.italic_correction then + char.italic = glyph.italic_correction + elseif glyph.width and glyph.boundingbox then + char.italic = glyph.boundingbox[3] - glyph.width + end + tab.subtable(characters, chr) + characters[chr] = char + + if glyph.lookups then + for lk, tb in pairs(glyph.lookups) do + local _lk = "-" .. lk + if lookups[lk] and lookups[_lk] then + for _, l in ipairs(tb) do + if l.type == "substitution" then + + tab.subtable(lookups[lk], "pairs") + lookups[lk].pairs[glyph.name] = l.specification.variant + + tab.subtable(lookups[_lk], "pairs") + lookups[_lk].pairs[l.specification.variant] = glyph.name + + elseif l.type == "ligature" then + + local comp, lig = str.explode(l.specification.components), l.specification.char + local lig = "" + for _, c in ipairs(comp) do + lig = lig .. c + end + + tab.subtable(lookups, lk) + tab.subtable(lookups[lk], "ligs", {all_ligs = {}}) + ligature(comp, lookups[lk].ligs, phantom_ligatures) + name_touni[lig .. ".lig"] = chr + + end + end + end + end + end + + if glyph.kerns then + for _, kern in pairs(glyph.kerns) do + local lks = type(kern.lookup) == "table" and kern.lookup or {kern.lookup} + for _, lk in ipairs(lks) do + tab.subtable(lookups[lk], "kerns") + tab.subtable(lookups[lk].kerns, glyph.name) + lookups[lk].kerns[glyph.name][kern.char] = kern.off + end + end + end + + end + + for lig in pairs(phantom_ligatures) do + if not name_touni[lig] then + max_char = max_char + 1 + name_touni[lig] = max_char + characters[max_char] = {name = lig} + end + end + + local lookup_table = {} + get_lookups(fontfile.gsub, lookup_table) + get_lookups(fontfile.gpos, lookup_table) + get_lookups(fontfile.lookups, lookup_table, true) + + if fontfile.lookups then + for name, lk in pairs(fontfile.lookups) do + local tb, format = {}, lk.format + for _, rule in ipairs(lk.rules) do + local ttb = { lookups = rule.lookups } + for pos, seq in pairs(rule[format]) do + ttb[pos] = {} + for _, glyfs in ipairs(seq) do + glyfs = str.explode(glyfs) + glyfs = tab.tohash(glyfs) + tab.insert(ttb[pos], glyfs) + end + end + tab.insert(tb, ttb) + end + lookups[name] = tb + end + end + + local loaded_font = { + + direction = 0, + filename = filename, + format = extension, + fullname = fontfile.names[1].names.fullname, + name = fontfile.fontname, + psname = fontfile.fontname, + type = "real", + units_per_em = fontfile.units_per_em, + + auto_expand = true, + + cidinfo = fontfile.cidinfo, + + -- Used only to adjust absoluteslant. + italicangle = -fontfile.italicangle, + name_to_unicode = name_touni, + max_char = max_char, + lookups = lookups, + lookup_table = lookup_table, + characters = characters + } + + if write then + local f = io.open(path, "w") + f:write("return {") + tab.write(loaded_font, f, "\n") + f:write("}") + f:close() + end + + return loaded_font + +end + +-- GETTING A FONT + +-- Finds a font file, and returns the original +-- file and the Lua version. +local name_luafile, get_features +local function is_font (name, mods, size) + + local lib, library_filename + for l, t in ipairs(library) do + if t[name] then + library_filename = t[name] + lib = t + break + end + end + if not library_filename then + library_filename = library.default[name] + lib = library.default + end + + if library_filename then + if type(library_filename) == "string" then + library_filename = lib[library_filename] + end + tab.sort(mods) + local T = library_filename + for _, t in ipairs(mods) do + local found + for tag in pairs(T) do + if str.match(tag, "^" .. t) then + T = T[tag] + found = true + break + end + end + if not found then + T = nil + break + end + end + + if T and T.__files then + local file, feats + local diff = 10000 + for s, f in pairs(T.__files) do + if num.abs(s - size) < diff then + diff = num.abs(s - size) + file, feats = f[1], f[2] + end + end + file, _file = lfs.find_file(file, lfs.kpse(file)), file + if file then + file = str.gsub(file, "\\", "/") + else + return 1, _file + end + local features = {} + if feats then + get_features(feats, features) + end + local lua = name_luafile(file, features.font) + lua = lfs.isfile(lua) and lua + return file, lua, feats + end + end +end + +-- Returns the full path to the Lua version of the font. +-- "sub" is a font in ttc. +function name_luafile (file, sub) + local lua + sub = sub and "_" .. sub or "" + sub = str.gsub(sub, " ", "_") + if str.match(file, "/") then + lua = str.match(file, ".*/(.-)%....$") + else + lua = str.match(file, "(.-)%....$") + end + lua = lua .. sub + return foundry_path .. "/" .. lua .. ".lua" +end + +local function apply_size (font, size, letterspacing, parameters) + if (size < 0) then size = (- 655.36) * size end + local to_size = size / font.units_per_em + font.size = size + font.designsize = size + font.to_size = to_size + local italic = font.italicangle or 0 + local space, stretch, shrink, extra + if parameters == "mono" then -- Creates a monospaced font with space equal to the + -- width of an "m" and no stretch or shrink. + space = font.characters[109].width * to_size + stretch, shrink, extra = 0, 0, 0 + else + parameters = parameters and str.explode(parameters) or {} + space = (parameters[1] or 0.25) * size + stretch = (parameters[2] or 0.166666) * size + shrink = (parameters[3] or 0.111111) * size + extra = (parameters[4] or 0.111111) * size + end + font.parameters = { + slant = size * num.floor(num.tan(italic * num.pi/180)), -- \fontdimen 1 + space = space, -- \fontdimen 2 + space_stretch = stretch, -- \fontdimen 3 + space_shrink = shrink, -- \fontdimen 4 + x_height = size * 0.4, -- \fontdimen 5 + quad = size, -- \fontdimen 6 + extra_space = extra -- \fontdimen 7 + } + + letterspacing = letterspacing or 1 + for c, t in pairs(font.characters) do + if t.width then + t.width, t.height, t.depth = t.width * to_size * letterspacing, t.height * to_size, t.depth * to_size + t.expansion_factor = 1000 + if t.italic then + t.italic = t.italic * to_size + end + end + end + + return font +end + + +local get_mods = lp.Ct((lp.space * lp.S"/" * lp.C(lp.alnum^1))^0) +local get_feats = lp.Ct((lp.C((1 - lp.S",;")^1) * (lp.S",;" + -1))^1) +function get_features (features, tb) + features = lp.match(get_feats, features) or {} + for _, f in ipairs(features) do + if str.match(f, "=") then + local key, val = str.match(f, "%s*(.-)%s*=%s*(.*)") + val = str.trim(val) + if val == "false" then + tb[key] = nil + else + tb[key] = val + end + else + f = str.trim(f) + neg, f = str.extract(f, "^%-") + if neg then + tb[f] = nil + else + _, f = str.extract(f, "^%+") + tb[f] = true + end + end + end +end + +local lookup_functions = {} + +function lookup_functions.gsub_single (tb, f) + local name_touni = f.name_to_unicode + for a, b in pairs(tb.pairs) do + local _a, _b = name_touni[a], name_touni[b] + f.max_char = f.max_char + 1 + f.characters[f.max_char] = f.characters[_a] + f.characters[_a] = f.characters[_b] + name_touni[a], name_touni[b] = f.max_char, _a + end + return f +end + +function lookup_functions.gsub_ligature (tb, f) + local name_touni = f.name_to_unicode + tb.ligs.all_ligs = nil + for a, tb in pairs(tb.ligs) do + a = name_touni[a] + tab.subtable(f.characters[a], "ligatures") + for b, ttb in pairs(tb) do + b, c = name_touni[b], name_touni[ttb.char] + f.characters[a].ligatures[b] = {char = c, type = ttb.type} + end + end + return f +end + +local function kern_pairs (tb, firsts, seconds, offset) + for _, c1 in ipairs(str.explode(firsts)) do + for __, c2 in ipairs(str.explode(seconds)) do + tab.subtable(tb, c1) + tb[c1][c2] = offset + end + end +end + +local function kern_classes (firsts, seconds, offsets, max) + local kerns = {} + for f, F in pairs (firsts) do + for s, S in pairs (seconds) do + local off = offsets[(f-1) * max + s] + if off then + kern_pairs (kerns, F, S, off) + end + end + end + return kerns +end + +local function apply_kerns (f, kerns, to_size) + local name_touni = f.name_to_unicode + to_size = to_size or 1 + for c1, ttb in pairs(kerns) do + for c2, off in pairs(ttb) do + tab.subtable(f.characters[name_touni[c1]], "kerns") + f.characters[name_touni[c1]].kerns[name_touni[c2]] = off * to_size + end + end +end + +function lookup_functions.gpos_pair (tb, f) + -- These are the big kern classes. + if tb.offsets then + local name_touni = f.name_to_unicode + for n, off in pairs(tb.offsets) do + tb.offsets[n] = off * f.to_size + end + local kerns = kern_classes(tb.firsts, tb.seconds, tb.offsets, tb.max) + apply_kerns(f, kerns) + end + -- These are the ones retrieved from individual glyphs. + if tb.kerns then + apply_kerns(f, tb.kerns, f.to_size) + end + return f +end + +function lookup_functions.gsub_contextchain (tb, f) + local name_touni = f.name_to_unicode + local T = f.contextchain or {} + for _, llk in ipairs(tb) do + if fontfile.lookups then + local sub, Sub = fontfile.lookups[llk].rules[1].lookups + local chain = fontfile.lookups[llk].rules[1].coverage + local cur, current = str.explode(chain.current[1]), {} + local aft, after = chain.after and str.explode(chain.after[1]) or {}, {} + for _, c in ipairs(cur) do + c = name_touni[c] + if sub then + Sub = {} + for n, x in ipairs(sub) do + Sub[n] = name_touni[fontfile.glyphs[f.characters[c].index].lookups[x .. "_s"][1].specification.variant] + end + end + local t = { lookup = Sub} + tab.subtable(T, C) + for __, a in ipairs(aft) do + tab.subtable(t, "after") + t.after[name_touni[a]] = true + end + tab.insert(T[c], t) + end + end + end + f.contextchain = T + return f +end + +local function _isactive (tb, ft, sc, lg) + for t in pairs(tb.tags) do + if ft[t] then + if t[sc] then + for _, lang in pairs(tb[sc]) do + if lang == lg then + return true + end + end + else + return true + end + end + end +end + + +local lookup_types = { + "gsub_single", + "gsub_ligature", + "gpos_pair" + } + +local function activate_lookups (font, features, script, lang) + for _, type in ipairs(lookup_types) do + if font.lookup_table and font.lookup_table[type] then + for l, tb in pairs(font.lookup_table[type]) do + if _isactive(tb, features, script, lang) then + for _, lk in ipairs(tb) do + local lt = font.lookups[lk] + if lt then + font = lookup_functions[type](lt, font) + end + end + end + end + end + end + return font +end + +local function load_font (name, size, id, done) + local loaded_font = lfs.find_file(name, "tfm") + if loaded_font then + loaded_font = fl.read_tfm(loaded_font, size) + else + local original = str.trim(str.match(name, "[^:]*")) + local family, mods, feats + family, name = str.extract(name, "([^/:]*)") + family = str.trim(family) + mods, name = str.extract(name, "[^:]*") + mods = lp.match(get_mods, mods) or {} + feats = str.extract(name, ":(.*)") or "" + local features = tab.copy(settings.features) + get_features(feats, features) + + local at_size + if features.size then + at_size = features.size + else + at_size = size + at_size = at_size > 0 and at_size or at_size * - 655.36 + at_size = at_size / 65536 + end + local source, lua, add_feats = is_font(family, mods, at_size) + if add_feats then get_features(add_feats, features) end + + if type(source) == "string" then + local cache = features.cache or "yes" + if lua then + if cache == "no" or cache == "rewrite" then + loaded_font = create_font(source, lfs.type(source), lua, features.font, cache == "rewrite") + else + loaded_font = dofile(lua) + end + else + lua = name_luafile(source, features.font) + loaded_font = create_font(source, lfs.type(source), lua, features.font, cache ~= "no") + end + else + if not done then + if type(source) == "number" then + wri.error("The library says `%s' matches `%s', but I can't find that file anywhere. Clean up your library!", original, lua) + else + recheck_fonts() + return load_font(original, size, id, true) + end + else + wri.error("I can't find `%s'. I return a default font to avoid further errors.", original) + end + end + + if loaded_font then + + local expansion = features.expansion and str.explode(features.expansion) or {} + loaded_font.stretch = expansion[1] or 0 + loaded_font.shrink = expansion[2] or 0 + loaded_font.step = expansion[3] or 0 + + local extend = features.extend or 1 + loaded_font.extend = extend * 1000 + local slant + if features.absoluteslant then + local italic = loaded_font.italicangle or 0 + slant = features.absoluteslant - italic + else + slant = features.slant or 0 + end + loaded_font.slant = num.tan(num.rad(slant)) * 1000 + + loaded_font = apply_size(loaded_font, size, features.letterspacing, features.space) + loaded_font = activate_lookups(loaded_font, features, features.script, features.lang) + + loaded_font.name = loaded_font.name .. id + loaded_font.fullname = loaded_font.fullname .. id + local embedding = features.embedding or "subset" + if embedding ~= "no" and embedding ~= "subset" and embedding ~= "full" then + wri.error("Invalid value `%s' for the `embedding' feature. Value should be `no', `subset' or `full'.", embedding) + embedding = "subset" + end + loaded_font.embedding = embedding + else + loaded_font = fl.read_tfm(lfs.find_file("cmr10", "tfm"), size) + end + end + return loaded_font +end + +callback.register("define_font", load_font) diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex new file mode 100644 index 00000000000..adf4622fe58 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex @@ -0,0 +1,308 @@ +\inputltcfile blot-fonts.lua +\pdfadjustspacing=2 + +\def\currentfont{} +\def\currentsize{normal} +\def\currentstyle{rm} +\def\currentweight{rg} +\def\currentcase{lc} +\def\makecurrentfont{% + \csname\currentfont @\currentsize @\currentstyle @\currentweight @\currentcase\endcsname + } +\def\normalsize{% + \def\currentsize{normal}% + \makecurrentfont + } +\def\small{% + \def\currentsize{small}% + \makecurrentfont + } +\def\verysmall{% + \def\currentsize{verysmall}% + \makecurrentfont + } +\def\smaller{% + \passexpanded\ifstring\currentsize{normal}% + {\def\currentsize{small}} + {\def\currentsize{verysmall}} + \makecurrentfont + } +\def\big{% + \def\currentsize{big}% + \makecurrentfont + } +\def\verybig{% + \def\currentsize{verybig}% + \makecurrentfont + } +\def\bigger{% + \passexpanded\ifstring\currentsize{normal}% + {\def\currentsize{big}} + {\def\currentsize{verybig}} + \makecurrentfont + } +\def\it{% + \def\currentstyle{it}% + \makecurrentfont + } +\def\rm{% + \def\currentstyle{rm}% + \makecurrentfont + } +\def\rmstring{rm} +\def\emph{% + \ifx\currentstyle\rmstring + \expandafter\ital + \else + \expandafter\rom + \fi + } +\def\bf{% + \def\currentweight{bf}% + \makecurrentfont + } +%\def\normalweight{% +\def\rg{% + \def\currentweight{rg}% + \makecurrentfont + } +\def\sc{% + \def\currentcase{sc}% + \makecurrentfont + } +%\def\normalcase{% +\def\lc{% + \def\currentcase{lc}% + \makecurrentfont + } +\freedef\ital{{\it#1}} +\freedef\bold{{\bf#1}} +\freedef\scap{{\sc#1}} +\freedef\rom{{\rm#1}} + + +\restrictparameter font : + command % The command to be used to switch to that font. + name % Actually the part common to all files' names for that font. + size % Well, the size. + small % Smaller size. + verysmall % Smaller yet. + big % Bigger. + verybig % Insanely big. + bold % Modifier for bold font. + italic % Modifier for italic font. + math % If set to "true", then used for math font. + % small, verysmall and italic should be specified + % (which shows I don't use it very often). + features % Font features (e.g. +onum, etc.). + slant % A number representing an angle, loading an italic + % font if no real italic is a available. + slantsc % The same, for small caps. + +% The font parameter should disappear some day, it's clumsy. +\def\setfont#1:{% + \setparameter font : command = #1% + } + +\setparameter metafont : % No relation :) + size = 10pt + bold = Bold + italic = Italic + features = "+onum; +liga; +trep; +tlig; expansion=30 20 5;" + +\setparameter font : + meta = metafont + +\newdimen\ptx@fontsize +\luacode +ptx_fonts = {} +function ptx_getfont(Font, ...) + if ptx_fonts[Font] then + local tempfont = ptx_fonts[Font] + for _, style in ipairs(arg) do + if ptx_getstyle[style] then + tempfont = tempfont:gsub("(%w+)@(%w+)@(%w+)@(%w+)@(%w+)",ptx_getstyle[style]) + else + tempfont = nil + texio.write_nl("! PiTeX error: Unknown font style `style'.") + return Font + end + end + return font.id(tempfont) + else + texio.write_nl("! PiTeX error: " .. Font .. " is not a PiTeX font. It can't be changed.") + end +end +ptx_getstyle = { + normal = "%1@normal@%3@%4@%5", + small = "%1@small@%3@%4@%5", + verysmall = "%1@verysmall@%3@%4@%5", + big = "%1@big@%3@%4@%5", + verybig = "%1@verybig@%3@%4@%5", + rm = "%1@%2@rm@%4@%5", + it = "%1@%2@it@%4@%5", + rg = "%1@%2@%3@rg@%5", + bf = "%1@%2@%3@bf@%5", + lc = "%1@%2@%3@%4@lc", + sc = "%1@%2@%3@%4@sc" + } +\luacode/ + +\newstring{+} \newstring{-} +\def\ptx@dofont#1#2#3#4#5{% + \edef\ptx@temp{\passvaluenobraces\commandtoname font : command }% + \ifexpression{ -\ifstring{#4}{normal} & { \ifprefix-{#5} | \ifprefix+{#5} } } + {\def\ptx@dofont_size{\dimexpr\usevalue font : size + #5\relax}} + {\def\ptx@dofont_size{#5}}% + \ptx@dofont_load{\ptx@temp @#4@#1@#2@lc}{#3}{}{\ptx@dofont_size}% + \ifstring{#1}{rm} + {\ptx@dofont_load{\ptx@temp @#4@#1@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}% + \ifattribute font : slant % Loading a slanted version of the font if no italic was given + {\ptx@dofont_load{\ptx@temp @#4@it@#2@lc}{#3}{slant=\usevalue font: slant ;}{\ptx@dofont_size} + \ifattribute font : slantsc {} + {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slant ;}{\ptx@dofont_size}}}{}% + \ifattribute font : slantsc + {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slantsc ;}{\ptx@dofont_size}}{}}% + {\ifattribute font : slantsc {}{\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}}} + } + +\def\ptx@dofont_load#1#2#3#4{% + \passcs\font{#1}="\usevalue font : name #2:#3\usevalue font : features " at #4\relax + \ptx@lua{ptx_fonts[font.id("#1")] = "#1"}% + } + + + +\def\dofont#1#2#3{% + \passvalue{\ptx@dofont{#1}{#2}{#3}{normal}} font : size + \passvalue{\ptx@dofont{#1}{#2}{#3}{small}} font : small + \passvalue{\ptx@dofont{#1}{#2}{#3}{verysmall}} font : verysmall + \passvalue{\ptx@dofont{#1}{#2}{#3}{big}} font : big + \passvalue{\ptx@dofont{#1}{#2}{#3}{verybig}} font : verybig +% + \ifvalue font : math = true + {\ifstring{#1#2}{rmrg} + {\passcs{\textfont0=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont0=}{\passvalue\commandtoname font : command @small@#1@#2@lc}% + \passcs{\scriptscriptfont0=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc} + \passcs{\textfont2=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont2=}{\passvalue\commandtoname font : command @small@#1@#2@lc}% + \passcs{\scriptscriptfont2=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}} + {\iffstring{#1#2}{itrg} + {\passcs{\textfont1=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}% + \passcs{\scriptscriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}}}% + }{}% + } + +\gates new \FontLoader {FontLoader} +\FontLoader list {fontloader} + [fl_command] + {% + \passvaluenobraces\edef font : command {% + \def\noexpand\currentfont{\passvalue\commandtoname font : command }% + \noexpand\makecurrentfont}} + (fl_load) + . ( fl_roman ) + . . [ fl_doromanregular ] + {\dofont{rm}{rg}{}} + . . [ fl_doromanbold ] ? {conditional = -\ifvalue font : bold = none } + {\dofont{rm}{bf}{/\usevalue font : bold }} + . ( fl_italic ) ? {conditional = -\ifvalue font : italic = none } + . . [ fl_doitalicregular ] + {\dofont{it}{rg}{/\usevalue font : italic }} + . . [ fl_doitalicbold ] ? {conditional = -\ifvalue font : bold = none } + {\dofont{it}{bf}{/\usevalue font : italic /\usevalue font : bold }} + [fl_use] ? {conditional = \ifvalue font : command = {\mainfont} } + {\mainfont} + (fl_post) + . [fl_delete] + {\deleteparameter font:} + . [fl_meta] + {\setattribute font : meta = metafont } + +\defactiveparameter font {% + \FontLoader execute {fontloader}% + } + + + + + + + +\long\def\color#1#2{% + \pdfcolorstack0 push {#1 rg #1 RG}% + #2% + \pdfcolorstack0 pop% + } + +\newattribute\ptx@underline_attribute +\luacode +local do_underline = function (head,order,ratio,sign) + local item, leader = head, false + while item do + leader = false + if node.has_attribute(item,\attributenumber\ptx@underline_attribute) + and not (item.id == 10 and (item.subtype == 8 or item.subtype == 9)) then + local item_line = node.new(2) + item_line.depth = tex.sp("1.4pt") + item_line.height = tex.sp("-1pt") + if node.has_field(item,"spec") then + item_line.width = item.spec.width + if order == 0 then + if sign == 1 then + item_line.width = item_line.width + ratio * item.spec.stretch + else + item_line.width = item_line.width - ratio * item.spec.shrink + end + else + if item.spec.stretch_order > 0 or item.spec.shrink_order > 0 then + lualog(item.spec.stretch_order) + item_line.width = 1 + item.subtype = 100 + item.leader = item_line + leader = true + end + end + elseif node.has_field(item,"width") then + item_line.width = item.width + elseif node.has_field(item,"kern") then + item_line.width = item.kern + end + if leader then + item = item.next + else + local item_kern = node.new(11) + item_kern.kern = -item_line.width + node.insert_after(head,item,item_line) + node.insert_after(head,item,item_kern) + item = item_line.next + end + else + item = item.next + end + end +end +pitex.misc.underline = function (head) + for line in node.traverse_id(0,head) do + do_underline(line.list,line.glue_order,line.glue_set,line.glue_sign) + end + return head +end +pitex.callback.register("post_linebreak_filter", "pitex.misc:underline") +pitex.callback.close("pitex.misc:underline", "post_linebreak_filter") +\luacode/ + +\freedef\underline{% + \ptx@lua{% + pitex.callback.ajar("pitex:underline", "post_linebreak_filter") + } +% local plf = callback.list_functions("post_linebreak_filter") +% if not plf or not plf["underline"] then +% callback.add_function(underline, "underline", "post_linebreak_filter") +% end}% + \quitvmode % Otherwise it might also underline the indentation box. + \ptx@underline_attribute=0\relax + #1\unsetattribute\ptx@underline_attribute + } diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex new file mode 100644 index 00000000000..f00e58c9d41 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex @@ -0,0 +1,26 @@ +\def\inputltcfile#1 {\directlua{dofile(kpse.find_file("#1"))}} + +\inputltcfile blot-base.lua + +\def\ptx@lua{\directlua name {Internal PiTeX chunk}} + +\newcatcodetable\luacatcodes{\#\%\^^M\~=12} +\newtoks\ptx@luacode_list +\newif\ifptx@luacode_store +% Mimicks a block (\newblock isn't defined yet +% and anyway it wouldn't be very useful). +\def\luacode{% + \begingroup + \catcodetable\luacatcodes + \ifnext[ + {\ptx@luacode_store} + {\ptx@luacode_store[]}} +\bgroup +\setcatcodes{\^^M=12}% +\long\gdef\ptx@luacode_store[#1]^^M#2\luacode/{% So line count is right. + \endgroup% + \ifemptystring{#1}% + {\ptx@lua{#2}}% + {\def#1{#2}}% + }% +\egroup diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua new file mode 100644 index 00000000000..5c24caa9378 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua @@ -0,0 +1,19 @@ +return { + + features = { + kern = true, + liga = true, + trep = true, + tlig = true, + script = "latn", + lang = "dflt", + --stretch = 30, + --shrink = 20, + --step = 10, + }, + + normal = { + "Normal", "Regular", "Book", + }, + +} diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot.tex b/Master/texmf-dist/tex/luatex/blopentype/blot.tex new file mode 100644 index 00000000000..44a89e553ef --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot.tex @@ -0,0 +1,254 @@ +% blopentype: a basic luatex open type loader +% +% some (most) pitex macros still in place.- 30.12.2022 +% +% User interface +% +\message{This is blopentype, v0.0.0 December 2022} + +\input luatex85.sty % deprecated 30.12.2022 +\input yax % which itself \input's texapi +\input gates + +\setcatcodes{\@\_=11} +\suppressoutererror=1 + +% MESSAGES +\def\ptx@error{\senderror{PiTeX}} +\def\ptx@log#1{% + \immediate\write17{^^J#1^^J}% + } +\def\ptx@warn#1{% + \ptx@log{PiTeX warning: #1}% + } + +% ATTRIBUTES +\newcount\ptx@attribute_count +\ptx@attribute_count=100 % The first 100 attributes are scratch. +\def\newattribute#1{% + \advance\ptx@attribute_count1 + \attributedef#1=\ptx@attribute_count + \xdefcs{ptx@attribute:\commandtoname#1}{\the\ptx@attribute_count}% + } +\def\unsetattribute#1{#1=-"7FFFFFFF\relax} +\def\attributenumber#1{\usecs{ptx@attribute:\commandtoname#1}} + +% FREEDEF +\def\freedef#1{% + \def#1{% + \ifnextnospace" + {\ptx@freedef_quote#1} + {\ifnextnospace/ + {\ptx@freedef_slash#1} + {\usecs{ptx@freedef_user:\commandtoname#1}}}% + }% + \defcs{ptx@freedef_user:\commandtoname#1}##1% + } +\def\ptx@freedef_quote#1"#2"{% + \usecs{ptx@freedef_user:\commandtoname#1}{#2}% + } +\def\ptx@freedef_slash#1/#2/{% + \usecs{ptx@freedef_user:\commandtoname#1}{#2}% + } + + +\newbox\ptx@box_temp + +\newif\ifmaintext +\maintexttrue + +% CATCODE TABLES +\newcount\ptx@catcodetable_count +\ptx@catcodetable_count=100 % First 100 are scratch. +\def\newcatcodetable#1#2{% + \global\advance\ptx@catcodetable_count1 + \chardef#1=\ptx@catcodetable_count + \begingroup + \setcatcodes{#2}% + \savecatcodetable#1% + \endgroup + } + +\newcatcodetable\texcatcodes{\@\_=12} + +\def\inputltmfile#1 {\input #1.tex } + +\inputltmfile blot-lua +\inputltmfile blot-files +\inputltmfile blot-fonts +\restorecatcodes +\endinput +% +% the remaining macros are leftovers from PiTeX, awaiting removal.- 30.12.2022 +% +% +\inputltmfile sections +\inputltmfile blocks +\inputltmfile references +\inputltmfile verbatim +\inputltmfile inserts +\inputltmfile output +\input navigator.tex + +% AUXILIARY FILE +\iffile{\jobname.aux}{% + \ptx@lua{% + remove_conversion() + tex.print("\luaescapestring{\noexpand\input\noexpand\jobname.aux}") + }% + \directlua{restore_conversion()}} +\immediate\openout\ptx@auxfile=\jobname.aux + +% PDF SETTINGS +\restrictparameter document : author title pdftitle date pdfdate subject keywords mode layout version\par +\restrictattribute document : mode outlines bookmarks thumbs thumbnails attachments files oc\par +\restrictattribute document : layout onepage onecolumn twopage twocolumn twopage* twocolumn*\par + +\suppressoutererror=1 +\let\ptx@bye\bye +\def\bye{% + \passvalueand{\setattribute navigator : title = } document : pdftitle { }{} + % The "date" attribute in the "document" parameter isn't supposed to hold a + % PDF-date, as navigator expects. + \deleteattribute document : date + \passvalueand{\setattribute navigator : date = } document : pdfdate { }{} + \finishpdffile\ptx@bye + } + +\setattribute navigator : meta = document + +% Turns a dimen into PostScript points, without the unit (as wanted by PDF). +\def\pdfpoint#1{% + \directlua{% + local d = "\the\dimexpr#1" + d = string.gsub(d, "pt", "") + tex.print(tostring(d * (72/72.27))) + }} + + + + +% TEX SETTINGS +\long\def\ptx@tex_set#1#2#3{% + \ifcs{#2} + {\usecs{#2}=#3\relax} + {\ptx@error{No TeX parameter `#2'}} + } + +\defactiveparameter tex {% + \parameterloop #1 : \ptx@tex_set + } + +\frenchspacing +\maxdepth=\maxdimen + +\def\antigobblespace{% + \ifcatnext a{ }{\iffnext({ }}% + } + +\def\strut#1#2{% + \vrule height#1 depth#2 width0pt + } + +\newdimen\extraboxspace +\newdimen\ptx@extraboxspace_top +\newdimen\ptx@extraboxspace_right +\newdimen\ptx@extraboxspace_bottom +\newdimen\ptx@extraboxspace_left + +\newfornoempty\ptx@colorbox_loop{1}#2,{% + \ifcase#1 + \ptx@extraboxspace_top =#2 + \ptx@extraboxspace_right =#2 + \ptx@extraboxspace_bottom =#2 + \ptx@extraboxspace_left =#2 + \or + \ptx@extraboxspace_right =#2 + \ptx@extraboxspace_left =#2 + \or + \ptx@extraboxspace_bottom =#2 + \or + \ptx@extraboxspace_left =#2 + \fi + \passarguments{\numexpr(#1+1)}% + } +\def\colorbox{% + \ifnextnospace[\ptx@colorbox_setborders + {\ptx@extraboxspace_top =\extraboxspace + \ptx@extraboxspace_right =\extraboxspace + \ptx@extraboxspace_bottom =\extraboxspace + \ptx@extraboxspace_left =\extraboxspace + \ptx@colorbox_do}% + } +\def\ptx@colorbox_setborders[#1]{% + \ptx@colorbox_loop{0}{#1,}% + \ptx@colorbox_do + } +{\setcatcodes{pt=12} +\gdef\noPT#1pt{#1 }} +\def\ptx@colorbox_do#1#2{% + \bgroup + \setbox\ptx@box_temp=\hbox{#2}% + \hbox{% + \pdfliteral{ + q #1 rg #1 RG + -\expandafter\noPT\the\ptx@extraboxspace_left + \expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top)\relax + \expandafter\noPT\the\dimexpr(\wd\ptx@box_temp+\ptx@extraboxspace_left+\ptx@extraboxspace_right)\relax + -\expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top+\dp\ptx@box_temp+\ptx@extraboxspace_bottom)\relax + re f Q}% + #2}% + \egroup + } + +\def\og{\char"00AB~} \def\fg{~\char"00BB\antigobblespace} + +\def\trace{\tracingcommands3 \tracingmacros2 } +\def\untrace{\tracingcommands0 \tracingmacros0 } + +\restorecatcodes + +\endinput +% +% These are leftovers from Isambert's code: they'll be removed as +% documentation improved.- 30.12.2022 +% +% This is piTeX, a set of macros I (Paul Isambert) use to +% typeset documentations for my packages (that's why it is +% archived on CTAN). +% +% Perhaps in the future, when this achieves some kind of +% format-like completude, it'll be publicly announced. In the +% meanwhile, a documentation exists (pitex-doc.pdf, also readable +% in a text editor as pitex-doc.txt). +% +% +% You can of course use those macros, but you are on your +% own, and the files will probably be modified without announcement. +% The file is supposed to be \input on plain TeX with LuaTeX, at least v.0.6. +% +% +% The files needed are: +% +% texapi.tex (an independent package for programming) +% yax.tex (an independent package for key=value interface) +% gates.tex and gates.lua (an independant package for overall architecture) +% navigator.tex (an independant package for PDF features) +% lua.ptx and base.ptxlua (Lua side) +% files.ptx (file management) +% fonts.ptx, fonts.ptxlua and foundry-settings.lua +% (fonts, should be independant some day; actually +% fonts.ptxlua can be used independantly, but there is +% no doc) +% sections.ptx (sectionning commands) +% blocks.ptx (text blocks) +% references.ptx (labels and references) +% verbatim.ptx (typesetting verbatim) +% inserts.ptx (footnotes and figures, a mess) +% output.ptx (output routine) +% +% The file i-pitex.lua is needed only to typeset the documentation with the +% Interpreter package. +% +% +% Date: November 2011. |