texlive[48594] Build/source/texk/web2c/luatexdir: luatex: correct
commits+lscarso at tug.org
commits+lscarso at tug.org
Wed Sep 5 23:57:30 CEST 2018
Revision: 48594
http://tug.org/svn/texlive?view=revision&revision=48594
Author: lscarso
Date: 2018-09-05 23:57:30 +0200 (Wed, 05 Sep 2018)
Log Message:
-----------
luatex: correct automake file for pplib; replaced cweb files with c files.
Added Paths:
-----------
trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am
trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
trunk/Build/source/texk/web2c/luatexdir/font/dofont.c
trunk/Build/source/texk/web2c/luatexdir/font/luafont.c
trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c
trunk/Build/source/texk/web2c/luatexdir/font/pkin.c
trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c
trunk/Build/source/texk/web2c/luatexdir/font/subfont.c
trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c
trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c
trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c
trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c
trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c
trunk/Build/source/texk/web2c/luatexdir/font/writecff.c
trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c
trunk/Build/source/texk/web2c/luatexdir/font/writefont.c
trunk/Build/source/texk/web2c/luatexdir/font/writet1.c
trunk/Build/source/texk/web2c/luatexdir/font/writet3.c
trunk/Build/source/texk/web2c/luatexdir/font/writettf.c
trunk/Build/source/texk/web2c/luatexdir/font/writetype0.c
trunk/Build/source/texk/web2c/luatexdir/font/writetype2.c
trunk/Build/source/texk/web2c/luatexdir/image/pdftoepdf.c
trunk/Build/source/texk/web2c/luatexdir/image/writeimg.c
trunk/Build/source/texk/web2c/luatexdir/image/writejbig2.c
trunk/Build/source/texk/web2c/luatexdir/image/writejp2.c
trunk/Build/source/texk/web2c/luatexdir/image/writejpg.c
trunk/Build/source/texk/web2c/luatexdir/image/writepng.c
trunk/Build/source/texk/web2c/luatexdir/lang/hnjalloc.c
trunk/Build/source/texk/web2c/luatexdir/lang/hyphen.c
trunk/Build/source/texk/web2c/luatexdir/lang/texlang.c
trunk/Build/source/texk/web2c/luatexdir/lua/helpers.c
trunk/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
trunk/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
trunk/Build/source/texk/web2c/luatexdir/lua/luainit.c
trunk/Build/source/texk/web2c/luatexdir/lua/luanode.c
trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.c
trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c
trunk/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
trunk/Build/source/texk/web2c/luatexdir/lua/texluac.c
trunk/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdffont.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfimage.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfobj.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfrule.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfxform.c
trunk/Build/source/texk/web2c/luatexdir/tex/align.c
trunk/Build/source/texk/web2c/luatexdir/tex/arithmetic.c
trunk/Build/source/texk/web2c/luatexdir/tex/backend.c
trunk/Build/source/texk/web2c/luatexdir/tex/backend.h
trunk/Build/source/texk/web2c/luatexdir/tex/buildpage.c
trunk/Build/source/texk/web2c/luatexdir/tex/commands.c
trunk/Build/source/texk/web2c/luatexdir/tex/conditional.c
trunk/Build/source/texk/web2c/luatexdir/tex/directions.c
trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c
trunk/Build/source/texk/web2c/luatexdir/tex/errors.c
trunk/Build/source/texk/web2c/luatexdir/tex/expand.c
trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c
trunk/Build/source/texk/web2c/luatexdir/tex/filename.c
trunk/Build/source/texk/web2c/luatexdir/tex/inputstack.c
trunk/Build/source/texk/web2c/luatexdir/tex/linebreak.c
trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c
trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
trunk/Build/source/texk/web2c/luatexdir/tex/mathcodes.c
trunk/Build/source/texk/web2c/luatexdir/tex/memoryword.c
trunk/Build/source/texk/web2c/luatexdir/tex/mlist.c
trunk/Build/source/texk/web2c/luatexdir/tex/nesting.c
trunk/Build/source/texk/web2c/luatexdir/tex/packaging.c
trunk/Build/source/texk/web2c/luatexdir/tex/postlinebreak.c
trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c
trunk/Build/source/texk/web2c/luatexdir/tex/printing.c
trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c
trunk/Build/source/texk/web2c/luatexdir/tex/stringpool.c
trunk/Build/source/texk/web2c/luatexdir/tex/texdeffont.c
trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c
trunk/Build/source/texk/web2c/luatexdir/tex/texmath.c
trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c
trunk/Build/source/texk/web2c/luatexdir/tex/textcodes.c
trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c
trunk/Build/source/texk/web2c/luatexdir/utils/avlstuff.c
trunk/Build/source/texk/web2c/luatexdir/utils/managed-sa.c
trunk/Build/source/texk/web2c/luatexdir/utils/unistring.c
trunk/Build/source/texk/web2c/luatexdir/utils/utils.c
Removed Paths:
-------------
trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
trunk/Build/source/texk/web2c/luatexdir/font/dofont.w
trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w
trunk/Build/source/texk/web2c/luatexdir/font/pkin.w
trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w
trunk/Build/source/texk/web2c/luatexdir/font/subfont.w
trunk/Build/source/texk/web2c/luatexdir/font/texfont.w
trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w
trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w
trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w
trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w
trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w
trunk/Build/source/texk/web2c/luatexdir/font/writecff.w
trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w
trunk/Build/source/texk/web2c/luatexdir/font/writefont.w
trunk/Build/source/texk/web2c/luatexdir/font/writet1.w
trunk/Build/source/texk/web2c/luatexdir/font/writet3.w
trunk/Build/source/texk/web2c/luatexdir/font/writettf.w
trunk/Build/source/texk/web2c/luatexdir/font/writetype0.w
trunk/Build/source/texk/web2c/luatexdir/font/writetype2.w
trunk/Build/source/texk/web2c/luatexdir/image/pdftoepdf.w
trunk/Build/source/texk/web2c/luatexdir/image/writeimg.w
trunk/Build/source/texk/web2c/luatexdir/image/writejbig2.w
trunk/Build/source/texk/web2c/luatexdir/image/writejp2.w
trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w
trunk/Build/source/texk/web2c/luatexdir/image/writepng.w
trunk/Build/source/texk/web2c/luatexdir/lang/hnjalloc.w
trunk/Build/source/texk/web2c/luatexdir/lang/hyphen.w
trunk/Build/source/texk/web2c/luatexdir/lang/texlang.w
trunk/Build/source/texk/web2c/luatexdir/lua/helpers.w
trunk/Build/source/texk/web2c/luatexdir/lua/llfslibext.c
trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w
trunk/Build/source/texk/web2c/luatexdir/lua/luanode.w
trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w
trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.w
trunk/Build/source/texk/web2c/luatexdir/lua/mplibstuff.w
trunk/Build/source/texk/web2c/luatexdir/lua/texluac.w
trunk/Build/source/texk/web2c/luatexdir/lua/texluajitc.w
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua
trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdffont.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w
trunk/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w
trunk/Build/source/texk/web2c/luatexdir/tex/align.w
trunk/Build/source/texk/web2c/luatexdir/tex/arithmetic.w
trunk/Build/source/texk/web2c/luatexdir/tex/buildpage.w
trunk/Build/source/texk/web2c/luatexdir/tex/commands.w
trunk/Build/source/texk/web2c/luatexdir/tex/conditional.w
trunk/Build/source/texk/web2c/luatexdir/tex/directions.w
trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.w
trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.w
trunk/Build/source/texk/web2c/luatexdir/tex/errors.w
trunk/Build/source/texk/web2c/luatexdir/tex/expand.w
trunk/Build/source/texk/web2c/luatexdir/tex/extensions.w
trunk/Build/source/texk/web2c/luatexdir/tex/filename.w
trunk/Build/source/texk/web2c/luatexdir/tex/inputstack.w
trunk/Build/source/texk/web2c/luatexdir/tex/linebreak.w
trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.w
trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.w
trunk/Build/source/texk/web2c/luatexdir/tex/mathcodes.w
trunk/Build/source/texk/web2c/luatexdir/tex/memoryword.w
trunk/Build/source/texk/web2c/luatexdir/tex/mlist.w
trunk/Build/source/texk/web2c/luatexdir/tex/nesting.w
trunk/Build/source/texk/web2c/luatexdir/tex/packaging.w
trunk/Build/source/texk/web2c/luatexdir/tex/postlinebreak.w
trunk/Build/source/texk/web2c/luatexdir/tex/primitive.w
trunk/Build/source/texk/web2c/luatexdir/tex/printing.w
trunk/Build/source/texk/web2c/luatexdir/tex/scanning.w
trunk/Build/source/texk/web2c/luatexdir/tex/stringpool.w
trunk/Build/source/texk/web2c/luatexdir/tex/texdeffont.w
trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.w
trunk/Build/source/texk/web2c/luatexdir/tex/texmath.w
trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.w
trunk/Build/source/texk/web2c/luatexdir/tex/textcodes.w
trunk/Build/source/texk/web2c/luatexdir/tex/textoken.w
trunk/Build/source/texk/web2c/luatexdir/utils/avlstuff.w
trunk/Build/source/texk/web2c/luatexdir/utils/managed-sa.w
trunk/Build/source/texk/web2c/luatexdir/utils/unistring.w
trunk/Build/source/texk/web2c/luatexdir/utils/utils.w
Added: trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,86 @@
+## texk/web2c/luatexdir/am/luapplib.am: Makefile fragment for libluapplib.
+##
+## Copyright (C) 2018 Luigi Scarso <tex-live at tug.org>
+## You may freely use, modify and/or distribute this file.
+
+## luapplib
+##
+EXTRA_LIBRARIES += libluapplib.a liblua53pplib.a libluajitpplib.a
+
+libluapplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+liblua53pplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+libluajitpplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+
+$(libluapplib_a_OBJECTS): $(LUA_DEPEND)
+$(liblua53pplib_a_OBJECTS): $(LUA_DEPEND)
+$(libluajitpplib_a_OBJECTS): $(LUAJIT_DEPEND)
+
+## replace -I../../libs/zlib/include $(ZLIB_INCLUDES)
+
+libluapplib_a_CPPFLAGS = \
+ -I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUA_INCLUDES)
+
+liblua53pplib_a_CPPFLAGS = \
+ -I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUA_LUA53_INCLUDES)
+
+libluajitpplib_a_CPPFLAGS = \
+ -I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUAJIT_INCLUDES)
+
+libluapplib_a_CFLAGS = # $(WARNING_CFLAGS)
+libluajitpplib_a_CFLAGS = # $(WARNING_CFLAGS)
+
+nodist_libluapplib_a_SOURCES = $(libluapplib_sources)
+nodist_liblua53pplib_a_SOURCES = $(libluapplib_sources)
+nodist_libluajitpplib_a_SOURCES = $(libluapplib_sources)
+
+libluapplib_sources = \
+ luatexdir/luapplib/ppapi.h \
+ luatexdir/luapplib/pparray.c \
+ luatexdir/luapplib/pparray.h \
+ luatexdir/luapplib/ppconf.h \
+ luatexdir/luapplib/ppcrypt.c \
+ luatexdir/luapplib/ppcrypt.h \
+ luatexdir/luapplib/ppdict.c \
+ luatexdir/luapplib/ppdict.h \
+ luatexdir/luapplib/ppfilter.h \
+ luatexdir/luapplib/ppheap.c \
+ luatexdir/luapplib/ppheap.h \
+ luatexdir/luapplib/pplib.h \
+ luatexdir/luapplib/ppload.c \
+ luatexdir/luapplib/ppload.h \
+ luatexdir/luapplib/ppstream.c \
+ luatexdir/luapplib/ppstream.h \
+ luatexdir/luapplib/ppxref.c \
+ luatexdir/luapplib/ppxref.h \
+ luatexdir/luapplib/util/utilbasexx.c \
+ luatexdir/luapplib/util/utilbasexx.h \
+ luatexdir/luapplib/util/utilcrypt.c \
+ luatexdir/luapplib/util/utilcrypt.h \
+ luatexdir/luapplib/util/utilcryptdef.h \
+ luatexdir/luapplib/util/utildecl.h \
+ luatexdir/luapplib/util/utilflate.c \
+ luatexdir/luapplib/util/utilflate.h \
+ luatexdir/luapplib/util/utilfpred.c \
+ luatexdir/luapplib/util/utilfpred.h \
+ luatexdir/luapplib/util/utiliof.c \
+ luatexdir/luapplib/util/utiliof.h \
+ luatexdir/luapplib/util/utillog.c \
+ luatexdir/luapplib/util/utillog.h \
+ luatexdir/luapplib/util/utillzw.c \
+ luatexdir/luapplib/util/utillzw.h \
+ luatexdir/luapplib/util/utilmd5.c \
+ luatexdir/luapplib/util/utilmd5.h \
+ luatexdir/luapplib/util/utilmem.c \
+ luatexdir/luapplib/util/utilmem.h \
+ luatexdir/luapplib/util/utilnumber.c \
+ luatexdir/luapplib/util/utilnumber.h \
+ luatexdir/luapplib/util/utilplat.h \
+ luatexdir/luapplib/util/utilsha.c \
+ luatexdir/luapplib/util/utilsha.h \
+ luatexdir/luapplib/zlib/zconf.h \
+ luatexdir/luapplib/zlib/zlib.h
+
+
+
+liblua53pplib_sources = $(libluapplib_sources)
+libluajitpplib_sources = $(libluapplib_sources)
Added: trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1558 @@
+/*
+
+dvigen.w
+
+Copyright 2009-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#undef write_dvi
+
+/*tex This is the current mode: */
+
+#define mode cur_list.mode_field
+
+/*tex
+
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules are to
+appear on printed pages. The form of these files was designed by David R. Fuchs
+in 1979. Almost any reasonable typesetting device can be driven by a program that
+takes \.{DVI} files as input, and dozens of such \.{DVI}-to-whatever programs
+have been written. Thus, it is possible to print the output of \TeX\ on many
+different kinds of equipment, using \TeX\ as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a series of
+commands in a machine-like language. The first byte of each command is the
+operation code, and this code is followed by zero or more bytes that provide
+parameters to the command. The parameters themselves may consist of several
+consecutive bytes; for example, the `|set_rule|' command has two parameters, each
+of which is four bytes long. Parameters are usually regarded as nonnegative
+integers; but four-byte-long parameters, and shorter parameters that denote
+distances, can be either positive or negative. Such parameters are given in two's
+complement notation. For example, a two-byte-long distance parameter has a value
+between $-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy more
+than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one or more
+``pages,'' followed by a ``postamble.'' The preamble is simply a |pre| command,
+with its parameters that define the dimensions used in the file; this must come
+first. Each ``page'' consists of a |bop| command, followed by any number of other
+commands that tell where characters are to be placed on a physical page, followed
+by an |eop| command. The pages appear in the order that \TeX\ generated them. If
+we ignore |nop| commands and \\{fnt\_def} commands (which are allowed between any
+two commands in the file), each |eop| command is immediately followed by a |bop|
+command, or by a |post| command; in the latter case, there are no more pages in
+the file, and the remaining bytes form the postamble. Further details about the
+postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file; the
+first byte is number~0, then comes number~1, and so on. For example, one of the
+parameters of a |bop| command points to the previous |bop|; this makes it
+feasible to read the pages in backwards order, in case the results are being
+directed to a device that stacks its output face up. Suppose the preamble of a
+\.{DVI} file occupies bytes 0 to 99. Now if the first page occupies bytes 100 to
+999, say, and if the second page occupies bytes 1000 to 1999, then the |bop| that
+starts in byte 1000 points to 100 and the |bop| that starts in byte 2000 points
+to 1000. (The very first |bop|, i.e., the one starting in byte 100, has a pointer
+of~$-1$.)
+
+The \.{DVI} format is intended to be both compact and easily interpreted by a
+machine. Compactness is achieved by making most of the information implicit
+instead of explicit. When a \.{DVI}-reading program reads the commands for a
+page, it keeps track of several quantities: (a)~The current font |f| is an
+integer; this value is changed only by \\{fnt} and \\{fnt\_num} commands. (b)~The
+current position on the page is given by two numbers called the horizontal and
+vertical coordinates, |h| and |v|. Both coordinates are zero at the upper left
+corner of the page; moving to the right corresponds to increasing the horizontal
+coordinate, and moving down corresponds to increasing the vertical coordinate.
+Thus, the coordinates are essentially Cartesian, except that vertical directions
+are flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The current
+spacing amounts are given by four numbers |w|, |x|, |y|, and |z|, where |w|
+and~|x| are used for horizontal spacing and where |y| and~|z| are used for
+vertical spacing. (d)~There is a stack containing |(h,v,w,x,y,z)| values; the
+\.{DVI} commands |push| and |pop| are used to change the current level of
+operation. Note that the current font~|f| is not pushed and popped; the stack
+contains only information about positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up to
+32 bits, including the sign. Since they represent physical distances, there is a
+small unit of measurement such that increasing |h| by~1 means moving a certain
+tiny distance to the right. The actual unit of measurement is variable, as
+explained below; \TeX\ sets things up so that its \.{DVI} output is in sp units,
+i.e., scaled points, in agreement with all the |scaled| dimensions in \TeX's data
+structures.
+
+Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte (e.g.,
+139), and its parameters (if any). The parameters are followed by a bracketed
+number telling how many bytes they occupy; for example, `|p[4]|' means that
+parameter |p| is four bytes long.
+
+\startitemize
+
+\startitem
+ |set_char_0| 0. Typeset character number~0 from font~|f| such that the
+ reference point of the character is at |(h,v)|. Then increase |h| by the
+ width of that character. Note that a character may have zero or negative
+ width, so one cannot be sure that |h| will advance after this command; but
+ |h| usually does increase.
+\stopitem
+
+\startitem
+ \\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+ Do the operations of |set_char_0|; but use the character whose number
+ matches the opcode, instead of character~0.
+\stopitem
+
+\startitem
+ |set1| 128 |c[1]|. Same as |set_char_0|, except that character number~|c| is
+ typeset. \TeX82 uses this command for characters in the range |128<=c<256|.
+\stopitem
+
+\startitem
+ |set2| 129 |c[2]|. Same as |set1|, except that |c|~is two bytes long, so it
+ is in the range |0<=c<65536|. \TeX82 never uses this command, but it should
+ come in handy for extensions of \TeX\ that deal with oriental languages.
+\stopitem
+
+\startitem
+ |set3| 130 |c[3]|. Same as |set1|, except that |c|~is three bytes long, so it
+ can be as large as $2^{24}-1$. Not even the Chinese language has this many
+ characters, but this command might prove useful in some yet unforeseen
+ extension.
+\stopitem
+
+\startitem
+ |set4| 131 |c[4]|. Same as |set1|, except that |c|~is four bytes long.
+ Imagine that.
+\stopitem
+
+\startitem
+ |set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle of height~|a|
+ and width~|b|, with its bottom left corner at |(h,v)|. Then set |h:=h+b|. If
+ either |a<=0| or |b<=0|, nothing should be typeset. Note that if |b<0|, the
+ value of |h| will decrease even though nothing else happens. See below for
+ details about how to typeset rules so that consistency with \MF\ is
+ guaranteed.
+\stopitem
+
+\startitem
+ |put1| 133 |c[1]|. Typeset character number~|c| from font~|f| such that the
+ reference point of the character is at |(h,v)|. (The `put' commands are
+ exactly like the `set' commands, except that they simply put out a character
+ or a rule without moving the reference point afterwards.)
+\stopitem
+
+\startitem
+ |put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+\stopitem
+
+\startitem
+ |put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+\stopitem
+
+\startitem
+ |put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+\stopitem
+
+\startitem
+ |put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that |h| is not
+ changed.
+\stopitem
+
+\startitem
+ |nop| 138. No operation, do nothing. Any number of |nop|'s may occur between
+ \.{DVI} commands, but a |nop| cannot be inserted between a command and its
+ parameters or between two parameters.
+\stopitem
+
+\startitem
+ |bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning of a page:
+ Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set the current
+ font |f| to an undefined value. The ten $c_i$ parameters hold the values of
+ \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time \.{\\shipout} was
+ invoked for this page; they can be used to identify pages, if a user wants to
+ print only part of a \.{DVI} file. The parameter |p| points to the previous
+ |bop| in the file; the first |bop| has $p=-1$.
+\stopitem
+
+\startitem
+ |eop| 140. End of page: Print what you have read since the previous |bop|. At
+ this point the stack should be empty. (The \.{DVI}-reading programs that
+ drive most output devices will have kept a buffer of the material that
+ appears on the page that has just ended. This material is largely, but not
+ entirely, in order by |v| coordinate and (for fixed |v|) by |h|~coordinate;
+ so it usually needs to be sorted into some order that is appropriate for the
+ device in question.)
+\stopitem
+
+\startitem
+ |push| 141. Push the current values of |(h,v,w,x,y,z)| onto the top of the
+ stack; do not change any of these values. Note that |f| is not pushed.
+\stopitem
+
+\startitem
+ |pop| 142. Pop the top six values off of the stack and assign them
+ respectively to |(h,v,w,x,y,z)|. The number of pops should never exceed the
+ number of pushes, since it would be highly embarrassing if the stack were
+ empty at the time of a |pop| command.
+
+\startitem
+ |right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units. The parameter
+ is a signed number in two's complement notation, |-128<=b<128|; if |b<0|, the
+ reference point moves left.
+\stopitem
+
+\startitem
+ |right2| 144 |b[2]|. Same as |right1|, except that |b| is a two-byte quantity
+ in the range |-32768<=b<32768|.
+\stopitem
+
+\startitem
+ |right3| 145 |b[3]|. Same as |right1|, except that |b| is a three-byte
+ quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |right4| 146 |b[4]|. Same as |right1|, except that |b| is a four-byte
+ quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck, this
+ parameterless command will usually suffice, because the same kind of motion
+ will occur several times in succession; the following commands explain how
+ |w| gets particular values.
+\stopitem
+
+\startitem
+ |w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a signed
+ quantity in two's complement notation, |-128<=b<128|. This command changes
+ the current |w|~spacing and moves right by |b|.
+\stopitem
+
+\startitem
+ |w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long, |-32768<=b<32768|.
+\stopitem
+
+\startitem
+ |w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
+ |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
+ |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|' commands are
+ like the `|w|' commands except that they involve |x| instead of |w|.
+\stopitem
+
+\startitem
+ |x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a signed
+ quantity in two's complement notation, |-128<=b<128|. This command changes
+ the current |x|~spacing and moves right by |b|.
+\stopitem
+
+\startitem
+ |x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long, |-32768<=b<32768|.
+\stopitem
+
+\startitem
+ |x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
+ |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
+ |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units. The parameter is
+ a signed number in two's complement notation, |-128<=a<128|; if |a<0|, the
+ reference point moves up.
+\stopitem
+
+\startitem
+ |down2| 158 |a[2]|. Same as |down1|, except that |a| is a two-byte quantity
+ in the range |-32768<=a<32768|.
+\stopitem
+
+\startitem
+ |down3| 159 |a[3]|. Same as |down1|, except that |a| is a three-byte quantity
+ in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |down4| 160 |a[4]|. Same as |down1|, except that |a| is a four-byte quantity
+ in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck, this
+ parameterless command will usually suffice, because the same kind of motion
+ will occur several times in succession; the following commands explain how
+ |y| gets particular values.
+\stopitem
+
+\startitem
+ |y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a signed
+ quantity in two's complement notation, |-128<=a<128|. This command changes
+ the current |y|~spacing and moves down by |a|.
+\stopitem
+
+\startitem
+ |y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long, |-32768<=a<32768|.
+\stopitem
+
+\startitem
+ |y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
+ |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
+ |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands are
+ like the `|y|' commands except that they involve |z| instead of |y|.
+\stopitem
+
+\startitem
+ |z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a signed
+ quantity in two's complement notation, |-128<=a<128|. This command changes
+ the current |z|~spacing and moves down by |a|.
+\stopitem
+
+\startitem
+ |z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long, |-32768<=a<32768|.
+\stopitem
+
+\startitem
+ |z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
+ |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+ |z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
+ |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been defined by a
+ \\{fnt\_def} instruction, as explained below.
+\stopitem
+
+\startitem
+ \\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set |f:=1|,
+ \dots, \hbox{|f:=63|}, respectively.
+\stopitem
+
+\startitem
+ |fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font numbers in
+ the range |64<=k<256|.
+\stopitem
+
+\startitem
+ |fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two bytes long, so it
+ is in the range |0<=k<65536|. \TeX82 never generates this command, but large
+ font numbers may prove useful for specifications of color or texture, or they
+ may be used for special fonts that have fixed numbers in some external coding
+ scheme.
+\stopitem
+
+\startitem
+ |fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three bytes long, so it
+ can be as large as $2^{24}-1$.
+\stopitem
+
+\startitem
+ |fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four bytes long; this
+ is for the really big font numbers (and for the negative ones).
+\stopitem
+
+\startitem
+ |xxx1| 239 |k[1]| |x[k]|. This command is undefined in general; it functions
+ as a $(k+2)$-byte |nop| unless special \.{DVI}-reading programs are being
+ used. \TeX82 generates |xxx1| when a short enough \.{\\special} appears,
+ setting |k| to the number of bytes being sent. It is recommended that |x| be
+ a string having the form of a keyword followed by possible parameters
+ relevant to that keyword.
+\stopitem
+
+\startitem
+ |xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
+\stopitem
+
+\startitem
+ |xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
+\stopitem
+
+\startitem
+ |xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously large.
+ \TeX82 uses |xxx4| when sending a string of length 256 or more.
+\stopitem
+
+\startitem
+ |fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+ font |k|, where |0<=k<256|; font definitions will be explained shortly.
+\stopitem
+
+\startitem
+ |fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+ font |k|, where |0<=k<65536|.
+\stopitem
+
+\startitem
+ |fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+ font |k|, where |0<=k<@t$2^{24}$@>|.
+\stopitem
+
+\startitem
+ |fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+ font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+ |pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|. Beginning of the
+ preamble; this must come at the very beginning of the file. Parameters |i|,
+ |num|, |den|, |mag|, |k|, and |x| are explained below.
+\stopitem
+
+\startitem
+ |post| 248. Beginning of the postamble, see below.
+\stopitem
+
+\startitem
+ |post_post| 249. Ending of the postamble, see below.
+\stopitem
+
+\startitem
+ Commands 250--255 are undefined at the present time.
+\stopitem
+
+*/
+
+#define set_char_0 0 /* typeset character 0 and move right */
+#define set1 128 /* typeset a character and move right */
+#define set_rule 132 /* typeset a rule and move right */
+#define put1 133 /* typeset a character without moving */
+#define put_rule 137 /* typeset a rule */
+#define nop 138 /* no operation */
+#define bop 139 /* beginning of page */
+#define eop 140 /* ending of page */
+#define push 141 /* save the current positions */
+#define pop 142 /* restore previous positions */
+#define right1 143 /* move right */
+#define right4 146 /* move right, 4 bytes */
+#define w0 147 /* move right by |w| */
+#define w1 148 /* move right and set |w| */
+#define x0 152 /* move right by |x| */
+#define x1 153 /* move right and set |x| */
+#define down1 157 /* move down */
+#define down4 160 /* move down, 4 bytes */
+#define y0 161 /* move down by |y| */
+#define y1 162 /* move down and set |y| */
+#define z0 166 /* move down by |z| */
+#define z1 167 /* move down and set |z| */
+#define fnt_num_0 171 /* set current font to 0 */
+#define fnt1 235 /* set current font */
+#define xxx1 239 /* extension to \.{DVI} primitives */
+#define xxx4 242 /* potentially long extension to \.{DVI} primitives */
+#define fnt_def1 243 /* define the meaning of a font number */
+#define pre 247 /* preamble */
+#define post 248 /* postamble beginning */
+#define post_post 249 /* postamble ending */
+
+/*tex
+
+The preamble contains basic information about the file as a whole. As stated
+above, there are six parameters: $$\hbox{|i[1]| |num[4]| |den[4]|
+|mag[4]| |k[1]| |x[k]|.}$$ The |i| byte identifies \.{DVI} format;
+currently this byte is always set to~2. (The value |i=3| is currently used for an
+extended format that allows a mixture of right-to-left and left-to-right
+typesetting. Some day we will set |i=4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define the
+units of measurement; they are the numerator and denominator of a fraction by
+which all dimensions in the \.{DVI} file could be multiplied in order to get
+lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} = 254{cm}$, and since
+\TeX\ works with scaled points where there are $2^{16}$ sp in a point, \TeX\ sets
+$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+
+The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the desired
+magnification. The actual fraction by which dimensions are multiplied is
+therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\ source document does
+not call for any `\.{true}' dimensions, and if you change it only by specifying a
+different \.{\\mag} setting, the \.{DVI} file that \TeX\ creates will be
+completely unchanged except for the value of |mag| in the preamble and postamble.
+(Fancy \.{DVI}-reading programs allow users to override the |mag|~setting when a
+\.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
+
+The next macro identifies the kind of \.{DVI} files described here.
+
+*/
+
+#define id_byte 2
+
+/*tex
+
+Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$ The four-byte value |c|
+is the check sum that \TeX\ found in the \.{TFM} file for this font; |c| should
+match the check sum of the font found by programs that read this \.{DVI} file.
+
+Parameter |s| contains a fixed-point scale factor that is applied to the
+character widths in font |k|; font dimensions in \.{TFM} files and other font
+files are relative to this quantity, which is called the ``at size'' elsewhere in
+this documentation. The value of |s| is always positive and less than $2^{27}$.
+It is given in the same units as the other \.{DVI} dimensions, i.e., in sp when
+\TeX82 has made the file. Parameter |d| is similar to |s|; it is the ``design
+size,'' and (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
+at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length of the
+``area'' or directory, and |l| is the length of the font name itself; the
+standard local system font area is supposed to be used when |a=0|. The |n| field
+contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+Sometimes it is desirable to make horizontal or vertical rules line up precisely
+with certain features in characters of a font. It is possible to guarantee the
+correct matching between \.{DVI} output and the characters generated by \MF\ by
+adhering to the following principles: (1)~The \MF\ characters should be
+positioned so that a bottom edge or left edge that is supposed to line up with
+the bottom or left edge of a rule appears at the reference point, i.e., in row~0
+and column~0 of the \MF\ raster. This ensures that the position of the rule will
+not be rounded differently when the pixel size is not a perfect multiple of the
+units of measurement in the \.{DVI} file. (2)~A typeset rule of height $a>0$ and
+width $b>0$ should be equivalent to a \MF-generated character having black pixels
+in precisely those raster positions whose \MF\ coordinates satisfy
+|0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number of
+pixels per \.{DVI} unit.
+
+The last page in a \.{DVI} file is followed by `|post|'; this command introduces
+the postamble, which summarizes important facts that \TeX\ has accumulated about
+the file, making it possible to print subsets of the data with reasonable
+efficiency. The postamble has the form
+
+$$\vbox{\halign{\hbox{#\hfil}\cr
+ |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+ $\langle\,$font definitions$\,\rangle$\cr
+ |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+
+Here |p| is a pointer to the final |bop| in the file. The next three parameters,
+|num|, |den|, and |mag|, are duplicates of the quantities that appeared in the
+preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions of
+the file. These numbers might be used by a \.{DVI}-reading program to position
+individual ``pages'' on large sheets of film or paper; however, the standard
+convention for output on normal size paper is to position each page so that the
+upper left-hand corner is exactly one inch from the left and the top. Experience
+has shown that it is unwise to design \.{DVI}-to-printer software that attempts
+cleverly to center the output; a fixed position of the upper left corner is
+easiest for users to understand and to work with. Therefore |l| and~|u| are often
+ignored. Parameter |s| is the maximum stack depth (i.e., the largest excess of
+
+|push| commands over |pop| commands) needed to process this file. Then comes |t|,
+the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once in
+the postamble.
+
+The last part of the postamble, following the |post_post| byte that signifies the
+end of the font definitions, contains |q|, a pointer to the |post| command that
+started the postamble. An identification byte, |i|, comes next; this currently
+equals~2, as in the preamble.
+
+The |i| byte is followed by four or more bytes that are all equal to the decimal
+number 223 (i.e., '337 in octal). \TeX\ puts out four to seven of these trailing
+bytes, until the total length of the file is a multiple of four bytes, since this
+works out best on machines that pack four bytes per word; but any number of 223's
+is allowed, as long as there are at least four of them. In effect, 223 is a sort
+of signature that is added at the very end.
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers, even
+though \TeX\ wants to write the postamble last. Most operating systems permit
+random access to individual words or bytes of a file, so the \.{DVI} reader can
+start at the end and skip backwards over the 223's until finding the
+identification byte. Then it can back up four bytes, read |q|, and move to byte
+|q| of the file. This byte should, of course, contain the value 248 (|post|); now
+the postamble can be read, so the \.{DVI} reader can discover all the information
+needed for typesetting the pages. Note that it is also possible to skip through
+the \.{DVI} file at reasonably high speed to locate a particular page, if that
+proves desirable. This saves a lot of time, since \.{DVI} files used in
+production jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to access
+a random position in a file, or even to determine the length of a file. Almost
+all systems nowadays provide the necessary capabilities, so \.{DVI} format has
+been designed to work most efficiently with modern operating systems. But if
+\.{DVI} files have to be processed under the restrictions of standard \PASCAL,
+one can simply read them from front to back, since the necessary header
+information is present in the preamble and in the font definitions. (The |l| and
+|u| and |s| and |t| parameters, which appear only in the postamble, are
+``frills'' that are handy but not absolutely necessary.)
+
+After considering \TeX's eyes and stomach, we come now to the bowels.
+
+The |ship_out| procedure is given a pointer to a box; its mission is to describe
+that box in \.{DVI} form, outputting a ``page'' to |dvi_file|. The \.{DVI}
+coordinates $(h,v)=(0,0)$ should correspond to the upper left corner of the box
+being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of |ship_out|
+is done by two mutually recursive routines, |hlist_out| and |vlist_out|, which
+traverse the hlists and vlists inside of horizontal and vertical boxes.
+
+As individual pages are being processed, we need to accumulate information about
+the entire set of pages, since such statistics must be reported in the postamble.
+The global variables |total_pages|, |max_v|, |max_h|, |max_push|, and |last_bop|
+are used to record this information.
+
+The variable |doing_leaders| is |true| while leaders are being output. The
+variable |dead_cycles| contains the number of times an output routine has been
+initiated since the last |ship_out|.
+
+A few additional global variables are also defined here for use in |vlist_out|
+and |hlist_out|. They could have been local variables, but that would waste stack
+space when boxes are deeply nested, since the values of these variables are not
+needed during recursive calls.
+
+*/
+
+/* Some global variables are defined in |backend| module. */
+
+static int max_push = 0; /* deepest nesting of |push| commands encountered so far */
+static int last_bop = -1; /* location of previous |bop| in the \.{DVI} output */
+static int oval, ocmd; /* used by |out_cmd| for generating |set|, |fnt| and |fnt_def| commands */
+pointer g; /* current glue specification */
+
+/*tex
+
+The \.{DVI} bytes are output to a buffer instead of being written directly to the
+output file. This makes it possible to reduce the overhead of subroutine calls,
+thereby measurably speeding up the computation, since output of \.{DVI} bytes is
+part of \TeX's inner loop. And it has another advantage as well, since we can
+change instructions in the buffer in order to make the output more compact. For
+example, a `|down2|' command can be changed to a `|y2|', thereby making a
+subsequent `|y0|' command possible, saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found in
+|dvi_buf[0..half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global variable
+|dvi_ptr| points to the position that will receive the next output byte. When
+|dvi_ptr| reaches |dvi_limit|, which is always equal to one of the two values
+|half_buf| or |dvi_buf_size|, the half buffer that is about to be invaded next is
+sent to the output and |dvi_limit| is changed to its other value. Thus, there is
+always at least a half buffer's worth of information present, except at the very
+beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0; the next
+byte to be generated will be number |dvi_offset+dvi_ptr|. A byte is present in
+the buffer only if its number is |>=dvi_gone|.
+
+Some systems may find it more efficient to make |dvi_buf| a |packed| array, since
+output of four bytes at once may be facilitated.
+
+Initially the buffer is all in one piece; we will output half of it only after it
+first fills up.
+
+*/
+
+int dvi_buf_size = 800; /* size of the output buffer; must be a multiple of 8 */
+eight_bits *dvi_buf; /* buffer for \.{DVI} output */
+static int half_buf = 0; /* half of |dvi_buf_size| */
+static int dvi_limit = 0; /* end of the current half buffer */
+static int dvi_ptr = 0; /* the next available buffer address */
+static int dvi_offset = 0; /* |dvi_buf_size| times the number of times the output buffer has been fully emptied */
+static int dvi_gone = 0; /* the number of bytes already output to |dvi_file| */
+
+/*
+To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+*/
+
+#define dvi_out(A) do { \
+ dvi_buf[dvi_ptr++]=(eight_bits)(A); \
+ if (dvi_ptr==dvi_limit) dvi_swap(); \
+} while (0)
+
+#define dvi_set(A,B) do { \
+ oval=A; ocmd=set1; out_cmd(); dvi.h += (B); \
+} while (0)
+
+#define dvi_put(A) do { \
+ oval=A; ocmd=put1; out_cmd(); \
+} while (0)
+
+/*
+The |vinfo| fields in the entries of the down stack or the right stack
+have six possible settings: |y_here| or |z_here| mean that the \.{DVI}
+command refers to |y| or |z|, respectively (or to |w| or |x|, in the
+case of horizontal motion); |yz_OK| means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either |y| or |z| (or
+to either |w| or |x|); |y_OK| means that it is \\{down} and can be changed
+to |y| but not |z|; |z_OK| is similar; and |d_fixed| means it must stay
+\\{down}.
+
+The four settings |yz_OK|, |y_OK|, |z_OK|, |d_fixed| would not need to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of |push| and |pop|
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `|push|'
+and `|pop|'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+*/
+
+typedef enum {
+ y_here = 1, /* |vinfo| when the movement entry points to a |y| command */
+ z_here = 2, /* |vinfo| when the movement entry points to a |z| command */
+ yz_OK = 3, /* |vinfo| corresponding to an unconstrained \\{down} command */
+ y_OK = 4, /* |vinfo| corresponding to a \\{down} that can't become a |z| */
+ z_OK = 5, /* |vinfo| corresponding to a \\{down} that can't become a |y| */
+ d_fixed = 6, /* |vinfo| corresponding to a \\{down} that can't change */
+} movement_codes;
+
+/* As we search through the stack, we are in one of three states,
+ |y_seen|, |z_seen|, or |none_seen|, depending on whether we have
+ encountered |y_here| or |z_here| nodes. These states are encoded as
+ multiples of 6, so that they can be added to the |info| fields for quick
+ decision-making. */
+
+# define none_seen 0 /* no |y_here| or |z_here| nodes have been encountered yet */
+# define y_seen 6 /* we have seen |y_here| but not |z_here| */
+# define z_seen 12 /* we have seen |z_here| but not |y_here| */
+
+void movement(scaled w, eight_bits o);
+
+/*
+extern void prune_movements(int l);
+*/
+
+/*
+The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: |dvi.h| and |dvi.v|
+are the |h| and |v| coordinates corresponding to the commands actually
+output to the \.{DVI} file, while |cur.h| and |cur.v| are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in |cur.h| and |cur.v| without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the |movement| procedure whenever we want to make |dvi.h=pos.h|
+or |dvi.v=pos.v|.
+
+The current font reflected in the \.{DVI} output is called |dvi_f|;
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|;
+this is essentially the depth of |push| commands in the \.{DVI} output.
+*/
+
+/*tex A \.{DVI} position in page coordinates, in sync with DVI file: */
+
+static scaledpos dvi;
+
+# define synch_h(p) do { \
+ if (p.h != dvi.h) { \
+ movement(p.h - dvi.h, right1); \
+ dvi.h = p.h; \
+ } \
+ } while (0)
+
+# define synch_v(p) do { \
+ if (p.v != dvi.v) { \
+ movement(dvi.v - p.v, down1); \
+ dvi.v = p.v; \
+ } \
+ } while (0)
+
+# define synch_dvi_with_pos(p) do {synch_h(p); synch_v(p); } while (0)
+
+/*tex
+
+The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. For best results, this procedure should be optimized to run as
+fast as possible on each particular system, since it is part of \TeX's inner
+loop. It is safe to assume that |a| and |b+1| will both be multiples of 4 when
+|write_dvi(a,b)| is called; therefore it is possible on many machines to use
+efficient methods to pack four bytes per word and to output an array of words
+with one system call.
+
+*/
+
+static void write_dvi(int a, int b)
+{
+ int k;
+ for (k = a; k <= b; k++)
+ fputc(dvi_buf[k], static_pdf->file);
+}
+
+/*tex This outputs half of the buffer: */
+
+static void dvi_swap(void)
+{
+ if (dvi_limit == dvi_buf_size) {
+ write_dvi(0, half_buf - 1);
+ dvi_limit = half_buf;
+ dvi_offset = dvi_offset + dvi_buf_size;
+ dvi_ptr = 0;
+ } else {
+ write_dvi(half_buf, dvi_buf_size - 1);
+ dvi_limit = dvi_buf_size;
+ }
+ dvi_gone = dvi_gone + half_buf;
+}
+
+/*tex
+
+The |dvi_four| procedure outputs four bytes in two's complement notation, without
+risking arithmetic overflow.
+
+*/
+
+static void dvi_four(int x)
+{
+ if (x >= 0) {
+ dvi_out(x / 0100000000);
+ } else {
+ x = x + 010000000000;
+ x = x + 010000000000;
+ dvi_out((x / 0100000000) + 128);
+ }
+ x = x % 0100000000;
+ dvi_out(x / 0200000);
+ x = x % 0200000;
+ dvi_out(x / 0400);
+ dvi_out(x % 0400);
+}
+
+/*tex
+
+A mild optimization of the output is performed by the |dvi_pop| routine, which
+issues a |pop| unless it is possible to cancel a `|push| |pop|' pair. The
+parameter to |dvi_pop| is the byte address following the old |push| that matches
+the new |pop|.
+
+*/
+
+static void dvi_push(void)
+{
+ dvi_out(push);
+}
+
+static void dvi_pop(int l)
+{
+ if ((l == dvi_offset + dvi_ptr) && (dvi_ptr > 0))
+ decr(dvi_ptr);
+ else
+ dvi_out(pop);
+}
+
+/*tex
+
+Here's a procedure that outputs a font definition. $\Omega$ allows more than 256
+different fonts per job, so the right font definition command must be selected.
+
+*/
+
+static void out_cmd(void)
+{
+ if ((oval < 0x100) && (oval >= 0)) {
+ if ((ocmd != set1) || (oval > 127)) {
+ if ((ocmd == fnt1) && (oval < 64))
+ oval += fnt_num_0;
+ else
+ dvi_out(ocmd);
+ }
+ } else {
+ if ((oval < 0x10000) && (oval >= 0)) {
+ dvi_out(ocmd + 1);
+ } else {
+ if ((oval < 0x1000000) && (oval >= 0)) {
+ dvi_out(ocmd + 2);
+ } else {
+ dvi_out(ocmd + 3);
+ if (oval >= 0) {
+ dvi_out(oval / 0x1000000);
+ } else {
+ oval += 0x40000000;
+ oval += 0x40000000;
+ dvi_out((oval / 0x1000000) + 128);
+ oval = oval % 0x1000000;
+ }
+ dvi_out(oval / 0x10000);
+ oval = oval % 0x10000;
+ }
+ dvi_out(oval / 0x10000);
+ oval = oval % 0x10000;
+ }
+ dvi_out(oval / 0x100);
+ oval = oval % 0x100;
+ }
+ dvi_out(oval);
+}
+
+static void dvi_font_def(internal_font_number f)
+{
+ char *fa;
+ oval = f - 1;
+ ocmd = fnt_def1;
+ out_cmd();
+ dvi_out(font_check_0(f));
+ dvi_out(font_check_1(f));
+ dvi_out(font_check_2(f));
+ dvi_out(font_check_3(f));
+ dvi_four(font_size(f));
+ dvi_four(font_dsize(f));
+ dvi_out(0); /* |font_area(f)| is unused */
+ dvi_out(strlen(font_name(f)));
+ /* Output the font name whose internal number is |f| */
+ fa = font_name(f);
+ while (*fa != '\0') {
+ dvi_out(*fa++);
+ }
+}
+
+/*tex
+
+Versions of \TeX\ intended for small computers might well choose to omit the
+ideas in the next few parts of this program, since it is not really necessary to
+optimize the \.{DVI} code by making use of the |w0|, |x0|, |y0|, and |z0|
+commands. Furthermore, the algorithm that we are about to describe does not
+pretend to give an optimum reduction in the length of the \.{DVI} code; after
+all, speed is more important than compactness. But the method is surprisingly
+effective, and it takes comparatively little time.
+
+We can best understand the basic idea by first considering a simpler problem that
+has the same essential characteristics. Given a sequence of digits, say
+$3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts $d$, $y$,
+or $z$ to each digit so as to maximize the number of ``$y$-hits'' and
+``$z$-hits''; a $y$-hit is an instance of two appearances of the same digit with
+the subscript $y$, where no $y$'s intervene between the two appearances, and a
+$z$-hit is defined similarly. For example, the sequence above could be decorated
+with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$ There are
+three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and one $z$-hit
+($3_z\ldots3_z$); there are no $d$-hits, since the two appearances of $9_d$ have
+$d$'s between them, but we don't count $d$-hits so it doesn't matter how many
+there are. These subscripts are analogous to the \.{DVI} commands called
+\\{down}, $y$, and $z$, and the digits are analogous to different amounts of
+vertical motion; a $y$-hit or $z$-hit corresponds to the opportunity to use the
+one-byte commands |y0| or |z0| in a \.{DVI} file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit, say
+$\delta$, to the right of the sequence. Now look back through the sequence until
+one of the following things happens: (a)~You see $\delta_y$ or $\delta_z$, and
+this was the first time you encountered a $y$ or $z$ subscript, respectively.
+Then assign $y$ or $z$ to the new $\delta$; you have scored a hit. (b)~You see
+$\delta_d$, and no $y$ subscripts have been encountered so far during this
+search. Then change the previous $\delta_d$ to $\delta_y$ (this corresponds to
+changing a command in the output buffer), and assign $y$ to the new $\delta$;
+it's another hit. (c)~You see $\delta_d$, and a $y$ subscript has been seen but
+not a $z$. Change the previous $\delta_d$ to $\delta_z$ and assign $z$ to the new
+$\delta$. (d)~You encounter both $y$ and $z$ subscripts before encountering a
+suitable $\delta$, or you scan all the way to the front of the sequence. Assign
+$d$ to the new $\delta$; this assignment may be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+In order to implement such an idea, \TeX\ maintains a stack of pointers to the
+\\{down}, $y$, and $z$ commands that have been generated for the current page.
+And there is a similar stack for \\{right}, |w|, and |x| commands. These stacks
+are called the down stack and right stack, and their top elements are maintained
+in the variables |down_ptr| and |right_ptr|.
+
+Each entry in these stacks contains four fields: The |width| field is the amount
+of motion down or to the right; the |location| field is the byte number of the
+\.{DVI} command in question (including the appropriate |dvi_offset|); the |vlink|
+field points to the next item below this one on the stack; and the |vinfo| field
+encodes the options for possible change in the \.{DVI} command.
+
+*/
+
+/*tex The \.{DVI} byte number for a movement command: */
+
+#define location(A) varmem[(A)+1].cint
+
+/*tex The heads of the down and right stacks: */
+
+static halfword down_ptr = null;
+static halfword right_ptr = null;
+
+/*tex
+
+Here is a subroutine that produces a \.{DVI} command for some specified downward
+or rightward motion. It has two parameters: |w| is the amount of motion, and |o|
+is either |down1| or |right1|. We use the fact that the command codes have
+convenient arithmetic properties: |y1-down1=w1-right1| and |z1-down1=x1-right1|.
+
+*/
+
+void movement(scaled w, eight_bits o)
+{
+ small_number mstate; /* have we seen a |y| or |z|? */
+ halfword p, q; /* current and top nodes on the stack */
+ int k; /* index into |dvi_buf|, modulo |dvi_buf_size| */
+ /*tex something todo? */
+ if (false) {
+ /*tex new node for the top of the stack */
+ q = new_node(movement_node, 0);
+ width(q) = w;
+ location(q) = dvi_offset + dvi_ptr;
+ if (o == down1) {
+ vlink(q) = down_ptr;
+ down_ptr = q;
+ } else {
+ vlink(q) = right_ptr;
+ right_ptr = q;
+ }
+ /*tex
+
+ Look at the other stack entries until deciding what sort of \.{DVI}
+ command to generate; |goto found| if node |p| is a ``hit''.
+ */
+ p = vlink(q);
+ mstate = none_seen;
+ while (p != null) {
+ if (width(p) == w) {
+ /*
+ Consider a node with matching width;|goto found| if it's a
+ hit. We might find a valid hit in a |y| or |z| byte that is
+ already gone from the buffer. But we can't change bytes that
+ are gone forever; ``the moving finger writes, $\ldots\,\,$.''
+ */
+ switch (mstate + vinfo(p)) {
+ case none_seen + yz_OK:
+ case none_seen + y_OK:
+ case z_seen + yz_OK:
+ case z_seen + y_OK:
+ if (location(p) < dvi_gone) {
+ goto NOT_FOUND;
+ } else {
+ /* Change buffered instruction to |y| or |w| and |goto found| */
+ k = location(p) - dvi_offset;
+ if (k < 0)
+ k = k + dvi_buf_size;
+ dvi_buf[k] = (eight_bits) (dvi_buf[k] + y1 - down1);
+ vinfo(p) = y_here;
+ goto FOUND;
+ }
+ break;
+ case none_seen + z_OK:
+ case y_seen + yz_OK:
+ case y_seen + z_OK:
+ if (location(p) < dvi_gone) {
+ goto NOT_FOUND;
+ } else {
+ /* Change buffered instruction to |z| or |x| and |goto found| */
+ k = location(p) - dvi_offset;
+ if (k < 0)
+ k = k + dvi_buf_size;
+ dvi_buf[k] = (eight_bits) (dvi_buf[k] + z1 - down1);
+ vinfo(p) = z_here;
+ goto FOUND;
+ }
+ break;
+ case none_seen + y_here:
+ case none_seen + z_here:
+ case y_seen + z_here:
+ case z_seen + y_here:
+ goto FOUND;
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (mstate + vinfo(p)) {
+ case none_seen + y_here:
+ mstate = y_seen;
+ break;
+ case none_seen + z_here:
+ mstate = z_seen;
+ break;
+ case y_seen + z_here:
+ case z_seen + y_here:
+ goto NOT_FOUND;
+ break;
+ default:
+ break;
+ }
+ }
+ p = vlink(p);
+ }
+ }
+ NOT_FOUND:
+ /*tex
+ Generate a |down| or |right| command for |w| and |return|:
+ */
+ if (abs(w) >= 040000000) {
+ /*tex |down4| or |right4| */
+ dvi_out(o + 3);
+ dvi_four(w);
+ return;
+ }
+ if (abs(w) >= 0100000) {
+ /*tex |down3| or |right3| */
+ dvi_out(o + 2);
+ if (w < 0)
+ w = w + 0100000000;
+ dvi_out(w / 0200000);
+ w = w % 0200000;
+ goto TWO;
+ }
+ if (abs(w) >= 0200) {
+ /*tex |down2| or |right2| */
+ dvi_out(o + 1);
+ if (w < 0)
+ w = w + 0200000;
+ goto TWO;
+ }
+ /*tex |down1| or |right1| */
+ dvi_out(o);
+ if (w < 0)
+ w = w + 0400;
+ goto ONE;
+ TWO:
+ dvi_out(w / 0400);
+ ONE:
+ dvi_out(w % 0400);
+ return;
+ FOUND:
+ /*tex
+
+ Generate a |y0| or |z0| command in order to reuse a previous appearance
+ of~|w|.
+
+ The program below removes movement nodes that are introduced after a
+ |push|, before it outputs the corresponding |pop|.
+
+ When the |movement| procedure gets to the label |found|, the value of
+ |vinfo(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
+ the procedure generates a |y0| command (or a |w0| command), and marks all
+ |vinfo| fields between |q| and |p| so that |y| is not OK in that range.
+
+ */
+ vinfo(q) = vinfo(p);
+ if (vinfo(q) == y_here) {
+ /*tex |y0| or |w0| */
+ dvi_out(o + y0 - down1);
+ while (vlink(q) != p) {
+ q = vlink(q);
+ switch (vinfo(q)) {
+ case yz_OK:
+ vinfo(q) = z_OK;
+ break;
+ case y_OK:
+ vinfo(q) = d_fixed;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ /*tex |z0| or |x0| */
+ dvi_out(o + z0 - down1);
+ while (vlink(q) != p) {
+ q = vlink(q);
+ switch (vinfo(q)) {
+ case yz_OK:
+ vinfo(q) = y_OK;
+ break;
+ case z_OK:
+ vinfo(q) = d_fixed;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/*tex
+
+In case you are wondering when all the movement nodes are removed from \TeX's
+memory, the answer is that they are recycled just before |hlist_out| and
+|vlist_out| finish outputting a box. This restores the down and right stacks to
+the state they were in before the box was output, except that some |vinfo|'s may
+have become more restrictive.
+
+Here we delete movement nodes with |location>=l|:
+
+*/
+
+static void prune_movements(int l)
+{
+ pointer p;
+ while (down_ptr != null) {
+ if (location(down_ptr) < l)
+ break;
+ p = down_ptr;
+ down_ptr = vlink(p);
+ flush_node(p);
+ }
+ while (right_ptr != null) {
+ if (location(right_ptr) < l)
+ return;
+ p = right_ptr;
+ right_ptr = vlink(p);
+ flush_node(p);
+ }
+}
+
+/*tex
+
+When |hlist_out| is called, its duty is to output the box represented by the
+|hlist_node| pointed to by |temp_ptr|. The reference point of that box has
+coordinates |(cur.h,cur.v)|.
+
+Similarly, when |vlist_out| is called, its duty is to output the box represented
+by the |vlist_node| pointed to by |temp_ptr|. The reference point of that box has
+coordinates |(cur.h,cur.v)|.
+
+The recursive procedures |hlist_out| and |vlist_out| each have a local variable
+|save_dvi| to hold the value of |dvi| just before entering a new level of
+recursion. In effect, the value of |save_dvi| on \TeX's run-time stack
+corresponds to the values of |h| and |v| that a \.{DVI}-reading program will push
+onto its coordinate stack.
+
+*/
+
+void dvi_place_rule(PDF pdf, halfword q, scaledpos size)
+{
+ synch_dvi_with_pos(pdf->posstruct->pos);
+ if ((subtype(q) >= box_rule) && (subtype(q) <= user_rule)) {
+ /*tex place nothing, only take space */
+ if (textdir_is_L(pdf->posstruct->dir))
+ dvi.h += size.h;
+ } else {
+ /*tex normal_rule or >= 100 being a leader rule */
+ if (textdir_is_L(pdf->posstruct->dir)) {
+ /*tex movement optimization for |dir_*L*| */
+ dvi_out(set_rule);
+ dvi.h += size.h;
+ } else
+ dvi_out(put_rule);
+ }
+ dvi_four(size.v);
+ dvi_four(size.h);
+}
+
+void dvi_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
+{
+ scaled_whd ci;
+ synch_dvi_with_pos(pdf->posstruct->pos);
+ if (f != pdf->f_cur) {
+ /*tex Change font |f_cur| to |f| */
+ if (!font_used(f)) {
+ dvi_font_def(f);
+ set_font_used(f, true);
+ }
+ oval = f - 1;
+ ocmd = fnt1;
+ out_cmd();
+ pdf->f_cur = f;
+ }
+ if (textdir_is_L(pdf->posstruct->dir)) {
+ ci = get_charinfo_whd(f, c);
+ /*tex movement optimization for |dir_*L*| */
+ dvi_set(c, ci.wd);
+ } else {
+ dvi_put(c);
+ }
+}
+
+void dvi_special(PDF pdf, halfword p)
+{
+ /*tex holds print |selector| */
+ int old_setting;
+ /*tex index into |cur_string| */
+ unsigned k;
+ synch_dvi_with_pos(pdf->posstruct->pos);
+ old_setting = selector;
+ selector = new_string;
+ show_token_list(token_link(write_tokens(p)), null, -1);
+ selector = old_setting;
+ if (cur_length < 256) {
+ dvi_out(xxx1);
+ dvi_out(cur_length);
+ } else {
+ dvi_out(xxx4);
+ dvi_four((int) cur_length);
+ }
+ for (k = 0; k < cur_length; k++) {
+ dvi_out(cur_string[k]);
+ }
+ /*tex erase the string */
+ cur_length = 0;
+}
+
+/*tex
+
+Here's an example of how these conventions are used. Whenever it is time to ship
+out a box of stuff, we shall use the macro |ensure_dvi_open|.
+
+*/
+
+void dvi_write_header(PDF pdf)
+{
+ unsigned l;
+ /*tex index into |str_pool| */
+ unsigned s;
+ /*tex saved |selector| setting */
+ int old_setting;
+ if (half_buf == 0) {
+ half_buf = dvi_buf_size / 2;
+ dvi_limit = dvi_buf_size;
+ }
+ dvi_out(pre);
+ /*tex output the preamble */
+ dvi_out(id_byte);
+ dvi_four(25400000);
+ /*tex conversion ratio for sp */
+ dvi_four(473628672);
+ prepare_mag();
+ /*tex magnification factor is frozen */
+ dvi_four(mag_par);
+ if (output_comment) {
+ l = (unsigned) strlen(output_comment);
+ dvi_out(l);
+ for (s = 0; s < l; s++) {
+ dvi_out(output_comment[s]);
+ }
+ } else {
+ /*tex the default code is unchanged */
+ old_setting = selector;
+ selector = new_string;
+ tprint(" LuaTeX output ");
+ print_int(year_par);
+ print_char('.');
+ print_two(month_par);
+ print_char('.');
+ print_two(day_par);
+ print_char(':');
+ print_two(time_par / 60);
+ print_two(time_par % 60);
+ selector = old_setting;
+ dvi_out(cur_length);
+ for (s = 0; s < cur_length; s++)
+ dvi_out(cur_string[s]);
+ cur_length = 0;
+ }
+}
+
+void dvi_begin_page(PDF pdf)
+{
+ int k;
+ /*tex location of the current |bop| */
+ int page_loc;
+ ensure_output_state(pdf, ST_HEADER_WRITTEN);
+ /*tex Initialize variables as |ship_out| begins */
+ page_loc = dvi_offset + dvi_ptr;
+ dvi_out(bop);
+ for (k = 0; k <= 9; k++)
+ dvi_four(count(k));
+ dvi_four(last_bop);
+ last_bop = page_loc;
+}
+
+void dvi_end_page(PDF pdf)
+{
+ (void) pdf;
+ dvi_out(eop);
+}
+
+/*tex
+
+At the end of the program, we must finish things off by writing the post\-amble.
+If |total_pages=0|, the \.{DVI} file was never opened. If |total_pages>=65536|,
+the \.{DVI} file will lie. And if |max_push>=65536|, the user deserves whatever
+chaos might ensue.
+
+*/
+
+void dvi_open_file(PDF pdf) {
+ ensure_output_file_open(pdf, ".dvi");
+}
+
+void dvi_finish_file(PDF pdf, int fatal_error)
+{
+ int k;
+ int callback_id = callback_defined(stop_run_callback);
+ if (fatal_error) {
+ print_err(" ==> Fatal error occurred, bad output DVI file produced!");
+ }
+ while (cur_s > -1) {
+ if (cur_s > 0) {
+ dvi_out(pop);
+ } else {
+ dvi_out(eop);
+ incr(total_pages);
+ }
+ decr(cur_s);
+ }
+ if (total_pages == 0) {
+ if (callback_id == 0) {
+ tprint_nl("No pages of output.");
+ print_ln();
+ } else if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ }
+ } else {
+ /*tex beginning of the postamble */
+ dvi_out(post);
+ dvi_four(last_bop);
+ last_bop = dvi_offset + dvi_ptr - 5;
+ /*tex |post| location */
+ dvi_four(25400000);
+ /*tex conversion ratio for sp */
+ dvi_four(473628672);
+ prepare_mag();
+ /*tex magnification factor */
+ dvi_four(mag_par);
+ dvi_four(max_v);
+ dvi_four(max_h);
+ dvi_out(max_push / 256);
+ dvi_out(max_push % 256);
+ dvi_out((total_pages / 256) % 256);
+ dvi_out(total_pages % 256);
+ /*tex Output the font definitions for all fonts that were used */
+ k = max_font_id();
+ while (k > 0) {
+ if (font_used(k)) {
+ dvi_font_def(k);
+ }
+ decr(k);
+ }
+ dvi_out(post_post);
+ dvi_four(last_bop);
+ dvi_out(id_byte);
+ /*tex the number of 223's */
+#ifndef IPC
+ k = 4 + ((dvi_buf_size - dvi_ptr) % 4);
+#else
+ k = 7 - ((3 + dvi_offset + dvi_ptr) % 4);
+#endif
+ while (k > 0) {
+ dvi_out(223);
+ decr(k);
+ }
+ /*tex
+ Here is how we clean out the buffer when \TeX\ is all through;
+ |dvi_ptr| will be a multiple of~4.
+ */
+ if (dvi_limit == half_buf)
+ write_dvi(half_buf, dvi_buf_size - 1);
+ if (dvi_ptr > 0)
+ write_dvi(0, dvi_ptr - 1);
+ if (callback_id == 0) {
+ tprint_nl("Output written on ");
+ tprint(pdf->file_name);
+ tprint(" (");
+ print_int(total_pages);
+ tprint(" page");
+ if (total_pages != 1)
+ print_char('s');
+ tprint(", ");
+ print_int(dvi_offset + dvi_ptr);
+ tprint(" bytes).");
+ } else if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ }
+ close_file(pdf->file);
+ }
+}
+
+void dvi_push_list(PDF pdf, scaledpos *saved_pos, int *saved_loc)
+{
+ if (cur_s > max_push) {
+ max_push = cur_s;
+ }
+ if (cur_s > 0) {
+ dvi_push();
+ *saved_pos = dvi;
+ }
+ *saved_loc = dvi_offset + dvi_ptr;
+}
+
+void dvi_pop_list(PDF pdf, scaledpos *saved_pos, int *saved_loc)
+{
+ prune_movements(*saved_loc);
+ if (cur_s > 0) {
+ dvi_pop(*saved_loc);
+ dvi = *saved_pos;
+ }
+}
+
+void dvi_set_reference_point(PDF pdf, posstructure *refpoint)
+{
+ refpoint->pos.h = one_true_inch;
+ refpoint->pos.v = pdf->page_size.v - one_true_inch;
+ dvi = refpoint->pos;
+}
+
+int dvi_get_status_ptr(PDF pdf)
+{
+ return dvi_ptr;
+}
+
+int dvi_get_status_gone(PDF pdf)
+{
+ return dvi_gone;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1258 +0,0 @@
-% dvigen.w
-%
-% Copyright 2009-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-\def\MF{MetaFont}
-\def\MP{MetaPost}
-\def\PASCAL{Pascal}
-\def\[#1]{#1}
-\pdfoutput=1
-\pdfmapline{cmtex10 < cmtex10.pfb}
-\pdfmapfile{pdftex.map}
-
-\title{: generation of DVI output}
-
-@ Initial identification of this file, and the needed headers.
- at c
-#include "ptexlib.h"
-
-@ Here is the start of the actual C file.
- at c
-#undef write_dvi
-
-/* todo: move macros to api */
-
-#define mode cur_list.mode_field /* current mode */
-
-@ The most important output produced by a run of \TeX\ is the ``device
-independent'' (\.{DVI}) file that specifies where characters and rules
-are to appear on printed pages. The form of these files was designed by
-David R. Fuchs in 1979. Almost any reasonable typesetting device can be
-@^Fuchs, David Raymond@>
-@:DVI_files}{\.{DVI} files@>
-driven by a program that takes \.{DVI} files as input, and dozens of such
-\.{DVI}-to-whatever programs have been written. Thus, it is possible to
-print the output of \TeX\ on many different kinds of equipment, using \TeX\
-as a device-independent ``front end.''
-
-A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
-series of commands in a machine-like language. The first byte of each command
-is the operation code, and this code is followed by zero or more bytes
-that provide parameters to the command. The parameters themselves may consist
-of several consecutive bytes; for example, the `|set_rule|' command has two
-parameters, each of which is four bytes long. Parameters are usually
-regarded as nonnegative integers; but four-byte-long parameters,
-and shorter parameters that denote distances, can be
-either positive or negative. Such parameters are given in two's complement
-notation. For example, a two-byte-long distance parameter has a value between
-$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
-more than one byte position appear in BigEndian order.
-
-A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
-or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
-|pre| command, with its parameters that define the dimensions used in the
-file; this must come first. Each ``page'' consists of a |bop| command,
-followed by any number of other commands that tell where characters are to
-be placed on a physical page, followed by an |eop| command. The pages
-appear in the order that \TeX\ generated them. If we ignore |nop| commands
-and \\{fnt\_def} commands (which are allowed between any two commands in
-the file), each |eop| command is immediately followed by a |bop| command,
-or by a |post| command; in the latter case, there are no more pages in the
-file, and the remaining bytes form the postamble. Further details about
-the postamble will be explained later.
-
-Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
-quantities that give the location number of some other byte in the file;
-the first byte is number~0, then comes number~1, and so on. For example,
-one of the parameters of a |bop| command points to the previous |bop|;
-this makes it feasible to read the pages in backwards order, in case the
-results are being directed to a device that stacks its output face up.
-Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
-first page occupies bytes 100 to 999, say, and if the second
-page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
-points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
-very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.)
-
-@ The \.{DVI} format is intended to be both compact and easily interpreted
-by a machine. Compactness is achieved by making most of the information
-implicit instead of explicit. When a \.{DVI}-reading program reads the
-commands for a page, it keeps track of several quantities: (a)~The current
-font |f| is an integer; this value is changed only
-by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
-is given by two numbers called the horizontal and vertical coordinates,
-|h| and |v|. Both coordinates are zero at the upper left corner of the page;
-moving to the right corresponds to increasing the horizontal coordinate, and
-moving down corresponds to increasing the vertical coordinate. Thus, the
-coordinates are essentially Cartesian, except that vertical directions are
-flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The
-current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
-where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
-are used for vertical spacing. (d)~There is a stack containing
-|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
-change the current level of operation. Note that the current font~|f| is
-not pushed and popped; the stack contains only information about
-positioning.
-
-The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
-to 32 bits, including the sign. Since they represent physical distances,
-there is a small unit of measurement such that increasing |h| by~1 means
-moving a certain tiny distance to the right. The actual unit of
-measurement is variable, as explained below; \TeX\ sets things up so that
-its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
-all the |scaled| dimensions in \TeX's data structures.
-
-@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
-command is specified by its symbolic name (e.g., |bop|), its opcode byte
-(e.g., 139), and its parameters (if any). The parameters are followed
-by a bracketed number telling how many bytes they occupy; for example,
-`|p[4]|' means that parameter |p| is four bytes long.
-
-\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
-such that the reference point of the character is at |(h,v)|. Then
-increase |h| by the width of that character. Note that a character may
-have zero or negative width, so one cannot be sure that |h| will advance
-after this command; but |h| usually does increase.
-
-\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
-Do the operations of |set_char_0|; but use the character whose number
-matches the opcode, instead of character~0.
-
-\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
-number~|c| is typeset. \TeX82 uses this command for characters in the
-range |128<=c<256|.
-
-\yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
-bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
-command, but it should come in handy for extensions of \TeX\ that deal
-with oriental languages.
-@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
-
-\yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
-bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
-language has this many characters, but this command might prove useful
-in some yet unforeseen extension.
-
-\yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
-bytes long. Imagine that.
-
-\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
-of height~|a| and width~|b|, with its bottom left corner at |(h,v)|. Then
-set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
-that if |b<0|, the value of |h| will decrease even though nothing else happens.
-See below for details about how to typeset rules so that consistency with
-\MF\ is guaranteed.
-
-\yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
-such that the reference point of the character is at |(h,v)|. (The `put'
-commands are exactly like the `set' commands, except that they simply put out a
-character or a rule without moving the reference point afterwards.)
-
-\yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
-
-\yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
-
-\yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
-
-\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
-|h| is not changed.
-
-\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
-may occur between \.{DVI} commands, but a |nop| cannot be inserted between
-a command and its parameters or between two parameters.
-
-\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
-of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
-the current font |f| to an undefined value. The ten $c_i$ parameters hold
-the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
-\.{\\shipout} was invoked for this page; they can be used to identify
-pages, if a user wants to print only part of a \.{DVI} file. The parameter
-|p| points to the previous |bop| in the file; the first
-|bop| has $p=-1$.
-
-\yskip\hang|eop| 140. End of page: Print what you have read since the
-previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
-programs that drive most output devices will have kept a buffer of the
-material that appears on the page that has just ended. This material is
-largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
-|h|~coordinate; so it usually needs to be sorted into some order that is
-appropriate for the device in question.)
-
-\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
-top of the stack; do not change any of these values. Note that |f| is
-not pushed.
-
-\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
-them respectively to |(h,v,w,x,y,z)|. The number of pops should never
-exceed the number of pushes, since it would be highly embarrassing if the
-stack were empty at the time of a |pop| command.
-
-\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
-The parameter is a signed number in two's complement notation, |-128<=b<128|;
-if |b<0|, the reference point moves left.
-
-\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
-two-byte quantity in the range |-32768<=b<32768|.
-
-\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
-three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
-four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
-this parameterless command will usually suffice, because the same kind of motion
-will occur several times in succession; the following commands explain how
-|w| gets particular values.
-
-\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
-signed quantity in two's complement notation, |-128<=b<128|. This command
-changes the current |w|~spacing and moves right by |b|.
-
-\yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long,
-|-32768<=b<32768|.
-
-\yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
-|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
-|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
-commands are like the `|w|' commands except that they involve |x| instead
-of |w|.
-
-\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
-signed quantity in two's complement notation, |-128<=b<128|. This command
-changes the current |x|~spacing and moves right by |b|.
-
-\yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long,
-|-32768<=b<32768|.
-
-\yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
-|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
-|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
-The parameter is a signed number in two's complement notation, |-128<=a<128|;
-if |a<0|, the reference point moves up.
-
-\yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a
-two-byte quantity in the range |-32768<=a<32768|.
-
-\yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a
-three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a
-four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
-this parameterless command will usually suffice, because the same kind of motion
-will occur several times in succession; the following commands explain how
-|y| gets particular values.
-
-\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
-signed quantity in two's complement notation, |-128<=a<128|. This command
-changes the current |y|~spacing and moves down by |a|.
-
-\yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long,
-|-32768<=a<32768|.
-
-\yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
-|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
-|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
-are like the `|y|' commands except that they involve |z| instead of |y|.
-
-\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
-signed quantity in two's complement notation, |-128<=a<128|. This command
-changes the current |z|~spacing and moves down by |a|.
-
-\yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long,
-|-32768<=a<32768|.
-
-\yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
-|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
-|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
-defined by a \\{fnt\_def} instruction, as explained below.
-
-\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
-|f:=1|, \dots, \hbox{|f:=63|}, respectively.
-
-\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
-numbers in the range |64<=k<256|.
-
-\yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
-bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
-command, but large font numbers may prove useful for specifications of
-color or texture, or they may be used for special fonts that have fixed
-numbers in some external coding scheme.
-
-\yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
-bytes long, so it can be as large as $2^{24}-1$.
-
-\yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
-bytes long; this is for the really big font numbers (and for the negative ones).
-
-\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
-general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
-programs are being used. \TeX82 generates |xxx1| when a short enough
-\.{\\special} appears, setting |k| to the number of bytes being sent. It
-is recommended that |x| be a string having the form of a keyword followed
-by possible parameters relevant to that keyword.
-
-\yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
-
-\yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
-
-\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
-large. \TeX82 uses |xxx4| when sending a string of length 256 or more.
-
-\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<256|; font definitions will be explained shortly.
-
-\yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<65536|.
-
-\yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<@t$2^{24}$@>|.
-
-\yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
-
-\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
-Beginning of the preamble; this must come at the very beginning of the
-file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
-
-\yskip\hang|post| 248. Beginning of the postamble, see below.
-
-\yskip\hang|post_post| 249. Ending of the postamble, see below.
-
-\yskip\noindent Commands 250--255 are undefined at the present time.
-
- at c
-#define set_char_0 0 /* typeset character 0 and move right */
-#define set1 128 /* typeset a character and move right */
-#define set_rule 132 /* typeset a rule and move right */
-#define put1 133 /* typeset a character without moving */
-#define put_rule 137 /* typeset a rule */
-#define nop 138 /* no operation */
-#define bop 139 /* beginning of page */
-#define eop 140 /* ending of page */
-#define push 141 /* save the current positions */
-#define pop 142 /* restore previous positions */
-#define right1 143 /* move right */
-#define right4 146 /* move right, 4 bytes */
-#define w0 147 /* move right by |w| */
-#define w1 148 /* move right and set |w| */
-#define x0 152 /* move right by |x| */
-#define x1 153 /* move right and set |x| */
-#define down1 157 /* move down */
-#define down4 160 /* move down, 4 bytes */
-#define y0 161 /* move down by |y| */
-#define y1 162 /* move down and set |y| */
-#define z0 166 /* move down by |z| */
-#define z1 167 /* move down and set |z| */
-#define fnt_num_0 171 /* set current font to 0 */
-#define fnt1 235 /* set current font */
-#define xxx1 239 /* extension to \.{DVI} primitives */
-#define xxx4 242 /* potentially long extension to \.{DVI} primitives */
-#define fnt_def1 243 /* define the meaning of a font number */
-#define pre 247 /* preamble */
-#define post 248 /* postamble beginning */
-#define post_post 249 /* postamble ending */
-
-@ The preamble contains basic information about the file as a whole. As
-stated above, there are six parameters:
-$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
-The |i| byte identifies \.{DVI} format; currently this byte is always set
-to~2. (The value |i=3| is currently used for an extended format that
-allows a mixture of right-to-left and left-to-right typesetting.
-Some day we will set |i=4|, when \.{DVI} format makes another
-incompatible change---perhaps in the year 2048.)
-
-The next two parameters, |num| and |den|, are positive integers that define
-the units of measurement; they are the numerator and denominator of a
-fraction by which all dimensions in the \.{DVI} file could be multiplied
-in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
-254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
-sp in a point, \TeX\ sets
-$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
-@^sp@>
-
-The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
-desired magnification. The actual fraction by which dimensions are
-multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
-source document does not call for any `\.{true}' dimensions, and if you
-change it only by specifying a different \.{\\mag} setting, the \.{DVI}
-file that \TeX\ creates will be completely unchanged except for the value
-of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
-users to override the |mag|~setting when a \.{DVI} file is being printed.)
-
-Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
-interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
-
-
- at c
-#define id_byte 2 /* identifies the kind of \.{DVI} files described here */
-
-@ Font definitions for a given font number |k| contain further parameters
-$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
-The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM}
-file for this font; |c| should match the check sum of the font found by
-programs that read this \.{DVI} file.
-@^check sum@>
-
-Parameter |s| contains a fixed-point scale factor that is applied to
-the character widths in font |k|; font dimensions in \.{TFM} files and
-other font files are relative to this quantity, which is called the
-``at size'' elsewhere in this documentation. The value of |s| is
-always positive and less than $2^{27}$. It is given in the same units
-as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
-file. Parameter |d| is similar to |s|; it is the ``design size,'' and
-(like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
-at $|mag|\cdot s/1000d$ times its normal size.
-
-The remaining part of a font definition gives the external name of the font,
-which is an ASCII string of length |a+l|. The number |a| is the length
-of the ``area'' or directory, and |l| is the length of the font name itself;
-the standard local system font area is supposed to be used when |a=0|.
-The |n| field contains the area in its first |a| bytes.
-
-Font definitions must appear before the first use of a particular font number.
-Once font |k| is defined, it must not be defined again; however, we
-shall see below that font definitions appear in the postamble as well as
-in the pages, so in this sense each font number is defined exactly twice,
-if at all. Like |nop| commands, font definitions can
-appear before the first |bop|, or between an |eop| and a |bop|.
-
-@ Sometimes it is desirable to make horizontal or vertical rules line up
-precisely with certain features in characters of a font. It is possible to
-guarantee the correct matching between \.{DVI} output and the characters
-generated by \MF\ by adhering to the following principles: (1)~The \MF\
-characters should be positioned so that a bottom edge or left edge that is
-supposed to line up with the bottom or left edge of a rule appears at the
-reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
-ensures that the position of the rule will not be rounded differently when
-the pixel size is not a perfect multiple of the units of measurement in
-the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
-should be equivalent to a \MF-generated character having black pixels in
-precisely those raster positions whose \MF\ coordinates satisfy
-|0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number
-of pixels per \.{DVI} unit.
-@:METAFONT}{\MF@>
-@^alignment of rules with characters@>
-@^rules aligning with characters@>
-
-@ The last page in a \.{DVI} file is followed by `|post|'; this command
-introduces the postamble, which summarizes important facts that \TeX\ has
-accumulated about the file, making it possible to print subsets of the data
-with reasonable efficiency. The postamble has the form
-$$\vbox{\halign{\hbox{#\hfil}\cr
- |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
- $\langle\,$font definitions$\,\rangle$\cr
- |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
-Here |p| is a pointer to the final |bop| in the file. The next three
-parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
-appeared in the preamble.
-
-Parameters |l| and |u| give respectively the height-plus-depth of the tallest
-page and the width of the widest page, in the same units as other dimensions
-of the file. These numbers might be used by a \.{DVI}-reading program to
-position individual ``pages'' on large sheets of film or paper; however,
-the standard convention for output on normal size paper is to position each
-page so that the upper left-hand corner is exactly one inch from the left
-and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
-software that attempts cleverly to center the output; a fixed position of
-the upper left corner is easiest for users to understand and to work with.
-Therefore |l| and~|u| are often ignored.
-
-Parameter |s| is the maximum stack depth (i.e., the largest excess of
-|push| commands over |pop| commands) needed to process this file. Then
-comes |t|, the total number of pages (|bop| commands) present.
-
-The postamble continues with font definitions, which are any number of
-\\{fnt\_def} commands as described above, possibly interspersed with |nop|
-commands. Each font number that is used in the \.{DVI} file must be defined
-exactly twice: Once before it is first selected by a \\{fnt} command, and once
-in the postamble.
-
-@ The last part of the postamble, following the |post_post| byte that
-signifies the end of the font definitions, contains |q|, a pointer to the
-|post| command that started the postamble. An identification byte, |i|,
-comes next; this currently equals~2, as in the preamble.
-
-The |i| byte is followed by four or more bytes that are all equal to
-the decimal number 223 (i.e., '337 in octal). \TeX\ puts out four to seven of
-these trailing bytes, until the total length of the file is a multiple of
-four bytes, since this works out best on machines that pack four bytes per
-word; but any number of 223's is allowed, as long as there are at least four
-of them. In effect, 223 is a sort of signature that is added at the very end.
-@^Fuchs, David Raymond@>
-
-This curious way to finish off a \.{DVI} file makes it feasible for
-\.{DVI}-reading programs to find the postamble first, on most computers,
-even though \TeX\ wants to write the postamble last. Most operating
-systems permit random access to individual words or bytes of a file, so
-the \.{DVI} reader can start at the end and skip backwards over the 223's
-until finding the identification byte. Then it can back up four bytes, read
-|q|, and move to byte |q| of the file. This byte should, of course,
-contain the value 248 (|post|); now the postamble can be read, so the
-\.{DVI} reader can discover all the information needed for typesetting the
-pages. Note that it is also possible to skip through the \.{DVI} file at
-reasonably high speed to locate a particular page, if that proves
-desirable. This saves a lot of time, since \.{DVI} files used in production
-jobs tend to be large.
-
-Unfortunately, however, standard \PASCAL\ does not include the ability to
-@^system dependencies@>
-access a random position in a file, or even to determine the length of a file.
-Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
-format has been designed to work most efficiently with modern operating systems.
-But if \.{DVI} files have to be processed under the restrictions of standard
-\PASCAL, one can simply read them from front to back, since the necessary
-header information is present in the preamble and in the font definitions.
-(The |l| and |u| and |s| and |t| parameters, which appear only in the
-postamble, are ``frills'' that are handy but not absolutely necessary.)
-
-
-@* \[32] Shipping pages out.
-After considering \TeX's eyes and stomach, we come now to the bowels.
-@^bowels@>
-
-The |ship_out| procedure is given a pointer to a box; its mission is
-to describe that box in \.{DVI} form, outputting a ``page'' to |dvi_file|.
-The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
-corner of the box being shipped.
-
-Since boxes can be inside of boxes inside of boxes, the main work of
-|ship_out| is done by two mutually recursive routines, |hlist_out|
-and |vlist_out|, which traverse the hlists and vlists inside of horizontal
-and vertical boxes.
-
-As individual pages are being processed, we need to accumulate
-information about the entire set of pages, since such statistics must be
-reported in the postamble. The global variables |total_pages|, |max_v|,
-|max_h|, |max_push|, and |last_bop| are used to record this information.
-
-The variable |doing_leaders| is |true| while leaders are being output.
-The variable |dead_cycles| contains the number of times an output routine
-has been initiated since the last |ship_out|.
-
-A few additional global variables are also defined here for use in
-|vlist_out| and |hlist_out|. They could have been local variables, but
-that would waste stack space when boxes are deeply nested, since the
-values of these variables are not needed during recursive calls.
-@^recursion@>
-
- at c
-int total_pages = 0; /* the number of pages that have been shipped out */
-scaled max_v = 0; /* maximum height-plus-depth of pages shipped so far */
-scaled max_h = 0; /* maximum width of pages shipped so far */
-int max_push = 0; /* deepest nesting of |push| commands encountered so far */
-int last_bop = -1; /* location of previous |bop| in the \.{DVI} output */
-int dead_cycles = 0; /* recent outputs that didn't ship anything out */
-boolean doing_leaders = false; /* are we inside a leader box? */
-int oval, ocmd; /* used by |out_cmd| for generating |set|, |fnt| and |fnt_def| commands */
-pointer g; /* current glue specification */
-int lq, lr; /* quantities used in calculations for leaders */
-int cur_s = -1; /* current depth of output box nesting, initially $-1$ */
-
-@ The \.{DVI} bytes are output to a buffer instead of being written directly
-to the output file. This makes it possible to reduce the overhead of
-subroutine calls, thereby measurably speeding up the computation, since
-output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
-advantage as well, since we can change instructions in the buffer in order to
-make the output more compact. For example, a `|down2|' command can be
-changed to a `|y2|', thereby making a subsequent `|y0|' command possible,
-saving two bytes.
-
-The output buffer is divided into two parts of equal size; the bytes found
-in |dvi_buf[0..half_buf-1]| constitute the first half, and those in
-|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global
-variable |dvi_ptr| points to the position that will receive the next
-output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
-to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
-is about to be invaded next is sent to the output and |dvi_limit| is
-changed to its other value. Thus, there is always at least a half buffer's
-worth of information present, except at the very beginning of the job.
-
-Bytes of the \.{DVI} file are numbered sequentially starting with 0;
-the next byte to be generated will be number |dvi_offset+dvi_ptr|.
-A byte is present in the buffer only if its number is |>=dvi_gone|.
-
-Some systems may find it more efficient to make |dvi_buf| a |packed|
-array, since output of four bytes at once may be facilitated.
-@^system dependencies@>
-
-
-@ Initially the buffer is all in one piece; we will output half of it only
-after it first fills up.
-
- at c
-int dvi_buf_size = 800; /* size of the output buffer; must be a multiple of 8 */
-eight_bits *dvi_buf; /* buffer for \.{DVI} output */
-dvi_index half_buf = 0; /* half of |dvi_buf_size| */
-dvi_index dvi_limit = 0; /* end of the current half buffer */
-dvi_index dvi_ptr = 0; /* the next available buffer address */
-int dvi_offset = 0; /* |dvi_buf_size| times the number of times the output buffer has been fully emptied */
-int dvi_gone = 0; /* the number of bytes already output to |dvi_file| */
-
-@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
-|write_dvi(a,b)|. For best results, this procedure should be optimized to
-run as fast as possible on each particular system, since it is part of
-\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
-multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
-many machines to use efficient methods to pack four bytes per word and to
-output an array of words with one system call.
-@^system dependencies@>
-@^inner loop@>
-@^defecation@>
-
- at c
-static void write_dvi(dvi_index a, dvi_index b)
-{
- dvi_index k;
- for (k = a; k <= b; k++)
- fputc(dvi_buf[k], static_pdf->file);
-}
-
-/* outputs half of the buffer */
-void dvi_swap(void)
-{
- if (dvi_limit == dvi_buf_size) {
- write_dvi(0, half_buf - 1);
- dvi_limit = half_buf;
- dvi_offset = dvi_offset + dvi_buf_size;
- dvi_ptr = 0;
- } else {
- write_dvi(half_buf, dvi_buf_size - 1);
- dvi_limit = dvi_buf_size;
- }
- dvi_gone = dvi_gone + half_buf;
-}
-
-@ The |dvi_four| procedure outputs four bytes in two's complement notation,
-without risking arithmetic overflow.
-
- at c
-void dvi_four(int x)
-{
- if (x >= 0) {
- dvi_out(x / 0100000000);
- } else {
- x = x + 010000000000;
- x = x + 010000000000;
- dvi_out((x / 0100000000) + 128);
- }
- x = x % 0100000000;
- dvi_out(x / 0200000);
- x = x % 0200000;
- dvi_out(x / 0400);
- dvi_out(x % 0400);
-}
-
-@
-A mild optimization of the output is performed by the |dvi_pop|
-routine, which issues a |pop| unless it is possible to cancel a
-`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address
-following the old |push| that matches the new |pop|.
-
-
- at c
-void dvi_push(void)
-{
- dvi_out(push);
-}
-
-void dvi_pop(int l)
-{
- if ((l == dvi_offset + dvi_ptr) && (dvi_ptr > 0))
- decr(dvi_ptr);
- else
- dvi_out(pop);
-}
-
-@ Here's a procedure that outputs a font definition. $\Omega$ allows
-more than 256 different fonts per job, so the right font definition
-command must be selected.
-
- at c
-void out_cmd(void)
-{
- if ((oval < 0x100) && (oval >= 0)) {
- if ((ocmd != set1) || (oval > 127)) {
- if ((ocmd == fnt1) && (oval < 64))
- oval += fnt_num_0;
- else
- dvi_out(ocmd);
- }
- } else {
- if ((oval < 0x10000) && (oval >= 0)) {
- dvi_out(ocmd + 1);
- } else {
- if ((oval < 0x1000000) && (oval >= 0)) {
- dvi_out(ocmd + 2);
- } else {
- dvi_out(ocmd + 3);
- if (oval >= 0) {
- dvi_out(oval / 0x1000000);
- } else {
- oval += 0x40000000;
- oval += 0x40000000;
- dvi_out((oval / 0x1000000) + 128);
- oval = oval % 0x1000000;
- }
- dvi_out(oval / 0x10000);
- oval = oval % 0x10000;
- }
- dvi_out(oval / 0x10000);
- oval = oval % 0x10000;
- }
- dvi_out(oval / 0x100);
- oval = oval % 0x100;
- }
- dvi_out(oval);
-}
-
-void dvi_font_def(internal_font_number f)
-{
- char *fa;
- oval = f - 1;
- ocmd = fnt_def1;
- out_cmd();
- dvi_out(font_check_0(f));
- dvi_out(font_check_1(f));
- dvi_out(font_check_2(f));
- dvi_out(font_check_3(f));
- dvi_four(font_size(f));
- dvi_four(font_dsize(f));
- dvi_out(0); /* |font_area(f)| is unused */
- dvi_out(strlen(font_name(f)));
- /* Output the font name whose internal number is |f| */
- fa = font_name(f);
- while (*fa != '\0') {
- dvi_out(*fa++);
- }
-}
-
-@ Versions of \TeX\ intended for small computers might well choose to omit
-the ideas in the next few parts of this program, since it is not really
-necessary to optimize the \.{DVI} code by making use of the |w0|, |x0|,
-|y0|, and |z0| commands. Furthermore, the algorithm that we are about to
-describe does not pretend to give an optimum reduction in the length
-of the \.{DVI} code; after all, speed is more important than compactness.
-But the method is surprisingly effective, and it takes comparatively little
-time.
-
-We can best understand the basic idea by first considering a simpler problem
-that has the same essential characteristics. Given a sequence of digits,
-say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
-$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
-and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
-digit with the subscript $y$, where no $y$'s intervene between the two
-appearances, and a $z$-hit is defined similarly. For example, the sequence
-above could be decorated with subscripts as follows:
-$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
-There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
-one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
-of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
-matter how many there are. These subscripts are analogous to the \.{DVI}
-commands called \\{down}, $y$, and $z$, and the digits are analogous to
-different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
-the opportunity to use the one-byte commands |y0| or |z0| in a \.{DVI} file.
-
-\TeX's method of assigning subscripts works like this: Append a new digit,
-say $\delta$, to the right of the sequence. Now look back through the
-sequence until one of the following things happens: (a)~You see
-$\delta_y$ or $\delta_z$, and this was the first time you encountered a
-$y$ or $z$ subscript, respectively. Then assign $y$ or $z$ to the new
-$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
-subscripts have been encountered so far during this search. Then change
-the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
-command in the output buffer), and assign $y$ to the new $\delta$; it's
-another hit. (c)~You see $\delta_d$, and a $y$ subscript has been seen
-but not a $z$. Change the previous $\delta_d$ to $\delta_z$ and assign
-$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
-before encountering a suitable $\delta$, or you scan all the way to the
-front of the sequence. Assign $d$ to the new $\delta$; this assignment may
-be changed later.
-
-The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
-produced by this procedure, as the reader can verify. (Go ahead and try it.)
-
-@ In order to implement such an idea, \TeX\ maintains a stack of pointers
-to the \\{down}, $y$, and $z$ commands that have been generated for the
-current page. And there is a similar stack for \\{right}, |w|, and |x|
-commands. These stacks are called the down stack and right stack, and their
-top elements are maintained in the variables |down_ptr| and |right_ptr|.
-
-Each entry in these stacks contains four fields: The |width| field is
-the amount of motion down or to the right; the |location| field is the
-byte number of the \.{DVI} command in question (including the appropriate
-|dvi_offset|); the |vlink| field points to the next item below this one
-on the stack; and the |vinfo| field encodes the options for possible change
-in the \.{DVI} command.
-
- at c
-#define location(A) varmem[(A)+1].cint /* \.{DVI} byte number for a movement command */
-
-halfword down_ptr = null, right_ptr = null; /* heads of the down and right stacks */
-
-@ Here is a subroutine that produces a \.{DVI} command for some specified
-downward or rightward motion. It has two parameters: |w| is the amount
-of motion, and |o| is either |down1| or |right1|. We use the fact that
-the command codes have convenient arithmetic properties: |y1-down1=w1-right1|
-and |z1-down1=x1-right1|.
-
- at c
-void movement(scaled w, eight_bits o)
-{
- small_number mstate; /* have we seen a |y| or |z|? */
- halfword p, q; /* current and top nodes on the stack */
- int k; /* index into |dvi_buf|, modulo |dvi_buf_size| */
- if (false) { /* TODO: HUH? */
- q = new_node(movement_node, 0); /* new node for the top of the stack */
- width(q) = w;
- location(q) = dvi_offset + dvi_ptr;
- if (o == down1) {
- vlink(q) = down_ptr;
- down_ptr = q;
- } else {
- vlink(q) = right_ptr;
- right_ptr = q;
- }
- /* Look at the other stack entries until deciding what sort of \.{DVI} command
- to generate; |goto found| if node |p| is a ``hit'' */
- p = vlink(q);
- mstate = none_seen;
- while (p != null) {
- if (width(p) == w) {
- /* Consider a node with matching width;|goto found| if it's a hit */
- /* We might find a valid hit in a |y| or |z| byte that is already gone
- from the buffer. But we can't change bytes that are gone forever; ``the
- moving finger writes, $\ldots\,\,$.'' */
-
- switch (mstate + vinfo(p)) {
- case none_seen + yz_OK:
- case none_seen + y_OK:
- case z_seen + yz_OK:
- case z_seen + y_OK:
- if (location(p) < dvi_gone) {
- goto NOT_FOUND;
- } else {
- /* Change buffered instruction to |y| or |w| and |goto found| */
- k = location(p) - dvi_offset;
- if (k < 0)
- k = k + dvi_buf_size;
- dvi_buf[k] = (eight_bits) (dvi_buf[k] + y1 - down1);
- vinfo(p) = y_here;
- goto FOUND;
- }
- break;
- case none_seen + z_OK:
- case y_seen + yz_OK:
- case y_seen + z_OK:
- if (location(p) < dvi_gone) {
- goto NOT_FOUND;
- } else {
- /* Change buffered instruction to |z| or |x| and |goto found| */
- k = location(p) - dvi_offset;
- if (k < 0)
- k = k + dvi_buf_size;
- dvi_buf[k] = (eight_bits) (dvi_buf[k] + z1 - down1);
- vinfo(p) = z_here;
- goto FOUND;
- }
- break;
- case none_seen + y_here:
- case none_seen + z_here:
- case y_seen + z_here:
- case z_seen + y_here:
- goto FOUND;
- break;
- default:
- break;
- }
- } else {
- switch (mstate + vinfo(p)) {
- case none_seen + y_here:
- mstate = y_seen;
- break;
- case none_seen + z_here:
- mstate = z_seen;
- break;
- case y_seen + z_here:
- case z_seen + y_here:
- goto NOT_FOUND;
- break;
- default:
- break;
- }
- }
- p = vlink(p);
- }
- }
- NOT_FOUND:
- /* Generate a |down| or |right| command for |w| and |return| */
- if (abs(w) >= 040000000) {
- dvi_out(o + 3); /* |down4| or |right4| */
- dvi_four(w);
- return;
- }
- if (abs(w) >= 0100000) {
- dvi_out(o + 2); /* |down3| or |right3| */
- if (w < 0)
- w = w + 0100000000;
- dvi_out(w / 0200000);
- w = w % 0200000;
- goto TWO;
- }
- if (abs(w) >= 0200) {
- dvi_out(o + 1); /* |down2| or |right2| */
- if (w < 0)
- w = w + 0200000;
- goto TWO;
- }
- dvi_out(o); /* |down1| or |right1| */
- if (w < 0)
- w = w + 0400;
- goto ONE;
- TWO:
- dvi_out(w / 0400);
- ONE:
- dvi_out(w % 0400);
- return;
- FOUND:
- /* Generate a |y0| or |z0| command in order to reuse a previous appearance of~|w| */
- /* The program below removes movement nodes that are introduced after a |push|,
- before it outputs the corresponding |pop|. */
- /*
- When the |movement| procedure gets to the label |found|, the value of
- |vinfo(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
- the procedure generates a |y0| command (or a |w0| command), and marks
- all |vinfo| fields between |q| and |p| so that |y| is not OK in that range.
- */
- vinfo(q) = vinfo(p);
- if (vinfo(q) == y_here) {
- dvi_out(o + y0 - down1); /* |y0| or |w0| */
- while (vlink(q) != p) {
- q = vlink(q);
- switch (vinfo(q)) {
- case yz_OK:
- vinfo(q) = z_OK;
- break;
- case y_OK:
- vinfo(q) = d_fixed;
- break;
- default:
- break;
- }
- }
- } else {
- dvi_out(o + z0 - down1); /* |z0| or |x0| */
- while (vlink(q) != p) {
- q = vlink(q);
- switch (vinfo(q)) {
- case yz_OK:
- vinfo(q) = y_OK;
- break;
- case z_OK:
- vinfo(q) = d_fixed;
- break;
- default:
- break;
- }
- }
- }
-}
-
-@ In case you are wondering when all the movement nodes are removed from
-\TeX's memory, the answer is that they are recycled just before
-|hlist_out| and |vlist_out| finish outputting a box. This restores the
-down and right stacks to the state they were in before the box was output,
-except that some |vinfo|'s may have become more restrictive.
-
-
- at c
-/* delete movement nodes with |location>=l| */
-void prune_movements(int l)
-{
- pointer p; /* node being deleted */
- while (down_ptr != null) {
- if (location(down_ptr) < l)
- break;
- p = down_ptr;
- down_ptr = vlink(p);
- flush_node(p);
- }
- while (right_ptr != null) {
- if (location(right_ptr) < l)
- return;
- p = right_ptr;
- right_ptr = vlink(p);
- flush_node(p);
- }
-}
-
-scaledpos dvi; /* a \.{DVI} position in page coordinates, in sync with DVI file */
-
-@ When |hlist_out| is called, its duty is to output the box represented
-by the |hlist_node| pointed to by |temp_ptr|. The reference point of that
-box has coordinates |(cur.h,cur.v)|.
-
-Similarly, when |vlist_out| is called, its duty is to output the box represented
-by the |vlist_node| pointed to by |temp_ptr|. The reference point of that
-box has coordinates |(cur.h,cur.v)|.
-@^recursion@>
-
-@ The recursive procedures |hlist_out| and |vlist_out| each have a local variable
-|save_dvi| to hold the value of |dvi| just before
-entering a new level of recursion. In effect, the value of |save_dvi|
-on \TeX's run-time stack corresponds to the values of |h| and |v|
-that a \.{DVI}-reading program will push onto its coordinate stack.
-
- at c
-void dvi_place_rule(PDF pdf, halfword q, scaledpos size)
-{
- synch_dvi_with_pos(pdf->posstruct->pos);
- if ((subtype(q) >= box_rule) && (subtype(q) <= user_rule)) {
- /* place nothing, only take space */
- if (textdir_is_L(pdf->posstruct->dir))
- dvi.h += size.h;
- } else {
- /* normal_rule or >= 100 being a leader rule */
- if (textdir_is_L(pdf->posstruct->dir)) {
- dvi_out(set_rule); /* movement optimization for |dir_*L*| */
- dvi.h += size.h;
- } else
- dvi_out(put_rule);
- }
- dvi_four(size.v);
- dvi_four(size.h);
-}
-
-void dvi_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
-{
- /* TODO: do something on ex, select font (if possible) */
- scaled_whd ci;
- synch_dvi_with_pos(pdf->posstruct->pos);
- if (f != pdf->f_cur) {
- /* Change font |f_cur| to |f| */
- if (!font_used(f)) {
- dvi_font_def(f);
- set_font_used(f, true);
- }
- oval = f - 1;
- ocmd = fnt1;
- out_cmd();
- pdf->f_cur = f;
- }
- if (textdir_is_L(pdf->posstruct->dir)) {
- ci = get_charinfo_whd(f, c);
- dvi_set(c, ci.wd); /* movement optimization for |dir_*L*| */
- } else
- dvi_put(c);
-}
-
-void dvi_special(PDF pdf, halfword p)
-{
- int old_setting; /* holds print |selector| */
- unsigned k; /* index into |cur_string| */
- synch_dvi_with_pos(pdf->posstruct->pos);
- old_setting = selector;
- selector = new_string;
- show_token_list(token_link(write_tokens(p)), null, -1);
- selector = old_setting;
- if (cur_length < 256) {
- dvi_out(xxx1);
- dvi_out(cur_length);
- } else {
- dvi_out(xxx4);
- dvi_four((int) cur_length);
- }
- for (k = 0; k < cur_length; k++)
- dvi_out(cur_string[k]);
- cur_length = 0; /* erase the string */
-}
-
-@ Here's an example of how these conventions are used. Whenever it is time to
-ship out a box of stuff, we shall use the macro |ensure_dvi_open|.
-
- at c
-void ensure_dvi_header_written(PDF pdf)
-{
- unsigned l;
- unsigned s; /* index into |str_pool| */
- int old_setting; /* saved |selector| setting */
- assert(output_mode_used == OMODE_DVI);
- assert(pdf->o_state == ST_FILE_OPEN);
-
- if (half_buf == 0) {
- half_buf = dvi_buf_size / 2;
- dvi_limit = dvi_buf_size;
- }
-
- dvi_out(pre);
- dvi_out(id_byte); /* output the preamble */
- dvi_four(25400000);
- dvi_four(473628672); /* conversion ratio for sp */
- prepare_mag();
- dvi_four(mag_par); /* magnification factor is frozen */
- if (output_comment) {
- l = (unsigned) strlen(output_comment);
- dvi_out(l);
- for (s = 0; s < l; s++)
- dvi_out(output_comment[s]);
- } else { /* the default code is unchanged */
- old_setting = selector;
- selector = new_string;
- tprint(" LuaTeX output ");
- print_int(year_par);
- print_char('.');
- print_two(month_par);
- print_char('.');
- print_two(day_par);
- print_char(':');
- print_two(time_par / 60);
- print_two(time_par % 60);
- selector = old_setting;
- dvi_out(cur_length);
- for (s = 0; s < cur_length; s++)
- dvi_out(cur_string[s]);
- cur_length = 0;
- }
-}
-
-void dvi_begin_page(PDF pdf)
-{
- int k;
- int page_loc; /* location of the current |bop| */
- ensure_output_state(pdf, ST_HEADER_WRITTEN);
- /* Initialize variables as |ship_out| begins */
- page_loc = dvi_offset + dvi_ptr;
- dvi_out(bop);
- for (k = 0; k <= 9; k++)
- dvi_four(count(k));
- dvi_four(last_bop);
- last_bop = page_loc;
-}
-
-void dvi_end_page(PDF pdf)
-{
- (void) pdf;
- dvi_out(eop);
-}
-
-@ At the end of the program, we must finish things off by writing the
-post\-amble. If |total_pages=0|, the \.{DVI} file was never opened.
-If |total_pages>=65536|, the \.{DVI} file will lie. And if
-|max_push>=65536|, the user deserves whatever chaos might ensue.
-
- at c
-void finish_dvi_file(PDF pdf, int version, int revision)
-{
- int k;
- int callback_id = callback_defined(stop_run_callback);
- (void) version;
- (void) revision;
- while (cur_s > -1) {
- if (cur_s > 0) {
- dvi_out(pop);
- } else {
- dvi_out(eop);
- incr(total_pages);
- }
- decr(cur_s);
- }
- if (total_pages == 0) {
- if (callback_id == 0) {
- tprint_nl("No pages of output.");
- print_ln();
- } else if (callback_id > 0) {
- run_callback(callback_id, "->");
- }
- } else {
- dvi_out(post); /* beginning of the postamble */
- dvi_four(last_bop);
- last_bop = dvi_offset + dvi_ptr - 5; /* |post| location */
- dvi_four(25400000);
- dvi_four(473628672); /* conversion ratio for sp */
- prepare_mag();
- dvi_four(mag_par); /* magnification factor */
- dvi_four(max_v);
- dvi_four(max_h);
- dvi_out(max_push / 256);
- dvi_out(max_push % 256);
- dvi_out((total_pages / 256) % 256);
- dvi_out(total_pages % 256);
- /* Output the font definitions for all fonts that were used */
- k = max_font_id();
- while (k > 0) {
- if (font_used(k)) {
- dvi_font_def(k);
- }
- decr(k);
- }
-
- dvi_out(post_post);
- dvi_four(last_bop);
- dvi_out(id_byte);
-#ifndef IPC
- k = 4 + ((dvi_buf_size - dvi_ptr) % 4); /* the number of 223's */
-#else
- k = 7 - ((3 + dvi_offset + dvi_ptr) % 4); /* the number of 223's */
-#endif
-
- while (k > 0) {
- dvi_out(223);
- decr(k);
- }
- /* Empty the last bytes out of |dvi_buf| */
- /* Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
- will be a multiple of~4. */
- if (dvi_limit == half_buf)
- write_dvi(half_buf, dvi_buf_size - 1);
- if (dvi_ptr > 0)
- write_dvi(0, dvi_ptr - 1);
-
- if (callback_id == 0) {
- tprint_nl("Output written on ");
- tprint(pdf->file_name);
- tprint(" (");
- print_int(total_pages);
- tprint(" page");
- if (total_pages != 1)
- print_char('s');
- tprint(", ");
- print_int(dvi_offset + dvi_ptr);
- tprint(" bytes).");
- } else if (callback_id > 0) {
- run_callback(callback_id, "->");
- }
- close_file(pdf->file);
- }
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/dofont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/dofont.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/dofont.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,141 @@
+/*
+
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/*tex
+
+ A bit more interfacing is needed for proper error reporting.
+
+*/
+
+static char *font_error_message(pointer u, char *nom, scaled s)
+{
+ char *str = xmalloc(256);
+ char *c = makecstring(cs_text(u));
+ const char *extra = "metric data not found or bad";
+ if (s >= 0) {
+ snprintf(str, 255, "Font \\%s=%s at %gpt not loadable: %s", c, nom, (double) s / 65536, extra);
+ } else if (s != -1000) {
+ snprintf(str, 255, "Font \\%s=%s scaled %d not loadable: %s", c, nom, (int) (-s), extra);
+ } else {
+ snprintf(str, 255, "Font \\%s=%s not loadable: %s", c, nom, extra);
+ }
+ free(c);
+ return str;
+}
+
+static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
+{
+ boolean res = 0;
+ char *cnam;
+ int r, t;
+ int callback_id = callback_defined(define_font_callback);
+ if (callback_id > 0) {
+ cnam = xstrdup(cnom);
+ callback_id = run_and_save_callback(callback_id, "Sdd->", cnam, s, f);
+ free(cnam);
+ if (callback_id > 0) {
+ /*tex Success. */
+ luaL_checkstack(Luas, 1, "out of stack space");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, callback_id);
+ t = lua_type(Luas, -1);
+ if (t == LUA_TTABLE) {
+ res = font_from_lua(Luas, f);
+ destroy_saved_callback(callback_id);
+ } else if (t == LUA_TNUMBER) {
+ r = (int) lua_tointeger(Luas, -1);
+ destroy_saved_callback(callback_id);
+ delete_font(f);
+ lua_pop(Luas, 1);
+ return r;
+ } else {
+ lua_pop(Luas, 1);
+ delete_font(f);
+ return 0;
+ }
+ }
+ } else if (callback_id == 0) {
+ res = read_tfm_info(f, cnom, s);
+ if (res) {
+ set_hyphen_char(f, default_hyphen_char_par);
+ set_skew_char(f, default_skew_char_par);
+ }
+ }
+ if (font_name(f) && strlen(font_name(f)) > 255) {
+ /*tex
+
+ The font name has to fit in the dvi file's single byte storage. There
+ is no need to test area, as we are never using it.
+ */
+ res = 0;
+ }
+ if (res) {
+ if (font_type(f) != virtual_font_type) {
+ /*tex This implies \LUA. */
+ do_vf(f);
+ set_font_natural_dir(f, natural_dir);
+ }
+ return f;
+ } else {
+ delete_font(f);
+ return 0;
+ }
+
+}
+
+int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
+{
+ int f;
+ char *msg;
+
+ f = new_font();
+ if ((f = do_define_font(f, cnom, s, natural_dir))) {
+ return f;
+ } else {
+ const char *help[] = {
+ "I wasn't able to read the size data for this font,",
+ "so I will ignore the font specification.",
+ "[Wizards can fix TFM files using TFtoPL/PLtoTF.]",
+ "You might try inserting a different font spec;",
+ "e.g., type `I\\font<same font id>=<substitute font name>'.",
+ NULL
+ };
+ if (suppress_fontnotfound_error_par == 0) {
+ msg = font_error_message(u, cnom, s);
+ tex_error(msg, help);
+ free(msg);
+ }
+ return 0;
+ }
+}
+
+int find_font_id(const char *nom, scaled s)
+{
+ int f;
+ f = new_font();
+ if ((f = do_define_font(f, nom, s, -1))) {
+ return f;
+ } else {
+ return 0;
+ }
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/dofont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/dofont.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/dofont.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,145 +0,0 @@
-% dofont.w
-%
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-@ a bit more interfacing is needed for proper error reporting
-
- at c
-static char *font_error_message(pointer u, char *nom, scaled s)
-{
- char *str = xmalloc(256);
- char *c = makecstring(cs_text(u));
- const char *extra = "metric data not found or bad";
- if (s >= 0) {
- snprintf(str, 255, "Font \\%s=%s at %gpt not loadable: %s", c, nom,
- (double) s / 65536, extra);
- } else if (s != -1000) {
- snprintf(str, 255, "Font \\%s=%s scaled %d not loadable: %s", c, nom,
- (int) (-s), extra);
- } else {
- snprintf(str, 255, "Font \\%s=%s not loadable: %s", c, nom, extra);
- }
- free(c);
- return str;
-}
-
-static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
-{
-
- boolean res; /* was the callback successful? */
- int callback_id;
- char *cnam;
- int r, t;
- res = 0;
-
- callback_id = callback_defined(define_font_callback);
- if (callback_id > 0) {
- cnam = xstrdup(cnom);
- callback_id = run_and_save_callback(callback_id, "Sdd->", cnam, s, f);
- free(cnam);
- if (callback_id > 0) { /* success */
- luaL_checkstack(Luas, 1, "out of stack space");
- lua_rawgeti(Luas, LUA_REGISTRYINDEX, callback_id);
- t = lua_type(Luas, -1);
- if (t == LUA_TTABLE) {
- res = font_from_lua(Luas, f);
- destroy_saved_callback(callback_id);
- /* |lua_pop(Luas, 1);| *//* done by |font_from_lua| */
- } else if (t == LUA_TNUMBER) {
- r = (int) lua_tointeger(Luas, -1);
- destroy_saved_callback(callback_id);
- delete_font(f);
- lua_pop(Luas, 1);
- return r;
- } else {
- lua_pop(Luas, 1);
- delete_font(f);
- return 0;
- }
- }
- } else if (callback_id == 0) {
- res = read_tfm_info(f, cnom, s);
- if (res) {
- set_hyphen_char(f, default_hyphen_char_par);
- set_skew_char(f, default_skew_char_par);
- }
- }
- if (font_name(f) && strlen(font_name(f)) > 255) {
- /* the font name has to fit in the dvi file's single byte storage */
- /* no need to test area, as we are never using it */
- res = 0;
- }
- if (res) {
- if (font_type(f) != virtual_font_type) { /* implies lua */
- do_vf(f);
- set_font_natural_dir(f, natural_dir);
- }
- return f;
- } else {
- delete_font(f);
- return 0;
- }
-
-}
-
-int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
-{
- int f;
- char *msg;
-
- f = new_font();
- if ((f = do_define_font(f, cnom, s, natural_dir))) {
- return f;
- } else {
- const char *help[] =
- { "I wasn't able to read the size data for this font,",
- "so I will ignore the font specification.",
- "[Wizards can fix TFM files using TFtoPL/PLtoTF.]",
- "You might try inserting a different font spec;",
- "e.g., type `I\\font<same font id>=<substitute font name>'.",
- NULL
- };
- if (suppress_fontnotfound_error_par == 0) {
- msg = font_error_message(u, cnom, s);
- tex_error(msg, help);
- free(msg);
- }
- return 0;
- }
-}
-
-@ TODO This function is a placeholder. There can easily appears holes in
- the |font_tables| array, and we could attempt to reuse those
-
- at c
-int find_font_id(const char *nom, scaled s)
-{
- int f;
- f = new_font();
- if ((f = do_define_font(f, nom, s, -1))) {
- return f;
- } else {
- return 0;
- }
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/luafont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/luafont.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/luafont.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,2420 @@
+/*
+
+Copyright 2006-2011 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define noVERBOSE
+
+/*tex
+
+ Todo: make these keys.
+
+*/
+
+const char *font_type_strings[] = {
+ "unknown", "virtual", "real", NULL
+};
+
+const char *font_writingmode_strings[] = {
+ "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_identity_strings[] = {
+ "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_format_strings[] = {
+ "unknown", "type1", "type3", "truetype", "opentype", NULL
+};
+
+const char *font_embedding_strings[] = {
+ "unknown", "no", "subset", "full", NULL
+};
+
+const char *ligature_type_strings[] = {
+ "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
+};
+
+const char *MATH_param_names[] = {
+ "nil",
+ "ScriptPercentScaleDown",
+ "ScriptScriptPercentScaleDown",
+ "DelimitedSubFormulaMinHeight",
+ "DisplayOperatorMinHeight",
+ "MathLeading",
+ "AxisHeight",
+ "AccentBaseHeight",
+ "FlattenedAccentBaseHeight",
+ "SubscriptShiftDown",
+ "SubscriptTopMax",
+ "SubscriptBaselineDropMin",
+ "SuperscriptShiftUp",
+ "SuperscriptShiftUpCramped",
+ "SuperscriptBottomMin",
+ "SuperscriptBaselineDropMax",
+ "SubSuperscriptGapMin",
+ "SuperscriptBottomMaxWithSubscript",
+ "SpaceAfterScript",
+ "UpperLimitGapMin",
+ "UpperLimitBaselineRiseMin",
+ "LowerLimitGapMin",
+ "LowerLimitBaselineDropMin",
+ "StackTopShiftUp",
+ "StackTopDisplayStyleShiftUp",
+ "StackBottomShiftDown",
+ "StackBottomDisplayStyleShiftDown",
+ "StackGapMin",
+ "StackDisplayStyleGapMin",
+ "StretchStackTopShiftUp",
+ "StretchStackBottomShiftDown",
+ "StretchStackGapAboveMin",
+ "StretchStackGapBelowMin",
+ "FractionNumeratorShiftUp",
+ "FractionNumeratorDisplayStyleShiftUp",
+ "FractionDenominatorShiftDown",
+ "FractionDenominatorDisplayStyleShiftDown",
+ "FractionNumeratorGapMin",
+ "FractionNumeratorDisplayStyleGapMin",
+ "FractionRuleThickness",
+ "FractionDenominatorGapMin",
+ "FractionDenominatorDisplayStyleGapMin",
+ "SkewedFractionHorizontalGap",
+ "SkewedFractionVerticalGap",
+ "OverbarVerticalGap",
+ "OverbarRuleThickness",
+ "OverbarExtraAscender",
+ "UnderbarVerticalGap",
+ "UnderbarRuleThickness",
+ "UnderbarExtraDescender",
+ "RadicalVerticalGap",
+ "RadicalDisplayStyleVerticalGap",
+ "RadicalRuleThickness",
+ "RadicalExtraAscender",
+ "RadicalKernBeforeDegree",
+ "RadicalKernAfterDegree",
+ "RadicalDegreeBottomRaisePercent",
+ "MinConnectorOverlap",
+ "SubscriptShiftDownWithSuperscript",
+ "FractionDelimiterSize",
+ "FractionDelimiterDisplayStyleSize",
+ "NoLimitSubFactor",
+ "NoLimitSupFactor",
+ NULL,
+};
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
+ const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
+ int i;
+ for (i=0; lst[i]; i++)
+ if (strcmp(lst[i], name) == 0)
+ return i;
+ return -1;
+}
+
+#define dump_intfield(L,n,c) \
+ lua_push_string_by_name(L,n); \
+ lua_pushinteger(L, c); \
+ lua_rawset(L, -3); \
+
+#define dump_stringfield(L,n,c) \
+ lua_push_string_by_name(L,n); \
+ lua_pushstring(L, c); \
+ lua_rawset(L, -3);
+
+#define dump_booleanfield(L,n,c) \
+ lua_push_string_by_name(L,n); \
+ lua_pushboolean(L, c); \
+ lua_rawset(L, -3);
+
+static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
+{
+ int i;
+ for (i = 0; i < l; i++) {
+ lua_newtable(L);
+ if (id==top_left_kern) {
+ dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
+ dump_intfield(L, kern, co->top_left_math_kern_array[(2*i)+1]);
+ } else if (id==top_right_kern) {
+ dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
+ dump_intfield(L, kern, co->top_right_math_kern_array[(2*i)+1]);
+ } else if (id==bottom_right_kern) {
+ dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
+ dump_intfield(L, kern, co->bottom_right_math_kern_array[(2*i)+1]);
+ } else if (id==bottom_left_kern) {
+ dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
+ dump_intfield(L, kern, co->bottom_left_math_kern_array[(2*i)+1]);
+ }
+ lua_rawseti(L, -2, (i + 1));
+ }
+}
+
+static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
+{
+ liginfo *l;
+ kerninfo *ki;
+ lua_createtable(L, 0, 10);
+ dump_intfield(L,width,get_charinfo_width(co));
+ dump_intfield(L,height,get_charinfo_height(co));
+ dump_intfield(L,depth,get_charinfo_depth(co));
+ if (get_charinfo_italic(co) != 0) {
+ dump_intfield(L,italic,get_charinfo_italic(co));
+ }
+ if (get_charinfo_vert_italic(co) != 0) {
+ dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
+ }
+ if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
+ dump_intfield(L,top_accent,get_charinfo_top_accent(co));
+ }
+ if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
+ dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
+ }
+ if (get_charinfo_ef(co) != 1000) {
+ dump_intfield(L,expansion_factor,get_charinfo_ef(co));
+ }
+ if (get_charinfo_lp(co) != 0) {
+ dump_intfield(L,left_protruding,get_charinfo_lp(co));
+ }
+ if (get_charinfo_rp(co) != 0) {
+ dump_intfield(L,right_protruding,get_charinfo_rp(co));
+ }
+ if (font_encodingbytes(f) == 2) {
+ dump_intfield(L,index,get_charinfo_index(co));
+ }
+ if (get_charinfo_name(co) != NULL) {
+ dump_stringfield(L,name,get_charinfo_name(co));
+ }
+ if (get_charinfo_tounicode(co) != NULL) {
+ dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
+ }
+ if (get_charinfo_tag(co) == list_tag) {
+ dump_intfield(L,next,get_charinfo_remainder(co));
+ }
+ if (get_charinfo_used(co)) {
+ dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
+ }
+ if (get_charinfo_tag(co) == ext_tag) {
+ extinfo *h;
+ h = get_charinfo_hor_variants(co);
+ if (h != NULL) {
+ int i = 1;
+ lua_push_string_by_name(L,horiz_variants);
+ lua_newtable(L);
+ while (h != NULL) {
+ lua_createtable(L, 0, 5);
+ dump_intfield(L, glyph, h->glyph);
+ dump_intfield(L, extender, h->extender);
+ dump_intfield(L, start, h->start_overlap);
+ dump_intfield(L, end, h->end_overlap);
+ dump_intfield(L, advance, h->advance);
+ lua_rawseti(L, -2, i);
+ i++;
+ h = h->next;
+ }
+ lua_rawset(L, -3);
+ }
+ h = get_charinfo_vert_variants(co);
+ if (h != NULL) {
+ int i = 1;
+ lua_push_string_by_name(L,vert_variants);
+ lua_newtable(L);
+ while (h != NULL) {
+ lua_createtable(L, 0, 5);
+ dump_intfield(L, glyph, h->glyph);
+ dump_intfield(L, extender, h->extender);
+ dump_intfield(L, start, h->start_overlap);
+ dump_intfield(L, end, h->end_overlap);
+ dump_intfield(L, advance, h->advance);
+ lua_rawseti(L, -2, i);
+ i++;
+ h = h->next;
+ }
+ lua_rawset(L, -3);
+ }
+ }
+ ki = get_charinfo_kerns(co);
+ if (ki != NULL) {
+ int i;
+ lua_push_string_by_name(L,kerns);
+ lua_createtable(L, 10, 1);
+ for (i = 0; !kern_end(ki[i]); i++) {
+ if (kern_disabled(ki[i])) {
+ /*tex Skip like in lookup. */
+ } else {
+ lua_rawgeti(L, -1, kern_char(ki[i]));
+ if (lua_type(L,-1) == LUA_TNIL) {
+ lua_pop(L,1);
+ if (kern_char(ki[i]) == right_boundarychar) {
+ lua_push_string_by_name(L,right_boundary);
+ } else {
+ lua_pushinteger(L, kern_char(ki[i]));
+ }
+ lua_pushinteger(L, kern_kern(ki[i]));
+ lua_rawset(L, -3);
+ } else {
+ /*tex The first one wins. */
+ lua_pop(L,1);
+ }
+ }
+ }
+ lua_rawset(L, -3);
+ }
+ l = get_charinfo_ligatures(co);
+ if (l != NULL) {
+ int i;
+ lua_push_string_by_name(L,ligatures);
+ lua_createtable(L, 10, 1);
+ for (i = 0; !lig_end(l[i]); i++) {
+ if (lig_char(l[i]) == right_boundarychar) {
+ lua_push_string_by_name(L,right_boundary);
+ } else {
+ lua_pushinteger(L, lig_char(l[i]));
+ }
+ lua_createtable(L, 0, 2);
+ lua_push_string_by_name(L,type);
+ lua_pushinteger(L, lig_type(l[i]));
+ lua_rawset(L, -3);
+ lua_push_string_by_name(L,char);
+ lua_pushinteger(L, lig_replacement(l[i]));
+ lua_rawset(L, -3);
+ lua_rawset(L, -3);
+ }
+ lua_rawset(L, -3);
+ }
+ lua_push_string_by_name(L,mathkern);
+ lua_newtable(L);
+ {
+ int i, j;
+ i = get_charinfo_math_kerns(co, top_right_kern);
+ j = 0;
+ if (i > 0) {
+ j++;
+ lua_push_string_by_name(L,top_right);
+ lua_newtable(L);
+ dump_math_kerns(L, co, i, top_right_kern);
+ lua_rawset(L, -3);
+ }
+ i = get_charinfo_math_kerns(co, top_left_kern);
+ if (i > 0) {
+ j++;
+ lua_push_string_by_name(L,top_left);
+ lua_newtable(L);
+ dump_math_kerns(L, co, i, top_left_kern);
+ lua_rawset(L, -3);
+ }
+ i = get_charinfo_math_kerns(co, bottom_right_kern);
+ if (i > 0) {
+ j++;
+ lua_push_string_by_name(L,bottom_right);
+ lua_newtable(L);
+ dump_math_kerns(L, co, i, bottom_right_kern);
+ lua_rawset(L, -3);
+ }
+ i = get_charinfo_math_kerns(co, bottom_left_kern);
+ if (i > 0) {
+ j++;
+ lua_push_string_by_name(L,bottom_left);
+ lua_newtable(L);
+ dump_math_kerns(L, co, i, bottom_left_kern);
+ lua_rawset(L, -3);
+ }
+ if (j > 0)
+ lua_rawset(L, -3);
+ else
+ lua_pop(L, 2);
+ }
+}
+
+static void write_lua_parameters(lua_State * L, int f)
+{
+ int k;
+ lua_push_string_by_name(L,parameters);
+ lua_newtable(L);
+ for (k = 1; k <= font_params(f); k++) {
+ switch (k) {
+ case slant_code:
+ dump_intfield(L,slant,font_param(f, k));
+ break;
+ case space_code:
+ dump_intfield(L,space,font_param(f, k));
+ break;
+ case space_stretch_code:
+ dump_intfield(L,space_stretch,font_param(f, k));
+ break;
+ case space_shrink_code:
+ dump_intfield(L,space_shrink,font_param(f, k));
+ break;
+ case x_height_code:
+ dump_intfield(L,x_height,font_param(f, k));
+ break;
+ case quad_code:
+ dump_intfield(L,quad,font_param(f, k));
+ break;
+ case extra_space_code:
+ dump_intfield(L,extra_space,font_param(f, k));
+ break;
+ default:
+ lua_pushinteger(L, font_param(f, k));
+ lua_rawseti(L, -2, k);
+ }
+ }
+ lua_rawset(L, -3);
+}
+
+static void write_lua_math_parameters(lua_State * L, int f)
+{
+ int k;
+ lua_push_string_by_name(L,MathConstants);
+ lua_newtable(L);
+ for (k = 1; k <= font_math_params(f); k++) {
+ lua_pushinteger(L, font_math_param(f, k));
+ if (k <= MATH_param_max) {
+ lua_setfield(L, -2, MATH_param_names[k]);
+ } else {
+ lua_rawseti(L, -2, k);
+ }
+ }
+ lua_rawset(L, -3);
+}
+
+int font_to_lua(lua_State * L, int f)
+{
+ int k;
+ charinfo *co;
+ if (font_cache_id(f) > 0) {
+ /*tex Fetch the table from the registry if it was saved there by |font_from_lua|. */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
+ /*tex Font dimenensions can be changed from \TEX\ code. */
+ write_lua_parameters(L, f);
+ return 1;
+ }
+ lua_newtable(L);
+ lua_push_string_by_name(L,name);
+ lua_pushstring(L, font_name(f));
+ lua_rawset(L, -3);
+ if (font_area(f) != NULL) {
+ dump_stringfield(L,area,font_area(f));
+ }
+ if (font_filename(f) != NULL) {
+ dump_stringfield(L,filename,font_filename(f));
+ }
+ if (font_fullname(f) != NULL) {
+ dump_stringfield(L,fullname,font_fullname(f));
+ }
+ if (font_psname(f) != NULL) {
+ dump_stringfield(L,psname,font_psname(f));
+ }
+ if (font_encodingname(f) != NULL) {
+ dump_stringfield(L,encodingname,font_encodingname(f));
+ }
+ dump_booleanfield(L,used,(font_used(f) ? true : false));
+ dump_stringfield(L,type,font_type_strings[font_type(f)]);
+ dump_stringfield(L,format,font_format_strings[font_format(f)]);
+ dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
+ dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
+ dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
+ dump_intfield(L,streamprovider,font_streamprovider(f));
+ dump_intfield(L,units_per_em,font_units_per_em(f));
+ dump_intfield(L,size,font_size(f));
+ dump_intfield(L,designsize,font_dsize(f));
+ dump_intfield(L,checksum,font_checksum(f));
+ dump_intfield(L,slant,font_slant(f));
+ dump_intfield(L,extend,font_extend(f));
+ dump_intfield(L,squeeze,font_squeeze(f));
+ dump_intfield(L,mode,font_mode(f));
+ dump_intfield(L,width,font_width(f));
+ dump_intfield(L,direction,font_natural_dir(f));
+ dump_intfield(L,encodingbytes,font_encodingbytes(f));
+ dump_booleanfield(L,oldmath,font_oldmath(f));
+ dump_intfield(L,tounicode,font_tounicode(f));
+ /*tex The next one is read only: */
+ if (font_max_shrink(f) != 0) {
+ dump_intfield(L,shrink,font_max_shrink(f));
+ }
+ if (font_max_stretch(f) != 0) {
+ dump_intfield(L,stretch,font_max_stretch(f));
+ }
+ if (font_step(f) != 0) {
+ dump_intfield(L,step,font_step(f));
+ }
+ if (pdf_font_attr(f) != 0) {
+ char *s = makecstring(pdf_font_attr(f));
+ dump_stringfield(L,attributes,s);
+ free(s);
+ }
+ /*tex Parameters: */
+ write_lua_parameters(L, f);
+ write_lua_math_parameters(L, f);
+ /*tex Characters: */
+ lua_push_string_by_name(L,characters);
+ lua_createtable(L, font_tables[f]->charinfo_size, 0);
+ if (has_left_boundary(f)) {
+ co = get_charinfo(f, left_boundarychar);
+ lua_push_string_by_name(L,left_boundary);
+ font_char_to_lua(L, f, co);
+ lua_rawset(L, -3);
+ }
+ if (has_right_boundary(f)) {
+ co = get_charinfo(f, right_boundarychar);
+ lua_push_string_by_name(L,right_boundary);
+ font_char_to_lua(L, f, co);
+ lua_rawset(L, -3);
+ }
+ for (k = font_bc(f); k <= font_ec(f); k++) {
+ if (quick_char_exists(f, k)) {
+ lua_pushinteger(L, k);
+ co = get_charinfo(f, k);
+ font_char_to_lua(L, f, co);
+ lua_rawset(L, -3);
+ }
+ }
+ lua_rawset(L, -3);
+ if (font_cache_id(f) == 0) {
+ /*tex Renew the cache. */
+ int r;
+ lua_pushvalue(L, -1);
+ r = luaL_ref(L, LUA_REGISTRYINDEX);
+ set_font_cache_id(f, r);
+ }
+ return 1;
+}
+
+#define count_hash_items(L,name,n) \
+ n = 0; \
+ lua_key_rawgeti(name); \
+ if (lua_type(L, -1) == LUA_TTABLE) { \
+ lua_pushnil(L); \
+ while (lua_next(L, -2) != 0) { \
+ n++; \
+ lua_pop(L, 1); \
+ } \
+ } \
+ if (n) { \
+ /*tex Keep the table on stack. */ \
+ } else{ \
+ lua_pop(L, 1); \
+ }
+
+#define streq(a,b) (strcmp(a,b)==0)
+
+#define append_packet(k) { *(cp++) = (eight_bits) (k); }
+
+#define do_store_four(l) { \
+ append_packet((l & 0xFF000000) >> 24); \
+ append_packet((l & 0x00FF0000) >> 16); \
+ append_packet((l & 0x0000FF00) >> 8); \
+ append_packet((l & 0x000000FF)); \
+}
+
+static void append_float(eight_bits ** cpp, float a)
+{
+ unsigned int i;
+ eight_bits *cp = *cpp;
+ union U {
+ float a;
+ eight_bits b[sizeof(float)];
+ } u;
+ u.a = a;
+ for (i = 0; i < sizeof(float); i++)
+ append_packet(u.b[i]);
+ *cpp = cp;
+}
+
+static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
+{
+ int k, t;
+ const char *s;
+ int i = dflt;
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+ lua_rawget(L, -2);
+ t = lua_type(L,-1);
+ if (t == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -1);
+ } else if (t == LUA_TSTRING) {
+ s = lua_tostring(L, -1);
+ k = 0;
+ while (values[k] != NULL) {
+ if (strcmp(values[k], s) == 0) {
+ i = k;
+ break;
+ }
+ k++;
+ }
+ }
+ lua_pop(L, 1);
+ return i;
+}
+
+static int n_boolean_field(lua_State * L, int name_index, int dflt)
+{
+ int i = dflt;
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+ lua_rawget(L, -2);
+ if (lua_isboolean(L, -1)) {
+ i = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+ return i;
+}
+
+static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
+{
+ char *i;
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+ lua_rawget(L, -2);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ i = xstrdup(lua_tostring(L, -1));
+ } else if (dflt == NULL) {
+ i = NULL;
+ } else {
+ i = xstrdup(dflt);
+ }
+ lua_pop(L, 1);
+ return i;
+}
+
+static const char *n_string_field(lua_State * L, int name_index)
+{
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+ lua_rawget(L, -2);
+ return lua_tostring(L,-1);
+}
+
+static int n_some_field(lua_State * L, int name_index)
+{
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+ lua_rawget(L, -2);
+ return lua_type(L,-1);
+}
+
+static int count_char_packet_bytes(lua_State * L)
+{
+ register int i;
+ register int ts;
+ register int l = 0;
+ int ff = 0;
+ for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+ lua_rawgeti(L, -1, i);
+ if (lua_istable(L, -1)) {
+ lua_rawgeti(L, -1, 1);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ const char *s = lua_tostring(L, -1);
+ if (lua_key_eq(s, font)) {
+ l += 5;
+ ff = 1;
+ } else if (lua_key_eq(s, char)) {
+ if (ff == 0) {
+ l += 5;
+ }
+ l += 5;
+ ff = 1;
+ } else if (lua_key_eq(s, slot)) {
+ l += 10;
+ } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+ ;
+ } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
+ l++;
+ } else if (lua_key_eq(s, rule)) {
+ l += 9;
+ } else if (lua_key_eq(s, right) || lua_key_eq(s, node) || lua_key_eq(s, down) || lua_key_eq(s, image) || lua_key_eq(s, lua)) {
+ l += 5;
+ } else if (lua_key_eq(s, scale)) {
+ l += sizeof(float) + 1;
+ } else if (lua_key_eq(s, pdf)) {
+ size_t len;
+ l += 5;
+ ts = lua_rawlen(L, -2);
+ lua_rawgeti(L, -2, 2);
+ if (ts == 3) {
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ /*tex There is no need to do something. */
+ } else if (lua_type(L,-1) == LUA_TNUMBER) {
+ /*tex There is no need to do something. */
+ } else {
+ normal_error("vf command","invalid packet pdf literal category");
+ }
+ lua_rawgeti(L, -3, 3);
+ }
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ (void) lua_tolstring(L, -1, &len);
+ if (len > 0) {
+ l = (int) (l + 5 + (int) len);
+ }
+ } else {
+ normal_error("vf command","invalid packet pdf literal");
+ }
+ lua_pop(L, ts == 3 ? 2 : 1);
+ } else if (lua_key_eq(s, special)) {
+ size_t len;
+ lua_rawgeti(L, -2, 2);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ (void) lua_tolstring(L, -1, &len);
+ if (len > 0) {
+ l = (int) (l + 5 + (int) len);
+ }
+ } else {
+ normal_error("vf command","invalid packet special");
+ }
+ lua_pop(L, 1);
+ } else {
+ normal_error("vf command","unknown packet command");
+ }
+ } else {
+ normal_error("vf command","no packet command");
+ }
+ /*tex Pop the command name: */
+ lua_pop(L, 1);
+ }
+ /*tex Pop this item: */
+ lua_pop(L, 1);
+ }
+ return l;
+}
+
+static scaled sp_to_dvi(halfword sp, halfword atsize)
+{
+ double result, mult;
+ mult = (double) (atsize / 65536.0);
+ result = (double) (sp * 16.0);
+ return floor(result / mult);
+}
+
+static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
+{
+ int i, n, m;
+ size_t l;
+ int cmd;
+ const char *s;
+ eight_bits *cpackets, *cp;
+ int ff = 0;
+ int sf = 0;
+ int ts = 0;
+ int max_f = 0;
+ int pc = count_char_packet_bytes(L);
+ if (pc <= 0)
+ return;
+ while (l_fonts[(max_f + 1)] != 0)
+ max_f++;
+ cp = cpackets = xmalloc((unsigned) (pc + 1));
+ for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+ lua_rawgeti(L, -1, i);
+ if (lua_istable(L, -1)) {
+ /*tex fetch the command code */
+ lua_rawgeti(L, -1, 1);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ s = lua_tostring(L, -1);
+ cmd = 0;
+ if (lua_key_eq(s, font)) {
+ cmd = packet_font_code;
+ } else if (lua_key_eq(s, char)) {
+ cmd = packet_char_code;
+ if (ff == 0) {
+ append_packet(packet_font_code);
+ ff = l_fonts[1];
+ do_store_four(ff);
+ }
+ } else if (lua_key_eq(s, slot)) {
+ /*tex we could be sparse but no real reason */
+ cmd = packet_nop_code;
+ lua_rawgeti(L, -2, 2);
+ n = (int) lua_roundnumber(L, -1);
+ if (n == 0) {
+ sf = f;
+ } else {
+ sf = (n > max_f ? l_fonts[1] : l_fonts[n]);
+ }
+ lua_rawgeti(L, -3, 3);
+ n = (int) lua_roundnumber(L, -1);
+ lua_pop(L, 2);
+ append_packet(packet_font_code);
+ do_store_four(sf);
+ append_packet(packet_char_code);
+ do_store_four(n);
+ } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+ cmd = packet_nop_code;
+ } else if (lua_key_eq(s, node)) {
+ cmd = packet_node_code;
+ } else if (lua_key_eq(s, push)) {
+ cmd = packet_push_code;
+ } else if (lua_key_eq(s, pop)) {
+ cmd = packet_pop_code;
+ } else if (lua_key_eq(s, rule)) {
+ cmd = packet_rule_code;
+ } else if (lua_key_eq(s, right)) {
+ cmd = packet_right_code;
+ } else if (lua_key_eq(s, down)) {
+ cmd = packet_down_code;
+ } else if (lua_key_eq(s, pdf)) {
+ cmd = packet_pdf_code;
+ } else if (lua_key_eq(s, special)) {
+ cmd = packet_special_code;
+ } else if (lua_key_eq(s, image)) {
+ cmd = packet_image_code;
+ } else if (lua_key_eq(s, scale)) {
+ cmd = packet_scale_code;
+ } else if (lua_key_eq(s, lua)) {
+ cmd = packet_lua_code;
+ }
+ switch (cmd) {
+ case packet_push_code:
+ case packet_pop_code:
+ append_packet(cmd);
+ break;
+ case packet_font_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = (int) lua_roundnumber(L, -1);
+ if (n == 0) {
+ ff = n;
+ } else {
+ ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
+ }
+ do_store_four(ff);
+ lua_pop(L, 1);
+ break;
+ case packet_node_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = copy_node_list(nodelist_from_lua(L,-1));
+ do_store_four(n);
+ lua_pop(L, 1);
+ break;
+ case packet_char_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = (int) lua_roundnumber(L, -1);
+ do_store_four(n);
+ lua_pop(L, 1);
+ break;
+ case packet_right_code:
+ case packet_down_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = (int) lua_roundnumber(L, -1);
+ do_store_four(sp_to_dvi(n, atsize));
+ lua_pop(L, 1);
+ break;
+ case packet_rule_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = (int) lua_roundnumber(L, -1);
+ do_store_four(sp_to_dvi(n, atsize));
+ lua_rawgeti(L, -3, 3);
+ n = (int) lua_roundnumber(L, -1);
+ do_store_four(sp_to_dvi(n, atsize));
+ lua_pop(L, 2);
+ break;
+ case packet_pdf_code:
+ ts = (int) lua_rawlen(L, -2);
+ lua_rawgeti(L, -2, 2);
+ if (ts == 3) {
+ /*tex mode on stack */
+ s = lua_tostring(L, -1);
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ /*tex |<pdf> <mode> <direct|page|text|raw|origin>| */
+ if (lua_key_eq(s, mode)) {
+ cmd = packet_pdf_mode;
+ lua_rawgeti(L, -3, 3);
+ /*tex mode on stack */
+ s = lua_tostring(L, -1);
+ }
+ } else {
+ /*tex |<pdf> <direct|page|text|raw|origin> <string>| */
+ }
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ if (lua_key_eq(s, direct)) {
+ n = direct_always;
+ } else if (lua_key_eq(s, page)) {
+ n = direct_page;
+ } else if (lua_key_eq(s, text)) {
+ n = direct_text;
+ } else if (lua_key_eq(s, font)) {
+ n = direct_font;
+ } else if (lua_key_eq(s, raw)) {
+ n = direct_raw;
+ } else if (lua_key_eq(s, origin)) {
+ n = set_origin;
+ } else {
+ n = set_origin ;
+ }
+ } else {
+ n = (int) lua_roundnumber(L, -1);
+ if (n < set_origin || n >= scan_special) {
+ n = set_origin ;
+ }
+ }
+ if (cmd == packet_pdf_code) {
+ /*tex string on stack */
+ lua_rawgeti(L, -3, 3);
+ }
+ } else {
+ n = set_origin;
+ }
+ append_packet(cmd);
+ do_store_four(n);
+ if (cmd == packet_pdf_code) {
+ s = luaL_checklstring(L, -1, &l);
+ do_store_four(l);
+ if (l > 0) {
+ m = (int) l;
+ while (m > 0) {
+ n = *s++;
+ m--;
+ append_packet(n);
+ }
+ }
+ }
+ lua_pop(L,ts == 3 ? 2 : 1);
+ break;
+ case packet_special_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ s = luaL_checklstring(L, -1, &l);
+ if (l > 0) {
+ do_store_four(l);
+ m = (int) l;
+ while (m > 0) {
+ n = *s++;
+ m--;
+ append_packet(n);
+ }
+ }
+ lua_pop(L, 1);
+ break;
+ case packet_lua_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ n = luaL_ref(L, LUA_REGISTRYINDEX);
+ do_store_four(n);
+ break;
+ case packet_image_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ if (lua_istable(L, -1)) {
+ lua_getglobal(L, "img");
+ lua_pushstring(L, "new");
+ lua_gettable(L, -2);
+ lua_insert(L, -3);
+ lua_pop(L, 1);
+ lua_call(L, 1, 1);
+ }
+ luaL_checkudata(L, -1, TYPE_IMG);
+ n = luaL_ref(L, LUA_REGISTRYINDEX);
+ do_store_four(n);
+ break;
+ case packet_nop_code:
+ break;
+ case packet_scale_code:
+ append_packet(cmd);
+ lua_rawgeti(L, -2, 2);
+ append_float(&cp, (float) luaL_checknumber(L, -1));
+ lua_pop(L, 1);
+ break;
+ default:
+ normal_error("vf command","invalid packet code");
+ }
+ }
+ /*tex Command code: */
+ lua_pop(L, 1);
+ } else {
+ normal_error("vf command","commands has to be a table");
+ }
+ /*tex Command table: */
+ lua_pop(L, 1);
+ }
+ append_packet(packet_end_code);
+ set_charinfo_packets(co, cpackets);
+ return;
+}
+
+static void read_lua_cidinfo(lua_State * L, int f)
+{
+ int i;
+ char *s;
+ lua_key_rawgeti(cidinfo);
+ if (lua_istable(L, -1)) {
+ i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
+ set_font_cidversion(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
+ set_font_cidsupplement(f, i);
+ s = n_string_field_copy(L, lua_key_index(registry), "Adobe");
+ set_font_cidregistry(f, s);
+ s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
+ set_font_cidordering(f, s);
+ }
+ lua_pop(L, 1);
+}
+
+static void read_lua_parameters(lua_State * L, int f)
+{
+ int i, n, t;
+ const char *s;
+ lua_key_rawgeti(parameters);
+ if (lua_istable(L, -1)) {
+ /*tex The number of parameters is the |max(IntegerKeys(L)),7)| */
+ n = 7;
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ if (lua_type(L, -2) == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -2);
+ if (i > n)
+ n = i;
+ }
+ lua_pop(L, 1);
+ }
+ if (n > 7)
+ set_font_params(f, n);
+ /*tex Sometimes it is handy to have all integer keys: */
+ for (i = 1; i <= 7; i++) {
+ lua_rawgeti(L, -1, i);
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ n = lua_roundnumber(L, -1);
+ set_font_param(f, i, n);
+ }
+ lua_pop(L, 1);
+ }
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ t = lua_type(L,-2);
+ if (t == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -2);
+ if (i >= 8) {
+ if (lua_type(L,-1) == LUA_TNUMBER) {
+ n = lua_roundnumber(L, -1);
+ } else {
+ n = 0;
+ }
+ set_font_param(f, i, n);
+ }
+ } else if (t == LUA_TSTRING) {
+ s = lua_tostring(L, -2);
+ if (lua_type(L,-1) == LUA_TNUMBER) {
+ n = lua_roundnumber(L, -1);
+ } else {
+ n = 0;
+ }
+ if (lua_key_eq(s, slant)) {
+ set_font_param(f, slant_code, n);
+ } else if (lua_key_eq(s, space)) {
+ set_font_param(f, space_code, n);
+ } else if (lua_key_eq(s, space_stretch)) {
+ set_font_param(f, space_stretch_code, n);
+ } else if (lua_key_eq(s, space_shrink)) {
+ set_font_param(f, space_shrink_code, n);
+ } else if (lua_key_eq(s, x_height)) {
+ set_font_param(f, x_height_code, n);
+ } else if (lua_key_eq(s, quad)) {
+ set_font_param(f, quad_code, n);
+ } else if (lua_key_eq(s, extra_space)) {
+ set_font_param(f, extra_space_code, n);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+}
+
+static void read_lua_math_parameters(lua_State * L, int f)
+{
+ int i = 0, n = 0, t;
+ lua_key_rawgeti(MathConstants);
+ if (lua_istable(L, -1)) {
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ t = lua_type(L,-2);
+ if (t == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -2);
+ } else if (t == LUA_TSTRING) {
+ i = ff_checkoption(L, -2, NULL, MATH_param_names);
+ }
+ n = (int) lua_roundnumber(L, -1);
+ if (i > 0) {
+ set_font_math_param(f, i, n);
+ }
+ lua_pop(L, 1);
+ }
+ set_font_oldmath(f,false);
+ } else {
+ set_font_oldmath(f,true);
+ }
+ lua_pop(L, 1);
+}
+
+#define MIN_INF -0x7FFFFFFF
+
+static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
+{
+ int l, k;
+ scaled ht, krn;
+ lua_key_direct_rawgeti(index);
+ if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
+ for (l = 0; l < k; l++) {
+ lua_rawgeti(L, -1, (l + 1));
+ if (lua_istable(L, -1)) {
+ ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
+ krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
+ if (krn > MIN_INF && ht > MIN_INF)
+ add_charinfo_math_kern(co, id, ht, krn);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+}
+
+static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
+{
+ int k, r, t, lt, u, n;
+ charinfo *co;
+ kerninfo *ckerns;
+ liginfo *cligs;
+ scaled j;
+ const char *s;
+ /*tex The number of ligature table items: */
+ int nl = 0;
+ /*tex The number of kern table items: */
+ int nk = 0;
+ int ctr = 0;
+ int atsize = font_size(f);
+ if (lua_istable(L, -1)) {
+ co = get_charinfo(f, i);
+ set_charinfo_tag(co, 0);
+ j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
+ set_charinfo_width(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
+ set_charinfo_height(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
+ set_charinfo_depth(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
+ set_charinfo_italic(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
+ set_charinfo_vert_italic(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
+ set_charinfo_index(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
+ set_charinfo_ef(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
+ set_charinfo_lp(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
+ set_charinfo_rp(co, j);
+ k = n_boolean_field(L, lua_key_index(used), 0);
+ set_charinfo_used(co, k);
+ s = n_string_field(L, lua_key_index(name));
+ if (s != NULL)
+ set_charinfo_name(co, xstrdup(s));
+ else
+ set_charinfo_name(co, NULL);
+ /*tex |n_string_field| leaves a value on stack*/
+ lua_pop(L,1);
+ u = n_some_field(L,lua_key_index(tounicode));
+ if (u == LUA_TNUMBER) {
+ u = lua_tointeger(L,-1);
+ if (u < 0) {
+ set_charinfo_tounicode(co, NULL);
+ } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+ char *s = malloc(5);
+ sprintf(s,"%04X",(unsigned int) u);
+ set_charinfo_tounicode(co,s);
+ } else {
+ char *s = malloc(11);
+ u = u - 0x10000;
+ sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+ set_charinfo_tounicode(co,s);
+ }
+ } else if (u == LUA_TTABLE) {
+ n = lua_rawlen(L,-1);
+ u = 0;
+ for (k = 1; k <= n; k++) {
+ lua_rawgeti(L, -1, k);
+ if (lua_type(L,-1) == LUA_TNUMBER) {
+ u = lua_tointeger(L,-1);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ if (u < 0) {
+ u = -1;
+ lua_pop(L, 1);
+ break;
+ } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+ u = u + 4;
+ } else {
+ u = u + 8;
+ }
+ lua_pop(L, 1);
+ }
+ if (u>0) {
+ char *s = malloc(u+1);
+ char *t = s ;
+ for (k = 1; k <= n; k++) {
+ lua_rawgeti(L, -1, k);
+ u = lua_tointeger(L,-1);
+ if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+ sprintf(t,"%04X",(unsigned int) u);
+ t += 4;
+ } else {
+ u = u - 0x10000;
+ sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+ t += 8;
+ }
+ lua_pop(L, 1);
+ }
+ set_charinfo_tounicode(co,s);
+ } else {
+ set_charinfo_tounicode(co, NULL);
+ }
+ } else if (u == LUA_TSTRING) {
+ s = lua_tostring(L,-1);
+ set_charinfo_tounicode(co, xstrdup(s));
+ } else {
+ set_charinfo_tounicode(co, NULL);
+ }
+ lua_pop(L,1);
+ if (has_math) {
+ j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
+ set_charinfo_top_accent(co, j);
+ j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
+ set_charinfo_bot_accent(co, j);
+ k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
+ if (k >= 0) {
+ set_charinfo_tag(co, list_tag);
+ set_charinfo_remainder(co, k);
+ }
+ lua_key_rawgeti(extensible);
+ if (lua_istable(L, -1)) {
+ int top, bot, mid, rep;
+ top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
+ bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
+ mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
+ rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
+ if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
+ set_charinfo_tag(co, ext_tag);
+ set_charinfo_extensible(co, top, bot, mid, rep);
+ } else {
+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", font_name(f), (int) i);
+ }
+ }
+ lua_pop(L, 1);
+ lua_key_rawgeti(horiz_variants);
+ if (lua_istable(L, -1)) {
+ int glyph, startconnect, endconnect, advance, extender;
+ extinfo *h;
+ set_charinfo_tag(co, ext_tag);
+ set_charinfo_hor_variants(co, NULL);
+ for (k = 1;; k++) {
+ lua_rawgeti(L, -1, k);
+ if (lua_istable(L, -1)) {
+ glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+ extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+ startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+ endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+ advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+ h = new_variant(glyph, startconnect, endconnect, advance, extender);
+ add_charinfo_hor_variant(co, h);
+ lua_pop(L, 1);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ }
+ lua_pop(L, 1);
+ lua_key_rawgeti(vert_variants);
+ if (lua_istable(L, -1)) {
+ int glyph, startconnect, endconnect, advance, extender;
+ extinfo *h;
+ set_charinfo_tag(co, ext_tag);
+ set_charinfo_vert_variants(co, NULL);
+ for (k = 1;; k++) {
+ lua_rawgeti(L, -1, k);
+ if (lua_istable(L, -1)) {
+ glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+ extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+ startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+ endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+ advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+ h = new_variant(glyph, startconnect, endconnect, advance, extender);
+ add_charinfo_vert_variant(co, h);
+ lua_pop(L, 1);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ }
+ lua_pop(L, 1);
+ /*tex
+ Here is a complete example:
+
+ \starttyping
+ mathkern = {
+ bottom_left = { { height = 420, kern = 80 }, { height = 520, kern = 4 } },
+ bottom_right = { { height = 0, kern = 48 } },
+ top_left = { { height = 620, kern = 0 }, { height = 720, kern = -80 } },
+ top_right = { { height = 676, kern = 115 }, { height = 776, kern = 45 } },
+ }
+ \stoptyping
+
+ */
+ lua_key_rawgeti(mathkern);
+ if (lua_istable(L, -1)) {
+ store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
+ store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
+ store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
+ store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
+ }
+ lua_pop(L, 1);
+ }
+ /*tex end of |has_math| */
+ count_hash_items(L, kerns, nk);
+ if (nk > 0) {
+ /*tex The kerns table is still on stack. */
+ ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
+ ctr = 0;
+ /*tex Traverse the hash. */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ k = non_boundarychar;
+ lt = lua_type(L,-2);
+ if (lt == LUA_TNUMBER) {
+ /*tex Adjacent char: */
+ k = (int) lua_tointeger(L, -2);
+ if (k < 0)
+ k = non_boundarychar;
+ } else if (lt == LUA_TSTRING) {
+ s = lua_tostring(L, -2);
+ if (lua_key_eq(s, right_boundary)) {
+ k = right_boundarychar;
+ if (!has_right_boundary(f))
+ set_right_boundary(f, get_charinfo(f, right_boundarychar));
+ }
+ }
+ j = lua_roundnumber(L, -1);
+ if (k != non_boundarychar) {
+ set_kern_item(ckerns[ctr], k, j);
+ ctr++;
+ } else {
+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field", font_name(f), (int) i);
+ }
+ lua_pop(L, 1);
+ }
+ /*tex A guard against empty tables. */
+ if (ctr > 0) {
+ set_kern_item(ckerns[ctr], end_kern, 0);
+ set_charinfo_kerns(co, ckerns);
+ } else {
+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", font_name(f), (int) i);
+ }
+ lua_pop(L, 1);
+ }
+ /*tex Packet commands. */
+ lua_key_rawgeti(commands);
+ if (lua_istable(L, -1)) {
+ lua_pushnil(L);
+ if (lua_next(L, -2) != 0) {
+ lua_pop(L, 2);
+ read_char_packets(L, (int *) l_fonts, co, f, atsize);
+ }
+ }
+ lua_pop(L, 1);
+ /*tex The ligatures. */
+ count_hash_items(L, ligatures, nl);
+ if (nl > 0) {
+ /*tex The ligatures table still on stack. */
+ cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
+ ctr = 0;
+ /*tex Traverse the hash. */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ k = non_boundarychar;
+ lt = lua_type(L,-2);
+ if (lt == LUA_TNUMBER) {
+ /*tex Adjacent char: */
+ k = (int) lua_tointeger(L, -2);
+ if (k < 0) {
+ k = non_boundarychar;
+ }
+ } else if (lt == LUA_TSTRING) {
+ s = lua_tostring(L, -2);
+ if (lua_key_eq(s, right_boundary)) {
+ k = right_boundarychar;
+ if (!has_right_boundary(f))
+ set_right_boundary(f, get_charinfo(f, right_boundarychar));
+ }
+ }
+ r = -1;
+ if (lua_istable(L, -1)) {
+ /*tex Ligature: */
+ r = lua_numeric_field_by_index(L, lua_key_index(char), -1);
+ }
+ if (r != -1 && k != non_boundarychar) {
+ t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
+ set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
+ ctr++;
+ } else {
+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field", font_name(f), (int) i);
+ }
+ /*tex The iterator value: */
+ lua_pop(L, 1);
+ }
+ /*tex A guard against empty tables. */
+ if (ctr > 0) {
+ set_ligature_item(cligs[ctr], 0, end_ligature, 0);
+ set_charinfo_ligatures(co, cligs);
+ } else {
+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field", font_name(f), (int) i);
+ }
+ /*tex The ligatures table. */
+ lua_pop(L, 1);
+ }
+ }
+}
+
+/*tex
+
+ The caller has to fix the state of the lua stack when there is an error!
+
+*/
+
+int font_from_lua(lua_State * L, int f)
+{
+ int i, n, r, t, lt;
+ int s_top;
+ int bc;
+ int ec;
+ char *s;
+ const char *ss;
+ int *l_fonts = NULL;
+ int save_ref ;
+ boolean no_math = false;
+ /*tex Will we save a cache of the \LUA\ table? */
+ save_ref = 1;
+ ss = NULL;
+ ss = n_string_field(L, lua_key_index(cache));
+ if (lua_key_eq(ss, no))
+ save_ref = -1;
+ else if (lua_key_eq(ss, renew))
+ save_ref = 0;
+ /*tex |n_string_field| leaves a value on stack. */
+ lua_pop(L,1);
+ /*tex The table is at stack |index -1| */
+ s = n_string_field_copy(L,lua_key_index(area), "");
+ set_font_area(f, s);
+ s = n_string_field_copy(L, lua_key_index(filename), NULL);
+ set_font_filename(f, s);
+ s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
+ set_font_encodingname(f, s);
+ s = n_string_field_copy(L, lua_key_index(name), NULL);
+ set_font_name(f, s);
+ s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
+ set_font_fullname(f, s);
+ if (s == NULL) {
+ formatted_error("font","lua-loaded font '%d' has no name!", f);
+ return false;
+ }
+ s = n_string_field_copy(L, lua_key_index(psname), NULL);
+ set_font_psname(f, s);
+ i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
+ set_font_units_per_em(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
+ set_font_dsize(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
+ set_font_size(f, i);
+ set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
+ i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
+ set_font_natural_dir(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
+ set_font_encodingbytes(f, (char) i);
+ i = lua_numeric_field_by_index(L,lua_key_index(streamprovider), 0);
+ set_font_streamprovider(f, (char) i);
+ i = n_boolean_field(L,lua_key_index(oldmath), 0);
+ set_font_oldmath(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
+ set_font_tounicode(f, (char) i);
+ i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
+ if (i < FONT_SLANT_MIN)
+ i = FONT_SLANT_MIN;
+ if (i > FONT_SLANT_MAX)
+ i = FONT_SLANT_MAX;
+ set_font_slant(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
+ if (i < FONT_EXTEND_MIN)
+ i = FONT_EXTEND_MIN;
+ if (i > FONT_EXTEND_MAX)
+ i = FONT_EXTEND_MAX;
+ set_font_extend(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(squeeze), 1000);
+ if (i < FONT_SQUEEZE_MIN)
+ i = FONT_SQUEEZE_MIN;
+ if (i > FONT_SQUEEZE_MAX)
+ i = FONT_SQUEEZE_MAX;
+ set_font_squeeze(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(width), 0);
+ if (i < FONT_WIDTH_MIN)
+ i = FONT_WIDTH_MIN;
+ if (i > FONT_WIDTH_MAX)
+ i = FONT_WIDTH_MAX;
+ set_font_width(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(mode), 0);
+ if (i < FONT_MODE_MIN)
+ i = FONT_MODE_MIN;
+ if (i > FONT_MODE_MAX)
+ i = FONT_MODE_MAX;
+ set_font_mode(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
+ set_hyphen_char(f, i);
+ i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
+ set_skew_char(f, i);
+ i = n_boolean_field(L, lua_key_index(used), 0);
+ set_font_used(f, (char) i);
+ s = n_string_field_copy(L, lua_key_index(attributes), NULL);
+ if (s != NULL && strlen(s) > 0) {
+ i = maketexstring(s);
+ set_pdf_font_attr(f, i);
+ }
+ free(s);
+ i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
+ set_font_type(f, i);
+ i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
+ set_font_format(f, i);
+ i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
+ set_font_writingmode(f, i);
+ i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
+ set_font_identity(f, i);
+ i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
+ set_font_embedding(f, i);
+ if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
+ set_font_encodingbytes(f, 2);
+ }
+ /*tex Now fetch the base fonts, if needed. */
+ count_hash_items(L, fonts, n);
+ if (n > 0) {
+ /*tex The font table still on stack. */
+ l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
+ memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
+ for (i = 1; i <= n; i++) {
+ lua_rawgeti(L, -1, i);
+ if (lua_istable(L, -1)) {
+ lua_key_rawgeti(id);
+ if (lua_isnumber(L, -1)) {
+ l_fonts[i] = (int) lua_tointeger(L, -1);
+ if (l_fonts[i] == 0) {
+ l_fonts[i] = (int) f;
+ }
+ /*tex Pop id and entry. */
+ lua_pop(L, 2);
+ continue;
+ }
+ /*tex Pop id. */
+ lua_pop(L, 1);
+ };
+ ss = NULL;
+ if (lua_istable(L, -1)) {
+ ss = n_string_field(L, lua_key_index(name));
+ /*tex The string is anchored. */
+ lua_pop(L,1);
+ }
+ if (ss != NULL) {
+ t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
+ /*tex The stack is messed up, otherwise this explicit resizing would not be needed! */
+ s_top = lua_gettop(L);
+ if (strcmp(font_name(f), ss) == 0)
+ l_fonts[i] = f;
+ else
+ l_fonts[i] = find_font_id(ss, t);
+ lua_settop(L, s_top);
+ } else {
+ formatted_error("font","invalid local font at index %i in lua-loaded font '%s' (1)",i,font_name(f));
+ }
+ /*tex Pop the list entry. */
+ lua_pop(L, 1);
+ }
+ /*tex Pop the font table. */
+ lua_pop(L, 1);
+ } else if (font_type(f) == virtual_font_type) {
+ /*tex
+ We no longer do this check but instead create an entry. This permits
+ (valid) tricks.
+ */
+ /*
+ formatted_error("font","invalid local fonts in lua-loaded font '%s' (2)", font_name(f));
+ */
+ } else {
+ l_fonts = xmalloc(3 * sizeof(int));
+ l_fonts[0] = 0;
+ l_fonts[1] = f;
+ l_fonts[2] = 0;
+ }
+ /*tex The parameters. */
+ no_math = n_boolean_field(L, lua_key_index(nomath), 0);
+ read_lua_parameters(L, f);
+ if (!no_math) {
+ read_lua_math_parameters(L, f);
+ if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
+ set_font_oldmath(f,true);
+ }
+
+ } else {
+ set_font_oldmath(f,true);
+ }
+ read_lua_cidinfo(L, f);
+ /*tex The characters. */
+ lua_key_rawgeti(characters);
+ if (lua_istable(L, -1)) {
+ /*tex Find the array size values; |num| holds the number of characters to add. */
+ int num = 0;
+ ec = 0;
+ bc = -1;
+ /*tex The first key: */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ if (lua_isnumber(L, -2)) {
+ i = (int) lua_tointeger(L, -2);
+ if (i >= 0) {
+ if (lua_istable(L, -1)) {
+ num++;
+ if (i > ec)
+ ec = i;
+ if (bc < 0)
+ bc = i;
+ if (bc >= 0 && i < bc)
+ bc = i;
+ }
+ }
+ }
+ lua_pop(L, 1);
+ }
+ if (bc != -1) {
+ int fstep;
+ font_malloc_charinfo(f, num);
+ set_font_bc(f, bc);
+ set_font_ec(f, ec);
+ /*tex The first key: */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ lt = lua_type(L,-2);
+ if (lt == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -2);
+ if (i >= 0) {
+ font_char_from_lua(L, f, i, l_fonts, !no_math);
+ }
+ } else if (lt == LUA_TSTRING) {
+ const char *ss1 = lua_tostring(L, -2);
+ if (lua_key_eq(ss1, left_boundary)) {
+ font_char_from_lua(L, f, left_boundarychar, l_fonts, !no_math);
+ } else if (lua_key_eq(ss1, right_boundary)) {
+ font_char_from_lua(L, f, right_boundarychar, l_fonts, !no_math);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ /*tex
+
+ Handle font expansion last: the |copy_font| routine is called eventually,
+ and that needs to know |bc| and |ec|. We permits virtual fonts to use
+ expansion as one can always turn it off.
+
+ */
+ fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
+ if (fstep < 0)
+ fstep = 0;
+ if (fstep > 100)
+ fstep = 100;
+ if (fstep != 0) {
+ int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
+ int fstretch= lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
+ if (fshrink < 0)
+ fshrink = 0;
+ if (fshrink > 500)
+ fshrink = 500;
+ fshrink -= (fshrink % fstep);
+ if (fshrink < 0)
+ fshrink = 0;
+ if (fstretch < 0)
+ fstretch = 0;
+ if (fstretch > 1000)
+ fstretch = 1000;
+ fstretch -= (fstretch % fstep);
+ if (fstretch < 0)
+ fstretch = 0;
+ set_expand_params(f, fstretch, fshrink, fstep);
+ }
+
+ } else {
+ formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
+ }
+ if (save_ref > 0) {
+ /*tex This pops the table. */
+ r = luaL_ref(L, LUA_REGISTRYINDEX);
+ set_font_cache_id(f, r);
+ } else {
+ lua_pop(L, 1);
+ set_font_cache_id(f, save_ref);
+ }
+ } else {
+ formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
+ }
+ if (l_fonts != NULL)
+ free(l_fonts);
+ return true;
+}
+
+int characters_from_lua(lua_State * L, int f)
+{
+ int i, n, t, lt;
+ int *l_fonts = NULL;
+ int s_top;
+ const char *ss;
+ boolean no_math = false;
+ /*tex Speedup: */
+ no_math = n_boolean_field(L, lua_key_index(nomath), 0);
+ /*tex Type: */
+ i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings);
+ set_font_type(f, i);
+ /*tex Fonts: */
+ count_hash_items(L, fonts, n);
+ if (n > 0) {
+ /*tex The font table still on stack. */
+ l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
+ memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
+ for (i = 1; i <= n; i++) {
+ lua_rawgeti(L, -1, i);
+ if (lua_istable(L, -1)) {
+ lua_key_rawgeti(id);
+ if (lua_isnumber(L, -1)) {
+ l_fonts[i] = (int) lua_tointeger(L, -1);
+ if (l_fonts[i] == 0) {
+ l_fonts[i] = (int) f;
+ }
+ /*tex Pop id and entry. */
+ lua_pop(L, 2);
+ continue;
+ }
+ /*tex Pop id. */
+ lua_pop(L, 1);
+ };
+ ss = NULL;
+ if (lua_istable(L, -1)) {
+ ss = n_string_field(L, lua_key_index(name));
+ /* string is anchored */
+ lua_pop(L,1);
+ }
+ if (ss != NULL) {
+ t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
+ /*tex the stack is messed up, otherwise this explicit resizing would not be needed! */
+ s_top = lua_gettop(L);
+ if (strcmp(font_name(f), ss) == 0)
+ l_fonts[i] = f;
+ else
+ l_fonts[i] = find_font_id(ss, t);
+ lua_settop(L, s_top);
+ } else {
+ formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f));
+ }
+ /*tex Pop list entry. */
+ lua_pop(L, 1);
+ }
+ /*tex Pop font table. */
+ lua_pop(L, 1);
+ } else if (font_type(f) == virtual_font_type) {
+ formatted_error("font","invalid local fonts in lua-loaded font '%s' (4)", font_name(f));
+ } else {
+ l_fonts = xmalloc(3 * sizeof(int));
+ l_fonts[0] = 0;
+ l_fonts[1] = f;
+ l_fonts[2] = 0;
+ }
+ /*tex The characters. */
+ lua_key_rawgeti(characters);
+ if (lua_istable(L, -1)) {
+ /*tex Find the array size values; |num| has the amount. */
+ int num = 0;
+ int todo = 0;
+ int bc = font_bc(f);
+ int ec = font_ec(f);
+ /*tex First key: */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ if (lua_isnumber(L, -2)) {
+ i = (int) lua_tointeger(L, -2);
+ if (i >= 0) {
+ if (lua_istable(L, -1)) {
+ todo++;
+ if (! quick_char_exists(f,i)) {
+ num++;
+ if (i > ec)
+ ec = i;
+ if (bc < 0)
+ bc = i;
+ if (bc >= 0 && i < bc)
+ bc = i;
+ }
+ }
+ }
+ }
+ lua_pop(L, 1);
+ }
+ if (todo > 0) {
+ font_malloc_charinfo(f, num);
+ set_font_bc(f, bc);
+ set_font_ec(f, ec);
+ /*tex First key: */
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ lt = lua_type(L,-2);
+ if (lt == LUA_TNUMBER) {
+ i = (int) lua_tointeger(L, -2);
+ if (i >= 0) {
+ if (quick_char_exists(f,i)) {
+ charinfo *co = char_info(f, i);
+ set_charinfo_name(co, NULL);
+ set_charinfo_tounicode(co, NULL);
+ set_charinfo_packets(co, NULL);
+ set_charinfo_ligatures(co, NULL);
+ set_charinfo_kerns(co, NULL);
+ set_charinfo_vert_variants(co, NULL);
+ set_charinfo_hor_variants(co, NULL);
+ }
+ font_char_from_lua(L, f, i, l_fonts, !no_math);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ if (l_fonts != NULL)
+ free(l_fonts);
+ return true;
+}
+
+/*tex Ligaturing starts here */
+
+static void nesting_append(halfword nest1, halfword newn)
+{
+ halfword tail = tlink(nest1);
+ if (tail == null) {
+ couple_nodes(nest1, newn);
+ } else {
+ couple_nodes(tail, newn);
+ }
+ tlink(nest1) = newn;
+}
+
+static void nesting_prepend(halfword nest1, halfword newn)
+{
+ halfword head = vlink(nest1);
+ couple_nodes(nest1, newn);
+ if (head == null) {
+ tlink(nest1) = newn;
+ } else {
+ couple_nodes(newn, head);
+ }
+}
+
+static void nesting_prepend_list(halfword nest1, halfword newn)
+{
+ halfword head = vlink(nest1);
+ couple_nodes(nest1, newn);
+ if (head == null) {
+ tlink(nest1) = tail_of_list(newn);
+ } else {
+ halfword tail = tail_of_list(newn);
+ couple_nodes(tail, head);
+ }
+}
+
+static int test_ligature(liginfo * lig, halfword left, halfword right)
+{
+ if (type(left) != glyph_node)
+ return 0;
+ if (font(left) != font(right))
+ return 0;
+ if (is_ghost(left) || is_ghost(right))
+ return 0;
+ *lig = get_ligature(font(left), character(left), character(right));
+ if (is_valid_ligature(*lig)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int try_ligature(halfword * frst, halfword fwd)
+{
+ halfword cur = *frst;
+ liginfo lig;
+ if (test_ligature(&lig, cur, fwd)) {
+ int move_after = (lig_type(lig) & 0x0C) >> 2;
+ int keep_right = ((lig_type(lig) & 0x01) != 0);
+ int keep_left = ((lig_type(lig) & 0x02) != 0);
+ halfword newgl = raw_glyph_node();
+ font(newgl) = font(cur);
+ character(newgl) = lig_replacement(lig);
+ set_is_ligature(newgl);
+ /*tex
+ Below might not be correct in contrived border case. but we use it
+ only for debugging.
+ */
+ if (character(cur) < 0) {
+ set_is_leftboundary(newgl);
+ }
+ if (character(fwd) < 0) {
+ set_is_rightboundary(newgl);
+ }
+ if (character(cur) < 0) {
+ if (character(fwd) < 0) {
+ build_attribute_list(newgl);
+ } else {
+ add_node_attr_ref(node_attr(fwd));
+ node_attr(newgl) = node_attr(fwd);
+ }
+ } else {
+ add_node_attr_ref(node_attr(cur));
+ node_attr(newgl) = node_attr(cur);
+ }
+ /*tex
+ Maybe if this ligature is consists of another ligature we should add
+ it's |lig_ptr| to the new glyphs |lig_ptr| (and cleanup the no longer
+ needed node). This has a very low priority, so low that it might
+ never happen.
+ */
+ /*tex Left side: */
+ if (keep_left) {
+ halfword new_first = copy_node(cur);
+ lig_ptr(newgl) = new_first;
+ couple_nodes(cur, newgl);
+ if (move_after) {
+ move_after--;
+ cur = newgl;
+ }
+ } else {
+ halfword prev = alink(cur);
+ uncouple_node(cur);
+ lig_ptr(newgl) = cur;
+ couple_nodes(prev, newgl);
+ cur = newgl; /* as cur has disappeared */
+ }
+ /*tex Right side: */
+ if (keep_right) {
+ halfword new_second = copy_node(fwd);
+ /*tex This is correct, because we {\em know} |lig_ptr| points to {\em one} node. */
+ couple_nodes(lig_ptr(newgl), new_second);
+ couple_nodes(newgl, fwd);
+ if (move_after) {
+ move_after--;
+ cur = fwd;
+ }
+ } else {
+ halfword next = vlink(fwd);
+ uncouple_node(fwd);
+ /*tex This works because we {\em know} |lig_ptr| points to {\em one} node. */
+ couple_nodes(lig_ptr(newgl), fwd);
+ if (next != null) {
+ couple_nodes(newgl, next);
+ }
+ }
+ /*tex Check and return. */
+ *frst = cur;
+ return 1;
+ }
+ return 0;
+}
+
+/*tex
+
+ There shouldn't be any ligatures here - we only add them at the end of
+ |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing
+ \.{DISC-1} (we continue with \.{DISC-1}'s |post_| and |no_break|.
+
+*/
+
+static halfword handle_lig_nest(halfword root, halfword cur)
+{
+ if (cur == null)
+ return root;
+ while (vlink(cur) != null) {
+ halfword fwd = vlink(cur);
+ if (type(cur) == glyph_node && type(fwd) == glyph_node &&
+ font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
+ continue;
+ }
+ cur = vlink(cur);
+ }
+ tlink(root) = cur;
+ return root;
+}
+
+static halfword handle_lig_word(halfword cur)
+{
+ halfword right = null;
+ if (type(cur) == boundary_node) {
+ halfword prev = alink(cur);
+ halfword fwd = vlink(cur);
+ /*tex There is no need to uncouple |cur|, it is freed. */
+ flush_node(cur);
+ if (fwd == null) {
+ vlink(prev) = fwd;
+ return prev;
+ }
+ couple_nodes(prev, fwd);
+ if (type(fwd) != glyph_node)
+ return prev;
+ cur = fwd;
+ } else if (has_left_boundary(font(cur))) {
+ halfword prev = alink(cur);
+ halfword p = new_glyph(font(cur), left_boundarychar);
+ couple_nodes(prev, p);
+ couple_nodes(p, cur);
+ cur = p;
+ }
+ if (has_right_boundary(font(cur))) {
+ right = new_glyph(font(cur), right_boundarychar);
+ }
+ while (1) {
+ /*tex A glyph followed by \unknown */
+ if (type(cur) == glyph_node) {
+ halfword fwd = vlink(cur);
+ if (fwd == null) {
+ /*tex The last character of a paragraph. */
+ if (right == null)
+ break;
+ /*tex |par| prohibits the use of |couple_nodes| here. */
+ try_couple_nodes(cur, right);
+ right = null;
+ continue;
+ }
+ if (type(fwd) == glyph_node) {
+ /*tex a glyph followed by a glyph */
+ if (font(cur) != font(fwd))
+ break;
+ if (try_ligature(&cur, fwd))
+ continue;
+ } else if (type(fwd) == disc_node) {
+ /*tex a glyph followed by a disc */
+ halfword pre = vlink_pre_break(fwd);
+ halfword nob = vlink_no_break(fwd);
+ halfword next, tail;
+ liginfo lig;
+ /*tex Check on: |a{b?}{?}{?}| and |a+b=>B| : |{B?}{?}{a?}| */
+ /*tex Check on: |a{?}{?}{b?}| and |a+b=>B| : |{a?}{?}{B?}| */
+ if ((pre != null && type(pre) == glyph_node && test_ligature(&lig, cur, pre))
+ || (nob != null && type(nob) == glyph_node && test_ligature(&lig, cur, nob))) {
+ /*tex Move |cur| from before disc to skipped part */
+ halfword prev = alink(cur);
+ uncouple_node(cur);
+ couple_nodes(prev, fwd);
+ nesting_prepend(no_break(fwd), cur);
+ /*tex Now ligature the |pre_break|. */
+ nesting_prepend(pre_break(fwd), copy_node(cur));
+ /*tex As we have removed cur, we need to start again. */
+ cur = prev;
+ }
+ /*tex Check on: |a{?}{?}{}b| and |a+b=>B| : |{a?}{?b}{B}|. */
+ next = vlink(fwd);
+ if (nob == null && next != null && type(next) == glyph_node && test_ligature(&lig, cur, next)) {
+ /*tex Move |cur| from before |disc| to |no_break| part. */
+ halfword prev = alink(cur);
+ uncouple_node(cur);
+ couple_nodes(prev, fwd);
+ /*tex We {\em know} it's empty. */
+ couple_nodes(no_break(fwd), cur);
+ /*tex Now copy |cur| the |pre_break|. */
+ nesting_prepend(pre_break(fwd), copy_node(cur));
+ /*tex Move next from after disc to |no_break| part. */
+ tail = vlink(next);
+ uncouple_node(next);
+ try_couple_nodes(fwd, tail);
+ /*tex We {\em know} this works. */
+ couple_nodes(cur, next);
+ /*tex Make sure the list is correct. */
+ tlink(no_break(fwd)) = next;
+ /*tex Now copy next to the |post_break|. */
+ nesting_append(post_break(fwd), copy_node(next));
+ /*tex As we have removed cur, we need to start again. */
+ cur = prev;
+ }
+ /*tex We are finished with the |pre_break|. */
+ handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
+ } else if (type(fwd) == boundary_node) {
+ halfword next = vlink(fwd);
+ try_couple_nodes(cur, next);
+ flush_node(fwd);
+ if (right != null) {
+ /*tex Shame, didn't need it. */
+ flush_node(right);
+ /*tex No need to reset |right|, we're going to leave the loop anyway. */
+ }
+ break;
+ } else {
+ /*tex Is something unknown. */
+ if (right == null)
+ break;
+ couple_nodes(cur, right);
+ couple_nodes(right, fwd);
+ right = null;
+ continue;
+ }
+ /*tex A discretionary followed by \unknown */
+ } else if (type(cur) == disc_node) {
+ /*tex If |{?}{x}{?}| or |{?}{?}{y}| then: */
+ if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
+ halfword prev = 0;
+ halfword fwd;
+ liginfo lig;
+ if (subtype(cur) == select_disc) {
+ prev = alink(cur);
+ if (vlink_post_break(cur) != null)
+ handle_lig_nest(post_break(prev), vlink_post_break(prev));
+ if (vlink_no_break(cur) != null)
+ handle_lig_nest(no_break(prev), vlink_no_break(prev));
+ }
+ if (vlink_post_break(cur) != null)
+ handle_lig_nest(post_break(cur), vlink_post_break(cur));
+ if (vlink_no_break(cur) != null)
+ handle_lig_nest(no_break(cur), vlink_no_break(cur));
+ while ((fwd = vlink(cur)) != null) {
+ halfword nob, pst, next;
+ if (type(fwd) != glyph_node)
+ break;
+ if (subtype(cur) != select_disc) {
+ nob = tlink_no_break(cur);
+ pst = tlink_post_break(cur);
+ if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+ (pst == null || !test_ligature(&lig, pst, fwd)))
+ break;
+ nesting_append(no_break(cur), copy_node(fwd));
+ handle_lig_nest(no_break(cur), nob);
+ } else {
+ int dobreak = 0;
+ nob = tlink_no_break(prev);
+ pst = tlink_post_break(prev);
+ if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+ (pst == null || !test_ligature(&lig, pst, fwd)))
+ dobreak = 1;
+ if (!dobreak) {
+ nesting_append(no_break(prev), copy_node(fwd));
+ handle_lig_nest(no_break(prev), nob);
+ nesting_append(post_break(prev), copy_node(fwd));
+ handle_lig_nest(post_break(prev), pst);
+ }
+ dobreak = 0;
+ nob = tlink_no_break(cur);
+ pst = tlink_post_break(cur);
+ if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+ (pst == null || !test_ligature(&lig, pst, fwd)))
+ dobreak = 1;
+ if (!dobreak) {
+ nesting_append(no_break(cur), copy_node(fwd));
+ handle_lig_nest(no_break(cur), nob);
+ }
+ if (dobreak)
+ break;
+ }
+ next = vlink(fwd);
+ uncouple_node(fwd);
+ try_couple_nodes(cur, next);
+ nesting_append(post_break(cur), fwd);
+ handle_lig_nest(post_break(cur), pst);
+ }
+ if (fwd != null && type(fwd) == disc_node) {
+ halfword next = vlink(fwd);
+ if (vlink_no_break(fwd) == null
+ && vlink_post_break(fwd) == null
+ && next != null
+ && type(next) == glyph_node
+ && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
+ (tlink_no_break (cur) != null && test_ligature(&lig, tlink_no_break (cur), next)))) {
+ /*tex Building an |init_disc| followed by a |select_disc|: |{a-}{b}{AB} {-}{}{} c| */
+ halfword last1 = vlink(next), tail;
+ uncouple_node(next);
+ try_couple_nodes(fwd, last1);
+ /*tex |{a-}{b}{AB} {-}{c}{}| */
+ nesting_append(post_break(fwd), copy_node(next));
+ /*tex |{a-}{b}{AB} {-}{c}{-}| */
+ if (vlink_no_break(cur) != null) {
+ nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
+ }
+ /*tex |{a-}{b}{AB} {b-}{c}{-}| */
+ if (vlink_post_break(cur) != null)
+ nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
+ /*tex |{a-}{b}{AB} {b-}{c}{AB-}| */
+ if (vlink_no_break(cur) != null) {
+ nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
+ }
+ /*tex |{a-}{b}{ABC} {b-}{c}{AB-}| */
+ tail = tlink_no_break(cur);
+ nesting_append(no_break(cur), copy_node(next));
+ handle_lig_nest(no_break(cur), tail);
+ /*tex |{a-}{BC}{ABC} {b-}{c}{AB-}| */
+ tail = tlink_post_break(cur);
+ nesting_append(post_break(cur), next);
+ handle_lig_nest(post_break(cur), tail);
+ /*tex Set the subtypes: */
+ subtype(cur) = init_disc;
+ subtype(fwd) = select_disc;
+ }
+ }
+ }
+
+ } else {
+ /*tex We have glyph nor disc. */
+ return cur;
+ }
+ /*tex Goto the next node, where |\par| allows |vlink(cur)| to be NULL. */
+ cur = vlink(cur);
+ }
+ return cur;
+}
+
+/*tex The return value is the new tail, head should be a dummy: */
+
+halfword handle_ligaturing(halfword head, halfword tail)
+{
+ /*tex A trick to allow explicit |node==null| tests. */
+ halfword save_tail1 = null;
+ halfword cur, prev;
+ if (vlink(head) == null)
+ return tail;
+ if (tail != null) {
+ save_tail1 = vlink(tail);
+ vlink(tail) = null;
+ }
+ if (fix_node_lists) {
+ fix_node_list(head);
+ }
+ prev = head;
+ cur = vlink(prev);
+ while (cur != null) {
+ if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
+ cur = handle_lig_word(cur);
+ }
+ prev = cur;
+ cur = vlink(cur);
+ }
+ if (prev == null) {
+ prev = tail;
+ }
+ if (tail != null) {
+ try_couple_nodes(prev, save_tail1);
+ }
+ return prev;
+}
+
+
+/*tex Kerning starts here: */
+
+static void add_kern_before(halfword left, halfword right)
+{
+ if ((!is_rightghost(right)) &&
+ font(left) == font(right) && has_kern(font(left), character(left))) {
+ int k = raw_get_kern(font(left), character(left), character(right));
+ if (k != 0) {
+ halfword kern = new_kern(k);
+ halfword prev = alink(right);
+ couple_nodes(prev, kern);
+ couple_nodes(kern, right);
+ /*tex Update the attribute list (inherit from left): */
+ delete_attribute_ref(node_attr(kern));
+ add_node_attr_ref(node_attr(left));
+ node_attr(kern) = node_attr(left);
+ }
+ }
+}
+
+static void add_kern_after(halfword left, halfword right, halfword aft)
+{
+ if ((!is_rightghost(right)) &&
+ font(left) == font(right) && has_kern(font(left), character(left))) {
+ int k = raw_get_kern(font(left), character(left), character(right));
+ if (k != 0) {
+ halfword kern = new_kern(k);
+ halfword next = vlink(aft);
+ couple_nodes(aft, kern);
+ try_couple_nodes(kern, next);
+ /*tex Update the attribute list (inherit from left == aft): */
+ delete_attribute_ref(node_attr(kern));
+ add_node_attr_ref(node_attr(aft));
+ node_attr(kern) = node_attr(aft);
+ }
+ }
+}
+
+static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
+{
+ halfword cur = vlink(root);
+ halfword left = null;
+ if (cur == null) {
+ if (init_left != null && init_right != null) {
+ add_kern_after(init_left, init_right, root);
+ tlink(root) = vlink(root);
+ }
+ return;
+ }
+ if (type(cur) == glyph_node) {
+ set_is_glyph(cur);
+ if (init_left != null)
+ add_kern_before(init_left, cur);
+ left = cur;
+ }
+ while ((cur = vlink(cur)) != null) {
+ if (type(cur) == glyph_node) {
+ set_is_glyph(cur);
+ if (left != null) {
+ add_kern_before(left, cur);
+ if (character(left) < 0 || is_ghost(left)) {
+ halfword prev = alink(left);
+ couple_nodes(prev, cur);
+ flush_node(left);
+ }
+ }
+ left = cur;
+ } else {
+ if (type(cur) == disc_node) {
+ halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
+ do_handle_kerning(pre_break(cur), left, null);
+ if (vlink_pre_break(cur) != null)
+ tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
+ do_handle_kerning(post_break(cur), null, right);
+ if (vlink_post_break(cur) != null)
+ tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
+ do_handle_kerning(no_break(cur), left, right);
+ if (vlink_no_break(cur) != null)
+ tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));
+ }
+ if (left != null) {
+ if (character(left) < 0 || is_ghost(left)) {
+ halfword prev = alink(left);
+ couple_nodes(prev, cur);
+ flush_node(left);
+ }
+ left = null;
+ }
+ }
+ }
+ if (left != null) {
+ if (init_right != null)
+ add_kern_after(left, init_right, left);
+ if (character(left) < 0 || is_ghost(left)) {
+ halfword prev = alink(left);
+ halfword next = vlink(left);
+ if (next != null) {
+ couple_nodes(prev, next);
+ tlink(root) = next;
+ } else if (prev != root) {
+ vlink(prev) = null;
+ tlink(root) = prev;
+ } else {
+ vlink(root) = null;
+ tlink(root) = null;
+ }
+ flush_node(left);
+ }
+ }
+}
+
+halfword handle_kerning(halfword head, halfword tail)
+{
+ halfword save_link = null;
+ if (tail == null) {
+ tlink(head) = null;
+ do_handle_kerning(head, null, null);
+ } else {
+ save_link = vlink(tail);
+ vlink(tail) = null;
+ tlink(head) = tail;
+ do_handle_kerning(head, null, null);
+ tail = tlink(head);
+ if (valid_node(save_link)) {
+ try_couple_nodes(tail, save_link);
+ }
+ }
+ return tail;
+}
+
+/*tex The ligaturing and kerning \LUA\ interface: */
+
+static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
+{
+ int i;
+ int top = lua_gettop(Luas);
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, top);
+ return tail;
+ }
+ nodelist_to_lua(Luas, head);
+ nodelist_to_lua(Luas, tail);
+ if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
+ formatted_warning("ligkern","error: %s",lua_tostring(Luas, -1));
+ lua_settop(Luas, top);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return tail;
+ }
+ if (fix_node_lists) {
+ fix_node_list(head);
+ }
+ lua_settop(Luas, top);
+ return tail;
+}
+
+halfword new_ligkern(halfword head, halfword tail)
+{
+ int callback_id = 0;
+ if (vlink(head) == null)
+ return tail;
+ callback_id = callback_defined(ligaturing_callback);
+ if (callback_id > 0) {
+ tail = run_lua_ligkern_callback(head, tail, callback_id);
+ if (tail == null)
+ tail = tail_of_list(head);
+ } else if (callback_id == 0) {
+ tail = handle_ligaturing(head, tail);
+ }
+ callback_id = callback_defined(kerning_callback);
+ if (callback_id > 0) {
+ tail = run_lua_ligkern_callback(head, tail, callback_id);
+ if (tail == null) {
+ tail = tail_of_list(head);
+ }
+ } else if (callback_id == 0) {
+ halfword nest1 = new_node(nesting_node, 1);
+ halfword cur = vlink(head);
+ halfword aft = vlink(tail);
+ couple_nodes(nest1, cur);
+ tlink(nest1) = tail;
+ vlink(tail) = null;
+ do_handle_kerning(nest1, null, null);
+ couple_nodes(head, vlink(nest1));
+ tail = tlink(nest1);
+ try_couple_nodes(tail, aft);
+ flush_node(nest1);
+ }
+ return tail;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/luafont.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/luafont.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,2426 +0,0 @@
-% luafont.w
-%
-% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-#define noVERBOSE
-
-/* todo: also keys */
-
-const char *font_type_strings[] = {
- "unknown", "virtual", "real", NULL
-};
-
-const char *font_writingmode_strings[] = {
- "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_identity_strings[] = {
- "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_format_strings[] = {
- "unknown", "type1", "type3", "truetype", "opentype", NULL
-};
-
-const char *font_embedding_strings[] = {
- "unknown", "no", "subset", "full", NULL
-};
-
-const char *ligature_type_strings[] = {
- "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
-};
-
-const char *MATH_param_names[] = {
- "nil",
- "ScriptPercentScaleDown",
- "ScriptScriptPercentScaleDown",
- "DelimitedSubFormulaMinHeight",
- "DisplayOperatorMinHeight",
- "MathLeading",
- "AxisHeight",
- "AccentBaseHeight",
- "FlattenedAccentBaseHeight",
- "SubscriptShiftDown",
- "SubscriptTopMax",
- "SubscriptBaselineDropMin",
- "SuperscriptShiftUp",
- "SuperscriptShiftUpCramped",
- "SuperscriptBottomMin",
- "SuperscriptBaselineDropMax",
- "SubSuperscriptGapMin",
- "SuperscriptBottomMaxWithSubscript",
- "SpaceAfterScript",
- "UpperLimitGapMin",
- "UpperLimitBaselineRiseMin",
- "LowerLimitGapMin",
- "LowerLimitBaselineDropMin",
- "StackTopShiftUp",
- "StackTopDisplayStyleShiftUp",
- "StackBottomShiftDown",
- "StackBottomDisplayStyleShiftDown",
- "StackGapMin",
- "StackDisplayStyleGapMin",
- "StretchStackTopShiftUp",
- "StretchStackBottomShiftDown",
- "StretchStackGapAboveMin",
- "StretchStackGapBelowMin",
- "FractionNumeratorShiftUp",
- "FractionNumeratorDisplayStyleShiftUp",
- "FractionDenominatorShiftDown",
- "FractionDenominatorDisplayStyleShiftDown",
- "FractionNumeratorGapMin",
- "FractionNumeratorDisplayStyleGapMin",
- "FractionRuleThickness",
- "FractionDenominatorGapMin",
- "FractionDenominatorDisplayStyleGapMin",
- "SkewedFractionHorizontalGap",
- "SkewedFractionVerticalGap",
- "OverbarVerticalGap",
- "OverbarRuleThickness",
- "OverbarExtraAscender",
- "UnderbarVerticalGap",
- "UnderbarRuleThickness",
- "UnderbarExtraDescender",
- "RadicalVerticalGap",
- "RadicalDisplayStyleVerticalGap",
- "RadicalRuleThickness",
- "RadicalExtraAscender",
- "RadicalKernBeforeDegree",
- "RadicalKernAfterDegree",
- "RadicalDegreeBottomRaisePercent",
- "MinConnectorOverlap",
- "SubscriptShiftDownWithSuperscript",
- "FractionDelimiterSize",
- "FractionDelimiterDisplayStyleSize",
- "NoLimitSubFactor",
- "NoLimitSupFactor",
- NULL,
-};
-
-/* here for now, may be useful elsewhere */
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
- const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
- int i;
- for (i=0; lst[i]; i++)
- if (strcmp(lst[i], name) == 0)
- return i;
- return -1;
-}
-
-#define dump_intfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushinteger(L, c); \
- lua_rawset(L, -3); \
-
-#define dump_stringfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushstring(L, c); \
- lua_rawset(L, -3);
-
-#define dump_booleanfield(L,n,c) \
- lua_push_string_by_name(L,n); \
- lua_pushboolean(L, c); \
- lua_rawset(L, -3);
-
-static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
-{
- int i;
- for (i = 0; i < l; i++) {
- lua_newtable(L);
- if (id==top_left_kern) {
- dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
- dump_intfield(L, kern, co->top_left_math_kern_array[(2*i)+1]);
- } else if (id==top_right_kern) {
- dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
- dump_intfield(L, kern, co->top_right_math_kern_array[(2*i)+1]);
- } else if (id==bottom_right_kern) {
- dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
- dump_intfield(L, kern, co->bottom_right_math_kern_array[(2*i)+1]);
- } else if (id==bottom_left_kern) {
- dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
- dump_intfield(L, kern, co->bottom_left_math_kern_array[(2*i)+1]);
- }
- lua_rawseti(L, -2, (i + 1));
- }
-}
-
-static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
-{
- liginfo *l;
- kerninfo *ki;
-
- lua_createtable(L, 0, 10);
-
- dump_intfield(L,width,get_charinfo_width(co));
- dump_intfield(L,height,get_charinfo_height(co));
- dump_intfield(L,depth,get_charinfo_depth(co));
-
- if (get_charinfo_italic(co) != 0) {
- dump_intfield(L,italic,get_charinfo_italic(co));
- }
- if (get_charinfo_vert_italic(co) != 0) {
- dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
- }
- if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
- dump_intfield(L,top_accent,get_charinfo_top_accent(co));
- }
- if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
- dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
- }
- if (get_charinfo_ef(co) != 1000) {
- dump_intfield(L,expansion_factor,get_charinfo_ef(co));
- }
- if (get_charinfo_lp(co) != 0) {
- dump_intfield(L,left_protruding,get_charinfo_lp(co));
- }
- if (get_charinfo_rp(co) != 0) {
- dump_intfield(L,right_protruding,get_charinfo_rp(co));
- }
- if (font_encodingbytes(f) == 2) {
- dump_intfield(L,index,get_charinfo_index(co));
- }
- if (get_charinfo_name(co) != NULL) {
- dump_stringfield(L,name,get_charinfo_name(co));
- }
- if (get_charinfo_tounicode(co) != NULL) {
- dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
- }
- if (get_charinfo_tag(co) == list_tag) {
- dump_intfield(L,next,get_charinfo_remainder(co));
- }
- if (get_charinfo_used(co)) {
- dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
- }
- if (get_charinfo_tag(co) == ext_tag) {
- extinfo *h;
- h = get_charinfo_hor_variants(co);
- if (h != NULL) {
- int i = 1;
- lua_push_string_by_name(L,horiz_variants);
- lua_newtable(L);
- while (h != NULL) {
- lua_createtable(L, 0, 5);
- dump_intfield(L, glyph, h->glyph);
- dump_intfield(L, extender, h->extender);
- dump_intfield(L, start, h->start_overlap);
- dump_intfield(L, end, h->end_overlap);
- dump_intfield(L, advance, h->advance);
- lua_rawseti(L, -2, i);
- i++;
- h = h->next;
- }
- lua_rawset(L, -3);
- }
- h = get_charinfo_vert_variants(co);
- if (h != NULL) {
- int i = 1;
- lua_push_string_by_name(L,vert_variants);
- lua_newtable(L);
- while (h != NULL) {
- lua_createtable(L, 0, 5);
- dump_intfield(L, glyph, h->glyph);
- dump_intfield(L, extender, h->extender);
- dump_intfield(L, start, h->start_overlap);
- dump_intfield(L, end, h->end_overlap);
- dump_intfield(L, advance, h->advance);
- lua_rawseti(L, -2, i);
- i++;
- h = h->next;
- }
- lua_rawset(L, -3);
- }
- }
- ki = get_charinfo_kerns(co);
- if (ki != NULL) {
- int i;
- lua_push_string_by_name(L,kerns);
- lua_createtable(L, 10, 1);
- for (i = 0; !kern_end(ki[i]); i++) {
- if (kern_disabled(ki[i])) {
- /* skip like in lookup */
- } else {
- lua_rawgeti(L, -1, kern_char(ki[i]));
- if (lua_type(L,-1) == LUA_TNIL) {
- lua_pop(L,1);
- if (kern_char(ki[i]) == right_boundarychar) {
- lua_push_string_by_name(L,right_boundary);
- } else {
- lua_pushinteger(L, kern_char(ki[i]));
- }
- lua_pushinteger(L, kern_kern(ki[i]));
- lua_rawset(L, -3);
- } else {
- /* first one wins */
- lua_pop(L,1);
- }
- }
- }
- lua_rawset(L, -3);
- }
- l = get_charinfo_ligatures(co);
- if (l != NULL) {
- int i;
- lua_push_string_by_name(L,ligatures);
- lua_createtable(L, 10, 1);
- for (i = 0; !lig_end(l[i]); i++) {
- if (lig_char(l[i]) == right_boundarychar) {
- lua_push_string_by_name(L,right_boundary);
- } else {
- lua_pushinteger(L, lig_char(l[i]));
- }
- lua_createtable(L, 0, 2);
- lua_push_string_by_name(L,type);
- lua_pushinteger(L, lig_type(l[i]));
- lua_rawset(L, -3);
- lua_push_string_by_name(L,char);
- lua_pushinteger(L, lig_replacement(l[i]));
- lua_rawset(L, -3);
- lua_rawset(L, -3);
- }
- lua_rawset(L, -3);
- }
-
- lua_push_string_by_name(L,mathkern);
- lua_newtable(L);
- {
- int i, j;
- i = get_charinfo_math_kerns(co, top_right_kern);
- j = 0;
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,top_right);
- lua_newtable(L);
- dump_math_kerns(L, co, i, top_right_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, top_left_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,top_left);
- lua_newtable(L);
- dump_math_kerns(L, co, i, top_left_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, bottom_right_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,bottom_right);
- lua_newtable(L);
- dump_math_kerns(L, co, i, bottom_right_kern);
- lua_rawset(L, -3);
- }
- i = get_charinfo_math_kerns(co, bottom_left_kern);
- if (i > 0) {
- j++;
- lua_push_string_by_name(L,bottom_left);
- lua_newtable(L);
- dump_math_kerns(L, co, i, bottom_left_kern);
- lua_rawset(L, -3);
- }
- if (j > 0)
- lua_rawset(L, -3);
- else
- lua_pop(L, 2);
- }
-}
-
-static void write_lua_parameters(lua_State * L, int f)
-{
- int k;
- lua_push_string_by_name(L,parameters);
- lua_newtable(L);
- for (k = 1; k <= font_params(f); k++) {
- switch (k) {
- case slant_code:
- dump_intfield(L,slant,font_param(f, k));
- break;
- case space_code:
- dump_intfield(L,space,font_param(f, k));
- break;
- case space_stretch_code:
- dump_intfield(L,space_stretch,font_param(f, k));
- break;
- case space_shrink_code:
- dump_intfield(L,space_shrink,font_param(f, k));
- break;
- case x_height_code:
- dump_intfield(L,x_height,font_param(f, k));
- break;
- case quad_code:
- dump_intfield(L,quad,font_param(f, k));
- break;
- case extra_space_code:
- dump_intfield(L,extra_space,font_param(f, k));
- break;
- default:
- lua_pushinteger(L, font_param(f, k));
- lua_rawseti(L, -2, k);
- }
- }
- lua_rawset(L, -3);
-}
-
-@ @c
-static void write_lua_math_parameters(lua_State * L, int f)
-{
- int k;
- lua_push_string_by_name(L,MathConstants);
- lua_newtable(L);
- for (k = 1; k <= font_math_params(f); k++) {
- lua_pushinteger(L, font_math_param(f, k));
- if (k <= MATH_param_max) {
- lua_setfield(L, -2, MATH_param_names[k]);
- } else {
- lua_rawseti(L, -2, k);
- }
- }
- lua_rawset(L, -3);
-}
-
-int font_to_lua(lua_State * L, int f)
-{
- int k;
- charinfo *co;
- if (font_cache_id(f) > 0) {
- /* fetch the table from the registry if it was
- saved there by |font_from_lua()| */
- lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
- /* fontdimens can be changed from tex code */
- write_lua_parameters(L, f);
- return 1;
- }
-
- lua_newtable(L);
- lua_push_string_by_name(L,name);
- lua_pushstring(L, font_name(f));
- lua_rawset(L, -3);
- if (font_area(f) != NULL) {
- dump_stringfield(L,area,font_area(f));
- }
- if (font_filename(f) != NULL) {
- dump_stringfield(L,filename,font_filename(f));
- }
- if (font_fullname(f) != NULL) {
- dump_stringfield(L,fullname,font_fullname(f));
- }
- if (font_psname(f) != NULL) {
- dump_stringfield(L,psname,font_psname(f));
- }
- if (font_encodingname(f) != NULL) {
- dump_stringfield(L,encodingname,font_encodingname(f));
- }
-
- dump_booleanfield(L,used,(font_used(f) ? true : false));
- dump_stringfield(L,type,font_type_strings[font_type(f)]);
- dump_stringfield(L,format,font_format_strings[font_format(f)]);
- dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
- dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
- dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
- dump_intfield(L,streamprovider,font_streamprovider(f));
-
- dump_intfield(L,units_per_em,font_units_per_em(f));
- dump_intfield(L,size,font_size(f));
- dump_intfield(L,designsize,font_dsize(f));
- dump_intfield(L,checksum,font_checksum(f));
- dump_intfield(L,slant,font_slant(f));
- dump_intfield(L,extend,font_extend(f));
- dump_intfield(L,direction,font_natural_dir(f));
- dump_intfield(L,encodingbytes,font_encodingbytes(f));
- dump_booleanfield(L,oldmath,font_oldmath(f));
- dump_intfield(L,tounicode,font_tounicode(f));
-
- /* the next one is read only */
- if (font_max_shrink(f) != 0) {
- dump_intfield(L,shrink,font_max_shrink(f));
- }
- if (font_max_stretch(f) != 0) {
- dump_intfield(L,stretch,font_max_stretch(f));
- }
- if (font_step(f) != 0) {
- dump_intfield(L,step,font_step(f));
- }
- if (pdf_font_attr(f) != 0) {
- char *s = makecstring(pdf_font_attr(f));
- dump_stringfield(L,attributes,s);
- free(s);
- }
-
- /* params */
- write_lua_parameters(L, f);
- write_lua_math_parameters(L, f);
-
- /* chars */
- lua_push_string_by_name(L,characters);
- lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all characters */
- if (has_left_boundary(f)) {
- co = get_charinfo(f, left_boundarychar);
- lua_push_string_by_name(L,left_boundary);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- if (has_right_boundary(f)) {
- co = get_charinfo(f, right_boundarychar);
- lua_push_string_by_name(L,right_boundary);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- for (k = font_bc(f); k <= font_ec(f); k++) {
- if (quick_char_exists(f, k)) {
- lua_pushinteger(L, k);
- co = get_charinfo(f, k);
- font_char_to_lua(L, f, co);
- lua_rawset(L, -3);
- }
- }
- lua_rawset(L, -3);
-
- if (font_cache_id(f) == 0) { /* renew */
- int r;
- lua_pushvalue(L, -1);
- r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
- set_font_cache_id(f, r);
- }
- return 1;
-}
-
-#define count_hash_items(L,name,n) \
- n = 0; \
- lua_key_rawgeti(name); \
- if (lua_type(L, -1) == LUA_TTABLE) { \
- lua_pushnil(L); \
- while (lua_next(L, -2) != 0) { \
- n++; \
- lua_pop(L, 1); \
- } \
- } \
- if (n) { \
- /* keep table on stack */ \
- } else{ \
- lua_pop(L, 1); \
- }
-
-@ @c
-#define streq(a,b) (strcmp(a,b)==0)
-
-#define append_packet(k) { *(cp++) = (eight_bits) (k); }
-
-#define do_store_four(l) { \
- append_packet((l & 0xFF000000) >> 24); \
- append_packet((l & 0x00FF0000) >> 16); \
- append_packet((l & 0x0000FF00) >> 8); \
- append_packet((l & 0x000000FF)); \
-}
-
-@ @c
-static void append_float(eight_bits ** cpp, float a)
-{
- unsigned int i;
- eight_bits *cp = *cpp;
- union U {
- float a;
- eight_bits b[sizeof(float)];
- } u;
- u.a = a;
- for (i = 0; i < sizeof(float); i++)
- append_packet(u.b[i]);
- *cpp = cp;
-}
-
-static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
-{
- int k, t;
- const char *s;
- int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- t = lua_type(L,-1);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -1);
- } else if (t == LUA_TSTRING) {
- s = lua_tostring(L, -1);
- k = 0;
- while (values[k] != NULL) {
- if (strcmp(values[k], s) == 0) {
- i = k;
- break;
- }
- k++;
- }
- }
- lua_pop(L, 1);
- return i;
-}
-
-static int n_boolean_field(lua_State * L, int name_index, int dflt)
-{
- int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- if (lua_isboolean(L, -1)) {
- i = lua_toboolean(L, -1);
- }
- lua_pop(L, 1);
- return i;
-}
-
-static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
-{
- char *i;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- if (lua_type(L,-1) == LUA_TSTRING) {
- i = xstrdup(lua_tostring(L, -1));
- } else if (dflt == NULL) {
- i = NULL;
- } else {
- i = xstrdup(dflt);
- }
- lua_pop(L, 1);
- return i;
-}
-
-static const char *n_string_field(lua_State * L, int name_index)
-{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- return lua_tostring(L,-1);
-}
-
-static int n_some_field(lua_State * L, int name_index)
-{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
- lua_rawget(L, -2);
- return lua_type(L,-1);
-}
-
-/*static void init_font_string_pointers(lua_State * L){}*/
-
-static int count_char_packet_bytes(lua_State * L)
-{
- register int i;
- register int ts;
- register int l = 0;
- int ff = 0;
- for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- lua_rawgeti(L, -1, 1);
- if (lua_type(L,-1) == LUA_TSTRING) {
- const char *s = lua_tostring(L, -1);
- if (lua_key_eq(s, font)) {
- l += 5;
- ff = 1;
- } else if (lua_key_eq(s, char)) {
- if (ff == 0) {
- l += 5;
- }
- l += 5;
- ff = 1;
- } else if (lua_key_eq(s, slot)) {
- l += 10;
- } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
- ;
- } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
- l++;
- } else if (lua_key_eq(s, rule)) {
- l += 9;
- } else if (lua_key_eq(s, right) || lua_key_eq(s, node) || lua_key_eq(s, down) || lua_key_eq(s, image)) {
- l += 5;
- } else if (lua_key_eq(s, scale)) {
- l += sizeof(float) + 1;
- } else if (lua_key_eq(s, pdf)) {
- size_t len;
- l += 5;
- ts = lua_rawlen(L, -2);
- lua_rawgeti(L, -2, 2);
- if (ts == 3) {
- if (lua_type(L,-1) == LUA_TSTRING) {
- /* no need to do something */
- } else if (lua_type(L,-1) == LUA_TNUMBER) {
- /* no need to do something */
- } else {
- normal_error("vf command","invalid packet pdf literal category");
- }
- lua_rawgeti(L, -3, 3);
- }
- if (lua_type(L,-1) == LUA_TSTRING) {
- (void) lua_tolstring(L, -1, &len);
- if (len > 0) {
- l = (int) (l + 5 + (int) len);
- }
- } else {
- normal_error("vf command","invalid packet pdf literal");
- }
- lua_pop(L, ts == 3 ? 2 : 1);
- } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
- size_t len;
- lua_rawgeti(L, -2, 2);
- if (lua_type(L,-1) == LUA_TSTRING) {
- (void) lua_tolstring(L, -1, &len);
- if (len > 0) {
- l = (int) (l + 5 + (int) len);
- }
- } else {
- normal_error("vf command","invalid packet special");
- }
- lua_pop(L, 1);
- } else {
- normal_error("vf command","unknown packet command");
- }
- } else {
- normal_error("vf command","no packet command");
- }
- lua_pop(L, 1); /* command name */
- }
- lua_pop(L, 1); /* item */
- }
- return l;
-}
-
-static scaled sp_to_dvi(halfword sp, halfword atsize)
-{
- double result, mult;
- mult = (double) (atsize / 65536.0);
- result = (double) (sp * 16.0);
- return floor(result / mult);
-}
-
-@ @c
-static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
-{
- int i, n, m;
- size_t l;
- int cmd;
- const char *s;
- eight_bits *cpackets, *cp;
- int ff = 0;
- int sf = 0;
- int ts = 0;
- int max_f = 0;
- int pc = count_char_packet_bytes(L);
- if (pc <= 0)
- return;
- while (l_fonts[(max_f + 1)] != 0)
- max_f++;
- cp = cpackets = xmalloc((unsigned) (pc + 1));
- for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- /* fetch the command code */
- lua_rawgeti(L, -1, 1);
- if (lua_type(L,-1) == LUA_TSTRING) {
- s = lua_tostring(L, -1);
- cmd = 0;
- if (lua_key_eq(s, font)) {
- cmd = packet_font_code;
- } else if (lua_key_eq(s, char)) {
- cmd = packet_char_code;
- if (ff == 0) {
- append_packet(packet_font_code);
- ff = l_fonts[1];
- do_store_four(ff);
- }
- } else if (lua_key_eq(s, slot)) {
- /* we could be sparse but no real reason */
- cmd = packet_nop_code;
- lua_rawgeti(L, -2, 2);
- n = (int) lua_roundnumber(L, -1);
- if (n == 0) {
- sf = f;
- } else {
- sf = (n > max_f ? l_fonts[1] : l_fonts[n]);
- }
- lua_rawgeti(L, -3, 3);
- n = (int) lua_roundnumber(L, -1);
- lua_pop(L, 2);
- append_packet(packet_font_code);
- do_store_four(sf);
- append_packet(packet_char_code);
- do_store_four(n);
- } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
- cmd = packet_nop_code;
- } else if (lua_key_eq(s, node)) {
- cmd = packet_node_code;
- } else if (lua_key_eq(s, push)) {
- cmd = packet_push_code;
- } else if (lua_key_eq(s, pop)) {
- cmd = packet_pop_code;
- } else if (lua_key_eq(s, rule)) {
- cmd = packet_rule_code;
- } else if (lua_key_eq(s, right)) {
- cmd = packet_right_code;
- } else if (lua_key_eq(s, down)) {
- cmd = packet_down_code;
- } else if (lua_key_eq(s, pdf)) {
- cmd = packet_pdf_code;
- } else if (lua_key_eq(s, special)) {
- cmd = packet_special_code;
- } else if (lua_key_eq(s, image)) {
- cmd = packet_image_code;
- } else if (lua_key_eq(s, scale)) {
- cmd = packet_scale_code;
- } else if (lua_key_eq(s, lua)) {
- cmd = packet_lua_code;
- }
- switch (cmd) {
- case packet_push_code:
- case packet_pop_code:
- append_packet(cmd);
- break;
- case packet_font_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- n = (int) lua_roundnumber(L, -1);
- if (n == 0) {
- ff = n;
- } else {
- ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
- }
- do_store_four(ff);
- lua_pop(L, 1);
- break;
- case packet_node_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- n = copy_node_list(nodelist_from_lua(L));
- do_store_four(n);
- lua_pop(L, 1);
- break;
- case packet_char_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- n = (int) lua_roundnumber(L, -1);
- do_store_four(n);
- lua_pop(L, 1);
- break;
- case packet_right_code:
- case packet_down_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- n = (int) lua_roundnumber(L, -1);
- do_store_four(sp_to_dvi(n, atsize));
- lua_pop(L, 1);
- break;
- case packet_rule_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- n = (int) lua_roundnumber(L, -1);
- do_store_four(sp_to_dvi(n, atsize));
- lua_rawgeti(L, -3, 3);
- n = (int) lua_roundnumber(L, -1);
- do_store_four(sp_to_dvi(n, atsize));
- lua_pop(L, 2);
- break;
- case packet_pdf_code:
- ts = (int) lua_rawlen(L, -2);
- lua_rawgeti(L, -2, 2);
- if (ts == 3) {
- /* mode on stack */
- s = lua_tostring(L, -1);
- if (lua_type(L, -1) == LUA_TSTRING) {
- /* <pdf> <mode> <direct|page|text|raw|origin> */
- if (lua_key_eq(s, mode)) {
- cmd = packet_pdf_mode;
- lua_rawgeti(L, -3, 3);
- /* mode on stack */
- s = lua_tostring(L, -1);
- }
- } else {
- /* <pdf> <direct|page|text|raw|origin> <string> */
- }
- if (lua_type(L, -1) == LUA_TSTRING) {
- if (lua_key_eq(s, direct)) {
- n = direct_always;
- } else if (lua_key_eq(s, page)) {
- n = direct_page;
- } else if (lua_key_eq(s, text)) {
- n = direct_text;
- } else if (lua_key_eq(s, font)) {
- n = direct_font;
- } else if (lua_key_eq(s, raw)) {
- n = direct_raw;
- } else if (lua_key_eq(s, origin)) {
- n = set_origin;
- } else {
- /* normal_warning("vf command","invalid pdf literal type"); */
- n = set_origin ;
- }
- } else {
- n = (int) lua_roundnumber(L, -1);
- if (n < set_origin || n >= scan_special) {
- n = set_origin ;
- }
- }
- if (cmd == packet_pdf_code) {
- lua_rawgeti(L, -3, 3);
- /* string on stack */
- }
- } else {
- n = set_origin;
- }
- append_packet(cmd);
- do_store_four(n);
- if (cmd == packet_pdf_code) {
- s = luaL_checklstring(L, -1, &l);
- do_store_four(l);
- if (l > 0) {
- m = (int) l;
- while (m > 0) {
- n = *s++;
- m--;
- append_packet(n);
- }
- }
- }
- lua_pop(L,ts == 3 ? 2 : 1);
- break;
- case packet_special_code:
- case packet_lua_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- s = luaL_checklstring(L, -1, &l);
- if (l > 0) {
- do_store_four(l);
- m = (int) l;
- while (m > 0) {
- n = *s++;
- m--;
- append_packet(n);
- }
- }
- lua_pop(L, 1);
- break;
- case packet_image_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2); /* img/imgtable? ... */
- if (lua_istable(L, -1)) { /* imgtable ... */
- lua_getglobal(L, "img"); /* imglib imgtable ... */
- lua_pushstring(L, "new"); /* `new' imglib imgtable ... */
- lua_gettable(L, -2); /* f imglib imgtable ... */
- lua_insert(L, -3); /* imglib imgtable f ... */
- lua_pop(L, 1); /* imgtable f ... */
- lua_call(L, 1, 1);
- } /* img ... */
- luaL_checkudata(L, -1, TYPE_IMG); /* img ... --- just typecheck */
- n = luaL_ref(L, LUA_REGISTRYINDEX); /* ... */
- do_store_four(n);
- break;
- case packet_nop_code:
- break;
- case packet_scale_code:
- append_packet(cmd);
- lua_rawgeti(L, -2, 2);
- append_float(&cp, (float) luaL_checknumber(L, -1));
- lua_pop(L, 1);
- break;
- default:
- normal_error("vf command","invalid packet code");
- /* fprintf(stdout, "Unknown char packet code %s\n", s); */
- }
- }
- lua_pop(L, 1); /* command code */
- } else {
- normal_error("vf command","commands has to be a table");
- /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
- }
- lua_pop(L, 1); /* command table */
- }
- append_packet(packet_end_code);
- set_charinfo_packets(co, cpackets);
- return;
-}
-
-@ @c
-static void read_lua_cidinfo(lua_State * L, int f)
-{
- int i;
- char *s;
- /*lua_getfield(L, -1, "cidinfo");*/
- lua_key_rawgeti(cidinfo);
- if (lua_istable(L, -1)) {
- i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
- set_font_cidversion(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
- set_font_cidsupplement(f, i);
- s = n_string_field_copy(L, lua_key_index(registry), "Adobe"); /* Adobe-Identity-0 */
- set_font_cidregistry(f, s);
- s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
- set_font_cidordering(f, s);
- }
- lua_pop(L, 1);
-}
-
-
-@ @c
-static void read_lua_parameters(lua_State * L, int f)
-{
- int i, n, t;
- const char *s;
- /*lua_getfield(L, -1, "parameters");*/
- lua_key_rawgeti(parameters);
- if (lua_istable(L, -1)) {
- /* the number of parameters is the max(IntegerKeys(L)),7) */
- n = 7;
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- if (lua_type(L, -2) == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i > n)
- n = i;
- }
- lua_pop(L, 1); /* pop value */
- }
- if (n > 7)
- set_font_params(f, n);
- /* sometimes it is handy to have all integer keys */
- for (i = 1; i <= 7; i++) {
- lua_rawgeti(L, -1, i);
- if (lua_type(L, -1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1); /* round ? */
- set_font_param(f, i, n);
- }
- lua_pop(L, 1);
- }
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- t = lua_type(L,-2);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 8) {
- if (lua_type(L,-1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1);
- } else {
- n = 0;
- }
- set_font_param(f, i, n);
- }
- } else if (t == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_type(L,-1) == LUA_TNUMBER) {
- n = lua_roundnumber(L, -1);
- } else {
- n = 0;
- }
- if (lua_key_eq(s, slant)) {
- set_font_param(f, slant_code, n);
- } else if (lua_key_eq(s, space)) {
- set_font_param(f, space_code, n);
- } else if (lua_key_eq(s, space_stretch)) {
- set_font_param(f, space_stretch_code, n);
- } else if (lua_key_eq(s, space_shrink)) {
- set_font_param(f, space_shrink_code, n);
- } else if (lua_key_eq(s, x_height)) {
- set_font_param(f, x_height_code, n);
- } else if (lua_key_eq(s, quad)) {
- set_font_param(f, quad_code, n);
- } else if (lua_key_eq(s, extra_space)) {
- set_font_param(f, extra_space_code, n);
- }
- }
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-
-}
-
-@ @c
-static void read_lua_math_parameters(lua_State * L, int f)
-{
- int i = 0, n = 0, t;
- /*lua_getfield(L, -1, "MathConstants");*/
- lua_key_rawgeti(MathConstants);
- if (lua_istable(L, -1)) {
- lua_pushnil(L);
- while (lua_next(L, -2) != 0) {
- t = lua_type(L,-2);
- if (t == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- } else if (t == LUA_TSTRING) {
- i = ff_checkoption(L, -2, NULL, MATH_param_names);
- }
- n = (int) lua_roundnumber(L, -1);
- if (i > 0) {
- set_font_math_param(f, i, n);
- }
- lua_pop(L, 1); /* pop value */
- }
- set_font_oldmath(f,false);
- } else {
- set_font_oldmath(f,true);
- }
- lua_pop(L, 1);
-}
-
-@ @c
-#define MIN_INF -0x7FFFFFFF
-
-static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
-{
- int l, k;
- scaled ht, krn;
- lua_key_direct_rawgeti(index);
- if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
- for (l = 0; l < k; l++) {
- lua_rawgeti(L, -1, (l + 1));
- if (lua_istable(L, -1)) {
- ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
- krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
- if (krn > MIN_INF && ht > MIN_INF)
- add_charinfo_math_kern(co, id, ht, krn);
- }
- lua_pop(L, 1);
- }
- }
- lua_pop(L, 1);
-}
-
-@ @c
-static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
-{
- int k, r, t, lt, u, n;
- charinfo *co;
- kerninfo *ckerns;
- liginfo *cligs;
- scaled j;
- const char *s;
- int nl = 0; /* number of ligature table items */
- int nk = 0; /* number of kern table items */
- int ctr = 0;
- int atsize = font_size(f);
- if (lua_istable(L, -1)) {
- co = get_charinfo(f, i);
- set_charinfo_tag(co, 0);
- j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
- set_charinfo_width(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
- set_charinfo_height(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
- set_charinfo_depth(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
- set_charinfo_italic(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
- set_charinfo_vert_italic(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
- set_charinfo_index(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
- set_charinfo_ef(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
- set_charinfo_lp(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
- set_charinfo_rp(co, j);
- k = n_boolean_field(L, lua_key_index(used), 0);
- set_charinfo_used(co, k);
- s = n_string_field(L, lua_key_index(name));
- if (s != NULL)
- set_charinfo_name(co, xstrdup(s));
- else
- set_charinfo_name(co, NULL);
- /* n_string_field leaves a value on stack*/
- lua_pop(L,1);
- u = n_some_field(L,lua_key_index(tounicode));
- if (u == LUA_TNUMBER) {
- u = lua_tointeger(L,-1);
- if (u < 0) {
- set_charinfo_tounicode(co, NULL);
- } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- char *s = malloc(5);
- sprintf(s,"%04X",(unsigned int) u);
- set_charinfo_tounicode(co,s);
- } else {
- char *s = malloc(9);
- u = u - 0x10000;
- sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
- set_charinfo_tounicode(co,s);
- }
- } else if (u == LUA_TTABLE) {
- n = lua_rawlen(L,-1);
- u = 0;
- for (k = 1; k <= n; k++) {
- lua_rawgeti(L, -1, k);
- if (lua_type(L,-1) == LUA_TNUMBER) {
- u = lua_tointeger(L,-1);
- } else {
- lua_pop(L, 1);
- break;
- }
- if (u < 0) {
- u = -1;
- lua_pop(L, 1);
- break;
- } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- u = u + 4;
- } else {
- u = u + 8;
- }
- lua_pop(L, 1);
- }
- if (u>0) {
- char *s = malloc(u+1);
- char *t = s ;
- for (k = 1; k <= n; k++) {
- lua_rawgeti(L, -1, k);
- u = lua_tointeger(L,-1);
- if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
- sprintf(t,"%04X",(unsigned int) u);
- t += 4;
- } else {
- u = u - 0x10000;
- sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
- t += 8;
- }
- lua_pop(L, 1);
- }
- set_charinfo_tounicode(co,s);
- } else {
- set_charinfo_tounicode(co, NULL);
- }
- } else if (u == LUA_TSTRING) {
- s = lua_tostring(L,-1);
- set_charinfo_tounicode(co, xstrdup(s));
- } else {
- set_charinfo_tounicode(co, NULL);
- }
- /* ... leaves a value on stack*/
- lua_pop(L,1);
-
- if (has_math) {
- j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
- set_charinfo_top_accent(co, j);
- j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
- set_charinfo_bot_accent(co, j);
- k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
- if (k >= 0) {
- set_charinfo_tag(co, list_tag);
- set_charinfo_remainder(co, k);
- }
-
- lua_key_rawgeti(extensible);
- if (lua_istable(L, -1)) {
- int top, bot, mid, rep;
- top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
- bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
- mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
- rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
- if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
- set_charinfo_tag(co, ext_tag);
- set_charinfo_extensible(co, top, bot, mid, rep);
- } else {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", font_name(f), (int) i);
- }
- }
- lua_pop(L, 1);
-
- lua_key_rawgeti(horiz_variants);
- if (lua_istable(L, -1)) {
- int glyph, startconnect, endconnect, advance, extender;
- extinfo *h;
- set_charinfo_tag(co, ext_tag);
- set_charinfo_hor_variants(co, NULL);
- for (k = 1;; k++) {
- lua_rawgeti(L, -1, k);
- if (lua_istable(L, -1)) {
- glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
- extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
- startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
- endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
- advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
- h = new_variant(glyph, startconnect, endconnect, advance, extender);
- add_charinfo_hor_variant(co, h);
- lua_pop(L, 1);
- } else {
- lua_pop(L, 1);
- break;
- }
- }
- }
- lua_pop(L, 1);
-
- lua_key_rawgeti(vert_variants);
- if (lua_istable(L, -1)) {
- int glyph, startconnect, endconnect, advance, extender;
- extinfo *h;
- set_charinfo_tag(co, ext_tag);
- set_charinfo_vert_variants(co, NULL);
- for (k = 1;; k++) {
- lua_rawgeti(L, -1, k);
- if (lua_istable(L, -1)) {
- glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
- extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
- startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
- endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
- advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
- h = new_variant(glyph, startconnect, endconnect, advance, extender);
- add_charinfo_vert_variant(co, h);
- lua_pop(L, 1);
- } else {
- lua_pop(L, 1);
- break;
- }
- }
- }
- lua_pop(L, 1);
-
- /*
- Here is a complete example:
-
- |mathkern = {|
- | bottom_left = { { height = 420, kern = 80 }, { height = 520, kern = 4 } },|
- | bottom_right = { { height = 0, kern = 48 } },|
- | top_left = { { height = 620, kern = 0 }, { height = 720, kern = -80 } },|
- | top_right = { { height = 676, kern = 115 }, { height = 776, kern = 45 } },|
- |}|
-
- */
-
- lua_key_rawgeti(mathkern);
- if (lua_istable(L, -1)) {
- store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
- store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
- store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
- store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
- }
- lua_pop(L, 1);
- }
- /* end of |has_math| */
- count_hash_items(L, kerns, nk);
- if (nk > 0) {
- /* kerns table still on stack */
- ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
- ctr = 0;
- lua_pushnil(L); /* traverse hash */
- while (lua_next(L, -2) != 0) {
- k = non_boundarychar;
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
- if (k < 0)
- k = non_boundarychar;
- } else if (lt == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_key_eq(s, right_boundary)) {
- k = right_boundarychar;
- if (!has_right_boundary(f))
- set_right_boundary(f, get_charinfo(f, right_boundarychar));
- }
- }
- j = lua_roundnumber(L, -1); /* movement */
- if (k != non_boundarychar) {
- set_kern_item(ckerns[ctr], k, j);
- ctr++;
- } else {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field", font_name(f), (int) i);
- }
- lua_pop(L, 1);
- }
- /* guard against empty tables */
- if (ctr > 0) {
- set_kern_item(ckerns[ctr], end_kern, 0);
- set_charinfo_kerns(co, ckerns);
- } else {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", font_name(f), (int) i);
- }
- lua_pop(L, 1);
- }
-
- /* packet commands */
-
- lua_key_rawgeti(commands);
- if (lua_istable(L, -1)) {
- lua_pushnil(L); /* first key */
- if (lua_next(L, -2) != 0) {
- lua_pop(L, 2);
- read_char_packets(L, (int *) l_fonts, co, f, atsize);
- }
- }
- lua_pop(L, 1);
-
- /* ligatures */
- count_hash_items(L, ligatures, nl);
- if (nl > 0) {
- /* ligatures table still on stack */
- cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
- ctr = 0;
- lua_pushnil(L); /* traverse hash */
- while (lua_next(L, -2) != 0) {
- k = non_boundarychar;
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
- if (k < 0) {
- k = non_boundarychar;
- }
- } else if (lt == LUA_TSTRING) {
- s = lua_tostring(L, -2);
- if (lua_key_eq(s, right_boundary)) {
- k = right_boundarychar;
- if (!has_right_boundary(f))
- set_right_boundary(f, get_charinfo(f, right_boundarychar));
- }
- }
- r = -1;
- if (lua_istable(L, -1)) {
- r = lua_numeric_field_by_index(L, lua_key_index(char), -1); /* ligature */
- }
- if (r != -1 && k != non_boundarychar) {
- t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
- set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
- ctr++;
- } else {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field", font_name(f), (int) i);
- }
- lua_pop(L, 1); /* iterator value */
- }
- /* guard against empty tables */
- if (ctr > 0) {
- set_ligature_item(cligs[ctr], 0, end_ligature, 0);
- set_charinfo_ligatures(co, cligs);
- } else {
- formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field", font_name(f), (int) i);
- }
- lua_pop(L, 1); /* ligatures table */
- }
- }
-}
-
-@ The caller has to fix the state of the lua stack when there is an error!
-
- at c
-int font_from_lua(lua_State * L, int f)
-{
- int i, n, r, t, lt;
- int s_top; /* lua stack top */
- int bc; /* first char index */
- int ec; /* last char index */
- char *s;
- const char *ss;
- int *l_fonts = NULL;
- int save_ref ;
- boolean no_math = false;
-
- /* will we save a cache of the luat table? */
-
- save_ref = 1; /* we start with ss = "yes" */
- ss = NULL;
- ss = n_string_field(L, lua_key_index(cache));
- if (lua_key_eq(ss, no))
- save_ref = -1;
- else if (lua_key_eq(ss, renew))
- save_ref = 0;
- /* n_string_field leaves a value on stack*/
- lua_pop(L,1);
-
- /* the table is at stack index -1 */
- s = n_string_field_copy(L,lua_key_index(area), "");
- set_font_area(f, s);
- s = n_string_field_copy(L, lua_key_index(filename), NULL);
- set_font_filename(f, s);
- s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
- set_font_encodingname(f, s);
-
- s = n_string_field_copy(L, lua_key_index(name), NULL);
- set_font_name(f, s);
- s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
- set_font_fullname(f, s);
-
- if (s == NULL) {
- formatted_error("font","lua-loaded font '%d' has no name!", f);
- return false;
- }
- s = n_string_field_copy(L, lua_key_index(psname), NULL);
- set_font_psname(f, s);
-
- i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
- set_font_units_per_em(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
- set_font_dsize(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
- set_font_size(f, i);
- set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
- i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
- set_font_natural_dir(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
- set_font_encodingbytes(f, (char) i);
- i = lua_numeric_field_by_index(L,lua_key_index(streamprovider), 0);
- set_font_streamprovider(f, (char) i);
- i = n_boolean_field(L,lua_key_index(oldmath), 0);
- set_font_oldmath(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
- set_font_tounicode(f, (char) i);
-
- i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
- if (i < FONT_EXTEND_MIN)
- i = FONT_EXTEND_MIN;
- if (i > FONT_EXTEND_MAX)
- i = FONT_EXTEND_MAX;
- set_font_extend(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
- if (i < FONT_SLANT_MIN)
- i = FONT_SLANT_MIN;
- if (i > FONT_SLANT_MAX)
- i = FONT_SLANT_MAX;
- set_font_slant(f, i);
-
- i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
- set_hyphen_char(f, i);
- i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
- set_skew_char(f, i);
- i = n_boolean_field(L, lua_key_index(used), 0);
- set_font_used(f, (char) i);
-
- s = n_string_field_copy(L, lua_key_index(attributes), NULL);
- if (s != NULL && strlen(s) > 0) {
- i = maketexstring(s);
- set_pdf_font_attr(f, i);
- }
- free(s);
-
- i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
- set_font_type(f, i);
- i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
- set_font_format(f, i);
- i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
- set_font_writingmode(f, i);
- i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
- set_font_identity(f, i);
- i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
- set_font_embedding(f, i);
- if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
- set_font_encodingbytes(f, 2);
- }
-
- /* now fetch the base fonts, if needed */
- count_hash_items(L, fonts, n);
- if (n > 0) {
- /* font table still on stack */
- l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
- memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
- for (i = 1; i <= n; i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- lua_key_rawgeti(id);
- if (lua_isnumber(L, -1)) {
- l_fonts[i] = (int) lua_tointeger(L, -1);
- if (l_fonts[i] == 0) {
- l_fonts[i] = (int) f;
- }
- lua_pop(L, 2); /* pop id and entry */
- continue;
- }
- lua_pop(L, 1); /* pop id */
- };
- ss = NULL;
- if (lua_istable(L, -1)) {
- ss = n_string_field(L, lua_key_index(name));
- /* string is anchored */
- lua_pop(L,1);
- }
- if (ss != NULL) {
- t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
- /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
- s_top = lua_gettop(L);
- if (strcmp(font_name(f), ss) == 0)
- l_fonts[i] = f;
- else
- l_fonts[i] = find_font_id(ss, t);
- lua_settop(L, s_top);
- } else {
- formatted_error("font","invalid local font at index %i in lua-loaded font '%s' (1)",i,font_name(f));
- }
- lua_pop(L, 1); /* pop list entry */
- }
- lua_pop(L, 1); /* pop font table */
- } else if (font_type(f) == virtual_font_type) {
- formatted_error("font","invalid local fonts in lua-loaded font '%s' (2)", font_name(f));
- } else {
- l_fonts = xmalloc(3 * sizeof(int));
- l_fonts[0] = 0;
- l_fonts[1] = f;
- l_fonts[2] = 0;
- }
- /* parameters */
- no_math = n_boolean_field(L, lua_key_index(nomath), 0);
- read_lua_parameters(L, f);
- if (!no_math) {
- read_lua_math_parameters(L, f);
- if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
- set_font_oldmath(f,true);
- }
-
- } else {
- set_font_oldmath(f,true);
- }
- read_lua_cidinfo(L, f);
-
- /* characters */
- lua_key_rawgeti(characters);
- if (lua_istable(L, -1)) {
- /* find the array size values */
- int num = 0; /* number of charinfo's to add */
- ec = 0;
- bc = -1;
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- if (lua_isnumber(L, -2)) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 0) {
- if (lua_istable(L, -1)) {
- num++;
- if (i > ec)
- ec = i;
- if (bc < 0)
- bc = i;
- if (bc >= 0 && i < bc)
- bc = i;
- }
- }
- }
- lua_pop(L, 1);
- }
- if (bc != -1) {
- font_malloc_charinfo(f, num);
- set_font_bc(f, bc);
- set_font_ec(f, ec);
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 0) {
- font_char_from_lua(L, f, i, l_fonts, !no_math);
- }
- } else if (lt == LUA_TSTRING) {
- const char *ss1 = lua_tostring(L, -2);
- if (lua_key_eq(ss1, left_boundary)) {
- font_char_from_lua(L, f, left_boundarychar, l_fonts, !no_math);
- } else if (lua_key_eq(ss1, right_boundary)) {
- font_char_from_lua(L, f, right_boundarychar, l_fonts, !no_math);
- }
- }
- lua_pop(L, 1);
- }
- lua_pop(L, 1);
-
- /*
- Handle font expansion last: the |copy_font| routine is called eventually,
- and that needs to know |bc| and |ec|.
- */
-
- if (font_type(f) != virtual_font_type) {
- int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
- if (fstep < 0)
- fstep = 0;
- if (fstep > 100)
- fstep = 100;
- if (fstep != 0) {
- int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
- int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
- if (fshrink < 0)
- fshrink = 0;
- if (fshrink > 500)
- fshrink = 500;
- fshrink -= (fshrink % fstep);
- if (fshrink < 0)
- fshrink = 0;
- if (fstretch < 0)
- fstretch = 0;
- if (fstretch > 1000)
- fstretch = 1000;
- fstretch -= (fstretch % fstep);
- if (fstretch < 0)
- fstretch = 0;
- set_expand_params(f, fstretch, fshrink, fstep);
- }
- }
-
- } else {
- /* jikes, no characters */
- formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
- }
-
- if (save_ref > 0) {
- r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
- set_font_cache_id(f, r);
- } else {
- lua_pop(L, 1);
- set_font_cache_id(f, save_ref);
- }
- } else {
- /* jikes, no characters */
- formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
- }
- if (l_fonts != NULL)
- free(l_fonts);
- return true;
-}
-
-int characters_from_lua(lua_State * L, int f)
-{
- int i, n, t, lt;
- int *l_fonts = NULL;
- int s_top;
- const char *ss;
- boolean no_math = false;
- /* speedup */
- no_math = n_boolean_field(L, lua_key_index(nomath), 0);
- /* type */
- i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings);
- set_font_type(f, i);
- /* fonts */
- count_hash_items(L, fonts, n);
- if (n > 0) {
- /* font table still on stack */
- l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
- memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
- for (i = 1; i <= n; i++) {
- lua_rawgeti(L, -1, i);
- if (lua_istable(L, -1)) {
- lua_key_rawgeti(id);
- if (lua_isnumber(L, -1)) {
- l_fonts[i] = (int) lua_tointeger(L, -1);
- if (l_fonts[i] == 0) {
- l_fonts[i] = (int) f;
- }
- lua_pop(L, 2); /* pop id and entry */
- continue;
- }
- lua_pop(L, 1); /* pop id */
- };
- ss = NULL;
- if (lua_istable(L, -1)) {
- ss = n_string_field(L, lua_key_index(name));
- /* string is anchored */
- lua_pop(L,1);
- }
- if (ss != NULL) {
- t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
- /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
- s_top = lua_gettop(L);
- if (strcmp(font_name(f), ss) == 0)
- l_fonts[i] = f;
- else
- l_fonts[i] = find_font_id(ss, t);
- lua_settop(L, s_top);
- } else {
- formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f));
- }
- lua_pop(L, 1); /* pop list entry */
- }
- lua_pop(L, 1); /* pop font table */
- } else if (font_type(f) == virtual_font_type) {
- formatted_error("font","invalid local fonts in lua-loaded font '%s' (4)", font_name(f));
- } else {
- l_fonts = xmalloc(3 * sizeof(int));
- l_fonts[0] = 0;
- l_fonts[1] = f;
- l_fonts[2] = 0;
- }
- /* characters */
- lua_key_rawgeti(characters);
- if (lua_istable(L, -1)) {
- /* find the array size values */
- int num = 0; /* number of charinfo's to add */
- int todo = 0;
- int bc = font_bc(f);
- int ec = font_ec(f);
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- if (lua_isnumber(L, -2)) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 0) {
- if (lua_istable(L, -1)) {
- todo++;
- if (! quick_char_exists(f,i)) {
- num++;
- if (i > ec)
- ec = i;
- if (bc < 0)
- bc = i;
- if (bc >= 0 && i < bc)
- bc = i;
- }
- }
- }
- }
- lua_pop(L, 1);
- }
- if (todo > 0) {
- font_malloc_charinfo(f, num);
- set_font_bc(f, bc);
- set_font_ec(f, ec);
- lua_pushnil(L); /* first key */
- while (lua_next(L, -2) != 0) {
- lt = lua_type(L,-2);
- if (lt == LUA_TNUMBER) {
- i = (int) lua_tointeger(L, -2);
- if (i >= 0) {
- if (quick_char_exists(f,i)) {
- charinfo *co = char_info(f, i);
- set_charinfo_name(co, NULL);
- set_charinfo_tounicode(co, NULL);
- set_charinfo_packets(co, NULL);
- set_charinfo_ligatures(co, NULL);
- set_charinfo_kerns(co, NULL);
- set_charinfo_vert_variants(co, NULL);
- set_charinfo_hor_variants(co, NULL);
- }
- font_char_from_lua(L, f, i, l_fonts, !no_math);
- }
- }
- lua_pop(L, 1);
- }
- lua_pop(L, 1);
- }
- }
- if (l_fonts != NULL)
- free(l_fonts);
- return true;
-}
-
-@* Ligaturing.
-
- at c
-static void nesting_append(halfword nest1, halfword newn)
-{
- halfword tail = tlink(nest1);
- if (tail == null) {
- couple_nodes(nest1, newn);
- } else {
- couple_nodes(tail, newn);
- }
- tlink(nest1) = newn;
-}
-
-static void nesting_prepend(halfword nest1, halfword newn)
-{
- halfword head = vlink(nest1);
- couple_nodes(nest1, newn);
- if (head == null) {
- tlink(nest1) = newn;
- } else {
- couple_nodes(newn, head);
- }
-}
-
-static void nesting_prepend_list(halfword nest1, halfword newn)
-{
- halfword head = vlink(nest1);
- couple_nodes(nest1, newn);
- if (head == null) {
- tlink(nest1) = tail_of_list(newn);
- } else {
- halfword tail = tail_of_list(newn);
- couple_nodes(tail, head);
- }
-}
-
-static int test_ligature(liginfo * lig, halfword left, halfword right)
-{
- if (type(left) != glyph_node)
- return 0;
- if (font(left) != font(right))
- return 0;
- if (is_ghost(left) || is_ghost(right))
- return 0;
- *lig = get_ligature(font(left), character(left), character(right));
- if (is_valid_ligature(*lig)) {
- return 1;
- }
- return 0;
-}
-
-static int try_ligature(halfword * frst, halfword fwd)
-{
- halfword cur = *frst;
- liginfo lig;
- if (test_ligature(&lig, cur, fwd)) {
- int move_after = (lig_type(lig) & 0x0C) >> 2;
- int keep_right = ((lig_type(lig) & 0x01) != 0);
- int keep_left = ((lig_type(lig) & 0x02) != 0);
- halfword newgl = raw_glyph_node();
- font(newgl) = font(cur);
- character(newgl) = lig_replacement(lig);
- set_is_ligature(newgl);
- /*
- below might not be correct in contrived border case.
- but we use it only for debugging, so ...
- */
- if (character(cur) < 0) {
- set_is_leftboundary(newgl);
- }
- if (character(fwd) < 0) {
- set_is_rightboundary(newgl);
- }
- if (character(cur) < 0) {
- if (character(fwd) < 0) {
- build_attribute_list(newgl);
- } else {
- add_node_attr_ref(node_attr(fwd));
- node_attr(newgl) = node_attr(fwd);
- }
- } else {
- add_node_attr_ref(node_attr(cur));
- node_attr(newgl) = node_attr(cur);
- }
-
- /*
- TODO/FIXME if this ligature is consists of another ligature
- we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
- cleanup the no longer needed node) LOW PRIORITY
- */
- /* left side */
- if (keep_left) {
- halfword new_first = copy_node(cur);
- lig_ptr(newgl) = new_first;
- couple_nodes(cur, newgl);
- if (move_after) {
- move_after--;
- cur = newgl;
- }
- } else {
- halfword prev = alink(cur);
- uncouple_node(cur);
- lig_ptr(newgl) = cur;
- couple_nodes(prev, newgl);
- cur = newgl; /* as cur has disappeared */
- }
- /* right side */
- if (keep_right) {
- halfword new_second = copy_node(fwd);
- /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
- couple_nodes(lig_ptr(newgl), new_second);
- couple_nodes(newgl, fwd);
- if (move_after) {
- move_after--;
- cur = fwd;
- }
- } else {
- halfword next = vlink(fwd);
- uncouple_node(fwd);
- /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
- couple_nodes(lig_ptr(newgl), fwd);
- if (next != null) {
- couple_nodes(newgl, next);
- }
- }
- /* check and return */
- *frst = cur;
- return 1;
- }
- return 0;
-}
-
-@ there shouldn't be any ligatures here - we only add them at the end of
- |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
- (we continue with \.{DISC-1}'s |post_| and |no_break|.
-
- at c
-static halfword handle_lig_nest(halfword root, halfword cur)
-{
- if (cur == null)
- return root;
- while (vlink(cur) != null) {
- halfword fwd = vlink(cur);
- if (type(cur) == glyph_node && type(fwd) == glyph_node &&
- font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
- continue;
- }
- cur = vlink(cur);
- }
- tlink(root) = cur;
- return root;
-}
-
-static halfword handle_lig_word(halfword cur)
-{
- halfword right = null;
- if (type(cur) == boundary_node) {
- halfword prev = alink(cur);
- halfword fwd = vlink(cur);
- /* no need to uncouple |cur|, it is freed */
- flush_node(cur);
- if (fwd == null) {
- vlink(prev) = fwd;
- return prev;
- }
- couple_nodes(prev, fwd);
- if (type(fwd) != glyph_node)
- return prev;
- cur = fwd;
- } else if (has_left_boundary(font(cur))) {
- halfword prev = alink(cur);
- halfword p = new_glyph(font(cur), left_boundarychar);
- couple_nodes(prev, p);
- couple_nodes(p, cur);
- cur = p;
- }
- if (has_right_boundary(font(cur))) {
- right = new_glyph(font(cur), right_boundarychar);
- }
- while (1) {
- /* A glyph followed by ... */
- if (type(cur) == glyph_node) {
- halfword fwd = vlink(cur);
- if (fwd == null) { /* last character of paragraph */
- if (right == null)
- break;
- /* \.{--\\par} prohibits use of |couple_nodes| here */
- try_couple_nodes(cur, right);
- right = null;
- continue;
- }
- if (type(fwd) == glyph_node) { /* |GLYPH - GLYPH| */
- if (font(cur) != font(fwd))
- break;
- if (try_ligature(&cur, fwd))
- continue;
- } else if (type(fwd) == disc_node) { /* |GLYPH - DISC| */
-
- /* if \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
- halfword pre = vlink_pre_break(fwd);
- halfword nob = vlink_no_break(fwd);
- halfword next, tail;
- liginfo lig;
- /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
- /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
- if ((pre != null && type(pre) == glyph_node
- && test_ligature(&lig, cur, pre))
- || (nob != null && type(nob) == glyph_node
- && test_ligature(&lig, cur, nob))) {
- /* move cur from before disc, to skipped part */
- halfword prev = alink(cur);
- uncouple_node(cur);
- couple_nodes(prev, fwd);
- nesting_prepend(no_break(fwd), cur);
- /* now ligature the |pre_break| */
- nesting_prepend(pre_break(fwd), copy_node(cur));
- /* As we have removed cur, we need to start again ... */
- cur = prev;
- }
- /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
- next = vlink(fwd);
- if (nob == null && next != null && type(next) == glyph_node
- && test_ligature(&lig, cur, next)) {
- /* move |cur| from before |disc| to |no_break| part */
- halfword prev = alink(cur);
- uncouple_node(cur);
- couple_nodes(prev, fwd);
- couple_nodes(no_break(fwd), cur); /* we {\it know\/} it's empty */
- /* now copy cur the |pre_break| */
- nesting_prepend(pre_break(fwd), copy_node(cur));
- /* move next from after disc to |no_break| part */
- tail = vlink(next);
- uncouple_node(next);
- try_couple_nodes(fwd, tail);
- couple_nodes(cur, next); /* we {\it know\/} this works */
- tlink(no_break(fwd)) = next; /* and make sure the list is correct */
- /* now copy next to the |post_break| */
- nesting_append(post_break(fwd), copy_node(next));
- /* As we have removed cur, we need to start again ... */
- cur = prev;
- }
- /* we are finished with the |pre_break| */
- handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
- } else if (type(fwd) == boundary_node) {
- halfword next = vlink(fwd);
- try_couple_nodes(cur, next);
- flush_node(fwd);
- if (right != null) {
- flush_node(right); /* Shame, didn't need it */
- /* no need to reset |right|, we're going to leave the loop anyway */
- }
- break;
- } else {
- /* fwd is something unknown */
- if (right == null)
- break;
- couple_nodes(cur, right);
- couple_nodes(right, fwd);
- right = null;
- continue;
- }
- /* A discretionary followed by ... */
- } else if (type(cur) == disc_node) {
- /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
- if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
- halfword prev = 0;
- halfword fwd;
- liginfo lig;
- if (subtype(cur) == select_disc) {
- prev = alink(cur);
- if (vlink_post_break(cur) != null)
- handle_lig_nest(post_break(prev), vlink_post_break(prev));
- if (vlink_no_break(cur) != null)
- handle_lig_nest(no_break(prev), vlink_no_break(prev));
- }
- if (vlink_post_break(cur) != null)
- handle_lig_nest(post_break(cur), vlink_post_break(cur));
- if (vlink_no_break(cur) != null)
- handle_lig_nest(no_break(cur), vlink_no_break(cur));
- while ((fwd = vlink(cur)) != null) {
- halfword nob, pst, next;
- if (type(fwd) != glyph_node)
- break;
- if (subtype(cur) != select_disc) {
- nob = tlink_no_break(cur);
- pst = tlink_post_break(cur);
- if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
- (pst == null || !test_ligature(&lig, pst, fwd)))
- break;
- nesting_append(no_break(cur), copy_node(fwd));
- handle_lig_nest(no_break(cur), nob);
- } else {
- int dobreak = 0;
- nob = tlink_no_break(prev);
- pst = tlink_post_break(prev);
- if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
- (pst == null || !test_ligature(&lig, pst, fwd)))
- dobreak = 1;
- if (!dobreak) {
- nesting_append(no_break(prev), copy_node(fwd));
- handle_lig_nest(no_break(prev), nob);
- nesting_append(post_break(prev), copy_node(fwd));
- handle_lig_nest(post_break(prev), pst);
- }
- dobreak = 0;
- nob = tlink_no_break(cur);
- pst = tlink_post_break(cur);
- if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
- (pst == null || !test_ligature(&lig, pst, fwd)))
- dobreak = 1;
- if (!dobreak) {
- nesting_append(no_break(cur), copy_node(fwd));
- handle_lig_nest(no_break(cur), nob);
- }
- if (dobreak)
- break;
- }
- next = vlink(fwd);
- uncouple_node(fwd);
- try_couple_nodes(cur, next);
- nesting_append(post_break(cur), fwd);
- handle_lig_nest(post_break(cur), pst);
- }
- if (fwd != null && type(fwd) == disc_node) {
- halfword next = vlink(fwd);
- if (vlink_no_break(fwd) == null
- && vlink_post_break(fwd) == null
- && next != null
- && type(next) == glyph_node
- && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
- (tlink_no_break (cur) != null && test_ligature(&lig, tlink_no_break (cur), next)))) {
- /* Building an |init_disc| followed by a |select_disc|
- \.{{a-}{b}{AB} {-}{}{}} 'c'
- */
- /* is it tail necessary ? */
- halfword last1 = vlink(next), tail ;
- uncouple_node(next);
- try_couple_nodes(fwd, last1);
- /* \.{{a-}{b}{AB} {-}{c}{}} */
- nesting_append(post_break(fwd), copy_node(next));
- /* \.{{a-}{b}{AB} {-}{c}{-}} */
- if (vlink_no_break(cur) != null) {
- nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
- }
- /* \.{{a-}{b}{AB} {b-}{c}{-}} */
- if (vlink_post_break(cur) != null)
- nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
- /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
- if (vlink_no_break(cur) != null) {
- nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
- }
- /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
- tail = tlink_no_break(cur);
- nesting_append(no_break(cur), copy_node(next));
- handle_lig_nest(no_break(cur), tail);
- /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
- tail = tlink_post_break(cur);
- nesting_append(post_break(cur), next);
- handle_lig_nest(post_break(cur), tail);
- /* and set the subtypes */
- subtype(cur) = init_disc;
- subtype(fwd) = select_disc;
- }
- }
- }
-
- } else {
- /* NO GLYPH NOR DISC */
- return cur;
- }
- /* step-to-next-node */
- /* \.{--\\par} allows |vlink(cur)| to be null */
- cur = vlink(cur);
- }
-
- return cur;
-}
-
-@ Return value is the new tail, head should be a dummy
-
- at c
-halfword handle_ligaturing(halfword head, halfword tail)
-{
- halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */
- halfword cur, prev;
-
- if (vlink(head) == null)
- return tail;
- if (tail != null) {
- save_tail1 = vlink(tail);
- vlink(tail) = null;
- }
-
- if (fix_node_lists) {
- fix_node_list(head);
- }
-
- prev = head;
- cur = vlink(prev);
-
- while (cur != null) {
- if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
- cur = handle_lig_word(cur);
- }
- prev = cur;
- cur = vlink(cur);
- }
- if (prev == null) {
- /* hh: looks bad to me */
- prev = tail;
- }
-
- if (tail != null) {
- try_couple_nodes(prev, save_tail1);
- }
- return prev;
-}
-
-
-@* Kerning.
-
- at c
-static void add_kern_before(halfword left, halfword right)
-{
- if ((!is_rightghost(right)) &&
- font(left) == font(right) && has_kern(font(left), character(left))) {
- int k = raw_get_kern(font(left), character(left), character(right));
- if (k != 0) {
- halfword kern = new_kern(k);
- halfword prev = alink(right);
- couple_nodes(prev, kern);
- couple_nodes(kern, right);
- /* update the attribute list (inherit from left) */
- delete_attribute_ref(node_attr(kern));
- add_node_attr_ref(node_attr(left));
- node_attr(kern) = node_attr(left);
- }
- }
-}
-
-static void add_kern_after(halfword left, halfword right, halfword aft)
-{
- if ((!is_rightghost(right)) &&
- font(left) == font(right) && has_kern(font(left), character(left))) {
- int k = raw_get_kern(font(left), character(left), character(right));
- if (k != 0) {
- halfword kern = new_kern(k);
- halfword next = vlink(aft);
- couple_nodes(aft, kern);
- try_couple_nodes(kern, next);
- /* update the attribute list (inherit from left == aft) */
- delete_attribute_ref(node_attr(kern));
- add_node_attr_ref(node_attr(aft));
- node_attr(kern) = node_attr(aft);
- }
- }
-}
-
-static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
-{
- halfword cur = vlink(root);
- halfword left = null;
- if (cur == null) {
- if (init_left != null && init_right != null) {
- add_kern_after(init_left, init_right, root);
- tlink(root) = vlink(root);
- }
- return;
- }
- if (type(cur) == glyph_node) {
- set_is_glyph(cur);
- if (init_left != null)
- add_kern_before(init_left, cur);
- left = cur;
- }
- while ((cur = vlink(cur)) != null) {
- if (type(cur) == glyph_node) {
- set_is_glyph(cur);
- if (left != null) {
- add_kern_before(left, cur);
- if (character(left) < 0 || is_ghost(left)) {
- halfword prev = alink(left);
- couple_nodes(prev, cur);
- flush_node(left);
- }
- }
- left = cur;
- } else {
- if (type(cur) == disc_node) {
- halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
- do_handle_kerning(pre_break(cur), left, null);
- if (vlink_pre_break(cur) != null)
- tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
- do_handle_kerning(post_break(cur), null, right);
- if (vlink_post_break(cur) != null)
- tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
- do_handle_kerning(no_break(cur), left, right);
- if (vlink_no_break(cur) != null)
- tlink_no_break(cur) = tail_of_list(vlink_no_break(cur)); /* needed? */
- }
- if (left != null) {
- if (character(left) < 0 || is_ghost(left)) {
- halfword prev = alink(left);
- couple_nodes(prev, cur);
- flush_node(left);
- }
- left = null;
- }
- }
- }
- if (left != null) {
- if (init_right != null)
- add_kern_after(left, init_right, left);
- if (character(left) < 0 || is_ghost(left)) {
- halfword prev = alink(left);
- halfword next = vlink(left);
- if (next != null) {
- couple_nodes(prev, next);
- tlink(root) = next;
- } else if (prev != root) {
- vlink(prev) = null;
- tlink(root) = prev;
- } else {
- vlink(root) = null;
- tlink(root) = null;
- }
- flush_node(left);
- }
- }
-}
-
-/*
-halfword handle_kerning(halfword head, halfword tail)
-{
- halfword save_link;
- save_link = vlink(tail);
- vlink(tail) = null;
- tlink(head) = tail;
- do_handle_kerning(head, null, null);
- tail = tlink(head);
- if (valid_node(save_link)) {
- try_couple_nodes(tail, save_link);
- }
- return tail;
-}
-*/
-
-halfword handle_kerning(halfword head, halfword tail)
-{
- halfword save_link = null;
- if (tail == null) {
- tlink(head) = null;
- do_handle_kerning(head, null, null);
- } else {
- save_link = vlink(tail);
- vlink(tail) = null;
- tlink(head) = tail;
- do_handle_kerning(head, null, null);
- tail = tlink(head);
- if (valid_node(save_link)) {
- try_couple_nodes(tail, save_link);
- }
- }
- return tail;
-}
-
-@* ligaturing and kerning : lua-interface.
-
- at c
-static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
-{
- int i;
- int top = lua_gettop(Luas);
- if (!get_callback(Luas, callback_id)) {
- lua_pop(Luas, 2);
- return tail;
- }
- nodelist_to_lua(Luas, head);
- nodelist_to_lua(Luas, tail);
- if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
- luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
- return tail;
- }
- if (fix_node_lists) {
- fix_node_list(head);
- }
- lua_settop(Luas, top);
- return tail;
-}
-
-halfword new_ligkern(halfword head, halfword tail)
-{
- int callback_id = 0;
- if (vlink(head) == null)
- return tail;
- callback_id = callback_defined(ligaturing_callback);
- if (callback_id > 0) {
- tail = run_lua_ligkern_callback(head, tail, callback_id);
- if (tail == null)
- tail = tail_of_list(head);
- } else if (callback_id == 0) {
- tail = handle_ligaturing(head, tail);
- }
- callback_id = callback_defined(kerning_callback);
- if (callback_id > 0) {
- tail = run_lua_ligkern_callback(head, tail, callback_id);
- if (tail == null) {
- tail = tail_of_list(head);
- }
- } else if (callback_id == 0) {
- halfword nest1 = new_node(nesting_node, 1);
- halfword cur = vlink(head);
- halfword aft = vlink(tail);
- couple_nodes(nest1, cur);
- tlink(nest1) = tail;
- vlink(tail) = null;
- do_handle_kerning(nest1, null, null);
- couple_nodes(head, vlink(nest1));
- tail = tlink(nest1);
- try_couple_nodes(tail, aft);
- flush_node(nest1);
- }
- return tail;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,770 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <math.h>
+#include <kpathsea/c-auto.h>
+#include <kpathsea/c-memstr.h>
+#include <string.h>
+
+#define FM_BUF_SIZE 1024
+
+static FILE *fm_file;
+
+static unsigned char *fm_buffer = NULL;
+static int fm_size = 0;
+static int fm_curbyte = 0;
+
+#define fm_open(a) (fm_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+#define fm_read_file() readbinfile(fm_file,&fm_buffer,&fm_size)
+#define fm_close() xfclose(fm_file, cur_file_name)
+#define fm_getchar() fm_buffer[fm_curbyte++]
+#define fm_eof() (fm_curbyte>fm_size)
+#define is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
+
+typedef enum { FM_DUPIGNORE, FM_REPLACE, FM_DELETE } updatemode;
+
+typedef struct mitem {
+ /*tex |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
+ updatemode mode;
+ /*tex map file or map line */
+ maptype type;
+ /*tex pointer to map file name or map line */
+ char *line;
+ /*tex line number in map file */
+ int lineno;
+} mapitem;
+
+mapitem *mitem = NULL;
+
+#define read_field(r, q, buf) do { \
+ q = buf; \
+ while (*r != ' ' && *r != '<' && *r != '"' && *r != '\0') \
+ *q++ = *r++; \
+ *q = '\0'; \
+ skip_char(r, ' '); \
+} while (0)
+
+#define set_field(F) do { \
+ if (q > buf) \
+ fm->F = xstrdup(buf); \
+ if (*r == '\0') \
+ goto done; \
+} while (0)
+
+fm_entry *new_fm_entry(void)
+{
+ fm_entry *fm;
+ fm = xtalloc(1, fm_entry);
+ fm->tfm_name = NULL;
+ fm->ps_name = NULL;
+ fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
+ fm->ff_name = NULL;
+ fm->encname = NULL;
+ fm->type = 0;
+ fm->slant = 0;
+ fm->extend = 1000;
+ unset_slantset(fm);
+ unset_extendset(fm);
+ unset_inuse(fm);
+ return fm;
+}
+
+void delete_fm_entry(fm_entry * fm)
+{
+ xfree(fm->tfm_name);
+ xfree(fm->ps_name);
+ xfree(fm->ff_name);
+ xfree(fm);
+}
+
+static ff_entry *new_ff_entry(void)
+{
+ ff_entry *ff;
+ ff = xtalloc(1, ff_entry);
+ ff->ff_name = NULL;
+ ff->ff_path = NULL;
+ return ff;
+}
+
+static void delete_ff_entry(ff_entry * ff)
+{
+ xfree(ff->ff_name);
+ xfree(ff->ff_path);
+ xfree(ff);
+}
+
+static struct avl_table *tfm_tree = NULL;
+static struct avl_table *ff_tree = NULL;
+static struct avl_table *encname_tree = NULL;
+
+/*tex
+
+ We sort |fm_entry| into |tfm_tree| by |tfm_name|:
+
+*/
+
+static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const fm_entry *) pa)->tfm_name, ((const fm_entry *) pb)->tfm_name);
+}
+
+/* We sort |ff_entry| into |ff_tree| by |ff_name|: */
+
+static int comp_ff_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const ff_entry *) pa)->ff_name, ((const ff_entry *) pb)->ff_name);
+}
+
+static void create_avl_trees(void)
+{
+ tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator);
+ ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator);
+ encname_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+}
+
+int avl_do_entry(fm_entry * fm, int mode)
+{
+ fm_entry *p;
+ void *a;
+ void **aa;
+ int delete_new = 0;
+ if (tfm_tree == NULL)
+ create_avl_trees();
+ p = (fm_entry *) avl_find(tfm_tree, fm);
+ if (p != NULL) {
+ switch (mode) {
+ case FM_DUPIGNORE:
+ formatted_warning("map file", "entry for '%s' already exists, duplicates ignored", fm->tfm_name);
+ delete_new = 1;
+ break;
+ case FM_REPLACE:
+ case FM_DELETE:
+ if (is_inuse(p)) {
+ formatted_warning("map file", "entry for '%s' has been used, replace/delete not allowed", fm->tfm_name);
+ delete_new = 1;
+ } else {
+ a = avl_delete(tfm_tree, p);
+ assert(a != NULL);
+ delete_fm_entry(p);
+ }
+ break;
+ default:
+ formatted_error("map file", "something bad happened",0);
+ }
+ }
+ if ((mode == FM_DUPIGNORE || mode == FM_REPLACE) && delete_new == 0) {
+ aa = avl_probe(tfm_tree, fm);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ } else
+ delete_new = 1;
+ return delete_new;
+}
+
+/*tex
+
+ Add the encoding name to an AVL tree. This has nothing to do with |writeenc.c|.
+
+*/
+
+static char *add_encname(char *s)
+{
+ char *p;
+ void **aa;
+ if ((p = (char *) avl_find(encname_tree, s)) == NULL) {
+ /*tex The encoding name has not yet been registered. */
+ p = xstrdup(s);
+ aa = avl_probe(encname_tree, p);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ }
+ return p;
+}
+
+/*tex
+
+ A consistency check for map entry, with warn flag.
+
+*/
+
+static int check_fm_entry(fm_entry * fm, boolean warn)
+{
+ int a = 0;
+ if (is_fontfile(fm) && !is_included(fm)) {
+ if (warn)
+ formatted_warning("map file",
+ "ambiguous entry for '%s': font file present but not included, "
+ "will be treated as font file not present", fm->tfm_name);
+ xfree(fm->ff_name);
+ /*tex Do not set variable |a| as this entry will be still accepted. */
+ }
+ /*tex If both ps_name and font file are missing, drop this entry. */
+ if (fm->ps_name == NULL && !is_fontfile(fm)) {
+ if (warn)
+ formatted_warning("map file", "invalid entry for '%s': both ps_name and font file missing", fm->tfm_name);
+ a += 1;
+ }
+ /*tex \TRUETYPE\ fonts cannot be reencoded without subsetting. */
+ if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) {
+ if (warn)
+ formatted_warning("map file", "invalid entry for '%s': only subsetted TrueType font can be reencoded", fm->tfm_name);
+ a += 2;
+ }
+ /*tex The value of |SlantFont| and |ExtendFont| must be reasonable. */
+ if (fm->slant < FONT_SLANT_MIN || fm->slant > FONT_SLANT_MAX) {
+ if (warn)
+ formatted_warning("map file", "invalid entry for '%s': value '%g' is to large for SlantFont",
+ fm->tfm_name, fm->slant / 1000.0);
+ a += 8;
+ }
+ if (fm->extend < FONT_EXTEND_MIN || fm->extend > FONT_EXTEND_MAX) {
+ if (warn)
+ formatted_warning("map file", "invalid entry for '%s': value '%g' is too large for ExtendFont",
+ fm->tfm_name, fm->extend / 1000.0);
+ a += 16;
+ }
+ return a;
+}
+
+/*tex
+
+ Returns the font number if s is one of the 14 std. font names, -1 otherwise.
+ A bit speed trimmed. Using these base fonts is oldfashioned and doesn't
+ happen in a decent \LUATEX\ produced file.
+
+*/
+
+int check_std_t1font(char *s)
+{
+ static const char *std_t1font_names[] = {
+ "Courier", /* 0:7 */
+ "Courier-Bold", /* 1:12 */
+ "Courier-Oblique", /* 2:15 */
+ "Courier-BoldOblique", /* 3:19 */
+ "Helvetica", /* 4:9 */
+ "Helvetica-Bold", /* 5:14 */
+ "Helvetica-Oblique", /* 6:17 */
+ "Helvetica-BoldOblique", /* 7:21 */
+ "Symbol", /* 8:6 */
+ "Times-Roman", /* 9:11 */
+ "Times-Bold", /* 10:10 */
+ "Times-Italic", /* 11:12 */
+ "Times-BoldItalic", /* 12:16 */
+ "ZapfDingbats" /* 13:12 */
+ };
+ static const int index[] = {
+ -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10,
+ 9, -1, -1, 5, 2, 12, 6, -1, 3, -1, 7
+ };
+ size_t n;
+ int k = -1;
+ n = strlen(s);
+ if (n > 21)
+ return -1;
+ if (n == 12) {
+ /*tex three names have length 12 */
+ switch (*s) {
+ case 'C':
+ /*tex Courier-Bold */
+ k = 1;
+ break;
+ case 'T':
+ /*tex Times-Italic */
+ k = 11;
+ break;
+ case 'Z':
+ /*tex ZapfDingbats */
+ k = 13;
+ break;
+ default:
+ return -1;
+ }
+ } else
+ k = index[n];
+ if (k > -1 && !strcmp(std_t1font_names[k], s))
+ return k;
+ return -1;
+}
+
+static void fm_scan_line(void)
+{
+ int a, b, c, j, u = 0, v = 0;
+ char cc;
+ float d;
+ fm_entry *fm;
+ char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
+ char *p, *q, *s;
+ char *r = NULL;
+ switch (mitem->type) {
+ case MAPFILE:
+ p = fm_line;
+ while (!fm_eof()) {
+ if (fm_curbyte == fm_size) {
+ fm_curbyte++;
+ cc = 10;
+ } else {
+ cc = (char) fm_getchar();
+ }
+ append_char_to_buf(cc, p, fm_line, FM_BUF_SIZE);
+ if (cc == 10)
+ break;
+ }
+ *(--p) = '\0';
+ r = fm_line;
+ break;
+ case MAPLINE:
+ /*tex Work on a string from |makecstring|. */
+ r = mitem->line;
+ break;
+ default:
+ assert(0);
+ }
+ if (*r == '\0' || is_cfg_comment(*r))
+ return;
+ fm = new_fm_entry();
+ read_field(r, q, buf);
+ set_field(tfm_name);
+ if (!isdigit((unsigned char)*r)) {
+ /*tex The 2nd field |ps_name| may not start with a digit. */
+ read_field(r, q, buf);
+ set_field(ps_name);
+ }
+ if (isdigit((unsigned char)*r)) {
+ /*tex Is the font descriptor |/Flags| given? */
+ for (s = r; isdigit((unsigned char)*s); s++);
+ if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') {
+ /*tex not e.g.\ |8r.enc| */
+ fm->fd_flags = atoi(r);
+ while (isdigit((unsigned char)*r))
+ r++;
+ }
+ }
+ /*tex Loop through specials, encoding, font file:*/
+ while (1) {
+ skip_char(r, ' ');
+ switch (*r) {
+ case '\0':
+ goto done;
+ case '"':
+ /*tex The pening quote. */
+ r++;
+ u = v = 0;
+ do {
+ skip_char(r, ' ');
+ if (sscanf(r, "%f %n", &d, &j) > 0) {
+ /*tex Jump behind number, eat also blanks, if any. */
+ s = r + j;
+ if (*(s - 1) == 'E' || *(s - 1) == 'e') {
+ /*tex e.g.\ |0.5ExtendFont|: |%f = 0.5E| */
+ s--;
+ }
+ if (str_prefix(s, "SlantFont")) {
+ /*tex Correct rounding also for negative numbers. */
+ d *= (float) 1000.0;
+ fm->slant = (int) (d > 0 ? d + 0.5 : d - 0.5);
+ set_slantset(fm);
+ r = s + strlen("SlantFont");
+ } else if (str_prefix(s, "ExtendFont")) {
+ d *= (float) 1000.0;
+ fm->extend = (int) (d > 0 ? d + 0.5 : d - 0.5);
+ set_extendset(fm);
+ r = s + strlen("ExtendFont");
+ } else {
+ /*tex unknown name, jump over it */
+ for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++);
+ c = *r;
+ *r = '\0';
+ formatted_warning("map file", "invalid entry for '%s': unknown name '%s' ignored", fm->tfm_name, s);
+ *r = (char) c;
+ }
+ } else
+ for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
+ }
+ while (*r == ' ');
+ if (*r == '"') {
+ /*tex The closing quote. */
+ r++;
+ } else {
+ formatted_warning("map file", "invalid entry for '%s': closing quote missing", fm->tfm_name);
+ goto bad_line;
+ }
+ break;
+ case 'P':
+ /*tex Handle cases for sub fonts like |PidEid=3,1| */
+ formatted_warning("map file", "invalid entry for '%s': subfonts are not supported", fm->tfm_name);
+ goto bad_line;
+ break;
+ default:
+ /*tex Encoding or font file specification. */
+ a = b = 0;
+ if (*r == '<') {
+ a = *r++;
+ if (*r == '<' || *r == '[')
+ b = *r++;
+ }
+ read_field(r, q, buf);
+ /*tex Encoding, Formats: |8r.enc| or |<8r.enc| or |<[8r.enc| */
+ if (strlen(buf) > 4 && strcasecmp(strend(buf) - 4, ".enc") == 0) {
+ /*tex |u|, |v| used if intervening blank: |<< foo| */
+ fm->encname = add_encname(buf);
+ u = v = 0;
+ } else if (strlen(buf) > 0) {
+ /*tex
+
+ We get the file name given where possible formats are:
+
+ \starttabulate[|||]
+ \NC subsetting \NC \tpe {<cmr10.pfa} \NC \NR
+ \NC no subsetting \NC \tpe {<<cmr10.pfa} \NC \NR
+ \NC no embedding \NC \tpe {cmr10.pfa} \NC \NR
+ \stoptabulate
+
+ */
+ if (a == '<' || u == '<') {
+ set_included(fm);
+ if ((a == '<' && b == 0) || (a == 0 && v == 0)) {
+ set_subsetted(fm);
+ } else {
+ /*tex
+
+ Otherwise |b| equals |<| or |[| which means that we have no subsetting.
+ */
+ }
+ }
+ set_field(ff_name);
+ u = v = 0;
+ } else {
+ u = a;
+ v = b;
+ }
+ }
+ }
+ done:
+ if (fm->ps_name != NULL && (check_std_t1font(fm->ps_name) >= 0))
+ set_std_t1font(fm);
+ if (is_fontfile(fm) && strlen(fm_fontfile(fm)) > 3) {
+ if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 0)
+ set_truetype(fm);
+ else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttc") == 0)
+ set_truetype(fm);
+ else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".otf") == 0)
+ set_opentype(fm);
+ else
+ set_type1(fm);
+ } else {
+ /*tex Assume a builtin font is \TYPEONE\: */
+ set_type1(fm);
+ }
+ if (check_fm_entry(fm, true) != 0)
+ goto bad_line;
+ /*tex
+
+ Until here the map line has been completely scanned without errors; |fm|
+ points to a valid, freshly filled-out |fm_entry| structure. Now follows
+ the actual work of registering or deleting.
+
+ */
+ if (avl_do_entry(fm, mitem->mode) == 0)
+ return;
+ bad_line:
+ delete_fm_entry(fm);
+}
+
+static void fm_read_info(void)
+{
+ int callback_id;
+ int file_opened = 0;
+
+ if (tfm_tree == NULL)
+ create_avl_trees();
+ if (mitem->line == NULL) {
+ /*tex There is nothing to do. */
+ return;
+ }
+ mitem->lineno = 1;
+ switch (mitem->type) {
+ case MAPFILE:
+ xfree(fm_buffer);
+ fm_curbyte = 0;
+ fm_size = 0;
+ cur_file_name = luatex_find_file(mitem->line, find_map_file_callback);
+ if (cur_file_name) {
+ callback_id = callback_defined(read_map_file_callback);
+ if (callback_id > 0) {
+ if (run_callback(callback_id, "S->bSd", cur_file_name,
+ &file_opened, &fm_buffer, &fm_size)) {
+ if (file_opened) {
+ if (fm_size > 0) {
+ report_start_file(filetype_map,cur_file_name);
+ while (!fm_eof()) {
+ fm_scan_line();
+ mitem->lineno++;
+ }
+ report_stop_file(filetype_map);
+ fm_file = NULL;
+ }
+ } else {
+ formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+ }
+ } else {
+ formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+ }
+ } else {
+ if (!fm_open(cur_file_name)) {
+ formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+ } else {
+ fm_read_file();
+ report_start_file(filetype_map,cur_file_name);
+ while (!fm_eof()) {
+ fm_scan_line();
+ mitem->lineno++;
+ }
+ fm_close();
+ report_stop_file(filetype_map);
+ fm_file = NULL;
+ }
+ }
+ cur_file_name = NULL;
+ }
+ break;
+ case MAPLINE:
+ cur_file_name = NULL;
+ fm_scan_line();
+ break;
+ default:
+ assert(0);
+ }
+ /*tex Done with this line: */
+ mitem->line = NULL;
+ cur_file_name = NULL;
+ return;
+}
+
+fm_entry *getfontmap(char *tfm_name)
+{
+ fm_entry *fm;
+ fm_entry tmp;
+ if (tfm_name == NULL) {
+ /*tex Wide \LUA\ loaded fonts may not have a name. */
+ return NULL;
+ }
+ if (tfm_tree == NULL) {
+ /*tex Only read the default map file. */
+ fm_read_info();
+ }
+ /*tex Look up the name. */
+ tmp.tfm_name = tfm_name;
+ fm = (fm_entry *) avl_find(tfm_tree, &tmp);
+ if (fm == NULL)
+ return NULL;
+ set_inuse(fm);
+ return fm;
+}
+
+/*tex
+
+ Process map file given by its name or map line contents. Items not beginning
+ with [+-=] flush default map file, if it has not yet been read. Leading
+ blanks and blanks immediately following [+-=] are ignored.
+
+*/
+
+void process_map_item(char *s, int type)
+{
+ char *p;
+ int mode;
+ if (*s == ' ') {
+ /*tex Ignore leading blanks: */
+ s++;
+ }
+ switch (*s) {
+ case '+':
+ /* +mapfile.map, +mapline: insert an entry, if it is not duplicate */
+ mode = FM_DUPIGNORE;
+ s++;
+ break;
+ case '=':
+ /* =mapfile.map, =mapline: try to replace an existing entry */
+ mode = FM_REPLACE;
+ s++;
+ break;
+ case '-':
+ /* -mapfile.map, -mapline: try to delete an entry */
+ mode = FM_DELETE;
+ s++;
+ break;
+ default:
+ /* like +, but also: flush the default map file name */
+ mode = FM_DUPIGNORE;
+ mitem->line = NULL;
+ }
+ if (*s == ' ') {
+ /*tex Ignore a blank after |[+-=]| */
+ s++;
+ }
+ /*tex The map item starts here. */
+ p = s;
+ switch (type) {
+ case MAPFILE:
+ /*tex Remove blank at the end. */
+ while (*p != '\0' && *p != ' ')
+ p++;
+ *p = '\0';
+ break;
+ case MAPLINE:
+ /*tex A blank at end is allowed. */
+ break;
+ default:
+ assert(0);
+ }
+ if (mitem->line != NULL) {
+ /*tex Read default map file first */
+ fm_read_info();
+ }
+ if (*s != '\0') {
+ /*tex Only if real item to process. */
+ mitem->mode = mode;
+ mitem->type = type;
+ mitem->line = s;
+ fm_read_info();
+ }
+}
+
+void pdfmapfile(int t)
+{
+ char *s = tokenlist_to_cstring(t, true, NULL);
+ process_map_item(s, MAPFILE);
+ free(s);
+}
+
+void pdfmapline(int t)
+{
+ char *s = tokenlist_to_cstring(t, true, NULL);
+ process_map_item(s, MAPLINE);
+ free(s);
+}
+
+void pdf_init_map_file(const char *map_name)
+{
+ assert(mitem == NULL);
+ mitem = xtalloc(1, mapitem);
+ mitem->mode = FM_DUPIGNORE;
+ mitem->type = MAPFILE;
+ mitem->line = xstrdup(map_name);
+}
+
+/*tex
+
+ An early check whether a font file exists. Search tree |ff_tree| is used in
+ 1st instance, as it may be faster than the |kpse_find_file|, and
+ |kpse_find_file| is called only once per font file name plus expansion
+ parameter. This might help keeping speed, if many \PDF\ pages with same fonts
+ are to be embedded (not that we deal with that fragile approach any longer in
+ \LUATEX).
+
+ The |ff_tree| contains only font files, which are actually needed, so this tree
+ typically is much smaller than the tfm_tree.
+
+*/
+
+ff_entry *check_ff_exist(char *ff_name, boolean is_tt)
+{
+ ff_entry *ff;
+ ff_entry tmp;
+ void **aa;
+ int callback_id;
+ char *filepath = NULL;
+ tmp.ff_name = ff_name;
+ ff = (ff_entry *) avl_find(ff_tree, &tmp);
+ if (ff == NULL) {
+ /*tex The name is not yet in the database. */
+ ff = new_ff_entry();
+ ff->ff_name = xstrdup(ff_name);
+ if (is_tt) {
+ callback_id = callback_defined(find_truetype_file_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "S->S", ff_name, &filepath);
+ if (filepath && strlen(filepath) == 0)
+ filepath = NULL;
+ ff->ff_path = filepath;
+ } else {
+ ff->ff_path = kpse_find_file(ff_name, kpse_truetype_format, 0);
+ }
+ } else {
+ callback_id = callback_defined(find_type1_file_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "S->S", ff_name, &filepath);
+ if (filepath && strlen(filepath) == 0)
+ filepath = NULL;
+ ff->ff_path = filepath;
+ } else {
+ ff->ff_path = kpse_find_file(ff_name, kpse_type1_format, 0);
+ }
+ }
+ aa = avl_probe(ff_tree, ff);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ }
+ return ff;
+}
+
+int is_subsetable(fm_entry * fm)
+{
+ assert(is_included(fm));
+ return is_subsetted(fm);
+}
+
+/*tex Cleaning up: */
+
+static void destroy_fm_entry_tfm(void *pa, void *pb)
+{
+ fm_entry *fm;
+ (void) pb;
+ fm = (fm_entry *) pa;
+ delete_fm_entry(fm);
+}
+
+static void destroy_ff_entry(void *pa, void *pb)
+{
+ ff_entry *ff;
+ (void) pb;
+ ff = (ff_entry *) pa;
+ delete_ff_entry(ff);
+}
+
+void fm_free(void)
+{
+ if (tfm_tree != NULL) {
+ avl_destroy(tfm_tree, destroy_fm_entry_tfm);
+ tfm_tree = NULL;
+ }
+ if (ff_tree != NULL) {
+ avl_destroy(ff_tree, destroy_ff_entry);
+ ff_tree = NULL;
+ }
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,715 +0,0 @@
-% mapfile.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <math.h>
-#include <kpathsea/c-auto.h>
-#include <kpathsea/c-memstr.h>
-#include <string.h>
-
-#define FM_BUF_SIZE 1024
-
-static FILE *fm_file;
-
-static unsigned char *fm_buffer = NULL;
-static int fm_size = 0;
-static int fm_curbyte = 0;
-
-#define fm_open(a) (fm_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-#define fm_read_file() readbinfile(fm_file,&fm_buffer,&fm_size)
-#define fm_close() xfclose(fm_file, cur_file_name)
-#define fm_getchar() fm_buffer[fm_curbyte++]
-#define fm_eof() (fm_curbyte>fm_size)
-#define is_cfg_comment(c) \
- (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
-
-typedef enum { FM_DUPIGNORE, FM_REPLACE, FM_DELETE } updatemode;
-
-typedef struct mitem {
- updatemode mode; /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE */
- maptype type; /* map file or map line */
- char *line; /* pointer to map file name or map line */
- int lineno; /* line number in map file */
-} mapitem;
-mapitem *mitem = NULL;
-
-#define read_field(r, q, buf) do { \
- q = buf; \
- while (*r != ' ' && *r != '<' && *r != '"' && *r != '\0') \
- *q++ = *r++; \
- *q = '\0'; \
- skip_char(r, ' '); \
-} while (0)
-
-#define set_field(F) do { \
- if (q > buf) \
- fm->F = xstrdup(buf); \
- if (*r == '\0') \
- goto done; \
-} while (0)
-
-fm_entry *new_fm_entry(void)
-{
- fm_entry *fm;
- fm = xtalloc(1, fm_entry);
- fm->tfm_name = NULL;
- fm->ps_name = NULL;
- fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
- fm->ff_name = NULL;
- fm->encname = NULL;
- fm->type = 0;
- fm->slant = 0;
- fm->extend = 1000;
- unset_slantset(fm);
- unset_extendset(fm);
- unset_inuse(fm);
- return fm;
-}
-
-void delete_fm_entry(fm_entry * fm)
-{
- xfree(fm->tfm_name);
- xfree(fm->ps_name);
- xfree(fm->ff_name);
- xfree(fm);
-}
-
-static ff_entry *new_ff_entry(void)
-{
- ff_entry *ff;
- ff = xtalloc(1, ff_entry);
- ff->ff_name = NULL;
- ff->ff_path = NULL;
- return ff;
-}
-
-static void delete_ff_entry(ff_entry * ff)
-{
- xfree(ff->ff_name);
- xfree(ff->ff_path);
- xfree(ff);
-}
-
-/**********************************************************************/
-
-static struct avl_table *tfm_tree = NULL;
-static struct avl_table *ff_tree = NULL;
-static struct avl_table *encname_tree = NULL;
-
-/* AVL sort fm_entry into tfm_tree by tfm_name */
-
-static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const fm_entry *) pa)->tfm_name,
- ((const fm_entry *) pb)->tfm_name);
-}
-
-/* AVL sort ff_entry into ff_tree by ff_name */
-
-static int comp_ff_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const ff_entry *) pa)->ff_name,
- ((const ff_entry *) pb)->ff_name);
-}
-
-static void create_avl_trees(void)
-{
- assert(tfm_tree == NULL);
- tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator);
- assert(tfm_tree != NULL);
- assert(ff_tree == NULL);
- ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator);
- assert(ff_tree != NULL);
- assert(encname_tree == NULL);
- encname_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
- assert(encname_tree != NULL);
-}
-
-int avl_do_entry(fm_entry * fm, int mode)
-{
- fm_entry *p;
- void *a;
- void **aa;
- int delete_new = 0;
- if (tfm_tree == NULL)
- create_avl_trees();
- p = (fm_entry *) avl_find(tfm_tree, fm);
- if (p != NULL) {
- switch (mode) {
- case FM_DUPIGNORE:
- formatted_warning("map file", "entry for '%s' already exists, duplicates ignored", fm->tfm_name);
- delete_new = 1;
- break;
- case FM_REPLACE:
- case FM_DELETE:
- if (is_inuse(p)) {
- formatted_warning("map file", "entry for '%s' has been used, replace/delete not allowed", fm->tfm_name);
- delete_new = 1;
- } else {
- a = avl_delete(tfm_tree, p);
- assert(a != NULL);
- delete_fm_entry(p);
- }
- break;
- default:
- assert(0);
- }
- }
- if ((mode == FM_DUPIGNORE || mode == FM_REPLACE) && delete_new == 0) {
- aa = avl_probe(tfm_tree, fm);
- assert(aa != NULL);
- } else
- delete_new = 1;
- return delete_new;
-}
-
-/* add the encoding name to an AVL tree. this has nothing to do with writeenc.c */
-
-static char *add_encname(char *s)
-{
- char *p;
- void **aa;
- assert(s != NULL);
- assert(encname_tree != NULL);
- if ((p = (char *) avl_find(encname_tree, s)) == NULL) { /* encoding name not yet registered */
- p = xstrdup(s);
- aa = avl_probe(encname_tree, p);
- assert(aa != NULL);
- }
- return p;
-}
-
-/**********************************************************************/
-/* consistency check for map entry, with warn flag */
-
-static int check_fm_entry(fm_entry * fm, boolean warn)
-{
- int a = 0;
- assert(fm != NULL);
-
- if (is_fontfile(fm) && !is_included(fm)) {
- if (warn)
- formatted_warning("map file",
- "ambiguous entry for '%s': font file present but not included, "
- "will be treated as font file not present", fm->tfm_name);
- xfree(fm->ff_name);
- /* do not set variable |a| as this entry will be still accepted */
- }
-
- /* if both ps_name and font file are missing, drop this entry */
- if (fm->ps_name == NULL && !is_fontfile(fm)) {
- if (warn)
- formatted_warning("map file", "invalid entry for '%s': both ps_name and font file missing", fm->tfm_name);
- a += 1;
- }
-
- /* TrueType fonts cannot be reencoded without subsetting */
- if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) {
- if (warn)
- formatted_warning("map file", "invalid entry for '%s': only subsetted TrueType font can be reencoded", fm->tfm_name);
- a += 2;
- }
-
- /* the value of SlantFont and ExtendFont must be reasonable */
- if (fm->slant < FONT_SLANT_MIN || fm->slant > FONT_SLANT_MAX) {
- if (warn)
- formatted_warning("map file", "invalid entry for '%s': value '%g' is to large for SlantFont",
- fm->tfm_name, fm->slant / 1000.0);
- a += 8;
- }
- if (fm->extend < FONT_EXTEND_MIN || fm->extend > FONT_EXTEND_MAX) {
- if (warn)
- formatted_warning("map file", "invalid entry for '%s': value '%g' is too large for ExtendFont",
- fm->tfm_name, fm->extend / 1000.0);
- a += 16;
- }
-
- return a;
-}
-
-/**********************************************************************/
-/* returns the font number if s is one of the 14 std. font names, -1 otherwise; speed-trimmed. */
-
-int check_std_t1font(char *s)
-{
- static const char *std_t1font_names[] = {
- "Courier", /* 0:7 */
- "Courier-Bold", /* 1:12 */
- "Courier-Oblique", /* 2:15 */
- "Courier-BoldOblique", /* 3:19 */
- "Helvetica", /* 4:9 */
- "Helvetica-Bold", /* 5:14 */
- "Helvetica-Oblique", /* 6:17 */
- "Helvetica-BoldOblique", /* 7:21 */
- "Symbol", /* 8:6 */
- "Times-Roman", /* 9:11 */
- "Times-Bold", /* 10:10 */
- "Times-Italic", /* 11:12 */
- "Times-BoldItalic", /* 12:16 */
- "ZapfDingbats" /* 13:12 */
- };
- static const int index[] =
- { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, -1,
- 3, -1, 7
- };
- size_t n;
- int k = -1;
- assert(s != NULL);
- n = strlen(s);
- if (n > 21)
- return -1;
- if (n == 12) { /* three names have length 12 */
- switch (*s) {
- case 'C':
- k = 1; /* Courier-Bold */
- break;
- case 'T':
- k = 11; /* Times-Italic */
- break;
- case 'Z':
- k = 13; /* ZapfDingbats */
- break;
- default:
- return -1;
- }
- } else
- k = index[n];
- if (k > -1 && !strcmp(std_t1font_names[k], s))
- return k;
- return -1;
-}
-
-/**********************************************************************/
-
-static void fm_scan_line(void)
-{
- int a, b, c, j, u = 0, v = 0;
- char cc;
- float d;
- fm_entry *fm;
- char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
- char *p, *q, *s;
- char *r = NULL;
- switch (mitem->type) {
- case MAPFILE:
- p = fm_line;
- while (!fm_eof()) {
- if (fm_curbyte == fm_size) {
- fm_curbyte++;
- cc = 10;
- } else {
- cc = (char) fm_getchar();
- }
- append_char_to_buf(cc, p, fm_line, FM_BUF_SIZE);
- if (cc == 10)
- break;
- }
- *(--p) = '\0';
- r = fm_line;
- break;
- case MAPLINE:
- r = mitem->line; /* work on string from makecstring() */
- break;
- default:
- assert(0);
- }
- if (*r == '\0' || is_cfg_comment(*r))
- return;
- fm = new_fm_entry();
- read_field(r, q, buf);
- set_field(tfm_name);
- if (!isdigit((unsigned char)*r)) { /* 2nd field ps_name may not start with a digit */
- read_field(r, q, buf);
- set_field(ps_name);
- }
- if (isdigit((unsigned char)*r)) { /* font descriptor /Flags given? */
- for (s = r; isdigit((unsigned char)*s); s++);
- if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') { /* not e. g. 8r.enc */
- fm->fd_flags = atoi(r);
- while (isdigit((unsigned char)*r))
- r++;
- }
- }
- while (1) { /* loop through "specials", encoding, font file */
- skip_char(r, ' ');
- switch (*r) {
- case '\0':
- goto done;
- case '"': /* opening quote */
- r++;
- u = v = 0;
- do {
- skip_char(r, ' ');
- if (sscanf(r, "%f %n", &d, &j) > 0) {
- s = r + j; /* jump behind number, eat also blanks, if any */
- if (*(s - 1) == 'E' || *(s - 1) == 'e')
- s--; /* e. g. 0.5ExtendFont: %f = 0.5E */
- if (str_prefix(s, "SlantFont")) {
- d *= (float) 1000.0; /* correct rounding also for neg. numbers */
- fm->slant = (int) (d > 0 ? d + 0.5 : d - 0.5);
- set_slantset(fm);
- r = s + strlen("SlantFont");
- } else if (str_prefix(s, "ExtendFont")) {
- d *= (float) 1000.0;
- fm->extend = (int) (d > 0 ? d + 0.5 : d - 0.5);
- set_extendset(fm);
- r = s + strlen("ExtendFont");
- } else { /* unknown name */
- for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++); /* jump over name */
- c = *r; /* remember char for temporary end of string */
- *r = '\0';
- formatted_warning("map file", "invalid entry for '%s': unknown name '%s' ignored", fm->tfm_name, s);
- *r = (char) c;
- }
- } else
- for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
- }
- while (*r == ' ');
- if (*r == '"') /* closing quote */
- r++;
- else {
- formatted_warning("map file", "invalid entry for '%s': closing quote missing", fm->tfm_name);
- goto bad_line;
- }
- break;
- case 'P': /* handle cases for sub fonts like 'PidEid=3,1' */
- formatted_warning("map file", "invalid entry for '%s': subfonts are not supported", fm->tfm_name);
- goto bad_line;
- break;
- default: /* encoding or font file specification */
- a = b = 0;
- if (*r == '<') {
- a = *r++;
- if (*r == '<' || *r == '[')
- b = *r++;
- }
- read_field(r, q, buf);
- /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
- if (strlen(buf) > 4 && strcasecmp(strend(buf) - 4, ".enc") == 0) {
- fm->encname = add_encname(buf);
- u = v = 0; /* u, v used if intervening blank: "<< foo" */
- } else if (strlen(buf) > 0) { /* file name given */
- /* font file, formats:
- * subsetting: '<cmr10.pfa'
- * no subsetting: '<<cmr10.pfa'
- * no embedding: 'cmr10.pfa'
- */
- if (a == '<' || u == '<') {
- set_included(fm);
- if ((a == '<' && b == 0) || (a == 0 && v == 0))
- set_subsetted(fm);
- /* otherwise b == '<' (or '[') => no subsetting */
- }
- set_field(ff_name);
- u = v = 0;
- } else {
- u = a;
- v = b;
- }
- }
- }
- done:
- if (fm->ps_name != NULL && (check_std_t1font(fm->ps_name) >= 0))
- set_std_t1font(fm);
- if (is_fontfile(fm) && strlen(fm_fontfile(fm)) > 3) {
- if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 0)
- set_truetype(fm);
- else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttc") == 0)
- set_truetype(fm);
- else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".otf") == 0)
- set_opentype(fm);
- else
- set_type1(fm);
- } else
- set_type1(fm); /* assume a builtin font is Type1 */
- if (check_fm_entry(fm, true) != 0)
- goto bad_line;
- /*
- Until here the map line has been completely scanned without errors;
- fm points to a valid, freshly filled-out fm_entry structure.
- Now follows the actual work of registering/deleting.
- */
- if (avl_do_entry(fm, mitem->mode) == 0)
- return;
- bad_line:
- delete_fm_entry(fm);
-}
-
-/**********************************************************************/
-
-static void fm_read_info(void)
-{
- int callback_id;
- int file_opened = 0;
-
- if (tfm_tree == NULL)
- create_avl_trees();
- if (mitem->line == NULL) /* nothing to do */
- return;
- mitem->lineno = 1;
- switch (mitem->type) {
- case MAPFILE:
- xfree(fm_buffer);
- fm_curbyte = 0;
- fm_size = 0;
- cur_file_name = luatex_find_file(mitem->line, find_map_file_callback);
- if (cur_file_name) {
- callback_id = callback_defined(read_map_file_callback);
- if (callback_id > 0) {
- if (run_callback(callback_id, "S->bSd", cur_file_name,
- &file_opened, &fm_buffer, &fm_size)) {
- if (file_opened) {
- if (fm_size > 0) {
- report_start_file(filetype_map,cur_file_name);
- while (!fm_eof()) {
- fm_scan_line();
- mitem->lineno++;
- }
- report_stop_file(filetype_map);
- fm_file = NULL;
- }
- } else {
- formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
- }
- } else {
- formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
- }
- } else {
- if (!fm_open(cur_file_name)) {
- formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
- } else {
- fm_read_file();
- report_start_file(filetype_map,cur_file_name);
- while (!fm_eof()) {
- fm_scan_line();
- mitem->lineno++;
- }
- fm_close();
- report_stop_file(filetype_map);
- fm_file = NULL;
- }
- }
- cur_file_name = NULL;
- }
- break;
- case MAPLINE:
- cur_file_name = NULL;
- fm_scan_line();
- break;
- default:
- assert(0);
- }
- mitem->line = NULL; /* done with this line */
- cur_file_name = NULL;
- return;
-}
-
-/**********************************************************************/
-
-fm_entry *getfontmap(char *tfm_name)
-{
- fm_entry *fm;
- fm_entry tmp;
- if (tfm_name == NULL) /* wide, lua loaded fonts may not have a name */
- return NULL;
- if (tfm_tree == NULL)
- fm_read_info(); /* only to read default map file */
- tmp.tfm_name = tfm_name; /* Look up for tfmname */
- fm = (fm_entry *) avl_find(tfm_tree, &tmp);
- if (fm == NULL)
- return NULL;
- set_inuse(fm);
- return fm;
-}
-
-/**********************************************************************/
-/*
- * Process map file given by its name or map line contents. Items not
- * beginning with [+-=] flush default map file, if it has not yet been
- * read. Leading blanks and blanks immediately following [+-=] are
- * ignored.
- */
-
-void process_map_item(char *s, int type)
-{
- char *p;
- int mode;
- if (*s == ' ')
- s++; /* ignore leading blank */
- switch (*s) {
- case '+': /* +mapfile.map, +mapline */
- mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
- s++;
- break;
- case '=': /* =mapfile.map, =mapline */
- mode = FM_REPLACE; /* try to replace earlier entry */
- s++;
- break;
- case '-': /* -mapfile.map, -mapline */
- mode = FM_DELETE; /* try to delete entry */
- s++;
- break;
- default:
- mode = FM_DUPIGNORE; /* like +, but also: */
- mitem->line = NULL; /* flush default map file name */
- }
- if (*s == ' ')
- s++; /* ignore blank after [+-=] */
- p = s; /* map item starts here */
- switch (type) {
- case MAPFILE: /* remove blank at end */
- while (*p != '\0' && *p != ' ')
- p++;
- *p = '\0';
- break;
- case MAPLINE: /* blank at end allowed */
- break;
- default:
- assert(0);
- }
- if (mitem->line != NULL) /* read default map file first */
- fm_read_info();
- if (*s != '\0') { /* only if real item to process */
- mitem->mode = mode;
- mitem->type = type;
- mitem->line = s;
- fm_read_info();
- }
-}
-
-void pdfmapfile(int t)
-{
- char *s = tokenlist_to_cstring(t, true, NULL);
- process_map_item(s, MAPFILE);
- free(s);
-}
-
-void pdfmapline(int t)
-{
- char *s = tokenlist_to_cstring(t, true, NULL);
- process_map_item(s, MAPLINE);
- free(s);
-}
-
-void pdf_init_map_file(const char *map_name)
-{
- assert(mitem == NULL);
- mitem = xtalloc(1, mapitem);
- mitem->mode = FM_DUPIGNORE;
- mitem->type = MAPFILE;
- mitem->line = xstrdup(map_name);
-}
-
-/**********************************************************************/
-/*
- * Early check whether a font file exists. Search tree ff_tree is used
- * in 1st instance, as it may be faster than the kpse_find_file(), and
- * kpse_find_file() is called only once per font file name + expansion
- * parameter. This might help keeping speed, if many PDF pages with
- * same fonts are to be embedded.
- *
- * The ff_tree contains only font files, which are actually needed,
- * so this tree typically is much smaller than the tfm_tree.
- */
-
-ff_entry *check_ff_exist(char *ff_name, boolean is_tt)
-{
- ff_entry *ff;
- ff_entry tmp;
- void **aa;
- int callback_id;
- char *filepath = NULL;
-
- assert(ff_name != NULL);
- tmp.ff_name = ff_name;
- ff = (ff_entry *) avl_find(ff_tree, &tmp);
- if (ff == NULL) { /* not yet in database */
- ff = new_ff_entry();
- ff->ff_name = xstrdup(ff_name);
- if (is_tt) {
- callback_id = callback_defined(find_truetype_file_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "S->S", ff_name, &filepath);
- if (filepath && strlen(filepath) == 0)
- filepath = NULL;
- ff->ff_path = filepath;
- } else {
- ff->ff_path = kpse_find_file(ff_name, kpse_truetype_format, 0);
- }
- } else {
- callback_id = callback_defined(find_type1_file_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "S->S", ff_name, &filepath);
- if (filepath && strlen(filepath) == 0)
- filepath = NULL;
- ff->ff_path = filepath;
- } else {
- ff->ff_path = kpse_find_file(ff_name, kpse_type1_format, 0);
- }
- }
- aa = avl_probe(ff_tree, ff);
- assert(aa != NULL);
- }
- return ff;
-}
-
-/**********************************************************************/
-
-int is_subsetable(fm_entry * fm)
-{
- assert(is_included(fm));
- return is_subsetted(fm);
-}
-
-/**********************************************************************/
-/* cleaning up... */
-
-static void destroy_fm_entry_tfm(void *pa, void *pb)
-{
- fm_entry *fm;
- (void) pb;
- fm = (fm_entry *) pa;
- delete_fm_entry(fm);
-}
-
-static void destroy_ff_entry(void *pa, void *pb)
-{
- ff_entry *ff;
- (void) pb;
- ff = (ff_entry *) pa;
- delete_ff_entry(ff);
-}
-
-void fm_free(void)
-{
- if (tfm_tree != NULL) {
- avl_destroy(tfm_tree, destroy_fm_entry_tfm);
- tfm_tree = NULL;
- }
- if (ff_tree != NULL) {
- avl_destroy(ff_tree, destroy_ff_entry);
- ff_tree = NULL;
- }
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/pkin.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/pkin.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/pkin.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,424 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2008 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+This implementation of readchar() uses parts of the program dvips written by
+Tomas Rokicki--the inventor of the pkformat--(loadfont.c, download.c and
+unpack.c). Dvips in turn is derived from pktype. Pktype(TeX) is described in debt
+in ``The PKtype processor'', which is available as pktype.weave as part of the
+METAFONTware. What was needed to implement readchar() is rearranged in pkfile.c
+to get more modularity in the style of MODULA2.
+
+May 1997: Eric Delaunay <delaunay at lix.polytechnique.fr> reports a problem with
+huge fonts (greater than 1008 DPI). The code for handling PK characters in
+`extended format' was wrongly derived from dvips. Made some minor improvements
+regarding error handling.
+
+At some point Piet Tutelaers <rcpt at urc.tue.nl> redesigned the code and later Han
+The Thanh <thanh at fi.muni.cz> again modified the code to suite \PDFTEX. Of course
+in \LUATEX\ again we adapted the code.
+
+*/
+
+#include "ptexlib.h"
+
+typedef short shalfword;
+
+/*tex
+
+Now we have some routines to get stuff from the \PK\ file. |pkbyte| returns the
+next byte from the \PK\ file.
+
+*/
+
+static shalfword pkbyte(void)
+{
+ register shalfword i;
+ i = t3_getchar();
+ if (t3_eof())
+ normal_error("type 3","unexpected EOF in pk file");
+ return (i);
+}
+
+static int pkduo(void)
+{
+ register int i;
+ i = pkbyte();
+ if (i > 127)
+ i -= 256;
+ i = i * 256 + pkbyte();
+ return (i);
+}
+
+static int pktrio(void)
+{
+ register int i;
+ i = pkbyte();
+ if (i > 127)
+ i -= 256;
+ i = i * 256 + pkbyte();
+ i = i * 256 + pkbyte();
+ return (i);
+}
+
+static int pkquad(void)
+{
+ register int i;
+ i = pkbyte();
+ if (i > 127)
+ i -= 256;
+ i = i * 256 + pkbyte();
+ i = i * 256 + pkbyte();
+ i = i * 256 + pkbyte();
+ return (i);
+}
+
+/*tex
+
+ The next part is devoted to unpacking the character data. We need procedures
+ to get a nybble, bit, and packed word from the packed data structure.
+
+*/
+
+static halfword inputbyte, flagbyte;
+static halfword bitweight;
+static halfword dynf;
+static halfword repeatcount;
+
+static shalfword getnyb(void)
+{
+ halfword temp;
+ if (bitweight == 0) {
+ bitweight = 16;
+ inputbyte = pkbyte();
+ temp = inputbyte >> 4;
+ } else {
+ bitweight = 0;
+ temp = inputbyte & 15;
+ }
+ return (shalfword) (temp);
+}
+
+static boolean getbit(void)
+{
+ bitweight >>= 1;
+ if (bitweight == 0) {
+ inputbyte = pkbyte();
+ bitweight = 128;
+ }
+ return (inputbyte & bitweight);
+}
+
+static halfword(*realfunc) (void);
+long pk_remainder;
+static halfword handlehuge(halfword i, halfword k);
+
+static halfword pkpackednum(void)
+{
+ register halfword i, j;
+ i = getnyb();
+ if (i == 0) {
+ do {
+ j = getnyb();
+ i++;
+ } while (!(j != 0));
+ if (i > 3) {
+ /*tex
+ Hm, we got a huge count! We {\em fake} it by giving an
+ artificially large repeat count.
+ */
+ return (handlehuge(i, j));
+ } else {
+ while (i > 0) {
+ j = j * 16 + getnyb();
+ i--;
+ }
+ return (j - 15 + (13 - dynf) * 16 + dynf);
+ }
+ } else if (i <= dynf)
+ return (i);
+ else if (i < 14)
+ return ((i - dynf - 1) * 16 + getnyb() + dynf + 1);
+ else {
+ if (i == 14)
+ repeatcount = pkpackednum();
+ else
+ repeatcount = 1;
+ return ((*realfunc) ());
+ }
+}
+
+static halfword rest(void)
+{
+ halfword i;
+ if (pk_remainder < 0) {
+ pk_remainder = -pk_remainder;
+ return (0);
+ } else if (pk_remainder > 0) {
+ if (pk_remainder > 4000) {
+ pk_remainder = 4000 - pk_remainder;
+ return (4000);
+ } else {
+ i = (halfword) pk_remainder;
+ pk_remainder = 0;
+ realfunc = pkpackednum;
+ return (i);
+ }
+ } else {
+ normal_error("type 3","pk issue that shouldn't happen");
+ return 0;
+ }
+}
+
+static halfword handlehuge(halfword i, halfword k)
+{
+ register long j = k;
+ while (i) {
+ j = (j << 4L) + getnyb();
+ i--;
+ }
+ pk_remainder = j - 15 + (13 - dynf) * 16 + dynf;
+ realfunc = rest;
+ return (rest());
+}
+
+
+/*tex
+
+ And now we have our unpacking routine.
+
+*/
+
+static halfword gpower[17] = {
+ 0, 1, 3, 7, 15, 31, 63, 127,
+ 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
+ 65535
+};
+
+static void unpack(chardesc * cd)
+{
+ register int i, j;
+ register halfword word, wordweight;
+ halfword *raster;
+ shalfword rowsleft;
+ boolean turnon;
+ shalfword hbit;
+ halfword count;
+ shalfword wordwidth;
+ wordwidth = (shalfword) ((cd->cwidth + 15) / 16);
+ i = (int) (2 * cd->cheight * (long) wordwidth);
+ if (i <= 0)
+ i = 2;
+ if (i > cd->rastersize) {
+ xfree(cd->raster);
+ cd->rastersize = i;
+ cd->raster = xtalloc((unsigned) cd->rastersize, halfword);
+ }
+ raster = cd->raster;
+ realfunc = pkpackednum;
+ dynf = flagbyte / 16;
+ turnon = flagbyte & 8;
+ if (dynf == 14) {
+ bitweight = 0;
+ for (i = 1; i <= cd->cheight; i++) {
+ word = 0;
+ wordweight = 32768;
+ for (j = 1; j <= cd->cwidth; j++) {
+ if (getbit())
+ word += wordweight;
+ wordweight >>= 1;
+ if (wordweight == 0) {
+ *raster++ = word;
+ word = 0;
+ wordweight = 32768;
+ }
+ }
+ if (wordweight != 32768)
+ *raster++ = word;
+ }
+ } else {
+ rowsleft = (shalfword) cd->cheight;
+ hbit = (shalfword) cd->cwidth;
+ repeatcount = 0;
+ wordweight = 16;
+ word = 0;
+ bitweight = 0;
+ while (rowsleft > 0) {
+ count = (*realfunc) ();
+ while (count != 0) {
+ if ((count < wordweight) && (count < hbit)) {
+ if (turnon)
+ word += gpower[wordweight] - gpower[wordweight - count];
+ hbit = (shalfword) (hbit - count);
+ wordweight -= count;
+ count = 0;
+ } else if ((count >= hbit) && (hbit <= wordweight)) {
+ if (turnon)
+ word += gpower[wordweight] - gpower[wordweight - hbit];
+ *raster++ = word;
+ for (i = 1; i <= repeatcount; i++) {
+ for (j = 1; j <= wordwidth; j++) {
+ *raster = *(raster - wordwidth);
+ raster++;
+ }
+ }
+ rowsleft = (shalfword) (rowsleft - repeatcount - 1);
+ repeatcount = 0;
+ word = 0;
+ wordweight = 16;
+ count -= hbit;
+ hbit = (shalfword) cd->cwidth;
+ } else {
+ if (turnon)
+ word += gpower[wordweight];
+ *raster++ = word;
+ word = 0;
+ count -= wordweight;
+ hbit = (shalfword) (hbit - wordweight);
+ wordweight = 16;
+ }
+ }
+ turnon = !turnon;
+ }
+ if ((rowsleft != 0) || ((int) hbit != cd->cwidth))
+ normal_error("type 3","error while unpacking, more bits than required");
+ }
+}
+
+/*tex
+
+ The main routine check pk preamble if necessary. It reads the character
+ definition of character |c| into |cd| if available or return |FALSE|
+ otherwise.
+
+*/
+
+int readchar(boolean check_preamble, chardesc * cd)
+{
+ register shalfword i;
+ register int k;
+ register int length = 0;
+ /*tex Check the preamble of the \PK\ file. */
+ if (check_preamble) {
+ if (pkbyte() != 247)
+ normal_error("type 3","bad pk file, expected pre");
+ if (pkbyte() != 89)
+ normal_error("type 3","bad version of pk file");
+ /*tex The creator of the file: */
+ for (i = pkbyte(); i > 0; i--)
+ (void) pkbyte();
+ /*tex The design size: */
+ (void) pkquad();
+ /*tex The checksum: */
+ k = pkquad();
+ /*tex The hppp: */
+ k = pkquad();
+ /*tex The vppp: */
+ k = pkquad();
+ }
+ /*tex
+ We also skip to the desired character definition.
+ */
+ while ((flagbyte = pkbyte()) != 245) {
+ if (flagbyte < 240) {
+ switch (flagbyte & 7) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ length = (flagbyte & 7) * 256 + pkbyte() - 3;
+ cd->charcode = pkbyte();
+ /*tex The \TFM\ width: */
+ (void) pktrio();
+ /*tex the pixel width: */
+ cd->xescape = pkbyte();
+ cd->cwidth = pkbyte();
+ cd->cheight = pkbyte();
+ cd->xoff = pkbyte();
+ cd->yoff = pkbyte();
+ if (cd->xoff > 127)
+ cd->xoff -= 256;
+ if (cd->yoff > 127)
+ cd->yoff -= 256;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ length = (int) ((flagbyte & 3) * 65536L + pkbyte() * 256L);
+ length = (int) (length + pkbyte() - 4L);
+ cd->charcode = pkbyte();
+ /*tex The \TFM\ width: */
+ (void) pktrio();
+ /*tex the pixel width: */
+ cd->xescape = pkduo();
+ cd->cwidth = pkduo();
+ cd->cheight = pkduo();
+ cd->xoff = pkduo();
+ cd->yoff = pkduo();
+ break;
+ case 7:
+ length = (int) (pkquad() - 9L);
+ cd->charcode = pkquad();
+ /*tex The \TFM\ width: */
+ (void) pkquad();
+ /*tex the pixel width: */
+ cd->xescape = pkquad();
+ k = pkquad();
+ cd->cwidth = pkquad();
+ cd->cheight = pkquad();
+ cd->xoff = pkquad();
+ cd->yoff = pkquad();
+ }
+ if (length <= 0)
+ formatted_error("type 3","pk packet length '%i' too small", (int) length);
+ unpack(cd);
+ return 1;
+ } else {
+ k = 0;
+ switch (flagbyte) {
+ case 243:
+ k = pkbyte();
+ if (k > 127)
+ k -= 256;
+ case 242:
+ k = k * 256 + pkbyte();
+ case 241:
+ k = k * 256 + pkbyte();
+ case 240:
+ k = k * 256 + pkbyte();
+ while (k-- > 0)
+ i = pkbyte();
+ break;
+ case 244:
+ k = pkquad();
+ break;
+ case 246:
+ break;
+ default:
+ formatted_error("type 3","unexpected pk command '%i'", (int) flagbyte);
+ }
+ }
+ }
+ /*tex Character not found: */
+ return 0;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/pkin.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/pkin.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/pkin.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,426 +0,0 @@
-% pkin.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@
-NAME
-
-pkin.c - implementation of readchar()
-
-DESCRIPTION
-
-This implementation of readchar() uses parts of the program dvips
-written by Tomas Rokicki--the inventor of the pkformat--(loadfont.c,
-download.c and unpack.c). Dvips in turn is derived from pktype.
-Pktype(TeX) is described in debt in ``The PKtype processor'',
-which is available as pktype.weave as part of the METAFONTware.
-What was needed to implement readchar() is rearranged in pkfile.c to
-get more modularity in the style of MODULA2.
-
-BUGFIXES
-
-May 1997: Eric Delaunay <delaunay@@lix.polytechnique.fr> reports a
-problem with huge fonts (greater than 1008 DPI). The code for
-handling PK characters in `extended format' was wrongly derived
-from dvips. Made some minor improvements regarding error handling.
-
-REDESIGN
-
-Piet Tutelaers <rcpt@@urc.tue.nl>
-
-Modified for use with pdftex by Han The Thanh <thanh@@fi.muni.cz>.
-
- at c
-
-
-#include "ptexlib.h"
-
-typedef short shalfword;
-
-@
-Now we have some routines to get stuff from the pk file. pkbyte returns
-the next byte from the pk file.
-
- at c
-static shalfword pkbyte(void)
-{
- register shalfword i;
- i = t3_getchar();
- if (t3_eof())
- normal_error("type 3","unexpected EOF in pk file");
- return (i);
-}
-
-static int pkduo(void)
-{
- register int i;
-
- i = pkbyte();
- if (i > 127)
- i -= 256;
- i = i * 256 + pkbyte();
- return (i);
-}
-
-static int pktrio(void)
-{
- register int i;
-
- i = pkbyte();
- if (i > 127)
- i -= 256;
- i = i * 256 + pkbyte();
- i = i * 256 + pkbyte();
- return (i);
-}
-
-static int pkquad(void)
-{
- register int i;
-
- i = pkbyte();
- if (i > 127)
- i -= 256;
- i = i * 256 + pkbyte();
- i = i * 256 + pkbyte();
- i = i * 256 + pkbyte();
- return (i);
-}
-
-
-
-@ The next part is devoted to unpacking the character data.
-
-@ We need procedures to get a nybble, bit, and packed word from the
-packed data structure.
-
- at c
-static halfword inputbyte, flagbyte;
-static halfword bitweight;
-static halfword dynf;
-static halfword repeatcount;
-
-static shalfword getnyb(void)
-{
- halfword temp;
- if (bitweight == 0) {
- bitweight = 16;
- inputbyte = pkbyte();
- temp = inputbyte >> 4;
- } else {
- bitweight = 0;
- temp = inputbyte & 15;
- }
- return (shalfword) (temp);
-}
-
-static boolean getbit(void)
-{
- bitweight >>= 1;
- if (bitweight == 0) {
- inputbyte = pkbyte();
- bitweight = 128;
- }
- return (inputbyte & bitweight);
-}
-
-static halfword(*realfunc) (void);
-long pk_remainder;
-static halfword handlehuge(halfword i, halfword k);
-
-static halfword pkpackednum(void)
-{
- register halfword i, j;
- i = getnyb();
- if (i == 0) {
- do {
- j = getnyb();
- i++;
- } while (!(j != 0));
- if (i > 3) {
-/*
- Damn, we got a huge count! We {\it fake} it by giving an artificially
- large repeat count.
- */
- return (handlehuge(i, j));
- } else {
- while (i > 0) {
- j = j * 16 + getnyb();
- i--;
- }
- return (j - 15 + (13 - dynf) * 16 + dynf);
- }
- } else if (i <= dynf)
- return (i);
- else if (i < 14)
- return ((i - dynf - 1) * 16 + getnyb() + dynf + 1);
- else {
- if (i == 14)
- repeatcount = pkpackednum();
- else
- repeatcount = 1;
-#ifdef DEBUG
- printf("[%d]", (int) repeatcount);
-#endif
- return ((*realfunc) ());
- }
-}
-
-static halfword rest(void)
-{
- halfword i;
-
- if (pk_remainder < 0) {
- pk_remainder = -pk_remainder;
- return (0);
- } else if (pk_remainder > 0) {
- if (pk_remainder > 4000) {
- pk_remainder = 4000 - pk_remainder;
- return (4000);
- } else {
- i = (halfword) pk_remainder;
- pk_remainder = 0;
- realfunc = pkpackednum;
- return (i);
- }
- } else {
- normal_error("type 3","pk issue that shouldn't happen");
- return 0;
- /*NOTREACHED*/}
-}
-
-static halfword handlehuge(halfword i, halfword k)
-{
- register long j = k;
-
- while (i) {
- j = (j << 4L) + getnyb();
- i--;
- }
- pk_remainder = j - 15 + (13 - dynf) * 16 + dynf;
- realfunc = rest;
- return (rest());
-}
-
-
-@ And now we have our unpacking routine.
-
- at c
-static halfword gpower[17] = { 0, 1, 3, 7, 15, 31, 63, 127,
- 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535
-};
-
-static void unpack(chardesc * cd)
-{
- register int i, j;
- register halfword word, wordweight;
- halfword *raster;
- shalfword rowsleft;
- boolean turnon;
- shalfword hbit;
- halfword count;
- shalfword wordwidth;
-
- wordwidth = (shalfword) ((cd->cwidth + 15) / 16);
- i = (int) (2 * cd->cheight * (long) wordwidth);
- if (i <= 0)
- i = 2;
- if (i > cd->rastersize) {
- xfree(cd->raster);
- cd->rastersize = i;
- cd->raster = xtalloc((unsigned) cd->rastersize, halfword);
- }
- raster = cd->raster;
- realfunc = pkpackednum;
- dynf = flagbyte / 16;
- turnon = flagbyte & 8;
- if (dynf == 14) {
- bitweight = 0;
- for (i = 1; i <= cd->cheight; i++) {
- word = 0;
- wordweight = 32768;
- for (j = 1; j <= cd->cwidth; j++) {
- if (getbit())
- word += wordweight;
- wordweight >>= 1;
- if (wordweight == 0) {
- *raster++ = word;
- word = 0;
- wordweight = 32768;
- }
- }
- if (wordweight != 32768)
- *raster++ = word;
- }
- } else {
- rowsleft = (shalfword) cd->cheight;
- hbit = (shalfword) cd->cwidth;
- repeatcount = 0;
- wordweight = 16;
- word = 0;
- bitweight = 0;
- while (rowsleft > 0) {
- count = (*realfunc) ();
- while (count != 0) {
- if ((count < wordweight) && (count < hbit)) {
- if (turnon)
- word += gpower[wordweight] - gpower[wordweight - count];
- hbit = (shalfword) (hbit - count);
- wordweight -= count;
- count = 0;
- } else if ((count >= hbit) && (hbit <= wordweight)) {
- if (turnon)
- word += gpower[wordweight] - gpower[wordweight - hbit];
- *raster++ = word;
- for (i = 1; i <= repeatcount; i++) {
- for (j = 1; j <= wordwidth; j++) {
- *raster = *(raster - wordwidth);
- raster++;
- }
- }
- rowsleft = (shalfword) (rowsleft - repeatcount - 1);
- repeatcount = 0;
- word = 0;
- wordweight = 16;
- count -= hbit;
- hbit = (shalfword) cd->cwidth;
- } else {
- if (turnon)
- word += gpower[wordweight];
- *raster++ = word;
- word = 0;
- count -= wordweight;
- hbit = (shalfword) (hbit - wordweight);
- wordweight = 16;
- }
- }
- turnon = !turnon;
- }
- if ((rowsleft != 0) || ((int) hbit != cd->cwidth))
- normal_error("type 3","error while unpacking, more bits than required");
- }
-}
-
-@
-|readchar()|: the main routine
-check pk preamble if necessary,
-Reads the character definition of character `c' into `cd' if available,
-return FALSE (0) otherwise.
-
- at c
-int readchar(boolean check_preamble, chardesc * cd)
-{
- register shalfword i;
- register int k;
- register int length = 0;
-
-/*
- Check the preamble of the pkfile
- */
- if (check_preamble) {
- if (pkbyte() != 247)
- normal_error("type 3","bad pk file, expected pre");
- if (pkbyte() != 89)
- normal_error("type 3","bad version of pk file");
- for (i = pkbyte(); i > 0; i--) /* creator of pkfile */
- (void) pkbyte();
- (void) pkquad(); /* design size */
- k = pkquad(); /* checksum */
- k = pkquad(); /* hppp */
- k = pkquad(); /* vppp */
- }
-/*
- Now we skip to the desired character definition
- */
- while ((flagbyte = pkbyte()) != 245) {
- if (flagbyte < 240) {
- switch (flagbyte & 7) {
- case 0:
- case 1:
- case 2:
- case 3:
- length = (flagbyte & 7) * 256 + pkbyte() - 3;
- cd->charcode = pkbyte();
- (void) pktrio(); /* TFMwidth */
- cd->xescape = pkbyte(); /* pixel width */
- cd->cwidth = pkbyte();
- cd->cheight = pkbyte();
- cd->xoff = pkbyte();
- cd->yoff = pkbyte();
- if (cd->xoff > 127)
- cd->xoff -= 256;
- if (cd->yoff > 127)
- cd->yoff -= 256;
- break;
- case 4:
- case 5:
- case 6:
- length = (int) ((flagbyte & 3) * 65536L + pkbyte() * 256L);
- length = (int) (length + pkbyte() - 4L);
- cd->charcode = pkbyte();
- (void) pktrio(); /* TFMwidth */
- cd->xescape = pkduo(); /* pixelwidth */
- cd->cwidth = pkduo();
- cd->cheight = pkduo();
- cd->xoff = pkduo();
- cd->yoff = pkduo();
- break;
- case 7:
- length = (int) (pkquad() - 9L);
- cd->charcode = pkquad();
- (void) pkquad(); /* TFMwidth */
- cd->xescape = pkquad(); /* pixelwidth */
- k = pkquad();
- cd->cwidth = pkquad();
- cd->cheight = pkquad();
- cd->xoff = pkquad();
- cd->yoff = pkquad();
- }
- if (length <= 0)
- formatted_error("type 3","pk packet length '%i' too small", (int) length);
- unpack(cd);
- return 1;
- } else {
- k = 0;
- switch (flagbyte) {
- case 243:
- k = pkbyte();
- if (k > 127)
- k -= 256;
- case 242:
- k = k * 256 + pkbyte();
- case 241:
- k = k * 256 + pkbyte();
- case 240:
- k = k * 256 + pkbyte();
- while (k-- > 0)
- i = pkbyte();
- break;
- case 244:
- k = pkquad();
- break;
- case 246:
- break;
- default:
- formatted_error("type 3","unexpected pk command '%i'", (int) flagbyte);
- }
- }
- }
- return 0; /* character not found */
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,392 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
+Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+ The code below is originally based on |dvipdfmx-0.13.2c|:
+
+*/
+
+#include "ptexlib.h"
+
+#if HAVE_CONFIG_H
+# include <w2c/config.h>
+#endif
+
+#include <string.h>
+
+#include "font/sfnt.h"
+
+/*tex
+
+ Types:
+
+ \starttabulate[||||]
+ \NC \type {true} \NC 0x74727565 \NC (Mac) TrueType \NC \NR
+ \NC \type {typ1| \NC 0x74797031 \NC (Mac) PostScript font housed in a sfnt wrapper \NC \NR
+ \NC \NC 0x00010000 \NC TrueType (Win)/OpenType \NC \NR
+ \NC \type {OTTO} \NC \NC PostScript CFF font with OpenType wrapper \NC \NR
+ \NC \type {ttcf} \NC \NC TrueType Collection \NC \NR
+ \stoptabulate
+
+*/
+
+#define SFNT_TRUETYPE 0x00010000UL
+#define SFNT_MAC_TRUE 0x74727565UL
+#define SFNT_OPENTYPE 0x00010000UL
+#define SFNT_POSTSCRIPT 0x4f54544fUL
+#define SFNT_TTC 0x74746366UL
+
+sfnt *sfnt_open(unsigned char *buff, int buflen)
+{
+ sfnt *sfont;
+ ULONG type;
+ sfont = xmalloc(sizeof(sfnt));
+ sfont->loc = 0;
+ sfont->buffer = buff;
+ sfont->buflen = buflen;
+ type = sfnt_get_ulong(sfont);
+ if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) {
+ sfont->type = SFNT_TYPE_TRUETYPE;
+ } else if (type == SFNT_OPENTYPE) {
+ sfont->type = SFNT_TYPE_OPENTYPE;
+ } else if (type == SFNT_POSTSCRIPT) {
+ sfont->type = SFNT_TYPE_POSTSCRIPT;
+ } else if (type == SFNT_TTC) {
+ sfont->type = SFNT_TYPE_TTC;
+ }
+ sfont->loc = 0;
+ sfont->directory = NULL;
+ return sfont;
+}
+
+static void release_directory(struct sfnt_table_directory *td)
+{
+ long i;
+ if (td) {
+ if (td->tables) {
+ for (i = 0; i < td->num_tables; i++) {
+ if (td->tables[i].data)
+ RELEASE(td->tables[i].data);
+ }
+ RELEASE(td->tables);
+ }
+ if (td->flags)
+ RELEASE(td->flags);
+ RELEASE(td);
+ }
+ return;
+}
+
+void sfnt_close(sfnt * sfont)
+{
+ if (sfont) {
+ if (sfont->directory)
+ release_directory(sfont->directory);
+ RELEASE(sfont);
+ }
+ return;
+}
+
+int put_big_endian(void *s, LONG q, int n)
+{
+ int i;
+ char *p;
+ p = (char *) s;
+ for (i = n - 1; i >= 0; i--) {
+ p[i] = (char) (q & 0xff);
+ q >>= 8;
+ }
+ return n;
+}
+
+/*tex
+
+ Convert four-byte number to big endianess in a machine independent way.
+
+*/
+
+static void convert_tag(char *tag, unsigned long u_tag)
+{
+ int i;
+ for (i = 3; i >= 0; i--) {
+ tag[i] = (char) (u_tag % 256);
+ u_tag /= 256;
+ }
+ return;
+}
+
+/*tex
+
+ Computes the max power of $|2 <= n$:
+
+*/
+
+static unsigned max2floor(unsigned n)
+{
+ int val = 1;
+ while (n > 1) {
+ n /= 2;
+ val *= 2;
+ }
+ return (unsigned) val;
+}
+
+/*tex
+
+ Computes the log2 of the max power of $2 <= n$
+
+*/
+
+static unsigned log2floor(unsigned n)
+{
+ unsigned val = 0;
+ while (n > 1) {
+ n /= 2;
+ val++;
+ }
+ return val;
+}
+
+static ULONG sfnt_calc_checksum(void *data, ULONG length)
+{
+ ULONG chksum = 0;
+ BYTE *p, *endptr;
+ ULONG count = 0;
+ p = (BYTE *) data;
+ endptr = p + length;
+ while (p < endptr) {
+ chksum = chksum + (ULONG) (p[0] << (8 * (3 - count)));
+ count = ((count + 1) & 3);
+ p++;
+ }
+ return chksum;
+}
+
+static int find_table_index(struct sfnt_table_directory *td, const char *tag)
+{
+ int idx;
+ if (!td)
+ return -1;
+ for (idx = 0; idx < td->num_tables; idx++) {
+ if (!memcmp(td->tables[idx].tag, tag, 4))
+ return idx;
+ }
+ return -1;
+}
+
+void sfnt_set_table(sfnt * sfont, const char *tag, void *data, ULONG length)
+{
+ struct sfnt_table_directory *td;
+ int idx;
+ td = sfont->directory;
+ idx = find_table_index(td, tag);
+ if (idx < 0) {
+ idx = td->num_tables;
+ td->num_tables++;
+ td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table);
+ memcpy(td->tables[idx].tag, tag, 4);
+ }
+ td->tables[idx].check_sum = sfnt_calc_checksum(data, length);
+ td->tables[idx].offset = 0L;
+ td->tables[idx].length = length;
+ td->tables[idx].data = data;
+ return;
+}
+
+ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
+{
+ ULONG length;
+ struct sfnt_table_directory *td;
+ int idx;
+ td = sfont->directory;
+ idx = find_table_index(td, tag);
+ if (idx < 0)
+ length = 0;
+ else {
+ length = td->tables[idx].length;
+ }
+ return length;
+}
+
+ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
+{
+ ULONG offset;
+ struct sfnt_table_directory *td;
+ int idx;
+ td = sfont->directory;
+ idx = find_table_index(td, tag);
+ if (idx < 0)
+ offset = 0;
+ else {
+ offset = td->tables[idx].offset;
+ }
+ return offset;
+}
+
+ULONG sfnt_locate_table(sfnt * sfont, const char *tag)
+{
+ ULONG offset;
+ offset = sfnt_find_table_pos(sfont, tag);
+ if (offset == 0)
+ normal_error("ttf","sfnt table not found");
+ sfnt_seek_set(sfont, (long) offset);
+ return offset;
+}
+
+int sfnt_read_table_directory(sfnt * sfont, ULONG offset)
+{
+ struct sfnt_table_directory *td;
+ unsigned long i, u_tag;
+ if (sfont->directory)
+ release_directory(sfont->directory);
+ sfont->directory = td = NEW(1, struct sfnt_table_directory);
+ sfnt_seek_set(sfont, (long) offset);
+ td->version = sfnt_get_ulong(sfont);
+ td->num_tables = sfnt_get_ushort(sfont);
+ td->search_range = sfnt_get_ushort(sfont);
+ td->entry_selector = sfnt_get_ushort(sfont);
+ td->range_shift = sfnt_get_ushort(sfont);
+ td->flags = NEW(td->num_tables, char);
+ td->tables = NEW(td->num_tables, struct sfnt_table);
+ for (i = 0; i < td->num_tables; i++) {
+ u_tag = sfnt_get_ulong(sfont);
+ convert_tag(td->tables[i].tag, u_tag);
+ td->tables[i].check_sum = sfnt_get_ulong(sfont);
+ td->tables[i].offset = sfnt_get_ulong(sfont);
+ td->tables[i].length = sfnt_get_ulong(sfont);
+ td->tables[i].data = NULL;
+ td->flags[i] = 0;
+ }
+ td->num_kept_tables = 0;
+ return 0;
+}
+
+int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
+{
+ struct sfnt_table_directory *td;
+ int idx;
+ td = sfont->directory;
+ idx = find_table_index(td, tag);
+ if (idx < 0) {
+ if (must_exist)
+ return -1;
+ } else {
+ td->flags[idx] |= SFNT_TABLE_REQUIRED;
+ td->num_kept_tables++;
+ }
+ return 0;
+}
+
+/*tex
+
+ All tables begin on four byte boundries, and pad any remaining space between
+ tables with zeros. Entries in the Table Directory must be sorted in ascending
+ order by tag The head table contains checksum of the whole font file. To
+ compute: first set it to 0, sum the entire font as ULONG, then store
+ 0xB1B0AFBA - sum.
+
+*/
+
+# include "font/luatexfont.h"
+# undef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+# define STREAM_COMPRESS
+
+static unsigned char wbuf[1024], padbytes[4] = { 0, 0, 0, 0 };
+
+pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
+{
+ pdf_obj *stream;
+ struct sfnt_table_directory *td;
+ long offset, nb_read, length;
+ int i, sr;
+ char *p;
+ stream = pdf_new_stream(STREAM_COMPRESS);
+ td = sfont->directory;
+ p = (char *) wbuf;
+ p += sfnt_put_ulong(p, (LONG) td->version);
+ p += sfnt_put_ushort(p, td->num_kept_tables);
+ sr = (int) (max2floor(td->num_kept_tables) * 16);
+ p += sfnt_put_ushort(p, sr);
+ p += sfnt_put_ushort(p, log2floor(td->num_kept_tables));
+ p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr);
+ pdf_add_stream(stream, wbuf, 12);
+ /*tex Compute start of actual tables (after headers). */
+ offset = 12 + 16 * td->num_kept_tables;
+ for (i = 0; i < td->num_tables; i++) {
+ /*tex This table must exist in |FontFile|: */
+ if (td->flags[i] & SFNT_TABLE_REQUIRED) {
+ if ((offset % 4) != 0) {
+ offset += 4 - (offset % 4);
+ }
+ p = (char *) wbuf;
+ memcpy(p, td->tables[i].tag, 4);
+ p += 4;
+ p += sfnt_put_ulong(p, (LONG) td->tables[i].check_sum);
+ p += sfnt_put_ulong(p, offset);
+ p += sfnt_put_ulong(p, (LONG) td->tables[i].length);
+ pdf_add_stream(stream, wbuf, 16);
+ offset = (long) (offset + (long) td->tables[i].length);
+ }
+ }
+ offset = 12 + 16 * td->num_kept_tables;
+ for (i = 0; i < td->num_tables; i++) {
+ if (td->flags[i] & SFNT_TABLE_REQUIRED) {
+ if ((offset % 4) != 0) {
+ length = 4 - (offset % 4);
+ pdf_add_stream(stream, padbytes, length);
+ offset += length;
+ }
+ if (!td->tables[i].data) {
+ if (!sfont->buffer) {
+ pdf_release_obj(stream);
+ normal_error("ttf","file not opened or already closed");
+ return NULL;
+ }
+ length = (long) td->tables[i].length;
+ sfnt_seek_set(sfont, (long) td->tables[i].offset);
+ while (length > 0) {
+ nb_read = sfnt_read(wbuf, (int) MIN(length, 1024), sfont);
+ if (nb_read < 0) {
+ pdf_release_obj(stream);
+ normal_error("ttf","reading file failed");
+ return NULL;
+ } else if (nb_read > 0) {
+ pdf_add_stream(stream, wbuf, nb_read);
+ }
+ length -= nb_read;
+ }
+ } else {
+ pdf_add_stream(stream,
+ (unsigned char *) td->tables[i].data,
+ (long) td->tables[i].length);
+ RELEASE(td->tables[i].data);
+ td->tables[i].data = NULL;
+ }
+ /*tex Set offset for next table. */
+ offset = (long) (offset + (long) td->tables[i].length);
+ }
+ }
+ return stream;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,462 +0,0 @@
-% sfnt.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ Based on dvipdfmx-0.13.2c
- at c
-
-
-#include "ptexlib.h"
-
-#if HAVE_CONFIG_H
-# include <w2c/config.h>
-#endif /* |HAVE_CONFIG_H_| */
-
-#include <string.h>
-
-#include "font/sfnt.h"
-
-@ type:
-
- `true' (0x74727565): TrueType (Mac)
-
- `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper
-
- 0x00010000: TrueType (Win)/OpenType
-
- `OTTO': PostScript CFF font with OpenType wrapper
-
- `ttcf': TrueType Collection
-
- at c
-#define SFNT_TRUETYPE 0x00010000UL
-#define SFNT_MAC_TRUE 0x74727565UL
-#define SFNT_OPENTYPE 0x00010000UL
-#define SFNT_POSTSCRIPT 0x4f54544fUL
-#define SFNT_TTC 0x74746366UL
-
-sfnt *sfnt_open(unsigned char *buff, int buflen)
-{
- sfnt *sfont;
- ULONG type;
-
- sfont = xmalloc(sizeof(sfnt));
- sfont->loc = 0;
- sfont->buffer = buff;
- sfont->buflen = buflen;
-
- type = sfnt_get_ulong(sfont);
-
- if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) {
- sfont->type = SFNT_TYPE_TRUETYPE;
- } else if (type == SFNT_OPENTYPE) {
- sfont->type = SFNT_TYPE_OPENTYPE;
- } else if (type == SFNT_POSTSCRIPT) {
- sfont->type = SFNT_TYPE_POSTSCRIPT;
- } else if (type == SFNT_TTC) {
- sfont->type = SFNT_TYPE_TTC;
- }
-
- sfont->loc = 0;
- sfont->directory = NULL;
- return sfont;
-}
-
-static void release_directory(struct sfnt_table_directory *td)
-{
- long i;
-
- if (td) {
- if (td->tables) {
- for (i = 0; i < td->num_tables; i++) {
- if (td->tables[i].data)
- RELEASE(td->tables[i].data);
- }
- RELEASE(td->tables);
- }
- if (td->flags)
- RELEASE(td->flags);
- RELEASE(td);
- }
-
- return;
-}
-
-void sfnt_close(sfnt * sfont)
-{
-
- if (sfont) {
- if (sfont->directory)
- release_directory(sfont->directory);
- RELEASE(sfont);
- }
-
- return;
-}
-
-int put_big_endian(void *s, LONG q, int n)
-{
- int i;
- char *p;
-
- p = (char *) s;
- for (i = n - 1; i >= 0; i--) {
- p[i] = (char) (q & 0xff);
- q >>= 8;
- }
-
- return n;
-}
-
-@ Convert four-byte number to big endianess in a machine independent way.
-
- at c
-static void convert_tag(char *tag, unsigned long u_tag)
-{
- int i;
-
- for (i = 3; i >= 0; i--) {
- tag[i] = (char) (u_tag % 256);
- u_tag /= 256;
- }
-
- return;
-}
-
-
-@ Computes the max power of 2 <= n
-
- at c
-static unsigned max2floor(unsigned n)
-{
- int val = 1;
-
- while (n > 1) {
- n /= 2;
- val *= 2;
- }
-
- return (unsigned) val;
-}
-
-
-@ Computes the log2 of the max power of 2 <= n
-
- at c
-static unsigned log2floor(unsigned n)
-{
- unsigned val = 0;
-
- while (n > 1) {
- n /= 2;
- val++;
- }
-
- return val;
-}
-
-@ @c
-static ULONG sfnt_calc_checksum(void *data, ULONG length)
-{
- ULONG chksum = 0;
- BYTE *p, *endptr;
- ULONG count = 0;
-
- p = (BYTE *) data;
- endptr = p + length;
- while (p < endptr) {
- chksum = chksum + (ULONG) (p[0] << (8 * (3 - count)));
- count = ((count + 1) & 3);
- p++;
- }
-
- return chksum;
-}
-
-@ @c
-static int find_table_index(struct sfnt_table_directory *td, const char *tag)
-{
- int idx;
-
- if (!td)
- return -1;
-
- for (idx = 0; idx < td->num_tables; idx++) {
- if (!memcmp(td->tables[idx].tag, tag, 4))
- return idx;
- }
-
- return -1;
-}
-
-@ @c
-void sfnt_set_table(sfnt * sfont, const char *tag, void *data, ULONG length)
-{
- struct sfnt_table_directory *td;
- int idx;
-
- ASSERT(sfont);
-
- td = sfont->directory;
- idx = find_table_index(td, tag);
-
- if (idx < 0) {
- idx = td->num_tables;
- td->num_tables++;
- td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table);
- memcpy(td->tables[idx].tag, tag, 4);
- }
-
- td->tables[idx].check_sum = sfnt_calc_checksum(data, length);
- td->tables[idx].offset = 0L;
- td->tables[idx].length = length;
- td->tables[idx].data = data;
-
- return;
-}
-
-@ @c
-ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
-{
- ULONG length;
- struct sfnt_table_directory *td;
- int idx;
-
- ASSERT(sfont && tag);
-
- td = sfont->directory;
- idx = find_table_index(td, tag);
- if (idx < 0)
- length = 0;
- else {
- length = td->tables[idx].length;
- }
-
- return length;
-}
-
-@ @c
-ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
-{
- ULONG offset;
- struct sfnt_table_directory *td;
- int idx;
-
- ASSERT(sfont && tag);
-
- td = sfont->directory;
- idx = find_table_index(td, tag);
- if (idx < 0)
- offset = 0;
- else {
- offset = td->tables[idx].offset;
- }
-
- return offset;
-}
-
-@ @c
-ULONG sfnt_locate_table(sfnt * sfont, const char *tag)
-{
- ULONG offset;
-
- ASSERT(sfont && tag);
-
- offset = sfnt_find_table_pos(sfont, tag);
- if (offset == 0)
- normal_error("ttf","sfnt table not found");
-
- sfnt_seek_set(sfont, (long) offset);
-
- return offset;
-}
-
-@ @c
-int sfnt_read_table_directory(sfnt * sfont, ULONG offset)
-{
- struct sfnt_table_directory *td;
- unsigned long i, u_tag;
-
- ASSERT(sfont);
-
- if (sfont->directory)
- release_directory(sfont->directory);
- sfont->directory = td = NEW(1, struct sfnt_table_directory);
-
- ASSERT(sfont->buffer);
- sfnt_seek_set(sfont, (long) offset);
-
- td->version = sfnt_get_ulong(sfont);
- td->num_tables = sfnt_get_ushort(sfont);
- td->search_range = sfnt_get_ushort(sfont);
- td->entry_selector = sfnt_get_ushort(sfont);
- td->range_shift = sfnt_get_ushort(sfont);
-
- td->flags = NEW(td->num_tables, char);
- td->tables = NEW(td->num_tables, struct sfnt_table);
-
- for (i = 0; i < td->num_tables; i++) {
- u_tag = sfnt_get_ulong(sfont);
-
- convert_tag(td->tables[i].tag, u_tag);
- td->tables[i].check_sum = sfnt_get_ulong(sfont);
- td->tables[i].offset = sfnt_get_ulong(sfont);
- td->tables[i].length = sfnt_get_ulong(sfont);
- td->tables[i].data = NULL;
-
- td->flags[i] = 0;
- }
-
- td->num_kept_tables = 0;
-
- return 0;
-}
-
-@ @c
-int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
-{
- struct sfnt_table_directory *td;
- int idx;
-
- ASSERT(sfont && sfont->directory);
-
- td = sfont->directory;
- idx = find_table_index(td, tag);
- if (idx < 0) {
- if (must_exist)
- return -1;
- } else {
- td->flags[idx] |= SFNT_TABLE_REQUIRED;
- td->num_kept_tables++;
- }
-
- return 0;
-}
-
-
-
-@ All tables begin on four byte boundries, and pad any remaining space
- between tables with zeros
-
- Entries in the Table Directory must be sorted in ascending order by tag
-
- The head table contains checksum of the whole font file.
- To compute: first set it to 0, sum the entire font as ULONG,
- then store 0xB1B0AFBA - sum.
-
- at c
-# include "font/luatexfont.h"
-# undef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-# define STREAM_COMPRESS
-
-static unsigned char wbuf[1024], padbytes[4] = { 0, 0, 0, 0 };
-
-pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
-{
- pdf_obj *stream;
- struct sfnt_table_directory *td;
- long offset, nb_read, length;
- int i, sr;
- char *p;
-
- ASSERT(sfont && sfont->directory);
-
- stream = pdf_new_stream(STREAM_COMPRESS);
-
- td = sfont->directory;
-
- /* Header */
- p = (char *) wbuf;
- p += sfnt_put_ulong(p, (LONG) td->version);
- p += sfnt_put_ushort(p, td->num_kept_tables);
- sr = (int) (max2floor(td->num_kept_tables) * 16);
- p += sfnt_put_ushort(p, sr);
- p += sfnt_put_ushort(p, log2floor(td->num_kept_tables));
- p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr);
-
- pdf_add_stream(stream, wbuf, 12);
-
- /*
- Compute start of actual tables (after headers).
- */
- offset = 12 + 16 * td->num_kept_tables;
- for (i = 0; i < td->num_tables; i++) {
- /* This table must exist in FontFile */
- if (td->flags[i] & SFNT_TABLE_REQUIRED) {
- if ((offset % 4) != 0) {
- offset += 4 - (offset % 4);
- }
-
- p = (char *) wbuf;
- memcpy(p, td->tables[i].tag, 4);
- p += 4;
- p += sfnt_put_ulong(p, (LONG) td->tables[i].check_sum);
- p += sfnt_put_ulong(p, offset);
- p += sfnt_put_ulong(p, (LONG) td->tables[i].length);
- pdf_add_stream(stream, wbuf, 16);
-
- offset = (long) (offset + (long) td->tables[i].length);
- }
- }
-
- offset = 12 + 16 * td->num_kept_tables;
- for (i = 0; i < td->num_tables; i++) {
- if (td->flags[i] & SFNT_TABLE_REQUIRED) {
- if ((offset % 4) != 0) {
- length = 4 - (offset % 4);
- pdf_add_stream(stream, padbytes, length);
- offset += length;
- }
- if (!td->tables[i].data) {
- if (!sfont->buffer)
- {
- pdf_release_obj(stream);
- normal_error("ttf","file not opened or already closed");
- return NULL;
- }
-
- length = (long) td->tables[i].length;
- sfnt_seek_set(sfont, (long) td->tables[i].offset);
- while (length > 0) {
- nb_read = sfnt_read(wbuf, (int) MIN(length, 1024), sfont);
- if (nb_read < 0) {
- pdf_release_obj(stream);
- normal_error("ttf","reading file failed");
- return NULL;
- } else if (nb_read > 0) {
- pdf_add_stream(stream, wbuf, nb_read);
- }
- length -= nb_read;
- }
- } else {
- pdf_add_stream(stream,
- (unsigned char *) td->tables[i].data,
- (long) td->tables[i].length);
- RELEASE(td->tables[i].data);
- td->tables[i].data = NULL;
- }
- /* Set offset for next table */
- offset = (long) (offset + (long) td->tables[i].length);
- }
- }
-
- return stream;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/subfont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/subfont.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/subfont.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,277 @@
+/*
+
+Copyright 2005-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2008 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <string.h>
+
+static struct avl_table *sfd_tree = NULL;
+
+static unsigned char *sfd_buffer = NULL;
+static int sfd_size = 0;
+static int sfd_curbyte = 0;
+
+#define SFD_BUF_SIZE SMALL_BUF_SIZE
+
+#define sfd_close() xfclose(sfd_file, cur_file_name)
+#define sfd_open(a) (sfd_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+
+#define sfd_read_file() readbinfile(sfd_file,&sfd_buffer,&sfd_size)
+#define sfd_getchar() sfd_buffer[sfd_curbyte++]
+#define sfd_eof() (sfd_curbyte>=sfd_size)
+
+static FILE *sfd_file;
+static char sfd_line[SFD_BUF_SIZE];
+
+static subfont_entry *new_subfont_entry(void)
+{
+ int i;
+ subfont_entry *subfont;
+ subfont = xtalloc(1, subfont_entry);
+ subfont->infix = NULL;
+ for (i = 0; i < 256; ++i) {
+ /*tex Unassigned: */
+ subfont->charcodes[i] = -1;
+ }
+ subfont->next = NULL;
+ return subfont;
+}
+
+static sfd_entry *new_sfd_entry(void)
+{
+ sfd_entry *sfd;
+ sfd = xtalloc(1, sfd_entry);
+ sfd->name = NULL;
+ sfd->subfont = NULL;
+ return sfd;
+}
+
+static void destroy_sfd_entry(void *pa, void *pb)
+{
+ subfont_entry *p, *q;
+ sfd_entry *sfd;
+ sfd = (sfd_entry *) pa;
+ (void) pb;
+ p = sfd->subfont;
+ while (p != NULL) {
+ q = p->next;
+ xfree(p->infix);
+ xfree(p);
+ p = q;
+ }
+ xfree(sfd->name);
+}
+
+static int comp_sfd_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const sfd_entry *) pa)->name, ((const sfd_entry *) pb)->name);
+}
+
+void sfd_free(void)
+{
+ if (sfd_tree != NULL)
+ avl_destroy(sfd_tree, destroy_sfd_entry);
+}
+
+static void sfd_getline(boolean expect_eof)
+{
+ char *p;
+ char c;
+ restart:
+ if (sfd_eof()) {
+ if (expect_eof) {
+ if (*sfd_line == '#')
+ *sfd_line = 10;
+ return;
+ } else
+ normal_error("sub font","unexpected end of file");
+ }
+ p = sfd_line;
+ do {
+ c = (char) sfd_getchar();
+ append_char_to_buf(c, p, sfd_line, SFD_BUF_SIZE);
+ } while (c != 10 && !sfd_eof());
+ append_eol(p, sfd_line, SFD_BUF_SIZE);
+ if (p - sfd_line < 2 || *sfd_line == '#')
+ goto restart;
+}
+
+static sfd_entry *read_sfd(char *sfd_name)
+{
+ void **aa;
+ sfd_entry *sfd, tmp_sfd;
+ subfont_entry *sf;
+ char buf[SMALL_BUF_SIZE], *p;
+ long int i, j, k;
+ int n;
+ int callback_id = 0;
+ int file_opened = 0;
+ /*tex Check whether this |sfd| has been read: */
+ tmp_sfd.name = sfd_name;
+ if (sfd_tree == NULL) {
+ sfd_tree = avl_create(comp_sfd_entry, NULL, &avl_xallocator);
+ assert(sfd_tree != NULL);
+ }
+ sfd = (sfd_entry *) avl_find(sfd_tree, &tmp_sfd);
+ if (sfd != NULL)
+ return sfd;
+ xfree(sfd_buffer);
+ sfd_curbyte = 0;
+ sfd_size = 0;
+ cur_file_name = luatex_find_file(sfd_name, find_sfd_file_callback);
+ if (cur_file_name) {
+ callback_id = callback_defined(read_sfd_file_callback);
+ if (callback_id > 0) {
+ if (!(run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &sfd_buffer, &sfd_size) &&
+ file_opened && sfd_size > 0)) {
+ formatted_warning("ttf font","cannot open SFD file for reading '%s'", cur_file_name);
+ cur_file_name = NULL;
+ return NULL;
+ }
+ } else {
+ if (!sfd_open(cur_file_name)) {
+ formatted_warning("ttf font", "cannot open SFD file for reading '%s'", cur_file_name);
+ cur_file_name = NULL;
+ return NULL;
+ }
+ sfd_read_file();
+ sfd_close();
+ }
+ }
+ tex_printf("{");
+ tex_printf("%s", cur_file_name);
+ sfd = new_sfd_entry();
+ sfd->name = xstrdup(sfd_name);
+ while (!sfd_eof()) {
+ sfd_getline(true);
+ if (*sfd_line == 10) {
+ /*tex An empty line indicates |EOF|. */
+ break;
+ }
+ sf = new_subfont_entry();
+ sf->next = sfd->subfont;
+ sfd->subfont = sf;
+ sscanf(sfd_line, "%s %n", buf, &n);
+ sf->infix = xstrdup(buf);
+ /*tex Skip to the next word: */
+ p = sfd_line + n;
+ k = 0;
+ read_ranges:
+ for (;;) {
+ if (*p == '\\') {
+ /*tex Continue on the next line: */
+ sfd_getline(false);
+ p = sfd_line;
+ goto read_ranges;
+ } else if (*p == 0) {
+ /*tex End of subfont. */
+ break;
+ }
+ if (sscanf(p, " %li %n", &i, &n) == 0)
+ formatted_error("sub font","invalid token: %s", p);
+ p += n;
+ if (*p == ':') {
+ /*tex Variant: offset */
+ k = i;
+ p++;
+ } else if (*p == '_') {
+ /*tex Variant: range */
+ if (sscanf(p + 1, " %li %n", &j, &n) == 0)
+ formatted_error("sub font","invalid token: %s", p);
+ if (i > j || k + (j - i) > 255)
+ formatted_error("sub font","invalid range: %s", p);
+ while (i <= j)
+ sf->charcodes[k++] = i++;
+ p += n + 1;
+ } else {
+ /*tex Variant: codepoint */
+ sf->charcodes[k++] = i;
+ }
+ }
+ }
+ tex_printf("}");
+ aa = avl_probe(sfd_tree, sfd);
+ assert(aa != NULL);
+ return sfd;
+}
+
+boolean handle_subfont_fm(fm_entry * fm, int mode)
+{
+ size_t l;
+ char *p, *q, *r;
+ sfd_entry *sfd;
+ subfont_entry *sf;
+ fm_entry *fm2;
+ char buf[SMALL_BUF_SIZE];
+ assert(fm->tfm_name != NULL);
+ p = fm->tfm_name;
+ /*tex Search for the first |@|. */
+ q = strchr(p, '@');
+ if (q == NULL)
+ return false;
+ /*tex Search for the second |@|: */
+ r = strchr(q + 1, '@');
+ if (r == NULL)
+ return false;
+ /*tex Check if prefix or sfd name is empty or the second |@| is not the last char yet. */
+ if (q <= p || r <= q + 1 || r - p != (int) strlen(p) - 1) {
+ return false;
+ }
+ /*tex The length of sfd name: */
+ l = (size_t) (r - (q + 1));
+ strncpy(buf, q + 1, l);
+ buf[l] = 0;
+ check_buf(strlen(buf) + 4, SMALL_BUF_SIZE);
+ strcat(buf, ".sfd");
+ sfd = read_sfd(buf);
+ if (sfd == NULL)
+ return false;
+ /*tex At this point we know fm is a subfont. */
+ set_subfont(fm);
+ xfree(fm->ps_name);
+ /*tex Set default values for |Pid| and |Eid|: */
+ if (fm->pid == -1) {
+ fm->pid = 3;
+ fm->eid = 1;
+ }
+ /*tex Calculate the length of base tfm name (prefix). */
+ l = (size_t) (q - p);
+ for (sf = sfd->subfont; sf != NULL; sf = sf->next) {
+ strncpy(buf, p, l);
+ buf[l] = 0;
+ strcat(buf, sf->infix);
+ fm2 = new_fm_entry();
+ fm2->tfm_name = xstrdup(buf);
+ fm2->ff_name = xstrdup(fm->ff_name);
+ fm2->type = fm->type;
+ fm2->pid = fm->pid;
+ fm2->eid = fm->eid;
+ fm2->subfont = sf;
+ /*tex Try to insert the entry. */
+ if (avl_do_entry(fm2, mode) != 0) {
+ /*tex And delete it if we failed. */
+ delete_fm_entry(fm2);
+ }
+ }
+ delete_fm_entry(fm);
+ return true;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/subfont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/subfont.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/subfont.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,265 +0,0 @@
-% subfont.w
-%
-% Copyright 2005-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <string.h>
-
-@ @c
-static struct avl_table *sfd_tree = NULL;
-
-static unsigned char *sfd_buffer = NULL;
-static int sfd_size = 0;
-static int sfd_curbyte = 0;
-
-#define SFD_BUF_SIZE SMALL_BUF_SIZE
-
-#define sfd_close() xfclose(sfd_file, cur_file_name)
-#define sfd_open(a) (sfd_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-
-#define sfd_read_file() readbinfile(sfd_file,&sfd_buffer,&sfd_size)
-#define sfd_getchar() sfd_buffer[sfd_curbyte++]
-#define sfd_eof() (sfd_curbyte>=sfd_size)
-
-
-static FILE *sfd_file;
-static char sfd_line[SFD_BUF_SIZE];
-
-static subfont_entry *new_subfont_entry(void)
-{
- int i;
- subfont_entry *subfont;
- subfont = xtalloc(1, subfont_entry);
- subfont->infix = NULL;
- for (i = 0; i < 256; ++i)
- subfont->charcodes[i] = -1; /* unassigned */
- subfont->next = NULL;
- return subfont;
-}
-
-static sfd_entry *new_sfd_entry(void)
-{
- sfd_entry *sfd;
- sfd = xtalloc(1, sfd_entry);
- sfd->name = NULL;
- sfd->subfont = NULL;
- return sfd;
-}
-
-static void destroy_sfd_entry(void *pa, void *pb)
-{
- subfont_entry *p, *q;
- sfd_entry *sfd;
- sfd = (sfd_entry *) pa;
- (void) pb;
- p = sfd->subfont;
- while (p != NULL) {
- q = p->next;
- xfree(p->infix);
- xfree(p);
- p = q;
- }
- xfree(sfd->name);
-}
-
-static int comp_sfd_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const sfd_entry *) pa)->name,
- ((const sfd_entry *) pb)->name);
-}
-
-void sfd_free(void)
-{
- if (sfd_tree != NULL)
- avl_destroy(sfd_tree, destroy_sfd_entry);
-}
-
-static void sfd_getline(boolean expect_eof)
-{
- char *p;
- char c;
- restart:
- if (sfd_eof()) {
- if (expect_eof) {
- if (*sfd_line == '#')
- *sfd_line = 10;
- return;
- } else
- normal_error("sub font","unexpected end of file");
- }
- p = sfd_line;
- do {
- c = (char) sfd_getchar();
- append_char_to_buf(c, p, sfd_line, SFD_BUF_SIZE);
- } while (c != 10 && !sfd_eof());
- append_eol(p, sfd_line, SFD_BUF_SIZE);
- if (p - sfd_line < 2 || *sfd_line == '#')
- goto restart;
-}
-
-@ @c
-static sfd_entry *read_sfd(char *sfd_name)
-{
- void **aa;
- sfd_entry *sfd, tmp_sfd;
- subfont_entry *sf;
-
- char buf[SMALL_BUF_SIZE], *p;
- long int i, j, k;
- int n;
- int callback_id = 0;
- int file_opened = 0;
- /* check whether this sfd has been read */
- tmp_sfd.name = sfd_name;
- if (sfd_tree == NULL) {
- sfd_tree = avl_create(comp_sfd_entry, NULL, &avl_xallocator);
- assert(sfd_tree != NULL);
- }
- sfd = (sfd_entry *) avl_find(sfd_tree, &tmp_sfd);
- if (sfd != NULL)
- return sfd;
- xfree(sfd_buffer);
- sfd_curbyte = 0;
- sfd_size = 0;
-
- cur_file_name = luatex_find_file(sfd_name, find_sfd_file_callback);
- if (cur_file_name) {
- callback_id = callback_defined(read_sfd_file_callback);
- if (callback_id > 0) {
- if (!(run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &sfd_buffer, &sfd_size) &&
- file_opened && sfd_size > 0)) {
- formatted_warning("ttf font","cannot open SFD file for reading '%s'", cur_file_name);
- cur_file_name = NULL;
- return NULL;
- }
- } else {
- if (!sfd_open(cur_file_name)) {
- formatted_warning("ttf font", "cannot open SFD file for reading '%s'", cur_file_name);
- cur_file_name = NULL;
- return NULL;
- }
- sfd_read_file();
- sfd_close();
- }
- }
- tex_printf("{");
- tex_printf("%s", cur_file_name);
- sfd = new_sfd_entry();
- sfd->name = xstrdup(sfd_name);
- while (!sfd_eof()) {
- sfd_getline(true);
- if (*sfd_line == 10) /* empty line indicating eof */
- break;
- sf = new_subfont_entry();
- sf->next = sfd->subfont;
- sfd->subfont = sf;
- sscanf(sfd_line, "%s %n", buf, &n);
- sf->infix = xstrdup(buf);
- p = sfd_line + n; /* skip to the next word */
- k = 0;
- read_ranges:
- for (;;) {
- if (*p == '\\') { /* continue on next line */
- sfd_getline(false);
- p = sfd_line;
- goto read_ranges;
- } else if (*p == 0) /* end of subfont */
- break;
- if (sscanf(p, " %li %n", &i, &n) == 0)
- formatted_error("sub font","invalid token: %s", p);
- p += n;
- if (*p == ':') { /* offset */
- k = i;
- p++;
- } else if (*p == '_') { /* range */
- if (sscanf(p + 1, " %li %n", &j, &n) == 0)
- formatted_error("sub font","invalid token: %s", p);
- if (i > j || k + (j - i) > 255)
- formatted_error("sub font","invalid range: %s", p);
- while (i <= j)
- sf->charcodes[k++] = i++;
- p += n + 1;
- } else /* codepoint */
- sf->charcodes[k++] = i;
- }
- }
- tex_printf("}");
- aa = avl_probe(sfd_tree, sfd);
- assert(aa != NULL);
- return sfd;
-}
-
-@ @c
-boolean handle_subfont_fm(fm_entry * fm, int mode)
-{
- size_t l;
- char *p, *q, *r;
- sfd_entry *sfd;
- subfont_entry *sf;
- fm_entry *fm2;
- char buf[SMALL_BUF_SIZE];
- assert(fm->tfm_name != NULL);
- p = fm->tfm_name;
- q = strchr(p, '@@'); /* search for the first '@@' */
- if (q == NULL)
- return false;
- r = strchr(q + 1, '@@'); /* search for the second '@@' */
- if (r == NULL)
- return false;
- if (q <= p || r <= q + 1 /* prefix or sfd name is empty */
- || r - p != (int) strlen(p) - 1) /* or the second '@@' is not the last char yet */
- return false;
- l = (size_t) (r - (q + 1)); /* length of sfd name */
- strncpy(buf, q + 1, l);
- buf[l] = 0;
- check_buf(strlen(buf) + 4, SMALL_BUF_SIZE);
- strcat(buf, ".sfd");
- sfd = read_sfd(buf);
- if (sfd == NULL)
- return false;
- /* at this point we know fm is a subfont */
- set_subfont(fm);
- xfree(fm->ps_name);
- /* set default values for PidEid */
- if (fm->pid == -1) {
- fm->pid = 3;
- fm->eid = 1;
- }
- l = (size_t) (q - p); /* length of base tfm name (prefix) */
- for (sf = sfd->subfont; sf != NULL; sf = sf->next) {
- strncpy(buf, p, l);
- buf[l] = 0;
- strcat(buf, sf->infix);
- fm2 = new_fm_entry();
- fm2->tfm_name = xstrdup(buf);
- fm2->ff_name = xstrdup(fm->ff_name);
- fm2->type = fm->type;
- fm2->pid = fm->pid;
- fm2->eid = fm->eid;
- fm2->subfont = sf;
- if (avl_do_entry(fm2, mode) != 0) /* try to insert the entry */
- delete_fm_entry(fm2); /* delete it if failed */
- }
- delete_fm_entry(fm);
- return true;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/texfont.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/texfont.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1950 @@
+/*
+
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+ Here is the main font API implementation for the original pascal parts. Stuff
+ to watch out for:
+
+ \startitemize
+
+ \startitem
+ Knuth had a |'null_character'| that was used when a character could
+ not be found by the |fetch()| routine, to signal an error. This has
+ been deleted, but it may mean that the output of luatex is
+ incompatible with TeX after |fetch()| has detected an error
+ condition.
+ \stopitem
+
+ \startitem
+ Knuth also had a |font_glue()| optimization. I've removed that
+ because it was a bit of dirty programming and it also was problematic
+ |if 0 != null|.
+ \stopitem
+
+ \stopitemize
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define noDEBUG
+
+#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f))
+#define do_realloc(a,b,d) a = xrealloc(a,(unsigned)((unsigned)(b)*sizeof(d)))
+
+texfont **font_tables = NULL;
+
+static int font_arr_max = 0;
+static int font_id_maxval = 0;
+
+static void grow_font_table(int id)
+{
+ int j;
+ if (id >= font_arr_max) {
+ font_bytes +=
+ (int) (((id + 8 - font_arr_max) * (int) sizeof(texfont *)));
+ font_tables =
+ xrealloc(font_tables,
+ (unsigned) (((unsigned) id + 8) * sizeof(texfont *)));
+ j = 8;
+ while (j--) {
+ font_tables[id + j] = NULL;
+ }
+ font_arr_max = id + 8;
+ }
+}
+
+int new_font_id(void)
+{
+ int i;
+ for (i = 0; i < font_arr_max; i++) {
+ if (font_tables[i] == NULL) {
+ break;
+ }
+ }
+ if (i >= font_arr_max)
+ grow_font_table(i);
+ if (i > font_id_maxval)
+ font_id_maxval = i;
+ return i;
+}
+
+int max_font_id(void)
+{
+ return font_id_maxval;
+}
+
+void set_max_font_id(int i)
+{
+ font_id_maxval = i;
+}
+
+int new_font(void)
+{
+ int k;
+ int id;
+ charinfo *ci;
+ sa_tree_item sa_value = { 0 };
+ id = new_font_id();
+ font_bytes += (int) sizeof(texfont);
+ /*tex Most stuff is zero */
+ font_tables[id] = xcalloc(1, sizeof(texfont));
+ font_tables[id]->_font_name = NULL;
+ font_tables[id]->_font_area = NULL;
+ font_tables[id]->_font_filename = NULL;
+ font_tables[id]->_font_fullname = NULL;
+ font_tables[id]->_font_psname = NULL;
+ font_tables[id]->_font_encodingname = NULL;
+ font_tables[id]->_font_cidregistry = NULL;
+ font_tables[id]->_font_cidordering = NULL;
+ font_tables[id]->_left_boundary = NULL;
+ font_tables[id]->_right_boundary = NULL;
+ font_tables[id]->_param_base = NULL;
+ font_tables[id]->_math_param_base = NULL;
+ /*tex |ec = 0| */
+ set_font_bc(id, 1);
+ set_font_writingmode(id, 0);
+ set_font_identity(id, 0);
+ set_hyphen_char(id, '-');
+ set_skew_char(id, -1);
+ /*tex vertical */
+ font_slant(id) = 0;
+ /*tex normal width */
+ font_extend(id) = 1000;
+ /*tex normal height */
+ font_squeeze(id) = 1000;
+ font_width(id) = 0;
+ font_mode(id) = 0;
+ /*tex allocate eight values including 0 */
+ set_font_params(id, 7);
+ for (k = 0; k <= 7; k++) {
+ set_font_param(id, k, 0);
+ }
+ /*tex character info zero is reserved for |notdef|. The stack size 1, default item value 0. */
+ font_tables[id]->characters = new_sa_tree(1, 1, sa_value);
+ ci = xcalloc(1, sizeof(charinfo));
+ set_charinfo_name(ci, xstrdup(".notdef"));
+ font_tables[id]->charinfo = ci;
+ font_tables[id]->charinfo_size = 1;
+ font_tables[id]->charinfo_cache = NULL;
+ return id;
+}
+
+void font_malloc_charinfo(internal_font_number f, int num)
+{
+ int glyph = font_tables[f]->charinfo_size;
+ font_bytes += (int) (num * (int) sizeof(charinfo));
+ do_realloc(font_tables[f]->charinfo, (unsigned) (glyph + num), charinfo);
+ memset(&(font_tables[f]->charinfo[glyph]), 0, (size_t) (num * (int) sizeof(charinfo)));
+ font_tables[f]->charinfo_size += num;
+}
+
+#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
+
+charinfo *get_charinfo(internal_font_number f, int c)
+{
+ int glyph;
+ charinfo *ci;
+ if (proper_char_index(c)) {
+ glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+ if (!glyph) {
+ sa_tree_item sa_value = { 0 };
+ int tglyph = ++font_tables[f]->charinfo_count;
+ if (tglyph >= font_tables[f]->charinfo_size) {
+ font_malloc_charinfo(f, 256);
+ }
+ font_tables[f]->charinfo[tglyph].ef = 1000;
+ sa_value.int_value = tglyph;
+ /*tex 1 means global */
+ set_sa_item(font_tables[f]->characters, c, sa_value, 1);
+ glyph = tglyph;
+ }
+ return &(font_tables[f]->charinfo[glyph]);
+ } else if (c == left_boundarychar) {
+ if (left_boundary(f) == NULL) {
+ ci = xcalloc(1, sizeof(charinfo));
+ font_bytes += (int) sizeof(charinfo);
+ set_left_boundary(f, ci);
+ }
+ return left_boundary(f);
+ } else if (c == right_boundarychar) {
+ if (right_boundary(f) == NULL) {
+ ci = xcalloc(1, sizeof(charinfo));
+ font_bytes += (int) sizeof(charinfo);
+ set_right_boundary(f, ci);
+ }
+ return right_boundary(f);
+ }
+ return &(font_tables[f]->charinfo[0]);
+}
+
+static void set_charinfo(internal_font_number f, int c, charinfo * ci)
+{
+ int glyph;
+ if (proper_char_index(c)) {
+ glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+ if (glyph) {
+ font_tables[f]->charinfo[glyph] = *ci;
+ } else {
+ normal_error("font","character insertion failed");
+ }
+ } else if (c == left_boundarychar) {
+ set_left_boundary(f, ci);
+ } else if (c == right_boundarychar) {
+ set_right_boundary(f, ci);
+ }
+}
+
+charinfo *copy_charinfo(charinfo * ci)
+{
+ int x, k;
+ kerninfo *kern;
+ liginfo *lig;
+ eight_bits *packet;
+ charinfo *co = NULL;
+ if (ci == NULL)
+ return NULL;
+ co = xmalloc(sizeof(charinfo));
+ memcpy(co, ci, sizeof(charinfo));
+ set_charinfo_used(co, false);
+ co->name = NULL;
+ co->tounicode = NULL;
+ co->packets = NULL;
+ co->ligatures = NULL;
+ co->kerns = NULL;
+ co->vert_variants = NULL;
+ co->hor_variants = NULL;
+ if (ci->name != NULL) {
+ co->name = xstrdup(ci->name);
+ }
+ if (ci->tounicode != NULL) {
+ co->tounicode = xstrdup(ci->tounicode);
+ }
+ /*tex Kerns */
+ if ((kern = get_charinfo_kerns(ci)) != NULL) {
+ x = 0;
+ while (!kern_end(kern[x])) {
+ x++;
+ }
+ x++;
+ co->kerns = xmalloc((unsigned) (x * (int) sizeof(kerninfo)));
+ memcpy(co->kerns, ci->kerns, (size_t) (x * (int) sizeof(kerninfo)));
+ }
+ /*tex Ligatures */
+ if ((lig = get_charinfo_ligatures(ci)) != NULL) {
+ x = 0;
+ while (!lig_end(lig[x])) {
+ x++;
+ }
+ x++;
+ co->ligatures = xmalloc((unsigned) (x * (int) sizeof(liginfo)));
+ memcpy(co->ligatures, ci->ligatures,
+ (size_t) (x * (int) sizeof(liginfo)));
+ }
+ /*tex Packets */
+ if ((packet = get_charinfo_packets(ci)) != NULL) {
+ x = vf_packet_bytes(ci);
+ co->packets = xmalloc((unsigned) x);
+ memcpy(co->packets, ci->packets, (size_t) x);
+ }
+ /*tex Horizontal and vertical extenders */
+ if (get_charinfo_vert_variants(ci) != NULL) {
+ set_charinfo_vert_variants(co, copy_variants(get_charinfo_vert_variants(ci)));
+ }
+ if (get_charinfo_hor_variants(ci) != NULL) {
+ set_charinfo_hor_variants(co, copy_variants(get_charinfo_hor_variants(ci)));
+ }
+ x = ci->top_left_math_kerns;
+ co->top_left_math_kerns = x;
+ if (x > 0) {
+ co->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < co->top_left_math_kerns; k++) {
+ co->top_left_math_kern_array[(2 * k)] = ci->top_left_math_kern_array[(2 * k)];
+ co->top_left_math_kern_array[(2 * k) + 1] = ci->top_left_math_kern_array[(2 * k) + 1];
+ }
+ }
+ x = ci->bottom_left_math_kerns;
+ co->bottom_left_math_kerns = x;
+ if (x > 0) {
+ co->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < co->bottom_left_math_kerns; k++) {
+ co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
+ co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
+ }
+ }
+ x = ci->top_right_math_kerns;
+ co->top_right_math_kerns = x;
+ if (x > 0) {
+ co->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < co->top_right_math_kerns; k++) {
+ co->top_right_math_kern_array[(2 * k)] = ci->top_right_math_kern_array[(2 * k)];
+ co->top_right_math_kern_array[(2 * k) + 1] = ci->top_right_math_kern_array[(2 * k) + 1];
+ }
+ }
+ x = ci->bottom_right_math_kerns;
+ co->bottom_right_math_kerns = x;
+ if (x > 0) {
+ co->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < co->bottom_right_math_kerns; k++) {
+ co->bottom_right_math_kern_array[(2 * k)] = ci->bottom_right_math_kern_array[(2 * k)];
+ co->bottom_right_math_kern_array[(2 * k) + 1] = ci->bottom_right_math_kern_array[(2 * k) + 1];
+ }
+ }
+ return co;
+}
+
+charinfo *char_info(internal_font_number f, int c)
+{
+ if (f > font_id_maxval)
+ return 0;
+ if (proper_char_index(c)) {
+ register int glyph = (int) find_charinfo_id(f, c);
+ return &(font_tables[f]->charinfo[glyph]);
+ } else if (c == left_boundarychar && left_boundary(f) != NULL) {
+ return left_boundary(f);
+ } else if (c == right_boundarychar && right_boundary(f) != NULL) {
+ return right_boundary(f);
+ }
+ return &(font_tables[f]->charinfo[0]);
+}
+
+scaled_whd get_charinfo_whd(internal_font_number f, int c)
+{
+ scaled_whd s;
+ charinfo *i;
+ i = char_info(f, c);
+ s.wd = i->width;
+ s.dp = i->depth;
+ s.ht = i->height;
+ return s;
+}
+
+int char_exists(internal_font_number f, int c)
+{
+ if (f > font_id_maxval)
+ return 0;
+ if (proper_char_index(c)) {
+ return (int) find_charinfo_id(f, c);
+ } else if ((c == left_boundarychar) && has_left_boundary(f)) {
+ return 1;
+ } else if ((c == right_boundarychar) && has_right_boundary(f)) {
+ return 1;
+ }
+ return 0;
+}
+
+int lua_glyph_not_found_callback(internal_font_number f, int c)
+{
+ int callback_id;
+ int ret = 0;
+ int top, i;
+ callback_id = callback_defined(glyph_not_found_callback);
+ if (callback_id != 0) {
+ top = lua_gettop(Luas);
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, top);
+ return 0;
+ }
+ lua_pushinteger(Luas, f);
+ lua_pushinteger(Luas, c);
+ if ((i=lua_pcall(Luas, 2, 1, 0)) != 0) {
+ formatted_warning ("glyph not found", "error: %s", lua_tostring(Luas, -1));
+ lua_settop(Luas, top);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ } else {
+ ret = lua_toboolean(Luas, -1);
+ }
+ lua_settop(Luas, top);
+ } else {
+ char_warning(f,c);
+ }
+ return ret;
+}
+
+extinfo *new_variant(int glyph, int startconnect, int endconnect, int advance, int repeater)
+{
+ extinfo *ext;
+ ext = xmalloc(sizeof(extinfo));
+ ext->next = NULL;
+ ext->glyph = glyph;
+ ext->start_overlap = startconnect;
+ ext->end_overlap = endconnect;
+ ext->advance = advance;
+ ext->extender = repeater;
+ return ext;
+}
+
+static extinfo *copy_variant(extinfo * old)
+{
+ extinfo *ext;
+ ext = xmalloc(sizeof(extinfo));
+ ext->next = NULL;
+ ext->glyph = old->glyph;
+ ext->start_overlap = old->start_overlap;
+ ext->end_overlap = old->end_overlap;
+ ext->advance = old->advance;
+ ext->extender = old->extender;
+ return ext;
+}
+
+static void dump_variant(extinfo * ext)
+{
+ dump_int(ext->glyph);
+ dump_int(ext->start_overlap);
+ dump_int(ext->end_overlap);
+ dump_int(ext->advance);
+ dump_int(ext->extender);
+ return;
+}
+
+static extinfo *undump_variant(void)
+{
+ int x;
+ extinfo *ext;
+ undump_int(x);
+ if (x == 0)
+ return NULL;
+ ext = xmalloc(sizeof(extinfo));
+ ext->next = NULL;
+ ext->glyph = x;
+ undump_int(x);
+ ext->start_overlap = x;
+ undump_int(x);
+ ext->end_overlap = x;
+ undump_int(x);
+ ext->advance = x;
+ undump_int(x);
+ ext->extender = x;
+ return ext;
+}
+
+void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
+{
+ if (ci->vert_variants == NULL) {
+ ci->vert_variants = ext;
+ } else {
+ extinfo *lst = ci->vert_variants;
+ while (lst->next != NULL)
+ lst = lst->next;
+ lst->next = ext;
+ }
+
+}
+
+void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
+{
+ if (ci->hor_variants == NULL) {
+ ci->hor_variants = ext;
+ } else {
+ extinfo *lst = ci->hor_variants;
+ while (lst->next != NULL)
+ lst = lst->next;
+ lst->next = ext;
+ }
+
+}
+
+extinfo *copy_variants(extinfo * o)
+{
+ extinfo *c, *t = NULL, *h = NULL;
+ while (o != NULL) {
+ c = copy_variant(o);
+ if (h == null)
+ h = c;
+ else
+ t->next = c;
+ t = c;
+ o = o->next;
+ }
+
+ return h;
+}
+
+static void dump_charinfo_variants(extinfo * o)
+{
+ while (o != NULL) {
+ dump_variant(o);
+ o = o->next;
+ }
+ dump_int(0);
+ return;
+}
+
+static extinfo *undump_charinfo_variants(void)
+{
+ extinfo *c, *t = NULL, *h = NULL;
+ c = undump_variant();
+ while (c != NULL) {
+ if (h == null)
+ h = c;
+ else
+ t->next = c;
+ t = c;
+ c = undump_variant();
+ }
+ return h;
+}
+
+
+/*tex
+
+ Note that many more small things like this are implemented as macros in the
+ header file.
+*/
+
+void set_charinfo_width(charinfo * ci, scaled val)
+{
+ ci->width = val;
+}
+
+void set_charinfo_height(charinfo * ci, scaled val)
+{
+ ci->height = val;
+}
+
+void set_charinfo_depth(charinfo * ci, scaled val)
+{
+ ci->depth = val;
+}
+
+void set_charinfo_italic(charinfo * ci, scaled val)
+{
+ ci->italic = val;
+}
+
+void set_charinfo_vert_italic(charinfo * ci, scaled val)
+{
+ ci->vert_italic = val;
+}
+
+void set_charinfo_top_accent(charinfo * ci, scaled val)
+{
+ ci->top_accent = val;
+}
+
+void set_charinfo_bot_accent(charinfo * ci, scaled val)
+{
+ ci->bot_accent = val;
+}
+
+void set_charinfo_tag(charinfo * ci, scaled val)
+{
+ ci->tag = (char) val;
+}
+
+void set_charinfo_remainder(charinfo * ci, scaled val)
+{
+ ci->remainder = val;
+}
+
+void set_charinfo_used(charinfo * ci, scaled val)
+{
+ ci->used = (char) val;
+}
+
+void set_charinfo_index(charinfo * ci, scaled val)
+{
+ ci->index = (unsigned short) val;
+}
+
+void set_charinfo_name(charinfo * ci, char *val)
+{
+ xfree(ci->name);
+ ci->name = val;
+}
+
+void set_charinfo_tounicode(charinfo * ci, char *val)
+{
+ xfree(ci->tounicode);
+ ci->tounicode = val;
+}
+
+void set_charinfo_ligatures(charinfo * ci, liginfo * val)
+{
+ dxfree(ci->ligatures, val);
+}
+
+void set_charinfo_kerns(charinfo * ci, kerninfo * val)
+{
+ dxfree(ci->kerns, val);
+}
+
+void set_charinfo_packets(charinfo * ci, eight_bits * val)
+{
+ dxfree(ci->packets, val);
+}
+
+void set_charinfo_ef(charinfo * ci, scaled val)
+{
+ ci->ef = val;
+}
+
+void set_charinfo_lp(charinfo * ci, scaled val)
+{
+ ci->lp = val;
+}
+
+void set_charinfo_rp(charinfo * ci, scaled val)
+{
+ ci->rp = val;
+}
+
+void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
+{
+ extinfo *c, *lst;
+ if (ci->vert_variants != NULL) {
+ lst = ci->vert_variants;
+ while (lst != NULL) {
+ c = lst->next;
+ free(lst);
+ lst = c;
+ }
+ }
+ ci->vert_variants = ext;
+}
+
+void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
+{
+ extinfo *c, *lst;
+ if (ci->hor_variants != NULL) {
+ lst = ci->hor_variants;
+ while (lst != NULL) {
+ c = lst->next;
+ free(lst);
+ lst = c;
+ }
+ }
+ ci->hor_variants = ext;
+
+}
+
+int get_charinfo_math_kerns(charinfo * ci, int id)
+{
+ /*tex All callers check for |result>0|. */
+ int k = 0;
+ if (id == top_left_kern) {
+ k = ci->top_left_math_kerns;
+ } else if (id == bottom_left_kern) {
+ k = ci->bottom_left_math_kerns;
+ } else if (id == top_right_kern) {
+ k = ci->top_right_math_kerns;
+ } else if (id == bottom_right_kern) {
+ k = ci->bottom_right_math_kerns;
+ } else {
+ confusion("get_charinfo_math_kerns");
+ }
+ return k;
+}
+
+void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
+{
+ int k;
+ if (id == top_left_kern) {
+ k = ci->top_left_math_kerns;
+ do_realloc(ci->top_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+ ci->top_left_math_kern_array[(2 * (k))] = ht;
+ ci->top_left_math_kern_array[((2 * (k)) + 1)] = krn;
+ ci->top_left_math_kerns++;
+ } else if (id == bottom_left_kern) {
+ k = ci->bottom_left_math_kerns;
+ do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+ ci->bottom_left_math_kern_array[(2 * (k))] = ht;
+ ci->bottom_left_math_kern_array[(2 * (k)) + 1] = krn;
+ ci->bottom_left_math_kerns++;
+ } else if (id == top_right_kern) {
+ k = ci->top_right_math_kerns;
+ do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+ ci->top_right_math_kern_array[(2 * (k))] = ht;
+ ci->top_right_math_kern_array[(2 * (k)) + 1] = krn;
+ ci->top_right_math_kerns++;
+ } else if (id == bottom_right_kern) {
+ k = ci->bottom_right_math_kerns;
+ do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+ ci->bottom_right_math_kern_array[(2 * (k))] = ht;
+ ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
+ ci->bottom_right_math_kerns++;
+ } else {
+ confusion("add_charinfo_math_kern");
+ }
+}
+
+static void dump_math_kerns(charinfo * ci)
+{
+ int k, l;
+ l = ci->top_left_math_kerns;
+ dump_int(l);
+ for (k = 0; k < l; k++) {
+ dump_int(ci->top_left_math_kern_array[(2 * k)]);
+ dump_int(ci->top_left_math_kern_array[(2 * k) + 1]);
+ }
+ l = ci->bottom_left_math_kerns;
+ dump_int(l);
+ for (k = 0; k < l; k++) {
+ dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
+ dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
+ }
+ l = ci->top_right_math_kerns;
+ dump_int(l);
+ for (k = 0; k < l; k++) {
+ dump_int(ci->top_right_math_kern_array[(2 * k)]);
+ dump_int(ci->top_right_math_kern_array[(2 * k) + 1]);
+ }
+ l = ci->bottom_right_math_kerns;
+ dump_int(l);
+ for (k = 0; k < l; k++) {
+ dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
+ dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
+ }
+}
+
+static void undump_math_kerns(charinfo * ci)
+{
+ int k, x;
+ undump_int(x);
+ ci->top_left_math_kerns = x;
+ if (x > 0)
+ ci->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < ci->top_left_math_kerns; k++) {
+ undump_int(x);
+ ci->top_left_math_kern_array[(2 * k)] = (scaled) x;
+ undump_int(x);
+ ci->top_left_math_kern_array[(2 * k) + 1] = (scaled) x;
+ }
+ undump_int(x);
+ ci->bottom_left_math_kerns = x;
+ if (x > 0)
+ ci->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < ci->bottom_left_math_kerns; k++) {
+ undump_int(x);
+ ci->bottom_left_math_kern_array[(2 * k)] = (scaled) x;
+ undump_int(x);
+ ci->bottom_left_math_kern_array[(2 * k) + 1] = (scaled) x;
+ }
+ undump_int(x);
+ ci->top_right_math_kerns = x;
+ if (x > 0)
+ ci->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < ci->top_right_math_kerns; k++) {
+ undump_int(x);
+ ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
+ undump_int(x);
+ ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+ }
+ undump_int(x);
+ ci->bottom_right_math_kerns = x;
+ if (x > 0)
+ ci->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+ for (k = 0; k < ci->bottom_right_math_kerns; k++) {
+ undump_int(x);
+ ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
+ undump_int(x);
+ ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+ }
+}
+
+/*tex
+
+ In TeX, extensibles were fairly simple things. This function squeezes a TFM
+ extensible into the vertical extender structures. |advance==0| is a special
+ case for TFM fonts, because finding the proper advance width during tfm
+ reading can be tricky.
+
+ A small complication arises if |rep| is the only non-zero: it needs to be
+ doubled as a non-repeatable to avoid mayhem.
+
+*/
+
+void set_charinfo_extensible(charinfo * ci, int top, int bot, int mid, int rep)
+{
+ extinfo *ext;
+ /*tex Clear old data: */
+ set_charinfo_vert_variants(ci, NULL);
+ if (bot == 0 && top == 0 && mid == 0 && rep != 0) {
+ ext = new_variant(rep, 0, 0, 0, EXT_NORMAL);
+ add_charinfo_vert_variant(ci, ext);
+ ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+ add_charinfo_vert_variant(ci, ext);
+ return;
+ }
+ if (bot != 0) {
+ ext = new_variant(bot, 0, 0, 0, EXT_NORMAL);
+ add_charinfo_vert_variant(ci, ext);
+ }
+ if (rep != 0) {
+ ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+ add_charinfo_vert_variant(ci, ext);
+ }
+ if (mid != 0) {
+ ext = new_variant(mid, 0, 0, 0, EXT_NORMAL);
+ add_charinfo_vert_variant(ci, ext);
+ if (rep != 0) {
+ ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+ add_charinfo_vert_variant(ci, ext);
+ }
+ }
+ if (top != 0) {
+ ext = new_variant(top, 0, 0, 0, EXT_NORMAL);
+ add_charinfo_vert_variant(ci, ext);
+ }
+}
+
+/*tex
+
+ Note that many more simple things like this are implemented as macros in the
+ header file.
+
+*/
+
+scaled get_charinfo_width(charinfo * ci)
+{
+ return ci->width;
+}
+
+scaled get_charinfo_height(charinfo * ci)
+{
+ return ci->height;
+}
+
+scaled get_charinfo_depth(charinfo * ci)
+{
+ return ci->depth;
+}
+
+scaled get_charinfo_italic(charinfo * ci)
+{
+ return ci->italic;
+}
+
+scaled get_charinfo_vert_italic(charinfo * ci)
+{
+ return ci->vert_italic;
+}
+
+scaled get_charinfo_top_accent(charinfo * ci)
+{
+ return ci->top_accent;
+}
+
+scaled get_charinfo_bot_accent(charinfo * ci)
+{
+ return ci->bot_accent;
+}
+
+char get_charinfo_tag(charinfo * ci)
+{
+ return ci->tag;
+}
+
+int get_charinfo_remainder(charinfo * ci)
+{
+ return ci->remainder;
+}
+
+char get_charinfo_used(charinfo * ci)
+{
+ return ci->used;
+}
+
+int get_charinfo_index(charinfo * ci)
+{
+ return ci->index;
+}
+
+char *get_charinfo_name(charinfo * ci)
+{
+ return ci->name;
+}
+
+char *get_charinfo_tounicode(charinfo * ci)
+{
+ return ci->tounicode;
+}
+
+liginfo *get_charinfo_ligatures(charinfo * ci)
+{
+ return ci->ligatures;
+}
+
+kerninfo *get_charinfo_kerns(charinfo * ci)
+{
+ return ci->kerns;
+}
+
+eight_bits *get_charinfo_packets(charinfo * ci)
+{
+ return ci->packets;
+}
+
+int get_charinfo_ef(charinfo * ci)
+{
+ return ci->ef;
+}
+
+int get_charinfo_rp(charinfo * ci)
+{
+ return ci->rp;
+}
+
+int get_charinfo_lp(charinfo * ci)
+{
+ return ci->lp;
+}
+
+extinfo *get_charinfo_vert_variants(charinfo * ci)
+{
+ extinfo *w = NULL;
+ if (ci->vert_variants != NULL)
+ w = ci->vert_variants;
+ return w;
+}
+
+extinfo *get_charinfo_hor_variants(charinfo * ci)
+{
+ extinfo *w = NULL;
+ if (ci->hor_variants != NULL)
+ w = ci->hor_variants;
+ return w;
+}
+
+
+scaled char_width(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ scaled w = get_charinfo_width(ci);
+ return w;
+}
+
+scaled calc_char_width(internal_font_number f, int c, int ex)
+{
+ charinfo *ci = char_info(f, c);
+ scaled w = get_charinfo_width(ci);
+ if (ex != 0)
+ w = round_xn_over_d(w, 1000 + ex, 1000);
+ return w;
+}
+
+scaled char_depth(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ scaled d = get_charinfo_depth(ci);
+ return d;
+}
+
+scaled char_height(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ scaled h = get_charinfo_height(ci);
+ return h;
+}
+
+scaled char_italic(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ scaled i = get_charinfo_italic(ci);
+ return i;
+}
+
+scaled char_vert_italic(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ scaled i = get_charinfo_vert_italic(ci);
+ return i;
+}
+
+scaled char_top_accent(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_top_accent(ci);
+}
+
+scaled char_bot_accent(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_bot_accent(ci);
+}
+
+int char_remainder(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_remainder(ci);
+}
+
+char char_tag(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_tag(ci);
+}
+
+char char_used(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_used(ci);
+}
+
+char *char_name(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_name(ci);
+}
+
+int char_index(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_index(ci);
+}
+
+liginfo *char_ligatures(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_ligatures(ci);
+}
+
+kerninfo *char_kerns(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_kerns(ci);
+}
+
+eight_bits *char_packets(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_packets(ci);
+}
+
+void set_font_params(internal_font_number f, int b)
+{
+ int i;
+ i = font_params(f);
+ if (i != b) {
+ font_bytes +=
+ (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
+ do_realloc(param_base(f), (b + 2), int);
+ font_params(f) = b;
+ if (b > i) {
+ while (i < b) {
+ i++;
+ set_font_param(f, i, 0);
+ }
+ }
+ }
+}
+
+void set_font_math_params(internal_font_number f, int b)
+{
+ int i;
+ i = font_math_params(f);
+ if (i != b) {
+ font_bytes +=
+ ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
+ do_realloc(math_param_base(f), (b + 2), int);
+ font_math_params(f) = b;
+ if (b > i) {
+ while (i < b) {
+ i++;
+ set_font_math_param(f, i, undefined_math_parameter);
+ }
+ }
+ }
+}
+
+int copy_font(int f)
+{
+ int i, ci_cnt, ci_size;
+ charinfo *ci;
+ int k = new_font();
+ {
+ ci = font_tables[k]->charinfo;
+ ci_cnt = font_tables[k]->charinfo_count;
+ ci_size = font_tables[k]->charinfo_size;
+ memcpy(font_tables[k], font_tables[f], sizeof(texfont));
+ font_tables[k]->charinfo = ci;
+ font_tables[k]->charinfo_count = ci_cnt;
+ font_tables[k]->charinfo_size = ci_size;
+ }
+ font_malloc_charinfo(k, font_tables[f]->charinfo_count);
+ set_font_cache_id(k, 0);
+ set_font_used(k, 0);
+ set_font_touched(k, 0);
+ font_tables[k]->_font_name = NULL;
+ font_tables[k]->_font_filename = NULL;
+ font_tables[k]->_font_fullname = NULL;
+ font_tables[k]->_font_psname = NULL;
+ font_tables[k]->_font_encodingname = NULL;
+ font_tables[k]->_font_area = NULL;
+ font_tables[k]->_font_cidregistry = NULL;
+ font_tables[k]->_font_cidordering = NULL;
+ font_tables[k]->_left_boundary = NULL;
+ font_tables[k]->_right_boundary = NULL;
+ set_font_name(k, xstrdup(font_name(f)));
+ if (font_filename(f) != NULL)
+ set_font_filename(k, xstrdup(font_filename(f)));
+ if (font_fullname(f) != NULL)
+ set_font_fullname(k, xstrdup(font_fullname(f)));
+ if (font_psname(f) != NULL)
+ set_font_psname(k, xstrdup(font_psname(f)));
+ if (font_encodingname(f) != NULL)
+ set_font_encodingname(k, xstrdup(font_encodingname(f)));
+ if (font_area(f) != NULL)
+ set_font_area(k, xstrdup(font_area(f)));
+ if (font_cidregistry(f) != NULL)
+ set_font_cidregistry(k, xstrdup(font_cidregistry(f)));
+ if (font_cidordering(f) != NULL)
+ set_font_cidordering(k, xstrdup(font_cidordering(f)));
+ i = (int) (sizeof(*param_base(f)) * (unsigned) (font_params(f)+1));
+ font_bytes += i;
+ param_base(k) = xmalloc((unsigned) (i+1));
+ memcpy(param_base(k), param_base(f), (size_t) (i));
+ if (font_math_params(f) > 0) {
+ i = (int) (sizeof(*math_param_base(f)) *
+ (unsigned) font_math_params(f));
+ font_bytes += i;
+ math_param_base(k) = xmalloc((unsigned) i);
+ memcpy(math_param_base(k), math_param_base(f), (size_t) i);
+ }
+ for (i = 0; i <= font_tables[f]->charinfo_count; i++) {
+ ci = copy_charinfo(&font_tables[f]->charinfo[i]);
+ font_tables[k]->charinfo[i] = *ci;
+ }
+ if (left_boundary(f) != NULL) {
+ ci = copy_charinfo(left_boundary(f));
+ set_charinfo(k, left_boundarychar, ci);
+ }
+ if (right_boundary(f) != NULL) {
+ ci = copy_charinfo(right_boundary(f));
+ set_charinfo(k, right_boundarychar, ci);
+ }
+ /*tex Not updated yet: */
+ font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
+ return k;
+}
+
+void delete_font(int f)
+{
+ int i;
+ charinfo *co;
+ assert(f > 0);
+ if (font_tables[f] != NULL) {
+ set_font_name(f, NULL);
+ set_font_filename(f, NULL);
+ set_font_fullname(f, NULL);
+ set_font_psname(f, NULL);
+ set_font_encodingname(f, NULL);
+ set_font_area(f, NULL);
+ set_font_cidregistry(f, NULL);
+ set_font_cidordering(f, NULL);
+ set_left_boundary(f, NULL);
+ set_right_boundary(f, NULL);
+ for (i = font_bc(f); i <= font_ec(f); i++) {
+ if (quick_char_exists(f, i)) {
+ co = char_info(f, i);
+ set_charinfo_name(co, NULL);
+ set_charinfo_tounicode(co, NULL);
+ set_charinfo_packets(co, NULL);
+ set_charinfo_ligatures(co, NULL);
+ set_charinfo_kerns(co, NULL);
+ set_charinfo_vert_variants(co, NULL);
+ set_charinfo_hor_variants(co, NULL);
+ }
+ }
+ /*tex free |notdef| */
+ set_charinfo_name(font_tables[f]->charinfo + 0, NULL);
+ free(font_tables[f]->charinfo);
+ destroy_sa_tree(font_tables[f]->characters);
+ free(param_base(f));
+ if (math_param_base(f) != NULL)
+ free(math_param_base(f));
+ free(font_tables[f]);
+ font_tables[f] = NULL;
+ if (font_id_maxval == f) {
+ font_id_maxval--;
+ }
+ }
+}
+
+void create_null_font(void)
+{
+ int i = new_font();
+ assert(i == 0);
+ set_font_name(i, xstrdup("nullfont"));
+ set_font_area(i, xstrdup(""));
+ set_font_touched(i, 1);
+}
+
+boolean is_valid_font(int id)
+{
+ int ret = 0;
+ if (id >= 0 && id <= font_id_maxval && font_tables[id] != NULL)
+ ret = 1;
+ return ret;
+}
+
+boolean cmp_font_area(int id, str_number t)
+{
+ char *tt = NULL;
+ char *tid = font_area(id);
+ if (t == 0) {
+ if (tid == NULL || strlen(tid) == 0)
+ return 1;
+ else
+ return 0;
+ }
+ tt = makecstring(t);
+ if ((tt == NULL || strlen(tt) == 0) && (tid == NULL || strlen(tid) == 0))
+ return 1;
+ if (tt == NULL || strcmp(tid, tt) != 0)
+ return 0;
+ free(tt);
+ return 1;
+}
+
+/*tex
+
+ Here come some subroutines to deal with expanded fonts for HZ-algorithm.
+ returning 1 means that they are identical.
+
+*/
+
+static boolean cmp_font_name(int id, char *tt)
+{
+ char *tid;
+ if (!is_valid_font(id))
+ return 0;
+ tid = font_name(id);
+ if (tt == NULL && tid == NULL)
+ return 1;
+ if (tt == NULL || tid == NULL || strcmp(tid, tt) != 0)
+ return 0;
+ return 1;
+}
+
+int test_no_ligatures(internal_font_number f)
+{
+ int c;
+ for (c = font_bc(f); c <= font_ec(f); c++) {
+ if (has_lig(f, c))
+ return 0;
+ }
+ return 1;
+}
+
+int get_tag_code(internal_font_number f, int c)
+{
+ small_number i;
+ if (char_exists(f, c)) {
+ i = char_tag(f, c);
+ if (i == lig_tag)
+ return 1;
+ else if (i == list_tag)
+ return 2;
+ else if (i == ext_tag)
+ return 4;
+ else
+ return 0;
+ }
+ return -1;
+}
+
+int get_lp_code(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_lp(ci);
+}
+
+int get_rp_code(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_rp(ci);
+}
+
+int get_ef_code(internal_font_number f, int c)
+{
+ charinfo *ci = char_info(f, c);
+ return get_charinfo_ef(ci);
+}
+
+void set_tag_code(internal_font_number f, int c, int i)
+{
+ int fixedi;
+ charinfo *co;
+ if (char_exists(f, c)) {
+ fixedi = -(i < -7 ? -7 : (i > 0 ? 0 : i));
+ co = char_info(f, c);
+ if (fixedi >= 4) {
+ if (char_tag(f, c) == ext_tag)
+ set_charinfo_tag(co, (char_tag(f, c) - ext_tag));
+ fixedi = fixedi - 4;
+ }
+ if (fixedi >= 2) {
+ if (char_tag(f, c) == list_tag)
+ set_charinfo_tag(co, (char_tag(f, c) - list_tag));
+ fixedi = fixedi - 2;
+ };
+ if (fixedi >= 1) {
+ if (has_lig(f, c))
+ set_charinfo_ligatures(co, NULL);
+ if (has_kern(f, c))
+ set_charinfo_kerns(co, NULL);
+ }
+ }
+}
+
+void set_lp_code(internal_font_number f, int c, int i)
+{
+ charinfo *co;
+ if (char_exists(f, c)) {
+ co = char_info(f, c);
+ set_charinfo_lp(co, i);
+ }
+}
+
+void set_rp_code(internal_font_number f, int c, int i)
+{
+ charinfo *co;
+ if (char_exists(f, c)) {
+ co = char_info(f, c);
+ set_charinfo_rp(co, i);
+ }
+}
+
+void set_ef_code(internal_font_number f, int c, int i)
+{
+ charinfo *co;
+ if (char_exists(f, c)) {
+ co = char_info(f, c);
+ set_charinfo_ef(co, i);
+ }
+}
+
+void set_no_ligatures(internal_font_number f)
+{
+ int c;
+ charinfo *co;
+ if (font_tables[f]->ligatures_disabled)
+ return;
+ co = char_info(f, left_boundarychar);
+ set_charinfo_ligatures(co, NULL);
+ co = char_info(f, right_boundarychar);
+ set_charinfo_ligatures(co, NULL);
+ for (c = 0; c < font_tables[f]->charinfo_count; c++) {
+ co = font_tables[f]->charinfo + c;
+ set_charinfo_ligatures(co, NULL);
+ }
+ font_tables[f]->ligatures_disabled = 1;
+}
+
+liginfo get_ligature(internal_font_number f, int lc, int rc)
+{
+ int k = 0;
+ liginfo t, u;
+ charinfo *co;
+ t.lig = 0;
+ t.type = 0;
+ t.adj = 0;
+ if (lc == non_boundarychar || rc == non_boundarychar || (!has_lig(f, lc)))
+ return t;
+ co = char_info(f, lc);
+ while (1) {
+ u = charinfo_ligature(co, k);
+ if (lig_end(u))
+ break;
+ if (lig_char(u) == rc) {
+ if (lig_disabled(u)) {
+ return t;
+ } else {
+ return u;
+ }
+ }
+ k++;
+ }
+ return t;
+}
+
+scaled raw_get_kern(internal_font_number f, int lc, int rc)
+{
+ int k = 0;
+ kerninfo u;
+ charinfo *co;
+ if (lc == non_boundarychar || rc == non_boundarychar)
+ return 0;
+ co = char_info(f, lc);
+ while (1) {
+ u = charinfo_kern(co, k);
+ if (kern_end(u))
+ break;
+ if (kern_char(u) == rc) {
+ if (kern_disabled(u))
+ return 0;
+ else
+ return kern_kern(u);
+ }
+ k++;
+ }
+ return 0;
+}
+
+scaled get_kern(internal_font_number f, int lc, int rc)
+{
+ if (lc == non_boundarychar || rc == non_boundarychar || (!has_kern(f, lc)))
+ return 0;
+ return raw_get_kern(f, lc, rc);
+}
+
+
+/*tex Dumping and undumping fonts. */
+
+#define dump_string(a) \
+ if (a!=NULL) { \
+ x = (int)(strlen(a)+1); \
+ dump_int(x); dump_things(*a, x); \
+ } else { \
+ x = 0; dump_int(x); \
+ }
+
+static void dump_charinfo(int f, int c)
+{
+ charinfo *co;
+ int x;
+ liginfo *lig;
+ kerninfo *kern;
+ dump_int(c);
+ co = char_info(f, c);
+ set_charinfo_used(co, 0);
+ dump_int(get_charinfo_width(co));
+ dump_int(get_charinfo_height(co));
+ dump_int(get_charinfo_depth(co));
+ dump_int(get_charinfo_italic(co));
+ dump_int(get_charinfo_vert_italic(co));
+ dump_int(get_charinfo_top_accent(co));
+ dump_int(get_charinfo_bot_accent(co));
+ dump_int(get_charinfo_tag(co));
+ dump_int(get_charinfo_ef(co));
+ dump_int(get_charinfo_rp(co));
+ dump_int(get_charinfo_lp(co));
+ dump_int(get_charinfo_remainder(co));
+ dump_int(get_charinfo_used(co));
+ dump_int(get_charinfo_index(co));
+ dump_string(get_charinfo_name(co));
+ dump_string(get_charinfo_tounicode(co));
+ /*tex Ligatures */
+ x = 0;
+ if ((lig = get_charinfo_ligatures(co)) != NULL) {
+ while (!lig_end(lig[x])) {
+ x++;
+ }
+ x++;
+ dump_int(x);
+ dump_things(*lig, x);
+ } else {
+ dump_int(x);
+ }
+ /*tex Kerns */
+ x = 0;
+ if ((kern = get_charinfo_kerns(co)) != NULL) {
+ while (!kern_end(kern[x])) {
+ x++;
+ }
+ x++;
+ dump_int(x);
+ dump_things(*kern, x);
+ } else {
+ dump_int(x);
+ }
+ /*tex Packets */
+ x = vf_packet_bytes(co);
+ dump_int(x);
+ if (x > 0) {
+ dump_things(*get_charinfo_packets(co), x);
+ }
+ if (get_charinfo_tag(co) == ext_tag) {
+ dump_charinfo_variants(get_charinfo_vert_variants(co));
+ dump_charinfo_variants(get_charinfo_hor_variants(co));
+ }
+ dump_math_kerns(co);
+}
+
+static void dump_font_entry(texfont * f)
+{
+ int x;
+ dump_int(f->_font_size);
+ dump_int(f->_font_dsize);
+ dump_int(f->_font_cidversion);
+ dump_int(f->_font_cidsupplement);
+ dump_int(f->_font_ec);
+ x = (int) f->_font_checksum;
+ dump_int(x);
+ dump_int(f->_font_used);
+ dump_int(f->_font_touched);
+ dump_int(f->_font_cache_id);
+ dump_int(f->_font_encodingbytes);
+ dump_int(f->_font_oldmath);
+ dump_int(f->_font_slant);
+ dump_int(f->_font_extend);
+ dump_int(f->_font_squeeze);
+ dump_int(f->_font_mode);
+ dump_int(f->_font_width);
+ dump_int(f->font_max_shrink);
+ dump_int(f->font_max_stretch);
+ dump_int(f->_font_step);
+ dump_int(f->_font_tounicode);
+ dump_int(f->_font_type);
+ dump_int(f->_font_format);
+ dump_int(f->_font_writingmode);
+ dump_int(f->_font_identity);
+ dump_int(f->_font_embedding);
+ dump_int(f->_font_streamprovider);
+ dump_int(f->_font_bc);
+ dump_int(f->_hyphen_char);
+ dump_int(f->_skew_char);
+ dump_int(f->_font_natural_dir);
+ dump_int(f->_font_params);
+ dump_int(f->_font_math_params);
+ dump_int(f->ligatures_disabled);
+ dump_int(f->_pdf_font_num);
+ dump_int(f->_pdf_font_attr);
+}
+
+void dump_font(int f)
+{
+ int i, x;
+ set_font_used(f, 0);
+ font_tables[f]->charinfo_cache = NULL;
+ dump_font_entry(font_tables[f]);
+ dump_string(font_name(f));
+ dump_string(font_area(f));
+ dump_string(font_filename(f));
+ dump_string(font_fullname(f));
+ dump_string(font_psname(f));
+ dump_string(font_encodingname(f));
+ dump_string(font_cidregistry(f));
+ dump_string(font_cidordering(f));
+ dump_things(*param_base(f), (font_params(f) + 1));
+ if (font_math_params(f) > 0) {
+ dump_things(*math_param_base(f), (font_math_params(f) + 1 ));
+ }
+ if (has_left_boundary(f)) {
+ dump_int(1);
+ dump_charinfo(f, left_boundarychar);
+ } else {
+ dump_int(0);
+ }
+ if (has_right_boundary(f)) {
+ dump_int(1);
+ dump_charinfo(f, right_boundarychar);
+ } else {
+ dump_int(0);
+ }
+ for (i = font_bc(f); i <= font_ec(f); i++) {
+ if (quick_char_exists(f, i)) {
+ dump_charinfo(f, i);
+ }
+ }
+}
+
+static int undump_charinfo(int f)
+{
+ charinfo *co;
+ int x, i;
+ char *s = NULL;
+ liginfo *lig = NULL;
+ kerninfo *kern = NULL;
+ eight_bits *packet = NULL;
+ undump_int(i);
+ co = get_charinfo(f, i);
+ undump_int(x);
+ set_charinfo_width(co, x);
+ undump_int(x);
+ set_charinfo_height(co, x);
+ undump_int(x);
+ set_charinfo_depth(co, x);
+ undump_int(x);
+ set_charinfo_italic(co, x);
+ undump_int(x);
+ set_charinfo_vert_italic(co, x);
+ undump_int(x);
+ set_charinfo_top_accent(co, x);
+ undump_int(x);
+ set_charinfo_bot_accent(co, x);
+ undump_int(x);
+ set_charinfo_tag(co, x);
+ undump_int(x);
+ set_charinfo_ef(co, x);
+ undump_int(x);
+ set_charinfo_rp(co, x);
+ undump_int(x);
+ set_charinfo_lp(co, x);
+ undump_int(x);
+ set_charinfo_remainder(co, x);
+ undump_int(x);
+ set_charinfo_used(co, x);
+ undump_int(x);
+ set_charinfo_index(co, x);
+ /*tex Name */
+ undump_int(x);
+ if (x > 0) {
+ font_bytes += x;
+ s = xmalloc((unsigned) x);
+ undump_things(*s, x);
+ }
+ set_charinfo_name(co, s);
+ /*tex Tounicode */
+ undump_int(x);
+ if (x > 0) {
+ font_bytes += x;
+ s = xmalloc((unsigned) x);
+ undump_things(*s, x);
+ }
+ set_charinfo_tounicode(co, s);
+ /*tex Ligatures */
+ undump_int(x);
+ if (x > 0) {
+ font_bytes += (int) ((unsigned) x * sizeof(liginfo));
+ lig = xmalloc((unsigned) ((unsigned) x * sizeof(liginfo)));
+ undump_things(*lig, x);
+ }
+ set_charinfo_ligatures(co, lig);
+ /*tex Kerns */
+ undump_int(x);
+ if (x > 0) {
+ font_bytes += (int) ((unsigned) x * sizeof(kerninfo));
+ kern = xmalloc((unsigned) ((unsigned) x * sizeof(kerninfo)));
+ undump_things(*kern, x);
+ }
+ set_charinfo_kerns(co, kern);
+
+ /*tex Packets */
+ undump_int(x);
+ if (x > 0) {
+ font_bytes += x;
+ packet = xmalloc((unsigned) x);
+ undump_things(*packet, x);
+ }
+ set_charinfo_packets(co, packet);
+ if (get_charinfo_tag(co) == ext_tag) {
+ set_charinfo_vert_variants(co, undump_charinfo_variants());
+ set_charinfo_hor_variants(co, undump_charinfo_variants());
+ }
+ undump_math_kerns(co);
+ return i;
+}
+
+#define undump_font_string(a) \
+ undump_int (x); \
+ if (x>0) { \
+ font_bytes += x; \
+ s = xmalloc((unsigned)x); \
+ undump_things(*s,x); \
+ a(f,s); \
+ }
+
+static void undump_font_entry(texfont * f)
+{
+ int x = 0;
+ undump_int(x); f->_font_size = x;
+ undump_int(x); f->_font_dsize = x;
+ undump_int(x); f->_font_cidversion = x;
+ undump_int(x); f->_font_cidsupplement = x;
+ undump_int(x); f->_font_ec = x;
+ undump_int(x); f->_font_checksum = (unsigned)x;
+ undump_int(x); f->_font_used = (char)x;
+ undump_int(x); f->_font_touched = (char)x;
+ undump_int(x); f->_font_cache_id = x;
+ undump_int(x); f->_font_encodingbytes = (char)x;
+ undump_int(x); f->_font_oldmath = x;
+ undump_int(x); f->_font_slant = x;
+ undump_int(x); f->_font_extend = x;
+ undump_int(x); f->_font_squeeze = x;
+ undump_int(x); f->_font_mode = x;
+ undump_int(x); f->_font_width = x;
+ undump_int(x); f->font_max_shrink = x;
+ undump_int(x); f->font_max_stretch = x;
+ undump_int(x); f->_font_step = x;
+ undump_int(x); f->_font_tounicode = (char)x;
+ undump_int(x); f->_font_type = x;
+ undump_int(x); f->_font_format = x;
+ undump_int(x); f->_font_writingmode = x;
+ undump_int(x); f->_font_identity = x;
+ undump_int(x); f->_font_embedding = x;
+ undump_int(x); f->_font_streamprovider = x;
+ undump_int(x); f->_font_bc = x;
+ undump_int(x); f->_hyphen_char = x;
+ undump_int(x); f->_skew_char = x;
+ undump_int(x); f->_font_natural_dir = x;
+ undump_int(x); f->_font_params = x;
+ undump_int(x); f->_font_math_params = x;
+ undump_int(x); f->ligatures_disabled = x;
+ undump_int(x); f->_pdf_font_num = x;
+ undump_int(x); f->_pdf_font_attr = x;
+}
+
+void undump_font(int f)
+{
+ int x, i;
+ texfont *tt;
+ charinfo *ci;
+ char *s;
+ sa_tree_item sa_value = { 0 };
+ grow_font_table(f);
+ tt = xmalloc(sizeof(texfont));
+ memset(tt, 0, sizeof(texfont));
+ font_bytes += (int) sizeof(texfont);
+ undump_font_entry(tt);
+ font_tables[f] = tt;
+ undump_font_string(set_font_name);
+ undump_font_string(set_font_area);
+ undump_font_string(set_font_filename);
+ undump_font_string(set_font_fullname);
+ undump_font_string(set_font_psname);
+ undump_font_string(set_font_encodingname);
+ undump_font_string(set_font_cidregistry);
+ undump_font_string(set_font_cidordering);
+ i = (int) (sizeof(*param_base(f)) * ((unsigned) font_params(f) + 1));
+ font_bytes += i;
+ param_base(f) = xmalloc((unsigned) i);
+ undump_things(*param_base(f), (font_params(f) + 1));
+ if (font_math_params(f) > 0) {
+ i = (int) (sizeof(*math_param_base(f)) *
+ ((unsigned) font_math_params(f) + 1));
+ font_bytes += i;
+ math_param_base(f) = xmalloc((unsigned) i);
+ undump_things(*math_param_base(f), (font_math_params(f) + 1));
+ }
+ /*tex stack size 1, default item value 0 */
+ font_tables[f]->characters = new_sa_tree(1, 1, sa_value);
+ ci = xcalloc(1, sizeof(charinfo));
+ set_charinfo_name(ci, xstrdup(".notdef"));
+ font_tables[f]->charinfo = ci;
+ undump_int(x);
+ if (x) {
+ /*tex left boundary */
+ i = undump_charinfo(f);
+ }
+ undump_int(x);
+ if (x) {
+ /*tex right boundary */
+ i = undump_charinfo(f);
+ }
+ i = font_bc(f);
+ while (i < font_ec(f)) {
+ i = undump_charinfo(f);
+ }
+}
+
+/* The \PK\ pixel density value from |texmf.cnf| */
+
+int pk_dpi;
+
+/*tex
+
+ This one looks up the font for a \TFM\ with name |s| loaded at |fs| size and
+ if found then flushes |s|.
+
+*/
+
+internal_font_number tfm_lookup(char *s, scaled fs)
+{
+ internal_font_number k;
+ if (fs != 0) {
+ for (k = 1; k <= max_font_id(); k++) {
+ if (cmp_font_name(k, s) && font_size(k) == fs) {
+ return k;
+ }
+ }
+ } else {
+ for (k = 1; k <= max_font_id(); k++) {
+ if (cmp_font_name(k, s)) {
+ return k;
+ }
+ }
+ }
+ return null_font;
+}
+
+/*tex
+
+ This returns the multiple of |font_step(f)| that is nearest to |e|.
+
+*/
+
+int fix_expand_value(internal_font_number f, int e)
+{
+ int step;
+ int max_expand;
+ boolean neg;
+ if (e == 0)
+ return 0;
+ if (e < 0) {
+ e = -e;
+ neg = true;
+ max_expand = font_max_shrink(f);
+ } else {
+ neg = false;
+ max_expand = font_max_stretch(f);
+ }
+ if (e > max_expand) {
+ e = max_expand;
+ } else {
+ step = font_step(f);
+ if (e % step > 0)
+ e = step * round_xn_over_d(e, 1, step);
+ }
+ if (neg)
+ e = -e;
+ return e;
+}
+
+void set_expand_params(internal_font_number f, int stretch_limit, int shrink_limit, int font_step)
+{
+ set_font_step(f, font_step);
+ set_font_max_shrink(f, shrink_limit);
+ set_font_max_stretch(f, stretch_limit);
+}
+
+/*tex
+
+ This reads font expansion spec and load expanded font.
+
+*/
+
+void read_expand_font(void)
+{
+ int shrink_limit, stretch_limit, font_step;
+ internal_font_number f;
+ scan_font_ident();
+ f = cur_val;
+ if (f == null_font)
+ normal_error("font expansion", "invalid font identifier");
+ scan_optional_equals();
+ scan_int();
+ stretch_limit = fix_int(cur_val, 0, 1000);
+ scan_int();
+ shrink_limit = fix_int(cur_val, 0, 500);
+ scan_int();
+ font_step = fix_int(cur_val, 0, 100);
+ if (font_step == 0)
+ normal_error("font expansion", "invalid step");
+ stretch_limit = stretch_limit - stretch_limit % font_step;
+ if (stretch_limit < 0)
+ stretch_limit = 0;
+ shrink_limit = shrink_limit - shrink_limit % font_step;
+ if (shrink_limit < 0)
+ shrink_limit = 0;
+ if ((stretch_limit == 0) && (shrink_limit == 0))
+ normal_error("font expansion", "invalid limit(s)");
+ if (scan_keyword("autoexpand")) {
+ normal_warning("font expansion", "autoexpand not supported");
+ /*tex scan an optional space */
+ get_x_token();
+ if (cur_cmd != spacer_cmd)
+ back_input();
+ }
+ if (font_step(f) != 0) {
+ /*tex This font has been expanded, ensure the expansion parameters are identical. */
+ if (font_step(f) != font_step)
+ normal_error("font expansion","font has been expanded with different expansion step");
+ if (((font_max_stretch(f) == 0) && (stretch_limit != 0)) ||
+ ((font_max_stretch(f) > 0) && (font_max_stretch(f) != stretch_limit)))
+ normal_error("font expansion","font has been expanded with different stretch limit");
+
+ if (((font_max_shrink(f) == 0) && (shrink_limit != 0)) ||
+ ((font_max_shrink(f) > 0) && (font_max_shrink(f) != shrink_limit)))
+ normal_error("font expansion","font has been expanded with different shrink limit");
+ } else {
+ if (font_used(f))
+ normal_warning("font expansion", "font should be expanded before its first use");
+ set_expand_params(f, stretch_limit, shrink_limit, font_step);
+ }
+}
+
+/*tex
+
+ Here's an old (sort of obsolete) letterspace-a-font helper. It does so by by
+ creating a virtual font.
+
+*/
+
+void new_letterspaced_font(small_number a)
+{
+ pointer u;
+ str_number t;
+ internal_font_number f, k;
+ boolean nolig = false;
+ get_r_token();
+ u = cur_cs;
+ if (u >= hash_base)
+ t = cs_text(u);
+ else
+ t = maketexstring("FONT");
+ define(u, set_font_cmd, null_font);
+ scan_optional_equals();
+ scan_font_ident();
+ k = cur_val;
+ scan_int();
+ if (scan_keyword("nolig"))
+ nolig=true;
+ f = letter_space_font(k, fix_int(cur_val, -1000, 1000), nolig);
+ equiv(u) = f;
+ eqtb[font_id_base + f] = eqtb[u];
+ font_id_text(f) = t;
+}
+
+/*tex
+
+ This makes a font copy for further use with font expansion. Again a
+ traditional font related helper.
+
+*/
+
+void make_font_copy(small_number a)
+{
+ pointer u;
+ str_number t;
+ internal_font_number f, k;
+ get_r_token();
+ u = cur_cs;
+ if (u >= hash_base)
+ t = cs_text(u);
+ else
+ t = maketexstring("FONT");
+ define(u, set_font_cmd, null_font);
+ scan_optional_equals();
+ scan_font_ident();
+ k = cur_val;
+ f = copy_font_info(k);
+ equiv(u) = f;
+ eqtb[font_id_base + f] = eqtb[u];
+ font_id_text(f) = t;
+}
+
+void glyph_to_unicode(void)
+{
+ str_number s1, s2;
+ scan_toks(false, true);
+ s1 = tokens_to_string(def_ref);
+ delete_token_ref(def_ref);
+ scan_toks(false, true);
+ s2 = tokens_to_string(def_ref);
+ delete_token_ref(def_ref);
+ def_tounicode(s1, s2);
+ flush_str(s2);
+ flush_str(s1);
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/texfont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/texfont.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/texfont.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1972 +0,0 @@
-% texfont.w
-%
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@* Main font API implementation for the original pascal parts.
-
-Stuff to watch out for:
-
-\item{} Knuth had a |'null_character'| that was used when a character could
-not be found by the |fetch()| routine, to signal an error. This has
-been deleted, but it may mean that the output of luatex is
-incompatible with TeX after |fetch()| has detected an error condition.
-
-\item{} Knuth also had a |font_glue()| optimization. I've removed that
-because it was a bit of dirty programming and it also was
-problematic |if 0 != null|.
-
- at c
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-@ @c
-#define noDEBUG
-
-#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f))
-#define do_realloc(a,b,d) a = xrealloc(a,(unsigned)((unsigned)(b)*sizeof(d)))
-
-texfont **font_tables = NULL;
-
-static int font_arr_max = 0;
-static int font_id_maxval = 0;
-
-@ @c
-static void grow_font_table(int id)
-{
- int j;
- if (id >= font_arr_max) {
- font_bytes +=
- (int) (((id + 8 - font_arr_max) * (int) sizeof(texfont *)));
- font_tables =
- xrealloc(font_tables,
- (unsigned) (((unsigned) id + 8) * sizeof(texfont *)));
- j = 8;
- while (j--) {
- font_tables[id + j] = NULL;
- }
- font_arr_max = id + 8;
- }
-}
-
-int new_font_id(void)
-{
- int i;
- for (i = 0; i < font_arr_max; i++) {
- if (font_tables[i] == NULL) {
- break;
- }
- }
- if (i >= font_arr_max)
- grow_font_table(i);
- if (i > font_id_maxval)
- font_id_maxval = i;
- return i;
-}
-
-int max_font_id(void)
-{
- return font_id_maxval;
-}
-
-void set_max_font_id(int i)
-{
- font_id_maxval = i;
-}
-
-@ @c
-int new_font(void)
-{
- int k;
- int id;
- charinfo *ci;
- sa_tree_item sa_value = { 0 };
- id = new_font_id();
- font_bytes += (int) sizeof(texfont);
- /* most stuff is zero */
- font_tables[id] = xcalloc(1, sizeof(texfont));
- font_tables[id]->_font_name = NULL;
- font_tables[id]->_font_area = NULL;
- font_tables[id]->_font_filename = NULL;
- font_tables[id]->_font_fullname = NULL;
- font_tables[id]->_font_psname = NULL;
- font_tables[id]->_font_encodingname = NULL;
- font_tables[id]->_font_cidregistry = NULL;
- font_tables[id]->_font_cidordering = NULL;
- font_tables[id]->_left_boundary = NULL;
- font_tables[id]->_right_boundary = NULL;
- font_tables[id]->_param_base = NULL;
- font_tables[id]->_math_param_base = NULL;
-
- set_font_bc(id, 1); /* ec = 0 */
- set_font_writingmode(id, 0);
- set_font_identity(id, 0);
- set_hyphen_char(id, '-');
- set_skew_char(id, -1);
- font_slant(id) = 0; /* vertical */
- font_extend(id) = 1000; /* normal width */
-
- /* allocate eight values including 0 */
- set_font_params(id, 7);
- for (k = 0; k <= 7; k++) {
- set_font_param(id, k, 0);
- }
- /* character info zero is reserved for notdef */
- font_tables[id]->characters = new_sa_tree(1, 1, sa_value); /* stack size 1, default item value 0 */
- ci = xcalloc(1, sizeof(charinfo));
- set_charinfo_name(ci, xstrdup(".notdef"));
- font_tables[id]->charinfo = ci;
- font_tables[id]->charinfo_size = 1;
- font_tables[id]->charinfo_cache = NULL;
-
- return id;
-}
-
-@ @c
-void font_malloc_charinfo(internal_font_number f, int num)
-{
- int glyph = font_tables[f]->charinfo_size;
- font_bytes += (int) (num * (int) sizeof(charinfo));
- do_realloc(font_tables[f]->charinfo, (unsigned) (glyph + num), charinfo);
- memset(&(font_tables[f]->charinfo[glyph]), 0,
- (size_t) (num * (int) sizeof(charinfo)));
- font_tables[f]->charinfo_size += num;
-}
-
-@ @c
-#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
-
-charinfo *get_charinfo(internal_font_number f, int c)
-{
- int glyph;
- charinfo *ci;
- if (proper_char_index(c)) {
- glyph = get_sa_item(font_tables[f]->characters, c).int_value;
- if (!glyph) {
- sa_tree_item sa_value = { 0 };
- int tglyph = ++font_tables[f]->charinfo_count;
- if (tglyph >= font_tables[f]->charinfo_size) {
- font_malloc_charinfo(f, 256);
- }
- font_tables[f]->charinfo[tglyph].ef = 1000; /* init */
- sa_value.int_value = tglyph;
- set_sa_item(font_tables[f]->characters, c, sa_value, 1); /* 1 = global */
- glyph = tglyph;
- }
- return &(font_tables[f]->charinfo[glyph]);
- } else if (c == left_boundarychar) {
- if (left_boundary(f) == NULL) {
- ci = xcalloc(1, sizeof(charinfo));
- font_bytes += (int) sizeof(charinfo);
- set_left_boundary(f, ci);
- }
- return left_boundary(f);
- } else if (c == right_boundarychar) {
- if (right_boundary(f) == NULL) {
- ci = xcalloc(1, sizeof(charinfo));
- font_bytes += (int) sizeof(charinfo);
- set_right_boundary(f, ci);
- }
- return right_boundary(f);
- }
- return &(font_tables[f]->charinfo[0]);
-}
-
-@ @c
-static void set_charinfo(internal_font_number f, int c, charinfo * ci)
-{
- int glyph;
- if (proper_char_index(c)) {
- glyph = get_sa_item(font_tables[f]->characters, c).int_value;
- if (glyph) {
- font_tables[f]->charinfo[glyph] = *ci;
- } else {
- normal_error("font","character insertion failed");
- }
- } else if (c == left_boundarychar) {
- set_left_boundary(f, ci);
- } else if (c == right_boundarychar) {
- set_right_boundary(f, ci);
- }
-}
-
-@ @c
-charinfo *copy_charinfo(charinfo * ci)
-{
- int x, k;
- kerninfo *kern;
- liginfo *lig;
- eight_bits *packet;
- charinfo *co = NULL;
- if (ci == NULL)
- return NULL;
- co = xmalloc(sizeof(charinfo));
- memcpy(co, ci, sizeof(charinfo));
- set_charinfo_used(co, false);
- co->name = NULL;
- co->tounicode = NULL;
- co->packets = NULL;
- co->ligatures = NULL;
- co->kerns = NULL;
- co->vert_variants = NULL;
- co->hor_variants = NULL;
- if (ci->name != NULL) {
- co->name = xstrdup(ci->name);
- }
- if (ci->tounicode != NULL) {
- co->tounicode = xstrdup(ci->tounicode);
- }
- /* kerns */
- if ((kern = get_charinfo_kerns(ci)) != NULL) {
- x = 0;
- while (!kern_end(kern[x])) {
- x++;
- }
- x++;
- co->kerns = xmalloc((unsigned) (x * (int) sizeof(kerninfo)));
- memcpy(co->kerns, ci->kerns, (size_t) (x * (int) sizeof(kerninfo)));
- }
- /* ligs */
- if ((lig = get_charinfo_ligatures(ci)) != NULL) {
- x = 0;
- while (!lig_end(lig[x])) {
- x++;
- }
- x++;
- co->ligatures = xmalloc((unsigned) (x * (int) sizeof(liginfo)));
- memcpy(co->ligatures, ci->ligatures,
- (size_t) (x * (int) sizeof(liginfo)));
- }
- /* packets */
- if ((packet = get_charinfo_packets(ci)) != NULL) {
- x = vf_packet_bytes(ci);
- co->packets = xmalloc((unsigned) x);
- memcpy(co->packets, ci->packets, (size_t) x);
- }
-
- /* horizontal and vertical extenders */
- if (get_charinfo_vert_variants(ci) != NULL) {
- set_charinfo_vert_variants(co, copy_variants(get_charinfo_vert_variants(ci)));
- }
- if (get_charinfo_hor_variants(ci) != NULL) {
- set_charinfo_hor_variants(co, copy_variants(get_charinfo_hor_variants(ci)));
- }
- x = ci->top_left_math_kerns;
- co->top_left_math_kerns = x;
- if (x > 0) {
- co->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < co->top_left_math_kerns; k++) {
- co->top_left_math_kern_array[(2 * k)] = ci->top_left_math_kern_array[(2 * k)];
- co->top_left_math_kern_array[(2 * k) + 1] = ci->top_left_math_kern_array[(2 * k) + 1];
- }
- }
- x = ci->bottom_left_math_kerns;
- co->bottom_left_math_kerns = x;
- if (x > 0) {
- co->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < co->bottom_left_math_kerns; k++) {
- co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
- co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
- }
- }
- x = ci->top_right_math_kerns;
- co->top_right_math_kerns = x;
- if (x > 0) {
- co->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < co->top_right_math_kerns; k++) {
- co->top_right_math_kern_array[(2 * k)] = ci->top_right_math_kern_array[(2 * k)];
- co->top_right_math_kern_array[(2 * k) + 1] = ci->top_right_math_kern_array[(2 * k) + 1];
- }
- }
- x = ci->bottom_right_math_kerns;
- co->bottom_right_math_kerns = x;
- if (x > 0) {
- co->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < co->bottom_right_math_kerns; k++) {
- co->bottom_right_math_kern_array[(2 * k)] = ci->bottom_right_math_kern_array[(2 * k)];
- co->bottom_right_math_kern_array[(2 * k) + 1] = ci->bottom_right_math_kern_array[(2 * k) + 1];
- }
- }
- return co;
-}
-
-charinfo *char_info(internal_font_number f, int c)
-{
- if (f > font_id_maxval)
- return 0;
- if (proper_char_index(c)) {
- register int glyph = (int) find_charinfo_id(f, c);
- return &(font_tables[f]->charinfo[glyph]);
- } else if (c == left_boundarychar && left_boundary(f) != NULL) {
- return left_boundary(f);
- } else if (c == right_boundarychar && right_boundary(f) != NULL) {
- return right_boundary(f);
- }
- return &(font_tables[f]->charinfo[0]);
-}
-
-@ @c
-scaled_whd get_charinfo_whd(internal_font_number f, int c)
-{
- scaled_whd s;
- charinfo *i;
- i = char_info(f, c);
- s.wd = i->width;
- s.dp = i->depth;
- s.ht = i->height;
- return s;
-}
-
-@ @c
-int char_exists(internal_font_number f, int c)
-{
- if (f > font_id_maxval)
- return 0;
- if (proper_char_index(c)) {
- return (int) find_charinfo_id(f, c);
- } else if ((c == left_boundarychar) && has_left_boundary(f)) {
- return 1;
- } else if ((c == right_boundarychar) && has_right_boundary(f)) {
- return 1;
- }
- return 0;
-}
-
-@ @c
-int lua_glyph_not_found_callback(internal_font_number f, int c)
-{
- int callback_id;
- int ret = 0;
- callback_id = callback_defined(glyph_not_found_callback);
- if (callback_id != 0) {
- if (!get_callback(Luas, callback_id)) {
- lua_pop(Luas, 2);
- return 0;
- }
- lua_pushinteger(Luas, f);
- lua_pushinteger(Luas, c);
- if (lua_pcall(Luas, 2, 1, 0) != 0) { /* two args, 1 result */
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
- lua_pop(Luas, 2);
- error();
- } else {
- ret = lua_toboolean(Luas, -1);
- }
- } else {
- char_warning(f,c);
- }
- return ret;
-}
-
-@ @c
-extinfo *new_variant(int glyph, int startconnect, int endconnect,
- int advance, int repeater)
-{
- extinfo *ext;
- ext = xmalloc(sizeof(extinfo));
- ext->next = NULL;
- ext->glyph = glyph;
- ext->start_overlap = startconnect;
- ext->end_overlap = endconnect;
- ext->advance = advance;
- ext->extender = repeater;
- return ext;
-}
-
-
-@ @c
-static extinfo *copy_variant(extinfo * old)
-{
- extinfo *ext;
- ext = xmalloc(sizeof(extinfo));
- ext->next = NULL;
- ext->glyph = old->glyph;
- ext->start_overlap = old->start_overlap;
- ext->end_overlap = old->end_overlap;
- ext->advance = old->advance;
- ext->extender = old->extender;
- return ext;
-}
-
-@ @c
-static void dump_variant(extinfo * ext)
-{
- dump_int(ext->glyph);
- dump_int(ext->start_overlap);
- dump_int(ext->end_overlap);
- dump_int(ext->advance);
- dump_int(ext->extender);
- return;
-}
-
-
-@ @c
-static extinfo *undump_variant(void)
-{
- int x;
- extinfo *ext;
- undump_int(x);
- if (x == 0)
- return NULL;
- ext = xmalloc(sizeof(extinfo));
- ext->next = NULL;
- ext->glyph = x;
- undump_int(x);
- ext->start_overlap = x;
- undump_int(x);
- ext->end_overlap = x;
- undump_int(x);
- ext->advance = x;
- undump_int(x);
- ext->extender = x;
- return ext;
-}
-
-@ @c
-void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
-{
- if (ci->vert_variants == NULL) {
- ci->vert_variants = ext;
- } else {
- extinfo *lst = ci->vert_variants;
- while (lst->next != NULL)
- lst = lst->next;
- lst->next = ext;
- }
-
-}
-
-@ @c
-void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
-{
- if (ci->hor_variants == NULL) {
- ci->hor_variants = ext;
- } else {
- extinfo *lst = ci->hor_variants;
- while (lst->next != NULL)
- lst = lst->next;
- lst->next = ext;
- }
-
-}
-
-@ @c
-extinfo *copy_variants(extinfo * o)
-{
- extinfo *c, *t = NULL, *h = NULL;
- while (o != NULL) {
- c = copy_variant(o);
- if (h == null)
- h = c;
- else
- t->next = c;
- t = c;
- o = o->next;
- }
-
- return h;
-}
-
-@ @c
-static void dump_charinfo_variants(extinfo * o)
-{
- while (o != NULL) {
- dump_variant(o);
- o = o->next;
- }
- dump_int(0);
- return;
-}
-
-@ @c
-static extinfo *undump_charinfo_variants(void)
-{
- extinfo *c, *t = NULL, *h = NULL;
- c = undump_variant();
- while (c != NULL) {
- if (h == null)
- h = c;
- else
- t->next = c;
- t = c;
- c = undump_variant();
- }
- return h;
-}
-
-
-@ Note that mant more small things like this are implemented
-as macros in the header file.
- at c
-void set_charinfo_width(charinfo * ci, scaled val)
-{
- ci->width = val;
-}
-
-void set_charinfo_height(charinfo * ci, scaled val)
-{
- ci->height = val;
-}
-
-void set_charinfo_depth(charinfo * ci, scaled val)
-{
- ci->depth = val;
-}
-
-void set_charinfo_italic(charinfo * ci, scaled val)
-{
- ci->italic = val;
-}
-
-void set_charinfo_vert_italic(charinfo * ci, scaled val)
-{
- ci->vert_italic = val;
-}
-
-void set_charinfo_top_accent(charinfo * ci, scaled val)
-{
- ci->top_accent = val;
-}
-
-void set_charinfo_bot_accent(charinfo * ci, scaled val)
-{
- ci->bot_accent = val;
-}
-
-void set_charinfo_tag(charinfo * ci, scaled val)
-{
- ci->tag = (char) val;
-}
-
-void set_charinfo_remainder(charinfo * ci, scaled val)
-{
- ci->remainder = val;
-}
-
-void set_charinfo_used(charinfo * ci, scaled val)
-{
- ci->used = (char) val;
-}
-
-void set_charinfo_index(charinfo * ci, scaled val)
-{
- ci->index = (unsigned short) val;
-}
-
-void set_charinfo_name(charinfo * ci, char *val)
-{
- xfree(ci->name);
- ci->name = val;
-}
-
-void set_charinfo_tounicode(charinfo * ci, char *val)
-{
- xfree(ci->tounicode);
- ci->tounicode = val;
-}
-
-void set_charinfo_ligatures(charinfo * ci, liginfo * val)
-{
- dxfree(ci->ligatures, val);
-}
-
-void set_charinfo_kerns(charinfo * ci, kerninfo * val)
-{
- dxfree(ci->kerns, val);
-}
-
-void set_charinfo_packets(charinfo * ci, eight_bits * val)
-{
- dxfree(ci->packets, val);
-}
-
-void set_charinfo_ef(charinfo * ci, scaled val)
-{
- ci->ef = val;
-}
-
-void set_charinfo_lp(charinfo * ci, scaled val)
-{
- ci->lp = val;
-}
-
-void set_charinfo_rp(charinfo * ci, scaled val)
-{
- ci->rp = val;
-}
-
-@ @c
-void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
-{
- extinfo *c, *lst;
- if (ci->vert_variants != NULL) {
- lst = ci->vert_variants;
- while (lst != NULL) {
- c = lst->next;
- free(lst);
- lst = c;
- }
- }
- ci->vert_variants = ext;
-}
-
-@ @c
-void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
-{
- extinfo *c, *lst;
- if (ci->hor_variants != NULL) {
- lst = ci->hor_variants;
- while (lst != NULL) {
- c = lst->next;
- free(lst);
- lst = c;
- }
- }
- ci->hor_variants = ext;
-
-}
-
-@ @c
-int get_charinfo_math_kerns(charinfo * ci, int id)
-{
-
- int k = 0; /* all callers check for |result>0| */
- if (id == top_left_kern) {
- k = ci->top_left_math_kerns;
- } else if (id == bottom_left_kern) {
- k = ci->bottom_left_math_kerns;
- } else if (id == top_right_kern) {
- k = ci->top_right_math_kerns;
- } else if (id == bottom_right_kern) {
- k = ci->bottom_right_math_kerns;
- } else {
- confusion("get_charinfo_math_kerns");
- }
- return k;
-}
-
-@ @c
-void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
-{
- int k;
- if (id == top_left_kern) {
- k = ci->top_left_math_kerns;
- do_realloc(ci->top_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
- ci->top_left_math_kern_array[(2 * (k))] = ht;
- ci->top_left_math_kern_array[((2 * (k)) + 1)] = krn;
- ci->top_left_math_kerns++;
- } else if (id == bottom_left_kern) {
- k = ci->bottom_left_math_kerns;
- do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
- ci->bottom_left_math_kern_array[(2 * (k))] = ht;
- ci->bottom_left_math_kern_array[(2 * (k)) + 1] = krn;
- ci->bottom_left_math_kerns++;
- } else if (id == top_right_kern) {
- k = ci->top_right_math_kerns;
- do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
- ci->top_right_math_kern_array[(2 * (k))] = ht;
- ci->top_right_math_kern_array[(2 * (k)) + 1] = krn;
- ci->top_right_math_kerns++;
- } else if (id == bottom_right_kern) {
- k = ci->bottom_right_math_kerns;
- do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
- ci->bottom_right_math_kern_array[(2 * (k))] = ht;
- ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
- ci->bottom_right_math_kerns++;
- } else {
- confusion("add_charinfo_math_kern");
- }
-}
-
-
-@ @c
-static void dump_math_kerns(charinfo * ci)
-{
- int k, l;
- l = ci->top_left_math_kerns;
- dump_int(l);
- for (k = 0; k < l; k++) {
- dump_int(ci->top_left_math_kern_array[(2 * k)]);
- dump_int(ci->top_left_math_kern_array[(2 * k) + 1]);
- }
- l = ci->bottom_left_math_kerns;
- dump_int(l);
- for (k = 0; k < l; k++) {
- dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
- dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
- }
- l = ci->top_right_math_kerns;
- dump_int(l);
- for (k = 0; k < l; k++) {
- dump_int(ci->top_right_math_kern_array[(2 * k)]);
- dump_int(ci->top_right_math_kern_array[(2 * k) + 1]);
- }
- l = ci->bottom_right_math_kerns;
- dump_int(l);
- for (k = 0; k < l; k++) {
- dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
- dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
- }
-}
-
-@ @c
-static void undump_math_kerns(charinfo * ci)
-{
- int k;
- int x;
- undump_int(x);
- ci->top_left_math_kerns = x;
- if (x > 0)
- ci->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < ci->top_left_math_kerns; k++) {
- undump_int(x);
- ci->top_left_math_kern_array[(2 * k)] = (scaled) x;
- undump_int(x);
- ci->top_left_math_kern_array[(2 * k) + 1] = (scaled) x;
- }
- undump_int(x);
- ci->bottom_left_math_kerns = x;
- if (x > 0)
- ci->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < ci->bottom_left_math_kerns; k++) {
- undump_int(x);
- ci->bottom_left_math_kern_array[(2 * k)] = (scaled) x;
- undump_int(x);
- ci->bottom_left_math_kern_array[(2 * k) + 1] = (scaled) x;
- }
- undump_int(x);
- ci->top_right_math_kerns = x;
- if (x > 0)
- ci->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < ci->top_right_math_kerns; k++) {
- undump_int(x);
- ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
- undump_int(x);
- ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
- }
- undump_int(x);
- ci->bottom_right_math_kerns = x;
- if (x > 0)
- ci->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
- for (k = 0; k < ci->bottom_right_math_kerns; k++) {
- undump_int(x);
- ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
- undump_int(x);
- ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
- }
-}
-
-
-@ In TeX, extensibles were fairly simple things.
- This function squeezes a TFM extensible into the vertical extender structures.
- |advance==0| is a special case for TFM fonts, because finding the proper
- advance width during tfm reading can be tricky
-
-
- a small complication arises if |rep| is the only non-zero: it needs to be
- doubled as a non-repeatable to avoid mayhem */
-
- at c
-void set_charinfo_extensible(charinfo * ci, int top, int bot, int mid, int rep)
-{
- extinfo *ext;
- set_charinfo_vert_variants(ci, NULL); /* clear old */
- if (bot == 0 && top == 0 && mid == 0 && rep != 0) {
- ext = new_variant(rep, 0, 0, 0, EXT_NORMAL);
- add_charinfo_vert_variant(ci, ext);
- ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
- add_charinfo_vert_variant(ci, ext);
- return;
- }
- if (bot != 0) {
- ext = new_variant(bot, 0, 0, 0, EXT_NORMAL);
- add_charinfo_vert_variant(ci, ext);
- }
- if (rep != 0) {
- ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
- add_charinfo_vert_variant(ci, ext);
- }
- if (mid != 0) {
- ext = new_variant(mid, 0, 0, 0, EXT_NORMAL);
- add_charinfo_vert_variant(ci, ext);
- if (rep != 0) {
- ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
- add_charinfo_vert_variant(ci, ext);
- }
- }
- if (top != 0) {
- ext = new_variant(top, 0, 0, 0, EXT_NORMAL);
- add_charinfo_vert_variant(ci, ext);
- }
-}
-
-@ Note that many more simple things like this are implemented as macros
-in the header file.
-
- at c
-scaled get_charinfo_width(charinfo * ci)
-{
- return ci->width;
-}
-
-scaled get_charinfo_height(charinfo * ci)
-{
- return ci->height;
-}
-
-scaled get_charinfo_depth(charinfo * ci)
-{
- return ci->depth;
-}
-
-scaled get_charinfo_italic(charinfo * ci)
-{
- return ci->italic;
-}
-
-scaled get_charinfo_vert_italic(charinfo * ci)
-{
- return ci->vert_italic;
-}
-
-scaled get_charinfo_top_accent(charinfo * ci)
-{
- return ci->top_accent;
-}
-
-scaled get_charinfo_bot_accent(charinfo * ci)
-{
- return ci->bot_accent;
-}
-
-char get_charinfo_tag(charinfo * ci)
-{
- return ci->tag;
-}
-
-int get_charinfo_remainder(charinfo * ci)
-{
- return ci->remainder;
-}
-
-char get_charinfo_used(charinfo * ci)
-{
- return ci->used;
-}
-
-int get_charinfo_index(charinfo * ci)
-{
- return ci->index;
-}
-
-char *get_charinfo_name(charinfo * ci)
-{
- return ci->name;
-}
-
-char *get_charinfo_tounicode(charinfo * ci)
-{
- return ci->tounicode;
-}
-
-liginfo *get_charinfo_ligatures(charinfo * ci)
-{
- return ci->ligatures;
-}
-
-kerninfo *get_charinfo_kerns(charinfo * ci)
-{
- return ci->kerns;
-}
-
-eight_bits *get_charinfo_packets(charinfo * ci)
-{
- return ci->packets;
-}
-
-int get_charinfo_ef(charinfo * ci)
-{
- return ci->ef;
-}
-
-int get_charinfo_rp(charinfo * ci)
-{
- return ci->rp;
-}
-
-int get_charinfo_lp(charinfo * ci)
-{
- return ci->lp;
-}
-
-extinfo *get_charinfo_vert_variants(charinfo * ci)
-{
- extinfo *w = NULL;
- if (ci->vert_variants != NULL)
- w = ci->vert_variants;
- return w;
-}
-
-extinfo *get_charinfo_hor_variants(charinfo * ci)
-{
- extinfo *w = NULL;
- if (ci->hor_variants != NULL)
- w = ci->hor_variants;
- return w;
-}
-
-
-scaled char_width(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- scaled w = get_charinfo_width(ci);
- return w;
-}
-
-scaled calc_char_width(internal_font_number f, int c, int ex)
-{
- charinfo *ci = char_info(f, c);
- scaled w = get_charinfo_width(ci);
- if (ex != 0)
- w = round_xn_over_d(w, 1000 + ex, 1000);
- return w;
-}
-
-scaled char_depth(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- scaled d = get_charinfo_depth(ci);
- return d;
-}
-
-scaled char_height(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- scaled h = get_charinfo_height(ci);
- return h;
-}
-
-scaled char_italic(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- scaled i = get_charinfo_italic(ci);
- return i;
-}
-
-scaled char_vert_italic(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- scaled i = get_charinfo_vert_italic(ci);
- return i;
-}
-
-scaled char_top_accent(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_top_accent(ci);
-}
-
-scaled char_bot_accent(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_bot_accent(ci);
-}
-
-
-int char_remainder(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_remainder(ci);
-}
-
-char char_tag(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_tag(ci);
-}
-
-char char_used(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_used(ci);
-}
-
-char *char_name(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_name(ci);
-}
-
-int char_index(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_index(ci);
-}
-
-liginfo *char_ligatures(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_ligatures(ci);
-}
-
-kerninfo *char_kerns(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_kerns(ci);
-}
-
-eight_bits *char_packets(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_packets(ci);
-}
-
-@ @c
-void set_font_params(internal_font_number f, int b)
-{
- int i;
- i = font_params(f);
- if (i != b) {
- font_bytes +=
- (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
- do_realloc(param_base(f), (b + 2), int);
- font_params(f) = b;
- if (b > i) {
- while (i < b) {
- i++;
- set_font_param(f, i, 0);
- }
- }
- }
-}
-
-@ @c
-void set_font_math_params(internal_font_number f, int b)
-{
- int i;
- i = font_math_params(f);
- if (i != b) {
- font_bytes +=
- ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
- do_realloc(math_param_base(f), (b + 2), int);
- font_math_params(f) = b;
- if (b > i) {
- while (i < b) {
- i++;
- set_font_math_param(f, i, undefined_math_parameter);
- }
- }
- }
-}
-
-@ @c
-int copy_font(int f)
-{
- int i, ci_cnt, ci_size;
- charinfo *ci;
- int k = new_font();
-
- {
- ci = font_tables[k]->charinfo;
- ci_cnt = font_tables[k]->charinfo_count;
- ci_size = font_tables[k]->charinfo_size;
- memcpy(font_tables[k], font_tables[f], sizeof(texfont));
- font_tables[k]->charinfo = ci;
- font_tables[k]->charinfo_count = ci_cnt;
- font_tables[k]->charinfo_size = ci_size;
- }
-
- font_malloc_charinfo(k, font_tables[f]->charinfo_count);
- set_font_cache_id(k, 0);
- set_font_used(k, 0);
- set_font_touched(k, 0);
-
- font_tables[k]->_font_name = NULL;
- font_tables[k]->_font_filename = NULL;
- font_tables[k]->_font_fullname = NULL;
- font_tables[k]->_font_psname = NULL;
- font_tables[k]->_font_encodingname = NULL;
- font_tables[k]->_font_area = NULL;
- font_tables[k]->_font_cidregistry = NULL;
- font_tables[k]->_font_cidordering = NULL;
- font_tables[k]->_left_boundary = NULL;
- font_tables[k]->_right_boundary = NULL;
-
- set_font_name(k, xstrdup(font_name(f)));
- if (font_filename(f) != NULL)
- set_font_filename(k, xstrdup(font_filename(f)));
- if (font_fullname(f) != NULL)
- set_font_fullname(k, xstrdup(font_fullname(f)));
- if (font_psname(f) != NULL)
- set_font_psname(k, xstrdup(font_psname(f)));
- if (font_encodingname(f) != NULL)
- set_font_encodingname(k, xstrdup(font_encodingname(f)));
- if (font_area(f) != NULL)
- set_font_area(k, xstrdup(font_area(f)));
- if (font_cidregistry(f) != NULL)
- set_font_cidregistry(k, xstrdup(font_cidregistry(f)));
- if (font_cidordering(f) != NULL)
- set_font_cidordering(k, xstrdup(font_cidordering(f)));
-
- i = (int) (sizeof(*param_base(f)) * (unsigned) (font_params(f)+1));
- font_bytes += i;
- param_base(k) = xmalloc((unsigned) (i+1));
- memcpy(param_base(k), param_base(f), (size_t) (i));
-
- if (font_math_params(f) > 0) {
- i = (int) (sizeof(*math_param_base(f)) *
- (unsigned) font_math_params(f));
- font_bytes += i;
- math_param_base(k) = xmalloc((unsigned) i);
- memcpy(math_param_base(k), math_param_base(f), (size_t) i);
- }
-
- for (i = 0; i <= font_tables[f]->charinfo_count; i++) {
- ci = copy_charinfo(&font_tables[f]->charinfo[i]);
- font_tables[k]->charinfo[i] = *ci;
- }
-
- if (left_boundary(f) != NULL) {
- ci = copy_charinfo(left_boundary(f));
- set_charinfo(k, left_boundarychar, ci);
- }
-
- if (right_boundary(f) != NULL) {
- ci = copy_charinfo(right_boundary(f));
- set_charinfo(k, right_boundarychar, ci);
- }
- /* not updated yet: */
- font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
- return k;
-}
-
-@ @c
-void delete_font(int f)
-{
- int i;
- charinfo *co;
- assert(f > 0);
- if (font_tables[f] != NULL) {
- set_font_name(f, NULL);
- set_font_filename(f, NULL);
- set_font_fullname(f, NULL);
- set_font_psname(f, NULL);
- set_font_encodingname(f, NULL);
- set_font_area(f, NULL);
- set_font_cidregistry(f, NULL);
- set_font_cidordering(f, NULL);
- set_left_boundary(f, NULL);
- set_right_boundary(f, NULL);
-
- for (i = font_bc(f); i <= font_ec(f); i++) {
- if (quick_char_exists(f, i)) {
- co = char_info(f, i);
- set_charinfo_name(co, NULL);
- set_charinfo_tounicode(co, NULL);
- set_charinfo_packets(co, NULL);
- set_charinfo_ligatures(co, NULL);
- set_charinfo_kerns(co, NULL);
- set_charinfo_vert_variants(co, NULL);
- set_charinfo_hor_variants(co, NULL);
- }
- }
- /* free .notdef */
- set_charinfo_name(font_tables[f]->charinfo + 0, NULL);
- free(font_tables[f]->charinfo);
- destroy_sa_tree(font_tables[f]->characters);
-
- free(param_base(f));
- if (math_param_base(f) != NULL)
- free(math_param_base(f));
- free(font_tables[f]);
- font_tables[f] = NULL;
-
- if (font_id_maxval == f) {
- font_id_maxval--;
- }
- }
-}
-
-@ @c
-void create_null_font(void)
-{
- int i = new_font();
- assert(i == 0);
- set_font_name(i, xstrdup("nullfont"));
- set_font_area(i, xstrdup(""));
- set_font_touched(i, 1);
-}
-
-@ @c
-boolean is_valid_font(int id)
-{
- int ret = 0;
- if (id >= 0 && id <= font_id_maxval && font_tables[id] != NULL)
- ret = 1;
- return ret;
-}
-
-@ @c
-boolean cmp_font_area(int id, str_number t)
-{
- char *tt = NULL;
- char *tid = font_area(id);
- if (t == 0) {
- if (tid == NULL || strlen(tid) == 0)
- return 1;
- else
- return 0;
- }
- tt = makecstring(t);
- if ((tt == NULL || strlen(tt) == 0) && (tid == NULL || strlen(tid) == 0))
- return 1;
- if (tt == NULL || strcmp(tid, tt) != 0)
- return 0;
- free(tt);
- return 1;
-}
-
-@ Here come some subroutines to deal with expanded fonts for HZ-algorithm.
-return 1 == identical
- at c
-static boolean cmp_font_name(int id, char *tt)
-{
- char *tid;
- if (!is_valid_font(id))
- return 0;
- tid = font_name(id);
- if (tt == NULL && tid == NULL)
- return 1;
- if (tt == NULL || tid == NULL || strcmp(tid, tt) != 0)
- return 0;
- return 1;
-}
-
-@ @c
-int test_no_ligatures(internal_font_number f)
-{
- int c;
- for (c = font_bc(f); c <= font_ec(f); c++) {
- if (has_lig(f, c)) /* |char_exists(f,c)| */
- return 0;
- }
- return 1;
-}
-
-@ @c
-int get_tag_code(internal_font_number f, int c)
-{
- small_number i;
- if (char_exists(f, c)) {
- i = char_tag(f, c);
- if (i == lig_tag)
- return 1;
- else if (i == list_tag)
- return 2;
- else if (i == ext_tag)
- return 4;
- else
- return 0;
- }
- return -1;
-}
-
-@ @c
-int get_lp_code(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_lp(ci);
-}
-
-int get_rp_code(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_rp(ci);
-}
-
-int get_ef_code(internal_font_number f, int c)
-{
- charinfo *ci = char_info(f, c);
- return get_charinfo_ef(ci);
-}
-
-@ @c
-void set_tag_code(internal_font_number f, int c, int i)
-{
- int fixedi;
- charinfo *co;
- if (char_exists(f, c)) {
- /* |abs(fix_int(i-7,0))| */
- fixedi = -(i < -7 ? -7 : (i > 0 ? 0 : i));
- co = char_info(f, c);
- if (fixedi >= 4) {
- if (char_tag(f, c) == ext_tag)
- set_charinfo_tag(co, (char_tag(f, c) - ext_tag));
- fixedi = fixedi - 4;
- }
- if (fixedi >= 2) {
- if (char_tag(f, c) == list_tag)
- set_charinfo_tag(co, (char_tag(f, c) - list_tag));
- fixedi = fixedi - 2;
- };
- if (fixedi >= 1) {
- if (has_lig(f, c))
- set_charinfo_ligatures(co, NULL);
- if (has_kern(f, c))
- set_charinfo_kerns(co, NULL);
- }
- }
-}
-
-@ @c
-void set_lp_code(internal_font_number f, int c, int i)
-{
- charinfo *co;
- if (char_exists(f, c)) {
- co = char_info(f, c);
- set_charinfo_lp(co, i);
- }
-}
-
-void set_rp_code(internal_font_number f, int c, int i)
-{
- charinfo *co;
- if (char_exists(f, c)) {
- co = char_info(f, c);
- set_charinfo_rp(co, i);
- }
-}
-
-void set_ef_code(internal_font_number f, int c, int i)
-{
- charinfo *co;
- if (char_exists(f, c)) {
- co = char_info(f, c);
- set_charinfo_ef(co, i);
- }
-}
-
-@ @c
-void set_no_ligatures(internal_font_number f)
-{
- int c;
- charinfo *co;
- if (font_tables[f]->ligatures_disabled)
- return;
- co = char_info(f, left_boundarychar);
- set_charinfo_ligatures(co, NULL);
- co = char_info(f, right_boundarychar); /* this is weird */
- set_charinfo_ligatures(co, NULL);
- for (c = 0; c < font_tables[f]->charinfo_count; c++) {
- co = font_tables[f]->charinfo + c;
- set_charinfo_ligatures(co, NULL);
- }
- font_tables[f]->ligatures_disabled = 1;
-}
-
-@ @c
-liginfo get_ligature(internal_font_number f, int lc, int rc)
-{
- int k = 0;
- liginfo t, u;
- charinfo *co;
- t.lig = 0;
- t.type = 0;
- t.adj = 0;
- if (lc == non_boundarychar || rc == non_boundarychar || (!has_lig(f, lc)))
- return t;
- co = char_info(f, lc);
- while (1) {
- u = charinfo_ligature(co, k);
- if (lig_end(u))
- break;
- if (lig_char(u) == rc) {
- if (lig_disabled(u)) {
- return t;
- } else {
- return u;
- }
- }
- k++;
- }
- return t;
-}
-
-@ @c
-scaled raw_get_kern(internal_font_number f, int lc, int rc)
-{
- int k = 0;
- kerninfo u;
- charinfo *co;
- if (lc == non_boundarychar || rc == non_boundarychar)
- return 0;
- co = char_info(f, lc);
- while (1) {
- u = charinfo_kern(co, k);
- if (kern_end(u))
- break;
- if (kern_char(u) == rc) {
- if (kern_disabled(u))
- return 0;
- else
- return kern_kern(u);
- }
- k++;
- }
- return 0;
-}
-
-@ @c
-scaled get_kern(internal_font_number f, int lc, int rc)
-{
- if (lc == non_boundarychar || rc == non_boundarychar || (!has_kern(f, lc)))
- return 0;
- return raw_get_kern(f, lc, rc);
-}
-
-
-@ dumping and undumping fonts
-
- at c
-#define dump_string(a) \
- if (a!=NULL) { \
- x = (int)(strlen(a)+1); \
- dump_int(x); dump_things(*a, x); \
- } else { \
- x = 0; dump_int(x); \
- }
-
-static void dump_charinfo(int f, int c)
-{
- charinfo *co;
- int x;
- liginfo *lig;
- kerninfo *kern;
- dump_int(c);
- co = char_info(f, c);
- set_charinfo_used(co, 0);
- dump_int(get_charinfo_width(co));
- dump_int(get_charinfo_height(co));
- dump_int(get_charinfo_depth(co));
- dump_int(get_charinfo_italic(co));
- dump_int(get_charinfo_vert_italic(co));
- dump_int(get_charinfo_top_accent(co));
- dump_int(get_charinfo_bot_accent(co));
- dump_int(get_charinfo_tag(co));
- dump_int(get_charinfo_ef(co));
- dump_int(get_charinfo_rp(co));
- dump_int(get_charinfo_lp(co));
- dump_int(get_charinfo_remainder(co));
- dump_int(get_charinfo_used(co));
- dump_int(get_charinfo_index(co));
- dump_string(get_charinfo_name(co));
- dump_string(get_charinfo_tounicode(co));
-
- /* ligatures */
- x = 0;
- if ((lig = get_charinfo_ligatures(co)) != NULL) {
- while (!lig_end(lig[x])) {
- x++;
- }
- x++;
- dump_int(x);
- dump_things(*lig, x);
- } else {
- dump_int(x);
- }
- /* kerns */
- x = 0;
- if ((kern = get_charinfo_kerns(co)) != NULL) {
- while (!kern_end(kern[x])) {
- x++;
- }
- x++;
- dump_int(x);
- dump_things(*kern, x);
- } else {
- dump_int(x);
- }
- /* packets */
- x = vf_packet_bytes(co);
- dump_int(x);
- if (x > 0) {
- dump_things(*get_charinfo_packets(co), x);
- }
-
- if (get_charinfo_tag(co) == ext_tag) {
- dump_charinfo_variants(get_charinfo_vert_variants(co));
- dump_charinfo_variants(get_charinfo_hor_variants(co));
- }
- dump_math_kerns(co);
-}
-
-static void dump_font_entry(texfont * f)
-{
- int x;
- dump_int(f->_font_size);
- dump_int(f->_font_dsize);
- dump_int(f->_font_cidversion);
- dump_int(f->_font_cidsupplement);
- dump_int(f->_font_ec);
- x = (int) f->_font_checksum;
- dump_int(x);
- dump_int(f->_font_used);
- dump_int(f->_font_touched);
- dump_int(f->_font_cache_id);
- dump_int(f->_font_encodingbytes);
- dump_int(f->_font_oldmath);
- dump_int(f->_font_slant);
- dump_int(f->_font_extend);
- dump_int(f->font_max_shrink);
- dump_int(f->font_max_stretch);
- dump_int(f->_font_step);
- dump_int(f->_font_tounicode);
- dump_int(f->_font_type);
- dump_int(f->_font_format);
- dump_int(f->_font_writingmode);
- dump_int(f->_font_identity);
- dump_int(f->_font_embedding);
- dump_int(f->_font_streamprovider);
- dump_int(f->_font_bc);
- dump_int(f->_hyphen_char);
- dump_int(f->_skew_char);
- dump_int(f->_font_natural_dir);
- dump_int(f->_font_params);
- dump_int(f->_font_math_params);
- dump_int(f->ligatures_disabled);
- dump_int(f->_pdf_font_num);
- dump_int(f->_pdf_font_attr);
-}
-
-void dump_font(int f)
-{
- int i, x;
-
- set_font_used(f, 0);
- font_tables[f]->charinfo_cache = NULL;
- dump_font_entry(font_tables[f]);
- dump_string(font_name(f));
- dump_string(font_area(f));
- dump_string(font_filename(f));
- dump_string(font_fullname(f));
- dump_string(font_psname(f));
- dump_string(font_encodingname(f));
- dump_string(font_cidregistry(f));
- dump_string(font_cidordering(f));
-
- dump_things(*param_base(f), (font_params(f) + 1));
-
- if (font_math_params(f) > 0) {
- dump_things(*math_param_base(f), (font_math_params(f) + 1 ));
- }
- if (has_left_boundary(f)) {
- dump_int(1);
- dump_charinfo(f, left_boundarychar);
- } else {
- dump_int(0);
- }
- if (has_right_boundary(f)) {
- dump_int(1);
- dump_charinfo(f, right_boundarychar);
- } else {
- dump_int(0);
- }
-
- for (i = font_bc(f); i <= font_ec(f); i++) {
- if (quick_char_exists(f, i)) {
- dump_charinfo(f, i);
- }
- }
-}
-
-@ @c
-static int undump_charinfo(int f)
-{
- charinfo *co;
- int x, i;
- char *s = NULL;
- liginfo *lig = NULL;
- kerninfo *kern = NULL;
- eight_bits *packet = NULL;
-
- undump_int(i);
- co = get_charinfo(f, i);
- undump_int(x);
- set_charinfo_width(co, x);
- undump_int(x);
- set_charinfo_height(co, x);
- undump_int(x);
- set_charinfo_depth(co, x);
- undump_int(x);
- set_charinfo_italic(co, x);
- undump_int(x);
- set_charinfo_vert_italic(co, x);
- undump_int(x);
- set_charinfo_top_accent(co, x);
- undump_int(x);
- set_charinfo_bot_accent(co, x);
- undump_int(x);
- set_charinfo_tag(co, x);
- undump_int(x);
- set_charinfo_ef(co, x);
- undump_int(x);
- set_charinfo_rp(co, x);
- undump_int(x);
- set_charinfo_lp(co, x);
- undump_int(x);
- set_charinfo_remainder(co, x);
- undump_int(x);
- set_charinfo_used(co, x);
- undump_int(x);
- set_charinfo_index(co, x);
-
- /* name */
- undump_int(x);
- if (x > 0) {
- font_bytes += x;
- s = xmalloc((unsigned) x);
- undump_things(*s, x);
- }
- set_charinfo_name(co, s);
- /* tounicode */
- undump_int(x);
- if (x > 0) {
- font_bytes += x;
- s = xmalloc((unsigned) x);
- undump_things(*s, x);
- }
- set_charinfo_tounicode(co, s);
- /* ligatures */
- undump_int(x);
- if (x > 0) {
- font_bytes += (int) ((unsigned) x * sizeof(liginfo));
- lig = xmalloc((unsigned) ((unsigned) x * sizeof(liginfo)));
- undump_things(*lig, x);
- }
- set_charinfo_ligatures(co, lig);
- /* kerns */
- undump_int(x);
- if (x > 0) {
- font_bytes += (int) ((unsigned) x * sizeof(kerninfo));
- kern = xmalloc((unsigned) ((unsigned) x * sizeof(kerninfo)));
- undump_things(*kern, x);
- }
- set_charinfo_kerns(co, kern);
-
- /* packets */
- undump_int(x);
- if (x > 0) {
- font_bytes += x;
- packet = xmalloc((unsigned) x);
- undump_things(*packet, x);
- }
- set_charinfo_packets(co, packet);
-
- if (get_charinfo_tag(co) == ext_tag) {
- set_charinfo_vert_variants(co, undump_charinfo_variants());
- set_charinfo_hor_variants(co, undump_charinfo_variants());
- }
- undump_math_kerns(co);
- return i;
-}
-
-#define undump_font_string(a) \
- undump_int (x); \
- if (x>0) { \
- font_bytes += x; \
- s = xmalloc((unsigned)x); \
- undump_things(*s,x); \
- a(f,s); \
- }
-
-static void undump_font_entry(texfont * f)
-{
- int x = 0;
- /* *INDENT-OFF* */
- undump_int(x); f->_font_size = x;
- undump_int(x); f->_font_dsize = x;
- undump_int(x); f->_font_cidversion = x;
- undump_int(x); f->_font_cidsupplement = x;
- undump_int(x); f->_font_ec = x;
- undump_int(x); f->_font_checksum = (unsigned)x;
- undump_int(x); f->_font_used = (char)x;
- undump_int(x); f->_font_touched = (char)x;
- undump_int(x); f->_font_cache_id = x;
- undump_int(x); f->_font_encodingbytes = (char)x;
- undump_int(x); f->_font_oldmath = x;
- undump_int(x); f->_font_slant = x;
- undump_int(x); f->_font_extend = x;
- undump_int(x); f->font_max_shrink = x;
- undump_int(x); f->font_max_stretch = x;
- undump_int(x); f->_font_step = x;
- undump_int(x); f->_font_tounicode = (char)x;
- undump_int(x); f->_font_type = x;
- undump_int(x); f->_font_format = x;
- undump_int(x); f->_font_writingmode = x;
- undump_int(x); f->_font_identity = x;
- undump_int(x); f->_font_embedding = x;
- undump_int(x); f->_font_streamprovider = x;
- undump_int(x); f->_font_bc = x;
- undump_int(x); f->_hyphen_char = x;
- undump_int(x); f->_skew_char = x;
- undump_int(x); f->_font_natural_dir = x;
- undump_int(x); f->_font_params = x;
- undump_int(x); f->_font_math_params = x;
- undump_int(x); f->ligatures_disabled = x;
- undump_int(x); f->_pdf_font_num = x;
- undump_int(x); f->_pdf_font_attr = x;
- /* *INDENT-ON* */
-}
-
-void undump_font(int f)
-{
- int x, i;
- texfont *tt;
- charinfo *ci;
- char *s;
- sa_tree_item sa_value = { 0 };
- grow_font_table(f);
- tt = xmalloc(sizeof(texfont));
- memset(tt, 0, sizeof(texfont));
- font_bytes += (int) sizeof(texfont);
- undump_font_entry(tt);
- font_tables[f] = tt;
-
- undump_font_string(set_font_name);
- undump_font_string(set_font_area);
- undump_font_string(set_font_filename);
- undump_font_string(set_font_fullname);
- undump_font_string(set_font_psname);
- undump_font_string(set_font_encodingname);
- undump_font_string(set_font_cidregistry);
- undump_font_string(set_font_cidordering);
-
- i = (int) (sizeof(*param_base(f)) * ((unsigned) font_params(f) + 1));
- font_bytes += i;
- param_base(f) = xmalloc((unsigned) i);
- undump_things(*param_base(f), (font_params(f) + 1));
-
- if (font_math_params(f) > 0) {
- i = (int) (sizeof(*math_param_base(f)) *
- ((unsigned) font_math_params(f) + 1));
- font_bytes += i;
- math_param_base(f) = xmalloc((unsigned) i);
- undump_things(*math_param_base(f), (font_math_params(f) + 1));
- }
-
- /* stack size 1, default item value 0 */
- font_tables[f]->characters = new_sa_tree(1, 1, sa_value);
- ci = xcalloc(1, sizeof(charinfo));
- set_charinfo_name(ci, xstrdup(".notdef"));
- font_tables[f]->charinfo = ci;
- undump_int(x);
- if (x) {
- i = undump_charinfo(f); /* left boundary */
- }
- undump_int(x);
- if (x) {
- i = undump_charinfo(f); /* right boundary */
- }
-
- i = font_bc(f);
- while (i < font_ec(f)) {
- i = undump_charinfo(f);
- }
-}
-
-/* moved from pdffont.w */
-
-@ @c
-int pk_dpi; /* PK pixel density value from \.{texmf.cnf} */
-
-@ @c
-internal_font_number tfm_lookup(char *s, scaled fs)
-{ /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
- internal_font_number k;
- if (fs != 0) {
- for (k = 1; k <= max_font_id(); k++) {
- if (cmp_font_name(k, s) && font_size(k) == fs) {
- return k;
- }
- }
- } else {
- for (k = 1; k <= max_font_id(); k++) {
- if (cmp_font_name(k, s)) {
- return k;
- }
- }
- }
- return null_font;
-}
-
-@ @c
-int fix_expand_value(internal_font_number f, int e)
-{ /* return the multiple of |font_step(f)| that is nearest to |e| */
- int step;
- int max_expand;
- boolean neg;
- if (e == 0)
- return 0;
- if (e < 0) {
- e = -e;
- neg = true;
- max_expand = font_max_shrink(f);
- } else {
- neg = false;
- max_expand = font_max_stretch(f);
- }
- if (e > max_expand) {
- e = max_expand;
- } else {
- step = font_step(f);
- if (e % step > 0)
- e = step * round_xn_over_d(e, 1, step);
- }
- if (neg)
- e = -e;
- return e;
-}
-
-@ @c
-void set_expand_params(internal_font_number f, int stretch_limit, int shrink_limit, int font_step)
-{
- set_font_step(f, font_step);
- set_font_max_shrink(f, shrink_limit);
- set_font_max_stretch(f, stretch_limit);
-}
-
-@ @c
-void read_expand_font(void)
-{ /* read font expansion spec and load expanded font */
- int shrink_limit, stretch_limit, font_step;
- internal_font_number f;
- /* read font expansion parameters */
- scan_font_ident();
- f = cur_val;
- if (f == null_font)
- normal_error("font expansion", "invalid font identifier");
- /*if (pdf_font_blink(f) != null_font)*/
- /* normal_error("font expansion",*/
- /* "\\fontexpand cannot be used this way (the base font has been expanded)");*/
- scan_optional_equals();
- scan_int();
- stretch_limit = fix_int(cur_val, 0, 1000);
- scan_int();
- shrink_limit = fix_int(cur_val, 0, 500);
- scan_int();
- font_step = fix_int(cur_val, 0, 100);
- if (font_step == 0)
- normal_error("font expansion", "invalid step");
- stretch_limit = stretch_limit - stretch_limit % font_step;
- if (stretch_limit < 0)
- stretch_limit = 0;
- shrink_limit = shrink_limit - shrink_limit % font_step;
- if (shrink_limit < 0)
- shrink_limit = 0;
- if ((stretch_limit == 0) && (shrink_limit == 0))
- normal_error("font expansion", "invalid limit(s)");
- if (scan_keyword("autoexpand")) {
- normal_warning("font expansion", "autoexpand not supported");
- /* Scan an optional space */
- get_x_token();
- if (cur_cmd != spacer_cmd)
- back_input();
- }
- if (font_step(f) != 0) {
- /* this font has been expanded, ensure the expansion parameters are identical */
- if (font_step(f) != font_step)
- normal_error("font expansion","font has been expanded with different expansion step");
-
- if (((font_max_stretch(f) == 0) && (stretch_limit != 0)) ||
- ((font_max_stretch(f) > 0)
- && (font_max_stretch(f) != stretch_limit)))
- normal_error("font expansion","font has been expanded with different stretch limit");
-
- if (((font_max_shrink(f) == 0) && (shrink_limit != 0)) ||
- ((font_max_shrink(f) > 0)
- && (font_max_shrink(f) != shrink_limit)))
- normal_error("font expansion","font has been expanded with different shrink limit");
- } else {
- if (font_used(f))
- normal_warning("font expansion", "font should be expanded before its first use");
- set_expand_params(f, stretch_limit, shrink_limit, font_step);
- }
-}
-
-@ @c
-void new_letterspaced_font(small_number a)
-{ /* letter-space a font by creating a virtual font */
- pointer u; /* user's font identifier */
- str_number t; /* name for the frozen font identifier */
- internal_font_number f, k;
- boolean nolig = false;
- get_r_token();
- u = cur_cs;
- if (u >= hash_base)
- t = cs_text(u);
- else
- t = maketexstring("FONT");
- define(u, set_font_cmd, null_font);
- scan_optional_equals();
- scan_font_ident();
- k = cur_val;
- scan_int();
- if (scan_keyword("nolig"))
- nolig=true;
- f = letter_space_font(k, fix_int(cur_val, -1000, 1000), nolig);
- equiv(u) = f;
- eqtb[font_id_base + f] = eqtb[u];
- font_id_text(f) = t;
-}
-
-@ @c
-void make_font_copy(small_number a)
-{ /* make a font copy for further use with font expansion */
- pointer u; /* user's font identifier */
- str_number t; /* name for the frozen font identifier */
- internal_font_number f, k;
- get_r_token();
- u = cur_cs;
- if (u >= hash_base)
- t = cs_text(u);
- else
- t = maketexstring("FONT");
- define(u, set_font_cmd, null_font);
- scan_optional_equals();
- scan_font_ident();
- k = cur_val;
- f = copy_font_info(k);
- equiv(u) = f;
- eqtb[font_id_base + f] = eqtb[u];
- font_id_text(f) = t;
-}
-
-@ @c
-void glyph_to_unicode(void)
-{
- str_number s1, s2;
- scan_toks(false, true);
- s1 = tokens_to_string(def_ref);
- delete_token_ref(def_ref);
- scan_toks(false, true);
- s2 = tokens_to_string(def_ref);
- delete_token_ref(def_ref);
- def_tounicode(s1, s2);
- flush_str(s2);
- flush_str(s1);
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1186 @@
+/*
+
+Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex Here are some macros that help process ligatures and kerns */
+
+#define lig_kern_start(f,c) char_remainder(f,c)
+
+/*tex A value indicating |STOP| in a lig/kern program: */
+
+#define stop_flag 128
+
+/*tex The op code for a kern step: */
+
+#define kern_flag 128
+
+#define skip_byte(z) lig_kerns[z].b0
+#define next_char(z) lig_kerns[z].b1
+#define op_byte(z) lig_kerns[z].b2
+#define rem_byte(z) lig_kerns[z].b3
+#define lig_kern_restart(c) (256*op_byte(c)+rem_byte(c))
+
+
+/*tex
+
+ The information in a \TFM\file appears in a sequence of 8-bit bytes. Since
+ the number of bytes is always a multiple of 4, we could also regard the file
+ as a sequence of 32-bit words, but \TeX\ uses the byte interpretation. The
+ format of \TFM\files was designed by Lyle Ramshaw in 1980. The intent is
+ to convey a lot of different kinds of information in a compact but useful
+ form.
+
+ $\Omega$ is capable of reading not only \TFM\files, but also \.{OFM}
+ files, which can describe fonts with up to 65536 characters and with huge
+ lig/kern tables. These fonts will often be virtual fonts built up from real
+ fonts with 256 characters, but $\Omega$ is not aware of this.
+
+ The documentation below describes \TFM\files, with slight additions to
+ show where \.{OFM} files differ.
+
+ The first 24 bytes (6 words) of a \TFM\file contain twelve 16-bit integers
+ that give the lengths of the various subsequent portions of the file. These
+ twelve integers are, in order:
+
+ \starttabulate
+ \NC \type {lf| \NC length of the entire file, in words \NC \NR
+ \NC \type {lh| \NC length of the header data, in words \NC \NR
+ \NC \type {bc| \NC smallest character code in the font \NC \NR
+ \NC \type {ec| \NC largest character code in the font \NC \NR
+ \NC \type {nw| \NC number of words in the width table \NC \NR
+ \NC \type {nh| \NC number of words in the height table \NC \NR
+ \NC \type {nd| \NC number of words in the depth table \NC \NR
+ \NC \type {ni| \NC number of words in the italic correction table \NC \NR
+ \NC \type {nl| \NC number of words in the lig/kern table \NC \NR
+ \NC \type {nk| \NC number of words in the kern table \NC \NR
+ \NC \type {ne| \NC number of words in the extensible character table \NC \NR
+ \NC \type {np| \NC number of font parameter words \NC \NR
+ \stoptabulate
+
+ They are all nonnegative and less than $2^{15}$. We must have
+ |bc-1<=ec<=255|, and $|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|$. Note that
+ a \TFM\font may contain as many as 256 characters (if |bc=0| and
+ |ec=255|), and as few as 0 characters (if |bc=ec+1|).
+
+ Incidentally, when two or more 8-bit bytes are combined to form an integer of
+ 16 or more bits, the most significant bytes appear first in the file. This is
+ called BigEndian order.
+
+ The first 52 bytes (13 words) of an \.{OFM} file contains thirteen 32-bit
+ integers that give the lengths of the various subsequent portions of the
+ file. The first word is 0 (future versions of \.{OFM} files could have
+ different values; what is important is that the first two bytes be 0 to
+ differentiate \TFM\and \.{OFM} files). The next twelve integers are as
+ above, all nonegative and less than~$2^{31}$. We must have |bc-1<=ec<=65535|,
+ and $$\hbox{|lf=13+lh+2*(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$ Note that an
+ \.{OFM} font may contain as many as 65536 characters (if |bc=0| and
+ |ec=65535|), and as few as 0 characters (if |bc=ec+1|).
+
+ The rest of the \TFM\file may be regarded as a sequence of ten data arrays
+ having the informal specification
+
+ \starttabulate
+ \NC \type {header} \NC \type {[0..lh-1]} \NC \type {stuff} \NC \NR
+ \NC \type {char\_info} \NC \type {[bc..ec]} \NC \type {char_info_word} \NC \NR
+ \NC \type {width} \NC \type {[0..nw-1]} \NC \type {fix_word} \NC \NR
+ \NC \type {height} \NC \type {[0..nh-1]} \NC \type {fix_word} \NC \NR
+ \NC \type {depth} \NC \type {[0..nd-1]} \NC \type {fix_word} \NC \NR
+ \NC \type {italic} \NC \type {[0..ni-1]} \NC \type {fix_word} \NC \NR
+ \NC \type {lig\_kern} \NC \type {[0..nl-1]} \NC \type {lig_kern_command} \NC \NR
+ \NC \type {kern} \NC \type {[0..nk-1]} \NC \type {fix_word} \NC \NR
+ \NC \type {exten} \NC \type {[0..ne-1]} \NC \type {extensible_recipe} \NC \NR
+ \NC \type {param} \NC \type {[1..np]} \NC \type {fix_word} \NC \NR
+ \stoptabulate
+
+ The most important data type used here is a |@!fix_word|, which is a 32-bit
+ representation of a binary fraction. A |fix_word| is a signed quantity, with
+ the two's complement of the entire word used to represent negation. Of the 32
+ bits in a |fix_word|, exactly 12 are to the left of the binary point; thus,
+ the largest |fix_word| value is $2048-2^{-20}$, and the smallest is $-2048$.
+ We will see below, however, that all but two of the |fix_word| values must
+ lie between $-16$ and $+16$.
+
+ The first data array is a block of header information, which contains general
+ facts about the font. The header must contain at least two words, |header[0]|
+ and |header[1]|, whose meaning is explained below. Additional header
+ information of use to other software routines might also be included, but
+ \TeX82 does not need to know about such details. For example, 16 more words
+ of header information are in use at the Xerox Palo Alto Research Center; the
+ first ten specify the character coding scheme used (e.g., `\.{XEROX text}' or
+ `\.{TeX math symbols}'), the next five give the font identifier (e.g.,
+ `\.{HELVETICA}' or `\.{CMSY}'), and the last gives the ``face byte.'' The
+ program that converts \.{DVI} files to Xerox printing format gets this
+ information by looking at the \TFM\file, which it needs to read anyway
+ because of other information that is not explicitly repeated in
+ \.{DVI}~format.
+
+ \startitemize
+
+ \startitem
+ |header[0]| is a 32-bit check sum that \TeX\ will copy into the
+ \.{DVI} output file. Later on when the \.{DVI} file is printed,
+ possibly on another computer, the actual font that gets used is
+ supposed to have a check sum that agrees with the one in the \TFM\
+ file used by \TeX. In this way, users will be warned about potential
+ incompatibilities. (However, if the check sum is zero in either the
+ font file or the \TFM\file, no check is made.) The actual relation
+ between this check sum and the rest of the \TFM\file is not
+ important; the check sum is simply an identification number with the
+ property that incompatible fonts almost always have distinct check
+ sums.
+ \stopitem
+
+ \startitem
+ |header[1]| is a |fix_word| containing the design size of the font,
+ in units of \TeX\ points. This number must be at least 1.0; it is
+ fairly arbitrary, but usually the design size is 10.0 for a ``10
+ point'' font, i.e., a font that was designed to look best at a
+ 10-point size, whatever that really means. When a \TeX\ user asks for
+ a font `\.{at} $\delta$ \.{pt}', the effect is to override the design
+ size and replace it by $\delta$, and to multiply the $x$ and~$y$
+ coordinates of the points in the font image by a factor of $\delta$
+ divided by the design size. {\sl All other dimensions in the\/
+ \TFM\file are |fix_word|\kern-1pt\ numbers in design-size units},
+ with the exception of |param[1]| (which denotes the slant ratio).
+ Thus, for example, the value of |param[6]|, which defines the \.{em}
+ unit, is often the |fix_word| value $2^{20}=1.0$, since many fonts
+ have a design size equal to one em. The other dimensions must be less
+ than 16 design-size units in absolute value; thus, |header[1]| and
+ |param[1]| are the only |fix_word| entries in the whole \TFM\file
+ whose first byte might be something besides 0 or 255.
+ \stopitem
+
+ \stopitemize
+
+ Next comes the |char_info| array, which contains one |@!char_info_word| per
+ character. Each word in this part of a \TFM\file contains six fields
+ packed into four bytes as follows.
+
+ \startitemize
+ \startitem
+ first byte: |width_index| (8 bits)
+ \stopitem
+ \startitem
+ second byte: |height_index| (4 bits) times 16, plus |depth_index|
+ (4~bits)
+ \stopitem
+ \startitem
+ third byte: |italic_index| (6 bits) times 4, plus |tag| (2~bits)
+ \stopitem
+ \startitem
+ fourth byte: |remainder| (8 bits)
+ \stopitem
+ \stopitemize
+
+ The actual width of a character is \\{width}|[width_index]|, in design-size
+ units; this is a device for compressing information, since many characters
+ have the same width. Since it is quite common for many characters to have the
+ same height, depth, or italic correction, the \TFM\format imposes a limit
+ of 16 different heights, 16 different depths, and 64 different italic
+ corrections.
+
+ For \.{OFM} files, two words (eight bytes) are used. The arrangement is as
+ follows.
+
+ \startitemize
+ \startitem
+ first and second bytes: |width_index| (16 bits)
+ \stopitem
+ \startitem third byte: |height_index| (8 bits)
+ \stopitem
+ \startitem
+ fourth byte: |depth_index| (8~bits)
+ \stopitem
+ \startitem
+ fifth and sixth bytes: |italic_index| (14 bits) times 4, plus |tag|
+ (2~bits)
+ \startitem
+ seventh and eighth bytes: |remainder| (16 bits)
+ \stopitem
+ \stopitemize
+
+ Therefore the \.{OFM} format imposes a limit of 256 different heights, 256
+ different depths, and 16384 different italic corrections.
+
+ The italic correction of a character has two different uses. (a)~In ordinary
+ text, the italic correction is added to the width only if the \TeX\ user
+ specifies `\.{\\/}' after the character. (b)~In math formulas, the italic
+ correction is always added to the width, except with respect to the
+ positioning of subscripts.
+
+ Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+ \\{italic}[0]=0$ should always hold, so that an index of zero implies a value
+ of zero. The |width_index| should never be zero unless the character does not
+ exist in the font, since a character is valid if and only if it lies between
+ |bc| and |ec| and has a nonzero |width_index|.
+
+ \TeX\ checks the information of a \TFM\file for validity as the file is
+ being read in, so that no further checks will be needed when typesetting is
+ going on. The somewhat tedious subroutine that does this is called
+ |read_font_info|. It has four parameters: the user font identifier~|u|, the
+ file name and area strings |nom| and |aire|, and the ``at'' size~|s|. If
+ |s|~is negative, it's the negative of a scale factor to be applied to the
+ design size; |s=-1000| is the normal case. Otherwise |s| will be substituted
+ for the design size; in this case, |s| must be positive and less than
+ $2048\rm\,pt$ (i.e., it must be less than $2^{27}$ when considered as an
+ integer).
+
+ The subroutine opens and closes a global file variable called |tfm_file|. It
+ returns the value of the internal font number that was just loaded. If an
+ error is detected, an error message is issued and no font information is
+ stored; |null_font| is returned in this case.
+
+ The |tag| field in a |char_info_word| has four values that explain how to
+ interpret the |remainder| field.
+
+ \startitemize
+ \startitem
+ |tag=0| (|no_tag|) means that |remainder| is unused.
+ \stopitem
+ \startitem
+ |tag=1| (|lig_tag|) means that this character has a ligature/kerning
+ program starting at position |remainder| in the |lig_kern| array
+ \stopitem
+ \startitem
+ |tag=2| (|list_tag|) means that this character is part of a chain of
+ characters of ascending sizes, and not the largest in the chain. The
+ |remainder| field gives the character code of the next larger
+ character
+ \stopitem
+ \startitem
+ |tag=3| (|ext_tag|) means that this character code represents an
+ extensible character, i.e., a character that is built up of smaller
+ pieces so that it can be made arbitrarily large. The pieces are
+ specified in |exten[remainder]|
+ \stopitem
+ \stopitemize
+
+ Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
+ unless they are used in special circumstances in math formulas. For example,
+ the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left} operation
+ looks for both |list_tag| and |ext_tag|.
+
+ The |lig_kern| array contains instructions in a simple programming language
+ that explains what to do for special letter pairs. Each word in this array,
+ in a \TFM\file, is a |@!lig_kern_command| of four bytes.
+
+ \startitemize
+ \startitem
+ first byte: |skip_byte|, indicates that this is the final program
+ step if the byte is 128 or more, otherwise the next step is obtained
+ by skipping this number of intervening steps
+ \stopitem
+ \startitem
+ second byte: |next_char|, if |next_char| follows the current
+ character, then perform the operation and stop, otherwise
+ continue
+ \stopitem
+ \startitem
+ third byte: |op_byte|, indicates a ligature step if less than~128, a
+ kern step otherwise
+ \stopitem
+ \startitem
+ fourth byte: |remainder|
+ \stopitem
+ \stopitemize
+
+ In an \.{OFM} file, eight bytes are used, two bytes for each field.
+
+ In a kern step, an additional space equal to |kern[256 * (op_byte-128) +
+ remainder]| is inserted between the current character and |next_char|. This
+ amount is often negative, so that the characters are brought closer together
+ by kerning; but it might be positive.
+
+ There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$
+ where $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+ |remainder| is inserted between the current character and |next_char|; then
+ the current character is deleted if $b=0$, and |next_char| is deleted if
+ $c=0$; then we pass over $a$~characters to reach the next current character
+ (which may have a ligature/kerning program of its own).
+
+ If the very first instruction of the |lig_kern| array has |skip_byte=255|,
+ the |next_char| byte is the so-called right boundary character of this font;
+ the value of |next_char| need not lie between |bc| and~|ec|. If the very last
+ instruction of the |lig_kern| array has |skip_byte=255|, there is a special
+ ligature/kerning program for a left boundary character, beginning at location
+ |256*op_byte+remainder|. The interpretation is that \TeX\ puts implicit
+ boundary characters before and after each consecutive string of characters
+ from the same font. These implicit characters do not appear in the output,
+ but they can affect ligatures and kerning.
+
+ If the very first instruction of a character's |lig_kern| program has
+ |skip_byte>128|, the program actually begins in location
+ |256*op_byte+remainder|. This feature allows access to large |lig_kern|
+ arrays, because the first instruction must otherwise appear in a location
+ |<=255| in a \TFM\file, |<=65535| in an \.{OFM} file.
+
+ Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy the
+ condition $$\hbox{|256*op_byte+remainder<nl|.}$$ If such an instruction is
+ encountered during normal program execution, it denotes an unconditional
+ halt; no ligature or kerning command is performed.
+
+ Extensible characters are specified by an |@!extensible_recipe|, which
+ consists of four bytes in a \TFM\file, called |@!top|, |@!mid|, |@!bot|,
+ and |@!rep| (in this order). In an \.{OFM} file, each field takes two bytes,
+ for eight in total. These bytes are the character codes of individual pieces
+ used to build up a large symbol. If |top|, |mid|, or |bot| are zero, they are
+ not present in the built-up result. For example, an extensible vertical line
+ is like an extensible bracket, except that the top and bottom pieces are
+ missing.
+
+ Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box if
+ the piece isn't present. Then the extensible characters have the form
+ $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent; in the
+ latter case we can have $TR^kB$ for both even and odd values of~|k|. The
+ width of the extensible character is the width of $R$; and the
+ height-plus-depth is the sum of the individual height-plus-depths of the
+ components used, since the pieces are butted together in a vertical list.
+
+ The final portion of a \TFM\file is the |param| array, which is another
+ sequence of |fix_word| values.
+
+ \startitemize
+
+ \startitem
+ |param[1]=slant| is the amount of italic slant, which is used to help
+ position accents. For example, |slant=.25| means that when you go up one
+ unit, you also go .25 units to the right. The |slant| is a pure number;
+ it's the only |fix_word| other than the design size itself that is not
+ scaled by the design size.
+ \stopitem
+
+ \startitem
+ |param[2]=space| is the normal spacing between words in text. Note that
+ character |" "| in the font need not have anything to do with blank
+ spaces.
+ \stopitem
+
+ \startitem
+ |param[3]=space_stretch| is the amount of glue stretching between words.
+ \stopitem
+
+ \startitem
+ |param[4]=space_shrink| is the amount of glue shrinking between words.
+ \stopitem
+
+ \startitem
+ |param[5]=x_height| is the size of one ex in the font; it is also the
+ height of letters for which accents don't have to be raised or lowered.
+ \stopitem
+
+ \startitem
+ |param[6]=quad| is the size of one em in the font.
+ \stopitem
+
+ \startitem
+ |param[7]=extra_space| is the amount added to |param[2]| at the ends of
+ sentences.
+ \stopitem
+
+
+ If fewer than seven parameters are present, \TeX\ sets the missing parameters
+ to zero. Fonts used for math symbols are required to have additional
+ parameter information, which is explained later.
+
+
+ There are programs called \.{TFtoPL} and \.{PLtoTF} that convert between the
+ \TFM\format and a symbolic property-list format that can be easily edited.
+ These programs contain extensive diagnostic information, so \TeX\ does not
+ have to bother giving precise details about why it rejects a particular
+ \TFM\file.
+
+*/
+
+#define tfm_abort { \
+ font_tables[f]->_font_name = NULL; \
+ font_tables[f]->_font_area = NULL; \
+ xfree(tfm_buffer); xfree(kerns); \
+ xfree(widths); \
+ xfree(heights); \
+ xfree(depths); \
+ xfree(italics); \
+ xfree(extens); \
+ xfree(lig_kerns); \
+ xfree(xligs); \
+ xfree(xkerns); \
+ return 0; \
+}
+
+#define tfm_success { \
+ xfree(tfm_buffer); \
+ xfree(kerns); \
+ xfree(widths); \
+ xfree(heights); \
+ xfree(depths); \
+ xfree(italics); \
+ xfree(extens); \
+ xfree(lig_kerns); \
+ xfree(xligs); \
+ xfree(xkerns); \
+ return 1; \
+}
+
+static int open_tfm_file(const char *nom, unsigned char **tfm_buf, int *tfm_siz)
+{
+ /*tex Was the callback successful? */
+ boolean res;
+ /*tex Was |tfm_file| successfully opened? */
+ boolean opened;
+ int callback_id;
+ FILE *tfm_file;
+ char *fname = luatex_find_file(nom, find_font_file_callback);
+ if (!fname)
+ return -1;
+ callback_id = callback_defined(read_font_file_callback);
+ if (callback_id > 0) {
+ res = run_callback(callback_id, "S->bSd", fname, &opened, tfm_buf, tfm_siz);
+ if (res && opened && (*tfm_siz > 0)) {
+ return 1;
+ }
+ if (!opened)
+ return -1;
+ } else {
+ if (luatex_open_input(&(tfm_file), fname, kpse_ofm_format, FOPEN_RBIN_MODE, true)) {
+ res = read_tfm_file(tfm_file, tfm_buf, tfm_siz);
+ close_file(tfm_file);
+ if (res) {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ Note: A malformed \TFM\file might be shorter than it claims to be; thus
+ |eof(tfm_file)| might be true when |read_font_info| refers to |tfm_file^| or
+ when it says |get(tfm_file)|. If such circumstances cause system error
+ messages, you will have to defeat them somehow, for example by defining |fget|
+ to be `\ignorespaces|begin get(tfm_file);| |if eof(tfm_file) then abort;
+ end|'.
+
+*/
+
+#define fget tfm_byte++
+#define fbyte tfm_buffer[tfm_byte]
+
+#define read_sixteen(a) { \
+ a=tfm_buffer[tfm_byte++]; \
+ if (a>127) { tfm_abort; } \
+ a=(a*256)+tfm_buffer[tfm_byte]; \
+}
+
+#define read_sixteen_unsigned(a) { \
+ a=tfm_buffer[tfm_byte++]; \
+ a=(a*256)+tfm_buffer[tfm_byte]; \
+}
+
+#define read_thirtytwo(a) { \
+ a=tfm_buffer[++tfm_byte]; \
+ if (a>127) { tfm_abort; } \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+}
+
+#define store_four_bytes(z) { \
+ a=tfm_buffer[++tfm_byte]; \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+ a=(a*256)+tfm_buffer[++tfm_byte]; \
+ z = a; \
+}
+
+#define store_char_info(z) { \
+ if (font_level!=-1) { \
+ fget; read_sixteen_unsigned(a); \
+ ci._width_index=a; \
+ fget; read_sixteen_unsigned(b); \
+ ci._height_index=b>>8; \
+ ci._depth_index=b%256; \
+ fget; read_sixteen_unsigned(c); \
+ ci._italic_index=c>>8; \
+ ci._tag=(unsigned char)(c%4); \
+ fget; read_sixteen_unsigned(d); \
+ ci._remainder=d; \
+ } else { \
+ a=tfm_buffer[++tfm_byte]; \
+ ci._width_index=a; \
+ b=tfm_buffer[++tfm_byte]; \
+ ci._height_index=b>>4; \
+ ci._depth_index=b%16; \
+ c=tfm_buffer[++tfm_byte]; \
+ ci._italic_index=c>>2; \
+ ci._tag=(unsigned char)(c%4); \
+ d=tfm_buffer[++tfm_byte]; \
+ ci._remainder=d; \
+ } \
+}
+
+#define read_four_quarters(q) { \
+ if (font_level!=-1) { \
+ fget; read_sixteen_unsigned(a); q.b0=(quarterword)a; \
+ fget; read_sixteen_unsigned(b); q.b1=(quarterword)b; \
+ fget; read_sixteen_unsigned(c); q.b2=(quarterword)c; \
+ fget; read_sixteen_unsigned(d); q.b3=(quarterword)d; \
+ } else { \
+ a=tfm_buffer[++tfm_byte]; q.b0=(quarterword)a; \
+ b=tfm_buffer[++tfm_byte]; q.b1=(quarterword)b; \
+ c=tfm_buffer[++tfm_byte]; q.b2=(quarterword)c; \
+ d=tfm_buffer[++tfm_byte]; q.b3=(quarterword)d; \
+ } \
+}
+
+#define check_byte_range(z) { if ((z<bc)||(z>ec)) tfm_abort ; }
+
+/*
+
+ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
+ the number $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+ b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+ -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$ (No other
+ choices of |a| are allowed, since the magnitude of a number in design-size
+ units must be less than 16.) We want to multiply this quantity by the
+ integer~|z|, which is known to be less than $2^{27}$. If $|z|<2^{23}$, the
+ individual multiplications $b\cdot z$, $c\cdot z$, $d\cdot z$ cannot
+ overflow; otherwise we will divide |z| by 2, 4, 8, or 16, to obtain a
+ multiplier less than $2^{23}$, and we can compensate for this later. If |z|
+ has thereby been replaced by $|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we
+ shall compute $$\lfloor (b + c \cdot2^{-8} + d \cdot2^{-16}) \, z^\prime /
+ \beta \rfloor$$ if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$
+ if $a=255$. This calculation must be done exactly, in order to guarantee
+ portability of \TeX\ between computers.
+
+*/
+
+#define store_scaled(zz) { \
+ fget; \
+ a = fbyte; \
+ fget; \
+ b = fbyte; \
+ fget; \
+ c = fbyte; \
+ fget; \
+ d = fbyte; \
+ sw = (((((d*z)>>8)+(c*z))>>8)+(b*z)) / beta; \
+ if (a == 0) { \
+ zz = sw; \
+ } else if (a == 255) { \
+ zz = sw-alpha; \
+ } else { \
+ tfm_abort; \
+ } \
+}
+
+scaled store_scaled_f(scaled sq, scaled z_in)
+{
+ eight_bits a, b, c, d;
+ scaled sw;
+ /*tex Here beta: runs from 1 upto 16 */
+ static int alpha, beta;
+ static scaled z, z_prev = 0;
+ /*tex Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
+ if (z_in != z_prev || z_prev == 0) {
+ z = z_prev = z_in;
+ alpha = 16;
+ while (z >= 0x800000) {
+ z /= 2;
+ alpha += alpha;
+ }
+ beta = 256 / alpha;
+ alpha *= z;
+ };
+ if (sq >= 0) {
+ d = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ c = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ b = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ a = (eight_bits) (sq % 256);
+ } else {
+ sq = (sq + 1073741824) + 1073741824;
+ d = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ c = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ b = (eight_bits) (sq % 256);
+ sq = sq / 256;
+ a = (eight_bits) ((sq + 128) % 256);
+ }
+ if (beta==0)
+ normal_error("vf", "vf scaling");
+ sw = (((((d * z) >> 8) + (c * z)) >> 8) + (b * z)) / beta;
+ if (a == 0)
+ return sw;
+ else if (a == 255)
+ return (sw - alpha);
+ else
+ normal_error("vf", "vf scaling");
+ return sw;
+}
+
+#define check_existence(z) { \
+ check_byte_range(z); \
+ if (!char_exists(f,z)) { \
+ tfm_abort; \
+ } \
+}
+
+typedef struct tfmcharacterinfo {
+ int _kern_index;
+ int _lig_index;
+ int _width_index;
+ int _height_index;
+ int _depth_index;
+ int _italic_index;
+ int _remainder;
+ unsigned char _tag;
+} tfmcharacterinfo;
+
+int read_tfm_info(internal_font_number f, const char *cnom, scaled s)
+{
+ /*tex index into |font_info| */
+ int k;
+ /*tex sizes of subfiles */
+ halfword lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, slh;
+ scaled *widths, *heights, *depths, *italics, *kerns;
+ halfword font_dir;
+ /*tex byte variables */
+ int a, b, c=0, d=0;
+ /*tex counter */
+ int i;
+ int font_level, header_length;
+ int ncw, nlw, neew;
+ tfmcharacterinfo ci;
+ charinfo *co;
+ four_quarters qw;
+ four_quarters *lig_kerns, *extens;
+ /*tex accumulators */
+ scaled sw;
+ /*tex left boundary start location, or infinity */
+ int bch_label;
+ /*tex 0..too_big_char; right boundary character, or |too_big_char| */
+ int bchar;
+ int first_two;
+ /*tex the design size or the ``at'' size */
+ scaled z;
+ int alpha;
+ /*tex 1..16 */
+ char beta;
+ /*tex aux. for ligkern processing */
+ int *xligs, *xkerns;
+ liginfo *cligs;
+ kerninfo *ckerns;
+ int fligs, fkerns;
+ char *tmpnam;
+ /*tex index into |tfm_buffer| */
+ int tfm_byte = 0;
+ /*tex saved index into |tfm_buffer| */
+ int saved_tfm_byte = 0;
+ /*tex byte buffer for tfm files */
+ unsigned char *tfm_buffer = NULL;
+ /*tex total size of the tfm file */
+ int tfm_size = 0;
+ int tmp;
+ widths = NULL;
+ heights = NULL;
+ depths = NULL;
+ italics = NULL;
+ kerns = NULL;
+ lig_kerns = NULL;
+ extens = NULL;
+ xkerns = NULL;
+ ckerns = NULL;
+ xligs = NULL;
+ cligs = NULL;
+ font_dir = 0;
+ memset(&ci, 0, sizeof(tfmcharacterinfo));
+ if (open_tfm_file(cnom, &tfm_buffer, &tfm_size) != 1)
+ tfm_abort;
+ /*tex When |cnom| is an absolute filename |xbasename| fixes that. */
+ tmpnam = strdup(xbasename(cnom));
+ if (strcmp(tmpnam + strlen(tmpnam) - 4, ".tfm") == 0 || strcmp(tmpnam + strlen(tmpnam) - 4, ".ofm") == 0) {
+ *(tmpnam + strlen(tmpnam) - 4) = 0;
+ }
+ set_font_name(f, tmpnam);
+ set_font_area(f, NULL);
+ /*tex Read the \TFM\ size fields. */
+ ncw = 0;
+ read_sixteen(first_two);
+ if (first_two != 0) {
+ font_level = -1;
+ lf = first_two;
+ fget;
+ read_sixteen(lh);
+ fget;
+ read_sixteen(bc);
+ fget;
+ read_sixteen(ec);
+ if ((bc > ec + 1) || (ec > 255))
+ tfm_abort;
+ if (bc > 255) {
+ /*tex |bc=256| and |ec=255| */
+ bc = 1;
+ ec = 0;
+ };
+ fget;
+ read_sixteen(nw);
+ fget;
+ read_sixteen(nh);
+ fget;
+ read_sixteen(nd);
+ fget;
+ read_sixteen(ni);
+ fget;
+ read_sixteen(nl);
+ fget;
+ read_sixteen(nk);
+ fget;
+ read_sixteen(ne);
+ fget;
+ read_sixteen(np);
+ header_length = 6;
+ ncw = (ec - bc + 1);
+ nlw = nl;
+ neew = ne;
+ } else {
+ fget;
+ read_sixteen(font_level);
+ if (font_level != 0)
+ tfm_abort;
+ read_thirtytwo(lf);
+ read_thirtytwo(lh);
+ read_thirtytwo(bc);
+ read_thirtytwo(ec);
+ if ((bc > ec + 1) || (ec > 65535))
+ tfm_abort;
+ if (bc > 65535) {
+ /*tex |bc=65536| and |ec=65535| */
+ bc = 1;
+ ec = 0;
+ };
+ read_thirtytwo(nw);
+ read_thirtytwo(nh);
+ read_thirtytwo(nd);
+ read_thirtytwo(ni);
+ read_thirtytwo(nl);
+ read_thirtytwo(nk);
+ read_thirtytwo(ne);
+ read_thirtytwo(np);
+ /*tex Some junk: */
+ read_thirtytwo(font_dir);
+ nlw = 2 * nl;
+ neew = 2 * ne;
+ header_length = 14;
+ ncw = 2 * (ec - bc + 1);
+ };
+ if (lf !=
+ (header_length + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np))
+ tfm_abort;
+ if ((nw == 0) || (nh == 0) || (nd == 0) || (ni == 0))
+ tfm_abort;
+ /*tex
+ We check to see that the \TFM\ file doesn't end prematurely; but no
+ error message is given for files having more than |lf| words.
+ */
+ if (lf * 4 > tfm_size)
+ tfm_abort;
+ /*tex Use size fields to allocate font information. */
+ set_font_natural_dir(f, font_dir);
+ set_font_bc(f, bc);
+ set_font_ec(f, ec);
+ /*tex Read the arrays first. */
+ widths = xmalloc((unsigned) ((unsigned) nw * sizeof(scaled)));
+ heights = xmalloc((unsigned) ((unsigned) nh * sizeof(scaled)));
+ depths = xmalloc((unsigned) ((unsigned) nd * sizeof(scaled)));
+ italics = xmalloc((unsigned) ((unsigned) ni * sizeof(scaled)));
+ extens = xmalloc((unsigned) ((unsigned) ne * sizeof(four_quarters)));
+ lig_kerns = xmalloc((unsigned) ((unsigned) nl * sizeof(four_quarters)));
+ kerns = xmalloc((unsigned) ((unsigned) nk * sizeof(scaled)));
+ /*
+ Read the \TFM\ header. Only the first two words of the header are needed
+ by \TeX82.
+ */
+ slh = lh;
+ if (lh < 2)
+ tfm_abort;
+ store_four_bytes(tmp);
+ font_checksum(f) = (unsigned) tmp;
+ fget;
+ /*tex This rejects a negative design size. */
+ read_sixteen(z);
+ fget;
+ z = z * 256 + fbyte;
+ fget;
+ z = (z * 16) + (fbyte >> 4);
+ if (z < unity)
+ tfm_abort;
+ while (lh > 2) {
+ fget;
+ fget;
+ fget;
+ fget;
+ /*tex Ignore the rest of the header. */
+ lh--;
+ };
+ /*tex Read the arrays before the character info. */
+ set_font_dsize(f, z);
+ if (s != -1000) {
+ z = (s >= 0 ? s : xn_over_d(z, -s, 1000));
+ }
+ set_font_size(f, z);
+ if (np > 7) {
+ set_font_params(f, np);
+ }
+ saved_tfm_byte = tfm_byte;
+ tfm_byte = (header_length + slh + ncw) * 4 - 1;
+ /*tex Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
+ alpha = 16;
+ while (z >= 040000000) {
+ z = z >> 1;
+ alpha = alpha + alpha;
+ };
+ beta = (char) (256 / alpha);
+ /*tex |beta| cannot be zero. */
+ if (beta==0)
+ normal_error("vf", "vf reading");
+ alpha = alpha * z;
+ /*tex Read box dimensions. */
+ for (k = 0; k < nw; k++) {
+ store_scaled(sw);
+ widths[k] = sw;
+ }
+ /*tex |width[0]| must be zero */
+ if (widths[0] != 0)
+ tfm_abort;
+ for (k = 0; k < nh; k++) {
+ store_scaled(sw);
+ heights[k] = sw;
+ }
+ /*tex |height[0]| must be zero */
+ if (heights[0] != 0)
+ tfm_abort;
+ for (k = 0; k < nd; k++) {
+ store_scaled(sw);
+ depths[k] = sw;
+ }
+ /*tex |depth[0]| must be zero */
+ if (depths[0] != 0)
+ tfm_abort;
+ for (k = 0; k < ni; k++) {
+ store_scaled(sw);
+ italics[k] = sw;
+ }
+ /*tex |italic[0]| must be zero */
+ if (italics[0] != 0)
+ tfm_abort;
+ /*tex Read ligature and kern programs */
+ bch_label = nl;
+ bchar = 65536;
+ if (nl > 0) {
+ for (k = 0; k < nl; k++) {
+ read_four_quarters(qw);
+ lig_kerns[k] = qw;
+ if (a > 128) {
+ if (256 * c + d >= nl)
+ tfm_abort;
+ if (a == 255 && k == 0)
+ bchar = b;
+ } else {
+ if (c < 128) {
+ /*tex Do nothing. */
+ } else if (256 * (c - 128) + d >= nk) {
+ /*tex Check kern. */
+ tfm_abort;
+ }
+ if ((a < 128) && (k - 0 + a + 1 >= nl))
+ tfm_abort;
+ };
+ };
+ if (a == 255)
+ bch_label = 256 * c + d;
+ };
+ /*tex The actual kerns */
+ for (k = 0; k < nk; k++) {
+ store_scaled(sw);
+ kerns[k] = sw;
+ }
+ /*tex Read extensible character recipes */
+ for (k = 0; k < ne; k++) {
+ read_four_quarters(qw);
+ extens[k] = qw;
+ }
+ /*tex Read font parameters. */
+ if (np > 7) {
+ set_font_params(f, np);
+ }
+ for (k = 1; k <= np; k++) {
+ if (k == 1) {
+ /*tex The |slant| parameter is a pure number. */
+ fget;
+ sw = fbyte;
+ if (sw > 127)
+ sw = sw - 256;
+ fget;
+ sw = sw * 256 + fbyte;
+ fget;
+ sw = sw * 256 + fbyte;
+ fget;
+ sw = (sw * 16) + (fbyte >> 4);
+ set_font_param(f, k, sw);
+ } else {
+ store_scaled(font_param(f, k));
+ }
+ }
+ tfm_byte = saved_tfm_byte;
+ /*tex Fix up the left boundary character. */
+ fligs = 0;
+ fkerns = 0;
+ if (bch_label != nl) {
+ k = bch_label;
+ while (1) {
+ if (skip_byte(k) <= stop_flag) {
+ if (op_byte(k) >= kern_flag) {
+ fkerns++;
+ } else {
+ fligs++;
+ }
+ }
+ if (skip_byte(k) == 0) {
+ k++;
+ } else {
+ if (skip_byte(k) >= stop_flag)
+ break;
+ k += skip_byte(k) + 1;
+ }
+ }
+ }
+ if (fkerns > 0 || fligs > 0) {
+ if (fligs > 0)
+ cligs = xcalloc((unsigned) (fligs + 1), sizeof(liginfo));
+ if (fkerns > 0)
+ ckerns = xcalloc((unsigned) (fkerns + 1), sizeof(kerninfo));
+ fligs = 0;
+ fkerns = 0;
+ k = bch_label;
+ while (1) {
+ if (skip_byte(k) <= stop_flag) {
+ if (op_byte(k) >= kern_flag) {
+ set_kern_item(ckerns[fkerns], next_char(k), kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+ fkerns++;
+ } else {
+ set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), next_char(k), rem_byte(k));
+ fligs++;
+ }
+ }
+ if (skip_byte(k) == 0) {
+ k++;
+ } else {
+ if (skip_byte(k) >= stop_flag)
+ break;
+ k += skip_byte(k) + 1;
+ }
+ }
+ if (fkerns > 0 || fligs > 0) {
+ co = get_charinfo(f, left_boundarychar);
+ if (fkerns > 0) {
+ set_kern_item(ckerns[fkerns], end_kern, 0);
+ fkerns++;
+ set_charinfo_kerns(co, ckerns);
+ }
+ if (fligs > 0) {
+ set_ligature_item(cligs[fligs], 0, end_ligature, 0);
+ fligs++;
+ set_charinfo_ligatures(co, cligs);
+ }
+ set_charinfo_remainder(co, 0);
+ }
+ }
+ /*tex Read character data. */
+ for (k = bc; k <= ec; k++) {
+ store_char_info(k);
+ if (ci._width_index == 0)
+ continue;
+ if (ci._width_index >= nw || ci._height_index >= nh ||
+ ci._depth_index >= nd || ci._italic_index >= ni)
+ tfm_abort;
+ d = ci._remainder;
+ switch (ci._tag) {
+ case lig_tag:
+ if (d >= nl)
+ tfm_abort;
+ break;
+ case ext_tag:
+ if (d >= ne)
+ tfm_abort;
+ break;
+ case list_tag:
+ /*tex
+
+ We want to make sure that there is no cycle of characters linked
+ together by |list_tag| entries, since such a cycle would get
+ \TEX\ into an endless loop. If such a cycle exists, the routine
+ here detects it when processing the largest character code in the
+ cycle.
+
+ */
+ check_byte_range(d);
+ while (d < k) {
+ /* |current_character == k| */
+ if (char_tag(f, d) != list_tag) {
+ /*tex Not a cycle. */
+ goto NOT_FOUND;
+ }
+ /*tex Goto the next character on the list. */
+ d = char_remainder(f, d);
+ };
+ if (d == k) {
+ /*tex Yes, there's a cycle! */
+ tfm_abort;
+ }
+ NOT_FOUND:
+ break;
+ }
+ /*tex Put it in the actual font. */
+ co = get_charinfo(f, k);
+ set_charinfo_index(co, k);
+ set_charinfo_tag(co, ci._tag);
+ if (ci._tag == ext_tag) {
+ /*tex top, bot, mid, rep */
+ set_charinfo_extensible(co,
+ extens[ci._remainder].b0,
+ extens[ci._remainder].b2,
+ extens[ci._remainder].b1,
+ extens[ci._remainder].b3);
+ set_charinfo_remainder(co, 0);
+ } else {
+ set_charinfo_remainder(co, ci._remainder);
+ }
+ set_charinfo_width(co, widths[ci._width_index]);
+ set_charinfo_height(co, heights[ci._height_index]);
+ set_charinfo_depth(co, depths[ci._depth_index]);
+ set_charinfo_italic(co, italics[ci._italic_index]);
+ };
+ /*tex We now know the number of ligatures and kerns. */
+ xligs = xcalloc((unsigned) (ec + 1), sizeof(int));
+ xkerns = xcalloc((unsigned) (ec + 1), sizeof(int));
+ for (i = bc; i <= ec; i++) {
+ if (char_tag(f, i) == lig_tag) {
+ k = lig_kern_start(f, i);
+ if (skip_byte(k) > stop_flag)
+ k = lig_kern_restart(k);
+ /*tex Now k is the start index. */
+ while (1) {
+ if (skip_byte(k) <= stop_flag) {
+ if (op_byte(k) >= kern_flag) {
+ xkerns[i]++;
+ if (next_char(k) == bchar)
+ xkerns[i]++;
+ } else {
+ xligs[i]++;
+ if (next_char(k) == bchar)
+ xligs[i]++;
+ }
+ }
+ if (skip_byte(k) == 0) {
+ k++;
+ } else {
+ if (skip_byte(k) >= stop_flag)
+ break;
+ k += skip_byte(k) + 1;
+ }
+ }
+ }
+ }
+ cligs = NULL;
+ ckerns = NULL;
+ for (i = bc; i <= ec; i++) {
+ fligs = 0;
+ fkerns = 0;
+ if (char_tag(f, i) == lig_tag) {
+ k = lig_kern_start(f, i);
+ if (skip_byte(k) > stop_flag)
+ k = lig_kern_restart(k);
+ /*tex Now k is the start index. */
+ if (xligs[i] > 0)
+ cligs = xcalloc((unsigned) (xligs[i] + 1), sizeof(liginfo));
+ if (xkerns[i] > 0)
+ ckerns = xcalloc((unsigned) (xkerns[i] + 1), sizeof(kerninfo));
+ while (1) {
+ if (skip_byte(k) <= stop_flag) {
+ if (op_byte(k) >= kern_flag) {
+ if (next_char(k) == bchar) {
+ set_kern_item(ckerns[fkerns], right_boundarychar, kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+ fkerns++;
+ }
+ set_kern_item(ckerns[fkerns], next_char(k), kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+ fkerns++;
+ } else { /* lig */
+ if (next_char(k) == bchar) {
+ set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), right_boundarychar, rem_byte(k));
+ fligs++;
+ }
+ set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), next_char(k), rem_byte(k));
+ fligs++;
+ }
+ }
+ if (skip_byte(k) == 0) {
+ k++;
+ } else {
+ if (skip_byte(k) >= stop_flag)
+ break;
+ k += skip_byte(k) + 1;
+ }
+ }
+ if (fkerns > 0 || fligs > 0) {
+ co = get_charinfo(f, i);
+ if (fkerns > 0) {
+ set_kern_item(ckerns[fkerns], end_kern, 0);
+ fkerns++;
+ set_charinfo_kerns(co, ckerns);
+ }
+ if (fligs > 0) {
+ set_ligature_item(cligs[fligs], 0, end_ligature, 0);
+ fligs++;
+ set_charinfo_ligatures(co, cligs);
+ }
+ set_charinfo_remainder(co, 0);
+ }
+ }
+ }
+ /*tex
+
+ Now it's time to wrap it up, we have checked all the necessary things
+ about the \TFM\file, and all we need to do is put the finishing
+ touches on the data for the new font.
+
+ */
+ if (bchar != 65536) {
+ co = copy_charinfo(char_info(f, bchar));
+ set_right_boundary(f, co);
+ }
+ tfm_success;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1119 +0,0 @@
-% tfmofm.w
-%
-% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ Here are some macros that help process ligatures and kerns
- at c
-#define lig_kern_start(f,c) char_remainder(f,c)
-#define stop_flag 128 /* value indicating `\.{STOP}' in a lig/kern program */
-#define kern_flag 128 /* op code for a kern step */
-
-#define skip_byte(z) lig_kerns[z].b0
-#define next_char(z) lig_kerns[z].b1
-#define op_byte(z) lig_kerns[z].b2
-#define rem_byte(z) lig_kerns[z].b3
-#define lig_kern_restart(c) (256*op_byte(c)+rem_byte(c))
-
-
-@
-The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
-Since the number of bytes is always a multiple of 4, we could
-also regard the file as a sequence of 32-bit words, but \TeX\ uses the
-byte interpretation. The format of \.{TFM} files was designed by
-Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
-@^Ramshaw, Lyle Harold@>
-of information in a compact but useful form.
-
-$\Omega$ is capable of reading not only \.{TFM} files, but also
-\.{OFM} files, which can describe fonts with up to 65536 characters
-and with huge lig/kern tables. These fonts will often be virtual
-fonts built up from real fonts with 256 characters, but $\Omega$
-is not aware of this.
-
-The documentation below describes \.{TFM} files, with slight additions
-to show where \.{OFM} files differ.
-
-@
-The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
-integers that give the lengths of the various subsequent portions
-of the file. These twelve integers are, in order:
-$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
-|lf|&length of the entire file, in words;\cr
-|lh|&length of the header data, in words;\cr
-|bc|&smallest character code in the font;\cr
-|ec|&largest character code in the font;\cr
-|nw|&number of words in the width table;\cr
-|nh|&number of words in the height table;\cr
-|nd|&number of words in the depth table;\cr
-|ni|&number of words in the italic correction table;\cr
-|nl|&number of words in the lig/kern table;\cr
-|nk|&number of words in the kern table;\cr
-|ne|&number of words in the extensible character table;\cr
-|np|&number of font parameter words.\cr}}$$
-They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
-and
-$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
-Note that a \.{TFM} font may contain as many as 256 characters
-(if |bc=0| and |ec=255|), and as few as 0 characters (if |bc=ec+1|).
-
-Incidentally, when two or more 8-bit bytes are combined to form an integer of
-16 or more bits, the most significant bytes appear first in the file.
-This is called BigEndian order.
-@!@^BigEndian order@>
-
-The first 52 bytes (13 words) of an \.{OFM} file contains thirteen
-32-bit integers that give the lengths of the various subsequent
-portions of the file. The first word is 0 (future versions of
-\.{OFM} files could have different values; what is important is that
-the first two bytes be 0 to differentiate \.{TFM} and \.{OFM} files).
-The next twelve integers are as above, all nonegative and less
-than~$2^{31}$. We must have |bc-1<=ec<=65535|, and
-$$\hbox{|lf=13+lh+2*(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
-Note that an \.{OFM} font may contain as many as 65536 characters
-(if |bc=0| and |ec=65535|), and as few as 0 characters (if |bc=ec+1|).
-
-The rest of the \.{TFM} file may be regarded as a sequence of ten data
-arrays having the informal specification
-$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
-\def\doarr\PB#1{\arr#1}
-\vbox{\halign{\hfil\\{#}&$\,:\,$\doarr#\hfil\cr
-header&|[0..lh-1]stuff|\cr
-char\_info&|[bc..ec]char_info_word|\cr
-width&|[0..nw-1]fix_word|\cr
-height&|[0..nh-1]fix_word|\cr
-depth&|[0..nd-1]fix_word|\cr
-italic&|[0..ni-1]fix_word|\cr
-lig\_kern&|[0..nl-1]lig_kern_command|\cr
-kern&|[0..nk-1]fix_word|\cr
-exten&|[0..ne-1]extensible_recipe|\cr
-param&\omit |[1..np]fix_word|\cr}}$$
-The most important data type used here is a |@!fix_word|, which is
-a 32-bit representation of a binary fraction. A |fix_word| is a signed
-quantity, with the two's complement of the entire word used to represent
-negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
-binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
-the smallest is $-2048$. We will see below, however, that all but two of
-the |fix_word| values must lie between $-16$ and $+16$.
-
-The first data array is a block of header information, which contains
-general facts about the font. The header must contain at least two words,
-|header[0]| and |header[1]|, whose meaning is explained below.
-Additional header information of use to other software routines might
-also be included, but \TeX82 does not need to know about such details.
-For example, 16 more words of header information are in use at the Xerox
-Palo Alto Research Center; the first ten specify the character coding
-scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
-give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
-last gives the ``face byte.'' The program that converts \.{DVI} files
-to Xerox printing format gets this information by looking at the \.{TFM}
-file, which it needs to read anyway because of other information that
-is not explicitly repeated in \.{DVI}~format.
-
-\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into
-the \.{DVI} output file. Later on when the \.{DVI} file is printed,
-possibly on another computer, the actual font that gets used is supposed
-to have a check sum that agrees with the one in the \.{TFM} file used by
-\TeX. In this way, users will be warned about potential incompatibilities.
-(However, if the check sum is zero in either the font file or the \.{TFM}
-file, no check is made.) The actual relation between this check sum and
-the rest of the \.{TFM} file is not important; the check sum is simply an
-identification number with the property that incompatible fonts almost
-always have distinct check sums.
-@^check sum@>
-
-\yskip\hang|header[1]| is a |fix_word| containing the design size of
-the font, in units of \TeX\ points. This number must be at least 1.0; it is
-fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
-font, i.e., a font that was designed to look best at a 10-point size,
-whatever that really means. When a \TeX\ user asks for a font
-`\.{at} $\delta$ \.{pt}', the effect is to override the design size
-and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
-of the points in the font image by a factor of $\delta$ divided by the
-design size. {\sl All other dimensions in the\/ \.{TFM} file are
-|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of
-|param[1]| (which denotes the slant ratio). Thus, for example, the value
-of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value
-$2^{20}=1.0$, since many fonts have a design size equal to one em.
-The other dimensions must be less than 16 design-size units in absolute
-value; thus, |header[1]| and |param[1]| are the only |fix_word|
-entries in the whole \.{TFM} file whose first byte might be something
-besides 0 or 255.
-
-Next comes the |char_info| array, which contains one |@!char_info_word|
-per character. Each word in this part of a \.{TFM} file contains six fields
-packed into four bytes as follows.
-
-\yskip\hang first byte: |@!width_index| (8 bits)\par
-\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
- (4~bits)\par
-\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
- (2~bits)\par
-\hang fourth byte: |@!remainder| (8 bits)\par
-\yskip\noindent
-The actual width of a character is \\{width}|[width_index]|, in design-size
-units; this is a device for compressing information, since many characters
-have the same width. Since it is quite common for many characters
-to have the same height, depth, or italic correction, the \.{TFM} format
-imposes a limit of 16 different heights, 16 different depths, and
-64 different italic corrections.
-
-For \.{OFM} files, two words (eight bytes) are used.
-The arrangement is as follows.
-
-\yskip\hang first and second bytes: |@!width_index| (16 bits)\par
-\hang third byte: |@!height_index| (8 bits)\par
-\hang fourth byte: |@!depth_index| (8~bits)\par
-\hang fifth and sixth bytes:
-|@!italic_index| (14 bits) times 4, plus |@!tag| (2~bits)\par
-\hang seventh and eighth bytes: |@!remainder| (16 bits)\par
-\yskip\noindent
-Therefore the \.{OFM} format imposes a limit of 256 different heights,
-256 different depths, and 16384 different italic corrections.
-
-@!@^italic correction@>
-The italic correction of a character has two different uses.
-(a)~In ordinary text, the italic correction is added to the width only if
-the \TeX\ user specifies `\.{\\/}' after the character.
-(b)~In math formulas, the italic correction is always added to the width,
-except with respect to the positioning of subscripts.
-
-Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
-\\{italic}[0]=0$ should always hold, so that an index of zero implies a
-value of zero. The |width_index| should never be zero unless the
-character does not exist in the font, since a character is valid if and
-only if it lies between |bc| and |ec| and has a nonzero |width_index|.
-
-
-@ \TeX\ checks the information of a \.{TFM} file for validity as the
-file is being read in, so that no further checks will be needed when
-typesetting is going on. The somewhat tedious subroutine that does this
-is called |read_font_info|. It has four parameters: the user font
-identifier~|u|, the file name and area strings |nom| and |aire|, and the
-``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor
-to be applied to the design size; |s=-1000| is the normal case.
-Otherwise |s| will be substituted for the design size; in this
-case, |s| must be positive and less than $2048\rm\,pt$
-(i.e., it must be less than $2^{27}$ when considered as an integer).
-
-The subroutine opens and closes a global file variable called |tfm_file|.
-It returns the value of the internal font number that was just loaded.
-If an error is detected, an error message is issued and no font
-information is stored; |null_font| is returned in this case.
-
-@
-The |tag| field in a |char_info_word| has four values that explain how to
-interpret the |remainder| field.
-
-\yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
-\hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
-program starting at position |remainder| in the |lig_kern| array.\par
-\hang|tag=2| (|list_tag|) means that this character is part of a chain of
-characters of ascending sizes, and not the largest in the chain. The
-|remainder| field gives the character code of the next larger character.\par
-\hang|tag=3| (|ext_tag|) means that this character code represents an
-extensible character, i.e., a character that is built up of smaller pieces
-so that it can be made arbitrarily large. The pieces are specified in
-|@!exten[remainder]|.\par
-\yskip\noindent
-Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
-unless they are used in special circumstances in math formulas. For example,
-the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
-operation looks for both |list_tag| and |ext_tag|.
-
-
-@ The |lig_kern| array contains instructions in a simple programming language
-that explains what to do for special letter pairs. Each word in this array,
-in a \.{TFM} file, is a |@!lig_kern_command| of four bytes.
-
-\yskip\hang first byte: |skip_byte|, indicates that this is the final program
- step if the byte is 128 or more, otherwise the next step is obtained by
- skipping this number of intervening steps.\par
-\hang second byte: |next_char|, ``if |next_char| follows the current character,
- then perform the operation and stop, otherwise continue.''\par
-\hang third byte: |op_byte|, indicates a ligature step if less than~128,
- a kern step otherwise.\par
-\hang fourth byte: |remainder|.\par
-\yskip\noindent
-In an \.{OFM} file, eight bytes are used, two bytes for each field.
-
-In a kern step, an
-additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
-between the current character and |next_char|. This amount is
-often negative, so that the characters are brought closer together
-by kerning; but it might be positive.
-
-There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
-$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
-|remainder| is inserted between the current character and |next_char|;
-then the current character is deleted if $b=0$, and |next_char| is
-deleted if $c=0$; then we pass over $a$~characters to reach the next
-current character (which may have a ligature/kerning program of its own).
-
-If the very first instruction of the |lig_kern| array has |skip_byte=255|,
-the |next_char| byte is the so-called right boundary character of this font;
-the value of |next_char| need not lie between |bc| and~|ec|.
-If the very last instruction of the |lig_kern| array has |skip_byte=255|,
-there is a special ligature/kerning program for a left boundary character,
-beginning at location |256*op_byte+remainder|.
-The interpretation is that \TeX\ puts implicit boundary characters
-before and after each consecutive string of characters from the same font.
-These implicit characters do not appear in the output, but they can affect
-ligatures and kerning.
-
-If the very first instruction of a character's |lig_kern| program has
-|skip_byte>128|, the program actually begins in location
-|256*op_byte+remainder|. This feature allows access to large |lig_kern|
-arrays, because the first instruction must otherwise
-appear in a location |<=255| in a \.{TFM} file, |<=65535| in an \.{OFM} file.
-
-Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
-the condition
-$$\hbox{|256*op_byte+remainder<nl|.}$$
-If such an instruction is encountered during
-normal program execution, it denotes an unconditional halt; no ligature
-or kerning command is performed.
-
-
-@ Extensible characters are specified by an |@!extensible_recipe|, which
-consists of four bytes in a \.{TFM} file,
-called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this order).
-In an \.{OFM} file, each field takes two bytes, for eight in total.
-These bytes are the character codes of individual pieces used to
-build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not
-present in the built-up result. For example, an extensible vertical line is
-like an extensible bracket, except that the top and bottom pieces are missing.
-
-Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
-if the piece isn't present. Then the extensible characters have the form
-$TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
-in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
-The width of the extensible character is the width of $R$; and the
-height-plus-depth is the sum of the individual height-plus-depths of the
-components used, since the pieces are butted together in a vertical list.
-
-
-@
-The final portion of a \.{TFM} file is the |param| array, which is another
-sequence of |fix_word| values.
-
-\yskip\hang|param[1]=slant| is the amount of italic slant, which is used
-to help position accents. For example, |slant=.25| means that when you go
-up one unit, you also go .25 units to the right. The |slant| is a pure
-number; it's the only |fix_word| other than the design size itself that is
-not scaled by the design size.
-
-\hang|param[2]=space| is the normal spacing between words in text.
-Note that character |" "| in the font need not have anything to do with
-blank spaces.
-
-\hang|param[3]=space_stretch| is the amount of glue stretching between words.
-
-\hang|param[4]=space_shrink| is the amount of glue shrinking between words.
-
-\hang|param[5]=x_height| is the size of one ex in the font; it is also
-the height of letters for which accents don't have to be raised or lowered.
-
-\hang|param[6]=quad| is the size of one em in the font.
-
-\hang|param[7]=extra_space| is the amount added to |param[2]| at the
-ends of sentences.
-
-\yskip\noindent
-If fewer than seven parameters are present, \TeX\ sets the missing parameters
-to zero. Fonts used for math symbols are required to have
-additional parameter information, which is explained later.
-
-
-@
- There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
- between the \.{TFM} format and a symbolic property-list format
- that can be easily edited. These programs contain extensive
- diagnostic information, so \TeX\ does not have to bother giving
- precise details about why it rejects a particular \.{TFM} file.
-
- at c
-#define tfm_abort { font_tables[f]->_font_name = NULL; \
- font_tables[f]->_font_area = NULL; \
- xfree(tfm_buffer); xfree(kerns); \
- xfree(widths); xfree(heights); xfree(depths); \
- xfree(italics); xfree(extens); xfree(lig_kerns); \
- xfree(xligs); xfree(xkerns); \
- return 0; }
-
-#define tfm_success { xfree(tfm_buffer); xfree(kerns); \
- xfree(widths); xfree(heights); xfree(depths); \
- xfree(italics); xfree(extens); xfree(lig_kerns); \
- xfree(xligs); xfree(xkerns); return 1; }
-
-@ @c
-static int open_tfm_file(const char *nom, unsigned char **tfm_buf, int *tfm_siz)
-{
- boolean res; /* was the callback successful? */
- boolean opened; /* was |tfm_file| successfully opened? */
- int callback_id;
- FILE *tfm_file;
- char *fname = luatex_find_file(nom, find_font_file_callback);
- if (!fname)
- return -1;
- callback_id = callback_defined(read_font_file_callback);
- if (callback_id > 0) {
- res =
- run_callback(callback_id, "S->bSd", fname, &opened, tfm_buf,
- tfm_siz);
- if (res && opened && (*tfm_siz > 0)) {
- return 1;
- }
- if (!opened)
- return -1;
- } else {
- if (luatex_open_input
- (&(tfm_file), fname, kpse_ofm_format, FOPEN_RBIN_MODE, true)) {
- res = read_tfm_file(tfm_file, tfm_buf, tfm_siz);
- close_file(tfm_file);
- if (res) {
- return 1;
- }
- } else {
- return -1;
- }
- }
- return 0;
-}
-
-
-@
- Note: A malformed \.{TFM} file might be shorter than it claims to be;
- thus |eof(tfm_file)| might be true when |read_font_info| refers to
- |tfm_file^| or when it says |get(tfm_file)|. If such circumstances
- cause system error messages, you will have to defeat them somehow,
- for example by defining |fget| to be `\ignorespaces|begin get(tfm_file);|
- |if eof(tfm_file) then abort; end|\unskip'.
- @^system dependencies@>
- at c
-
-#define fget tfm_byte++
-#define fbyte tfm_buffer[tfm_byte]
-
-#define read_sixteen(a) \
- { a=tfm_buffer[tfm_byte++]; \
- if (a>127) { tfm_abort; } \
- a=(a*256)+tfm_buffer[tfm_byte]; }
-
-#define read_sixteen_unsigned(a) \
- { a=tfm_buffer[tfm_byte++]; \
- a=(a*256)+tfm_buffer[tfm_byte]; }
-
-#define read_thirtytwo(a) \
- { a=tfm_buffer[++tfm_byte]; \
- if (a>127) { tfm_abort; } \
- a=(a*256)+tfm_buffer[++tfm_byte]; \
- a=(a*256)+tfm_buffer[++tfm_byte]; \
- a=(a*256)+tfm_buffer[++tfm_byte]; }
-
-#define store_four_bytes(z) \
- { a=tfm_buffer[++tfm_byte]; \
- a=(a*256)+tfm_buffer[++tfm_byte]; \
- a=(a*256)+tfm_buffer[++tfm_byte]; \
- a=(a*256)+tfm_buffer[++tfm_byte]; \
- z = a; }
-
-#define store_char_info(z) \
- { if (font_level!=-1) { \
- fget; read_sixteen_unsigned(a); \
- ci._width_index=a; \
- fget; read_sixteen_unsigned(b); \
- ci._height_index=b>>8; \
- ci._depth_index=b%256; \
- fget; read_sixteen_unsigned(c); \
- ci._italic_index=c>>8; \
- ci._tag=(unsigned char)(c%4); \
- fget; read_sixteen_unsigned(d); \
- ci._remainder=d; \
- } else { \
- a=tfm_buffer[++tfm_byte]; \
- ci._width_index=a; \
- b=tfm_buffer[++tfm_byte]; \
- ci._height_index=b>>4; \
- ci._depth_index=b%16; \
- c=tfm_buffer[++tfm_byte]; \
- ci._italic_index=c>>2; \
- ci._tag=(unsigned char)(c%4); \
- d=tfm_buffer[++tfm_byte]; \
- ci._remainder=d; \
- } }
-
-#define read_four_quarters(q) \
- { if (font_level!=-1) { \
- fget; read_sixteen_unsigned(a); q.b0=(quarterword)a; \
- fget; read_sixteen_unsigned(b); q.b1=(quarterword)b; \
- fget; read_sixteen_unsigned(c); q.b2=(quarterword)c; \
- fget; read_sixteen_unsigned(d); q.b3=(quarterword)d; \
- } else { \
- a=tfm_buffer[++tfm_byte]; q.b0=(quarterword)a; \
- b=tfm_buffer[++tfm_byte]; q.b1=(quarterword)b; \
- c=tfm_buffer[++tfm_byte]; q.b2=(quarterword)c; \
- d=tfm_buffer[++tfm_byte]; q.b3=(quarterword)d; \
- } }
-
-#define check_byte_range(z) { if ((z<bc)||(z>ec)) tfm_abort ; }
-
-
-@ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
- the number
- $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
- b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
- -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
- (No other choices of |a| are allowed, since the magnitude of a number in
- design-size units must be less than 16.) We want to multiply this
- quantity by the integer~|z|, which is known to be less than $2^{27}$.
- If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
- $c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
- 4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
- compensate for this later. If |z| has thereby been replaced by
- $|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
- $$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
- if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
- This calculation must be done exactly, in order to guarantee portability
- of \TeX\ between computers.
-
- at c
-#define store_scaled(zz) \
- { fget; a=fbyte; fget; b=fbyte; \
- fget; c=fbyte; fget; d=fbyte; \
- sw=(((((d*z)>>8)+(c*z))>>8)+(b*z)) / beta; \
- if (a==0) { zz=sw; } else if (a==255) { zz=sw-alpha; } else tfm_abort; \
- }
-
-scaled store_scaled_f(scaled sq, scaled z_in)
-{
- eight_bits a, b, c, d;
- scaled sw;
- static int alpha, beta; /* beta:1..16 */
- static scaled z, z_prev = 0;
- /* Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
- if (z_in != z_prev || z_prev == 0) {
- z = z_prev = z_in;
- alpha = 16;
- while (z >= 0x800000) {
- z /= 2;
- alpha += alpha;
- }
- beta = 256 / alpha;
- alpha *= z;
- };
- if (sq >= 0) {
- d = (eight_bits) (sq % 256);
- sq = sq / 256;
- c = (eight_bits) (sq % 256);
- sq = sq / 256;
- b = (eight_bits) (sq % 256);
- sq = sq / 256;
- a = (eight_bits) (sq % 256);
- } else {
- sq = (sq + 1073741824) + 1073741824; /* braces for optimizing compiler */
- d = (eight_bits) (sq % 256);
- sq = sq / 256;
- c = (eight_bits) (sq % 256);
- sq = sq / 256;
- b = (eight_bits) (sq % 256);
- sq = sq / 256;
- a = (eight_bits) ((sq + 128) % 256);
- }
- if (beta==0)
- normal_error("vf", "vf scaling");
- sw = (((((d * z) >> 8) + (c * z)) >> 8) + (b * z)) / beta;
- if (a == 0)
- return sw;
- else if (a == 255)
- return (sw - alpha);
- else
- normal_error("vf", "vf scaling");
- return sw; /* not reached, just to make the compiler happy */
-}
-
-@ @c
-#define check_existence(z) \
- { check_byte_range(z); \
- if (!char_exists(f,z)) tfm_abort; \
- }
-
-typedef struct tfmcharacterinfo {
- int _kern_index;
- int _lig_index;
- int _width_index;
- int _height_index;
- int _depth_index;
- int _italic_index;
- int _remainder;
- unsigned char _tag;
-} tfmcharacterinfo;
-
-@ @c
-int read_tfm_info(internal_font_number f, const char *cnom, scaled s)
-{
- int k; /* index into |font_info| */
- halfword lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, slh; /* sizes of subfiles */
- scaled *widths, *heights, *depths, *italics, *kerns;
- halfword font_dir;
- int a, b, c=0, d=0; /* byte variables */
- int i; /* counter */
- int font_level, header_length;
- int ncw, nlw, neew;
- tfmcharacterinfo ci;
- charinfo *co;
- four_quarters qw;
- four_quarters *lig_kerns, *extens;
- scaled sw; /* accumulators */
- int bch_label; /* left boundary start location, or infinity */
- int bchar; /* |:0..too_big_char;| *//* right boundary character, or |too_big_char| */
- int first_two;
- scaled z; /* the design size or the ``at'' size */
- int alpha;
- char beta; /* :1..16 */
- int *xligs, *xkerns; /* aux. for ligkern processing */
- liginfo *cligs;
- kerninfo *ckerns;
- int fligs, fkerns;
- char *tmpnam;
- int tfm_byte = 0; /* index into |tfm_buffer| */
- int saved_tfm_byte = 0; /* saved index into |tfm_buffer| */
- unsigned char *tfm_buffer = NULL; /* byte buffer for tfm files */
- int tfm_size = 0; /* total size of the tfm file */
- int tmp;
-
- widths = NULL;
- heights = NULL;
- depths = NULL;
- italics = NULL;
- kerns = NULL;
- lig_kerns = NULL;
- extens = NULL;
- xkerns = NULL;
- ckerns = NULL;
- xligs = NULL;
- cligs = NULL;
-
- font_dir = 0;
-
- memset(&ci, 0, sizeof(tfmcharacterinfo));
-
- if (open_tfm_file(cnom, &tfm_buffer, &tfm_size) != 1)
- tfm_abort;
-
- /* cnom can be an absolute filename, xbasename() fixes that. */
-
- tmpnam = strdup(xbasename(cnom));
- if (strcmp(tmpnam + strlen(tmpnam) - 4, ".tfm") == 0 || strcmp(tmpnam + strlen(tmpnam) - 4, ".ofm") == 0) {
- *(tmpnam + strlen(tmpnam) - 4) = 0;
- }
- set_font_name(f, tmpnam);
- set_font_area(f, NULL);
-
- /* Read the {\.{TFM}} size fields */
- ncw = 0;
- read_sixteen(first_two);
- if (first_two != 0) {
- font_level = -1;
- lf = first_two;
- fget;
- read_sixteen(lh);
- fget;
- read_sixteen(bc);
- fget;
- read_sixteen(ec);
- if ((bc > ec + 1) || (ec > 255))
- tfm_abort;
- if (bc > 255) { /* |bc=256| and |ec=255| */
- bc = 1;
- ec = 0;
- };
- fget;
- read_sixteen(nw);
- fget;
- read_sixteen(nh);
- fget;
- read_sixteen(nd);
- fget;
- read_sixteen(ni);
- fget;
- read_sixteen(nl);
- fget;
- read_sixteen(nk);
- fget;
- read_sixteen(ne);
- fget;
- read_sixteen(np);
- header_length = 6;
- ncw = (ec - bc + 1);
- nlw = nl;
- neew = ne;
- } else {
- fget;
- read_sixteen(font_level);
- if (font_level != 0)
- tfm_abort;
- read_thirtytwo(lf);
- read_thirtytwo(lh);
- read_thirtytwo(bc);
- read_thirtytwo(ec);
- if ((bc > ec + 1) || (ec > 65535))
- tfm_abort;
- if (bc > 65535) { /* |bc=65536| and |ec=65535| */
- bc = 1;
- ec = 0;
- };
- read_thirtytwo(nw);
- read_thirtytwo(nh);
- read_thirtytwo(nd);
- read_thirtytwo(ni);
- read_thirtytwo(nl);
- read_thirtytwo(nk);
- read_thirtytwo(ne);
- read_thirtytwo(np);
- read_thirtytwo(font_dir); /* junk */
- nlw = 2 * nl;
- neew = 2 * ne;
- header_length = 14;
- ncw = 2 * (ec - bc + 1);
- };
- if (lf !=
- (header_length + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np))
- tfm_abort;
- if ((nw == 0) || (nh == 0) || (nd == 0) || (ni == 0))
- tfm_abort;
-
- /*
- We check to see that the \.{TFM} file doesn't end prematurely; but
- no error message is given for files having more than |lf| words.
- */
- if (lf * 4 > tfm_size)
- tfm_abort;
-
- /* Use size fields to allocate font information */
-
- set_font_natural_dir(f, font_dir);
- set_font_bc(f, bc);
- set_font_ec(f, ec);
-
- /* read the arrays first */
- widths = xmalloc((unsigned) ((unsigned) nw * sizeof(scaled)));
- heights = xmalloc((unsigned) ((unsigned) nh * sizeof(scaled)));
- depths = xmalloc((unsigned) ((unsigned) nd * sizeof(scaled)));
- italics = xmalloc((unsigned) ((unsigned) ni * sizeof(scaled)));
- extens = xmalloc((unsigned) ((unsigned) ne * sizeof(four_quarters)));
- lig_kerns = xmalloc((unsigned) ((unsigned) nl * sizeof(four_quarters)));
- kerns = xmalloc((unsigned) ((unsigned) nk * sizeof(scaled)));
-
- /* Read the {\.{TFM}} header */
-
- /* Only the first two words of the header are needed by \TeX82. */
- slh = lh;
- if (lh < 2)
- tfm_abort;
- store_four_bytes(tmp);
- font_checksum(f) = (unsigned) tmp;
- fget;
- read_sixteen(z); /* this rejects a negative design size */
- fget;
- z = z * 256 + fbyte;
- fget;
- z = (z * 16) + (fbyte >> 4);
- if (z < unity)
- tfm_abort;
- while (lh > 2) {
- fget;
- fget;
- fget;
- fget;
- lh--; /* ignore the rest of the header */
- };
-
- /* read the arrays before the character info */
-
- set_font_dsize(f, z);
- if (s != -1000) {
- z = (s >= 0 ? s : xn_over_d(z, -s, 1000));
- }
- set_font_size(f, z);
-
- if (np > 7)
- set_font_params(f, np);
-
- saved_tfm_byte = tfm_byte;
- tfm_byte = (header_length + slh + ncw) * 4 - 1;
-
- /* Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
-
- alpha = 16;
- while (z >= 040000000) {
- z = z >> 1;
- alpha = alpha + alpha;
- };
- beta = (char) (256 / alpha);
-
- /* beta cannot be zero */
- if (beta==0)
- normal_error("vf", "vf reading");
- alpha = alpha * z;
-
- /* Read box dimensions */
-
- for (k = 0; k < nw; k++) {
- store_scaled(sw);
- widths[k] = sw;
- }
- if (widths[0] != 0) /* \\{width}[0] must be zero */
- tfm_abort;
- for (k = 0; k < nh; k++) {
- store_scaled(sw);
- heights[k] = sw;
- }
- if (heights[0] != 0)
- tfm_abort; /* \\{height}[0] must be zero */
- for (k = 0; k < nd; k++) {
- store_scaled(sw);
- depths[k] = sw;
- }
- if (depths[0] != 0)
- tfm_abort; /* \\{depth}[0] must be zero */
- for (k = 0; k < ni; k++) {
- store_scaled(sw);
- italics[k] = sw;
- }
- if (italics[0] != 0)
- tfm_abort; /* \\{italic}[0] must be zero */
-
-
- /* Read ligature/kern program */
-
- bch_label = nl; /* infinity */
- bchar = 65536;
- if (nl > 0) {
- for (k = 0; k < nl; k++) {
- read_four_quarters(qw);
- lig_kerns[k] = qw;
- if (a > 128) {
- if (256 * c + d >= nl)
- tfm_abort;
- if (a == 255 && k == 0)
- bchar = b;
- } else {
-#if 0
- if (b!=bchar) check_existence(b);
-#endif
- if (c < 128) {
-#if 0
- check_existence(d); /* check ligature */
-#endif
- } else if (256 * (c - 128) + d >= nk) {
- tfm_abort; /* check kern */
- }
- if ((a < 128) && (k - 0 + a + 1 >= nl))
- tfm_abort;
- };
- };
- if (a == 255)
- bch_label = 256 * c + d;
- };
-
- /* the actual kerns */
- for (k = 0; k < nk; k++) {
- store_scaled(sw);
- kerns[k] = sw;
- }
-
- /* Read extensible character recipes */
- for (k = 0; k < ne; k++) {
- read_four_quarters(qw);
- extens[k] = qw;
- }
-
- /* Read font parameters */
-
- if (np > 7) {
- set_font_params(f, np);
- }
- for (k = 1; k <= np; k++) {
- if (k == 1) { /* the |slant| parameter is a pure number */
- fget;
- sw = fbyte;
- if (sw > 127)
- sw = sw - 256;
- fget;
- sw = sw * 256 + fbyte;
- fget;
- sw = sw * 256 + fbyte;
- fget;
- sw = (sw * 16) + (fbyte >> 4);
- set_font_param(f, k, sw);
- } else {
- store_scaled(font_param(f, k));
- }
- }
-
- tfm_byte = saved_tfm_byte;
-
- /* fix up the left boundary character */
- fligs = 0;
- fkerns = 0;
- if (bch_label != nl) {
- k = bch_label;
-#if 0
- if (skip_byte(k) > stop_flag)
- k = lig_kern_restart(k);
-#endif
- while (1) {
- if (skip_byte(k) <= stop_flag) {
- if (op_byte(k) >= kern_flag) { /* kern */
- fkerns++;
- } else { /* lig */
- fligs++;
- }
- }
- if (skip_byte(k) == 0) {
- k++;
- } else {
- if (skip_byte(k) >= stop_flag)
- break;
- k += skip_byte(k) + 1;
- }
- }
- }
- if (fkerns > 0 || fligs > 0) {
- if (fligs > 0)
- cligs = xcalloc((unsigned) (fligs + 1), sizeof(liginfo));
- if (fkerns > 0)
- ckerns = xcalloc((unsigned) (fkerns + 1), sizeof(kerninfo));
- fligs = 0;
- fkerns = 0;
- k = bch_label;
-#if 0
- if (skip_byte(k) > stop_flag)
- k = lig_kern_restart(k);
-#endif
- while (1) {
- if (skip_byte(k) <= stop_flag) {
- if (op_byte(k) >= kern_flag) { /* kern */
- set_kern_item(ckerns[fkerns], next_char(k),
- kerns[256 * (op_byte(k) - 128) +
- rem_byte(k)]);
- fkerns++;
- } else { /* lig */
- set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1),
- next_char(k), rem_byte(k));
- fligs++;
- }
- }
- if (skip_byte(k) == 0) {
- k++;
- } else {
- if (skip_byte(k) >= stop_flag)
- break;
- k += skip_byte(k) + 1;
- }
- }
- if (fkerns > 0 || fligs > 0) {
- co = get_charinfo(f, left_boundarychar);
- if (fkerns > 0) {
- set_kern_item(ckerns[fkerns], end_kern, 0);
- fkerns++;
- set_charinfo_kerns(co, ckerns);
- }
- if (fligs > 0) {
- set_ligature_item(cligs[fligs], 0, end_ligature, 0);
- fligs++;
- set_charinfo_ligatures(co, cligs);
- }
- set_charinfo_remainder(co, 0);
- }
- }
-
- /* Read character data */
- for (k = bc; k <= ec; k++) {
- store_char_info(k);
- if (ci._width_index == 0)
- continue;
- if (ci._width_index >= nw || ci._height_index >= nh ||
- ci._depth_index >= nd || ci._italic_index >= ni)
- tfm_abort;
- d = ci._remainder;
- switch (ci._tag) {
- case lig_tag:
- if (d >= nl)
- tfm_abort;
- break;
- case ext_tag:
- if (d >= ne)
- tfm_abort;
- break;
- case list_tag:
- /* We want to make sure that there is no cycle of characters linked together
- by |list_tag| entries, since such a cycle would get \TeX\ into an endless
- loop. If such a cycle exists, the routine here detects it when processing
- the largest character code in the cycle.
- */
- check_byte_range(d);
- while (d < k) { /* |current_character == k| */
- if (char_tag(f, d) != list_tag)
- goto NOT_FOUND; /* not a cycle */
- d = char_remainder(f, d); /* next character on the list */
- };
- if (d == k)
- tfm_abort; /* yes, there's a cycle */
- NOT_FOUND:
- break;
- }
- /* put it in the actual font */
- co = get_charinfo(f, k);
- set_charinfo_index(co, k);
- set_charinfo_tag(co, ci._tag);
- if (ci._tag == ext_tag) {
- set_charinfo_extensible(co, extens[ci._remainder].b0, /* top */
- extens[ci._remainder].b2, /* bot */
- extens[ci._remainder].b1, /* mid */
- extens[ci._remainder].b3); /* rep */
- set_charinfo_remainder(co, 0);
- } else {
- set_charinfo_remainder(co, ci._remainder);
- }
- set_charinfo_width(co, widths[ci._width_index]);
- set_charinfo_height(co, heights[ci._height_index]);
- set_charinfo_depth(co, depths[ci._depth_index]);
- set_charinfo_italic(co, italics[ci._italic_index]);
- };
-
- /* first pass: count ligs and kerns */
-
- xligs = xcalloc((unsigned) (ec + 1), sizeof(int));
- xkerns = xcalloc((unsigned) (ec + 1), sizeof(int));
-
- for (i = bc; i <= ec; i++) {
- if (char_tag(f, i) == lig_tag) {
- k = lig_kern_start(f, i);
- if (skip_byte(k) > stop_flag)
- k = lig_kern_restart(k);
- /* now k is the start index */
- while (1) {
- if (skip_byte(k) <= stop_flag) {
- if (op_byte(k) >= kern_flag) { /* kern */
- xkerns[i]++;
- if (next_char(k) == bchar)
- xkerns[i]++;
- } else { /* lig */
- xligs[i]++;
- if (next_char(k) == bchar)
- xligs[i]++;
- }
- }
- if (skip_byte(k) == 0) {
- k++;
- } else {
- if (skip_byte(k) >= stop_flag)
- break;
- k += skip_byte(k) + 1;
- }
- }
- }
- }
-
- cligs = NULL;
- ckerns = NULL;
-
- for (i = bc; i <= ec; i++) {
- fligs = 0;
- fkerns = 0;
- if (char_tag(f, i) == lig_tag) {
- k = lig_kern_start(f, i);
- if (skip_byte(k) > stop_flag)
- k = lig_kern_restart(k);
- /* now k is the start index */
- if (xligs[i] > 0)
- cligs = xcalloc((unsigned) (xligs[i] + 1), sizeof(liginfo));
- if (xkerns[i] > 0)
- ckerns = xcalloc((unsigned) (xkerns[i] + 1), sizeof(kerninfo));
- while (1) {
- if (skip_byte(k) <= stop_flag) {
- if (op_byte(k) >= kern_flag) { /* kern */
- if (next_char(k) == bchar) {
- set_kern_item(ckerns[fkerns], right_boundarychar,
- kerns[256 * (op_byte(k) - 128) +
- rem_byte(k)]);
- fkerns++;
- }
- set_kern_item(ckerns[fkerns], next_char(k),
- kerns[256 * (op_byte(k) - 128) +
- rem_byte(k)]);
- fkerns++;
- } else { /* lig */
- if (next_char(k) == bchar) {
- set_ligature_item(cligs[fligs],
- (char) (op_byte(k) * 2 + 1),
- right_boundarychar, rem_byte(k));
- fligs++;
- }
- set_ligature_item(cligs[fligs],
- (char) (op_byte(k) * 2 + 1),
- next_char(k), rem_byte(k));
- fligs++;
- }
- }
- if (skip_byte(k) == 0) {
- k++;
- } else {
- if (skip_byte(k) >= stop_flag)
- break;
- k += skip_byte(k) + 1;
- }
- }
- if (fkerns > 0 || fligs > 0) {
- co = get_charinfo(f, i);
- if (fkerns > 0) {
- set_kern_item(ckerns[fkerns], end_kern, 0);
- fkerns++;
- set_charinfo_kerns(co, ckerns);
- }
- if (fligs > 0) {
- set_ligature_item(cligs[fligs], 0, end_ligature, 0);
- fligs++;
- set_charinfo_ligatures(co, cligs);
- }
- set_charinfo_remainder(co, 0);
- }
- }
- }
-
-
- /* Make final adjustments and |goto done| */
-
- /* Now to wrap it up, we have checked all the necessary things about the \.{TFM}
- file, and all we need to do is put the finishing touches on the data for
- the new font.
- */
-
- if (bchar != 65536) {
- co = copy_charinfo(char_info(f, bchar));
- set_right_boundary(f, co);
- }
-
- tfm_success;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,624 @@
+/*
+
+Copyright 2006 Han The Thanh, <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#define isXdigit(c) (isdigit(c) || ('A' <= (c) && (c) <= 'F'))
+
+/*tex
+
+ |UNIC_STRING| is a string allocated by |def_tounicode| while
+ |UNI_EXTRA_STRING| is one allocated by |set_glyph_unicode|.
+
+*/
+
+#define UNI_UNDEF -1
+#define UNI_STRING -2
+#define UNI_EXTRA_STRING -3
+
+static struct avl_table *glyph_unicode_tree = NULL;
+
+static int comp_glyph_unicode_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const glyph_unicode_entry *) pa)->name, ((const glyph_unicode_entry *) pb)->name);
+}
+
+static glyph_unicode_entry *new_glyph_unicode_entry(void)
+{
+ glyph_unicode_entry *e;
+ e = xtalloc(1, glyph_unicode_entry);
+ e->name = NULL;
+ e->code = UNI_UNDEF;
+ e->unicode_seq = NULL;
+ return e;
+}
+
+static void destroy_glyph_unicode_entry(void *pa, void *pb)
+{
+ glyph_unicode_entry *e = (glyph_unicode_entry *) pa;
+ (void) pb;
+ xfree(e->name);
+ if (e->code == UNI_STRING) {
+ xfree(e->unicode_seq);
+ }
+}
+
+void glyph_unicode_free(void)
+{
+ if (glyph_unicode_tree != NULL)
+ avl_destroy(glyph_unicode_tree, destroy_glyph_unicode_entry);
+}
+
+void def_tounicode(str_number glyph, str_number unistr)
+{
+ char buf[SMALL_BUF_SIZE], *p, *ph;
+ char buf2[SMALL_BUF_SIZE], *q;
+ /*tex |0| is invalid, |1| an \UNICODE\ value and |2| a string */
+ int valid_unistr;
+ int i, l;
+ glyph_unicode_entry *gu, t;
+ void **aa;
+ p = makecstring(glyph);
+ assert(strlen(p) < SMALL_BUF_SIZE);
+ strcpy(buf, p);
+ free(p);
+ p = makecstring(unistr);
+ ph = p;
+ /*tex Ignore leading spaces. */
+ while (*p == ' ')
+ p++;
+ l = (int) strlen(p);
+ /*tex Ignore traling spaces. */
+ while (l > 0 && p[l - 1] == ' ')
+ l--;
+ /*tex A \UNICODE\ value is the most common case. */
+ valid_unistr = 1;
+ for (i = 0; i < l; i++) {
+ /*tex If a space occurs we treat this entry as a string. */
+ if (p[i] == ' ')
+ valid_unistr = 2;
+ else if (!isXdigit((unsigned char)p[i])) {
+ valid_unistr = 0;
+ break;
+ }
+ }
+ if (l == 0 || valid_unistr == 0 || strlen(buf) == 0 || strcmp(buf, notdef) == 0) {
+ formatted_warning("tounicode", "invalid parameter(s): %s -> %s", buf, p);
+ return;
+ }
+ if (glyph_unicode_tree == NULL) {
+ glyph_unicode_tree = avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
+ }
+ t.name = buf;
+ /*tex Allow overriding existing entries. */
+ if ((gu = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &t)) != NULL) {
+ if (gu->code == UNI_STRING) {
+ xfree(gu->unicode_seq);
+ }
+ } else {
+ /*tex Make a new entry. */
+ gu = new_glyph_unicode_entry();
+ gu->name = xstrdup(buf);
+ }
+ if (valid_unistr == 2) {
+ /*tex A string can have space(s) that we ignore by copying |p| to |buf2|. */
+ for (q = buf2; *p != 0; p++)
+ if (*p != ' ')
+ *q++ = *p;
+ *q = 0;
+ gu->code = UNI_STRING;
+ gu->unicode_seq = xstrdup(buf2);
+ } else {
+ i = sscanf(p, "%lX", &(gu->code));
+ }
+ aa = avl_probe(glyph_unicode_tree, gu);
+ assert(aa != NULL);
+ free(ph);
+}
+
+static long check_unicode_value(char *s, boolean multiple_value)
+{
+ int l = (int) strlen(s);
+ int i;
+ /*tex Anything that is not |UNI_UNDEF| will do: */
+ long code = 0;
+ if (l == 0)
+ return UNI_UNDEF;
+ if (multiple_value && l % 4 != 0)
+ return UNI_UNDEF;
+ if (!multiple_value && !(4 <= l && l <= 6))
+ return UNI_UNDEF;
+ for (i = 0; i < l; i++) {
+ if (!isXdigit((unsigned char)s[i]))
+ return UNI_UNDEF;
+ if (multiple_value) {
+ if (i % 4 == 3) {
+ if (sscanf(s + i - 3, "%4lX", &code) != 1)
+ return UNI_UNDEF;
+ if (!((0x0000 <= code && code <= 0xD7FF) ||
+ (0xE000 <= code && code <= 0xFFFF)))
+ return UNI_UNDEF;
+ }
+ } else { /* single value */
+ if (i == l - 1) {
+ if (sscanf(s, "%lX", &code) != 1)
+ return UNI_UNDEF;
+ if (!((0x0000 <= code && code <= 0xD7FF) ||
+ (0xE000 <= code && code <= 0x10FFFF)))
+ return UNI_UNDEF;
+ }
+ }
+ }
+ return code;
+}
+
+/*
+
+ This function set proper values to |*gp| based on |s|; in case it returns
+ |gp->code == UNI_EXTRA_STRING| then the caller is responsible for freeing
+ |gp->unicode_seq| too.
+
+*/
+
+static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
+{
+ char buf[SMALL_BUF_SIZE], buf2[SMALL_BUF_SIZE], *p;
+ long code;
+ boolean last_component;
+ glyph_unicode_entry tmp, *ptmp;
+ /*tex Skip dummy entries. */
+ if (s == NULL || s == notdef)
+ return;
+ /*tex Strip everything after the first dot. */
+ p = strchr(s, '.');
+ if (p != NULL) {
+ *buf = 0;
+ strncat(buf, s, (size_t) (p - s));
+ s = buf;
+ }
+ if (strlen(s) == 0)
+ return;
+ /*tex Check for case of multiple components separated by |_|. */
+ p = strchr(s, '_');
+ if (p != NULL) {
+ assert(strlen(s) < sizeof(buf));
+ if (s != buf) {
+ strcpy(buf, s);
+ p = strchr(buf, '_');
+ s = buf;
+ }
+ *buf2 = 0;
+ last_component = false;
+ for (;;) {
+ *p = 0;
+ tmp.code = UNI_UNDEF;
+ set_glyph_unicode(s, &tmp);
+ switch (tmp.code) {
+ case UNI_UNDEF:
+ /*tex Not found, do nothing. */
+ break;
+ case UNI_STRING:
+ /*tex |s| matched an entry with string value in the database. */
+ assert(tmp.unicode_seq != NULL);
+ assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
+ strcat(buf2, tmp.unicode_seq);
+ break;
+ case UNI_EXTRA_STRING:
+ /*tex |s| is a multiple value of form "uniXXXX" */
+ assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
+ strcat(buf2, tmp.unicode_seq);
+ xfree(tmp.unicode_seq);
+ break;
+ default:
+ /*tex
+ |s| matched an entry with numeric value in the database, or a
+ value derived from |uXXXX|.
+ */
+ assert(tmp.code >= 0);
+ strcat(buf2, utf16be_str(tmp.code));
+ }
+ if (last_component)
+ break;
+ s = p + 1;
+ p = strchr(s, '_');
+ if (p == NULL) {
+ p = strend(s);
+ last_component = true;
+ }
+ }
+ gp->code = UNI_EXTRA_STRING;
+ gp->unicode_seq = xstrdup(buf2);
+ return;
+ }
+ /*tex Lookup glyph name in the database. */
+ tmp.name = s;
+ tmp.code = UNI_UNDEF;
+ ptmp = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &tmp);
+ if (ptmp != NULL) {
+ gp->code = ptmp->code;
+ gp->unicode_seq = ptmp->unicode_seq;
+ return;
+ }
+ /*tex Check for case of |uniXXXX|, multiple 4-hex-digit values allowed. */
+ if (str_prefix(s, "uni")) {
+ p = s + strlen("uni");
+ code = check_unicode_value(p, true);
+ if (code != UNI_UNDEF) {
+ if (strlen(p) == 4) {
+ /*tex Single value: */
+ gp->code = code;
+ } else {
+ /*tex Multiple value: */
+ gp->code = UNI_EXTRA_STRING;
+ gp->unicode_seq = xstrdup(p);
+ }
+ }
+ /*tex Since the last case cannot happen: */
+ return;
+ }
+ /*tex Check for case of |uXXXX|, a single value up to 6 hex digits. */
+ if (str_prefix(s, "u")) {
+ p = s + strlen("u");
+ code = check_unicode_value(p, false);
+ if (code != UNI_UNDEF) {
+ assert(code >= 0);
+ gp->code = code;
+ }
+ }
+}
+
+static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp, internal_font_number f)
+{
+ char *s;
+ if (font_tounicode(f)) {
+ if ((s = get_charinfo_tounicode(char_info(f, (int) index))) != NULL) {
+ gp->code = UNI_EXTRA_STRING;
+ gp->unicode_seq = xstrdup(s);
+ } else {
+ /*tex No fall back as we're providing them ourselves. */
+ }
+ } else {
+ /*tex Fall back. */
+ gp->code = index;
+ }
+}
+
+int write_tounicode(PDF pdf, char **glyph_names, char *name)
+{
+ char buf[SMALL_BUF_SIZE], *p;
+ static char builtin_suffix[] = "-builtin";
+ short range_size[257];
+ glyph_unicode_entry gtab[257];
+ int objnum;
+ int i, j;
+ int bfchar_count, bfrange_count, subrange_count;
+ assert(strlen(name) + strlen(builtin_suffix) < SMALL_BUF_SIZE);
+ if (glyph_unicode_tree == NULL) {
+ pdf->gen_tounicode = 0;
+ return 0;
+ }
+ strcpy(buf, name);
+ if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".enc") == 0) {
+ /*tex
+ Strip |.enc| from encoding name.
+ */
+ *p = 0;
+ } else {
+ /*
+ The suffix |.enc| is not present so this is a builtin encoding so the
+ name becomes e.g. |cmr10-builtin|.
+ */
+ strcat(buf, builtin_suffix);
+ }
+ objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ pdf_printf(pdf,
+ "%%!PS-Adobe-3.0 Resource-CMap\n"
+ "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"
+ "%%%%IncludeResource: ProcSet (CIDInit)\n"
+ "%%%%BeginResource: CMap (TeX-%s-0)\n"
+ "%%%%Title: (TeX-%s-0 TeX %s 0)\n"
+ "%%%%Version: 1.000\n"
+ "%%%%EndComments\n"
+ "/CIDInit /ProcSet findresource begin\n"
+ "12 dict begin\n"
+ "begincmap\n"
+ "/CIDSystemInfo\n"
+ "<< /Registry (TeX)\n"
+ "/Ordering (%s)\n"
+ "/Supplement 0\n"
+ ">> def\n"
+ "/CMapName /TeX-%s-0 def\n"
+ "/CMapType 2 def\n"
+ "1 begincodespacerange\n"
+ "<00> <FF>\n" "endcodespacerange\n",
+ buf, buf, buf, buf, buf);
+ /*tex Set gtab: */
+ for (i = 0; i < 256; ++i) {
+ gtab[i].code = UNI_UNDEF;
+ set_glyph_unicode(glyph_names[i], >ab[i]);
+ }
+ gtab[256].code = UNI_UNDEF;
+ /*tex Set |range_size|: */
+ for (i = 0; i < 256;) {
+ if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+ /*tex Single entry: */
+ range_size[i] = 1;
+ i++;
+ } else if (gtab[i].code == UNI_UNDEF) {
+ /*tex No entry: */
+ range_size[i] = 0;
+ i++;
+ } else {
+ /*tex |gtab[i].code >= 0| */
+ j = i;
+ while (i < 256 && gtab[i + 1].code >= 0 && gtab[i].code + 1 == gtab[i + 1].code)
+ i++;
+ /*tex
+ At this point |i| is the last entry of the subrange so we move |i| to
+ the next entry.
+ */
+ i++;
+ range_size[j] = (short) (i - j);
+ }
+ }
+ /*tex Calculate |bfrange_count| and |bfchar_count|. */
+ bfrange_count = 0;
+ bfchar_count = 0;
+ for (i = 0; i < 256;) {
+ if (range_size[i] == 1) {
+ bfchar_count++;
+ i++;
+ } else if (range_size[i] > 1) {
+ bfrange_count++;
+ i += range_size[i];
+ } else
+ i++;
+ }
+ /*tex Write out |bfrange|. */
+ i = 0;
+ write_bfrange:
+ if (bfrange_count > 100)
+ subrange_count = 100;
+ else
+ subrange_count = bfrange_count;
+ bfrange_count -= subrange_count;
+ pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
+ for (j = 0; j < subrange_count; j++) {
+ while (range_size[i] <= 1 && i < 256)
+ i++;
+ assert(i < 256);
+ pdf_printf(pdf, "<%02X> <%02X> <%s>\n", i, i + range_size[i] - 1,
+ utf16be_str(gtab[i].code));
+ i += range_size[i];
+ }
+ pdf_printf(pdf, "endbfrange\n");
+ if (bfrange_count > 0)
+ goto write_bfrange;
+ /*tex Write out |bfchar|. */
+ i = 0;
+ write_bfchar:
+ if (bfchar_count > 100)
+ subrange_count = 100;
+ else
+ subrange_count = bfchar_count;
+ bfchar_count -= subrange_count;
+ pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
+ for (j = 0; j < subrange_count; j++) {
+ while (i < 256) {
+ if (range_size[i] > 1)
+ i += range_size[i];
+ else if (range_size[i] == 0)
+ i++;
+ else
+ break;
+ }
+ assert(i < 256 && gtab[i].code != UNI_UNDEF);
+ if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+ assert(gtab[i].unicode_seq != NULL);
+ pdf_printf(pdf, "<%02X> <%s>\n", i, gtab[i].unicode_seq);
+ } else
+ pdf_printf(pdf, "<%02X> <%s>\n", i, utf16be_str(gtab[i].code));
+ i++;
+ }
+ pdf_printf(pdf, "endbfchar\n");
+ if (bfchar_count > 0)
+ goto write_bfchar;
+ /*tex Free strings allocated by |set_glyph_unicode|. */
+ for (i = 0; i < 256; ++i) {
+ if (gtab[i].code == UNI_EXTRA_STRING)
+ xfree(gtab[i].unicode_seq);
+ }
+ pdf_printf(pdf,
+ "endcmap\n"
+ "CMapName currentdict /CMap defineresource pop\n"
+ "end\n"
+ "end\n"
+ "%%%%EndResource\n"
+ "%%%%EOF\n");
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+ return objnum;
+}
+
+int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+ static int range_size[65537];
+ static glyph_unicode_entry gtab[65537];
+ int objnum;
+ int i, j, k;
+ int bfchar_count, bfrange_count, subrange_count;
+ char *buf;
+ buf = xmalloc((unsigned) (strlen(fo->fd->fontname) + 8));
+ sprintf(buf, "%s-%s", (fo->fd->subset_tag != NULL ? fo->fd->subset_tag : "UCS"), fo->fd->fontname);
+ objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ pdf_printf(pdf,
+ "%%!PS-Adobe-3.0 Resource-CMap\n"
+ "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"
+ "%%%%IncludeResource: ProcSet (CIDInit)\n"
+ "%%%%BeginResource: CMap (TeX-%s-0)\n"
+ "%%%%Title: (TeX-%s-0 TeX %s 0)\n"
+ "%%%%Version: 1.000\n"
+ "%%%%EndComments\n"
+ "/CIDInit /ProcSet findresource begin\n"
+ "12 dict begin\n"
+ "begincmap\n"
+ "/CIDSystemInfo\n"
+ "<< /Registry (TeX)\n"
+ "/Ordering (%s)\n"
+ "/Supplement 0\n"
+ ">> def\n"
+ "/CMapName /TeX-Identity-%s def\n"
+ "/CMapType 2 def\n"
+ "1 begincodespacerange\n"
+ "<0000> <FFFF>\n"
+ "endcodespacerange\n",
+ buf, buf, buf, buf, buf);
+ xfree(buf);
+ /*tex Set up |gtab|: */
+ for (i = 0; i < 65537; ++i) {
+ gtab[i].code = UNI_UNDEF;
+ }
+ for (k = 1; k <= max_font_id(); k++) {
+ if (k == f || -f == pdf_font_num(k)) {
+ for (i = font_bc(k); i <= font_ec(k); i++) {
+ if (quick_char_exists(k, i) && char_used(k, i)) {
+ j = char_index(k, i);
+ if (gtab[j].code == UNI_UNDEF) {
+ set_cid_glyph_unicode(i, >ab[j], f);
+ }
+ }
+ }
+ }
+ }
+ /*tex Set |range_size|: */
+ for (i = 0; i < 65536;) {
+ if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+ /*tex Single entry. */
+ range_size[i] = 1;
+ i++;
+ } else if (gtab[i].code == UNI_UNDEF) {
+ /*tex No entry. */
+ range_size[i] = 0;
+ i++;
+ } else {
+ /*tex |gtab[i].code >= 0| */
+ j = i;
+ k = i % 256;
+ while (i < 65536 && k<255 && gtab[i + 1].code >= 0 &&
+ gtab[i].code + 1 == gtab[i + 1].code) {
+ i++; k++;
+ }
+ /* tex
+ At this point |i| is the last entry of the subrange so we move
+ |i| to the next entry
+ */
+ i++;
+ range_size[j] = i - j;
+ }
+ }
+ /*tex Calculate |bfrange_count| and |bfchar_count|. */
+ bfrange_count = 0;
+ bfchar_count = 0;
+ for (i = 0; i < 65536;) {
+ if (range_size[i] == 1) {
+ bfchar_count++;
+ i++;
+ } else if (range_size[i] > 1) {
+ bfrange_count++;
+ i += range_size[i];
+ } else
+ i++;
+ }
+ /*tex Write out |bfrange|. */
+ i = 0;
+ write_bfrange:
+ if (bfrange_count > 100)
+ subrange_count = 100;
+ else
+ subrange_count = bfrange_count;
+ bfrange_count -= subrange_count;
+ pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
+ for (j = 0; j < subrange_count; j++) {
+ while (range_size[i] <= 1 && i < 65536)
+ i++;
+ pdf_printf(pdf, "<%04X> <%04X> <%s>\n", i, i + range_size[i] - 1, utf16be_str(gtab[i].code));
+ i += range_size[i];
+ }
+ pdf_printf(pdf, "endbfrange\n");
+ if (bfrange_count > 0)
+ goto write_bfrange;
+ /*tex Write out |bfchar| */
+ i = 0;
+ write_bfchar:
+ if (bfchar_count > 100)
+ subrange_count = 100;
+ else
+ subrange_count = bfchar_count;
+ bfchar_count -= subrange_count;
+ pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
+ for (j = 0; j < subrange_count; j++) {
+ while (i < 65536) {
+ if (range_size[i] > 1)
+ i += range_size[i];
+ else if (range_size[i] == 0)
+ i++;
+ else
+ /* |range_size[i] == 1| */
+ break;
+ }
+ assert(i < 65536 && gtab[i].code != UNI_UNDEF);
+ if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+ pdf_printf(pdf, "<%04X> <%s>\n", i, gtab[i].unicode_seq);
+ } else
+ pdf_printf(pdf, "<%04X> <%s>\n", i, utf16be_str(gtab[i].code));
+ i++;
+ }
+ pdf_printf(pdf, "endbfchar\n");
+ if (bfchar_count > 0)
+ goto write_bfchar;
+ /*tex Free strings allocated by |set_glyph_unicode|: */
+ for (i = 0; i < 65536; ++i) {
+ if (gtab[i].code == UNI_EXTRA_STRING)
+ xfree(gtab[i].unicode_seq);
+ }
+ pdf_printf(pdf,
+ "endcmap\n"
+ "CMapName currentdict /CMap defineresource pop\n"
+ "end\n"
+ "end\n"
+ "%%%%EndResource\n"
+ "%%%%EOF\n");
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+ return objnum;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,612 +0,0 @@
-% tounicode.w
-%
-% Copyright 2006 Han The Thanh, <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ @c
-#define isXdigit(c) (isdigit(c) || ('A' <= (c) && (c) <= 'F'))
-#define UNI_UNDEF -1
-#define UNI_STRING -2 /* string allocated by |def_tounicode()| */
-#define UNI_EXTRA_STRING -3 /* string allocated by |set_glyph_unicode()| */
-
-static struct avl_table *glyph_unicode_tree = NULL;
-
-static int comp_glyph_unicode_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const glyph_unicode_entry *) pa)->name,
- ((const glyph_unicode_entry *) pb)->name);
-}
-
-static glyph_unicode_entry *new_glyph_unicode_entry(void)
-{
- glyph_unicode_entry *e;
- e = xtalloc(1, glyph_unicode_entry);
- e->name = NULL;
- e->code = UNI_UNDEF;
- e->unicode_seq = NULL;
- return e;
-}
-
-static void destroy_glyph_unicode_entry(void *pa, void *pb)
-{
- glyph_unicode_entry *e = (glyph_unicode_entry *) pa;
- (void) pb;
- xfree(e->name);
- if (e->code == UNI_STRING) {
- assert(e->unicode_seq != NULL);
- xfree(e->unicode_seq);
- }
-}
-
-void glyph_unicode_free(void)
-{
- if (glyph_unicode_tree != NULL)
- avl_destroy(glyph_unicode_tree, destroy_glyph_unicode_entry);
-}
-
-@ @c
-void def_tounicode(str_number glyph, str_number unistr)
-{
- char buf[SMALL_BUF_SIZE], *p, *ph;
- char buf2[SMALL_BUF_SIZE], *q;
- int valid_unistr; /* 0: invalid; 1: unicode value; 2: string */
- int i, l;
- glyph_unicode_entry *gu, t;
- void **aa;
-
- p = makecstring(glyph);
- assert(strlen(p) < SMALL_BUF_SIZE);
- strcpy(buf, p);
- free(p);
- p = makecstring(unistr);
- ph = p;
- while (*p == ' ')
- p++; /* ignore leading spaces */
- l = (int) strlen(p);
- while (l > 0 && p[l - 1] == ' ')
- l--; /* ignore traling spaces */
- valid_unistr = 1; /* a unicode value is the most common case */
- for (i = 0; i < l; i++) {
- if (p[i] == ' ')
- valid_unistr = 2; /* if a space occurs we treat this entry as a string */
- else if (!isXdigit((unsigned char)p[i])) {
- valid_unistr = 0;
- break;
- }
- }
- if (l == 0 || valid_unistr == 0 || strlen(buf) == 0 || strcmp(buf, notdef) == 0) {
- formatted_warning("tounicode", "invalid parameter(s): %s -> %s", buf, p);
- return;
- }
- if (glyph_unicode_tree == NULL) {
- glyph_unicode_tree =
- avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
- assert(glyph_unicode_tree != NULL);
- }
- t.name = buf;
- /* allow overriding existing entries */
- if ((gu = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &t)) != NULL) {
- if (gu->code == UNI_STRING) {
- assert(gu->unicode_seq != NULL);
- xfree(gu->unicode_seq);
- }
- } else { /* make new entry */
- gu = new_glyph_unicode_entry();
- gu->name = xstrdup(buf);
- }
- if (valid_unistr == 2) { /* a string with space(s) */
- /* copy p to buf2, ignoring spaces */
- for (q = buf2; *p != 0; p++)
- if (*p != ' ')
- *q++ = *p;
- *q = 0;
- gu->code = UNI_STRING;
- gu->unicode_seq = xstrdup(buf2);
- } else {
- i = sscanf(p, "%lX", &(gu->code));
- assert(i == 1);
- }
- aa = avl_probe(glyph_unicode_tree, gu);
- assert(aa != NULL);
- free(ph);
-}
-
-
-@ @c
-static long check_unicode_value(char *s, boolean multiple_value)
-{
- int l = (int) strlen(s);
- int i;
- long code = 0; /* anything that is not |UNI_UNDEF| will do */
-
- if (l == 0)
- return UNI_UNDEF;
- if (multiple_value && l % 4 != 0)
- return UNI_UNDEF;
- if (!multiple_value && !(4 <= l && l <= 6))
- return UNI_UNDEF;
-
- for (i = 0; i < l; i++) {
- if (!isXdigit((unsigned char)s[i]))
- return UNI_UNDEF;
- if (multiple_value) {
- if (i % 4 == 3) {
- if (sscanf(s + i - 3, "%4lX", &code) != 1)
- return UNI_UNDEF;
- if (!((0x0000 <= code && code <= 0xD7FF) ||
- (0xE000 <= code && code <= 0xFFFF)))
- return UNI_UNDEF;
- }
- } else { /* single value */
- if (i == l - 1) {
- if (sscanf(s, "%lX", &code) != 1)
- return UNI_UNDEF;
- if (!((0x0000 <= code && code <= 0xD7FF) ||
- (0xE000 <= code && code <= 0x10FFFF)))
- return UNI_UNDEF;
- }
- }
- }
- return code;
-}
-
-@ This function set proper values to |*gp| based on |s|; in case it returns
- |gp->code == UNI_EXTRA_STRING| then the caller is responsible for freeing
- |gp->unicode_seq| too.
- at c
-static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
-{
- char buf[SMALL_BUF_SIZE], buf2[SMALL_BUF_SIZE], *p;
- long code;
- boolean last_component;
- glyph_unicode_entry tmp, *ptmp;
-
- /* skip dummy entries */
- if (s == NULL || s == notdef)
- return;
-
- /* strip everything after the first dot */
- p = strchr(s, '.');
- if (p != NULL) {
- *buf = 0;
- strncat(buf, s, (size_t) (p - s));
- s = buf;
- }
-
- if (strlen(s) == 0)
- return;
-
- /* check for case of multiple components separated by |'_'| */
- p = strchr(s, '_');
- if (p != NULL) {
- assert(strlen(s) < sizeof(buf));
- if (s != buf) {
- strcpy(buf, s);
- p = strchr(buf, '_');
- s = buf;
- }
- *buf2 = 0;
- last_component = false;
- for (;;) {
- *p = 0;
- tmp.code = UNI_UNDEF;
- set_glyph_unicode(s, &tmp);
- switch (tmp.code) {
- case UNI_UNDEF: /* not found, do nothing */
- break;
- case UNI_STRING: /* s matched an entry with string value in the database */
- assert(tmp.unicode_seq != NULL);
- assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
- strcat(buf2, tmp.unicode_seq);
- break;
- case UNI_EXTRA_STRING: /* s is a multiple value of form "uniXXXX" */
- assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
- strcat(buf2, tmp.unicode_seq);
- xfree(tmp.unicode_seq);
- break;
- default: /* s matched an entry with numeric value in the
- database, or a value derived from "uXXXX" */
- assert(tmp.code >= 0);
- strcat(buf2, utf16be_str(tmp.code));
- }
- if (last_component)
- break;
- s = p + 1;
- p = strchr(s, '_');
- if (p == NULL) {
- p = strend(s);
- last_component = true;
- }
- }
- gp->code = UNI_EXTRA_STRING;
- gp->unicode_seq = xstrdup(buf2);
- return;
- }
-
- /* lookup for glyph name in the database */
- tmp.name = s;
- tmp.code = UNI_UNDEF;
- ptmp = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &tmp);
- if (ptmp != NULL) {
- gp->code = ptmp->code;
- gp->unicode_seq = ptmp->unicode_seq;
- return;
- }
-
- /* check for case of "uniXXXX" (multiple 4-hex-digit values allowed) */
- if (str_prefix(s, "uni")) {
- p = s + strlen("uni");
- code = check_unicode_value(p, true);
- if (code != UNI_UNDEF) {
- if (strlen(p) == 4) /* single value */
- gp->code = code;
- else { /* multiple value */
- gp->code = UNI_EXTRA_STRING;
- gp->unicode_seq = xstrdup(p);
- }
- }
- return; /* since the last case cannot happen */
- }
-
- /* check for case of "uXXXX" (single value up to 6 hex digits) */
- if (str_prefix(s, "u")) {
- p = s + strlen("u");
- code = check_unicode_value(p, false);
- if (code != UNI_UNDEF) {
- assert(code >= 0);
- gp->code = code;
- }
- }
-}
-
-@ @c
-static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp,
- internal_font_number f)
-{
- char *s;
- if (font_tounicode(f)) {
- if ((s = get_charinfo_tounicode(char_info(f, (int) index))) != NULL) {
- gp->code = UNI_EXTRA_STRING;
- gp->unicode_seq = xstrdup(s);
- } else {
- /* no fallback as we're providing them ourselves */
- }
- } else {
- /* fallback */
- gp->code = index;
- }
-}
-
-@ @c
-int write_tounicode(PDF pdf, char **glyph_names, char *name)
-{
- char buf[SMALL_BUF_SIZE], *p;
- static char builtin_suffix[] = "-builtin";
- short range_size[257];
- glyph_unicode_entry gtab[257];
- int objnum;
- int i, j;
- int bfchar_count, bfrange_count, subrange_count;
- assert(strlen(name) + strlen(builtin_suffix) < SMALL_BUF_SIZE);
- if (glyph_unicode_tree == NULL) {
- pdf->gen_tounicode = 0;
- return 0;
- }
- strcpy(buf, name);
- if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".enc") == 0)
- *p = 0; /* strip ".enc" from encoding name */
- else
- strcat(buf, builtin_suffix); /* ".enc" not present, this is a builtin
- encoding so the name is eg "cmr10-builtin" */
- objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
- pdf_begin_dict(pdf);
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- pdf_printf(pdf, "%%!PS-Adobe-3.0 Resource-CMap\n"@/
- "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"@/
- "%%%%IncludeResource: ProcSet (CIDInit)\n"@/
- "%%%%BeginResource: CMap (TeX-%s-0)\n"@/
- "%%%%Title: (TeX-%s-0 TeX %s 0)\n"@/
- "%%%%Version: 1.000\n"@/
- "%%%%EndComments\n"@/
- "/CIDInit /ProcSet findresource begin\n"@/
- "12 dict begin\n"@/
- "begincmap\n"@/
- "/CIDSystemInfo\n"@/
- "<< /Registry (TeX)\n"@/
- "/Ordering (%s)\n"@/
- "/Supplement 0\n"@/
- ">> def\n"@/
- "/CMapName /TeX-%s-0 def\n"@/
- "/CMapType 2 def\n"@/
- "1 begincodespacerange\n"@/
- "<00> <FF>\n" "endcodespacerange\n", buf, buf, buf, buf, buf);
-
- /* set gtab */
- for (i = 0; i < 256; ++i) {
- gtab[i].code = UNI_UNDEF;
- set_glyph_unicode(glyph_names[i], >ab[i]);
- }
- gtab[256].code = UNI_UNDEF;
-
- /* set |range_size| */
- for (i = 0; i < 256;) {
- if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
- range_size[i] = 1; /* single entry */
- i++;
- } else if (gtab[i].code == UNI_UNDEF) {
- range_size[i] = 0; /* no entry */
- i++;
- } else { /* gtab[i].code >= 0 */
- j = i;
- while (i < 256 && gtab[i + 1].code >= 0 &&
- gtab[i].code + 1 == gtab[i + 1].code)
- i++;
- /* at this point i is the last entry of the subrange */
- i++; /* move i to the next entry */
- range_size[j] = (short) (i - j);
- }
- }
-
- /* calculate |bfrange_count| and |bfchar_count| */
- bfrange_count = 0;
- bfchar_count = 0;
- for (i = 0; i < 256;) {
- if (range_size[i] == 1) {
- bfchar_count++;
- i++;
- } else if (range_size[i] > 1) {
- bfrange_count++;
- i += range_size[i];
- } else
- i++;
- }
-
- /* write out bfrange */
- i = 0;
- write_bfrange:
- if (bfrange_count > 100)
- subrange_count = 100;
- else
- subrange_count = bfrange_count;
- bfrange_count -= subrange_count;
- pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
- for (j = 0; j < subrange_count; j++) {
- while (range_size[i] <= 1 && i < 256)
- i++;
- assert(i < 256);
- pdf_printf(pdf, "<%02X> <%02X> <%s>\n", i, i + range_size[i] - 1,
- utf16be_str(gtab[i].code));
- i += range_size[i];
- }
- pdf_printf(pdf, "endbfrange\n");
- if (bfrange_count > 0)
- goto write_bfrange;
-
- /* write out bfchar */
- i = 0;
- write_bfchar:
- if (bfchar_count > 100)
- subrange_count = 100;
- else
- subrange_count = bfchar_count;
- bfchar_count -= subrange_count;
- pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
- for (j = 0; j < subrange_count; j++) {
- while (i < 256) {
- if (range_size[i] > 1)
- i += range_size[i];
- else if (range_size[i] == 0)
- i++;
- else /* |range_size[i] == 1| */
- break;
- }
- assert(i < 256 && gtab[i].code != UNI_UNDEF);
- if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
- assert(gtab[i].unicode_seq != NULL);
- pdf_printf(pdf, "<%02X> <%s>\n", i, gtab[i].unicode_seq);
- } else
- pdf_printf(pdf, "<%02X> <%s>\n", i, utf16be_str(gtab[i].code));
- i++;
- }
- pdf_printf(pdf, "endbfchar\n");
- if (bfchar_count > 0)
- goto write_bfchar;
-
- /* free strings allocated by |set_glyph_unicode()| */
- for (i = 0; i < 256; ++i) {
- if (gtab[i].code == UNI_EXTRA_STRING)
- xfree(gtab[i].unicode_seq);
- }
-
- pdf_printf(pdf, "endcmap\n"
- "CMapName currentdict /CMap defineresource pop\n"
- "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n");
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- return objnum;
-}
-
-@ @c
-int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
-{
-
- static int range_size[65537];
- static glyph_unicode_entry gtab[65537];
- int objnum;
- int i, j, k;
- int bfchar_count, bfrange_count, subrange_count;
- char *buf;
-
- assert(fo->fd->fontname);
- buf = xmalloc((unsigned) (strlen(fo->fd->fontname) + 8));
- sprintf(buf, "%s-%s",
- (fo->fd->subset_tag != NULL ? fo->fd->subset_tag : "UCS"),
- fo->fd->fontname);
-
- objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
- pdf_begin_dict(pdf);
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- pdf_printf(pdf, "%%!PS-Adobe-3.0 Resource-CMap\n"@/
- "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"@/
- "%%%%IncludeResource: ProcSet (CIDInit)\n"@/
- "%%%%BeginResource: CMap (TeX-%s-0)\n"@/
- "%%%%Title: (TeX-%s-0 TeX %s 0)\n"@/
- "%%%%Version: 1.000\n"@/
- "%%%%EndComments\n"@/
- "/CIDInit /ProcSet findresource begin\n"@/
- "12 dict begin\n"@/
- "begincmap\n"@/
- "/CIDSystemInfo\n"@/
- "<< /Registry (TeX)\n"@/
- "/Ordering (%s)\n"@/
- "/Supplement 0\n"@/
- ">> def\n"@/
- "/CMapName /TeX-Identity-%s def\n"@/
- "/CMapType 2 def\n"@/
- "1 begincodespacerange\n"@/
- "<0000> <FFFF>\n"@/
- "endcodespacerange\n", buf, buf, buf, buf, buf);
- xfree(buf);
- /* set up gtab */
- for (i = 0; i < 65537; ++i) {
- gtab[i].code = UNI_UNDEF;
- }
- for (k = 1; k <= max_font_id(); k++) {
- if (k == f || -f == pdf_font_num(k)) {
- for (i = font_bc(k); i <= font_ec(k); i++) {
- if (quick_char_exists(k, i) && char_used(k, i)) {
- j = char_index(k, i);
- if (gtab[j].code == UNI_UNDEF) {
- set_cid_glyph_unicode(i, >ab[j], f);
- }
- }
- }
- }
- }
-
- /* set |range_size| */
- for (i = 0; i < 65536;) {
- if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
- range_size[i] = 1; /* single entry */
- i++;
- } else if (gtab[i].code == UNI_UNDEF) {
- range_size[i] = 0; /* no entry */
- i++;
- } else { /* |gtab[i].code >= 0| */
- j = i;
- k = i % 256;
- while (i < 65536 && k<255 && gtab[i + 1].code >= 0 &&
- gtab[i].code + 1 == gtab[i + 1].code) {
- i++; k++;
- }
- /* at this point i is the last entry of the subrange */
- i++; /* move i to the next entry */
- range_size[j] = i - j;
- }
- }
-
- /* calculate |bfrange_count| and |bfchar_count| */
- bfrange_count = 0;
- bfchar_count = 0;
- for (i = 0; i < 65536;) {
- if (range_size[i] == 1) {
- bfchar_count++;
- i++;
- } else if (range_size[i] > 1) {
- bfrange_count++;
- i += range_size[i];
- } else
- i++;
- }
-
- /* write out bfrange */
- i = 0;
- write_bfrange:
- if (bfrange_count > 100)
- subrange_count = 100;
- else
- subrange_count = bfrange_count;
- bfrange_count -= subrange_count;
- pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
- for (j = 0; j < subrange_count; j++) {
- while (range_size[i] <= 1 && i < 65536)
- i++;
- assert(i < 65536);
- pdf_printf(pdf, "<%04X> <%04X> <%s>\n", i, i + range_size[i] - 1,
- utf16be_str(gtab[i].code));
- i += range_size[i];
- }
- pdf_printf(pdf, "endbfrange\n");
- if (bfrange_count > 0)
- goto write_bfrange;
-
- /* write out bfchar */
- i = 0;
- write_bfchar:
- if (bfchar_count > 100)
- subrange_count = 100;
- else
- subrange_count = bfchar_count;
- bfchar_count -= subrange_count;
- pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
- for (j = 0; j < subrange_count; j++) {
- while (i < 65536) {
- if (range_size[i] > 1)
- i += range_size[i];
- else if (range_size[i] == 0)
- i++;
- else /* |range_size[i] == 1| */
- break;
- }
- assert(i < 65536 && gtab[i].code != UNI_UNDEF);
- if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
- assert(gtab[i].unicode_seq != NULL);
- pdf_printf(pdf, "<%04X> <%s>\n", i, gtab[i].unicode_seq);
- } else
- pdf_printf(pdf, "<%04X> <%s>\n", i, utf16be_str(gtab[i].code));
- i++;
- }
- pdf_printf(pdf, "endbfchar\n");
- if (bfchar_count > 0)
- goto write_bfchar;
-
- /* free strings allocated by |set_glyph_unicode()| */
- for (i = 0; i < 65536; ++i) {
- if (gtab[i].code == UNI_EXTRA_STRING)
- xfree(gtab[i].unicode_seq);
- }
-
- pdf_printf(pdf, "endcmap\n"
- "CMapName currentdict /CMap defineresource pop\n"
- "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n");
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- return objnum;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,569 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+the dvipdfmx project team <dvipdfmx at project.ktug.or.kr>
+Copyright 2006-2012 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#include "font/sfnt.h"
+#include "font/tt_table.h"
+#include "font/tt_glyf.h"
+#include "font/writettf.h"
+
+#define NUM_GLYPH_LIMIT 65534
+#define TABLE_DATA_ALLOC_SIZE 40960
+#define GLYPH_ARRAY_ALLOC_SIZE 256
+
+static USHORT find_empty_slot(struct tt_glyphs *g)
+{
+ USHORT gid;
+ for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
+ if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
+ break;
+ }
+ if (gid == NUM_GLYPH_LIMIT)
+ normal_error("ttf","no empty glyph slot available.");
+ return gid;
+}
+
+USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
+{
+ USHORT idx, new_gid = 0;
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (gid == g->gd[idx].ogid) {
+ new_gid = g->gd[idx].gid;
+ break;
+ }
+ }
+ return new_gid;
+}
+
+USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
+{
+ USHORT idx;
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (gid == g->gd[idx].gid)
+ break;
+ }
+ if (idx == g->num_glyphs)
+ idx = 0;
+ return idx;
+}
+
+USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
+{
+ if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
+ formatted_warning("ttf","slot %u already used", new_gid);
+ } else {
+ if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
+ normal_error("ttf","too many glyphs");
+
+ if (g->num_glyphs >= g->max_glyphs) {
+ g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
+ g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
+ }
+ g->gd[g->num_glyphs].gid = new_gid;
+ g->gd[g->num_glyphs].ogid = gid;
+ g->gd[g->num_glyphs].length = 0;
+ g->gd[g->num_glyphs].data = NULL;
+ g->used_slot[new_gid / 8] = (unsigned char) (g->used_slot[new_gid / 8] | (1 << (7 - (new_gid % 8))));
+ g->num_glyphs++;
+ }
+ if (new_gid > g->last_gid) {
+ g->last_gid = new_gid;
+ }
+ return new_gid;
+}
+
+/*tex Initialization */
+
+struct tt_glyphs *tt_build_init(void)
+{
+ struct tt_glyphs *g;
+ g = NEW(1, struct tt_glyphs);
+ g->num_glyphs = 0;
+ g->max_glyphs = 0;
+ g->last_gid = 0;
+ g->emsize = 1;
+ g->default_advh = 0;
+ g->default_tsb = 0;
+ g->gd = NULL;
+ g->used_slot = NEW(8192, unsigned char);
+ memset(g->used_slot, 0, 8192);
+ tt_add_glyph(g, 0, 0);
+ return g;
+}
+
+void tt_build_finish(struct tt_glyphs *g)
+{
+ if (g) {
+ if (g->gd) {
+ USHORT idx;
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (g->gd[idx].data)
+ RELEASE(g->gd[idx].data);
+ }
+ RELEASE(g->gd);
+ }
+ if (g->used_slot)
+ RELEASE(g->used_slot);
+ RELEASE(g);
+ }
+}
+
+static int glyf_cmp(const void *v1, const void *v2)
+{
+ int cmp = 0;
+ const struct tt_glyph_desc *sv1, *sv2;
+ sv1 = (const struct tt_glyph_desc *) v1;
+ sv2 = (const struct tt_glyph_desc *) v2;
+ if (sv1->gid == sv2->gid)
+ cmp = 0;
+ else if (sv1->gid < sv2->gid)
+ cmp = -1;
+ else
+ cmp = 1;
+ return cmp;
+}
+
+int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
+{
+ char *hmtx_table_data = NULL, *loca_table_data = NULL;
+ char *glyf_table_data = NULL;
+ ULONG hmtx_table_size, loca_table_size, glyf_table_size, glyf_table_used;
+ /*tex Some information available from other \TRUETYPE\ table. */
+ struct tt_head_table *head = NULL;
+ struct tt_hhea_table *hhea = NULL;
+ struct tt_maxp_table *maxp = NULL;
+ struct tt_longMetrics *hmtx, *vmtx = NULL;
+ struct tt_os2__table *os2;
+ /*tex Something temporary: */
+ ULONG *location, offset;
+ long i;
+ /*tex Estimate the most frequently appeared width. */
+ USHORT *w_stat;
+ int tex_font = fd->tex_font;
+ int streamprovider = 0;
+ int callback_id = 0 ;
+ if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
+ streamprovider = font_streamprovider(tex_font);
+ callback_id = callback_defined(glyph_stream_provider_callback);
+ }
+ if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+ normal_error("ttf","invalid font type");
+ if (g->num_glyphs > NUM_GLYPH_LIMIT)
+ normal_error("ttf","too many glyphs");
+ head = tt_read_head_table(sfont);
+ hhea = tt_read_hhea_table(sfont);
+ maxp = tt_read_maxp_table(sfont);
+ if (hhea->metricDataFormat != 0)
+ normal_error("ttf","unknown metricDataFormat");
+ g->emsize = head->unitsPerEm;
+ sfnt_locate_table(sfont, "hmtx");
+ hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+ os2 = tt_read_os2__table(sfont);
+ if (os2) {
+ g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+ g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+ /*tex |dvipdfmx| does this elsewhere! */
+ fd_cur->font_dim[STEMV_CODE].val =
+ (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
+ }
+ if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+ struct tt_vhea_table *vhea;
+ vhea = tt_read_vhea_table(sfont);
+ sfnt_locate_table(sfont, "vmtx");
+ vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics);
+ RELEASE(vhea);
+ } else {
+ vmtx = NULL;
+ }
+ sfnt_locate_table(sfont, "loca");
+ location = NEW(maxp->numGlyphs + 1, ULONG);
+ if (head->indexToLocFormat == 0) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+ } else if (head->indexToLocFormat == 1) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = sfnt_get_ulong(sfont);
+ } else {
+ normal_error("ttf","unknown IndexToLocFormat");
+ }
+ w_stat = NEW(g->emsize + 2, USHORT);
+ memset(w_stat, 0, (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
+ offset = sfnt_locate_table(sfont, "glyf");
+ /*tex
+
+ The |num_glyphs| may grow when composite glyph is found. A component of
+ glyph refered by a composite glyph is appended to |used_glyphs| if it is
+ not already registered in |used_glyphs|. Glyph programs of composite
+ glyphs are modified so that it correctly refer to new gid of their
+ components.
+ */
+ for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
+ USHORT gid;
+ ULONG loc, len;
+ BYTE *p, *endptr;
+ SHORT number_of_contours;
+ if (i >= g->num_glyphs)
+ break;
+ gid = g->gd[i].ogid;
+ if (gid >= maxp->numGlyphs)
+ formatted_error("ttf","invalid glyph index (gid %u)", gid);
+ loc = location[gid];
+ len = location[gid + 1] - loc;
+ g->gd[i].advw = hmtx[gid].advance;
+ g->gd[i].lsb = hmtx[gid].sideBearing;
+ if (vmtx) {
+ g->gd[i].advh = vmtx[gid].advance;
+ g->gd[i].tsb = vmtx[gid].sideBearing;
+ } else {
+ g->gd[i].advh = g->default_advh;
+ g->gd[i].tsb = g->default_tsb;
+ }
+ g->gd[i].length = len;
+ g->gd[i].data = NULL;
+ if (g->gd[i].advw <= g->emsize) {
+ w_stat[g->gd[i].advw]++;
+ } else {
+ /*tex It's larger than em. */
+ w_stat[g->emsize + 1]++;
+ }
+
+ if (len == 0) {
+ /*tex Does not contain any data. */
+ continue;
+ } else if (len < 10) {
+ formatted_error("ttf","invalid glyph data (gid %u)", gid);
+ }
+ /*tex There is no real need for this. */
+ g->gd[i].data = p = NEW(len, BYTE);
+ endptr = p + len;
+ sfnt_seek_set(sfont, (long) (offset + loc));
+ number_of_contours = sfnt_get_short(sfont);
+ p += sfnt_put_short(p, number_of_contours);
+ /* BoundingBox: FWord x 4 */
+ g->gd[i].llx = sfnt_get_short(sfont);
+ g->gd[i].lly = sfnt_get_short(sfont);
+ g->gd[i].urx = sfnt_get_short(sfont);
+ g->gd[i].ury = sfnt_get_short(sfont);
+ if (!vmtx) {
+ /*tex A fix: |vertOriginY == sTypeAscender| */
+ g->gd[i].tsb = (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+ }
+ p += sfnt_put_short(p, g->gd[i].llx);
+ p += sfnt_put_short(p, g->gd[i].lly);
+ p += sfnt_put_short(p, g->gd[i].urx);
+ p += sfnt_put_short(p, g->gd[i].ury);
+ /*tex Read evrything else. */
+ sfnt_read(p, (int) len - 10, sfont);
+ /*tex Fix GIDs of composite glyphs. */
+ if (number_of_contours < 0) {
+ USHORT flags, cgid, new_gid;
+ do {
+ if (p >= endptr)
+ formatted_error("ttf","invalid glyph data (gid %u): %u bytes", gid, (unsigned int) len);
+ flags = (USHORT) (((*p) << 8) | *(p + 1));
+ p += 2;
+ cgid = (USHORT) (((*p) << 8) | *(p + 1));
+ if (cgid >= maxp->numGlyphs) {
+ formatted_error("ttf","invalid gid (%u > %u) in composite glyph %u", cgid, maxp->numGlyphs, gid);
+ }
+ new_gid = tt_find_glyph(g, cgid);
+ if (new_gid == 0) {
+ new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
+ }
+ p += sfnt_put_ushort(p, new_gid);
+ /*tex Just skip remaining part. */
+ p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
+ if (flags & WE_HAVE_A_SCALE) {
+ /*tex |F2Dot14| */
+ p += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+ /*tex two times |F2Dot14| */
+ p += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ /*tex four times |F2Dot14| */
+ p += 8;
+ }
+ } while (flags & MORE_COMPONENTS);
+ /*tex
+
+ TrueType instructions comes here. The call pattern is:
+
+ \starttyping
+ |length_of_instruction| (|ushort|)
+ instruction (|byte * length_of_instruction|)
+ \stoptyping
+
+ */
+ }
+ }
+ RELEASE(location);
+ RELEASE(hmtx);
+ if (vmtx) {
+ RELEASE(vmtx);
+ }
+ {
+ int max_count = -1;
+ g->dw = g->gd[0].advw;
+ for (i = 0; i < g->emsize + 1; i++) {
+ if (w_stat[i] > max_count) {
+ max_count = w_stat[i];
+ g->dw = (USHORT) i;
+ }
+ }
+ }
+ RELEASE(w_stat);
+ qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
+ {
+ USHORT prev, last_advw;
+ char *p, *q;
+ int padlen, num_hm_known;
+ glyf_table_size = 0UL;
+ num_hm_known = 0;
+ last_advw = g->gd[g->num_glyphs - 1].advw;
+ for (i = g->num_glyphs - 1; i >= 0; i--) {
+ padlen =
+ (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+ glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
+ if (!num_hm_known && last_advw != g->gd[i].advw) {
+ hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
+ num_hm_known = 1;
+ }
+ }
+ /*tex All advance widths are the same. */
+ if (!num_hm_known) {
+ hhea->numberOfHMetrics = 1;
+ }
+ hmtx_table_size = (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
+ /*tex
+
+ Choosing short format does not always give good result when
+ compressed. Sometimes increases size.
+
+ */
+ if (glyf_table_size < 0x20000UL) {
+ head->indexToLocFormat = 0;
+ loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
+ } else {
+ head->indexToLocFormat = 1;
+ loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
+ }
+ hmtx_table_data = p = NEW(hmtx_table_size, char);
+ loca_table_data = q = NEW(loca_table_size, char);
+ glyf_table_data = NEW(glyf_table_size, char);
+ glyf_table_used = 0;
+ offset = 0UL;
+ prev = 0;
+ for (i = 0; i < g->num_glyphs; i++) {
+ long gap, j;
+ gap = (long) g->gd[i].gid - prev - 1;
+ for (j = 1; j <= gap; j++) {
+ if (prev + j == hhea->numberOfHMetrics - 1) {
+ p += sfnt_put_ushort(p, last_advw);
+ } else if (prev + j < hhea->numberOfHMetrics) {
+ p += sfnt_put_ushort(p, 0);
+ }
+ p += sfnt_put_short(p, 0);
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+ }
+ if (g->gd[i].gid < hhea->numberOfHMetrics) {
+ p += sfnt_put_ushort(p, g->gd[i].advw);
+ }
+ p += sfnt_put_short(p, g->gd[i].lsb);
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+ if (callback_id > 0) {
+ lstring * result;
+ long size = 0;
+ run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result);
+ padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
+ size = (size_t) result->l + (ULONG) padlen;
+ if (glyf_table_used + size >= glyf_table_size) {
+ glyf_table_size = glyf_table_size + 20 * size; /* just a guess */
+ glyf_table_data = xrealloc(glyf_table_data, (unsigned)((unsigned)glyf_table_size*sizeof(char)));
+ }
+ glyf_table_used += size;
+ memset(glyf_table_data + offset, 0, (size_t) size);
+ memcpy(glyf_table_data + offset, (const char *) result->s, (size_t) result->l);
+ offset += size;
+ xfree(result);
+ } else {
+ padlen = (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+ memset(glyf_table_data + offset, 0, (size_t) (g->gd[i].length + (ULONG) padlen));
+ memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
+ offset += (g->gd[i].length + (ULONG) padlen);
+ }
+ prev = g->gd[i].gid;
+ RELEASE(g->gd[i].data);
+ /*tex We free data here since it consume much memory. */
+ g->gd[i].length = 0;
+ g->gd[i].data = NULL;
+ }
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+ sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
+ sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
+ if (callback_id > 0) {
+ glyf_table_size = glyf_table_used;
+ }
+ sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
+ }
+ head->checkSumAdjustment = 0;
+ maxp->numGlyphs = (USHORT) (g->last_gid + 1);
+ sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
+ sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
+ sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
+ RELEASE(maxp);
+ RELEASE(hhea);
+ RELEASE(head);
+ if (os2) {
+ RELEASE(os2);
+ }
+ return 0;
+}
+
+int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
+{
+ struct tt_head_table *head = NULL;
+ struct tt_hhea_table *hhea = NULL;
+ struct tt_maxp_table *maxp = NULL;
+ struct tt_longMetrics *hmtx, *vmtx = NULL;
+ struct tt_os2__table *os2;
+ ULONG *location, offset;
+ long i;
+ USHORT *w_stat;
+ if (sfont == NULL || sfont->buffer == NULL)
+ normal_error("ttf","file not opened");
+ if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+ normal_error("ttf","invalid font type");
+ head = tt_read_head_table(sfont);
+ hhea = tt_read_hhea_table(sfont);
+ maxp = tt_read_maxp_table(sfont);
+ if (hhea->metricDataFormat != 0)
+ normal_error("ttf","unknown metricDataFormat");
+ g->emsize = head->unitsPerEm;
+ sfnt_locate_table(sfont, "hmtx");
+ hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+ os2 = tt_read_os2__table(sfont);
+ g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+ g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+ if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+ struct tt_vhea_table *vhea;
+ vhea = tt_read_vhea_table(sfont);
+ sfnt_locate_table(sfont, "vmtx");
+ vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics);
+ RELEASE(vhea);
+ } else {
+ vmtx = NULL;
+ }
+ sfnt_locate_table(sfont, "loca");
+ location = NEW(maxp->numGlyphs + 1, ULONG);
+ if (head->indexToLocFormat == 0) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+ } else if (head->indexToLocFormat == 1) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = sfnt_get_ulong(sfont);
+ } else {
+ normal_error("ttf","inknown IndexToLocFormat");
+ }
+ w_stat = NEW(g->emsize + 2, USHORT);
+ memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
+ /*tex Read glyf table. */
+ offset = sfnt_locate_table(sfont, "glyf");
+ for (i = 0; i < g->num_glyphs; i++) {
+ USHORT gid;
+ ULONG loc, len;
+ gid = g->gd[i].ogid;
+ if (gid >= maxp->numGlyphs)
+ formatted_error("ttf","invalid glyph index (gid %u)", gid);
+ loc = location[gid];
+ len = location[gid + 1] - loc;
+ g->gd[i].advw = hmtx[gid].advance;
+ g->gd[i].lsb = hmtx[gid].sideBearing;
+ if (vmtx) {
+ g->gd[i].advh = vmtx[gid].advance;
+ g->gd[i].tsb = vmtx[gid].sideBearing;
+ } else {
+ g->gd[i].advh = g->default_advh;
+ g->gd[i].tsb = g->default_tsb;
+ }
+ g->gd[i].length = len;
+ g->gd[i].data = NULL;
+ if (g->gd[i].advw <= g->emsize) {
+ w_stat[g->gd[i].advw]++;
+ } else {
+ /*tex It's larger than em: */
+ w_stat[g->emsize + 1]++;
+ }
+ if (len == 0) {
+ /*tex No data. */
+ continue;
+ } else if (len < 10) {
+ formatted_error("ttf","invalid glyph data (gid %u)", gid);
+ }
+ sfnt_seek_set(sfont, (long) (offset + loc));
+ /*tex Skip the number of contours */
+ (void)sfnt_get_short(sfont);
+ /*tex Fetch the BoundingBox. */
+ g->gd[i].llx = sfnt_get_short(sfont);
+ g->gd[i].lly = sfnt_get_short(sfont);
+ g->gd[i].urx = sfnt_get_short(sfont);
+ g->gd[i].ury = sfnt_get_short(sfont);
+ if (!vmtx) {
+ /*tex We fix |vertOriginY == sTypeAscender|. */
+ g->gd[i].tsb = (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+ }
+ }
+ RELEASE(location);
+ RELEASE(hmtx);
+ RELEASE(maxp);
+ RELEASE(hhea);
+ RELEASE(head);
+ RELEASE(os2);
+ if (vmtx) {
+ RELEASE(vmtx);
+ }
+ {
+ int max_count = -1;
+ g->dw = g->gd[0].advw;
+ for (i = 0; i < g->emsize + 1; i++) {
+ if (w_stat[i] > max_count) {
+ max_count = w_stat[i];
+ g->dw = (USHORT) i;
+ }
+ }
+ }
+ RELEASE(w_stat);
+ return 0;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,695 +0,0 @@
-% tt_glyf.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@* Subsetting glyf, updating loca, hmtx, etc.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-#include "font/sfnt.h"
-#include "font/tt_table.h"
-#include "font/tt_glyf.h"
-#include "font/writettf.h"
-
-@ @c
-#define NUM_GLYPH_LIMIT 65534
-#define TABLE_DATA_ALLOC_SIZE 40960
-#define GLYPH_ARRAY_ALLOC_SIZE 256
-
-static USHORT find_empty_slot(struct tt_glyphs *g)
-{
- USHORT gid;
-
- ASSERT(g);
-
- for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
- if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
- break;
- }
- if (gid == NUM_GLYPH_LIMIT)
- normal_error("ttf","no empty glyph slot available.");
-
- return gid;
-}
-
-USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
-{
- USHORT idx, new_gid = 0;
-
- ASSERT(g);
-
- for (idx = 0; idx < g->num_glyphs; idx++) {
- if (gid == g->gd[idx].ogid) {
- new_gid = g->gd[idx].gid;
- break;
- }
- }
-
- return new_gid;
-}
-
-USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
-{
- USHORT idx;
-
- ASSERT(g);
-
- for (idx = 0; idx < g->num_glyphs; idx++) {
- if (gid == g->gd[idx].gid)
- break;
- }
- if (idx == g->num_glyphs)
- idx = 0;
-
- return idx;
-}
-
-USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
-{
- ASSERT(g);
-
- if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
- formatted_warning("ttf","slot %u already used", new_gid);
- } else {
- if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
- normal_error("ttf","too many glyphs");
-
- if (g->num_glyphs >= g->max_glyphs) {
- g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
- g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
- }
- g->gd[g->num_glyphs].gid = new_gid;
- g->gd[g->num_glyphs].ogid = gid;
- g->gd[g->num_glyphs].length = 0;
- g->gd[g->num_glyphs].data = NULL;
- g->used_slot[new_gid / 8] =
- (unsigned char) (g->used_slot[new_gid /
- 8] | (1 << (7 - (new_gid % 8))));
- g->num_glyphs++;
- }
-
- if (new_gid > g->last_gid) {
- g->last_gid = new_gid;
- }
-
- return new_gid;
-}
-
-
-@ Initialization
- at c
-struct tt_glyphs *tt_build_init(void)
-{
- struct tt_glyphs *g;
-
- g = NEW(1, struct tt_glyphs);
-
- g->num_glyphs = 0;
- g->max_glyphs = 0;
- g->last_gid = 0;
- g->emsize = 1;
- g->default_advh = 0;
- g->default_tsb = 0;
- g->gd = NULL;
- g->used_slot = NEW(8192, unsigned char);
- memset(g->used_slot, 0, 8192);
- tt_add_glyph(g, 0, 0);
-
- return g;
-}
-
-void tt_build_finish(struct tt_glyphs *g)
-{
- if (g) {
- if (g->gd) {
- USHORT idx;
- for (idx = 0; idx < g->num_glyphs; idx++) {
- if (g->gd[idx].data)
- RELEASE(g->gd[idx].data);
- }
- RELEASE(g->gd);
- }
- if (g->used_slot)
- RELEASE(g->used_slot);
- RELEASE(g);
- }
-}
-
-static int glyf_cmp(const void *v1, const void *v2)
-{
- int cmp = 0;
- const struct tt_glyph_desc *sv1, *sv2;
-
- sv1 = (const struct tt_glyph_desc *) v1;
- sv2 = (const struct tt_glyph_desc *) v2;
-
- if (sv1->gid == sv2->gid)
- cmp = 0;
- else if (sv1->gid < sv2->gid)
- cmp = -1;
- else
- cmp = 1;
-
- return cmp;
-}
-
-@ @c
-int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
-{
- char *hmtx_table_data = NULL, *loca_table_data = NULL;
- char *glyf_table_data = NULL;
- ULONG hmtx_table_size, loca_table_size, glyf_table_size, glyf_table_used;
- /* some information available from other TrueType table */
- struct tt_head_table *head = NULL;
- struct tt_hhea_table *hhea = NULL;
- struct tt_maxp_table *maxp = NULL;
- struct tt_longMetrics *hmtx, *vmtx = NULL;
- struct tt_os2__table *os2;
- /* temp */
- ULONG *location, offset;
- long i;
- USHORT *w_stat; /* Estimate most frequently appeared width */
-
- int tex_font = fd->tex_font;
- int streamprovider = 0;
- int callback_id = 0 ;
- if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
- streamprovider = font_streamprovider(tex_font);
- callback_id = callback_defined(glyph_stream_provider_callback);
- }
-
- ASSERT(g);
-
- if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
- normal_error("ttf","invalid font type");
-
- if (g->num_glyphs > NUM_GLYPH_LIMIT)
- normal_error("ttf","too many glyphs");
-
- /*
- Read head, hhea, maxp, loca:
-
- unitsPerEm --> head
-
- numHMetrics --> hhea
-
- indexToLocFormat --> head
-
- numGlyphs --> maxp
- */
- head = tt_read_head_table(sfont);
- hhea = tt_read_hhea_table(sfont);
- maxp = tt_read_maxp_table(sfont);
-
- if (hhea->metricDataFormat != 0)
- normal_error("ttf","unknown metricDataFormat");
-
- g->emsize = head->unitsPerEm;
-
- sfnt_locate_table(sfont, "hmtx");
- hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
-
- os2 = tt_read_os2__table(sfont);
- if (os2) {
- g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
- g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
-
- /* dvipdfmx does this elsewhere! */
- fd_cur->font_dim[STEMV_CODE].val =
- (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
- }
-
- if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
- struct tt_vhea_table *vhea;
- vhea = tt_read_vhea_table(sfont);
- sfnt_locate_table(sfont, "vmtx");
- vmtx =
- tt_read_longMetrics(sfont, maxp->numGlyphs,
- vhea->numOfLongVerMetrics);
- RELEASE(vhea);
- } else {
- vmtx = NULL;
- }
-
- sfnt_locate_table(sfont, "loca");
- location = NEW(maxp->numGlyphs + 1, ULONG);
- if (head->indexToLocFormat == 0) {
- for (i = 0; i <= maxp->numGlyphs; i++)
- location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
- } else if (head->indexToLocFormat == 1) {
- for (i = 0; i <= maxp->numGlyphs; i++)
- location[i] = sfnt_get_ulong(sfont);
- } else {
- normal_error("ttf","unknown IndexToLocFormat");
- }
-
- w_stat = NEW(g->emsize + 2, USHORT);
- memset(w_stat, 0,
- (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
- /*
- * Read glyf table.
- */
- offset = sfnt_locate_table(sfont, "glyf");
- /*
- The |num_glyphs| may grow when composite glyph is found.
- A component of glyph refered by a composite glyph is appended
- to |used_glyphs| if it is not already registered in |used_glyphs|.
- Glyph programs of composite glyphs are modified so that it
- correctly refer to new gid of their components.
- */
- for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
- USHORT gid; /* old gid */
- ULONG loc, len;
- BYTE *p, *endptr;
- SHORT number_of_contours;
-
- if (i >= g->num_glyphs) /* finished */
- break;
-
- gid = g->gd[i].ogid;
- if (gid >= maxp->numGlyphs)
- formatted_error("ttf","invalid glyph index (gid %u)", gid);
-
- loc = location[gid];
- len = location[gid + 1] - loc;
- g->gd[i].advw = hmtx[gid].advance;
- g->gd[i].lsb = hmtx[gid].sideBearing;
- if (vmtx) {
- g->gd[i].advh = vmtx[gid].advance;
- g->gd[i].tsb = vmtx[gid].sideBearing;
- } else {
- g->gd[i].advh = g->default_advh;
- g->gd[i].tsb = g->default_tsb;
- }
- g->gd[i].length = len;
- g->gd[i].data = NULL;
- if (g->gd[i].advw <= g->emsize) {
- w_stat[g->gd[i].advw]++;
- } else {
- w_stat[g->emsize + 1]++; /* larger than em */
- }
-
- if (len == 0) { /* Does not contains any data. */
- continue;
- } else if (len < 10) {
- formatted_error("ttf","invalid glyph data (gid %u)", gid);
- }
-
-/* todo: no need for this */
- g->gd[i].data = p = NEW(len, BYTE);
- endptr = p + len;
-
- sfnt_seek_set(sfont, (long) (offset + loc));
- number_of_contours = sfnt_get_short(sfont);
- p += sfnt_put_short(p, number_of_contours);
-
- /* BoundingBox: FWord x 4 */
- g->gd[i].llx = sfnt_get_short(sfont);
- g->gd[i].lly = sfnt_get_short(sfont);
- g->gd[i].urx = sfnt_get_short(sfont);
- g->gd[i].ury = sfnt_get_short(sfont);
- /* |_FIXME_| */
-#if 1
- if (!vmtx) /* |vertOriginY == sTypeAscender| */
- g->gd[i].tsb =
- (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
- p += sfnt_put_short(p, g->gd[i].llx);
- p += sfnt_put_short(p, g->gd[i].lly);
- p += sfnt_put_short(p, g->gd[i].urx);
- p += sfnt_put_short(p, g->gd[i].ury);
-
- /* Read evrything else. */
- sfnt_read(p, (int) len - 10, sfont);
- /*
- Fix GIDs of composite glyphs.
- */
- if (number_of_contours < 0) {
- USHORT flags, cgid, new_gid; /* flag, gid of a component */
- do {
- if (p >= endptr)
- formatted_error("ttf","invalid glyph data (gid %u): %u bytes", gid, (unsigned int) len);
- /*
- * Flags and gid of component glyph are both USHORT.
- */
- flags = (USHORT) (((*p) << 8) | *(p + 1));
- p += 2;
- cgid = (USHORT) (((*p) << 8) | *(p + 1));
- if (cgid >= maxp->numGlyphs) {
- formatted_error("ttf","invalid gid (%u > %u) in composite glyph %u", cgid, maxp->numGlyphs, gid);
- }
- new_gid = tt_find_glyph(g, cgid);
- if (new_gid == 0) {
- new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
- }
- p += sfnt_put_ushort(p, new_gid);
- /*
- * Just skip remaining part.
- */
- p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
- if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
- p += 2;
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
- p += 4;
- else if (flags & WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
- p += 8;
- } while (flags & MORE_COMPONENTS);
- /*
- TrueType instructions comes here:
-
- |length_of_instruction| (|ushort|)
-
- instruction (|byte * length_of_instruction|)
- */
- }
- }
- RELEASE(location);
- RELEASE(hmtx);
- if (vmtx)
- RELEASE(vmtx);
-
- {
- int max_count = -1;
-
- g->dw = g->gd[0].advw;
- for (i = 0; i < g->emsize + 1; i++) {
- if (w_stat[i] > max_count) {
- max_count = w_stat[i];
- g->dw = (USHORT) i;
- }
- }
- }
- RELEASE(w_stat);
-
- qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
- {
- USHORT prev, last_advw;
- char *p, *q;
- int padlen, num_hm_known;
-
- glyf_table_size = 0UL;
- num_hm_known = 0;
- last_advw = g->gd[g->num_glyphs - 1].advw;
- for (i = g->num_glyphs - 1; i >= 0; i--) {
- padlen =
- (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
- glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
- if (!num_hm_known && last_advw != g->gd[i].advw) {
- hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
- num_hm_known = 1;
- }
- }
- /* All advance widths are same. */
- if (!num_hm_known) {
- hhea->numberOfHMetrics = 1;
- }
- hmtx_table_size =
- (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
-
- /*
- Choosing short format does not always give good result
- when compressed. Sometimes increases size.
- */
- if (glyf_table_size < 0x20000UL) {
- head->indexToLocFormat = 0;
- loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
- } else {
- head->indexToLocFormat = 1;
- loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
- }
-
- hmtx_table_data = p = NEW(hmtx_table_size, char);
- loca_table_data = q = NEW(loca_table_size, char);
- glyf_table_data = NEW(glyf_table_size, char);
- glyf_table_used = 0;
-
- offset = 0UL;
- prev = 0;
- for (i = 0; i < g->num_glyphs; i++) {
- long gap, j;
- gap = (long) g->gd[i].gid - prev - 1;
- for (j = 1; j <= gap; j++) {
- if (prev + j == hhea->numberOfHMetrics - 1) {
- p += sfnt_put_ushort(p, last_advw);
- } else if (prev + j < hhea->numberOfHMetrics) {
- p += sfnt_put_ushort(p, 0);
- }
- p += sfnt_put_short(p, 0);
- if (head->indexToLocFormat == 0) {
- q += sfnt_put_ushort(q, (USHORT) (offset / 2));
- } else {
- q += sfnt_put_ulong(q, (LONG) offset);
- }
- }
- if (g->gd[i].gid < hhea->numberOfHMetrics) {
- p += sfnt_put_ushort(p, g->gd[i].advw);
- }
- p += sfnt_put_short(p, g->gd[i].lsb);
- if (head->indexToLocFormat == 0) {
- q += sfnt_put_ushort(q, (USHORT) (offset / 2));
- } else {
- q += sfnt_put_ulong(q, (LONG) offset);
- }
-
- if (callback_id > 0) {
-
- lstring * result;
- long size = 0;
- run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result); /* this call can be sped up */
- padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
- size = (size_t) result->l + (ULONG) padlen;
- if (glyf_table_used + size >= glyf_table_size) {
- glyf_table_size = glyf_table_size + 20 * size; /* just a guess */
- glyf_table_data = xrealloc(glyf_table_data, (unsigned)((unsigned)glyf_table_size*sizeof(char)));
- }
- glyf_table_used += size;
- memset(glyf_table_data + offset, 0, (size_t) size);
- memcpy(glyf_table_data + offset, (const char *) result->s, (size_t) result->l);
- offset += size;
- xfree(result);
-
- } else {
-
- padlen = (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
- memset(glyf_table_data + offset, 0, (size_t) (g->gd[i].length + (ULONG) padlen));
- memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
- offset += (g->gd[i].length + (ULONG) padlen);
-
- }
- prev = g->gd[i].gid;
- RELEASE(g->gd[i].data);
- /* free data here since it consume much memory */
- g->gd[i].length = 0;
- g->gd[i].data = NULL;
- }
- if (head->indexToLocFormat == 0) {
- q += sfnt_put_ushort(q, (USHORT) (offset / 2));
- } else {
- q += sfnt_put_ulong(q, (LONG) offset);
- }
-
- sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
- sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
- if (callback_id > 0) {
- glyf_table_size = glyf_table_used;
- }
- sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
- }
-
- head->checkSumAdjustment = 0;
- maxp->numGlyphs = (USHORT) (g->last_gid + 1);
-
- /* TODO */
- sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
- sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
- sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
- RELEASE(maxp);
- RELEASE(hhea);
- RELEASE(head);
- if (os2)
- RELEASE(os2);
-
- return 0;
-}
-
-int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
-{
- struct tt_head_table *head = NULL;
- struct tt_hhea_table *hhea = NULL;
- struct tt_maxp_table *maxp = NULL;
- struct tt_longMetrics *hmtx, *vmtx = NULL;
- struct tt_os2__table *os2;
- /* temp */
- ULONG *location, offset;
- long i;
- USHORT *w_stat;
-
- ASSERT(g);
-
- if (sfont == NULL ||
-#ifdef XETEX
- sfont->ft_face == NULL
-#elif defined(pdfTeX)
- sfont->buffer == NULL
-#else
- sfont->stream == NULL
-#endif
- )
- normal_error("ttf","file not opened");
-
- if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
- normal_error("ttf","invalid font type");
-
- /*
- Read head, hhea, maxp, loca:
-
- unitsPerEm --> head
-
- numHMetrics --> hhea
-
- indexToLocFormat --> head
-
- numGlyphs --> maxp
- */
- head = tt_read_head_table(sfont);
- hhea = tt_read_hhea_table(sfont);
- maxp = tt_read_maxp_table(sfont);
-
- if (hhea->metricDataFormat != 0)
- normal_error("ttf","unknown metricDataFormat");
-
- g->emsize = head->unitsPerEm;
-
- sfnt_locate_table(sfont, "hmtx");
- hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
-
- os2 = tt_read_os2__table(sfont);
- g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
- g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
-
- if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
- struct tt_vhea_table *vhea;
- vhea = tt_read_vhea_table(sfont);
- sfnt_locate_table(sfont, "vmtx");
- vmtx =
- tt_read_longMetrics(sfont, maxp->numGlyphs,
- vhea->numOfLongVerMetrics);
- RELEASE(vhea);
- } else {
- vmtx = NULL;
- }
-
- sfnt_locate_table(sfont, "loca");
- location = NEW(maxp->numGlyphs + 1, ULONG);
- if (head->indexToLocFormat == 0) {
- for (i = 0; i <= maxp->numGlyphs; i++)
- location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
- } else if (head->indexToLocFormat == 1) {
- for (i = 0; i <= maxp->numGlyphs; i++)
- location[i] = sfnt_get_ulong(sfont);
- } else {
- normal_error("ttf","inknown IndexToLocFormat");
- }
-
- w_stat = NEW(g->emsize + 2, USHORT);
- memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
- /*
- Read glyf table.
- */
- offset = sfnt_locate_table(sfont, "glyf");
- for (i = 0; i < g->num_glyphs; i++) {
- USHORT gid; /* old gid */
- ULONG loc, len;
- /*SHORT number_of_contours;*/
-
- gid = g->gd[i].ogid;
- if (gid >= maxp->numGlyphs)
- formatted_error("ttf","invalid glyph index (gid %u)", gid);
-
- loc = location[gid];
- len = location[gid + 1] - loc;
- g->gd[i].advw = hmtx[gid].advance;
- g->gd[i].lsb = hmtx[gid].sideBearing;
- if (vmtx) {
- g->gd[i].advh = vmtx[gid].advance;
- g->gd[i].tsb = vmtx[gid].sideBearing;
- } else {
- g->gd[i].advh = g->default_advh;
- g->gd[i].tsb = g->default_tsb;
- }
- g->gd[i].length = len;
- g->gd[i].data = NULL;
-
- if (g->gd[i].advw <= g->emsize) {
- w_stat[g->gd[i].advw]++;
- } else {
- w_stat[g->emsize + 1]++; /* larger than em */
- }
-
- if (len == 0) { /* Does not contains any data. */
- continue;
- } else if (len < 10) {
- formatted_error("ttf","invalid glyph data (gid %u)", gid);
- }
-
- sfnt_seek_set(sfont, (long) (offset + loc));
- /*number_of_contours = */(void)sfnt_get_short(sfont);
-
- /* BoundingBox: FWord x 4 */
- g->gd[i].llx = sfnt_get_short(sfont);
- g->gd[i].lly = sfnt_get_short(sfont);
- g->gd[i].urx = sfnt_get_short(sfont);
- g->gd[i].ury = sfnt_get_short(sfont);
- /* |_FIXME_| */
-#if 1
- if (!vmtx) /* |vertOriginY == sTypeAscender| */
- g->gd[i].tsb =
- (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
- }
- RELEASE(location);
- RELEASE(hmtx);
- RELEASE(maxp);
- RELEASE(hhea);
- RELEASE(head);
- RELEASE(os2);
-
- if (vmtx)
- RELEASE(vmtx);
-
- {
- int max_count = -1;
-
- g->dw = g->gd[0].advw;
- for (i = 0; i < g->emsize + 1; i++) {
- if (w_stat[i] > max_count) {
- max_count = w_stat[i];
- g->dw = (USHORT) i;
- }
- }
- }
- RELEASE(w_stat);
-
-
- return 0;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,404 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project
+ team <dvipdfmx at project.ktug.or.kr>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <stdio.h>
+#include "font/sfnt.h"
+#include "font/tt_table.h"
+
+/*tex
+
+ Tables contain information referred by other tables.
+
+*/
+
+char *tt_pack_head_table(struct tt_head_table *table)
+{
+ int i;
+ char *p, *data;
+ if (table == NULL)
+ normal_error("ttf","passed NULL pointer");
+ p = data = NEW(TT_HEAD_TABLE_SIZE, char);
+ p += sfnt_put_ulong(p, (LONG) table->version);
+ p += sfnt_put_ulong(p, (LONG) table->fontRevision);
+ p += sfnt_put_ulong(p, (LONG) table->checkSumAdjustment);
+ p += sfnt_put_ulong(p, (LONG) table->magicNumber);
+ p += sfnt_put_ushort(p, table->flags);
+ p += sfnt_put_ushort(p, table->unitsPerEm);
+ for (i = 0; i < 8; i++) {
+ *(p++) = (char) (table->created)[i];
+ }
+ for (i = 0; i < 8; i++) {
+ *(p++) = (char) (table->modified)[i];
+ }
+ p += sfnt_put_short(p, table->xMin);
+ p += sfnt_put_short(p, table->yMin);
+ p += sfnt_put_short(p, table->xMax);
+ p += sfnt_put_short(p, table->yMax);
+ p += sfnt_put_ushort(p, table->macStyle);
+ p += sfnt_put_ushort(p, table->lowestRecPPEM);
+ p += sfnt_put_short(p, table->fontDirectionHint);
+ p += sfnt_put_short(p, table->indexToLocFormat);
+ p += sfnt_put_short(p, table->glyphDataFormat);
+ return data;
+}
+
+struct tt_head_table *tt_read_head_table(sfnt * sfont)
+{
+ int i;
+ struct tt_head_table *table = NULL;
+ table = NEW(1, struct tt_head_table);
+ sfnt_locate_table(sfont, "head");
+ table->version = sfnt_get_ulong(sfont);
+ table->fontRevision = sfnt_get_ulong(sfont);
+ table->checkSumAdjustment = sfnt_get_ulong(sfont);
+ table->magicNumber = sfnt_get_ulong(sfont);
+ table->flags = sfnt_get_ushort(sfont);
+ table->unitsPerEm = sfnt_get_ushort(sfont);
+ for (i = 0; i < 8; i++) {
+ (table->created)[i] = sfnt_get_byte(sfont);
+ }
+ for (i = 0; i < 8; i++) {
+ (table->modified)[i] = sfnt_get_byte(sfont);
+ }
+ table->xMin = sfnt_get_short(sfont);
+ table->yMin = sfnt_get_short(sfont);
+ table->xMax = sfnt_get_short(sfont);
+ table->yMax = sfnt_get_short(sfont);
+ table->macStyle = (USHORT) sfnt_get_short(sfont);
+ table->lowestRecPPEM = (USHORT) sfnt_get_short(sfont);
+ table->fontDirectionHint = sfnt_get_short(sfont);
+ table->indexToLocFormat = sfnt_get_short(sfont);
+ table->glyphDataFormat = sfnt_get_short(sfont);
+ return table;
+}
+
+char *tt_pack_maxp_table(struct tt_maxp_table *table)
+{
+ char *p, *data;
+ p = data = NEW(TT_MAXP_TABLE_SIZE, char);
+ p += sfnt_put_ulong(p, (LONG) table->version);
+ p += sfnt_put_ushort(p, table->numGlyphs);
+ p += sfnt_put_ushort(p, table->maxPoints);
+ p += sfnt_put_ushort(p, table->maxContours);
+ p += sfnt_put_ushort(p, table->maxComponentPoints);
+ p += sfnt_put_ushort(p, table->maxComponentContours);
+ p += sfnt_put_ushort(p, table->maxZones);
+ p += sfnt_put_ushort(p, table->maxTwilightPoints);
+ p += sfnt_put_ushort(p, table->maxStorage);
+ p += sfnt_put_ushort(p, table->maxFunctionDefs);
+ p += sfnt_put_ushort(p, table->maxInstructionDefs);
+ p += sfnt_put_ushort(p, table->maxStackElements);
+ p += sfnt_put_ushort(p, table->maxSizeOfInstructions);
+ p += sfnt_put_ushort(p, table->maxComponentElements);
+ p += sfnt_put_ushort(p, table->maxComponentDepth);
+ return data;
+}
+
+struct tt_maxp_table *tt_read_maxp_table(sfnt * sfont)
+{
+ struct tt_maxp_table *table = NULL;
+ table = NEW(1, struct tt_maxp_table);
+ sfnt_locate_table(sfont, "maxp");
+ table->version = sfnt_get_ulong(sfont);
+ table->numGlyphs = sfnt_get_ushort(sfont);
+ table->maxPoints = sfnt_get_ushort(sfont);
+ table->maxContours = sfnt_get_ushort(sfont);
+ table->maxComponentPoints = sfnt_get_ushort(sfont);
+ table->maxComponentContours = sfnt_get_ushort(sfont);
+ table->maxZones = sfnt_get_ushort(sfont);
+ table->maxTwilightPoints = sfnt_get_ushort(sfont);
+ table->maxStorage = sfnt_get_ushort(sfont);
+ table->maxFunctionDefs = sfnt_get_ushort(sfont);
+ table->maxInstructionDefs = sfnt_get_ushort(sfont);
+ table->maxStackElements = sfnt_get_ushort(sfont);
+ table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
+ table->maxComponentElements = sfnt_get_ushort(sfont);
+ table->maxComponentDepth = sfnt_get_ushort(sfont);
+ return table;
+}
+
+char *tt_pack_hhea_table(struct tt_hhea_table *table)
+{
+ int i;
+ char *p, *data;
+ p = data = NEW(TT_HHEA_TABLE_SIZE, char);
+ p += sfnt_put_ulong(p, (LONG) table->version);
+ p += sfnt_put_short(p, table->Ascender);
+ p += sfnt_put_short(p, table->Descender);
+ p += sfnt_put_short(p, table->LineGap);
+ p += sfnt_put_ushort(p, table->advanceWidthMax);
+ p += sfnt_put_short(p, table->minLeftSideBearing);
+ p += sfnt_put_short(p, table->minRightSideBearing);
+ p += sfnt_put_short(p, table->xMaxExtent);
+ p += sfnt_put_short(p, table->caretSlopeRise);
+ p += sfnt_put_short(p, table->caretSlopeRun);
+ for (i = 0; i < 5; i++) {
+ p += sfnt_put_short(p, table->reserved[i]);
+ }
+ p += sfnt_put_short(p, table->metricDataFormat);
+ p += sfnt_put_ushort(p, table->numberOfHMetrics);
+ return data;
+}
+
+struct tt_hhea_table *tt_read_hhea_table(sfnt * sfont)
+{
+ int i;
+ struct tt_hhea_table *table = NULL;
+ table = NEW(1, struct tt_hhea_table);
+ sfnt_locate_table(sfont, "hhea");
+ table->version = sfnt_get_ulong(sfont);
+ table->Ascender = sfnt_get_short(sfont);
+ table->Descender = sfnt_get_short(sfont);
+ table->LineGap = sfnt_get_short(sfont);
+ table->advanceWidthMax = sfnt_get_ushort(sfont);
+ table->minLeftSideBearing = sfnt_get_short(sfont);
+ table->minRightSideBearing = sfnt_get_short(sfont);
+ table->xMaxExtent = sfnt_get_short(sfont);
+ table->caretSlopeRise = sfnt_get_short(sfont);
+ table->caretSlopeRun = sfnt_get_short(sfont);
+ for (i = 0; i < 5; i++) {
+ table->reserved[i] = sfnt_get_short(sfont);
+ }
+ table->metricDataFormat = sfnt_get_short(sfont);
+ if (table->metricDataFormat != 0)
+ normal_error("ttf","unknown metricDaraFormat");
+ table->numberOfHMetrics = sfnt_get_ushort(sfont);
+ return table;
+}
+
+char *tt_pack_vhea_table(struct tt_vhea_table *table)
+{
+ int i;
+ char *p, *data;
+ p = data = NEW(TT_VHEA_TABLE_SIZE, char);
+ p += sfnt_put_ulong(p, (LONG) table->version);
+ p += sfnt_put_short(p, table->vertTypoAscender);
+ p += sfnt_put_short(p, table->vertTypoDescender);
+ p += sfnt_put_short(p, table->vertTypoLineGap);
+ p += sfnt_put_short(p, table->advanceHeightMax);
+ p += sfnt_put_short(p, table->minTopSideBearing);
+ p += sfnt_put_short(p, table->minBottomSideBearing);
+ p += sfnt_put_short(p, table->yMaxExtent);
+ p += sfnt_put_short(p, table->caretSlopeRise);
+ p += sfnt_put_short(p, table->caretSlopeRun);
+ p += sfnt_put_short(p, table->caretOffset);
+ for (i = 0; i < 5; i++) {
+ p += sfnt_put_short(p, table->reserved[i]);
+ }
+ p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
+ return data;
+}
+
+struct tt_vhea_table *tt_read_vhea_table(sfnt * sfont)
+{
+ int i;
+ struct tt_vhea_table *table = NULL;
+ table = NEW(1, struct tt_vhea_table);
+ sfnt_locate_table(sfont, "vhea");
+ table->version = sfnt_get_ulong(sfont);
+ table->vertTypoAscender = sfnt_get_short(sfont);
+ table->vertTypoDescender = sfnt_get_short(sfont);
+ table->vertTypoLineGap = sfnt_get_short(sfont);
+ table->advanceHeightMax = sfnt_get_short(sfont);
+ table->minTopSideBearing = sfnt_get_short(sfont);
+ table->minBottomSideBearing = sfnt_get_short(sfont);
+ table->yMaxExtent = sfnt_get_short(sfont);
+ table->caretSlopeRise = sfnt_get_short(sfont);
+ table->caretSlopeRun = sfnt_get_short(sfont);
+ table->caretOffset = sfnt_get_short(sfont);
+ for (i = 0; i < 5; i++) {
+ (table->reserved)[i] = sfnt_get_short(sfont);
+ }
+ table->numOfLongVerMetrics = sfnt_get_ushort(sfont);
+ return table;
+}
+
+struct tt_VORG_table *tt_read_VORG_table(sfnt * sfont)
+{
+ struct tt_VORG_table *vorg;
+ ULONG offset;
+ USHORT i;
+ offset = sfnt_find_table_pos(sfont, "VORG");
+ if (offset > 0) {
+ vorg = NEW(1, struct tt_VORG_table);
+ sfnt_locate_table(sfont, "VORG");
+ if (sfnt_get_ushort(sfont) != 1 || sfnt_get_ushort(sfont) != 0)
+ normal_error("ttf","unsupported VORG version");
+ vorg->defaultVertOriginY = sfnt_get_short(sfont);
+ vorg->numVertOriginYMetrics = sfnt_get_ushort(sfont);
+ vorg->vertOriginYMetrics = NEW(vorg->numVertOriginYMetrics, struct tt_vertOriginYMetrics);
+ /*tex
+ The |vertOriginYMetrics| array must be sorted in increasing |glyphIndex| order.
+ */
+ for (i = 0; i < vorg->numVertOriginYMetrics; i++) {
+ vorg->vertOriginYMetrics[i].glyphIndex = sfnt_get_ushort(sfont);
+ vorg->vertOriginYMetrics[i].vertOriginY = sfnt_get_short(sfont);
+ }
+ } else {
+ vorg = NULL;
+ }
+ return vorg;
+}
+
+/*tex
+
+ Reading and writing |hmtx| and |vmtx| depends on other tables, like |maxp|,
+ |hhea| and |vhea|.
+
+*/
+
+struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs, USHORT numLongMetrics)
+{
+ struct tt_longMetrics *m;
+ USHORT gid, last_adv = 0;
+ m = NEW(numGlyphs, struct tt_longMetrics);
+ for (gid = 0; gid < numGlyphs; gid++) {
+ if (gid < numLongMetrics)
+ last_adv = sfnt_get_ushort(sfont);
+ m[gid].sideBearing = sfnt_get_short(sfont);
+ m[gid].advance = last_adv;
+ }
+ return m;
+}
+
+/*tex
+
+ The |OS/2| table may not exist.
+
+*/
+
+struct tt_os2__table *tt_read_os2__table(sfnt * sfont)
+{
+ struct tt_os2__table *table = NULL;
+ int i;
+ if (sfnt_find_table_pos(sfont, "OS/2") == 0)
+ return NULL;
+ sfnt_locate_table(sfont, "OS/2");
+ table = NEW(1, struct tt_os2__table);
+ table->version = sfnt_get_ushort(sfont);
+ table->xAvgCharWidth = sfnt_get_short(sfont);
+ table->usWeightClass = sfnt_get_ushort(sfont);
+ table->usWidthClass = sfnt_get_ushort(sfont);
+ table->fsType = sfnt_get_short(sfont);
+ table->ySubscriptXSize = sfnt_get_short(sfont);
+ table->ySubscriptYSize = sfnt_get_short(sfont);
+ table->ySubscriptXOffset = sfnt_get_short(sfont);
+ table->ySubscriptYOffset = sfnt_get_short(sfont);
+ table->ySuperscriptXSize = sfnt_get_short(sfont);
+ table->ySuperscriptYSize = sfnt_get_short(sfont);
+ table->ySuperscriptXOffset = sfnt_get_short(sfont);
+ table->ySuperscriptYOffset = sfnt_get_short(sfont);
+ table->yStrikeoutSize = sfnt_get_short(sfont);
+ table->yStrikeoutPosition = sfnt_get_short(sfont);
+ table->sFamilyClass = sfnt_get_short(sfont);
+ for (i = 0; i < 10; i++) {
+ table->panose[i] = sfnt_get_byte(sfont);
+ }
+ table->ulUnicodeRange1 = sfnt_get_ulong(sfont);
+ table->ulUnicodeRange2 = sfnt_get_ulong(sfont);
+ table->ulUnicodeRange3 = sfnt_get_ulong(sfont);
+ table->ulUnicodeRange4 = sfnt_get_ulong(sfont);
+ for (i = 0; i < 4; i++) {
+ table->achVendID[i] = sfnt_get_char(sfont);
+ }
+ table->fsSelection = sfnt_get_ushort(sfont);
+ table->usFirstCharIndex = sfnt_get_ushort(sfont);
+ table->usLastCharIndex = sfnt_get_ushort(sfont);
+ table->sTypoAscender = sfnt_get_short(sfont);
+ table->sTypoDescender = sfnt_get_short(sfont);
+ table->sTypoLineGap = sfnt_get_short(sfont);
+ table->usWinAscent = sfnt_get_ushort(sfont);
+ table->usWinDescent = sfnt_get_ushort(sfont);
+ table->ulCodePageRange1 = sfnt_get_ulong(sfont);
+ table->ulCodePageRange2 = sfnt_get_ulong(sfont);
+ if (table->version == 0x0002) {
+ table->sxHeight = sfnt_get_short(sfont);
+ table->sCapHeight = sfnt_get_short(sfont);
+ table->usDefaultChar = sfnt_get_ushort(sfont);
+ table->usBreakChar = sfnt_get_ushort(sfont);
+ table->usMaxContext = sfnt_get_ushort(sfont);
+ }
+ return table;
+}
+
+USHORT tt_get_name(sfnt * sfont, char *dest, USHORT destlen,
+ USHORT plat_id, USHORT enco_id, USHORT lang_id, USHORT name_id)
+{
+ USHORT length = 0;
+ USHORT num_names, string_offset;
+ ULONG name_offset;
+ int i;
+ name_offset = sfnt_locate_table(sfont, "name");
+ if (sfnt_get_ushort(sfont))
+ normal_error("ttf","expecting zero");
+ num_names = sfnt_get_ushort(sfont);
+ string_offset = sfnt_get_ushort(sfont);
+ for (i = 0; i < num_names; i++) {
+ USHORT p_id, e_id, n_id, l_id;
+ USHORT offset;
+ p_id = sfnt_get_ushort(sfont);
+ e_id = sfnt_get_ushort(sfont);
+ l_id = sfnt_get_ushort(sfont);
+ n_id = sfnt_get_ushort(sfont);
+ length = sfnt_get_ushort(sfont);
+ offset = sfnt_get_ushort(sfont);
+ /*tex The language |ID| value |0xffffu| stands for ``accept any language ID''. */
+ if ((p_id == plat_id) && (e_id == enco_id) &&
+ (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) {
+ if (length > destlen - 1) {
+ normal_warning("ttf","truncating a very long name");
+ length = (USHORT) (destlen - 1);
+ }
+ sfnt_seek_set(sfont, (long) (name_offset + string_offset + offset));
+ sfnt_read((unsigned char *) dest, length, sfont);
+ dest[length] = '\0';
+ break;
+ }
+ }
+ if (i == num_names) {
+ length = 0;
+ }
+ return length;
+}
+
+USHORT tt_get_ps_fontname(sfnt * sfont, char *dest, USHORT destlen)
+{
+ USHORT namelen = 0;
+ /*tex First try Mac-Roman PS name and then Win-Unicode PS name. */
+ if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 6)) != 0 ||
+ (namelen = tt_get_name(sfont, dest, destlen, 3, 1, 0x409u, 6)) != 0 ||
+ (namelen = tt_get_name(sfont, dest, destlen, 3, 5, 0x412u, 6)) != 0)
+ return namelen;
+ normal_warning("ttf","no valid PostScript name available");
+ /*tex
+ This is a workaround for some bad TTfonts: the language ID value |0xffffu|
+ indicates ``accept any language ID''.
+ */
+ if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0xffffu, 6)) == 0) {
+ /*tex
+ Finally we're falling back to Mac Roman name field. Some bad Japanese TTfonts
+ using SJIS encoded string in the Mac Roman name field.
+ */
+ namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 1);
+ }
+ return namelen;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,460 +0,0 @@
-% tt_table.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-#include <stdio.h>
-#include "font/sfnt.h"
-#include "font/tt_table.h"
-
-@ tables contains information refered by other tables
-
- |maxp->numGlyphs, etc --> loca, etc|
-
- |hhea->numberOfHMetrics --> hmtx|
-
- |head->indexToLocFormat --> loca|
-
- |head->glyphDataFormat --> glyf|
-
- at c
-char *tt_pack_head_table(struct tt_head_table *table)
-{
- int i;
- char *p, *data;
-
- if (table == NULL)
- normal_error("ttf","passed NULL pointer");
-
- p = data = NEW(TT_HEAD_TABLE_SIZE, char);
- p += sfnt_put_ulong(p, (LONG) table->version);
- p += sfnt_put_ulong(p, (LONG) table->fontRevision);
- p += sfnt_put_ulong(p, (LONG) table->checkSumAdjustment);
- p += sfnt_put_ulong(p, (LONG) table->magicNumber);
- p += sfnt_put_ushort(p, table->flags);
- p += sfnt_put_ushort(p, table->unitsPerEm);
- for (i = 0; i < 8; i++) {
- *(p++) = (char) (table->created)[i];
- }
- for (i = 0; i < 8; i++) {
- *(p++) = (char) (table->modified)[i];
- }
- p += sfnt_put_short(p, table->xMin);
- p += sfnt_put_short(p, table->yMin);
- p += sfnt_put_short(p, table->xMax);
- p += sfnt_put_short(p, table->yMax);
- p += sfnt_put_ushort(p, table->macStyle);
- p += sfnt_put_ushort(p, table->lowestRecPPEM);
- p += sfnt_put_short(p, table->fontDirectionHint);
- p += sfnt_put_short(p, table->indexToLocFormat);
- p += sfnt_put_short(p, table->glyphDataFormat);
-
- return data;
-}
-
-struct tt_head_table *tt_read_head_table(sfnt * sfont)
-{
- int i;
- struct tt_head_table *table = NULL;
-
- table = NEW(1, struct tt_head_table);
-
- sfnt_locate_table(sfont, "head");
-
- table->version = sfnt_get_ulong(sfont);
- table->fontRevision = sfnt_get_ulong(sfont);
- table->checkSumAdjustment = sfnt_get_ulong(sfont);
- table->magicNumber = sfnt_get_ulong(sfont);
- table->flags = sfnt_get_ushort(sfont);
- table->unitsPerEm = sfnt_get_ushort(sfont);
- for (i = 0; i < 8; i++) {
- (table->created)[i] = sfnt_get_byte(sfont);
- }
- for (i = 0; i < 8; i++) {
- (table->modified)[i] = sfnt_get_byte(sfont);
- }
- table->xMin = sfnt_get_short(sfont);
- table->yMin = sfnt_get_short(sfont);
- table->xMax = sfnt_get_short(sfont);
- table->yMax = sfnt_get_short(sfont);
- table->macStyle = (USHORT) sfnt_get_short(sfont);
- table->lowestRecPPEM = (USHORT) sfnt_get_short(sfont);
- table->fontDirectionHint = sfnt_get_short(sfont);
- table->indexToLocFormat = sfnt_get_short(sfont);
- table->glyphDataFormat = sfnt_get_short(sfont);
-
- return table;
-}
-
-char *tt_pack_maxp_table(struct tt_maxp_table *table)
-{
- char *p, *data;
-
- p = data = NEW(TT_MAXP_TABLE_SIZE, char);
- p += sfnt_put_ulong(p, (LONG) table->version);
- p += sfnt_put_ushort(p, table->numGlyphs);
- p += sfnt_put_ushort(p, table->maxPoints);
- p += sfnt_put_ushort(p, table->maxContours);
- p += sfnt_put_ushort(p, table->maxComponentPoints);
- p += sfnt_put_ushort(p, table->maxComponentContours);
- p += sfnt_put_ushort(p, table->maxZones);
- p += sfnt_put_ushort(p, table->maxTwilightPoints);
- p += sfnt_put_ushort(p, table->maxStorage);
- p += sfnt_put_ushort(p, table->maxFunctionDefs);
- p += sfnt_put_ushort(p, table->maxInstructionDefs);
- p += sfnt_put_ushort(p, table->maxStackElements);
- p += sfnt_put_ushort(p, table->maxSizeOfInstructions);
- p += sfnt_put_ushort(p, table->maxComponentElements);
- p += sfnt_put_ushort(p, table->maxComponentDepth);
-
- return data;
-}
-
-struct tt_maxp_table *tt_read_maxp_table(sfnt * sfont)
-{
- struct tt_maxp_table *table = NULL;
-
- table = NEW(1, struct tt_maxp_table);
-
- sfnt_locate_table(sfont, "maxp");
- table->version = sfnt_get_ulong(sfont);
- table->numGlyphs = sfnt_get_ushort(sfont);
- table->maxPoints = sfnt_get_ushort(sfont);
- table->maxContours = sfnt_get_ushort(sfont);
- table->maxComponentPoints = sfnt_get_ushort(sfont);
- table->maxComponentContours = sfnt_get_ushort(sfont);
- table->maxZones = sfnt_get_ushort(sfont);
- table->maxTwilightPoints = sfnt_get_ushort(sfont);
- table->maxStorage = sfnt_get_ushort(sfont);
- table->maxFunctionDefs = sfnt_get_ushort(sfont);
- table->maxInstructionDefs = sfnt_get_ushort(sfont);
- table->maxStackElements = sfnt_get_ushort(sfont);
- table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
- table->maxComponentElements = sfnt_get_ushort(sfont);
- table->maxComponentDepth = sfnt_get_ushort(sfont);
-
- return table;
-}
-
-char *tt_pack_hhea_table(struct tt_hhea_table *table)
-{
- int i;
- char *p, *data;
-
- p = data = NEW(TT_HHEA_TABLE_SIZE, char);
- p += sfnt_put_ulong(p, (LONG) table->version);
- p += sfnt_put_short(p, table->Ascender);
- p += sfnt_put_short(p, table->Descender);
- p += sfnt_put_short(p, table->LineGap);
- p += sfnt_put_ushort(p, table->advanceWidthMax);
- p += sfnt_put_short(p, table->minLeftSideBearing);
- p += sfnt_put_short(p, table->minRightSideBearing);
- p += sfnt_put_short(p, table->xMaxExtent);
- p += sfnt_put_short(p, table->caretSlopeRise);
- p += sfnt_put_short(p, table->caretSlopeRun);
- for (i = 0; i < 5; i++) {
- p += sfnt_put_short(p, table->reserved[i]);
- }
- p += sfnt_put_short(p, table->metricDataFormat);
- p += sfnt_put_ushort(p, table->numberOfHMetrics);
-
- return data;
-}
-
-struct tt_hhea_table *tt_read_hhea_table(sfnt * sfont)
-{
- int i;
- struct tt_hhea_table *table = NULL;
-
- table = NEW(1, struct tt_hhea_table);
-
- sfnt_locate_table(sfont, "hhea");
- table->version = sfnt_get_ulong(sfont);
- table->Ascender = sfnt_get_short(sfont);
- table->Descender = sfnt_get_short(sfont);
- table->LineGap = sfnt_get_short(sfont);
- table->advanceWidthMax = sfnt_get_ushort(sfont);
- table->minLeftSideBearing = sfnt_get_short(sfont);
- table->minRightSideBearing = sfnt_get_short(sfont);
- table->xMaxExtent = sfnt_get_short(sfont);
- table->caretSlopeRise = sfnt_get_short(sfont);
- table->caretSlopeRun = sfnt_get_short(sfont);
- for (i = 0; i < 5; i++) {
- table->reserved[i] = sfnt_get_short(sfont);
- }
- table->metricDataFormat = sfnt_get_short(sfont);
- if (table->metricDataFormat != 0)
- normal_error("ttf","unknown metricDaraFormat");
- table->numberOfHMetrics = sfnt_get_ushort(sfont);
-
- return table;
-}
-
-@ vhea
- at c
-char *tt_pack_vhea_table(struct tt_vhea_table *table)
-{
- int i;
- char *p, *data;
-
- p = data = NEW(TT_VHEA_TABLE_SIZE, char);
- p += sfnt_put_ulong(p, (LONG) table->version);
- p += sfnt_put_short(p, table->vertTypoAscender);
- p += sfnt_put_short(p, table->vertTypoDescender);
- p += sfnt_put_short(p, table->vertTypoLineGap);
- p += sfnt_put_short(p, table->advanceHeightMax); /* ushort ? */
- p += sfnt_put_short(p, table->minTopSideBearing);
- p += sfnt_put_short(p, table->minBottomSideBearing);
- p += sfnt_put_short(p, table->yMaxExtent);
- p += sfnt_put_short(p, table->caretSlopeRise);
- p += sfnt_put_short(p, table->caretSlopeRun);
- p += sfnt_put_short(p, table->caretOffset);
- for (i = 0; i < 5; i++) {
- p += sfnt_put_short(p, table->reserved[i]);
- }
- p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
-
- return data;
-}
-
-struct tt_vhea_table *tt_read_vhea_table(sfnt * sfont)
-{
- int i;
- struct tt_vhea_table *table = NULL;
-
- table = NEW(1, struct tt_vhea_table);
-
- sfnt_locate_table(sfont, "vhea");
- table->version = sfnt_get_ulong(sfont);
- table->vertTypoAscender = sfnt_get_short(sfont);
- table->vertTypoDescender = sfnt_get_short(sfont);
- table->vertTypoLineGap = sfnt_get_short(sfont);
- table->advanceHeightMax = sfnt_get_short(sfont); /* ushort ? */
- table->minTopSideBearing = sfnt_get_short(sfont);
- table->minBottomSideBearing = sfnt_get_short(sfont);
- table->yMaxExtent = sfnt_get_short(sfont);
- table->caretSlopeRise = sfnt_get_short(sfont);
- table->caretSlopeRun = sfnt_get_short(sfont);
- table->caretOffset = sfnt_get_short(sfont);
- for (i = 0; i < 5; i++) {
- (table->reserved)[i] = sfnt_get_short(sfont);
- }
- table->numOfLongVerMetrics = sfnt_get_ushort(sfont);
-
- return table;
-}
-
-
-struct tt_VORG_table *tt_read_VORG_table(sfnt * sfont)
-{
- struct tt_VORG_table *vorg;
- ULONG offset;
- USHORT i;
-
- offset = sfnt_find_table_pos(sfont, "VORG");
-
- if (offset > 0) {
- vorg = NEW(1, struct tt_VORG_table);
-
- sfnt_locate_table(sfont, "VORG");
- if (sfnt_get_ushort(sfont) != 1 || sfnt_get_ushort(sfont) != 0)
- normal_error("ttf","unsupported VORG version");
-
- vorg->defaultVertOriginY = sfnt_get_short(sfont);
- vorg->numVertOriginYMetrics = sfnt_get_ushort(sfont);
- vorg->vertOriginYMetrics = NEW(vorg->numVertOriginYMetrics,
- struct tt_vertOriginYMetrics);
- /*
- * The vertOriginYMetrics array must be sorted in increasing
- * glyphIndex order.
- */
- for (i = 0; i < vorg->numVertOriginYMetrics; i++) {
- vorg->vertOriginYMetrics[i].glyphIndex = sfnt_get_ushort(sfont);
- vorg->vertOriginYMetrics[i].vertOriginY = sfnt_get_short(sfont);
- }
- } else {
- vorg = NULL;
- }
-
- return vorg;
-}
-
-
-@ hmtx and vmtx
-
-Reading/writing hmtx and vmtx depend on other tables, maxp and hhea/vhea.
-
- at c
-struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs,
- USHORT numLongMetrics)
-{
- struct tt_longMetrics *m;
- USHORT gid, last_adv = 0;
-
- m = NEW(numGlyphs, struct tt_longMetrics);
- for (gid = 0; gid < numGlyphs; gid++) {
- if (gid < numLongMetrics)
- last_adv = sfnt_get_ushort(sfont);
- m[gid].sideBearing = sfnt_get_short(sfont);
- m[gid].advance = last_adv;
- }
-
- return m;
-}
-
-@ OS/2 table
-
-this table may not exist
- at c
-struct tt_os2__table *tt_read_os2__table(sfnt * sfont)
-{
- struct tt_os2__table *table = NULL;
- int i;
-
- if (sfnt_find_table_pos(sfont, "OS/2") == 0)
- return NULL;
-
- sfnt_locate_table(sfont, "OS/2");
-
- table = NEW(1, struct tt_os2__table);
-
- table->version = sfnt_get_ushort(sfont);
- table->xAvgCharWidth = sfnt_get_short(sfont);
- table->usWeightClass = sfnt_get_ushort(sfont);
- table->usWidthClass = sfnt_get_ushort(sfont);
- table->fsType = sfnt_get_short(sfont);
- table->ySubscriptXSize = sfnt_get_short(sfont);
- table->ySubscriptYSize = sfnt_get_short(sfont);
- table->ySubscriptXOffset = sfnt_get_short(sfont);
- table->ySubscriptYOffset = sfnt_get_short(sfont);
- table->ySuperscriptXSize = sfnt_get_short(sfont);
- table->ySuperscriptYSize = sfnt_get_short(sfont);
- table->ySuperscriptXOffset = sfnt_get_short(sfont);
- table->ySuperscriptYOffset = sfnt_get_short(sfont);
- table->yStrikeoutSize = sfnt_get_short(sfont);
- table->yStrikeoutPosition = sfnt_get_short(sfont);
- table->sFamilyClass = sfnt_get_short(sfont);
- for (i = 0; i < 10; i++) {
- table->panose[i] = sfnt_get_byte(sfont);
- }
- table->ulUnicodeRange1 = sfnt_get_ulong(sfont);
- table->ulUnicodeRange2 = sfnt_get_ulong(sfont);
- table->ulUnicodeRange3 = sfnt_get_ulong(sfont);
- table->ulUnicodeRange4 = sfnt_get_ulong(sfont);
- for (i = 0; i < 4; i++) {
- table->achVendID[i] = sfnt_get_char(sfont);
- }
- table->fsSelection = sfnt_get_ushort(sfont);
- table->usFirstCharIndex = sfnt_get_ushort(sfont);
- table->usLastCharIndex = sfnt_get_ushort(sfont);
- table->sTypoAscender = sfnt_get_short(sfont);
- table->sTypoDescender = sfnt_get_short(sfont);
- table->sTypoLineGap = sfnt_get_short(sfont);
- table->usWinAscent = sfnt_get_ushort(sfont);
- table->usWinDescent = sfnt_get_ushort(sfont);
- table->ulCodePageRange1 = sfnt_get_ulong(sfont);
- table->ulCodePageRange2 = sfnt_get_ulong(sfont);
- if (table->version == 0x0002) {
- table->sxHeight = sfnt_get_short(sfont);
- table->sCapHeight = sfnt_get_short(sfont);
- table->usDefaultChar = sfnt_get_ushort(sfont);
- table->usBreakChar = sfnt_get_ushort(sfont);
- table->usMaxContext = sfnt_get_ushort(sfont);
- }
-
- return table;
-}
-
-USHORT
-tt_get_name(sfnt * sfont, char *dest, USHORT destlen,
- USHORT plat_id, USHORT enco_id, USHORT lang_id, USHORT name_id)
-{
- USHORT length = 0;
- USHORT num_names, string_offset;
- ULONG name_offset;
- int i;
-
- name_offset = sfnt_locate_table(sfont, "name");
-
- if (sfnt_get_ushort(sfont))
- normal_error("ttf","expecting zero");
-
- num_names = sfnt_get_ushort(sfont);
- string_offset = sfnt_get_ushort(sfont);
- for (i = 0; i < num_names; i++) {
- USHORT p_id, e_id, n_id, l_id;
- USHORT offset;
-
- p_id = sfnt_get_ushort(sfont);
- e_id = sfnt_get_ushort(sfont);
- l_id = sfnt_get_ushort(sfont);
- n_id = sfnt_get_ushort(sfont);
- length = sfnt_get_ushort(sfont);
- offset = sfnt_get_ushort(sfont);
- /* language ID value 0xffffu for `accept any language ID' */
- if ((p_id == plat_id) && (e_id == enco_id) &&
- (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) {
- if (length > destlen - 1) {
- normal_warning("ttf","truncating a very long name");
- length = (USHORT) (destlen - 1);
- }
- sfnt_seek_set(sfont, (long) (name_offset + string_offset + offset));
- sfnt_read((unsigned char *) dest, length, sfont);
- dest[length] = '\0';
- break;
- }
- }
- if (i == num_names) {
- length = 0;
- }
-
- return length;
-}
-
-USHORT tt_get_ps_fontname(sfnt * sfont, char *dest, USHORT destlen)
-{
- USHORT namelen = 0;
-
- /* First try Mac-Roman PS name and then Win-Unicode PS name */
- if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 6)) != 0 ||
- (namelen = tt_get_name(sfont, dest, destlen, 3, 1, 0x409u, 6)) != 0 ||
- (namelen = tt_get_name(sfont, dest, destlen, 3, 5, 0x412u, 6)) != 0)
- return namelen;
-
- normal_warning("ttf","no valid PostScript name available");
- /*
- Wrokaround for some bad TTfonts:
- Language ID value 0xffffu for `accept any language ID'
- */
- if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0xffffu, 6)) == 0) {
- /*
- Finally falling back to Mac Roman name field.
- Warning: Some bad Japanese TTfonts using SJIS encoded string in the
- Mac Roman name field.
- */
- namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 1);
- }
-
- return namelen;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1444 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#define font_max 5000
+
+/* The instruction set: */
+
+#define set_char_0 0 /* typeset character 0 and move right */
+#define set1 128 /* typeset a character and move right */
+#define set2 129 /* typeset a character and move right */
+#define set3 130 /* typeset a character and move right */
+#define set4 131 /* typeset a character and move right */
+#define set_rule 132 /* typeset a rule and move right */
+#define put1 133 /* typeset a character without moving */
+#define put2 134 /* typeset a character without moving */
+#define put3 135 /* typeset a character without moving */
+#define put4 136 /* typeset a character without moving */
+#define put_rule 137 /* typeset a rule */
+#define nop 138 /* no operation */
+#define bop 139 /* beginning of page */
+#define eop 140 /* ending of page */
+#define push 141 /* save the current positions */
+#define pop 142 /* restore previous positions */
+#define right1 143 /* move right */
+#define right2 144 /* move right */
+#define right3 145 /* move right */
+#define right4 146 /* move right, 4 bytes */
+#define w0 147 /* move right by |w| */
+#define w1 148 /* move right and set |w| */
+#define w2 149 /* move right and set |w| */
+#define w3 150 /* move right and set |w| */
+#define w4 151 /* move right and set |w| */
+#define x0 152 /* move right by |x| */
+#define x1 153 /* move right and set |x| */
+#define x2 154 /* move right and set |x| */
+#define x3 155 /* move right and set |x| */
+#define x4 156 /* move right and set |x| */
+#define down1 157 /* move down */
+#define down2 158 /* move down */
+#define down3 159 /* move down */
+#define down4 160 /* move down, 4 bytes */
+#define y0 161 /* move down by |y| */
+#define y1 162 /* move down and set |y| */
+#define y2 163 /* move down and set |y| */
+#define y3 164 /* move down and set |y| */
+#define y4 165 /* move down and set |y| */
+#define z0 166 /* move down by |z| */
+#define z1 167 /* move down and set |z| */
+#define z2 168 /* move down and set |z| */
+#define z3 169 /* move down and set |z| */
+#define z4 170 /* move down and set |z| */
+#define fnt_num_0 171 /* set current font to 0 */
+#define fnt1 235 /* set current font */
+#define fnt2 236 /* set current font */
+#define fnt3 237 /* set current font */
+#define fnt4 238 /* set current font */
+#define xxx1 239 /* extension to DVI primitives */
+#define xxx2 240 /* extension to DVI primitives */
+#define xxx3 241 /* extension to DVI primitives */
+#define xxx4 242 /* potentially long extension to DVI primitives */
+#define fnt_def1 243 /* define the meaning of a font number */
+#define pre 247 /* preamble */
+#define post 248 /* postamble beginning */
+#define post_post 249 /* postamble ending */
+#define yyy1 250 /* PDF literal text */
+#define yyy2 251 /* PDF literal text */
+#define yyy3 252 /* PDF literal text */
+#define yyy4 253 /* PDF literal text */
+
+#define null_font 0
+
+#define long_char 242 /* |VF| command for general character packet */
+
+#define vf_id 202 /* identifies \VF\ files */
+
+/*tex
+
+ Quit |VF| processing with an error message.
+
+*/
+
+#define bad_vf(a) { \
+ xfree(vf_buffer); \
+ print_nlp(); \
+ formatted_warning("virtual font","file '%s', %s, font will be ignored",font_name(f),a); \
+ print_ln(); \
+ return; \
+}
+
+#define lua_bad_vf(a) { \
+ xfree(vf_buffer); \
+ lua_settop(L,s_top); \
+ lua_pushnil(L); \
+ lua_pushstring(L,a); \
+ return 2; \
+}
+
+#define tmp_b0 tmp_w.qqqq.b0
+#define tmp_b1 tmp_w.qqqq.b1
+#define tmp_b2 tmp_w.qqqq.b2
+#define tmp_b3 tmp_w.qqqq.b3
+#define tmp_int tmp_w.cint
+
+/*tex \DVI\ files shouldn't |push| beyond this depth: */
+
+#define vf_stack_size 100
+
+/*tex An index into the stack: */
+
+typedef unsigned char vf_stack_index;
+
+typedef struct vf_stack_record {
+ scaled stack_w, stack_x, stack_y, stack_z;
+} vf_stack_record;
+
+/*tex Get a byte from the \VF\ file: */
+
+#define vf_byte(a) \
+{ \
+ eight_bits vf_tmp_b; \
+ if (vf_cur >= vf_size) { \
+ normal_error("virtual font","unexpected eof"); \
+ } \
+ vf_tmp_b = vf_buffer[vf_cur++]; \
+ a = vf_tmp_b; \
+}
+
+#define vf_replace_z() \
+{ \
+ vf_alpha = 16; \
+ while (vf_z >= 040000000) { \
+ vf_z = vf_z / 2; \
+ vf_alpha += vf_alpha; \
+ } \
+ /*tex |vf_beta = (char)(256 / vf_alpha)| */ \
+ vf_alpha = (vf_alpha * vf_z); \
+}
+
+/*tex
+
+ Read |k| bytes as an integer from \VF\ file. Beware: the |vf_read| macro
+ differs from |vf_read| in |vftovp.web| for 1 upto 3 byte words.
+
+*/
+
+#define vf_read(k, l) \
+{ \
+ int itmp = 0, dtmp = (int)(k), jtmp = 0; \
+ while (dtmp > 0) { \
+ vf_byte(jtmp); \
+ if ((dtmp == (int) k) && jtmp > 127) \
+ jtmp = jtmp - 256; \
+ itmp = itmp * 256 + jtmp; \
+ decr(dtmp); \
+ } \
+ l = itmp; \
+}
+
+#define vf_read_u(k, l) \
+{ \
+ int dtmp = (int)(k); \
+ unsigned int itmp = 0, jtmp = 0; \
+ while (dtmp-- > 0) { \
+ vf_byte(jtmp); \
+ itmp = itmp * 256 + jtmp; \
+ } \
+ l = itmp; \
+}
+
+void pdf_check_vf(internal_font_number f)
+{
+ if (font_type(f) == virtual_font_type)
+ normal_error("font", "command cannot be used with virtual font");
+}
+
+static void vf_local_font_warning(internal_font_number f, internal_font_number k, const char *s, int a, int b)
+{
+ print_nlp();
+ tprint(s);
+ tprint(" in local font ");
+ tprint(font_name(k));
+ tprint(" (");
+ print_int(b);
+ tprint(" != ");
+ print_int(a);
+ tprint(") in virtual font ");
+ tprint(font_name(f));
+ tprint(".vf ignored.");
+}
+
+/*tex Process a local font in the \VF\ file. */
+
+int level = 0;
+
+static internal_font_number vf_def_font(internal_font_number f, unsigned char *vf_buffer, int *vf_cr)
+{
+ internal_font_number k;
+ str_number s;
+ char *st;
+ scaled ds, fs;
+ four_quarters cs;
+ /*tex The accumulator: */
+ memory_word tmp_w;
+ int junk;
+ unsigned int checksum;
+ cs.b0 = vf_buffer[(*vf_cr)];
+ cs.b1 = vf_buffer[(*vf_cr) + 1];
+ cs.b2 = vf_buffer[(*vf_cr) + 2];
+ cs.b3 = vf_buffer[(*vf_cr) + 3];
+ (*vf_cr) += 4;
+ checksum = (unsigned) (cs.b0 * 256 * 256 * 256 + cs.b1 * 256 * 256 + cs.b2 * 256 + cs.b3);
+ k = vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ if (k > 127)
+ k -= 256;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ fs = store_scaled_f(k, font_size(f));
+ k = vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ if (k > 127)
+ k -= 256;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ k = k * 256 + vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ ds = k / 16;
+ tmp_b0 = vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ tmp_b1 = vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ while (tmp_b0 > 0) {
+ /*tex Skip the font path. */
+ tmp_b0--;
+ (*vf_cr)++;
+ }
+ str_room((unsigned) tmp_b1);
+ while (tmp_b1 > 0) {
+ tmp_b1--;
+ junk = vf_buffer[(*vf_cr)];
+ (*vf_cr)++;
+ append_char(junk);
+ }
+ if (level > 5) {
+ normal_warning("vf","quitting at recurse depth > 5");
+ k = f ;
+ } else if ((level > 1) && (fs > 65536*1024)) {
+ normal_warning("vf","quitting when recursing at size > 65536*1024");
+ k = f ;
+ } else {
+ level += 1 ;
+ s = make_string();
+ st = makecstring(s);
+ k = tfm_lookup(st, fs);
+ if (k == null_font)
+ k = read_font_info(null_cs, st, fs, -1);
+ free(st);
+ level -= 1 ;
+ if (k != null_font) {
+ if (checksum != 0 && font_checksum(k) != 0
+ && checksum != font_checksum(k))
+ vf_local_font_warning(f, k, "checksum mismatch", (int) checksum, (int) font_checksum(k));
+ if (ds != font_dsize(k))
+ vf_local_font_warning(f, k, "design size mismatch", ds, font_dsize(k));
+ }
+ }
+ return k;
+}
+
+static int open_vf_file(const char *fn, unsigned char **vbuffer, int *vsize)
+{
+ /*tex Was the callback successful? */
+ boolean res;
+ int callback_id;
+ /*tex Was |vf_file| successfully read? */
+ boolean file_read = false;
+ FILE *vf_file;
+ const char *fname = luatex_find_file(fn, find_vf_file_callback);
+ if (fname == NULL || strlen(fname) == 0) {
+ return 0;
+ }
+
+ callback_id = callback_defined(read_vf_file_callback);
+ if (callback_id > 0) {
+ res = run_callback(callback_id, "S->bSd", fname,
+ &file_read, vbuffer, vsize);
+ if (res && file_read && (*vsize > 0)) {
+ return 1;
+ }
+ if (!file_read)
+ return 0;
+ } else {
+ if (luatex_open_input
+ (&(vf_file), fname, kpse_ovf_format, FOPEN_RBIN_MODE, false)
+ || luatex_open_input(&(vf_file), fname, kpse_vf_format, FOPEN_RBIN_MODE, false)) {
+ res = read_vf_file(vf_file, vbuffer, vsize);
+ close_file(vf_file);
+ if (res) {
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ The |do_vf| procedure attempts to read the \VF\ file for a font, and sets
+ |font_type()| to |real_font_type| if the \VF\ file could not be found or
+ loaded, otherwise sets |font_type()| to |virtual_font_type|. At this time,
+ |tmp_f| is the internal font number of the current \TFM\ font. To process
+ font definitions in virtual font we call |vf_def_font|.
+
+*/
+
+#define append_packet(k) vpackets[vf_np++] = (eight_bits)(k)
+
+/*tex
+
+ Life is easier if all internal font commands are |fnt4| and all character
+ commands are |set4| or |put4|.
+
+*/
+
+#define append_fnt_set(k) \
+{ \
+ assert(k > 0); \
+ append_packet(packet_font_code); \
+ append_four(k); \
+}
+
+#define append_four(k) \
+{ \
+ append_packet((k & 0xFF000000) >> 24); \
+ append_packet((k & 0x00FF0000) >> 16); \
+ append_packet((k & 0x0000FF00) >> 8); \
+ append_packet((k & 0x000000FF)); \
+}
+
+/*tex Some of these things happen twice, adding a define is simplest. */
+
+#define test_checksum() { vf_byte(tmp_b0); vf_byte(tmp_b1); \
+ vf_byte(tmp_b2); vf_byte(tmp_b3); \
+ if (((tmp_b0 != 0) || (tmp_b1 != 0) || (tmp_b2 != 0) || (tmp_b3 != 0)) && \
+ ((font_check_0(f) != 0) || (font_check_1(f) != 0) || \
+ (font_check_2(f) != 0) || (font_check_3(f) != 0)) && \
+ ((tmp_b0 != font_check_0(f)) || (tmp_b1 != font_check_1(f)) || \
+ (tmp_b2 != font_check_2(f)) || (tmp_b3 != font_check_3(f)))) { \
+ print_nlp(); \
+ tprint("checksum mismatch in font "); \
+ tprint(font_name(f)); \
+ tprint(".vf ignored "); } }
+
+#define test_dsize() \
+{ \
+ int read_tmp; \
+ vf_read(4, read_tmp); \
+ if ((read_tmp / 16) != font_dsize(f)) { \
+ print_nlp(); \
+ tprint("design size mismatch in font "); \
+ tprint(font_name(f)); \
+ tprint(".vf ignored"); \
+ } \
+}
+
+static int count_packet_bytes(eight_bits * vf_buf, int cur_bute, int count)
+{
+ unsigned k = 0;
+ int ff = 0;
+ int acc = 0;
+ unsigned int cmd = 0;
+ unsigned int d = 0;
+ while (k < (unsigned) count) {
+ cmd = vf_buf[cur_bute + (int) k];
+ k++;
+ if (cmd < set1) {
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ acc += 5;
+ } else if ((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) {
+ ff = 1;
+ acc += 5;
+ } else {
+ switch (cmd) {
+ case fnt1:
+ acc += 5;
+ k += 1;
+ ff = 1;
+ break;
+ case fnt2:
+ acc += 5;
+ k += 2;
+ ff = 1;
+ break;
+ case fnt3:
+ acc += 5;
+ k += 3;
+ ff = 1;
+ break;
+ case fnt4:
+ acc += 5;
+ k += 4;
+ ff = 1;
+ break;
+ case set_rule:
+ acc += 9;
+ k += 8;
+ break;
+ case put_rule:
+ acc += 11;
+ k += 8;
+ break;
+ case set1:
+ acc += 5;
+ k += 1;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case set2:
+ acc += 5;
+ k += 2;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case set3:
+ acc += 5;
+ k += 3;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case set4:
+ acc += 5;
+ k += 4;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case put1:
+ acc += 7;
+ k += 1;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case put2:
+ acc += 7;
+ k += 2;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case put3:
+ acc += 7;
+ k += 3;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case put4:
+ acc += 7;
+ k += 4;
+ if (ff == 0) {
+ ff = 1;
+ acc += 5;
+ }
+ break;
+ case right1:
+ acc += 5;
+ k += 1;
+ break;
+ case right2:
+ acc += 5;
+ k += 2;
+ break;
+ case right3:
+ acc += 5;
+ k += 3;
+ break;
+ case right4:
+ acc += 5;
+ k += 4;
+ break;
+ case w1:
+ acc += 5;
+ k += 1;
+ break;
+ case w2:
+ acc += 5;
+ k += 2;
+ break;
+ case w3:
+ acc += 5;
+ k += 3;
+ break;
+ case w4:
+ acc += 5;
+ k += 4;
+ break;
+ case x1:
+ acc += 5;
+ k += 1;
+ break;
+ case x2:
+ acc += 5;
+ k += 2;
+ break;
+ case x3:
+ acc += 5;
+ k += 3;
+ break;
+ case x4:
+ acc += 5;
+ k += 4;
+ break;
+ case down1:
+ acc += 5;
+ k += 1;
+ break;
+ case down2:
+ acc += 5;
+ k += 2;
+ break;
+ case down3:
+ acc += 5;
+ k += 3;
+ break;
+ case down4:
+ acc += 5;
+ k += 4;
+ break;
+ case y1:
+ acc += 5;
+ k += 1;
+ break;
+ case y2:
+ acc += 5;
+ k += 2;
+ break;
+ case y3:
+ acc += 5;
+ k += 3;
+ break;
+ case y4:
+ acc += 5;
+ k += 4;
+ break;
+ case z1:
+ acc += 5;
+ k += 1;
+ break;
+ case z2:
+ acc += 5;
+ k += 2;
+ break;
+ case z3:
+ acc += 5;
+ k += 3;
+ break;
+ case z4:
+ acc += 5;
+ k += 4;
+ break;
+ case xxx1:
+ d = vf_buf[cur_bute + (int) k];
+ k++;
+ k += d;
+ acc += 5 + (int) d;
+ break;
+ case xxx2:
+ d = vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ k += d;
+ acc += 5 + (int) d;
+ break;
+ case xxx3:
+ d = vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ k += d;
+ acc += 5 + (int) d;
+ break;
+ case xxx4:
+ d = vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ d = d * 256 + vf_buf[cur_bute + (int) k];
+ k++;
+ k += d;
+ acc += 5 + (int) d;
+ break;
+ case w0:
+ acc += 5;
+ break;
+ case x0:
+ acc += 5;
+ break;
+ case y0:
+ acc += 5;
+ break;
+ case z0:
+ acc += 5;
+ break;
+ case nop:
+ break;
+ case push:
+ acc += 1;
+ break;
+ case pop:
+ acc += 1;
+ break;
+ }
+ }
+ }
+ return (acc + 1);
+}
+
+void do_vf(internal_font_number f)
+{
+ int k, i;
+ unsigned cmd, n;
+ scaled x, y, w, z, h, v;
+ int cc, cmd_length;
+ unsigned packet_length;
+ charinfo *co;
+ scaled tfm_width;
+ int save_cur_byte;
+ vf_stack_index stack_level;
+ /*tex multiplier */
+ int vf_z;
+ /*tex correction for negative values */
+ int vf_alpha;
+ int vf_np;
+ eight_bits *vpackets;
+ /*tex accumulator */
+ memory_word tmp_w;
+ vf_stack_record vf_stack[256];
+ int junk;
+ unsigned utmp;
+ unsigned char *vf_buffer;
+ int vf_size;
+ int vf_cur;
+ /*tex external font ids */
+ unsigned *vf_local_fnts = NULL;
+ /*tex internal font ids */
+ unsigned *vf_real_fnts = NULL;
+ /*tex local font counter */
+ unsigned vf_nf = 0;
+ if (font_type(f) != unknown_font_type)
+ return;
+ set_font_type(f, real_font_type);
+ stack_level = 0;
+ /*tex Open |vf_file|, return if not found */
+ vf_cur = 0;
+ vf_buffer = NULL;
+ vf_size = 0;
+ if (!open_vf_file(font_name(f), &vf_buffer, &vf_size))
+ return;
+ /*tex Process the preamble */
+ set_font_type(f, virtual_font_type);
+ vf_byte(k);
+ if (k != pre)
+ bad_vf("PRE command expected");
+ vf_byte(k);
+ if (k != vf_id)
+ bad_vf("wrong id byte");
+ vf_byte(cmd_length);
+ for (k = 1; k <= cmd_length; k++)
+ vf_byte(junk);
+ test_checksum();
+ test_dsize();
+ vf_z = font_size(f);
+ vf_replace_z();
+ /*tex Process the font definitions; scan forward to find the number of internal fonts. */
+ vf_nf = 0;
+ save_cur_byte = vf_cur;
+ vf_byte(cmd);
+ while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
+ vf_read_u((cmd - fnt_def1 + 1), utmp);
+ vf_read(4, junk);
+ vf_read(4, junk);
+ vf_read(4, junk);
+ vf_byte(k);
+ vf_byte(junk);
+ k += junk;
+ while (k-- > 0) {
+ vf_byte(junk);
+ }
+ incr(vf_nf);
+ vf_byte(cmd);
+ }
+ vf_cur = save_cur_byte;
+ vf_byte(cmd);
+ /*tex Do a |malloc| and fill the local font arrays. */
+ if (vf_nf > 0) {
+ unsigned ii = (unsigned) ((unsigned) vf_nf * sizeof(int));
+ vf_local_fnts = xmalloc(ii);
+ memset(vf_local_fnts, 0, ii);
+ vf_real_fnts = xmalloc(ii);
+ memset(vf_real_fnts, 0, ii);
+ vf_nf = 0;
+ while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
+ vf_read_u((cmd - fnt_def1 + 1), vf_local_fnts[vf_nf]);
+ vf_real_fnts[vf_nf] = (unsigned) vf_def_font(f, vf_buffer, &vf_cur);
+ incr(vf_nf);
+ vf_byte(cmd);
+ }
+ }
+ while (cmd <= long_char) {
+ /*tex Build a character packet. */
+ vf_np = 0;
+ if (cmd == long_char) {
+ vf_read_u(4, packet_length);
+ vf_read_u(4, utmp);
+ cc = (int) utmp;
+ if (!char_exists(f, cc)) {
+ bad_vf("invalid character code");
+ }
+ vf_read(4, k);
+ tfm_width = store_scaled_f(k, font_size(f));
+ } else {
+ packet_length = cmd;
+ vf_byte(cc);
+ if (!char_exists(f, cc)) {
+ bad_vf("invalid character code");
+ }
+ vf_read_u(3, utmp);
+ /*tex cf. |vftovp.web|, line 1028 */
+ k = (int) utmp;
+ tfm_width = store_scaled_f(k, font_size(f));
+ }
+ if (tfm_width != char_width(f, cc)) {
+ if (tfm_width != char_width(f, cc)) {
+ print_nlp();
+ tprint("character width mismatch in font ");
+ tprint(font_name(f));
+ tprint(".vf ignored");
+ }
+ }
+ k = count_packet_bytes(vf_buffer, vf_cur, (int) packet_length);
+ /*tex We need one extra extra for |packet_end|. */
+ vpackets = xmalloc((unsigned) (k + 1));
+ co = get_charinfo(f, cc);
+ k = 0;
+ w = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ while (packet_length > 0) {
+ vf_byte(cmd);
+ decr(packet_length);
+ if (cmd < set1) {
+ if (k == 0) {
+ k = (int) vf_real_fnts[0];
+ append_fnt_set(k);
+ }
+ append_packet(packet_char_code);
+ append_four(cmd);
+ cmd_length = 0;
+ cmd = nop;
+ } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
+ ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
+ if (cmd >= fnt1) {
+ vf_read_u((cmd - fnt1 + 1), utmp);
+ k = (int) utmp;
+ packet_length -= (cmd - fnt1 + 1);
+ } else {
+ k = (int) cmd - fnt_num_0;
+ }
+ /*tex Change from local to external font id. */
+ n = 0;
+ while ((n < vf_nf) && (vf_local_fnts[n] != (unsigned) k))
+ n++;
+ if (n == vf_nf)
+ bad_vf("undefined local font");
+ k = (int) vf_real_fnts[n];
+ append_fnt_set(k);
+ cmd_length = 0;
+ cmd = nop;
+ } else {
+ switch (cmd) {
+ case set_rule:
+ vf_read(4, h);
+ vf_read(4, v);
+ append_packet(packet_rule_code);
+ append_four(h);
+ append_four(v);
+ packet_length -= 8;
+ break;
+ case put_rule:
+ vf_read(4, h);
+ vf_read(4, v);
+ append_packet(packet_push_code);
+ append_packet(packet_rule_code);
+ append_four(h);
+ append_four(v);
+ append_packet(packet_pop_code);
+ packet_length -= 8;
+ break;
+ case set1:
+ case set2:
+ case set3:
+ case set4:
+ if (k == 0) {
+ k = (int) vf_real_fnts[0];
+ append_fnt_set(k);
+ }
+ vf_read_u((cmd - set1 + 1), utmp);
+ i = (int) utmp;
+ append_packet(packet_char_code);
+ append_four(i);
+ packet_length -= (cmd - set1 + 1);
+ break;
+ case put1:
+ case put2:
+ case put3:
+ case put4:
+ if (k == 0) {
+ k = (int) vf_real_fnts[0];
+ append_fnt_set(k);
+ }
+ vf_read_u((cmd - put1 + 1), utmp);
+ i = (int) utmp;
+ append_packet(packet_push_code);
+ append_packet(packet_char_code);
+ append_four(i);
+ append_packet(packet_pop_code);
+ packet_length -= (cmd - put1 + 1);
+ break;
+ case right1:
+ case right2:
+ case right3:
+ case right4:
+ vf_read((cmd - right1 + 1), i);
+ append_packet(packet_right_code);
+ append_four(i);
+ packet_length -= (cmd - right1 + 1);
+ break;
+ case w1:
+ case w2:
+ case w3:
+ case w4:
+ vf_read((cmd - w1 + 1), w);
+ append_packet(packet_right_code);
+ append_four(w);
+ packet_length -= (cmd - w1 + 1);
+ break;
+ case x1:
+ case x2:
+ case x3:
+ case x4:
+ vf_read((cmd - x1 + 1), x);
+ append_packet(packet_right_code);
+ append_four(x);
+ packet_length -= (cmd - x1 + 1);
+ break;
+ case down1:
+ case down2:
+ case down3:
+ case down4:
+ vf_read((cmd - down1 + 1), i);
+ append_packet(packet_down_code);
+ append_four(i);
+ packet_length -= (cmd - down1 + 1);
+ break;
+ case y1:
+ case y2:
+ case y3:
+ case y4:
+ vf_read((cmd - y1 + 1), y);
+ append_packet(packet_down_code);
+ append_four(y);
+ packet_length -= (cmd - y1 + 1);
+ break;
+ case z1:
+ case z2:
+ case z3:
+ case z4:
+ vf_read((cmd - z1 + 1), z);
+ append_packet(packet_down_code);
+ append_four(z);
+ packet_length -= (cmd - z1 + 1);
+ break;
+ case xxx1:
+ case xxx2:
+ case xxx3:
+ case xxx4:
+ vf_read_u((cmd - xxx1 + 1), utmp);
+ cmd_length = (int) utmp;
+ packet_length -= (cmd - xxx1 + 1);
+ if (cmd_length <= 0)
+ bad_vf("special of negative length");
+ packet_length -= (unsigned) cmd_length;
+ append_packet(packet_special_code);
+ append_four(cmd_length);
+ while (cmd_length > 0) {
+ cmd_length--;
+ vf_byte(i);
+ append_packet(i);
+ }
+ break;
+ case w0:
+ append_packet(packet_right_code);
+ append_four(w);
+ break;
+ case x0:
+ append_packet(packet_right_code);
+ append_four(x);
+ break;
+ case y0:
+ append_packet(packet_down_code);
+ append_four(y);
+ break;
+ case z0:
+ append_packet(packet_down_code);
+ append_four(z);
+ break;
+ case nop:
+ break;
+ case push:
+ if (stack_level == vf_stack_size) {
+ overflow("virtual font stack size", vf_stack_size);
+ } else {
+ vf_stack[stack_level].stack_w = w;
+ vf_stack[stack_level].stack_x = x;
+ vf_stack[stack_level].stack_y = y;
+ vf_stack[stack_level].stack_z = z;
+ incr(stack_level);
+ append_packet(packet_push_code);
+ }
+ break;
+ case pop:
+ if (stack_level == 0) {
+ bad_vf("more POPs than PUSHs in character");
+ } else {
+ decr(stack_level);
+ w = vf_stack[stack_level].stack_w;
+ x = vf_stack[stack_level].stack_x;
+ y = vf_stack[stack_level].stack_y;
+ z = vf_stack[stack_level].stack_z;
+ append_packet(packet_pop_code);
+ }
+ break;
+ default:
+ bad_vf("improver DVI command");
+ }
+ }
+ }
+ /*tex Signal end of packet. */
+ append_packet(packet_end_code);
+ if (stack_level != 0)
+ bad_vf("more PUSHs than POPs in character packet");
+ if (packet_length != 0)
+ bad_vf("invalid packet length or DVI command in packet");
+ /*tex Store the packet being built. */
+ set_charinfo_packets(co, vpackets);
+ vf_byte(cmd);
+ }
+ if (cmd != post)
+ bad_vf("POST command expected");
+
+ xfree(vf_buffer);
+}
+
+#define make_command0(N,K) { \
+ lua_newtable(L); \
+ lua_pushstring(L, N); \
+ lua_rawseti(L,-2, 1); \
+ lua_rawseti(L,-2, K); \
+ K++; }
+
+#define make_command1(N,V,K) { \
+ lua_newtable(L); \
+ lua_pushstring(L, N); \
+ lua_rawseti(L,-2, 1); \
+ lua_pushinteger(L, V); \
+ lua_rawseti(L,-2, 2); \
+ lua_rawseti(L,-2, K); \
+ K++; }
+
+#define make_command2(N,V,W,K) { \
+ lua_newtable(L); \
+ lua_pushstring(L, N); \
+ lua_rawseti(L,-2, 1); \
+ lua_pushinteger(L, V); \
+ lua_rawseti(L,-2, 2); \
+ lua_pushinteger(L, W); \
+ lua_rawseti(L,-2, 3); \
+ lua_rawseti(L,-2, K); \
+ K++; }
+
+#define make_commands(N,S,V,K) { \
+ lua_newtable(L); \
+ lua_pushstring(L, N); \
+ lua_rawseti(L,-2, 1); \
+ lua_pushlstring(L, S, V); \
+ lua_rawseti(L,-2, 2); \
+ lua_rawseti(L,-2, K); \
+ K++; }
+
+int make_vf_table(lua_State * L, const char *cnom, scaled atsize)
+{
+ int cmd, k, i;
+ int cc;
+ unsigned cmd_length, packet_length;
+ scaled tfm_width;
+ vf_stack_index stack_level;
+ /*tex multiplier */
+ int vf_z;
+ /*tex correction for negative values */
+ int vf_alpha;
+ eight_bits *s;
+ scaled h, v;
+ scaled w, x, y, z;
+ /*tex \LUA\ stack */
+ int s_top;
+ /*tex local font counter */
+ int vf_nf;
+ scaled ds, fs;
+ four_quarters cs;
+ /*tex accumulator */
+ memory_word tmp_w;
+ vf_stack_record vf_stack[256];
+ unsigned char *vf_buffer;
+ int vf_size;
+ int vf_cur;
+ unsigned utmp;
+ stack_level = 0;
+ /*tex Open |vf_file|, return if not found. */
+ vf_cur = 0;
+ vf_buffer = NULL;
+ vf_size = 0;
+ if (!open_vf_file(cnom, &vf_buffer, &vf_size)) {
+ lua_pushnil(L);
+ return 1;
+ }
+ /*tex Start by creating a table. */
+ s_top = lua_gettop(L);
+ lua_newtable(L);
+ /*tex Process the preamble. */
+ vf_byte(k);
+ if (k != pre)
+ lua_bad_vf("PRE command expected");
+ vf_byte(k);
+ if (k != vf_id)
+ lua_bad_vf("wrong id byte");
+ vf_byte(cmd_length);
+ s = xmalloc(cmd_length);
+ for (k = 1; k <= (int) cmd_length; k++)
+ vf_byte(s[(k - 1)]);
+ lua_pushlstring(L, (char *) s, (size_t) cmd_length);
+ free(s);
+ lua_setfield(L, -2, "header");
+ vf_byte(cs.b0);
+ vf_byte(cs.b1);
+ vf_byte(cs.b2);
+ vf_byte(cs.b3);
+ lua_pushinteger(L, (lua_Number) ((cs.b0 << 24) + (cs.b1 << 16) + (cs.b2 << 8) + cs.b3));
+ lua_setfield(L, -2, "checksum");
+ vf_read(4, k);
+ ds = k / 16;
+ lua_pushinteger(L, ds);
+ lua_setfield(L, -2, "designsize");
+ lua_pushstring(L, cnom);
+ lua_setfield(L, -2, "name");
+ lua_pushinteger(L, atsize);
+ lua_setfield(L, -2, "size");
+ vf_z = atsize;
+ vf_replace_z();
+ /*tex Process the font definitions. */
+ vf_byte(cmd);
+ lua_newtable(L);
+ i = 1;
+ while ((cmd >= fnt_def1) && (cmd <= fnt_def1 + 3)) {
+ lua_newtable(L);
+ vf_read_u((cmd - fnt_def1 + 1), utmp);
+ vf_nf = (int) utmp;
+ vf_nf++;
+ /*tex Add a checksum. */
+ vf_byte(cs.b0);
+ vf_byte(cs.b1);
+ vf_byte(cs.b2);
+ vf_byte(cs.b3);
+ vf_read(4, k);
+ fs = store_scaled_f(k, atsize);
+ lua_pushstring(L, "size");
+ lua_pushinteger(L, fs);
+ lua_rawset(L, -3);
+ vf_read(4, k);
+ /*tex |dsize| is not used */
+ ds = k / 16;
+ vf_byte(tmp_b0);
+ vf_byte(tmp_b1);
+ /*tex Skip the font path. */
+ while (tmp_b0 > 0) {
+ tmp_b0--;
+ vf_byte(k);
+ }
+ s = xmalloc((unsigned) (tmp_b1 + 1));
+ k = 0;
+ while (tmp_b1-- > 0)
+ vf_byte(s[k++]);
+ s[k] = 0;
+ lua_pushstring(L, "name");
+ lua_pushstring(L, xstrdup((char *) s));
+ free(s);
+ lua_rawset(L, -3);
+ lua_rawseti(L, -2, vf_nf);
+ i++;
+ vf_byte(cmd);
+ }
+ if (i > 1) {
+ lua_setfield(L, -2, "fonts");
+ } else {
+ lua_pop(L, 1);
+ }
+ /*tex The table; with characters comes next. */
+ lua_newtable(L);
+ while (cmd <= long_char) {
+ /*tex Build a character packet. */
+ if (cmd == long_char) {
+ vf_read_u(4, packet_length);
+ vf_read_u(4, utmp);
+ cc = (int) utmp;
+ vf_read(4, tfm_width);
+ } else {
+ packet_length = (unsigned) cmd;
+ vf_byte(cc);
+ vf_read_u(3, utmp);
+ tfm_width = (int) utmp;
+ }
+ /*tex For this character entry. */
+ lua_newtable(L);
+ lua_pushinteger(L, tfm_width);
+ lua_setfield(L, -2, "width");
+ /*tex for |commands|: */
+ lua_newtable(L);
+ k = 1;
+ vf_nf = 0;
+ w = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ while (packet_length > 0) {
+ vf_byte(cmd);
+ decr(packet_length);
+ if ((cmd >= set_char_0) && (cmd < set1)) {
+ if (vf_nf == 0) {
+ vf_nf = 1;
+ make_command1("font", vf_nf, k);
+ }
+ make_command1("char", cmd, k);
+ } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) || ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
+ if (cmd >= fnt1) {
+ vf_read_u((cmd - fnt1 + 1), utmp);
+ vf_nf = (int) utmp;
+ vf_nf++;
+ packet_length -= (unsigned) (cmd - fnt1 + 1);
+ } else {
+ vf_nf = cmd - fnt_num_0 + 1;
+ }
+ make_command1("font", vf_nf, k);
+ } else {
+ switch (cmd) {
+ case set_rule:
+ vf_read(4, h);
+ vf_read(4, v);
+ make_command2("rule", store_scaled_f(h, atsize),
+ store_scaled_f(v, atsize), k);
+ packet_length -= 8;
+ break;
+ case put_rule:
+ vf_read(4, h);
+ vf_read(4, v);
+ make_command0("push", k);
+ make_command2("rule", store_scaled_f(h, atsize),
+ store_scaled_f(v, atsize), k);
+ make_command0("pop", k);
+ packet_length -= 8;
+ break;
+ case set1:
+ case set2:
+ case set3:
+ case set4:
+ if (vf_nf == 0) {
+ vf_nf = 1;
+ make_command1("font", vf_nf, k);
+ }
+ vf_read_u((cmd - set1 + 1), utmp);
+ i = (int) utmp;
+ make_command1("char", i, k);
+ packet_length -= (unsigned) (cmd - set1 + 1);
+ break;
+ case put1:
+ case put2:
+ case put3:
+ case put4:
+ if (vf_nf == 0) {
+ vf_nf = 1;
+ make_command1("font", vf_nf, k);
+ }
+ vf_read_u((cmd - put1 + 1), utmp);
+ i = (int) utmp;
+ make_command0("push", k);
+ make_command1("char", i, k);
+ make_command0("pop", k);
+ packet_length -= (unsigned) (cmd - put1 + 1);
+ break;
+ case right1:
+ case right2:
+ case right3:
+ case right4:
+ vf_read((cmd - right1 + 1), i);
+ make_command1("right", store_scaled_f(i, atsize), k);
+ packet_length -= (unsigned) (cmd - right1 + 1);
+ break;
+ case w1:
+ case w2:
+ case w3:
+ case w4:
+ vf_read((cmd - w1 + 1), w);
+ make_command1("right", store_scaled_f(w, atsize), k);
+ packet_length -= (unsigned) (cmd - w1 + 1);
+ break;
+ case x1:
+ case x2:
+ case x3:
+ case x4:
+ vf_read((cmd - x1 + 1), x);
+ make_command1("right", store_scaled_f(x, atsize), k);
+ packet_length -= (unsigned) (cmd - x1 + 1);
+ break;
+ case down1:
+ case down2:
+ case down3:
+ case down4:
+ vf_read((cmd - down1 + 1), i);
+ make_command1("down", store_scaled_f(i, atsize), k);
+ packet_length -= (unsigned) (cmd - down1 + 1);
+ break;
+ case y1:
+ case y2:
+ case y3:
+ case y4:
+ vf_read((cmd - y1 + 1), y);
+ make_command1("down", store_scaled_f(y, atsize), k);
+ packet_length -= (unsigned) (cmd - y1 + 1);
+ break;
+ case z1:
+ case z2:
+ case z3:
+ case z4:
+ vf_read((cmd - z1 + 1), z);
+ make_command1("down", store_scaled_f(z, atsize), k);
+ packet_length -= (unsigned) (cmd - z1 + 1);
+ break;
+ case xxx1:
+ case xxx2:
+ case xxx3:
+ case xxx4:
+ vf_read_u((cmd - xxx1 + 1), cmd_length);
+ packet_length -= (unsigned) (cmd - xxx1 + 1);
+ if (cmd_length <= 0)
+ lua_bad_vf("special of negative length");
+ packet_length -= cmd_length;
+ s = xmalloc((cmd_length + 1));
+ i = 0;
+ while (cmd_length > 0) {
+ cmd_length--;
+ vf_byte(s[i]);
+ i++;
+ }
+ s[i] = 0;
+ make_commands("special", xstrdup((char *) s), (size_t) i, k);
+ free(s);
+ break;
+ case w0:
+ make_command1("right", store_scaled_f(w, atsize), k);
+ break;
+ case x0:
+ make_command1("right", store_scaled_f(x, atsize), k);
+ break;
+ case y0:
+ make_command1("down", store_scaled_f(y, atsize), k);
+ break;
+ case z0:
+ make_command1("down", store_scaled_f(z, atsize), k);
+ break;
+ case nop:
+ break;
+ case push:
+ if (stack_level == vf_stack_size) {
+ overflow("virtual font stack size", vf_stack_size);
+ } else {
+ vf_stack[stack_level].stack_w = w;
+ vf_stack[stack_level].stack_x = x;
+ vf_stack[stack_level].stack_y = y;
+ vf_stack[stack_level].stack_z = z;
+ incr(stack_level);
+ make_command0("push", k);
+ }
+ break;
+ case pop:
+ if (stack_level == 0) {
+ lua_bad_vf("more POPs than PUSHs in character");
+ } else {
+ decr(stack_level);
+ w = vf_stack[stack_level].stack_w;
+ x = vf_stack[stack_level].stack_x;
+ y = vf_stack[stack_level].stack_y;
+ z = vf_stack[stack_level].stack_z;
+ make_command0("pop", k);
+ }
+ break;
+ default:
+ lua_bad_vf("improver DVI command");
+ }
+ }
+ }
+ /*tex Signal end of packet. */
+ lua_setfield(L, -2, "commands");
+ if (stack_level != 0)
+ lua_bad_vf("more PUSHs than POPs in character packet");
+ if (packet_length != 0)
+ lua_bad_vf("invalid packet length or DVI command in packet");
+ lua_rawseti(L, -2, cc);
+ vf_byte(cmd);
+ }
+ lua_setfield(L, -2, "characters");
+ if (cmd != post)
+ lua_bad_vf("POST command expected");
+ xfree(vf_buffer);
+ return 1;
+}
+
+internal_font_number letter_space_font(internal_font_number f, int e, boolean nolig)
+{
+ internal_font_number k;
+ scaled w;
+ int c;
+ charinfo *co;
+ char *new_font_name;
+ /*tex Read a new font and expand the character widths. */
+ k = copy_font(f);
+ if (nolig) {
+ /*tex Disable ligatures for letter-spaced fonts. */
+ set_no_ligatures(k);
+ }
+ /*tex append e.g. |+100ls| to font name; |abs(e) <= 1000|. */
+ new_font_name = xmalloc((unsigned) (strlen(font_name(k)) + 8));
+ if (e > 0) {
+ sprintf(new_font_name, "%s+%ils", font_name(k), (int) e);
+ } else {
+ /*tex Minus from |%i|: */
+ sprintf(new_font_name, "%s%ils", font_name(k), (int) e);
+ }
+ set_font_name(k, new_font_name);
+ /* Create the corresponding virtual font. */
+ set_font_type(k, virtual_font_type);
+ for (c=font_bc(k);c<=font_ec(k);c++) {
+ if (quick_char_exists(k, c)) {
+ int half_w;
+ int vf_np = 0;
+ eight_bits *vpackets = xmalloc((unsigned) (10+10+1));
+ if (e<0) {
+ half_w = -round_xn_over_d(quad(k), -e, 2000);
+ } else {
+ half_w = round_xn_over_d(quad(k), e, 2000);
+ }
+ co = get_charinfo(k, c);
+ w = char_width(k, c)+2*half_w;
+ set_charinfo_width(co, w);
+ append_packet(packet_right_code);
+ append_four(half_w);
+ append_fnt_set(f);
+ append_packet(packet_char_code);
+ append_four(c);
+ append_packet(packet_right_code);
+ append_four(half_w);
+ append_packet(packet_end_code);
+ set_charinfo_packets(co, vpackets);
+ }
+ }
+ /*tex Now patch the quad size. Ok, not in order to remain compatible with \PDFTEX: */
+#if 0
+ if (e<0) {
+ set_font_param(k, quad_code, -round_xn_over_d(quad(k), 1000-e, 1000));
+ } else {
+ set_font_param(k, quad_code, round_xn_over_d(quad(k), 1000+e, 1000));
+ }
+#endif
+ return k;
+}
+
+internal_font_number copy_font_info(internal_font_number f)
+{
+ return copy_font(f);
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1480 +0,0 @@
-% vfovf.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ @c
-/* this is a hack! */
-#define font_max 5000
-
-#define set_char_0 0 /* typeset character 0 and move right */
-#define set1 128 /* typeset a character and move right */
-#define set2 129 /* typeset a character and move right */
-#define set3 130 /* typeset a character and move right */
-#define set4 131 /* typeset a character and move right */
-#define set_rule 132 /* typeset a rule and move right */
-#define put1 133 /* typeset a character without moving */
-#define put2 134 /* typeset a character without moving */
-#define put3 135 /* typeset a character without moving */
-#define put4 136 /* typeset a character without moving */
-#define put_rule 137 /* typeset a rule */
-#define nop 138 /* no operation */
-#define bop 139 /* beginning of page */
-#define eop 140 /* ending of page */
-#define push 141 /* save the current positions */
-#define pop 142 /* restore previous positions */
-#define right1 143 /* move right */
-#define right2 144 /* move right */
-#define right3 145 /* move right */
-#define right4 146 /* move right, 4 bytes */
-#define w0 147 /* move right by |w| */
-#define w1 148 /* move right and set |w| */
-#define w2 149 /* move right and set |w| */
-#define w3 150 /* move right and set |w| */
-#define w4 151 /* move right and set |w| */
-#define x0 152 /* move right by |x| */
-#define x1 153 /* move right and set |x| */
-#define x2 154 /* move right and set |x| */
-#define x3 155 /* move right and set |x| */
-#define x4 156 /* move right and set |x| */
-#define down1 157 /* move down */
-#define down2 158 /* move down */
-#define down3 159 /* move down */
-#define down4 160 /* move down, 4 bytes */
-#define y0 161 /* move down by |y| */
-#define y1 162 /* move down and set |y| */
-#define y2 163 /* move down and set |y| */
-#define y3 164 /* move down and set |y| */
-#define y4 165 /* move down and set |y| */
-#define z0 166 /* move down by |z| */
-#define z1 167 /* move down and set |z| */
-#define z2 168 /* move down and set |z| */
-#define z3 169 /* move down and set |z| */
-#define z4 170 /* move down and set |z| */
-#define fnt_num_0 171 /* set current font to 0 */
-#define fnt1 235 /* set current font */
-#define fnt2 236 /* set current font */
-#define fnt3 237 /* set current font */
-#define fnt4 238 /* set current font */
-#define xxx1 239 /* extension to DVI primitives */
-#define xxx2 240 /* extension to DVI primitives */
-#define xxx3 241 /* extension to DVI primitives */
-#define xxx4 242 /* potentially long extension to DVI primitives */
-#define fnt_def1 243 /* define the meaning of a font number */
-#define pre 247 /* preamble */
-#define post 248 /* postamble beginning */
-#define post_post 249 /* postamble ending */
-#define yyy1 250 /* PDF literal text */
-#define yyy2 251 /* PDF literal text */
-#define yyy3 252 /* PDF literal text */
-#define yyy4 253 /* PDF literal text */
-
-#define null_font 0
-
-#define long_char 242 /* \.{VF} command for general character packet */
-#define vf_id 202 /* identifies \.{VF} files */
-
-@ go out \.{VF} processing with an error message
- at c
-#define bad_vf(a) { \
- xfree(vf_buffer); \
- print_nlp(); \
- formatted_warning("virtual font","file '%s', %s, font will be ignored",font_name(f),a); \
- print_ln(); \
- return; \
-}
-
-#define lua_bad_vf(a) { \
- xfree(vf_buffer); \
- lua_settop(L,s_top); \
- lua_pushnil(L); \
- lua_pushstring(L,a); \
- return 2; \
-}
-
-#define tmp_b0 tmp_w.qqqq.b0
-#define tmp_b1 tmp_w.qqqq.b1
-#define tmp_b2 tmp_w.qqqq.b2
-#define tmp_b3 tmp_w.qqqq.b3
-#define tmp_int tmp_w.cint
-
-#define vf_stack_size 100 /* \.{DVI} files shouldn't |push| beyond this depth */
-
-@ @c
-typedef unsigned char vf_stack_index; /* an index into the stack */
-
-typedef struct vf_stack_record {
- scaled stack_w, stack_x, stack_y, stack_z;
-} vf_stack_record;
-
-@ get a byte from\.{VF} file
- at c
-#define vf_byte(a) \
-{ \
- eight_bits vf_tmp_b; \
- if (vf_cur >= vf_size) { \
- normal_error("virtual font","unexpected eof"); \
- } \
- vf_tmp_b = vf_buffer[vf_cur++]; \
- a = vf_tmp_b; \
-}
-
-@ @c
-#define vf_replace_z() \
-{ \
- vf_alpha = 16; \
- while (vf_z >= 040000000) { \
- vf_z = vf_z / 2; \
- vf_alpha += vf_alpha; \
- } \
- /*vf_beta = (char)(256 / vf_alpha);*/ \
- vf_alpha = (vf_alpha * vf_z); \
-}
-
-
-@ read |k| bytes as an integer from \.{VF} file
-beware: the |vf_read()| macro differs from |vf_read()| in vftovp.web for 1...3 byte words.
- at c
-#define vf_read(k, l) \
-{ \
- int itmp = 0, dtmp = (int)(k), jtmp = 0; \
- while (dtmp > 0) { \
- vf_byte(jtmp); \
- if ((dtmp == (int) k) && jtmp > 127) \
- jtmp = jtmp - 256; \
- itmp = itmp * 256 + jtmp; \
- decr(dtmp); \
- } \
- l = itmp; \
-}
-
-#define vf_read_u(k, l) \
-{ \
- int dtmp = (int)(k); \
- unsigned int itmp = 0, jtmp = 0; \
- while (dtmp-- > 0) { \
- vf_byte(jtmp); \
- itmp = itmp * 256 + jtmp; \
- } \
- l = itmp; \
-}
-
-@ @c
-void pdf_check_vf(internal_font_number f)
-{
- if (font_type(f) == virtual_font_type)
- normal_error("font", "command cannot be used with virtual font");
-}
-
-static void
-vf_local_font_warning(internal_font_number f, internal_font_number k, const char *s, int a, int b)
-{
- print_nlp();
- tprint(s);
- tprint(" in local font ");
- tprint(font_name(k));
- tprint(" (");
- print_int(b);
- tprint(" != ");
- print_int(a);
- tprint(") in virtual font ");
- tprint(font_name(f));
- tprint(".vf ignored.");
-}
-
-
-@ process a local font in \.{VF} file
- at c
-int level = 0;
-
-static internal_font_number
-vf_def_font(internal_font_number f, unsigned char *vf_buffer, int *vf_cr)
-{
- internal_font_number k;
- str_number s;
- char *st;
- scaled ds, fs;
- four_quarters cs;
- memory_word tmp_w; /* accumulator */
- int junk;
- unsigned int checksum;
- cs.b0 = vf_buffer[(*vf_cr)];
- cs.b1 = vf_buffer[(*vf_cr) + 1];
- cs.b2 = vf_buffer[(*vf_cr) + 2];
- cs.b3 = vf_buffer[(*vf_cr) + 3];
- (*vf_cr) += 4;
- checksum = (unsigned)
- (cs.b0 * 256 * 256 * 256 + cs.b1 * 256 * 256 + cs.b2 * 256 + cs.b3);
- k = vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- if (k > 127)
- k -= 256;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
-
- fs = store_scaled_f(k, font_size(f));
-
- k = vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- if (k > 127)
- k -= 256;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- k = k * 256 + vf_buffer[(*vf_cr)];
- (*vf_cr)++;
-
- ds = k / 16;
-
-
- tmp_b0 = vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- tmp_b1 = vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- while (tmp_b0 > 0) {
- tmp_b0--;
- (*vf_cr)++; /* skip the font path */
- }
- str_room((unsigned) tmp_b1);
- while (tmp_b1 > 0) {
- tmp_b1--;
- junk = vf_buffer[(*vf_cr)];
- (*vf_cr)++;
- append_char(junk);
- }
- if (level > 5) {
- normal_warning("vf","quitting at recurse depth > 5");
- k = f ;
- } else if ((level > 1) && (fs > 65536*1024)) {
- normal_warning("vf","quitting when recursing at size > 65536*1024");
- k = f ;
- } else {
- level += 1 ;
- s = make_string();
- st = makecstring(s);
- k = tfm_lookup(st, fs);
- if (k == null_font)
- k = read_font_info(null_cs, st, fs, -1);
- free(st);
- level -= 1 ;
- if (k != null_font) {
- if (checksum != 0 && font_checksum(k) != 0
- && checksum != font_checksum(k))
- vf_local_font_warning(f, k, "checksum mismatch", (int) checksum, (int) font_checksum(k));
- if (ds != font_dsize(k))
- vf_local_font_warning(f, k, "design size mismatch", ds, font_dsize(k));
- }
- }
- return k;
-}
-
-@ @c
-static int open_vf_file(const char *fn, unsigned char **vbuffer, int *vsize)
-{
- boolean res; /* was the callback successful? */
- int callback_id;
- boolean file_read = false; /* was |vf_file| successfully read? */
- FILE *vf_file;
- const char *fname = luatex_find_file(fn, find_vf_file_callback);
- if (fname == NULL || strlen(fname) == 0) {
- /* fname = fn; */
- return 0;
- }
-
- callback_id = callback_defined(read_vf_file_callback);
- if (callback_id > 0) {
- res = run_callback(callback_id, "S->bSd", fname,
- &file_read, vbuffer, vsize);
- if (res && file_read && (*vsize > 0)) {
- return 1;
- }
- if (!file_read)
- return 0; /* -1 */
- } else {
- if (luatex_open_input
- (&(vf_file), fname, kpse_ovf_format, FOPEN_RBIN_MODE, false)
- || luatex_open_input(&(vf_file), fname, kpse_vf_format,
- FOPEN_RBIN_MODE, false)) {
- res = read_vf_file(vf_file, vbuffer, vsize);
- close_file(vf_file);
- if (res) {
- return 1;
- }
- } else {
- return 0; /* -1 */
- }
- }
- return 0;
-}
-
-
-
-@ The |do_vf| procedure attempts to read the \.{VF} file for a font, and sets
- |font_type()| to |real_font_type| if the \.{VF} file could not be found
- or loaded, otherwise sets |font_type()| to |virtual_font_type|. At this
- time, |tmp_f| is the internal font number of the current \.{TFM} font. To
- process font definitions in virtual font we call |vf_def_font|.
-
- at c
-#define append_packet(k) vpackets[vf_np++] = (eight_bits)(k)
-
-@ life is easier if all internal font commands are fnt4 and
- all character commands are set4 or put4
-
- at c
-#define append_fnt_set(k) \
-{ \
- assert(k > 0); \
- append_packet(packet_font_code); \
- append_four(k); \
-}
-
-#define append_four(k) \
-{ \
- append_packet((k & 0xFF000000) >> 24); \
- append_packet((k & 0x00FF0000) >> 16); \
- append_packet((k & 0x0000FF00) >> 8); \
- append_packet((k & 0x000000FF)); \
-}
-
-@ some of these things happen twice, adding a define is simplest
-
- at c
-#define test_checksum() { vf_byte(tmp_b0); vf_byte(tmp_b1); \
- vf_byte(tmp_b2); vf_byte(tmp_b3); \
- if (((tmp_b0 != 0) || (tmp_b1 != 0) || (tmp_b2 != 0) || (tmp_b3 != 0)) && \
- ((font_check_0(f) != 0) || (font_check_1(f) != 0) || \
- (font_check_2(f) != 0) || (font_check_3(f) != 0)) && \
- ((tmp_b0 != font_check_0(f)) || (tmp_b1 != font_check_1(f)) || \
- (tmp_b2 != font_check_2(f)) || (tmp_b3 != font_check_3(f)))) { \
- print_nlp(); \
- tprint("checksum mismatch in font "); \
- tprint(font_name(f)); \
- tprint(".vf ignored "); } }
-
-#define test_dsize() \
-{ \
- int read_tmp; \
- vf_read(4, read_tmp); \
- if ((read_tmp / 16) != font_dsize(f)) { \
- print_nlp(); \
- tprint("design size mismatch in font "); \
- tprint(font_name(f)); \
- tprint(".vf ignored"); \
- } \
-}
-
-@ @c
-static int count_packet_bytes(eight_bits * vf_buf, int cur_bute, int count)
-{
- unsigned k = 0;
- int ff = 0;
- int acc = 0;
- unsigned int cmd = 0;
- unsigned int d = 0;
- while (k < (unsigned) count) {
- cmd = vf_buf[cur_bute + (int) k];
- k++;
- if (cmd < set1) {
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- acc += 5;
- } else if ((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) {
- ff = 1;
- acc += 5;
- } else {
- switch (cmd) {
- case fnt1:
- acc += 5;
- k += 1;
- ff = 1;
- break;
- case fnt2:
- acc += 5;
- k += 2;
- ff = 1;
- break;
- case fnt3:
- acc += 5;
- k += 3;
- ff = 1;
- break;
- case fnt4:
- acc += 5;
- k += 4;
- ff = 1;
- break;
- case set_rule:
- acc += 9;
- k += 8;
- break;
- case put_rule:
- acc += 11;
- k += 8;
- break;
- case set1:
- acc += 5;
- k += 1;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case set2:
- acc += 5;
- k += 2;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case set3:
- acc += 5;
- k += 3;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case set4:
- acc += 5;
- k += 4;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case put1:
- acc += 7;
- k += 1;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case put2:
- acc += 7;
- k += 2;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case put3:
- acc += 7;
- k += 3;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case put4:
- acc += 7;
- k += 4;
- if (ff == 0) {
- ff = 1;
- acc += 5;
- }
- break;
- case right1:
- acc += 5;
- k += 1;
- break;
- case right2:
- acc += 5;
- k += 2;
- break;
- case right3:
- acc += 5;
- k += 3;
- break;
- case right4:
- acc += 5;
- k += 4;
- break;
- case w1:
- acc += 5;
- k += 1;
- break;
- case w2:
- acc += 5;
- k += 2;
- break;
- case w3:
- acc += 5;
- k += 3;
- break;
- case w4:
- acc += 5;
- k += 4;
- break;
- case x1:
- acc += 5;
- k += 1;
- break;
- case x2:
- acc += 5;
- k += 2;
- break;
- case x3:
- acc += 5;
- k += 3;
- break;
- case x4:
- acc += 5;
- k += 4;
- break;
- case down1:
- acc += 5;
- k += 1;
- break;
- case down2:
- acc += 5;
- k += 2;
- break;
- case down3:
- acc += 5;
- k += 3;
- break;
- case down4:
- acc += 5;
- k += 4;
- break;
- case y1:
- acc += 5;
- k += 1;
- break;
- case y2:
- acc += 5;
- k += 2;
- break;
- case y3:
- acc += 5;
- k += 3;
- break;
- case y4:
- acc += 5;
- k += 4;
- break;
- case z1:
- acc += 5;
- k += 1;
- break;
- case z2:
- acc += 5;
- k += 2;
- break;
- case z3:
- acc += 5;
- k += 3;
- break;
- case z4:
- acc += 5;
- k += 4;
- break;
- case xxx1:
- d = vf_buf[cur_bute + (int) k];
- k++;
- k += d;
- acc += 5 + (int) d;
- break;
- case xxx2:
- d = vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- k += d;
- acc += 5 + (int) d;
- break;
- case xxx3:
- d = vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- k += d;
- acc += 5 + (int) d;
- break;
- case xxx4:
- d = vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- d = d * 256 + vf_buf[cur_bute + (int) k];
- k++;
- k += d;
- acc += 5 + (int) d;
- break;
- case w0:
- acc += 5;
- break;
- case x0:
- acc += 5;
- break;
- case y0:
- acc += 5;
- break;
- case z0:
- acc += 5;
- break;
- case nop:
- break;
- case push:
- acc += 1;
- break;
- case pop:
- acc += 1;
- break;
- }
- }
- }
- return (acc + 1);
-}
-
-@ @c
-void do_vf(internal_font_number f)
-{
- int k, i;
- unsigned cmd, n;
- scaled x, y, w, z, h, v;
- int cc, cmd_length;
- unsigned packet_length;
- charinfo *co;
- scaled tfm_width;
- int save_cur_byte;
- vf_stack_index stack_level;
- int vf_z; /* multiplier */
- int vf_alpha; /* correction for negative values */
- /*char vf_beta;*/ /* divisor */
- int vf_np;
- eight_bits *vpackets;
- memory_word tmp_w; /* accumulator */
- vf_stack_record vf_stack[256];
- int junk;
- unsigned utmp;
- unsigned char *vf_buffer;
- int vf_size;
- int vf_cur;
- unsigned *vf_local_fnts = NULL; /* external font ids */
- unsigned *vf_real_fnts = NULL; /* internal font ids */
- unsigned vf_nf = 0; /* local font counter */
-
- if (font_type(f) != unknown_font_type)
- return;
- set_font_type(f, real_font_type);
- stack_level = 0;
- /* Open |vf_file|, return if not found */
- vf_cur = 0;
- vf_buffer = NULL;
- vf_size = 0;
- if (!open_vf_file(font_name(f), &vf_buffer, &vf_size))
- return;
- /* Process the preamble */
- set_font_type(f, virtual_font_type);
- vf_byte(k);
- if (k != pre)
- bad_vf("PRE command expected");
- vf_byte(k);
- if (k != vf_id)
- bad_vf("wrong id byte");
- vf_byte(cmd_length);
- for (k = 1; k <= cmd_length; k++)
- vf_byte(junk);
- test_checksum();
- test_dsize();
- vf_z = font_size(f);
- vf_replace_z();
- /* Process the font definitions */
- /* scan forward to find the number of internal fonts */
- vf_nf = 0;
- save_cur_byte = vf_cur;
- vf_byte(cmd);
- while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
- vf_read_u((cmd - fnt_def1 + 1), utmp);
- vf_read(4, junk);
- vf_read(4, junk);
- vf_read(4, junk);
- vf_byte(k);
- vf_byte(junk);
- k += junk;
- while (k-- > 0) {
- vf_byte(junk);
- }
- incr(vf_nf);
- vf_byte(cmd);
- }
- vf_cur = save_cur_byte;
- vf_byte(cmd);
- /* malloc and fill the local font arrays */
- if (vf_nf > 0) {
- unsigned ii = (unsigned) ((unsigned) vf_nf * sizeof(int));
- vf_local_fnts = xmalloc(ii);
- memset(vf_local_fnts, 0, ii);
- vf_real_fnts = xmalloc(ii);
- memset(vf_real_fnts, 0, ii);
- vf_nf = 0;
- while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
- vf_read_u((cmd - fnt_def1 + 1), vf_local_fnts[vf_nf]);
- vf_real_fnts[vf_nf] = (unsigned) vf_def_font(f, vf_buffer, &vf_cur);
- incr(vf_nf);
- vf_byte(cmd);
- }
- }
-
-
- while (cmd <= long_char) {
- /* Build a character packet */
- vf_np = 0;
- if (cmd == long_char) {
- vf_read_u(4, packet_length);
- vf_read_u(4, utmp);
- cc = (int) utmp;
- if (!char_exists(f, cc)) {
- bad_vf("invalid character code");
- }
- vf_read(4, k);
- tfm_width = store_scaled_f(k, font_size(f));
- } else {
- packet_length = cmd;
- vf_byte(cc);
- if (!char_exists(f, cc)) {
- bad_vf("invalid character code");
- }
- vf_read_u(3, utmp);
- k = (int) utmp; /* cf. vftovp.web, line 1028 */
- tfm_width = store_scaled_f(k, font_size(f));
- }
-
-
- if (tfm_width != char_width(f, cc)) {
- if (tfm_width != char_width(f, cc)) {
- print_nlp();
- tprint("character width mismatch in font ");
- tprint(font_name(f));
- tprint(".vf ignored");
- }
- }
- k = count_packet_bytes(vf_buffer, vf_cur, (int) packet_length);
- vpackets = xmalloc((unsigned) (k + 1)); /* need one extra extra for |packet_end| */
- co = get_charinfo(f, cc);
- k = 0;
- w = 0;
- x = 0;
- y = 0;
- z = 0;
- while (packet_length > 0) {
- vf_byte(cmd);
- decr(packet_length);
-
- if (cmd < set1) {
- if (k == 0) {
- k = (int) vf_real_fnts[0];
- append_fnt_set(k);
- }
- append_packet(packet_char_code);
- append_four(cmd);
- cmd_length = 0;
- cmd = nop;
-
- } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
- ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
- if (cmd >= fnt1) {
- vf_read_u((cmd - fnt1 + 1), utmp);
- k = (int) utmp;
- packet_length -= (cmd - fnt1 + 1);
- } else {
- k = (int) cmd - fnt_num_0;
- }
-
- /* change from local to external font id */
- n = 0;
- while ((n < vf_nf) && (vf_local_fnts[n] != (unsigned) k))
- n++;
- if (n == vf_nf)
- bad_vf("undefined local font");
-
- k = (int) vf_real_fnts[n];
- append_fnt_set(k);
- cmd_length = 0;
- cmd = nop;
- } else {
- switch (cmd) {
- case set_rule:
- vf_read(4, h);
- vf_read(4, v);
- append_packet(packet_rule_code);
- append_four(h);
- append_four(v);
- packet_length -= 8;
- break;
- case put_rule:
- vf_read(4, h);
- vf_read(4, v);
- append_packet(packet_push_code);
- append_packet(packet_rule_code);
- append_four(h);
- append_four(v);
- append_packet(packet_pop_code);
- packet_length -= 8;
- break;
- case set1:
- case set2:
- case set3:
- case set4:
- if (k == 0) {
- k = (int) vf_real_fnts[0];
- append_fnt_set(k);
- }
- vf_read_u((cmd - set1 + 1), utmp);
- i = (int) utmp;
- append_packet(packet_char_code);
- append_four(i);
- packet_length -= (cmd - set1 + 1);
- break;
- case put1:
- case put2:
- case put3:
- case put4:
- if (k == 0) {
- k = (int) vf_real_fnts[0];
- append_fnt_set(k);
- }
- vf_read_u((cmd - put1 + 1), utmp);
- i = (int) utmp;
- append_packet(packet_push_code);
- append_packet(packet_char_code);
- append_four(i);
- append_packet(packet_pop_code);
- packet_length -= (cmd - put1 + 1);
- break;
- case right1:
- case right2:
- case right3:
- case right4:
- vf_read((cmd - right1 + 1), i);
- append_packet(packet_right_code);
- append_four(i);
- packet_length -= (cmd - right1 + 1);
- break;
- case w1:
- case w2:
- case w3:
- case w4:
- vf_read((cmd - w1 + 1), w);
- append_packet(packet_right_code);
- append_four(w);
- packet_length -= (cmd - w1 + 1);
- break;
- case x1:
- case x2:
- case x3:
- case x4:
- vf_read((cmd - x1 + 1), x);
- append_packet(packet_right_code);
- append_four(x);
- packet_length -= (cmd - x1 + 1);
- break;
- case down1:
- case down2:
- case down3:
- case down4:
- vf_read((cmd - down1 + 1), i);
- append_packet(packet_down_code);
- append_four(i);
- packet_length -= (cmd - down1 + 1);
- break;
- case y1:
- case y2:
- case y3:
- case y4:
- vf_read((cmd - y1 + 1), y);
- append_packet(packet_down_code);
- append_four(y);
- packet_length -= (cmd - y1 + 1);
- break;
- case z1:
- case z2:
- case z3:
- case z4:
- vf_read((cmd - z1 + 1), z);
- append_packet(packet_down_code);
- append_four(z);
- packet_length -= (cmd - z1 + 1);
- break;
- case xxx1:
- case xxx2:
- case xxx3:
- case xxx4:
- vf_read_u((cmd - xxx1 + 1), utmp);
- cmd_length = (int) utmp;
- packet_length -= (cmd - xxx1 + 1);
- if (cmd_length <= 0)
- bad_vf("special of negative length");
- packet_length -= (unsigned) cmd_length;
-
- append_packet(packet_special_code);
- append_four(cmd_length);
- while (cmd_length > 0) {
- cmd_length--;
- vf_byte(i);
- append_packet(i);
- }
- break;
- case w0:
- append_packet(packet_right_code);
- append_four(w);
- break;
- case x0:
- append_packet(packet_right_code);
- append_four(x);
- break;
- case y0:
- append_packet(packet_down_code);
- append_four(y);
- break;
- case z0:
- append_packet(packet_down_code);
- append_four(z);
- break;
- case nop:
- break;
- case push:
- if (stack_level == vf_stack_size) {
- overflow("virtual font stack size", vf_stack_size);
- } else {
- vf_stack[stack_level].stack_w = w;
- vf_stack[stack_level].stack_x = x;
- vf_stack[stack_level].stack_y = y;
- vf_stack[stack_level].stack_z = z;
- incr(stack_level);
- append_packet(packet_push_code);
- }
- break;
- case pop:
- if (stack_level == 0) {
- bad_vf("more POPs than PUSHs in character");
- } else {
- decr(stack_level);
- w = vf_stack[stack_level].stack_w;
- x = vf_stack[stack_level].stack_x;
- y = vf_stack[stack_level].stack_y;
- z = vf_stack[stack_level].stack_z;
- append_packet(packet_pop_code);
- }
- break;
- default:
- bad_vf("improver DVI command");
- }
- }
- }
- /* signal end of packet */
- append_packet(packet_end_code);
-
- if (stack_level != 0)
- bad_vf("more PUSHs than POPs in character packet");
- if (packet_length != 0)
- bad_vf("invalid packet length or DVI command in packet");
- /* \.{Store the packet being built} */
- set_charinfo_packets(co, vpackets);
- vf_byte(cmd);
- }
- if (cmd != post)
- bad_vf("POST command expected");
-
- xfree(vf_buffer);
-}
-
-@ @c
-#define make_command0(N,K) { \
- lua_newtable(L); \
- lua_pushstring(L, N); \
- lua_rawseti(L,-2, 1); \
- lua_rawseti(L,-2, K); \
- K++; }
-
-#define make_command1(N,V,K) { \
- lua_newtable(L); \
- lua_pushstring(L, N); \
- lua_rawseti(L,-2, 1); \
- lua_pushinteger(L, V); \
- lua_rawseti(L,-2, 2); \
- lua_rawseti(L,-2, K); \
- K++; }
-
-#define make_command2(N,V,W,K) { \
- lua_newtable(L); \
- lua_pushstring(L, N); \
- lua_rawseti(L,-2, 1); \
- lua_pushinteger(L, V); \
- lua_rawseti(L,-2, 2); \
- lua_pushinteger(L, W); \
- lua_rawseti(L,-2, 3); \
- lua_rawseti(L,-2, K); \
- K++; }
-
-#define make_commands(N,S,V,K) { \
- lua_newtable(L); \
- lua_pushstring(L, N); \
- lua_rawseti(L,-2, 1); \
- lua_pushlstring(L, S, V); \
- lua_rawseti(L,-2, 2); \
- lua_rawseti(L,-2, K); \
- K++; }
-
-
-int make_vf_table(lua_State * L, const char *cnom, scaled atsize)
-{
- int cmd, k, i;
- int cc;
- unsigned cmd_length, packet_length;
- scaled tfm_width;
- vf_stack_index stack_level;
- int vf_z; /* multiplier */
- int vf_alpha; /* correction for negative values */
- /*char vf_beta;*/ /* divisor */
- eight_bits *s;
- scaled h, v;
- scaled w, x, y, z;
- int s_top; /* lua stack */
- int vf_nf; /* local font counter */
- scaled ds, fs;
- four_quarters cs;
- memory_word tmp_w; /* accumulator */
- vf_stack_record vf_stack[256];
- unsigned char *vf_buffer;
- int vf_size;
- int vf_cur;
- unsigned utmp;
-
-
- stack_level = 0;
- /* Open |vf_file|, return if not found */
- vf_cur = 0;
- vf_buffer = NULL;
- vf_size = 0;
- if (!open_vf_file(cnom, &vf_buffer, &vf_size)) {
- lua_pushnil(L);
- return 1;
- }
-
- /* start by creating a table */
- s_top = lua_gettop(L);
- lua_newtable(L);
-
- /* Process the preamble */
- vf_byte(k);
- if (k != pre)
- lua_bad_vf("PRE command expected");
- vf_byte(k);
- if (k != vf_id)
- lua_bad_vf("wrong id byte");
- vf_byte(cmd_length);
-
- s = xmalloc(cmd_length);
- for (k = 1; k <= (int) cmd_length; k++)
- vf_byte(s[(k - 1)]);
-
- lua_pushlstring(L, (char *) s, (size_t) cmd_length);
- free(s);
- lua_setfield(L, -2, "header");
-
- vf_byte(cs.b0);
- vf_byte(cs.b1);
- vf_byte(cs.b2);
- vf_byte(cs.b3);
- lua_pushinteger(L, (lua_Number) ((cs.b0 << 24) + (cs.b1 << 16) + (cs.b2 << 8) + cs.b3));
- lua_setfield(L, -2, "checksum");
-
- vf_read(4, k);
- ds = k / 16;
- lua_pushinteger(L, ds);
- lua_setfield(L, -2, "designsize");
-
-
- lua_pushstring(L, cnom);
- lua_setfield(L, -2, "name");
-
- lua_pushinteger(L, atsize);
- lua_setfield(L, -2, "size");
-
- vf_z = atsize;
- vf_replace_z();
- /* Process the font definitions */
- vf_byte(cmd);
- lua_newtable(L);
-
- i = 1;
- while ((cmd >= fnt_def1) && (cmd <= fnt_def1 + 3)) {
-
- lua_newtable(L);
- vf_read_u((cmd - fnt_def1 + 1), utmp);
- vf_nf = (int) utmp;
- vf_nf++;
- /* checksum */
- vf_byte(cs.b0);
- vf_byte(cs.b1);
- vf_byte(cs.b2);
- vf_byte(cs.b3);
-
- vf_read(4, k);
- fs = store_scaled_f(k, atsize);
- lua_pushstring(L, "size");
- lua_pushinteger(L, fs);
- lua_rawset(L, -3);
-
- vf_read(4, k);
- ds = k / 16; /* dsize, not used */
-
- vf_byte(tmp_b0);
- vf_byte(tmp_b1);
- while (tmp_b0 > 0) {
- tmp_b0--;
- vf_byte(k);
- } /* skip the font path */
-
- s = xmalloc((unsigned) (tmp_b1 + 1));
- k = 0;
- while (tmp_b1-- > 0)
- vf_byte(s[k++]);
- s[k] = 0;
- lua_pushstring(L, "name");
- lua_pushstring(L, xstrdup((char *) s));
- free(s);
- lua_rawset(L, -3);
-
- lua_rawseti(L, -2, vf_nf);
- i++;
- vf_byte(cmd);
- }
-
- if (i > 1) {
- lua_setfield(L, -2, "fonts");
- } else {
- lua_pop(L, 1);
- }
-
- lua_newtable(L); /* 'characters' */
- while (cmd <= long_char) {
- /* Build a character packet */
- if (cmd == long_char) {
- vf_read_u(4, packet_length);
- vf_read_u(4, utmp);
- cc = (int) utmp;
- vf_read(4, tfm_width);
- } else {
- packet_length = (unsigned) cmd;
- vf_byte(cc);
- vf_read_u(3, utmp);
- tfm_width = (int) utmp;
- }
- lua_newtable(L); /* for this character */
- lua_pushinteger(L, tfm_width);
- lua_setfield(L, -2, "width");
- lua_newtable(L); /* for 'commands' */
- k = 1;
- vf_nf = 0;
- w = 0;
- x = 0;
- y = 0;
- z = 0;
- while (packet_length > 0) {
- vf_byte(cmd);
- decr(packet_length);
- if ((cmd >= set_char_0) && (cmd < set1)) {
- if (vf_nf == 0) {
- vf_nf = 1;
- make_command1("font", vf_nf, k);
- }
- make_command1("char", cmd, k);
- } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
- ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
- if (cmd >= fnt1) {
- vf_read_u((cmd - fnt1 + 1), utmp);
- vf_nf = (int) utmp;
- vf_nf++;
- packet_length -= (unsigned) (cmd - fnt1 + 1);
- } else {
- vf_nf = cmd - fnt_num_0 + 1;
- }
- make_command1("font", vf_nf, k);
- } else {
- switch (cmd) {
- case set_rule:
- vf_read(4, h);
- vf_read(4, v);
- make_command2("rule", store_scaled_f(h, atsize),
- store_scaled_f(v, atsize), k);
- packet_length -= 8;
- break;
- case put_rule:
- vf_read(4, h);
- vf_read(4, v);
- make_command0("push", k);
- make_command2("rule", store_scaled_f(h, atsize),
- store_scaled_f(v, atsize), k);
- make_command0("pop", k);
- packet_length -= 8;
- break;
- case set1:
- case set2:
- case set3:
- case set4:
- if (vf_nf == 0) {
- vf_nf = 1;
- make_command1("font", vf_nf, k);
- }
- vf_read_u((cmd - set1 + 1), utmp);
- i = (int) utmp;
- make_command1("char", i, k);
- packet_length -= (unsigned) (cmd - set1 + 1);
- break;
- case put1:
- case put2:
- case put3:
- case put4:
- if (vf_nf == 0) {
- vf_nf = 1;
- make_command1("font", vf_nf, k);
- }
- vf_read_u((cmd - put1 + 1), utmp);
- i = (int) utmp;
- make_command0("push", k);
- make_command1("char", i, k);
- make_command0("pop", k);
- packet_length -= (unsigned) (cmd - put1 + 1);
- break;
- case right1:
- case right2:
- case right3:
- case right4:
- vf_read((cmd - right1 + 1), i);
- make_command1("right", store_scaled_f(i, atsize), k);
- packet_length -= (unsigned) (cmd - right1 + 1);
- break;
- case w1:
- case w2:
- case w3:
- case w4:
- vf_read((cmd - w1 + 1), w);
- make_command1("right", store_scaled_f(w, atsize), k);
- packet_length -= (unsigned) (cmd - w1 + 1);
- break;
- case x1:
- case x2:
- case x3:
- case x4:
- vf_read((cmd - x1 + 1), x);
- make_command1("right", store_scaled_f(x, atsize), k);
- packet_length -= (unsigned) (cmd - x1 + 1);
- break;
- case down1:
- case down2:
- case down3:
- case down4:
- vf_read((cmd - down1 + 1), i);
- make_command1("down", store_scaled_f(i, atsize), k);
- packet_length -= (unsigned) (cmd - down1 + 1);
- break;
- case y1:
- case y2:
- case y3:
- case y4:
- vf_read((cmd - y1 + 1), y);
- make_command1("down", store_scaled_f(y, atsize), k);
- packet_length -= (unsigned) (cmd - y1 + 1);
- break;
- case z1:
- case z2:
- case z3:
- case z4:
- vf_read((cmd - z1 + 1), z);
- make_command1("down", store_scaled_f(z, atsize), k);
- packet_length -= (unsigned) (cmd - z1 + 1);
- break;
- case xxx1:
- case xxx2:
- case xxx3:
- case xxx4:
- vf_read_u((cmd - xxx1 + 1), cmd_length);
- packet_length -= (unsigned) (cmd - xxx1 + 1);
- if (cmd_length <= 0)
- lua_bad_vf("special of negative length");
- packet_length -= cmd_length;
-
- s = xmalloc((cmd_length + 1));
- i = 0;
- while (cmd_length > 0) {
- cmd_length--;
- vf_byte(s[i]);
- i++;
- }
- s[i] = 0;
- make_commands("special", xstrdup((char *) s), (size_t) i,
- k);
- free(s);
- break;
- case w0:
- make_command1("right", store_scaled_f(w, atsize), k);
- break;
- case x0:
- make_command1("right", store_scaled_f(x, atsize), k);
- break;
- case y0:
- make_command1("down", store_scaled_f(y, atsize), k);
- break;
- case z0:
- make_command1("down", store_scaled_f(z, atsize), k);
- break;
- case nop:
- break;
- case push:
- if (stack_level == vf_stack_size) {
- overflow("virtual font stack size", vf_stack_size);
- } else {
- vf_stack[stack_level].stack_w = w;
- vf_stack[stack_level].stack_x = x;
- vf_stack[stack_level].stack_y = y;
- vf_stack[stack_level].stack_z = z;
- incr(stack_level);
- make_command0("push", k);
- }
- break;
- case pop:
- if (stack_level == 0) {
- lua_bad_vf("more POPs than PUSHs in character");
- } else {
- decr(stack_level);
- w = vf_stack[stack_level].stack_w;
- x = vf_stack[stack_level].stack_x;
- y = vf_stack[stack_level].stack_y;
- z = vf_stack[stack_level].stack_z;
- make_command0("pop", k);
- }
- break;
- default:
- lua_bad_vf("improver DVI command");
- }
- }
- }
- /* signal end of packet */
- lua_setfield(L, -2, "commands");
-
- if (stack_level != 0)
- lua_bad_vf("more PUSHs than POPs in character packet");
- if (packet_length != 0)
- lua_bad_vf("invalid packet length or DVI command in packet");
-
- lua_rawseti(L, -2, cc);
-
- vf_byte(cmd);
- }
- lua_setfield(L, -2, "characters");
-
- if (cmd != post)
- lua_bad_vf("POST command expected");
- xfree(vf_buffer);
- return 1;
-}
-
-@ @c
-internal_font_number
-letter_space_font(internal_font_number f, int e, boolean nolig)
-{
- internal_font_number k;
- scaled w;
- int c;
- charinfo *co;
- char *new_font_name;
-
- /* read a new font and expand the character widths */
- k = copy_font(f);
-
- if (nolig)
- set_no_ligatures(k); /* disable ligatures for letter-spaced fonts */
-
- /* append eg '+100ls' to font name */
- new_font_name = xmalloc((unsigned) (strlen(font_name(k)) + 8)); /* |abs(e) <= 1000| */
- if (e > 0) {
- sprintf(new_font_name, "%s+%ils", font_name(k), (int) e);
- } else {
- /* minus from \%i */
- sprintf(new_font_name, "%s%ils", font_name(k), (int) e);
- }
- set_font_name(k, new_font_name);
-
- /* create the corresponding virtual font */
- set_font_type(k, virtual_font_type);
-
- for (c=font_bc(k);c<=font_ec(k);c++) {
- if (quick_char_exists(k, c)) {
- int half_w;
- int vf_np = 0;
- eight_bits *vpackets = xmalloc((unsigned) (10+10+1));
- if (e<0) {
- half_w = -round_xn_over_d(quad(k), -e, 2000);
- } else {
- half_w = round_xn_over_d(quad(k), e, 2000);
- }
- co = get_charinfo(k, c);
- w = char_width(k, c)+2*half_w;
- set_charinfo_width(co, w);
-
- append_packet(packet_right_code);
- append_four(half_w);
- append_fnt_set(f);
- append_packet(packet_char_code);
- append_four(c);
- append_packet(packet_right_code);
- append_four(half_w);
- append_packet(packet_end_code);
-
- set_charinfo_packets(co, vpackets);
- }
- }
- /* now patch the quad size */
- /* Patch 20100922: do not do this, to remain compatible with pdftex */
-#if 0
- if (e<0) {
- set_font_param(k, quad_code, -round_xn_over_d(quad(k), 1000-e, 1000));
- } else {
- set_font_param(k, quad_code, round_xn_over_d(quad(k), 1000+e, 1000));
- }
-#endif
- return k;
-}
-
-@ @c
-internal_font_number copy_font_info(internal_font_number f)
-{
- return copy_font(f);
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,445 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/*tex
+
+ Some macros for processing character packets.
+
+*/
+
+#define packet_number(fw) { \
+ fw = *(vfp++); \
+ fw = fw * 256 + *(vfp++); \
+ fw = fw * 256 + *(vfp++); \
+ fw = fw * 256 + *(vfp++); \
+}
+
+#define packet_scaled(a, fs) { \
+ int fw; \
+ fw = *(vfp++); \
+ if (fw > 127) \
+ fw = fw - 256; \
+ fw = fw * 256 + *(vfp++); \
+ fw = fw * 256 + *(vfp++); \
+ fw = fw * 256 + *(vfp++); \
+ a = store_scaled_f(fw, fs); \
+}
+
+vf_struct *new_vfstruct(void)
+{
+ vf_struct *vp = (vf_struct *) xmalloc(sizeof(vf_struct));
+ vp->packet_stack_level = vp->packet_stack_minlevel = 0;
+ vp->packet_stack = (packet_stack_record *) xmalloc(packet_stack_size * sizeof(packet_stack_record));
+ vp->lf = 0;
+ vp->fs_f = 0;
+ vp->packet_cur_s = 0;
+ vp->refpos = NULL;
+ vp->vflua = false;
+ return vp;
+}
+
+/*tex
+
+ Count the number of bytes in a command packet.
+*/
+
+int vf_packet_bytes(charinfo * co)
+{
+ eight_bits *vf_packets, *vfp;
+ unsigned k;
+ int cmd;
+ vfp = vf_packets = get_charinfo_packets(co);
+ if (vf_packets == NULL) {
+ return 0;
+ }
+ while ((cmd = *(vfp++)) != packet_end_code) {
+ switch (cmd) {
+ case packet_nop_code:
+ case packet_pop_code:
+ case packet_push_code:
+ break;
+ case packet_char_code:
+ case packet_down_code:
+ case packet_font_code:
+ case packet_image_code:
+ case packet_node_code:
+ case packet_right_code:
+ vfp += 4;
+ break;
+ case packet_rule_code:
+ vfp += 8;
+ break;
+ case packet_pdf_mode:
+ vfp += 4;
+ break;
+ case packet_pdf_code:
+ vfp += 4;
+ /*tex Plus a string so we fall through: */
+ case packet_special_code:
+ /*tex |+4| */
+ packet_number(k);
+ vfp += (int) k;
+ break;
+ default:
+ normal_error("vf", "invalid DVI command (1)");
+ }
+ };
+ return (vfp - vf_packets);
+}
+
+/*tex
+
+ Typeset the \.{DVI} commands in the character packet for character |c| in
+ current font |f|.
+*/
+
+const char *packet_command_names[] = {
+ /*tex |slot| maps to |char| and |font| */
+ "char",
+ "font",
+ "pop",
+ "push",
+ "special",
+ "image",
+ "right",
+ "down",
+ "rule",
+ "node",
+ "nop",
+ "end",
+ /*tex the next one is not (yet) supported */
+ "scale",
+ "lua",
+ "pdf",
+ NULL
+};
+
+static float packet_float(eight_bits ** vfpp)
+{
+ unsigned int i;
+ union U {
+ float a;
+ eight_bits b[sizeof(float)];
+ } u;
+ eight_bits *vfp = *vfpp;
+ for (i = 0; i < sizeof(float); i++)
+ u.b[i] = *(vfp++);
+ *vfpp = vfp;
+ return u.a;
+}
+
+/*tex
+
+ The |do_vf_packet| procedure is called in order to interpret the character
+ packet for a virtual character. Such a packet may contain the instruction to
+ typeset a character from the same or an other virtual font; in such cases
+ |do_vf_packet| calls itself recursively. The recursion level, i.e., the
+ number of times this has happened, is kept in the global variable
+ |packet_cur_s| and should not exceed |packet_max_recursion|.
+*/
+
+void do_vf_packet(PDF pdf, internal_font_number vf_f, int c, int ex_glyph)
+{
+ eight_bits *vfp;
+ posstructure *save_posstruct, localpos;
+ vf_struct *save_vfstruct, localvfstruct, *vp;
+ int cmd, w, mode;
+ unsigned k;
+ scaledpos size;
+ scaled i;
+ str_number s;
+ float f;
+ packet_stack_record *mat_p;
+ vfp = get_charinfo_packets(get_charinfo(vf_f, c));
+ save_posstruct = pdf->posstruct;
+ /*tex use local structure for recursion */
+ pdf->posstruct = &localpos;
+ localpos.pos = save_posstruct->pos;
+ /*tex invariably for vf */
+ localpos.dir = dir_TLT;
+ save_vfstruct = pdf->vfstruct;
+ vp = pdf->vfstruct = &localvfstruct;
+ localvfstruct = *save_vfstruct;
+ vp->packet_stack_minlevel = ++(vp->packet_stack_level);
+ vp->lf = 0;
+ vp->fs_f = font_size(vf_f);
+ vp->ex_glyph = ex_glyph;
+ vp->packet_cur_s++;
+ if (vp->packet_cur_s == packet_max_recursion)
+ overflow("max level recursion of virtual fonts", packet_max_recursion);
+ vp->refpos = save_posstruct;
+ vp->vflua = false;
+ mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+ mat_p->c0 = 1.0;
+ mat_p->c1 = 0.0;
+ mat_p->c2 = 0.0;
+ mat_p->c3 = 1.0;
+ mat_p->pos.h = 0;
+ mat_p->pos.v = 0;
+ while ((cmd = *(vfp++)) != packet_end_code) {
+ switch (cmd) {
+ case packet_font_code:
+ packet_number(vp->lf);
+ break;
+ case packet_push_code:
+ vp->packet_stack_level++;
+ if (vp->packet_stack_level == packet_stack_size)
+ normal_error("vf", "packet_stack_level overflow");
+ vp->packet_stack[vp->packet_stack_level] = *mat_p;
+ mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+ break;
+ case packet_pop_code:
+ if (vp->packet_stack_level == vp->packet_stack_minlevel)
+ normal_error("vf", "packet_stack_level underflow");
+ vp->packet_stack_level--;
+ mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+ break;
+ case packet_char_code:
+ packet_number(k);
+ /*tex We also check if |c == k| and |font(c) == font(k)| */
+ if (!char_exists(vp->lf, (int) k)) {
+ char_warning(vp->lf, (int) k);
+ } else if (! ((c == k && vp->lf == vf_f)) && (has_packet(vp->lf, (int) k))) {
+ do_vf_packet(pdf, vp->lf, (int) k, ex_glyph);
+ } else {
+ backend_out[glyph_node] (pdf, vp->lf, (int) k, ex_glyph);
+ }
+ w = char_width(vp->lf, (int) k);
+ if (ex_glyph != 0 && w != 0)
+ w = round_xn_over_d(w, 1000 + ex_glyph, 1000);
+ mat_p->pos.h += w;
+ break;
+ case packet_rule_code:
+ packet_scaled(size.v, vp->fs_f);
+ packet_scaled(size.h, vp->fs_f);
+ if (ex_glyph != 0 && size.h > 0)
+ size.h = round_xn_over_d(size.h, 1000 + ex_glyph, 1000);
+ if (size.h > 0 && size.v > 0)
+ backend_out[rule_node](pdf, 0, size);
+ mat_p->pos.h += size.h;
+ break;
+ case packet_right_code:
+ packet_scaled(i, vp->fs_f);
+ if (ex_glyph != 0 && i != 0)
+ i = round_xn_over_d(i, 1000 + ex_glyph, 1000);
+ mat_p->pos.h += i;
+ break;
+ case packet_down_code:
+ packet_scaled(i, vp->fs_f);
+ mat_p->pos.v += i;
+ break;
+ case packet_pdf_code:
+ packet_number(mode);
+ packet_number(k);
+ str_room(k);
+ while (k > 0) {
+ k--;
+ append_char(*(vfp++));
+ }
+ s = make_string();
+ pdf_literal(pdf, s, mode, false);
+ flush_str(s);
+ break;
+ case packet_pdf_mode:
+ packet_number(mode);
+ pdf_literal_set_mode(pdf, mode);
+ break;
+ case packet_special_code:
+ packet_number(k);
+ str_room(k);
+ while (k > 0) {
+ k--;
+ append_char(*(vfp++));
+ }
+ s = make_string();
+ pdf_literal(pdf, s, scan_special, false);
+ flush_str(s);
+ break;
+ case packet_lua_code:
+ packet_number(k);
+ vp->vflua = true;
+ luacall_vf(k, vf_f, c);
+ /*tex
+
+ We don't release as we (can ) flush multiple times, so no:
+
+ \starttyping
+ luaL_unref(Luas, LUA_REGISTRYINDEX, k);
+ \stoptyping
+
+ here!
+
+ */
+ vp->vflua = false;
+ break;
+ case packet_image_code:
+ packet_number(k);
+ vf_out_image(pdf, k);
+ break;
+ case packet_node_code:
+ packet_number(k);
+ hlist_out(pdf, (halfword) k, 0);
+ break;
+ case packet_nop_code:
+ break;
+ case packet_scale_code:
+ /*tex This is not yet supported in the backend. */
+ f = packet_float(&vfp);
+ mat_p->c0 = mat_p->c0 * f;
+ mat_p->c3 = mat_p->c3 * f;
+ /* pdf->pstruct->scale = f; */
+ pdf->pstruct->need_tm = true;
+ pdf->pstruct->need_tf = true;
+ break;
+ default:
+ normal_error("vf", "invalid DVI command (2)");
+ }
+ /*tex The trivial case, always |TLT|. */
+ synch_pos_with_cur(&localpos, save_posstruct, mat_p->pos);
+ }
+ pdf->posstruct = save_posstruct;
+ pdf->vfstruct = save_vfstruct;
+}
+
+int *packet_local_fonts(internal_font_number f, int *num)
+{
+ int c, cmd, lf, k, l, i;
+ int localfonts[256] = { 0 };
+ int *lfs;
+ charinfo *co;
+ eight_bits *vf_packets, *vfp;
+ k = 0;
+ for (c = font_bc(f); c <= font_ec(f); c++) {
+ if (quick_char_exists(f, c)) {
+ co = get_charinfo(f, c);
+ vfp = vf_packets = get_charinfo_packets(co);
+ if (vf_packets == NULL)
+ continue;
+ while ((cmd = *(vfp++)) != packet_end_code) {
+ switch (cmd) {
+ case packet_font_code:
+ packet_number(lf);
+ for (l = 0; l < k; l++) {
+ if (localfonts[l] == lf) {
+ break;
+ }
+ }
+ if (l == k) {
+ localfonts[k++] = lf;
+ }
+ break;
+ case packet_nop_code:
+ case packet_pop_code:
+ case packet_push_code:
+ break;
+ case packet_char_code:
+ case packet_down_code:
+ case packet_image_code:
+ case packet_node_code:
+ case packet_right_code:
+ vfp += 4;
+ break;
+ case packet_rule_code:
+ vfp += 8;
+ break;
+ case packet_special_code:
+ packet_number(i);
+ vfp += i;
+ break;
+ default:
+ normal_error("vf", "invalid DVI command (3)");
+ }
+ }
+ }
+ }
+ *num = k;
+ if (k > 0) {
+ lfs = xmalloc((unsigned) ((unsigned) k * sizeof(int)));
+ memcpy(lfs, localfonts, (size_t) ((unsigned) k * sizeof(int)));
+ return lfs;
+ }
+ return NULL;
+}
+
+void replace_packet_fonts(internal_font_number f, int *old_fontid, int *new_fontid, int count)
+{
+ int c, cmd, lf, k, l;
+ charinfo *co;
+ eight_bits *vf_packets, *vfp;
+ for (c = font_bc(f); c <= font_ec(f); c++) {
+ if (quick_char_exists(f, c)) {
+ co = get_charinfo(f, c);
+ vfp = vf_packets = get_charinfo_packets(co);
+ if (vf_packets == NULL)
+ continue;
+ while ((cmd = *(vfp++)) != packet_end_code) {
+ switch (cmd) {
+ case packet_font_code:
+ packet_number(lf);
+ for (l = 0; l < count; l++) {
+ if (old_fontid[l] == lf) {
+ break;
+ }
+ }
+ if (l < count) {
+ k = new_fontid[l];
+ *(vfp - 4) = (eight_bits)
+ ((k & 0xFF000000) >> 24);
+ *(vfp - 3) = (eight_bits)
+ ((k & 0x00FF0000) >> 16);
+ *(vfp - 2) = (eight_bits)
+ ((k & 0x0000FF00) >> 8);
+ *(vfp - 1) = (eight_bits) (k & 0x000000FF);
+ }
+ break;
+ case packet_nop_code:
+ case packet_pop_code:
+ case packet_push_code:
+ break;
+ case packet_char_code:
+ case packet_down_code:
+ case packet_image_code:
+ case packet_node_code:
+ case packet_right_code:
+ case packet_rule_code:
+ vfp += 8;
+ break;
+ case packet_pdf_mode:
+ vfp += 4;
+ break;
+ case packet_pdf_code:
+ vfp += 4;
+ /*tex Plus a string so we fall through. */
+ case packet_special_code:
+ packet_number(k);
+ vfp += k;
+ break;
+ default:
+ normal_error("vf", "invalid DVI command (4)");
+ }
+ }
+ }
+ }
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,424 +0,0 @@
-% vfpacket.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ Some macros for processing character packets.
- at c
-#define packet_number(fw) { \
- fw = *(vfp++); \
- fw = fw * 256 + *(vfp++); \
- fw = fw * 256 + *(vfp++); \
- fw = fw * 256 + *(vfp++); \
-}
-
-#define packet_scaled(a, fs) { \
- int fw; \
- fw = *(vfp++); \
- if (fw > 127) \
- fw = fw - 256; \
- fw = fw * 256 + *(vfp++); \
- fw = fw * 256 + *(vfp++); \
- fw = fw * 256 + *(vfp++); \
- a = store_scaled_f(fw, fs); \
-}
-
-@ @c
-vf_struct *new_vfstruct(void)
-{
- vf_struct *vp = (vf_struct *) xmalloc(sizeof(vf_struct));
- vp->packet_stack_level = vp->packet_stack_minlevel = 0;
- vp->packet_stack =
- (packet_stack_record *) xmalloc(packet_stack_size *
- sizeof(packet_stack_record));
- vp->lf = 0;
- vp->fs_f = 0;
- vp->packet_cur_s = 0;
- vp->refpos = NULL;
- vp->vflua = false;
- return vp;
-}
-
-@ Count the number of bytes in a command packet.
- at c
-int vf_packet_bytes(charinfo * co)
-{
- eight_bits *vf_packets, *vfp;
- unsigned k;
- int cmd;
-
- vfp = vf_packets = get_charinfo_packets(co);
- if (vf_packets == NULL) {
- return 0;
- }
- while ((cmd = *(vfp++)) != packet_end_code) {
- switch (cmd) {
- case packet_nop_code:
- case packet_pop_code:
- case packet_push_code:
- break;
- case packet_char_code:
- case packet_down_code:
- case packet_font_code:
- case packet_image_code:
- case packet_node_code:
- case packet_right_code:
- case packet_rule_code:
- vfp += 8;
- break;
- case packet_pdf_mode:
- vfp += 4;
- break;
- case packet_pdf_code:
- vfp += 4;
- /* plus a string so we fall through */
- case packet_special_code:
- packet_number(k); /* +4 */
- vfp += (int) k;
- break;
- default:
- normal_error("vf", "invalid DVI command (1)");
- }
- };
- return (vfp - vf_packets);
-}
-
-@ Typeset the \.{DVI} commands in the character packet
- for character |c| in current font |f|.
- at c
-const char *packet_command_names[] = {
- "char", "font", "pop", "push", "special", "image",
- "right", "down", "rule", "node", "nop", "end", "scale", "lua", "pdf", NULL
-};
-
-@ @c
-static float packet_float(eight_bits ** vfpp)
-{
- unsigned int i;
- union U {
- float a;
- eight_bits b[sizeof(float)];
- } u;
- eight_bits *vfp = *vfpp;
- for (i = 0; i < sizeof(float); i++)
- u.b[i] = *(vfp++);
- *vfpp = vfp;
- return u.a;
-}
-
-@ The |do_vf_packet| procedure is called in order to interpret the
- character packet for a virtual character. Such a packet may contain
- the instruction to typeset a character from the same or an other
- virtual font; in such cases |do_vf_packet| calls itself
- recursively. The recursion level, i.e., the number of times this has
- happened, is kept in the global variable |packet_cur_s| and should
- not exceed |packet_max_recursion|.
- at c
-void do_vf_packet(PDF pdf, internal_font_number vf_f, int c, int ex_glyph)
-{
- eight_bits *vfp;
- posstructure *save_posstruct, localpos;
- vf_struct *save_vfstruct, localvfstruct, *vp;
- int cmd, w, mode;
- unsigned k;
- scaledpos size;
- scaled i;
- str_number s;
- float f;
- packet_stack_record *mat_p;
-
- vfp = get_charinfo_packets(get_charinfo(vf_f, c));
- assert(vfp != NULL);
-
- save_posstruct = pdf->posstruct;
- pdf->posstruct = &localpos; /* use local structure for recursion */
- localpos.pos = save_posstruct->pos;
- localpos.dir = dir_TLT; /* invariably for vf */
-
- save_vfstruct = pdf->vfstruct;
- vp = pdf->vfstruct = &localvfstruct;
- localvfstruct = *save_vfstruct;
-
- vp->packet_stack_minlevel = ++(vp->packet_stack_level);
- vp->lf = 0;
- vp->fs_f = font_size(vf_f);
- vp->ex_glyph = ex_glyph;
- vp->packet_cur_s++;
- if (vp->packet_cur_s == packet_max_recursion)
- overflow("max level recursion of virtual fonts", packet_max_recursion);
- vp->refpos = save_posstruct;
- vp->vflua = false;
-
- mat_p = &(vp->packet_stack[vp->packet_stack_level]);
- mat_p->c0 = 1.0;
- mat_p->c1 = 0.0;
- mat_p->c2 = 0.0;
- mat_p->c3 = 1.0;
- mat_p->pos.h = 0;
- mat_p->pos.v = 0;
-
- while ((cmd = *(vfp++)) != packet_end_code) {
-#ifdef DEBUG
- if (cmd > packet_end_code) {
- fprintf(stdout, "do_vf_packet(%i,%i) command code = illegal \n",
- vf_f, c);
- } else {
- fprintf(stdout, "do_vf_packet(%i,%i) command code = %s\n", vf_f, c,
- packet_command_names[cmd]);
- }
-#endif
- switch (cmd) {
- case packet_font_code:
- packet_number(vp->lf);
- break;
- case packet_push_code:
- vp->packet_stack_level++;
- if (vp->packet_stack_level == packet_stack_size)
- normal_error("vf", "packet_stack_level overflow");
- vp->packet_stack[vp->packet_stack_level] = *mat_p;
- mat_p = &(vp->packet_stack[vp->packet_stack_level]);
- break;
- case packet_pop_code:
- if (vp->packet_stack_level == vp->packet_stack_minlevel)
- normal_error("vf", "packet_stack_level underflow");
- vp->packet_stack_level--;
- mat_p = &(vp->packet_stack[vp->packet_stack_level]);
- break;
- case packet_char_code:
- packet_number(k);
- /* we also check if c == k and font(c) == font)k) */
- if (!char_exists(vp->lf, (int) k)) {
- char_warning(vp->lf, (int) k);
- } else if (! ((c == k && vp->lf == vf_f)) && (has_packet(vp->lf, (int) k))) {
- do_vf_packet(pdf, vp->lf, (int) k, ex_glyph);
- } else {
- backend_out[glyph_node] (pdf, vp->lf, (int) k, ex_glyph);
- }
- w = char_width(vp->lf, (int) k);
- mat_p->pos.h += round_xn_over_d(w, 1000 + ex_glyph, 1000);
- break;
- case packet_rule_code:
- packet_scaled(size.v, vp->fs_f); /* height (where is depth?) */
- packet_scaled(size.h, vp->fs_f);
- if (size.h > 0 && size.v > 0)
- backend_out[rule_node](pdf, 0, size); /* the 0 is unused */
- mat_p->pos.h += size.h;
- break;
- case packet_right_code:
- packet_scaled(i, vp->fs_f);
- mat_p->pos.h += i;
- break;
- case packet_down_code:
- packet_scaled(i, vp->fs_f);
- mat_p->pos.v += i;
- break;
- case packet_pdf_code:
- packet_number(mode);
- packet_number(k);
- str_room(k);
- while (k > 0) {
- k--;
- append_char(*(vfp++));
- }
- s = make_string();
- pdf_literal(pdf, s, mode, false);
- flush_str(s);
- break;
- case packet_pdf_mode:
- packet_number(mode);
- pdf_literal_set_mode(pdf, mode);
- break;
- case packet_special_code:
- packet_number(k);
- str_room(k);
- while (k > 0) {
- k--;
- append_char(*(vfp++));
- }
- s = make_string();
- pdf_literal(pdf, s, scan_special, false);
- flush_str(s);
- break;
- case packet_lua_code:
- packet_number(k);
- vp->vflua = true;
- if (luaL_loadbuffer
- (Luas, (const char *) vfp, (size_t) k, "packet_lua_code")
- || lua_pcall(Luas, 0, LUA_MULTRET, 0))
- lua_error(Luas);
- vp->vflua = false;
- vfp += k;
- break;
- case packet_image_code:
- packet_number(k);
- vf_out_image(pdf, k);
- break;
- case packet_node_code:
- packet_number(k);
- hlist_out(pdf, (halfword) k, 0);
- break;
- case packet_nop_code:
- break;
- case packet_scale_code:
- f = packet_float(&vfp);
- mat_p->c0 = mat_p->c0 * f;
- mat_p->c3 = mat_p->c3 * f;
- /* pdf->pstruct->scale = f; *//* scale is still NOP */
- pdf->pstruct->need_tm = true;
- pdf->pstruct->need_tf = true;
- break;
- default:
- normal_error("vf", "invalid DVI command (2)");
- }
- synch_pos_with_cur(&localpos, save_posstruct, mat_p->pos); /* trivial case, always TLT */
- }
- pdf->posstruct = save_posstruct;
- pdf->vfstruct = save_vfstruct;
-}
-
-@ @c
-int *packet_local_fonts(internal_font_number f, int *num)
-{
- int c, cmd, lf, k, l, i;
- int localfonts[256] = { 0 };
- int *lfs;
- charinfo *co;
-
- eight_bits *vf_packets, *vfp;
- k = 0;
- for (c = font_bc(f); c <= font_ec(f); c++) {
- if (quick_char_exists(f, c)) {
- co = get_charinfo(f, c);
- vfp = vf_packets = get_charinfo_packets(co);
- if (vf_packets == NULL)
- continue;
- while ((cmd = *(vfp++)) != packet_end_code) {
- switch (cmd) {
- case packet_font_code:
- packet_number(lf);
- for (l = 0; l < k; l++) {
- if (localfonts[l] == lf) {
- break;
- }
- }
- if (l == k) {
- localfonts[k++] = lf;
- }
- break;
- case packet_nop_code:
- case packet_pop_code:
- case packet_push_code:
- break;
- case packet_char_code:
- case packet_down_code:
- case packet_image_code:
- case packet_node_code:
- case packet_right_code:
- vfp += 4;
- break;
- case packet_rule_code:
- vfp += 8;
- break;
- case packet_special_code:
- packet_number(i);
- vfp += i;
- break;
- default:
- normal_error("vf", "invalid DVI command (3)");
- }
- }
- }
- }
- *num = k;
- if (k > 0) {
- lfs = xmalloc((unsigned) ((unsigned) k * sizeof(int)));
- memcpy(lfs, localfonts, (size_t) ((unsigned) k * sizeof(int)));
- return lfs;
- }
- return NULL;
-}
-
-@ @c
-void
-replace_packet_fonts(internal_font_number f, int *old_fontid,
- int *new_fontid, int count)
-{
- int c, cmd, lf, k, l;
- charinfo *co;
- eight_bits *vf_packets, *vfp;
-
- for (c = font_bc(f); c <= font_ec(f); c++) {
- if (quick_char_exists(f, c)) {
- co = get_charinfo(f, c);
- vfp = vf_packets = get_charinfo_packets(co);
- if (vf_packets == NULL)
- continue;
- while ((cmd = *(vfp++)) != packet_end_code) {
- switch (cmd) {
- case packet_font_code:
- packet_number(lf);
- for (l = 0; l < count; l++) {
- if (old_fontid[l] == lf) {
- break;
- }
- }
- if (l < count) {
- k = new_fontid[l];
- *(vfp - 4) = (eight_bits)
- ((k & 0xFF000000) >> 24);
- *(vfp - 3) = (eight_bits)
- ((k & 0x00FF0000) >> 16);
- *(vfp - 2) = (eight_bits)
- ((k & 0x0000FF00) >> 8);
- *(vfp - 1) = (eight_bits) (k & 0x000000FF);
- }
- break;
- case packet_nop_code:
- case packet_pop_code:
- case packet_push_code:
- break;
- case packet_char_code:
- case packet_down_code:
- case packet_image_code:
- case packet_node_code:
- case packet_right_code:
- case packet_rule_code:
- vfp += 8;
- break;
- case packet_pdf_mode:
- vfp += 4;
- break;
- case packet_pdf_code:
- vfp += 4;
- /* plus a string so we fall through */
- case packet_special_code:
- packet_number(k);
- vfp += k;
- break;
- default:
- normal_error("vf", "invalid DVI command (4)");
- }
- }
- }
- }
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/writecff.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writecff.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writecff.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,3156 @@
+/*
+
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#include "font/writecff.h"
+
+extern int cidset;
+
+#define get_offset(s,n) get_unsigned(s, (n))
+#define get_card8(a) (card8)(a->stream[a->offset++])
+#define get_card16(a) (card16)(get_unsigned(a,2))
+#define get_card32(a) (get_unsigned(a,4))
+
+#undef b0
+#undef b1
+#undef b2
+#undef b3
+
+#define WORK_BUFFER_SIZE 1024
+
+static char work_buffer[WORK_BUFFER_SIZE];
+
+static unsigned long get_unsigned(cff_font * cff, int n)
+{
+ unsigned long v = 0;
+ while (n-- > 0)
+ v = v * 256 + get_card8(cff);
+ return v;
+}
+
+const char *const cff_stdstr[CFF_STDSTR_MAX] = {
+ ".notdef", "space", "exclam", "quotedbl", "numbersign",
+ "dollar", "percent", "ampersand", "quoteright", "parenleft",
+ "parenright", "asterisk", "plus", "comma", "hyphen",
+ "period", "slash", "zero", "one", "two",
+ "three", "four", "five", "six", "seven",
+ "eight", "nine", "colon", "semicolon", "less",
+ "equal", "greater", "question", "at", "A",
+ "B", "C", "D", "E", "F",
+ "G", "H", "I", "J", "K",
+ "L", "M", "N", "O", "P",
+ "Q", "R", "S", "T", "U",
+ "V", "W", "X", "Y", "Z",
+ "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
+ "quoteleft", "a", "b", "c", "d",
+ "e", "f", "g", "h", "i",
+ "j", "k", "l", "m", "n",
+ "o", "p", "q", "r", "s",
+ "t", "u", "v", "w", "x",
+ "y", "z", "braceleft", "bar", "braceright",
+ "asciitilde", "exclamdown", "cent", "sterling", "fraction",
+ "yen", "florin", "section", "currency", "quotesingle",
+ "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi",
+ "fl", "endash", "dagger", "daggerdbl", "periodcentered",
+ "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
+ "guillemotright", "ellipsis", "perthousand", "questiondown", "grave",
+ "acute", "circumflex", "tilde", "macron", "breve",
+ "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
+ "ogonek", "caron", "emdash", "AE", "ordfeminine",
+ "Lslash", "Oslash", "OE", "ordmasculine", "ae",
+ "dotlessi", "lslash", "oslash", "oe", "germandbls",
+ "onesuperior", "logicalnot", "mu", "trademark", "Eth",
+ "onehalf", "plusminus", "Thorn", "onequarter", "divide",
+ "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
+ "registered", "minus", "eth", "multiply", "threesuperior",
+ "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
+ "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
+ "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
+ "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis",
+ "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
+ "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
+ "aacute", "acircumflex", "adieresis", "agrave", "aring",
+ "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis",
+ "egrave", "iacute", "icircumflex", "idieresis", "igrave",
+ "ntilde", "oacute", "ocircumflex", "odieresis", "ograve",
+ "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
+ "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
+ "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior", "parenrightsuperior", "twodotenleader",
+ "onedotenleader", "zerooldstyle",
+ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
+ "bsuperior",
+ "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
+ "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
+ "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
+ "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
+ "Asmall",
+ "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
+ "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall",
+ "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
+ "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
+ "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall",
+ "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall",
+ "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
+ "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird",
+ "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
+ "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
+ "oneinferior",
+ "twoinferior", "threeinferior", "fourinferior", "fiveinferior",
+ "sixinferior",
+ "seveninferior", "eightinferior", "nineinferior", "centinferior",
+ "dollarinferior",
+ "periodinferior", "commainferior", "Agravesmall", "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
+ "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
+ "Odieresissmall",
+ "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall",
+ "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall",
+ "001.000", "001.001", "001.002", "001.003",
+ "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
+};
+
+/*tex Only read the header part and forget about the body */
+
+cff_index *cff_get_index_header(cff_font * cff)
+{
+ cff_index *idx;
+ card16 i, count;
+ idx = xcalloc(1, sizeof(cff_index));
+ if (cff->header_major == 2) {
+ idx->count = count = get_card32(cff);
+ } else {
+ idx->count = count = get_card16(cff);
+ }
+ if (count > 0) {
+ idx->offsize = get_card8(cff);
+ if (idx->offsize < 1 || idx->offsize > 4)
+ normal_error("cff","invalid offsize data (1)");
+ idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
+ for (i = 0; i <count + 1 ; i++) {
+ (idx->offset)[i] = get_offset(cff, idx->offsize);
+ if (i == USHRT_MAX)
+ break;
+ }
+ if (idx->offset[0] != 1)
+ normal_error("cff","invalid index data");
+ idx->data = NULL;
+ } else {
+ idx->offsize = 0;
+ idx->offset = NULL;
+ idx->data = NULL;
+ }
+ return idx;
+}
+
+cff_index *cff_get_index(cff_font * cff)
+{
+ cff_index *idx;
+ card16 i, count;
+ size_t length;
+ idx = xcalloc(1, sizeof(cff_index));
+ idx->count = count = get_card16(cff);
+ if (count > 0) {
+ idx->offsize = get_card8(cff);
+ if (idx->offsize < 1 || idx->offsize > 4)
+ normal_error("cff","invalid offsize data (2)");
+ idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
+ for (i = 0; i < count + 1; i++) {
+ idx->offset[i] = get_offset(cff, idx->offsize);
+ }
+ if (idx->offset[0] != 1)
+ normal_error("cff","invalid index offset data");
+ length = (size_t) (idx->offset[count] - idx->offset[0]);
+ idx->data = xmalloc((unsigned) length * sizeof(card8));
+ memcpy(idx->data, &cff->stream[cff->offset], length);
+ cff->offset += length;
+ } else {
+ idx->offsize = 0;
+ idx->offset = NULL;
+ idx->data = NULL;
+ }
+ return idx;
+}
+
+static cff_index *cff_empty_index(cff_font * cff)
+{
+ cff_index *idx;
+ idx = xcalloc(1, sizeof(cff_index));
+ idx->count = 0;
+ idx->offsize = 0;
+ idx->offset = NULL;
+ idx->data = NULL;
+ return idx;
+}
+
+static cff_index *cff_get_index2(cff_font * cff)
+{
+ /*tex We fake a dict array. */
+ cff_index *idx;
+ size_t length;
+ idx = xcalloc(1, sizeof(cff_index));
+ length = (size_t) cff->header_offsize;
+ idx->offsize = 2;
+ idx->count = 1;
+ idx->offset = xmalloc((unsigned) (((unsigned) 2) * sizeof(l_offset)));
+ idx->offset[0] = 1;
+ idx->offset[1] = length + 1;
+ idx->data = xmalloc((unsigned) length * sizeof(card8));
+ memcpy(idx->data, &cff->stream[cff->offset], length );
+ cff->offset += length ;
+ return idx;
+}
+
+long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
+{
+ long len = 0;
+ unsigned long datalen;
+ card16 i;
+ if (idx->count < 1) {
+ if (destlen < 2)
+ normal_error("cff","not enough space available");
+ memset(dest, 0, 2);
+ return 2;
+ }
+ len = cff_index_size(idx);
+ datalen = idx->offset[idx->count] - 1;
+ if (destlen < len)
+ normal_error("cff","not enough space available");
+ *(dest++) = (card8) ((idx->count >> 8) & 0xff);
+ *(dest++) = (card8) (idx->count & 0xff);
+ if (datalen < 0xffUL) {
+ idx->offsize = 1;
+ *(dest++) = 1;
+ for (i = 0; i <= idx->count; i++) {
+ *(dest++) = (card8) (idx->offset[i] & 0xff);
+ }
+ } else if (datalen < 0xffffUL) {
+ idx->offsize = 2;
+ *(dest++) = 2;
+ for (i = 0; i <= idx->count; i++) {
+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+ *(dest++) = (card8) (idx->offset[i] & 0xff);
+ }
+ } else if (datalen < 0xffffffUL) {
+ idx->offsize = 3;
+ *(dest++) = 3;
+ for (i = 0; i <= idx->count; i++) {
+ *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+ *(dest++) = (card8) (idx->offset[i] & 0xff);
+ }
+ } else {
+ idx->offsize = 4;
+ *(dest++) = 4;
+ for (i = 0; i <= idx->count; i++) {
+ *(dest++) = (card8) ((idx->offset[i] >> 24) & 0xff);
+ *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+ *(dest++) = (card8) (idx->offset[i] & 0xff);
+ }
+ }
+ memmove(dest, idx->data, idx->offset[idx->count] - 1);
+ return len;
+}
+
+long cff_index_size(cff_index * idx)
+{
+ if (idx->count > 0) {
+ l_offset datalen;
+ datalen = idx->offset[idx->count] - 1;
+ if (datalen < 0xffUL) {
+ idx->offsize = 1;
+ } else if (datalen < 0xffffUL) {
+ idx->offsize = 2;
+ } else if (datalen < 0xffffffUL) {
+ idx->offsize = 3;
+ } else {
+ idx->offsize = 4;
+ }
+ return (3 + (idx->offsize) * (idx->count + 1) + (long) datalen);
+ } else {
+ return 2;
+ }
+}
+
+cff_index *cff_new_index(card16 count)
+{
+ cff_index *idx;
+ idx = xcalloc(1, sizeof(cff_index));
+ idx->count = count;
+ idx->offsize = 0;
+ if (count > 0) {
+ idx->offset = xcalloc((unsigned) (count + 1), sizeof(l_offset));
+ (idx->offset)[0] = 1;
+ } else {
+ idx->offset = NULL;
+ }
+ idx->data = NULL;
+ return idx;
+}
+
+void cff_release_index(cff_index * idx)
+{
+ if (idx) {
+ xfree(idx->data);
+ xfree(idx->offset);
+ xfree(idx);
+ }
+}
+
+void cff_release_dict(cff_dict * dict)
+{
+ if (dict) {
+ if (dict->entries) {
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ xfree((dict->entries)[i].values);
+ }
+ xfree(dict->entries);
+ }
+ xfree(dict);
+ }
+}
+
+void cff_release_encoding(cff_encoding * encoding)
+{
+ if (encoding) {
+ switch (encoding->format & (~0x80)) {
+ case 0:
+ xfree(encoding->data.codes);
+ break;
+ case 1:
+ xfree(encoding->data.range1);
+ break;
+ default:
+ normal_error("cff","unknown encoding format");
+ }
+ if (encoding->format & 0x80)
+ xfree(encoding->supp);
+ xfree(encoding);
+ }
+}
+
+void cff_release_charsets(cff_charsets * charset)
+{
+ if (charset) {
+ switch (charset->format) {
+ case 0:
+ xfree(charset->data.glyphs);
+ break;
+ case 1:
+ xfree(charset->data.range1);
+ break;
+ case 2:
+ xfree(charset->data.range2);
+ break;
+ default:
+ break;
+ }
+ xfree(charset);
+ }
+}
+
+void cff_release_fdselect(cff_fdselect * fdselect)
+{
+ if (fdselect) {
+ if (fdselect->format == 0) {
+ xfree(fdselect->data.fds);
+ } else if (fdselect->format == 3) {
+ xfree(fdselect->data.ranges);
+ }
+ xfree(fdselect);
+ }
+}
+
+void cff_close(cff_font * cff)
+{
+ card16 i;
+ if (cff) {
+ xfree(cff->fontname);
+ if (cff->name)
+ cff_release_index(cff->name);
+ if (cff->topdict)
+ cff_release_dict(cff->topdict);
+ if (cff->string)
+ cff_release_index(cff->string);
+ if (cff->gsubr)
+ cff_release_index(cff->gsubr);
+ if (cff->encoding)
+ cff_release_encoding(cff->encoding);
+ if (cff->charsets)
+ cff_release_charsets(cff->charsets);
+ if (cff->fdselect)
+ cff_release_fdselect(cff->fdselect);
+ if (cff->cstrings)
+ cff_release_index(cff->cstrings);
+ if (cff->fdarray) {
+ for (i = 0; i < cff->num_fds; i++) {
+ if (cff->fdarray[i])
+ cff_release_dict(cff->fdarray[i]);
+ }
+ xfree(cff->fdarray);
+ }
+ if (cff->private) {
+ for (i = 0; i < cff->num_fds; i++) {
+ if (cff->private[i])
+ cff_release_dict(cff->private[i]);
+ }
+ xfree(cff->private);
+ }
+ if (cff->subrs) {
+ for (i = 0; i < cff->num_fds; i++) {
+ if (cff->subrs[i])
+ cff_release_index(cff->subrs[i]);
+ }
+ xfree(cff->subrs);
+ }
+ if (cff->_string)
+ cff_release_index(cff->_string);
+ xfree(cff);
+ }
+ return;
+}
+
+char *cff_get_name(cff_font * cff)
+{
+ char *fontname;
+ l_offset len;
+ cff_index *idx;
+ idx = cff->name;
+ len = idx->offset[cff->index + 1] - idx->offset[cff->index];
+ fontname = xmalloc((unsigned) (len + 1) * sizeof(char));
+ memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len);
+ fontname[len] = '\0';
+ return fontname;
+}
+
+long cff_set_name(cff_font * cff, char *name)
+{
+ cff_index *idx;
+ if (strlen(name) > 127)
+ normal_error("cff","FontName string length too large");
+ if (cff->name)
+ cff_release_index(cff->name);
+ cff->name = idx = xcalloc(1, sizeof(cff_index));
+ idx->count = 1;
+ idx->offsize = 1;
+ idx->offset = xmalloc(2 * sizeof(l_offset));
+ (idx->offset)[0] = 1;
+ (idx->offset)[1] = strlen(name) + 1;
+ idx->data = xmalloc((unsigned) strlen(name) * sizeof(card8));
+ /*tex No trailing |\0| */
+ memmove(idx->data, name, strlen(name));
+ return (long) (5 + strlen(name));
+}
+
+long cff_put_header(cff_font * cff, card8 * dest, long destlen)
+{
+ if (destlen < 4)
+ normal_error("cff","not enough space available");
+ /*tex cff->header_major */
+ *(dest++) = 1;
+ *(dest++) = cff->header_minor;
+ *(dest++) = 4;
+ /*tex
+ Additional data in between header and Name INDEX is ignored. We will set
+ all offset (0) to a four-byte integer.
+ */
+ *(dest++) = 4;
+ cff->header_offsize = 4;
+ return 4;
+}
+
+#define CFF_PARSE_OK 0
+#define CFF_CFF_ERROR_PARSE_CFF_ERROR -1
+#define CFF_CFF_ERROR_STACK_OVERFLOW -2
+#define CFF_CFF_ERROR_STACK_UNDERFLOW -3
+#define CFF_CFF_ERROR_STACK_RANGECHECK -4
+
+#define DICT_ENTRY_MAX 16
+
+cff_dict *cff_new_dict(void)
+{
+ cff_dict *dict;
+ dict = xcalloc(1, sizeof(cff_dict));
+ dict->max = DICT_ENTRY_MAX;
+ dict->count = 0;
+ dict->entries = xcalloc((unsigned) dict->max, sizeof(cff_dict_entry));
+ return dict;
+}
+
+/*tex
+
+ Operand stack: only numbers are stored (as double). Operand types are:
+
+ \startitemize
+ \startitem number: double (integer or real) \stopitem
+ \startitem boolean: stored as a number \stopitem
+ \startitem SID: stored as a number \stopitem
+ \startitem array: array of numbers \stopitem
+ \startitem delta: array of numbers \stopitem
+ \stopitemize
+
+*/
+
+#define CFF_DICT_STACK_LIMIT 64
+static int stack_top = 0;
+static double arg_stack[CFF_DICT_STACK_LIMIT];
+
+/* The CFF DICT encoding: */
+
+#define CFF_LAST_DICT_OP1 26
+#define CFF_LAST_DICT_OP2 39
+#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
+
+static struct {
+ const char *opname;
+ int argtype;
+} dict_operator[CFF_LAST_DICT_OP] = {
+ { "version", CFF_TYPE_SID },
+ { "Notice", CFF_TYPE_SID },
+ { "FullName", CFF_TYPE_SID },
+ { "FamilyName", CFF_TYPE_SID },
+ { "Weight", CFF_TYPE_SID },
+ { "FontBBox", CFF_TYPE_ARRAY },
+ { "BlueValues", CFF_TYPE_DELTA },
+ { "OtherBlues", CFF_TYPE_DELTA },
+ { "FamilyBlues", CFF_TYPE_DELTA },
+ { "FamilyOtherBlues", CFF_TYPE_DELTA },
+ { "StdHW", CFF_TYPE_NUMBER },
+ { "StdVW", CFF_TYPE_NUMBER },
+ { NULL, -1 },
+ { "UniqueID", CFF_TYPE_NUMBER },
+ { "XUID", CFF_TYPE_ARRAY },
+ { "charset", CFF_TYPE_OFFSET },
+ { "Encoding", CFF_TYPE_OFFSET },
+ { "CharStrings", CFF_TYPE_OFFSET },
+ { "Private", CFF_TYPE_SZOFF },
+ { "Subrs", CFF_TYPE_OFFSET },
+ { "defaultWidthX", CFF_TYPE_NUMBER },
+ { "nominalWidthX", CFF_TYPE_NUMBER },
+ { NULL, -1 },
+ { NULL, -1 },
+ /*tex two CFF2 instructions */
+ { "vstore", CFF_TYPE_OFFSET },
+ { "maxstack", CFF_TYPE_NUMBER },
+ /*tex Here we start with operator 2 of 12. */
+ { "Copyright", CFF_TYPE_SID },
+ { "IsFixedPitch", CFF_TYPE_BOOLEAN },
+ { "ItalicAngle", CFF_TYPE_NUMBER },
+ { "UnderlinePosition", CFF_TYPE_NUMBER },
+ { "UnderlineThickness", CFF_TYPE_NUMBER },
+ { "PaintType", CFF_TYPE_NUMBER },
+ { "CharstringType", CFF_TYPE_NUMBER },
+ { "FontMatrix", CFF_TYPE_ARRAY },
+ { "StrokeWidth", CFF_TYPE_NUMBER },
+ { "BlueScale", CFF_TYPE_NUMBER },
+ { "BlueShift", CFF_TYPE_NUMBER },
+ { "BlueFuzz", CFF_TYPE_NUMBER },
+ { "StemSnapH", CFF_TYPE_DELTA },
+ { "StemSnapV", CFF_TYPE_DELTA },
+ { "ForceBold", CFF_TYPE_BOOLEAN },
+ { NULL, -1 },
+ { NULL, -1 },
+ { "LanguageGroup", CFF_TYPE_NUMBER },
+ { "ExpansionFactor", CFF_TYPE_NUMBER },
+ { "InitialRandomSeed", CFF_TYPE_NUMBER },
+ { "SyntheticBase", CFF_TYPE_NUMBER },
+ { "PostScript", CFF_TYPE_SID },
+ { "BaseFontName", CFF_TYPE_SID },
+ { "BaseFontBlend", CFF_TYPE_DELTA },
+ { NULL, -1 },
+ { NULL, -1 },
+ { NULL, -1 },
+ { NULL, -1 },
+ { NULL, -1 },
+ { NULL, -1 },
+ { "ROS", CFF_TYPE_ROS },
+ { "CIDFontVersion", CFF_TYPE_NUMBER },
+ { "CIDFontRevision", CFF_TYPE_NUMBER },
+ { "CIDFontType", CFF_TYPE_NUMBER },
+ { "CIDCount", CFF_TYPE_NUMBER },
+ { "UIDBase", CFF_TYPE_NUMBER },
+ { "FDArray", CFF_TYPE_OFFSET },
+ { "FDSelect", CFF_TYPE_OFFSET },
+ { "FontName", CFF_TYPE_SID }
+};
+
+/*tex Parse DICT data */
+
+static double get_integer(card8 ** data, card8 * endptr, int *status)
+{
+ long result = 0;
+ card8 b0, b1, b2;
+
+ b0 = *(*data)++;
+ if (b0 == 28 && *data < endptr - 2) {
+ /*tex shortint */
+ b1 = *(*data)++;
+ b2 = *(*data)++;
+ result = b1 * 256 + b2;
+ if (result > 0x7fffL)
+ result -= 0x10000L;
+ } else if (b0 == 29 && *data < endptr - 4) {
+ /*tex longint */
+ int i;
+ result = *(*data)++;
+ if (result > 0x7f)
+ result -= 0x100;
+ for (i = 0; i < 3; i++) {
+ result = result * 256 + (**data);
+ *data += 1;
+ }
+ } else if (b0 >= 32 && b0 <= 246) {
+ /*tex int (1) */
+ result = b0 - 139;
+ } else if (b0 >= 247 && b0 <= 250) {
+ /*tex int (2) */
+ b1 = *(*data)++;
+ result = (b0 - 247) * 256 + b1 + 108;
+ } else if (b0 >= 251 && b0 <= 254) {
+ b1 = *(*data)++;
+ result = -(b0 - 251) * 256 - b1 - 108;
+ } else {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ }
+ return (double) result;
+}
+
+/*tex Simply uses |strtod|: */
+
+static double get_real(card8 ** data, card8 * endptr, int *status)
+{
+ double result = 0.0;
+ int nibble = 0, pos = 0;
+ int len = 0, fail = 0;
+
+ if (**data != 30 || *data >= endptr - 1) {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ return 0.0;
+ }
+ /*tex Skip the first byte (30): */
+ *data += 1;
+ pos = 0;
+ while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
+ /*tex Get a nibble. */
+ if (pos % 2) {
+ nibble = **data & 0x0f;
+ *data += 1;
+ } else {
+ nibble = (**data >> 4) & 0x0f;
+ }
+ if (nibble >= 0x00 && nibble <= 0x09) {
+ work_buffer[len++] = (char) (nibble + '0');
+ } else if (nibble == 0x0a) { /* . */
+ work_buffer[len++] = '.';
+ } else if (nibble == 0x0b || nibble == 0x0c) {
+ /*tex E, E- */
+ work_buffer[len++] = 'e';
+ if (nibble == 0x0c)
+ work_buffer[len++] = '-';
+ } else if (nibble == 0x0e) {
+ /*tex the minus */
+ work_buffer[len++] = '-';
+ } else if (nibble == 0x0d) {
+ /*tex do nothing */
+ } else if (nibble == 0x0f) {
+ /*tex we're done */
+ work_buffer[len++] = '\0';
+ if (((pos % 2) == 0) && (**data != 0xff)) {
+ fail = 1;
+ }
+ break;
+ } else {
+ /*tex invalid */
+ fail = 1;
+ }
+ pos++;
+ }
+ /*tex the returned values */
+ if (fail || nibble != 0x0f) {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ } else {
+ char *s;
+ errno=0;
+ result = strtod(work_buffer, &s);
+ if ((result==0.0 && work_buffer==s) || errno) {
+ /*tex Conversion is not possible. */
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ }
+ }
+ return result;
+}
+
+/*tex Operators */
+
+static void add_dict(cff_dict * dict, card8 ** data, card8 * endptr, int *status)
+{
+ int id, argtype, t;
+ id = **data;
+ if (id == 0x0c) {
+ *data += 1;
+ if (*data >= endptr ||
+ (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ return;
+ }
+ } else if (id >= CFF_LAST_DICT_OP1) {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ return;
+ }
+ argtype = dict_operator[id].argtype;
+ if (dict_operator[id].opname == NULL || argtype < 0) {
+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+ return;
+ }
+ if (dict->count >= dict->max) {
+ dict->max += DICT_ENTRY_MAX;
+ /*tex Not zeroed! */
+ dict->entries = xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry)));
+ }
+ (dict->entries)[dict->count].id = id;
+ (dict->entries)[dict->count].key = dict_operator[id].opname;
+ if (argtype == CFF_TYPE_NUMBER ||
+ argtype == CFF_TYPE_BOOLEAN ||
+ argtype == CFF_TYPE_SID || argtype == CFF_TYPE_OFFSET) {
+ /*tex Check for underflow here, as exactly one operand is expected. */
+ if (stack_top < 1) {
+ *status = CFF_CFF_ERROR_STACK_UNDERFLOW;
+ return;
+ }
+ stack_top--;
+ (dict->entries)[dict->count].count = 1;
+ (dict->entries)[dict->count].values = xcalloc(1, sizeof(double));
+ (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
+ dict->count += 1;
+ } else {
+ /*tex
+ Just ignore operator if there were no operands provided. Don't treat
+ this as underflow, e.g. |StemSnapV| in |TemporaLGCUni-Italic.otf|.
+ */
+ if ((t = stack_top) > 0) {
+ (dict->entries)[dict->count].count = stack_top;
+ (dict->entries)[dict->count].values =
+ xmalloc((unsigned) ((unsigned) stack_top * sizeof(double)));
+ while (stack_top > 0) {
+ stack_top--;
+ (dict->entries)[dict->count].values[stack_top] =
+ arg_stack[stack_top];
+ }
+ if (t > 3 && strcmp(dict_operator[id].opname, "FontMatrix") == 0) {
+ (dict->entries)[dict->count].values[0] = 0.001;
+ (dict->entries)[dict->count].values[3] = 0.001;
+ }
+ dict->count += 1;
+ }
+ }
+ *data += 1;
+ return;
+}
+
+/*tex
+
+ All operands are treated as number or array of numbers.
+
+ \startitemize
+ \startitem |Private|: two numbers, size and offset \stopitem
+ \startitem |ROS|: hree numbers, SID, SID, and a number \stopitem
+ \stopitemize
+
+*/
+
+cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
+{
+ cff_dict *dict;
+ int status = CFF_PARSE_OK;
+ stack_top = 0;
+ dict = cff_new_dict();
+ while (data < endptr && status == CFF_PARSE_OK) {
+ if (*data < CFF_LAST_DICT_OP1) {
+ /*tex Some operator. */
+ add_dict(dict, &data, endptr, &status);
+ } else if (*data == 30) {
+ /*tex First byte of a sequence (variable). */
+ if (stack_top < CFF_DICT_STACK_LIMIT) {
+ arg_stack[stack_top] = get_real(&data, endptr, &status);
+ stack_top++;
+ } else {
+ status = CFF_CFF_ERROR_STACK_OVERFLOW;
+ }
+ } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) {
+ /*tex Reserved. */
+ data++;
+ } else {
+ /*tex Everything else is an integer. */
+ if (stack_top < CFF_DICT_STACK_LIMIT) {
+ arg_stack[stack_top] = get_integer(&data, endptr, &status);
+ stack_top++;
+ } else {
+ status = CFF_CFF_ERROR_STACK_OVERFLOW;
+ }
+ }
+ }
+ if (status != CFF_PARSE_OK) {
+ formatted_error("cff","parsing DICT failed (error=%d)", status);
+ } else if (stack_top != 0) {
+ normal_warning("cff","garbage in DICT data");
+ stack_top = 0;
+ }
+ return dict;
+}
+
+int cff_dict_known(cff_dict * dict, const char *key)
+{
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if (key && strcmp(key, (dict->entries)[i].key) == 0
+ && (dict->entries)[i].count > 0)
+ return 1;
+ }
+ return 0;
+}
+
+double cff_dict_get(cff_dict * dict, const char *key, int idx)
+{
+ double value = 0.0;
+ int i;
+ assert(key && dict);
+ for (i = 0; i < dict->count; i++) {
+ if (strcmp(key, (dict->entries)[i].key) == 0) {
+ if ((dict->entries)[i].count > idx)
+ value = (dict->entries)[i].values[idx];
+ else
+ normal_error("cff","invalid index number");
+ break;
+ }
+ }
+ if (i == dict->count)
+ formatted_error("cff","DICT entry '%s' not found", key);
+ return value;
+}
+
+card8 cff_fdselect_lookup(cff_font * cff, card16 gid)
+{
+ card8 fd = 0xff;
+ cff_fdselect *fdsel;
+ if (cff->fdselect == NULL)
+ normal_error("cff","FDSelect not available");
+ fdsel = cff->fdselect;
+ if (gid >= cff->num_glyphs)
+ normal_error("cff","invalid glyph index");
+ switch (fdsel->format) {
+ case 0:
+ fd = fdsel->data.fds[gid];
+ break;
+ case 3:
+ {
+ if (gid == 0) {
+ fd = (fdsel->data).ranges[0].fd;
+ } else {
+ card16 i;
+ for (i = 1; i < (fdsel->num_entries); i++) {
+ if (gid < (fdsel->data).ranges[i].first)
+ break;
+ }
+ fd = (fdsel->data).ranges[i - 1].fd;
+ }
+ }
+ break;
+ default:
+ normal_error("cff","invalid FDSelect format");
+ break;
+ }
+ if (fd >= cff->num_fds)
+ normal_error("cff","invalid Font DICT index");
+ return fd;
+}
+
+long cff_read_subrs(cff_font * cff)
+{
+ long len = 0;
+ long offset;
+ int i;
+ if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdselect == NULL) {
+ cff_read_fdselect(cff);
+ }
+ if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) {
+ cff_read_fdarray(cff);
+ }
+ if (cff->private == NULL)
+ cff_read_private(cff);
+ if (cff->gsubr == NULL) {
+ cff->offset = cff->gsubr_offset;
+ cff->gsubr = cff_get_index(cff);
+ }
+ cff->subrs = xcalloc(cff->num_fds, sizeof(cff_index *));
+ if (cff->flag & FONTTYPE_CIDFONT) {
+ for (i = 0; i < cff->num_fds; i++) {
+ if (cff->private[i] == NULL ||
+ !cff_dict_known(cff->private[i], "Subrs")) {
+ (cff->subrs)[i] = NULL;
+ } else {
+ offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
+ offset += (long) cff_dict_get(cff->private[i], "Subrs", 0);
+ cff->offset = (l_offset) offset;
+ (cff->subrs)[i] = cff_get_index(cff);
+ len += cff_index_size((cff->subrs)[i]);
+ }
+ }
+ } else if (cff->private[0] == NULL || !cff_dict_known(cff->private[0], "Subrs")) {
+ (cff->subrs)[0] = NULL;
+ } else {
+ offset = (long) cff_dict_get(cff->topdict, "Private", 1);
+ offset += (long) cff_dict_get(cff->private[0], "Subrs", 0);
+ cff->offset = (l_offset) offset;
+ (cff->subrs)[0] = cff_get_index(cff);
+ len += cff_index_size((cff->subrs)[0]);
+ }
+ return len;
+}
+
+long cff_read_fdarray(cff_font * cff)
+{
+ long len = 0;
+ cff_index *idx;
+ long offset, size;
+ card16 i;
+ if (cff->topdict == NULL)
+ normal_error("cff","top DICT not found");
+ if (!(cff->flag & FONTTYPE_CIDFONT))
+ return 0;
+ offset = (long) cff_dict_get(cff->topdict, "FDArray", 0);
+ cff->offset = (l_offset) offset;
+ idx = cff_get_index(cff);
+ cff->num_fds = (card8) idx->count;
+ cff->fdarray = xmalloc((unsigned) (idx->count * sizeof(cff_dict *)));
+ for (i = 0; i < idx->count; i++) {
+ card8 *data = idx->data + (idx->offset)[i] - 1;
+ size = (long) ((idx->offset)[i + 1] - (idx->offset)[i]);
+ if (size > 0) {
+ (cff->fdarray)[i] = cff_dict_unpack(data, data + size);
+ } else {
+ (cff->fdarray)[i] = NULL;
+ }
+ }
+ len = cff_index_size(idx);
+ cff_release_index(idx);
+ return len;
+}
+
+long cff_read_private(cff_font * cff)
+{
+ long len = 0;
+ card8 *data;
+ long offset, size;
+ if (cff->flag & FONTTYPE_CIDFONT) {
+ int i;
+ if (cff->fdarray == NULL)
+ cff_read_fdarray(cff);
+ cff->private = xmalloc((unsigned) (cff->num_fds * sizeof(cff_dict *)));
+ for (i = 0; i < cff->num_fds; i++) {
+ if (cff->fdarray[i] != NULL &&
+ cff_dict_known(cff->fdarray[i], "Private") &&
+ (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0)) > 0) {
+ offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
+ cff->offset = (l_offset) offset;
+ data = xmalloc((unsigned) size * sizeof(card8));
+ memcpy(data, &cff->stream[cff->offset], (size_t) size);
+ cff->offset = (l_offset) size;
+ (cff->private)[i] = cff_dict_unpack(data, data + size);
+ xfree(data);
+ len += size;
+ } else {
+ (cff->private)[i] = NULL;
+ }
+ }
+ } else {
+ cff->num_fds = 1;
+ cff->private = xmalloc(sizeof(cff_dict *));
+ if (cff_dict_known(cff->topdict, "Private") &&
+ (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) {
+ offset = (long) cff_dict_get(cff->topdict, "Private", 1);
+ cff->offset = (l_offset) offset;
+ data = xmalloc((unsigned) size * sizeof(card8));
+ memcpy(data, &cff->stream[cff->offset], (size_t) size);
+ cff->offset = (l_offset) size;
+ cff->private[0] = cff_dict_unpack(data, data + size);
+ xfree(data);
+ len += size;
+ } else {
+ (cff->private)[0] = NULL;
+ len = 0;
+ }
+ }
+ return len;
+}
+
+cff_font *read_cff(unsigned char *buf, long buflength, int n)
+{
+ cff_font *cff;
+ cff_index *idx;
+ long offset;
+ cff = xcalloc(1, sizeof(cff_font));
+ cff->stream = buf;
+ cff->stream_size = (l_offset) buflength;
+ cff->index = n;
+ cff->header_major = get_card8(cff);
+ cff->header_minor = get_card8(cff);
+ cff->header_hdr_size = get_card8(cff);
+ if (cff->header_major == 2) {
+ /*tex We have only one top dictionary. */
+ cff->header_offsize = get_card16(cff);
+ } else {
+ cff->header_offsize = get_card8(cff);
+ if (cff->header_offsize < 1 || cff->header_offsize > 4) {
+ normal_warning("cff","invalid offsize data (4)");
+ cff_close(cff);
+ return NULL;
+ }
+ }
+ if (cff->header_major > 2) {
+ formatted_warning("cff","major version %u not supported", cff->header_major);
+ cff_close(cff);
+ return NULL;
+ }
+ cff->offset = cff->header_hdr_size;
+ /*tex The name index. */
+ if (cff->header_major == 2) {
+ cff->name = cff_empty_index(cff);
+ } else {
+ idx = cff_get_index(cff);
+ if (n > idx->count - 1) {
+ normal_warning("cff","invalid fontset index number");
+ cff_close(cff);
+ return NULL;
+ }
+ cff->name = idx;
+ cff->fontname = cff_get_name(cff);
+ }
+ /*tex The top dict index. */
+ if (cff->header_major == 2) {
+ /*tex we fake an index (just one entry) */
+ idx = cff_get_index2(cff);
+ } else {
+ idx = cff_get_index(cff);
+ }
+ if (n > idx->count - 1) {
+ normal_warning("cff","top DICT not exist");
+ cff_close(cff);
+ return NULL;
+ }
+ cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1, idx->data + idx->offset[n + 1] - 1);
+ if (!cff->topdict) {
+ normal_warning("cff","parsing top DICT data failed");
+ cff_close(cff);
+ return NULL;
+ }
+ cff_release_index(idx);
+ if (cff_dict_known(cff->topdict, "CharstringType") &&
+ cff_dict_get(cff->topdict, "CharstringType", 0) != 2) {
+ normal_warning("cff","only type 2 charstrings supported");
+ cff_close(cff);
+ return NULL;
+ }
+ if (cff_dict_known(cff->topdict, "SyntheticBase")) {
+ normal_warning("cff","synthetic font not supported");
+ cff_close(cff);
+ return NULL;
+ }
+ /*tex The string index. */
+ if (cff->header_major == 2) {
+ /*tex do nothing */
+ } else {
+ cff->string = cff_get_index(cff);
+ }
+ /*tex The offset to subroutines. */
+ cff->gsubr_offset = cff->offset;
+ /*tex The number of glyphs. */
+ offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0);
+ cff->offset = (l_offset) offset;
+ cff->num_glyphs = get_card16(cff);
+ /*tex Check for font type. */
+ if (cff_dict_known(cff->topdict, "ROS")) {
+ cff->flag |= FONTTYPE_CIDFONT;
+ } else {
+ cff->flag |= FONTTYPE_FONT;
+ }
+ /*tex Check for the encoding. */
+ if (cff_dict_known(cff->topdict, "Encoding")) {
+ offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
+ if (offset == 0) { /* predefined */
+ cff->flag |= ENCODING_STANDARD;
+ } else if (offset == 1) {
+ cff->flag |= ENCODING_EXPERT;
+ }
+ } else {
+ cff->flag |= ENCODING_STANDARD;
+ }
+ cff->offset = cff->gsubr_offset;
+ return cff;
+}
+
+/*tex Write CFF data for an \OPENTYPE\ font. We need to pack dictionary data. */
+
+static long pack_integer(card8 * dest, long destlen, long value)
+{
+ long len = 0;
+ if (value >= -107 && value <= 107) {
+ if (destlen < 1)
+ normal_error("cff","buffer overflow (1)");
+ dest[0] = (card8) ((value + 139) & 0xff);
+ len = 1;
+ } else if (value >= 108 && value <= 1131) {
+ if (destlen < 2)
+ normal_error("cff","buffer overflow (2)");
+ value = (long) 0xf700u + value - 108;
+ dest[0] = (card8) ((value >> 8) & 0xff);
+ dest[1] = (card8) (value & 0xff);
+ len = 2;
+ } else if (value >= -1131 && value <= -108) {
+ if (destlen < 2)
+ normal_error("cff","buffer overflow (3)");
+ value = (long) 0xfb00u - value - 108;
+ dest[0] = (card8) ((value >> 8) & 0xff);
+ dest[1] = (card8) (value & 0xff);
+ len = 2;
+ } else if (value >= -32768 && value <= 32767) {
+ /*tex shortint */
+ if (destlen < 3)
+ normal_error("cff","buffer overflow (4)");
+ dest[0] = 28;
+ dest[1] = (card8) ((value >> 8) & 0xff);
+ dest[2] = (card8) (value & 0xff);
+ len = 3;
+ } else {
+ /*tex longint */
+ if (destlen < 5)
+ normal_error("cff","buffer overflow (5)");
+ dest[0] = 29;
+ dest[1] = (card8) ((value >> 24) & 0xff);
+ dest[2] = (card8) ((value >> 16) & 0xff);
+ dest[3] = (card8) ((value >> 8) & 0xff);
+ dest[4] = (card8) (value & 0xff);
+ len = 5;
+ }
+ return len;
+}
+
+static long pack_real(card8 * dest, long destlen, double value)
+{
+ long e;
+ int i = 0, pos = 2;
+ int res;
+#define CFF_REAL_MAX_LEN 17
+ if (destlen < 2)
+ normal_error("cff","buffer overflow (6)");
+ dest[0] = 30;
+ if (value == 0.0) {
+ dest[1] = 0x0f;
+ return 2;
+ }
+ if (value < 0.0) {
+ dest[1] = 0xe0;
+ value *= -1.0;
+ pos++;
+ }
+ e = 0;
+ if (value >= 10.0) {
+ while (value >= 10.0) {
+ value /= 10.0;
+ e++;
+ }
+ } else if (value < 1.0) {
+ while (value < 1.0) {
+ value *= 10.0;
+ e--;
+ }
+ }
+ res = sprintf(work_buffer, "%1.14g", value);
+ if (res<0)
+ normal_error("cff","invalid conversion");
+ if (res>CFF_REAL_MAX_LEN)
+ res=CFF_REAL_MAX_LEN;
+ for (i = 0; i < res; i++) {
+ unsigned char ch = 0;
+ if (work_buffer[i] == '\0') {
+ /*tex In fact |res| should prevent this. */
+ break;
+ } else if (work_buffer[i] == '.') {
+ ch = 0x0a;
+ } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
+ ch = (unsigned char) (work_buffer[i] - '0');
+ } else {
+ normal_error("cff","invalid character");
+ }
+ if (destlen < pos / 2 + 1)
+ normal_error("cff","buffer overflow (7)");
+
+ if (pos % 2) {
+ dest[pos / 2] = (card8) (dest[pos / 2] + ch);
+ } else {
+ dest[pos / 2] = (card8) (ch << 4);
+ }
+ pos++;
+ }
+ if (e > 0) {
+ if (pos % 2) {
+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b);
+ } else {
+ if (destlen < pos / 2 + 1)
+ normal_error("cff","buffer overflow (8)");
+ dest[pos / 2] = (card8) (0xb0);
+ }
+ pos++;
+ } else if (e < 0) {
+ if (pos % 2) {
+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0c);
+ } else {
+ if (destlen < pos / 2 + 1)
+ normal_error("cff","buffer overflow (9)");
+ dest[pos / 2] = (card8) (0xc0);
+ }
+ e *= -1;
+ pos++;
+ }
+ if (e != 0) {
+ sprintf(work_buffer, "%ld", e);
+ for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
+ unsigned char ch = 0;
+ if (work_buffer[i] == '\0') {
+ break;
+ } else if (work_buffer[i] == '.') {
+ ch = 0x0a;
+ } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
+ ch = (unsigned char) (work_buffer[i] - '0');
+ } else {
+ normal_error("cff","invalid character");
+ }
+ if (destlen < pos / 2 + 1)
+ normal_error("cff","buffer overflow (10)");
+ if (pos % 2) {
+ dest[pos / 2] = (card8) (dest[pos / 2] + ch);
+ } else {
+ dest[pos / 2] = (card8) (ch << 4);
+ }
+ pos++;
+ }
+ }
+ if (pos % 2) {
+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f);
+ pos++;
+ } else {
+ if (destlen < pos / 2 + 1)
+ normal_error("cff","buffer overflow (11)");
+ dest[pos / 2] = (card8) (0xff);
+ pos += 2;
+ }
+ return pos / 2;
+}
+
+static long cff_dict_put_number(double value, card8 * dest, long destlen, int type)
+{
+ long len = 0;
+ double nearint;
+ nearint = floor(value + 0.5);
+ if (type == CFF_TYPE_OFFSET) {
+ long lvalue;
+ lvalue = (long) value;
+ if (destlen < 5)
+ normal_error("cff","buffer overflow (12)");
+ dest[0] = 29;
+ dest[1] = (card8) ((lvalue >> 24) & 0xff);
+ dest[2] = (card8) ((lvalue >> 16) & 0xff);
+ dest[3] = (card8) ((lvalue >> 8) & 0xff);
+ dest[4] = (card8) (lvalue & 0xff);
+ len = 5;
+ } else if (value > CFF_INT_MAX || value < CFF_INT_MIN || (fabs(value - nearint) > 1.0e-5)) {
+ /*tex A real */
+ len = pack_real(dest, destlen, value);
+ } else {
+ /*tex An integer */
+ len = pack_integer(dest, destlen, (long) nearint);
+ }
+ return len;
+}
+
+static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen)
+{
+ long len = 0;
+ int i, type, id;
+ if (de->count > 0) {
+ id = de->id;
+ if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
+ dict_operator[id].argtype == CFF_TYPE_SZOFF) {
+ type = CFF_TYPE_OFFSET;
+ } else {
+ type = CFF_TYPE_NUMBER;
+ }
+ for (i = 0; i < de->count; i++) {
+ len += cff_dict_put_number(de->values[i], dest + len, destlen - len, type);
+ }
+ if (id >= 0 && id < CFF_LAST_DICT_OP1) {
+ if (len + 1 > destlen)
+ normal_error("cff","buffer overflow (13)");
+ dest[len++] = (card8) id;
+ } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
+ if (len + 2 > destlen)
+ normal_error("cff","buffer overflow (14)");
+ dest[len++] = 12;
+ dest[len++] = (card8) (id - CFF_LAST_DICT_OP1);
+ } else {
+ normal_error("cff","invalid DICT operator ID");
+ }
+ }
+ return len;
+}
+
+long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen)
+{
+ long len = 0;
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if (!strcmp(dict->entries[i].key, "ROS")) {
+ len += put_dict_entry(&dict->entries[i], dest, destlen);
+ break;
+ }
+ }
+ for (i = 0; i < dict->count; i++) {
+ if (strcmp(dict->entries[i].key, "ROS")) {
+ len += put_dict_entry(&dict->entries[i], dest + len, destlen - len);
+ }
+ }
+ return len;
+}
+
+void cff_dict_add(cff_dict * dict, const char *key, int count)
+{
+ int id, i;
+ for (id = 0; id < CFF_LAST_DICT_OP; id++) {
+ if (key && dict_operator[id].opname &&
+ strcmp(dict_operator[id].opname, key) == 0)
+ break;
+ }
+ if (id == CFF_LAST_DICT_OP)
+ normal_error("cff","unknown DICT operator");
+ for (i = 0; i < dict->count; i++) {
+ if ((dict->entries)[i].id == id) {
+ if ((dict->entries)[i].count != count)
+ normal_error("cff","inconsistent DICT argument number");
+ return;
+ }
+ }
+ if (dict->count + 1 >= dict->max) {
+ dict->max += 8;
+ dict->entries =
+ xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry)));
+ }
+ (dict->entries)[dict->count].id = id;
+ (dict->entries)[dict->count].key = dict_operator[id].opname;
+ (dict->entries)[dict->count].count = count;
+ if (count > 0) {
+ (dict->entries)[dict->count].values = xcalloc((unsigned) count, sizeof(double));
+ } else {
+ (dict->entries)[dict->count].values = NULL;
+ }
+ dict->count += 1;
+ return;
+}
+
+void cff_dict_remove(cff_dict * dict, const char *key)
+{
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if (key && strcmp(key, (dict->entries)[i].key) == 0) {
+ (dict->entries)[i].count = 0;
+ xfree((dict->entries)[i].values);
+ }
+ }
+}
+
+void cff_dict_set(cff_dict * dict, const char *key, int idx, double value)
+{
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if (strcmp(key, (dict->entries)[i].key) == 0) {
+ if ((dict->entries)[i].count > idx)
+ (dict->entries)[i].values[idx] = value;
+ else
+ normal_error("cff","invalid index number");
+ break;
+ }
+ }
+ if (i == dict->count)
+ formatted_error("cff","DICT entry '%s' not found", key);
+}
+
+
+/*tex Strings */
+
+char *cff_get_string(cff_font * cff, s_SID id)
+{
+ char *result = NULL;
+ size_t len;
+ if (id < CFF_STDSTR_MAX) {
+ len = strlen(cff_stdstr[id]);
+ result = xmalloc((unsigned) (len + 1) * sizeof(char));
+ memcpy(result, cff_stdstr[id], len);
+ result[len] = '\0';
+ } else if (cff && cff->string) {
+ cff_index *strings = cff->string;
+ id = (s_SID) (id - CFF_STDSTR_MAX);
+ if (id < strings->count) {
+ len = (strings->offset)[id + 1] - (strings->offset)[id];
+ result = xmalloc((unsigned) (len + 1) * sizeof(char));
+ memmove(result, strings->data + (strings->offset)[id] - 1, len);
+ result[len] = '\0';
+ }
+ }
+ return result;
+}
+
+long cff_get_sid(cff_font * cff, const char *str)
+{
+ card16 i;
+ if (!cff || !str)
+ return -1;
+ /*tex We search the string index first. */
+ if (cff && cff->string) {
+ cff_index *idx = cff->string;
+ for (i = 0; i < idx->count; i++) {
+ if (strlen(str) == (idx->offset)[i + 1] - (idx->offset)[i] &&
+ !memcmp(str, (idx->data) + (idx->offset)[i] - 1, strlen(str)))
+ return (i + CFF_STDSTR_MAX);
+ }
+ }
+ for (i = 0; i < CFF_STDSTR_MAX; i++) {
+ if (!strcmp(str, cff_stdstr[i]))
+ return i;
+ }
+ return -1;
+}
+
+void cff_update_string(cff_font * cff)
+{
+ if (cff == NULL)
+ normal_error("cff","CFF font not opened");
+ if (cff->string)
+ cff_release_index(cff->string);
+ cff->string = cff->_string;
+ cff->_string = NULL;
+}
+
+s_SID cff_add_string(cff_font * cff, const char *str)
+{
+ card16 idx;
+ cff_index *strings;
+ l_offset offset, size;
+ if (cff == NULL) {
+ normal_error("cff","CFF font not opened");
+ }
+ if (cff->_string == NULL) {
+ cff->_string = cff_new_index(0);
+ }
+ strings = cff->_string;
+ for (idx = 0; idx < strings->count; idx++) {
+ size = strings->offset[idx + 1] - strings->offset[idx];
+ offset = strings->offset[idx];
+ if (size == strlen(str) && !memcmp(strings->data + offset - 1, str, strlen(str))) {
+ return (s_SID) (idx + CFF_STDSTR_MAX);
+ }
+ }
+ for (idx = 0; idx < CFF_STDSTR_MAX; idx++) {
+ if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str)) {
+ return idx;
+ }
+ }
+ offset = (strings->count > 0) ? strings->offset[strings->count] : 1;
+ strings->offset = xrealloc(strings->offset, (unsigned) (((unsigned) strings->count + 2) * sizeof(l_offset)));
+ if (strings->count == 0)
+ strings->offset[0] = 1;
+ idx = strings->count;
+ strings->count = (card16) (strings->count + 1);
+ strings->offset[strings->count] = offset + strlen(str);
+ strings->data = xrealloc(strings->data, (unsigned) ((offset + strlen(str) - 1) * sizeof(card8)));
+ memcpy(strings->data + offset - 1, str, strlen(str));
+ return (s_SID) (idx + CFF_STDSTR_MAX);
+}
+
+void cff_dict_update(cff_dict * dict, cff_font * cff)
+{
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if ((dict->entries)[i].count > 0) {
+ char *str;
+ int id;
+ id = (dict->entries)[i].id;
+ if (dict_operator[id].argtype == CFF_TYPE_SID) {
+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
+ if (str != NULL) {
+ (dict->entries)[i].values[0] = cff_add_string(cff, str);
+ xfree(str);
+ }
+ } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
+ if (str != NULL) {
+ (dict->entries)[i].values[0] = cff_add_string(cff, str);
+ xfree(str);
+ }
+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[1]);
+ if (str != NULL) {
+ (dict->entries)[i].values[1] = cff_add_string(cff, str);
+ xfree(str);
+ }
+ }
+ }
+ }
+}
+
+/*tex The charsets. */
+
+long cff_read_charsets(cff_font * cff)
+{
+ cff_charsets *charset;
+ long offset, length;
+ card16 count, i;
+ if (cff->topdict == NULL)
+ normal_error("cff","top DICT not available");
+ if (!cff_dict_known(cff->topdict, "charset")) {
+ cff->flag |= CHARSETS_ISOADOBE;
+ cff->charsets = NULL;
+ return 0;
+ }
+ offset = (long) cff_dict_get(cff->topdict, "charset", 0);
+ if (offset == 0) {
+ /*tex predefined */
+ cff->flag |= CHARSETS_ISOADOBE;
+ cff->charsets = NULL;
+ return 0;
+ } else if (offset == 1) {
+ cff->flag |= CHARSETS_EXPERT;
+ cff->charsets = NULL;
+ return 0;
+ } else if (offset == 2) {
+ cff->flag |= CHARSETS_EXPSUB;
+ cff->charsets = NULL;
+ return 0;
+ }
+ cff->offset = (l_offset) offset;
+ cff->charsets = charset = xcalloc(1, sizeof(cff_charsets));
+ charset->format = get_card8(cff);
+ charset->num_entries = 0;
+ count = (card16) (cff->num_glyphs - 1);
+ length = 1;
+ /*tex Not well documented. */
+ switch (charset->format) {
+ case 0:
+ charset->num_entries = (card16) (cff->num_glyphs - 1); /* no .notdef */
+ charset->data.glyphs =
+ xmalloc((unsigned) (charset->num_entries * sizeof(s_SID)));
+ length += (charset->num_entries) * 2;
+ for (i = 0; i < (charset->num_entries); i++) {
+ charset->data.glyphs[i] = get_card16(cff);
+ }
+ count = 0;
+ break;
+ case 1:
+ {
+ cff_range1 *ranges = NULL;
+ while (count > 0 && charset->num_entries < cff->num_glyphs) {
+ ranges =
+ xrealloc(ranges,
+ (unsigned) (((unsigned) charset->num_entries +
+ 1) * sizeof(cff_range1)));
+ ranges[charset->num_entries].first = get_card16(cff);
+ ranges[charset->num_entries].n_left = get_card8(cff);
+ count = (card16) (count - ranges[charset->num_entries].n_left + 1); /* no-overrap */
+ charset->num_entries++;
+ charset->data.range1 = ranges;
+ }
+ length += (charset->num_entries) * 3;
+ }
+ break;
+ case 2:
+ {
+ cff_range2 *ranges = NULL;
+ while (count > 0 && charset->num_entries < cff->num_glyphs) {
+ ranges =
+ xrealloc(ranges,
+ (unsigned) (((unsigned) charset->num_entries +
+ 1) * sizeof(cff_range2)));
+ ranges[charset->num_entries].first = get_card16(cff);
+ ranges[charset->num_entries].n_left = get_card16(cff);
+ count = (card16) (count - (ranges[charset->num_entries].n_left + 1)); /* non-overrapping */
+ charset->num_entries++;
+ }
+ charset->data.range2 = ranges;
+ length += (charset->num_entries) * 4;
+ }
+ break;
+ default:
+ xfree(charset);
+ normal_error("cff","unknown charset format");
+ break;
+ }
+ if (count > 0) {
+ normal_warning("cff","charset data possibly broken (too many glyphs)");
+ }
+ return length;
+}
+
+long cff_pack_charsets(cff_font * cff, card8 * dest, long destlen)
+{
+ long len = 0;
+ card16 i;
+ cff_charsets *charset;
+ if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL)
+ return 0;
+ if (destlen < 1)
+ normal_error("cff","buffer overflow (15)");
+ charset = cff->charsets;
+ dest[len++] = charset->format;
+ switch (charset->format) {
+ case 0:
+ if (destlen < len + (charset->num_entries) * 2)
+ normal_error("cff","buffer overflow (16)");
+ for (i = 0; i < (charset->num_entries); i++) {
+ s_SID sid = (charset->data).glyphs[i]; /* or CID */
+ dest[len++] = (card8) ((sid >> 8) & 0xff);
+ dest[len++] = (card8) (sid & 0xff);
+ }
+ break;
+ case 1:
+ {
+ if (destlen < len + (charset->num_entries) * 3)
+ normal_error("cff","buffer overflow (17)");
+ for (i = 0; i < (charset->num_entries); i++) {
+ dest[len++] = (card8) (((charset->data).range1[i].first >> 8) & 0xff);
+ dest[len++] = (card8) ((charset->data).range1[i].first & 0xff);
+ dest[len++] = (card8) ((charset->data).range1[i].n_left);
+ }
+ }
+ break;
+ case 2:
+ {
+ if (destlen < len + (charset->num_entries) * 4)
+ normal_error("cff","buffer overflow (18)");
+ for (i = 0; i < (charset->num_entries); i++) {
+ dest[len++] = (card8) (((charset->data).range2[i].first >> 8) & 0xff);
+ dest[len++] = (card8) ((charset->data).range2[i].first & 0xff);
+ dest[len++] = (card8) (((charset->data).range2[i].n_left >> 8) & 0xff);
+ dest[len++] = (card8) ((charset->data).range2[i].n_left & 0xff);
+ }
+ }
+ break;
+ default:
+ normal_error("cff","unknown charset format");
+ break;
+ }
+ return len;
+}
+
+/*tex
+
+ Here we decode and encode Type 2 charstring. All local/global subroutine
+ calls in a given charstring is replace by the content of subroutine
+ charstrings. We do this because some PostScript RIP may have problems with
+ sparse subroutine array. Workaround for this is to re-order subroutine array
+ so that no gap appears in the subroutine array, or put dummy charstrings that
+ contains only `return' in the gap. However, re-ordering of subroutine is
+ rather difficult for Type 2 charstrings due to the bias which depends on the
+ total number of subroutines. Replacing callgsubr/callsubr calls with the
+ content of the corresponding subroutine charstring may be more efficient than
+ putting dummy subroutines in the case of subsetted font. Adobe distiller
+ seems doing same thing.
+
+ And also note that subroutine numbers within subroutines can depend on the
+ content of operand stack as follows:
+
+ \startyping
+ \.{ ... l m callsubr << subr \#(m+bias): n add callsubr >> ...}
+ \stoptyping
+
+ I've not implemented the `random' operator which generates a pseudo-random
+ number in the range (0, 1] and push them into argument stack. How
+ pseudo-random sequences are generated is not documented in the Type 2
+ charstring spec.
+
+*/
+
+#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser"
+#define CS_TYPE2_DEBUG 5
+
+#define CS_BUFFER_CFF_ERROR -3
+#define CS_STACK_CFF_ERROR -2
+#define CS_PARSE_CFF_ERROR -1
+#define CS_PARSE_OK 0
+#define CS_PARSE_END 1
+#define CS_SUBR_RETURN 2
+#define CS_CHAR_END 3
+
+static int status = CS_PARSE_CFF_ERROR;
+
+#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_CFF_ERROR ; return ; }}
+#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_CFF_ERROR ; return ; }}
+#define NEED(a,b) {if ((a) < (b)) { status = CS_STACK_CFF_ERROR ; return ; }}
+
+/*tex The hintmask and cntrmask need the number of stem zones. */
+
+static int num_stems = 0;
+static int phase = 0;
+
+/*tex Subroutine nesting.
+*/
+static int cs2_nest = 0;
+
+/*tex The advance width. */
+
+static int have_width = 0;
+static double width = 0.0;
+
+/*tex
+
+ Standard Encoding Accented Characters: Optional four arguments for endchar.
+ See, CFF spec., p.35. This is obsolete feature and is no longer supported.
+
+ \starttyping
+ static double seac[4] = { 0.0, 0.0, 0.0, 0.0 }; // gone
+ \stoptyping
+
+*/
+
+/*tex Operand stack and Transient array */
+
+static int cs2_stack_top = 0;
+static double cs2_arg_stack[CS_ARG_STACK_MAX];
+static double trn_array[CS_TRANS_ARRAY_MAX];
+
+/*tex
+
+ Type 2 CharString encoding, first the 1 byte operators:
+
+*/
+
+/* RESERVED 0 */
+#define cs_hstem 1
+/* RESERVED 2 */
+#define cs_vstem 3
+#define cs_vmoveto 4
+#define cs_rlineto 5
+#define cs_hlineto 6
+#define cs_vlineto 7
+#define cs_rrcurveto 8
+/* cs_closepath 9 */
+#define cs_callsubr 10
+#define cs_return 11
+#define cs_escape 12
+/* cs_hsbw 13 */
+#define cs_endchar 14
+#define cs_setvsindex 15
+#define cs_blend 16
+/* RESERVED 17 */
+#define cs_hstemhm 18
+#define cs_hintmask 19
+#define cs_cntrmask 20
+#define cs_rmoveto 21
+#define cs_hmoveto 22
+#define cs_vstemhm 23
+#define cs_rcurveline 24
+#define cs_rlinecurve 25
+#define cs_vvcurveto 26
+#define cs_hhcurveto 27
+/* SHORTINT 28 */
+#define cs_callgsubr 29
+#define cs_vhcurveto 30
+#define cs_hvcurveto 31
+
+/*tex
+
+ Next the two byte CharString operators:
+
+*/
+
+#define cs_dotsection 0
+/* cs_vstem3 1 */
+/* cs_hstem3 2 */
+#define cs_and 3
+#define cs_or 4
+#define cs_not 5
+/* cs_seac 6 */
+/* cs_sbw 7 */
+/* RESERVED 8 */
+#define cs_abs 9
+#define cs_add 10
+#define cs_sub 11
+#define cs_div 12
+/* RESERVED 13 */
+#define cs_neg 14
+#define cs_eq 15
+/* cs_callothersubr 16 */
+/* cs_pop| 17 */
+#define cs_drop 18
+/* RESERVED 19 */
+#define cs_put 20
+#define cs_get 21
+#define cs_ifelse 22
+#define cs_random 23
+#define cs_mul 24
+/* RESERVED 25 */
+#define cs_sqrt 26
+#define cs_dup 27
+#define cs_exch 28
+#define cs_index 29
+#define cs_roll 30
+/* cs_setcurrentpoint 31 */
+/* RESERVED 32 */
+/* RESERVED 33 */
+#define cs_hflex 34
+#define cs_flex 35
+#define cs_hflex1 36
+#define cs_flex1 37
+
+/*tex |clear_stack| put all operands sotred in operand stack to dest. */
+
+static void clear_stack(card8 ** dest, card8 * limit)
+{
+ int i;
+ for (i = 0; i < cs2_stack_top; i++) {
+ double value;
+ long ivalue;
+ value = cs2_arg_stack[i];
+ /*tex The nearest integer value. */
+ ivalue = (long) floor(value + 0.5);
+ if (value >= 0x8000L || value <= (-0x8000L - 1)) {
+ /*tex
+ This number cannot be represented as a single operand. We must
+ use |a b mul ...| or |a c div| to represent large values.
+ */
+ normal_error("cff","argument value too large (this is bug)");
+ } else if (fabs(value - (double) ivalue) > 3.0e-5) {
+ /*tex A 16.16-bit signed fixed value */
+ DST_NEED(limit, *dest + 5);
+ *(*dest)++ = 255;
+ /*tex The mantissa. */
+ ivalue = (long) floor(value);
+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+ *(*dest)++ = (card8) (ivalue & 0xff);
+ /*tex The fraction. */
+ ivalue = (long) ((value - (double) ivalue) * 0x10000l);
+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+ *(*dest)++ = (card8) (ivalue & 0xff);
+ /*tex Everything else is integer. */
+ } else if (ivalue >= -107 && ivalue <= 107) {
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = (card8) (ivalue + 139);
+ } else if (ivalue >= 108 && ivalue <= 1131) {
+ DST_NEED(limit, *dest + 2);
+ ivalue = (long) 0xf700u + ivalue - 108;
+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+ *(*dest)++ = (card8) (ivalue & 0xff);
+ } else if (ivalue >= -1131 && ivalue <= -108) {
+ DST_NEED(limit, *dest + 2);
+ ivalue = (long) 0xfb00u - ivalue - 108;
+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+ *(*dest)++ = (card8) (ivalue & 0xff);
+ } else if (ivalue >= -32768 && ivalue <= 32767) {
+ /*tex A shortint. */
+ DST_NEED(limit, *dest + 3);
+ *(*dest)++ = 28;
+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+ *(*dest)++ = (card8) ((ivalue) & 0xff);
+ } else {
+ normal_error("cff","unexpected error");
+ }
+ }
+ /*tex Clear the stack. */
+ cs2_stack_top = 0;
+ return;
+}
+
+/*tex
+ Single byte operators: Path construction, Operator for finishing a path, Hint
+ operators. Phases:
+
+ \starttabulate
+ \NC \type{0} \NC inital state \NC \NR
+ \NC \type{1} \NC hint declaration, first stack-clearing operator appeared \NC \NR
+ \NC \type{2} \NC in path construction \NC \NR
+ \stoptabulate
+
+*/
+
+static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
+{
+ card8 op = **data;
+
+ *data += 1;
+
+ switch (op) {
+ case cs_hstemhm:
+ case cs_vstemhm:
+ /*tex A charstring may have a hintmask if the above operator has been seen. */
+ case cs_hstem:
+ case cs_vstem:
+ if (phase == 0 && (cs2_stack_top % 2)) {
+ have_width = 1;
+ width = cs2_arg_stack[0];
+ }
+ num_stems += cs2_stack_top / 2;
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 1;
+ break;
+ case cs_hintmask:
+ case cs_cntrmask:
+ if (phase < 2) {
+ if (phase == 0 && (cs2_stack_top % 2)) {
+ have_width = 1;
+ width = cs2_arg_stack[0];
+ }
+ num_stems += cs2_stack_top / 2;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ if (num_stems > 0) {
+ int masklen = (num_stems + 7) / 8;
+ DST_NEED(limit, *dest + masklen);
+ SRC_NEED(endptr, *data + masklen);
+ memmove(*dest, *data, (size_t) masklen);
+ *data += masklen;
+ *dest += masklen;
+ }
+ phase = 2;
+ break;
+ case cs_rmoveto:
+ if (phase == 0 && (cs2_stack_top % 2)) {
+ have_width = 1;
+ width = cs2_arg_stack[0];
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 2;
+ break;
+ case cs_hmoveto:
+ case cs_vmoveto:
+ if (phase == 0 && (cs2_stack_top % 2) == 0) {
+ have_width = 1;
+ width = cs2_arg_stack[0];
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ phase = 2;
+ break;
+ case cs_endchar:
+ if (cs2_stack_top == 1) {
+ have_width = 1;
+ width = cs2_arg_stack[0];
+ clear_stack(dest, limit);
+ } else if (cs2_stack_top == 4 || cs2_stack_top == 5) {
+ normal_warning("cff","'seac' character deprecated in type 2 charstring");
+ status = CS_PARSE_CFF_ERROR;
+ return;
+ } else if (cs2_stack_top > 0) {
+ normal_warning("cff","operand stack not empty");
+ }
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ status = CS_CHAR_END;
+ break;
+ /*tex The above operators are candidate for first stack clearing operator. */
+ case cs_setvsindex:
+ /*
+ vsindex = cs2_arg_stack[cs2_stack_top-1];
+ cs2_stack_top -= 1;
+ */
+ normal_warning("cff2","unsupported setvindex operator");
+ status = CS_PARSE_CFF_ERROR;
+ break;
+ case cs_blend:
+ /*
+ blends = cs2_arg_stack[cs2_stack_top-1];
+ cs2_stack_top -= 1;
+ cs2_stack_top -= blends * regions ;
+ */
+ normal_warning("cff2","unsupported blend operator");
+ status = CS_PARSE_CFF_ERROR;
+ break;
+ case cs_rlineto:
+ case cs_hlineto:
+ case cs_vlineto:
+ case cs_rrcurveto:
+ case cs_rcurveline:
+ case cs_rlinecurve:
+ case cs_vvcurveto:
+ case cs_hhcurveto:
+ case cs_vhcurveto:
+ case cs_hvcurveto:
+ if (phase < 2) {
+ normal_warning("cff","broken type 2 charstring");
+ status = CS_PARSE_CFF_ERROR;
+ return;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 1);
+ *(*dest)++ = op;
+ break;
+ /*tex All the operotors above are stack clearing. */
+ case cs_return:
+ normal_error("cff","unexpected return");
+ case cs_callgsubr:
+ normal_error("cff","unexpected callgsubr");
+ case cs_callsubr:
+ normal_error("cff","unexpected callsubr");
+ break;
+ default:
+ formatted_warning("cff","%s: unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op);
+ status = CS_PARSE_CFF_ERROR;
+ break;
+ }
+ return;
+}
+
+/*tex
+
+ Double byte operators: Flex, arithmetic, conditional, and storage operators.
+ The following operators are not supported: random but How random ?
+
+*/
+
+static void do_operator2(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
+{
+ card8 op;
+ *data += 1;
+ SRC_NEED(endptr, *data + 1);
+ op = **data;
+ *data += 1;
+ switch (op) {
+ case cs_dotsection:
+ normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring");
+ status = CS_PARSE_CFF_ERROR;
+ return;
+ break;
+ case cs_hflex:
+ case cs_flex:
+ case cs_hflex1:
+ case cs_flex1:
+ if (phase < 2) {
+ formatted_warning("cff","%s: broken type 2 charstring", CS_TYPE2_DEBUG_STR);
+ status = CS_PARSE_CFF_ERROR;
+ return;
+ }
+ clear_stack(dest, limit);
+ DST_NEED(limit, *dest + 2);
+ *(*dest)++ = cs_escape;
+ *(*dest)++ = op;
+ break;
+ /*tex All operators above are stack clearing. */
+ case cs_and:
+ NEED(cs2_stack_top, 2);
+ cs2_stack_top--;
+ if (cs2_arg_stack[cs2_stack_top] && cs2_arg_stack[cs2_stack_top - 1]) {
+ cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+ } else {
+ cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+ }
+ break;
+ case cs_or:
+ NEED(cs2_stack_top, 2);
+ cs2_stack_top--;
+ if (cs2_arg_stack[cs2_stack_top] || cs2_arg_stack[cs2_stack_top - 1]) {
+ cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+ } else {
+ cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+ }
+ break;
+ case cs_not:
+ NEED(cs2_stack_top, 1);
+ if (cs2_arg_stack[cs2_stack_top - 1]) {
+ cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+ } else {
+ cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+ }
+ break;
+ case cs_abs:
+ NEED(cs2_stack_top, 1);
+ cs2_arg_stack[cs2_stack_top - 1] =
+ fabs(cs2_arg_stack[cs2_stack_top - 1]);
+ break;
+ case cs_add:
+ NEED(cs2_stack_top, 2);
+ cs2_arg_stack[cs2_stack_top - 2] += cs2_arg_stack[cs2_stack_top - 1];
+ cs2_stack_top--;
+ break;
+ case cs_sub:
+ NEED(cs2_stack_top, 2);
+ cs2_arg_stack[cs2_stack_top - 2] -= cs2_arg_stack[cs2_stack_top - 1];
+ cs2_stack_top--;
+ break;
+ case cs_div:
+ NEED(cs2_stack_top, 2);
+ cs2_arg_stack[cs2_stack_top - 2] /= cs2_arg_stack[cs2_stack_top - 1];
+ cs2_stack_top--;
+ break;
+ case cs_neg:
+ NEED(cs2_stack_top, 1);
+ cs2_arg_stack[cs2_stack_top - 1] *= -1.0;
+ break;
+ case cs_eq:
+ NEED(cs2_stack_top, 2);
+ cs2_stack_top--;
+ if (cs2_arg_stack[cs2_stack_top] == cs2_arg_stack[cs2_stack_top - 1]) {
+ cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+ } else {
+ cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+ }
+ break;
+ case cs_drop:
+ NEED(cs2_stack_top, 1);
+ cs2_stack_top--;
+ break;
+ case cs_put:
+ NEED(cs2_stack_top, 2);
+ {
+ int idx = (int) cs2_arg_stack[--cs2_stack_top];
+ NEED(CS_TRANS_ARRAY_MAX, idx);
+ trn_array[idx] = cs2_arg_stack[--cs2_stack_top];
+ }
+ break;
+ case cs_get:
+ NEED(cs2_stack_top, 1);
+ {
+ int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
+ NEED(CS_TRANS_ARRAY_MAX, idx);
+ cs2_arg_stack[cs2_stack_top - 1] = trn_array[idx];
+ }
+ break;
+ case cs_ifelse:
+ NEED(cs2_stack_top, 4);
+ cs2_stack_top -= 3;
+ if (cs2_arg_stack[cs2_stack_top + 1] > cs2_arg_stack[cs2_stack_top + 2]) {
+ cs2_arg_stack[cs2_stack_top - 1] = cs2_arg_stack[cs2_stack_top];
+ }
+ break;
+ case cs_mul:
+ NEED(cs2_stack_top, 2);
+ cs2_arg_stack[cs2_stack_top - 2] =
+ cs2_arg_stack[cs2_stack_top - 2] * cs2_arg_stack[cs2_stack_top - 1];
+ cs2_stack_top--;
+ break;
+ case cs_sqrt:
+ NEED(cs2_stack_top, 1);
+ cs2_arg_stack[cs2_stack_top - 1] =
+ sqrt(cs2_arg_stack[cs2_stack_top - 1]);
+ break;
+ case cs_dup:
+ NEED(cs2_stack_top, 1);
+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+ cs2_arg_stack[cs2_stack_top] = cs2_arg_stack[cs2_stack_top - 1];
+ cs2_stack_top++;
+ break;
+ case cs_exch:
+ NEED(cs2_stack_top, 2);
+ {
+ double save = cs2_arg_stack[cs2_stack_top - 2];
+ cs2_arg_stack[cs2_stack_top - 2] = cs2_arg_stack[cs2_stack_top - 1];
+ cs2_arg_stack[cs2_stack_top - 1] = save;
+ }
+ break;
+ case cs_index:
+ NEED(cs2_stack_top, 2);
+ {
+ int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
+ if (idx < 0) {
+ cs2_arg_stack[cs2_stack_top - 1] =
+ cs2_arg_stack[cs2_stack_top - 2];
+ } else {
+ NEED(cs2_stack_top, idx + 2);
+ cs2_arg_stack[cs2_stack_top - 1] =
+ cs2_arg_stack[cs2_stack_top - idx - 2];
+ }
+ }
+ break;
+ case cs_roll:
+ NEED(cs2_stack_top, 2);
+ {
+ int N, J;
+ J = (int) cs2_arg_stack[--cs2_stack_top];
+ N = (int) cs2_arg_stack[--cs2_stack_top];
+ NEED(cs2_stack_top, N);
+ if (J > 0) {
+ J = J % N;
+ while (J-- > 0) {
+ double save = cs2_arg_stack[cs2_stack_top - 1];
+ int i = cs2_stack_top - 1;
+ while (i > cs2_stack_top - N) {
+ cs2_arg_stack[i] = cs2_arg_stack[i - 1];
+ i--;
+ }
+ cs2_arg_stack[i] = save;
+ }
+ } else {
+ J = (-J) % N;
+ while (J-- > 0) {
+ double save = cs2_arg_stack[cs2_stack_top - N];
+ int i = cs2_stack_top - N;
+ while (i < cs2_stack_top - 1) {
+ cs2_arg_stack[i] = cs2_arg_stack[i + 1];
+ i++;
+ }
+ cs2_arg_stack[i] = save;
+ }
+ }
+ }
+ break;
+ case cs_random:
+ formatted_warning("cff","%s: Charstring operator 'random' found.", CS_TYPE2_DEBUG_STR);
+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+ cs2_arg_stack[cs2_stack_top++] = 1.0;
+ break;
+ default:
+ formatted_warning("cff","%s: unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op);
+ status = CS_PARSE_CFF_ERROR;
+ break;
+ }
+ return;
+}
+
+/*tex integer: exactly the same as the DICT encoding (except 29) */
+
+static void cs2_get_integer(card8 ** data, card8 * endptr)
+{
+ long result = 0;
+ card8 b0 = **data, b1, b2;
+ *data += 1;
+ if (b0 == 28) {
+ /*tex shortint */
+ SRC_NEED(endptr, *data + 2);
+ b1 = **data;
+ b2 = *(*data + 1);
+ result = b1 * 256 + b2;
+ if (result > 0x7fff)
+ result -= 0x10000L;
+ *data += 2;
+ } else if (b0 >= 32 && b0 <= 246) {
+ /*tex int (1) */
+ result = b0 - 139;
+ } else if (b0 >= 247 && b0 <= 250) {
+ /*tex int (2) */
+ SRC_NEED(endptr, *data + 1);
+ b1 = **data;
+ result = (b0 - 247) * 256 + b1 + 108;
+ *data += 1;
+ } else if (b0 >= 251 && b0 <= 254) {
+ SRC_NEED(endptr, *data + 1);
+ b1 = **data;
+ result = -(b0 - 251) * 256 - b1 - 108;
+ *data += 1;
+ } else {
+ status = CS_PARSE_CFF_ERROR;
+ return;
+ }
+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+ cs2_arg_stack[cs2_stack_top++] = (double) result;
+ return;
+}
+
+/*tex Signed 16.16-bits fixed number for Type 2 charstring encoding. */
+
+static void get_fixed(card8 ** data, card8 * endptr)
+{
+ long ivalue;
+ double rvalue;
+ *data += 1;
+ SRC_NEED(endptr, *data + 4);
+ ivalue = *(*data) * 0x100 + *(*data + 1);
+ rvalue = (double) ((ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue);
+ ivalue = *(*data + 2) * 0x100 + *(*data + 3);
+ rvalue += ((double) ivalue) / 0x10000L;
+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+ cs2_arg_stack[cs2_stack_top++] = rvalue;
+ *data += 4;
+ return;
+}
+
+/*tex
+
+Subroutines: the bias for subroutine number is introduced in type 2
+charstrings.
+
+\starttabulate
+\NC \type {subr} \NC set to a pointer to the subroutine charstring \NC \NR
+\NC \type {len} \NC set to the length of subroutine charstring \NC \NR
+\NC \type {subr_idx} \NC CFF INDEX data that contains subroutines \NC \NR
+\NC \type {id} \NC biased subroutine number \NC \NR
+\stoptabulate
+
+*/
+
+static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id)
+{
+ card16 count;
+ if (subr_idx == NULL)
+ formatted_error("cff","%s: subroutine called but no subroutine found",CS_TYPE2_DEBUG_STR);
+ count = subr_idx->count;
+ /*tex addi the bias number */
+ if (count < 1240) {
+ id += 107;
+ } else if (count < 33900) {
+ id += 1131;
+ } else {
+ id += 32768;
+ }
+ if (id > count)
+ formatted_error("cff","%s: invalid subroutine index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count);
+ *len = (long) ((subr_idx->offset)[id + 1] - (subr_idx->offset)[id]);
+ *subr = subr_idx->data + (subr_idx->offset)[id] - 1;
+ return;
+}
+
+/*tex
+
+ The Type 2 interpretation of a number encoded in five-bytes (those with an
+ initial byte value of 255) differs from how it is interpreted in the Type 1
+ format.
+
+*/
+
+static void do_charstring(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr,
+ cff_index * gsubr_idx, cff_index * subr_idx, int cff2)
+{
+ card8 b0 = 0, *subr;
+ long len;
+ if (cs2_nest > CS_SUBR_NEST_MAX)
+ formatted_error("cff","%s: subroutine nested too deeply", CS_TYPE2_DEBUG_STR);
+ cs2_nest++;
+ while (*data < endptr && status == CS_PARSE_OK) {
+ b0 = **data;
+ if (b0 == 255) {
+ /*tex A 16-bit.16-bit fixed signed number. */
+ get_fixed(data, endptr);
+ } else if (b0 == cs_return) {
+ status = CS_SUBR_RETURN;
+ } else if (b0 == cs_callgsubr) {
+ if (cs2_stack_top < 1) {
+ status = CS_STACK_CFF_ERROR;
+ } else {
+ cs2_stack_top--;
+ get_subr(&subr, &len, gsubr_idx, (long) cs2_arg_stack[cs2_stack_top]);
+ if (*dest + len > limit)
+ formatted_error("cff","%s: possible buffer overflow (1)", CS_TYPE2_DEBUG_STR);
+ do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
+ *data += 1;
+ }
+ } else if (b0 == cs_callsubr) {
+ if (cs2_stack_top < 1) {
+ status = CS_STACK_CFF_ERROR;
+ } else {
+ cs2_stack_top--;
+ get_subr(&subr, &len, subr_idx, (long) cs2_arg_stack[cs2_stack_top]);
+ if (limit < *dest + len)
+ formatted_error("cff","%s: possible buffer overflow (2)", CS_TYPE2_DEBUG_STR);
+ do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
+ *data += 1;
+ }
+ } else if (b0 == cs_escape) {
+ do_operator2(dest, limit, data, endptr);
+ } else if (b0 < 32 && b0 != 28) {
+ do_operator1(dest, limit, data, endptr);
+ } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) {
+ status = CS_PARSE_CFF_ERROR;
+ } else {
+ cs2_get_integer(data, endptr);
+ }
+ }
+ if (cff2) {
+ DST_NEED(limit, *dest + 1);
+ ++endptr;
+ *(*dest)++ = cs_endchar;
+ } else if (status == CS_SUBR_RETURN) {
+ status = CS_PARSE_OK;
+ } else if (status == CS_CHAR_END && *data < endptr) {
+ formatted_warning("cff","%s: garbage after endchar", CS_TYPE2_DEBUG_STR);
+ } else if (status < CS_PARSE_OK) {
+ formatted_error("cff","%s: parsing charstring failed: (status=%d, stack=%d)", CS_TYPE2_DEBUG_STR, status, cs2_stack_top);
+ }
+ cs2_nest--;
+ return;
+}
+
+static void cs_parse_init(void)
+{
+ status = CS_PARSE_OK;
+ cs2_nest = 0;
+ phase = 0;
+ num_stems = 0;
+ cs2_stack_top = 0;
+}
+
+/*tex Not just copying \unknown */
+
+static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srclen, cff_index * gsubr,
+ cff_index * subr, double default_width, double nominal_width, cs_ginfo * ginfo, int cff2)
+{
+ card8 *save = dst;
+
+ cs_parse_init();
+
+ width = 0.0;
+ have_width = 0;
+
+ /* expand call(g)subrs */
+ do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr, cff2);
+
+ if (ginfo) {
+ ginfo->flags = 0; /* not used */
+ if (have_width) {
+ ginfo->wx = nominal_width + width;
+ } else {
+ ginfo->wx = default_width;
+ }
+ }
+
+ return (long) (dst - save);
+}
+
+/*tex CID-Keyed font specific. */
+
+long cff_read_fdselect(cff_font * cff)
+{
+ cff_fdselect *fdsel;
+ long offset, length;
+ card16 i;
+ if (cff->topdict == NULL)
+ normal_error("cff","top DICT not available");
+ if (!(cff->flag & FONTTYPE_CIDFONT))
+ return 0;
+ offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0);
+ cff->offset = (l_offset) offset;
+ cff->fdselect = fdsel = xcalloc(1, sizeof(cff_fdselect));
+ fdsel->format = get_card8(cff);
+ length = 1;
+ switch (fdsel->format) {
+ case 0:
+ fdsel->num_entries = cff->num_glyphs;
+ (fdsel->data).fds = xmalloc(fdsel->num_entries * sizeof(card8));
+ for (i = 0; i < (fdsel->num_entries); i++) {
+ (fdsel->data).fds[i] = get_card8(cff);
+ }
+ length += fdsel->num_entries;
+ break;
+ case 3:
+ {
+ cff_range3 *ranges;
+ fdsel->num_entries = get_card16(cff);
+ fdsel->data.ranges = ranges =
+ xcalloc(fdsel->num_entries, sizeof(cff_range3));
+ for (i = 0; i < (fdsel->num_entries); i++) {
+ ranges[i].first = get_card16(cff);
+ ranges[i].fd = get_card8(cff);
+ }
+ if (ranges[0].first != 0)
+ normal_error("cff","range not starting with 0");
+ if (cff->num_glyphs != get_card16(cff))
+ normal_error("cff","sentinel value mismatched with number of glyphs");
+ length += (fdsel->num_entries) * 3 + 4;
+ }
+ break;
+ default:
+ xfree(fdsel);
+ normal_error("cff","unknown FDSelect format");
+ break;
+ }
+ return length;
+}
+
+long cff_pack_fdselect(cff_font * cff, card8 * dest, long destlen)
+{
+ cff_fdselect *fdsel;
+ long len = 0;
+ card16 i;
+ if (cff->fdselect == NULL)
+ return 0;
+ if (destlen < 1)
+ normal_error("cff","buffer overflow (23)");
+ fdsel = cff->fdselect;
+ dest[len++] = fdsel->format;
+ switch (fdsel->format) {
+ case 0:
+ if (fdsel->num_entries != cff->num_glyphs)
+ normal_error("cff","invalid data");
+ if (destlen < len + fdsel->num_entries)
+ normal_error("cff","buffer overflow (24)");
+ for (i = 0; i < fdsel->num_entries; i++) {
+ dest[len++] = (fdsel->data).fds[i];
+ }
+ break;
+ case 3:
+ {
+ if (destlen < len + 2)
+ normal_error("cff","buffer overflow (25)");
+ len += 2;
+ for (i = 0; i < (fdsel->num_entries); i++) {
+ if (destlen < len + 3)
+ normal_error("cff","buffer overflow (26)");
+ dest[len++] =
+ (card8) (((fdsel->data).ranges[i].first >> 8) & 0xff);
+ dest[len++] = (card8) ((fdsel->data).ranges[i].first & 0xff);
+ dest[len++] = (card8) ((fdsel->data).ranges[i].fd);
+ }
+ if (destlen < len + 2)
+ normal_error("cff","buffer overflow (27)");
+ dest[len++] = (card8) ((cff->num_glyphs >> 8) & 0xff);
+ dest[len++] = (card8) (cff->num_glyphs & 0xff);
+ dest[1] = (card8) (((len / 3 - 1) >> 8) & 0xff);
+ dest[2] = (card8) ((len / 3 - 1) & 0xff);
+ }
+ break;
+ default:
+ normal_error("cff","unknown FDSelect format");
+ break;
+ }
+ return len;
+}
+
+/*tex Create an instance of embeddable font. */
+
+static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname)
+{
+ cff_index *topdict, *fdarray, *private;
+ unsigned char *dest;
+ long destlen = 0, i, size;
+ long offset, topdict_offset, fdarray_offset;
+ topdict = cff_new_index(1);
+ fdarray = cff_new_index(cffont->num_fds);
+ private = cff_new_index(cffont->num_fds);
+ cff_dict_remove(cffont->topdict, "UniqueID");
+ cff_dict_remove(cffont->topdict, "XUID");
+ /*tex A bad font may have this: */
+ cff_dict_remove(cffont->topdict, "Private");
+ /*tex A bad font may have this: */
+ cff_dict_remove(cffont->topdict, "Encoding");
+ /*tex This is CFF2 specific: */
+ cff_dict_remove(cffont->topdict, "vstore");
+ /*tex This is CFF2 specific: */
+ cff_dict_remove(cffont->topdict, "maxstack");
+ topdict->offset[1] = (l_offset) cff_dict_pack(cffont->topdict, (card8 *) work_buffer, WORK_BUFFER_SIZE) + 1;
+ for (i = 0; i < cffont->num_fds; i++) {
+ size = 0;
+ if (cffont->private && cffont->private[i]) {
+ size = cff_dict_pack(cffont->private[i], (card8 *) work_buffer, WORK_BUFFER_SIZE);
+ if (size < 1) {
+ /*tex |Private| contains only |Subr|: */
+ cff_dict_remove(cffont->fdarray[i], "Private");
+ }
+ }
+ (private->offset)[i + 1] = (unsigned long) ((private->offset)[i] + (unsigned) size);
+ (fdarray->offset)[i + 1] = (unsigned long) ((fdarray->offset)[i]
+ + (unsigned) cff_dict_pack(cffont->fdarray[i], (card8 *) work_buffer, WORK_BUFFER_SIZE));
+ }
+ /*tex The header size: */
+ destlen = 4;
+ destlen += cff_set_name(cffont, fullname);
+ destlen += cff_index_size(topdict);
+ destlen += cff_index_size(cffont->string);
+ destlen += cff_index_size(cffont->gsubr);
+ /*tex |charset| format 0 */
+ destlen += (cffont->charsets->num_entries) * 2 + 1;
+ /*tex |fdselect| format 3 */
+ destlen += (cffont->fdselect->num_entries) * 3 + 5;
+ destlen += cff_index_size(cffont->cstrings);
+ destlen += cff_index_size(fdarray);
+ /* |Private| is not indexed */
+ destlen = (long) (destlen + (long) private->offset[private->count] - 1);
+ dest = xcalloc((unsigned) destlen, sizeof(card8));
+ offset = 0;
+ /*tex |Header| */
+ offset += cff_put_header(cffont, dest + offset, destlen - offset);
+ /*tex |Name| */
+ offset += cff_pack_index(cffont->name, dest + offset, destlen - offset);
+ /*tex |Top DICT| */
+ topdict_offset = offset;
+ offset += cff_index_size(topdict);
+ /*tex |Strings| */
+ offset += cff_pack_index(cffont->string, dest + offset, destlen - offset);
+ /*tex |Global Subrs| */
+ offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset);
+ /*tex |charset| */
+ cff_dict_set(cffont->topdict, "charset", 0, (double) offset);
+ offset += cff_pack_charsets(cffont, dest + offset, destlen - offset);
+ /*tex |FDSelect| */
+ cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset);
+ offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset);
+ /*tex |CharStrings| */
+ cff_dict_set(cffont->topdict, "CharStrings", 0, (double) offset);
+ offset += cff_pack_index(cffont->cstrings, dest + offset, cff_index_size(cffont->cstrings));
+ cff_release_index(cffont->cstrings);
+ /*tex |Charstring|s can consume a lot of memory. */
+ cffont->cstrings = NULL;
+ /*tex |FDArray| and |Private| */
+ cff_dict_set(cffont->topdict, "FDArray", 0, (double) offset);
+ fdarray_offset = offset;
+ offset += cff_index_size(fdarray);
+ fdarray->data = xcalloc((unsigned) (fdarray->offset[fdarray->count] - 1), sizeof(card8));
+ for (i = 0; i < cffont->num_fds; i++) {
+ size = (long) (private->offset[i + 1] - private->offset[i]);
+ if (cffont->private[i] && size > 0) {
+ cff_dict_pack(cffont->private[i], dest + offset, size);
+ cff_dict_set(cffont->fdarray[i], "Private", 0, (double) size);
+ cff_dict_set(cffont->fdarray[i], "Private", 1, (double) offset);
+ }
+ cff_dict_pack(cffont->fdarray[i], fdarray->data + (fdarray->offset)[i] - 1, (long) (fdarray->offset[fdarray->count] - 1));
+ offset += size;
+ }
+ cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray));
+ cff_release_index(fdarray);
+ cff_release_index(private);
+ /*tex Finally the |Top DICT| */
+ topdict->data = xcalloc((unsigned) (topdict->offset[topdict->count] - 1), sizeof(card8));
+ cff_dict_pack(cffont->topdict, topdict->data, (long) (topdict->offset[topdict->count] - 1));
+ cff_pack_index(topdict, dest + topdict_offset, cff_index_size(topdict));
+ cff_release_index(topdict);
+ for (i = 0; i < offset; i++) {
+ strbuf_putchar(pdf->fb, dest[i]);
+ }
+ xfree(dest);
+ return;
+}
+
+void write_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
+{
+ cff_index *charstrings, *cs_idx;
+ long charstring_len, max_len;
+ long size, offset = 0;
+ card8 *data;
+ card16 num_glyphs, cs_count1, code, gid, last_cid;
+ double nominal_width, default_width;
+ char *fontname;
+ char *fullname;
+ glw_entry *glyph, *found;
+ struct avl_traverser t;
+ cffont->_string = NULL;
+ fontname = xcalloc((unsigned) (1 + strlen(fd->fontname)), 1);
+ sprintf(fontname, "%s", fd->fontname);
+ fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
+ sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
+ /*tex Finish parsing the CFF. */
+ cff_read_private(cffont);
+ cff_read_subrs(cffont);
+ /*tex The |Width|s. */
+ if (cffont->private[0] && cff_dict_known(cffont->private[0], "defaultWidthX")) {
+ default_width = (double) cff_dict_get(cffont->private[0], "defaultWidthX", 0);
+ } else {
+ default_width = CFF_DEFAULTWIDTHX_DEFAULT;
+ }
+ if (cffont->private[0] && cff_dict_known(cffont->private[0], "nominalWidthX")) {
+ nominal_width = (double) cff_dict_get(cffont->private[0], "nominalWidthX", 0);
+ } else {
+ nominal_width = CFF_NOMINALWIDTHX_DEFAULT;
+ }
+ num_glyphs = 0;
+ last_cid = 0;
+ glyph = xtalloc(1, glw_entry);
+ /*tex insert |notdef| */
+ glyph->id = 0;
+ if (avl_find(fd->gl_tree, glyph) == NULL) {
+ avl_insert(fd->gl_tree, glyph);
+ glyph = xtalloc(1, glw_entry);
+ }
+ avl_t_init(&t, fd->gl_tree);
+ for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
+ found != NULL; found = (glw_entry *) avl_t_next(&t)) {
+ if (found->id > last_cid)
+ last_cid = (card16) found->id;
+ num_glyphs++;
+ }
+ {
+ cff_fdselect *fdselect;
+ fdselect = xcalloc(1, sizeof(cff_fdselect));
+ fdselect->format = 3;
+ fdselect->num_entries = 1;
+ fdselect->data.ranges = xcalloc(1, sizeof(cff_range3));
+ fdselect->data.ranges[0].first = 0;
+ fdselect->data.ranges[0].fd = 0;
+ cffont->fdselect = fdselect;
+ }
+ {
+ cff_charsets *charset;
+ charset = xcalloc(1, sizeof(cff_charsets));
+ charset->format = 0;
+ charset->num_entries = (card16) (num_glyphs - 1);
+ charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
+ gid = 0;
+ avl_t_init(&t, fd->gl_tree);
+ for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
+ found != NULL; found = (glw_entry *) avl_t_next(&t)) {
+ if (found->id != 0) {
+ charset->data.glyphs[gid] = (s_SID) found->id;
+ gid++;
+ }
+ }
+ cffont->charsets = charset;
+ if (cffont->header_major == 2) {
+ cff_dict_add(cffont->topdict, "charset", 1);
+ }
+ }
+ cff_dict_add(cffont->topdict, "CIDCount", 1);
+ cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1);
+ if (cffont->header_major == 2) {
+ cff_dict_add(cffont->topdict, "FullName", 1);
+ cff_dict_set(cffont->topdict, "FullName", 0, (double) cff_add_string(cffont, fontname));
+ cff_dict_add(cffont->topdict, "FontBBox", 4);
+ cff_dict_set(cffont->topdict, "FontBBox", 0, fd->font_dim[FONTBBOX1_CODE].val);
+ cff_dict_set(cffont->topdict, "FontBBox", 1, fd->font_dim[FONTBBOX2_CODE].val);
+ cff_dict_set(cffont->topdict, "FontBBox", 2, fd->font_dim[FONTBBOX3_CODE].val);
+ cff_dict_set(cffont->topdict, "FontBBox", 3, fd->font_dim[FONTBBOX4_CODE].val);
+ }
+ cffont->fdarray = xcalloc(1, sizeof(cff_dict *));
+ cffont->fdarray[0] = cff_new_dict();
+ cff_dict_add(cffont->fdarray[0], "FontName", 1);
+ /*tex fix: skip XXXXXX+ */
+ cff_dict_set(cffont->fdarray[0], "FontName", 0, (double) cff_add_string(cffont, fullname));
+ cff_dict_add(cffont->fdarray[0], "Private", 2);
+ cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
+ cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
+ /*tex |FDArray| index offset, not known yet */
+ cff_dict_add(cffont->topdict, "FDArray", 1);
+ cff_dict_set(cffont->topdict, "FDArray", 0, 0.0);
+ /*tex |FDSelect| offset, not known yet */
+ cff_dict_add(cffont->topdict, "FDSelect", 1);
+ cff_dict_set(cffont->topdict, "FDSelect", 0, 0.0);
+ cff_dict_remove(cffont->topdict, "UniqueID");
+ cff_dict_remove(cffont->topdict, "XUID");
+ cff_dict_remove(cffont->topdict, "Private");
+ cff_dict_remove(cffont->topdict, "Encoding");
+ cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
+ cs_idx = cff_get_index_header(cffont);
+ offset = (long) cffont->offset;
+ cs_count1 = cs_idx->count;
+ if (cs_count1 < 2) {
+ normal_error("cff","no valid charstring data found");
+ }
+ /*tex Build the new charstrings entry. */
+ charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
+ max_len = 2 * CS_STR_LEN_MAX;
+ charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
+ charstring_len = 0;
+ gid = 0;
+ data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
+ {
+ int i;
+ int tex_font = fd->tex_font;
+ int streamprovider = 0;
+ int callback_id = 0 ;
+ if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
+ streamprovider = font_streamprovider(tex_font);
+ callback_id = callback_defined(glyph_stream_provider_callback);
+ }
+ for (i = 0; i < cs_count1; i++) {
+ code = (card16) i;
+ glyph->id = code;
+ if ((avl_find(fd->gl_tree,glyph) != NULL)) {
+ /*tex This code is the same as below, apart from small details */
+ if (callback_id > 0) {
+ lstring * result;
+ run_callback(callback_id, "ddd->L", tex_font, i, streamprovider, &result); /* this call can be sped up */
+ size = (size_t) result->l ;
+ if (size > 0) {
+ if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+ }
+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
+ memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t) size);
+ charstring_len += size;
+ xfree(result);
+ }
+ } else {
+ size = (long)(cs_idx->offset[code+1] - cs_idx->offset[code]);
+ if (size > CS_STR_LEN_MAX) {
+ formatted_error("cff","charstring too long: gid=%u, %ld bytes", code, size);
+ }
+ if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+ }
+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
+ memcpy(data,&cffont->stream[cffont->offset],(size_t)size);
+ charstring_len += cs_copy_charstring(
+ charstrings->data + charstring_len,
+ max_len - charstring_len,
+ data, size,
+ cffont->gsubr, (cffont->subrs)[0],
+ default_width, nominal_width, NULL,
+ cffont->header_major == 2
+ );
+ }
+ gid++;
+ }
+ }
+ }
+ /*tex
+ The |CIDSet| is a table of bits indexed by cid, bytes with high order bit
+ first, each (set) bit is a (present) CID.
+ */
+ if (1) {
+ int cid;
+ cidset = pdf_create_obj(pdf, obj_type_others, 0);
+ if (cidset != 0) {
+ size_t l = (last_cid/8)+1;
+ char *stream = xmalloc(l);
+ memset(stream, 0, l);
+ for (cid = 1; cid <= (long) last_cid; cid++) {
+ glyph->id = cid;
+ if (avl_find(fd->gl_tree,glyph) != NULL) {
+ stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
+ }
+ }
+ pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ pdf_out_block(pdf, stream, l);
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+ }
+ }
+ /*tex
+ This happens if the internal metrics do not agree with the actual disk
+ font.
+ */
+ if (gid < num_glyphs) {
+ formatted_warning("cff","embedded subset is smaller than expected: %d instead of %d glyphs", gid, num_glyphs);
+ num_glyphs = gid;
+ }
+ xfree(data);
+ cff_release_index(cs_idx);
+ (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
+ charstrings->count = num_glyphs;
+ cffont->num_glyphs = num_glyphs;
+ cffont->cstrings = charstrings;
+ /*tex
+ We don't use subroutines at all.
+ */
+ if (cffont->gsubr)
+ cff_release_index(cffont->gsubr);
+ cffont->gsubr = cff_new_index(0);
+ if (cffont->subrs && cffont->subrs[0])
+ cff_release_index(cffont->subrs[0]);
+ cffont->subrs[0] = NULL;
+ if (cffont->private && (cffont->private)[0]) {
+ cff_dict_remove((cffont->private)[0], "Subrs"); /* no Subrs */
+ }
+ cff_dict_update(cffont->topdict, cffont);
+ cff_add_string(cffont, "Adobe");
+ cff_add_string(cffont, "Identity");
+ if (cffont->header_major == 2) {
+ /*tex A crash. */
+ } else {
+ cff_dict_update(cffont->private[0], cffont);
+ }
+ cff_update_string(cffont);
+ /* CFF code need to be rewritten */
+ cff_dict_add(cffont->topdict, "ROS", 3);
+ cff_dict_set(cffont->topdict, "ROS", 0, (double) cff_get_sid(cffont, "Adobe"));
+ cff_dict_set(cffont->topdict, "ROS", 1, (double) cff_get_sid(cffont, "Identity"));
+ cff_dict_set(cffont->topdict, "ROS", 2, 0.0);
+ write_fontfile(pdf, cffont, fullname);
+ xfree(fontname);
+ xfree(fullname);
+ cff_close(cffont);
+}
+
+#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT)
+#define CID_MAX 65535
+
+void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
+{
+ cff_index *charstrings, *cs_idx;
+ long charstring_len, max_len;
+ long size, offset = 0;
+ int tex_font = fd->tex_font;
+ int streamprovider = 0;
+ int callback_id = 0 ;
+ card8 *data;
+ card16 num_glyphs, cs_count1, gid, last_cid;
+ int fdsel, prev_fd, cid_count, cid ;
+ char *fullname;
+ glw_entry *glyph;
+ unsigned char *CIDToGIDMap = NULL;
+ cff_fdselect *fdselect = NULL;
+ cff_charsets *charset = NULL;
+ if (!is_cidfont(cffont)) {
+ normal_error("cff","invalid CIDfont");
+ return;
+ }
+ if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
+ streamprovider = font_streamprovider(tex_font);
+ callback_id = callback_defined(glyph_stream_provider_callback);
+ }
+ fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
+ sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
+ /*tex Finish parsing the CFF. */
+ if (cff_dict_known(cffont->topdict, "CIDCount")) {
+ cid_count = (card16) cff_dict_get(cffont->topdict, "CIDCount", 0);
+ } else {
+ cid_count = CFF_CIDCOUNT_DEFAULT;
+ }
+ if (cffont->header_major == 2) {
+ /*tex hm */
+ } else {
+ cff_read_charsets(cffont);
+ }
+ CIDToGIDMap = xmalloc((unsigned) ((2 * (unsigned) cid_count) * sizeof(unsigned char)));
+ memset(CIDToGIDMap, 0, (size_t) (2 * cid_count));
+ glyph = xtalloc(1, glw_entry);
+ /*tex insert |notdef| */
+ glyph->id = 0;
+ if (avl_find(fd->gl_tree, glyph) == NULL) {
+ avl_insert(fd->gl_tree, glyph);
+ glyph = xtalloc(1, glw_entry);
+ }
+ last_cid = 0;
+ num_glyphs = 0;
+ for (cid = 0; cid <= CID_MAX; cid++) {
+ glyph->id = (unsigned) cid;
+ if (avl_find(fd->gl_tree, glyph) != NULL) {
+ gid = (card16) cid;
+ CIDToGIDMap[2 * cid] = (unsigned char) ((gid >> 8) & 0xff);
+ CIDToGIDMap[2 * cid + 1] = (unsigned char) (gid & 0xff);
+ last_cid = (card16) cid;
+ num_glyphs++;
+ }
+ }
+ if (cffont->header_major == 2) {
+ /*tex hm */
+ } else if (last_cid >= cffont->num_glyphs) {
+ formatted_error("cff font","bad glyph index %i",last_cid);
+ }
+ /*tex
+ The |CIDSet| table is a table of bits indexed by cid, bytes with high
+ order bit first, each (set) bit is a (present) CID.
+ */
+ if (1) {
+ cidset = pdf_create_obj(pdf, obj_type_others, 0);
+ if (cidset != 0) {
+ size_t l = (last_cid / 8) + 1;
+ char *stream = xmalloc(l);
+ memset(stream, 0, l);
+ for (cid = 1; cid <= (long) last_cid; cid++) {
+ if (CIDToGIDMap[2 * cid] || CIDToGIDMap[2 * cid + 1]) {
+ stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
+ }
+ }
+ pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ pdf_out_block(pdf, stream, l);
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+ xfree(stream);
+ }
+ }
+ cff_read_fdselect(cffont);
+ cff_read_fdarray(cffont);
+ cff_read_private(cffont);
+ cff_read_subrs(cffont);
+ cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
+ cs_idx = cff_get_index_header(cffont);
+ offset = (long) cffont->offset;
+ cs_count1 = cs_idx->count;
+ if (cs_count1 < 2) {
+ normal_error("cff","no valid charstring data found");
+ }
+ charset = xcalloc(1, sizeof(cff_charsets));
+ charset->format = 0;
+ charset->num_entries = 0;
+ charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
+ fdselect = xcalloc(1, sizeof(cff_fdselect));
+ fdselect->format = 3;
+ fdselect->num_entries = 0;
+ fdselect->data.ranges = xcalloc(num_glyphs, sizeof(cff_range3));
+ charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
+ max_len = 2 * CS_STR_LEN_MAX;
+ charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
+ charstring_len = 0;
+ prev_fd = -1;
+ gid = 0;
+ data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
+ for (cid = 0; cid <= last_cid; cid++) {
+ unsigned short gid_org;
+ glyph->id = (unsigned) cid;
+ if (avl_find(fd->gl_tree, glyph) == NULL)
+ continue;
+ gid_org = (short unsigned) ((CIDToGIDMap[2 * cid] << 8) | (CIDToGIDMap[2 * cid + 1]));
+ fdsel = cff_fdselect_lookup(cffont, gid_org);
+ if (callback_id > 0) {
+ /*tex The next blob is not yet tested \unknown\ I need a font. */
+ lstring * result;
+ run_callback(callback_id, "ddd->L", tex_font, gid_org, streamprovider, &result);
+ size = (size_t) result->l ;
+ if (size > 0) {
+ if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+ }
+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[gid_org] - 1);
+ memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t)size);
+ charstring_len += size;
+ xfree(result);
+ }
+ } else {
+ size = (long) (cs_idx->offset[gid_org + 1] - cs_idx->offset[gid_org]);
+ if (size > CS_STR_LEN_MAX) {
+ formatted_error("cff","charstring too long: gid=%u, %ld bytes", cid, size);
+ }
+ if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+ max_len = charstring_len + 2 * CS_STR_LEN_MAX;
+ charstrings->data = xrealloc(charstrings->data, (unsigned) ((unsigned) max_len * sizeof(card8)));
+ }
+ (charstrings->offset)[gid] = (l_offset) (charstring_len + 1);
+ cffont->offset = (l_offset) ((unsigned) offset + (cs_idx->offset)[gid_org] - 1);
+ memcpy(data, &cffont->stream[cffont->offset], (size_t) size);
+ charstring_len += cs_copy_charstring(
+ charstrings->data + charstring_len,
+ max_len - charstring_len,
+ data, size,
+ cffont->gsubr, (cffont->subrs)[fdsel],
+ 0, 0, NULL,
+ cffont->header_major == 2
+ );
+ }
+ if (cid > 0 && gid_org > 0) {
+ charset->data.glyphs[charset->num_entries] = (s_SID) cid;
+ charset->num_entries++;
+ }
+ if (fdsel != prev_fd) {
+ fdselect->data.ranges[fdselect->num_entries].first = gid;
+ fdselect->data.ranges[fdselect->num_entries].fd = (card8) fdsel;
+ fdselect->num_entries++;
+ prev_fd = fdsel;
+ }
+ gid++;
+ }
+ if (gid != num_glyphs)
+ formatted_error("cff","unexpected error: %i != %i", gid, num_glyphs);
+ xfree(data);
+ cff_release_index(cs_idx);
+ xfree(CIDToGIDMap);
+ (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
+ charstrings->count = num_glyphs;
+ cffont->num_glyphs = num_glyphs;
+ cffont->cstrings = charstrings;
+ cff_release_charsets(cffont->charsets);
+ cffont->charsets = charset;
+ cff_release_fdselect(cffont->fdselect);
+ cffont->fdselect = fdselect;
+ /*tex
+ We don't use subroutines at all.
+ */
+ if (cffont->gsubr)
+ cff_release_index(cffont->gsubr);
+ cffont->gsubr = cff_new_index(0);
+ for (fdsel = 0; fdsel < cffont->num_fds; fdsel++) {
+ if (cffont->subrs && cffont->subrs[fdsel]) {
+ cff_release_index(cffont->subrs[fdsel]);
+ cffont->subrs[fdsel] = NULL;
+ }
+ if (cffont->private && (cffont->private)[fdsel]) {
+ cff_dict_remove((cffont->private)[fdsel], "Subrs"); /* no Subrs */
+ }
+ }
+ write_fontfile(pdf, cffont, fullname);
+ xfree(fullname);
+ cff_close(cffont);
+}
+
+/*tex
+
+ Here is a sneaky trick: fontforge knows how to convert Type1 to CFF, so I
+ have defined a utility function in luafflib.c that does exactly that. If it
+ works out ok, I will clean up this code.
+
+*/
+
+void writetype1w(PDF pdf, fd_entry * fd)
+{
+ cff_font *cff;
+ int i;
+ FILE *fp;
+ ff_entry *ff;
+ unsigned char *tfm_buffer = NULL;
+ int tfm_size = 0;
+ ff = check_ff_exist(fd->fm->ff_name, 0);
+ fp = fopen(ff->ff_path, "rb");
+ cur_file_name = ff->ff_path;
+ if (!fp) {
+ formatted_error("cff","could not open Type1 font: %s", cur_file_name);
+ }
+ fclose(fp);
+ if (is_subsetted(fd->fm)) {
+ report_start_file(filetype_subset,cur_file_name);
+ } else {
+ report_start_file(filetype_font,cur_file_name);
+ }
+ (void) ff_createcff(ff->ff_path, &tfm_buffer, &tfm_size);
+ if (tfm_size > 0) {
+ cff = read_cff(tfm_buffer, tfm_size, 0);
+ if (cff != NULL) {
+ write_cff(pdf, cff, fd);
+ } else {
+ for (i = 0; i < tfm_size; i++)
+ strbuf_putchar(pdf->fb, tfm_buffer[i]);
+ }
+ fd->ff_found = 1;
+ } else {
+ formatted_error("cff","could not understand Type1 font: %s",cur_file_name);
+ }
+ if (is_subsetted(fd->fm)) {
+ report_stop_file(filetype_subset);
+ } else {
+ report_stop_file(filetype_font);
+ }
+ cur_file_name = NULL;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writecff.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writecff.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writecff.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,3381 +0,0 @@
-% writecff.w
-%
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-#include "font/writecff.h"
-
-extern int cidset;
-
-@ @c
-#define get_offset(s,n) get_unsigned(s, (n))
-#define get_card8(a) (card8)(a->stream[a->offset++])
-#define get_card16(a) (card16)(get_unsigned(a,2))
-#define get_card32(a) (get_unsigned(a,4))
-
-#undef b0
-#undef b1
-#undef b2
-#undef b3
-
-#define WORK_BUFFER_SIZE 1024
-
-static char work_buffer[WORK_BUFFER_SIZE];
-
-static unsigned long get_unsigned(cff_font * cff, int n)
-{
- unsigned long v = 0;
- while (n-- > 0)
- v = v * 256 + get_card8(cff);
- return v;
-}
-
-@ @c
-
-const char *const cff_stdstr[CFF_STDSTR_MAX] = {
- ".notdef", "space", "exclam", "quotedbl", "numbersign",
- "dollar", "percent", "ampersand", "quoteright", "parenleft",
- "parenright", "asterisk", "plus", "comma", "hyphen",
- "period", "slash", "zero", "one", "two",
- "three", "four", "five", "six", "seven",
- "eight", "nine", "colon", "semicolon", "less",
- "equal", "greater", "question", "at", "A",
- "B", "C", "D", "E", "F",
- "G", "H", "I", "J", "K",
- "L", "M", "N", "O", "P",
- "Q", "R", "S", "T", "U",
- "V", "W", "X", "Y", "Z",
- "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
- "quoteleft", "a", "b", "c", "d",
- "e", "f", "g", "h", "i",
- "j", "k", "l", "m", "n",
- "o", "p", "q", "r", "s",
- "t", "u", "v", "w", "x",
- "y", "z", "braceleft", "bar", "braceright",
- "asciitilde", "exclamdown", "cent", "sterling", "fraction",
- "yen", "florin", "section", "currency", "quotesingle",
- "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi",
- "fl", "endash", "dagger", "daggerdbl", "periodcentered",
- "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
- "guillemotright", "ellipsis", "perthousand", "questiondown", "grave",
- "acute", "circumflex", "tilde", "macron", "breve",
- "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
- "ogonek", "caron", "emdash", "AE", "ordfeminine",
- "Lslash", "Oslash", "OE", "ordmasculine", "ae",
- "dotlessi", "lslash", "oslash", "oe", "germandbls",
- "onesuperior", "logicalnot", "mu", "trademark", "Eth",
- "onehalf", "plusminus", "Thorn", "onequarter", "divide",
- "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
- "registered", "minus", "eth", "multiply", "threesuperior",
- "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
- "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
- "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
- "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis",
- "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
- "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
- "aacute", "acircumflex", "adieresis", "agrave", "aring",
- "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis",
- "egrave", "iacute", "icircumflex", "idieresis", "igrave",
- "ntilde", "oacute", "ocircumflex", "odieresis", "ograve",
- "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
- "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
- "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
- "Acutesmall",
- "parenleftsuperior", "parenrightsuperior", "twodotenleader",
- "onedotenleader", "zerooldstyle",
- "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
- "fiveoldstyle",
- "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle",
- "commasuperior",
- "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
- "bsuperior",
- "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
- "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
- "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
- "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
- "Asmall",
- "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
- "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall",
- "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
- "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
- "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall",
- "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall",
- "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall",
- "Dieresissmall",
- "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
- "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
- "questiondownsmall",
- "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird",
- "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
- "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
- "oneinferior",
- "twoinferior", "threeinferior", "fourinferior", "fiveinferior",
- "sixinferior",
- "seveninferior", "eightinferior", "nineinferior", "centinferior",
- "dollarinferior",
- "periodinferior", "commainferior", "Agravesmall", "Aacutesmall",
- "Acircumflexsmall",
- "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
- "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
- "Igravesmall",
- "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
- "Ntildesmall",
- "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
- "Odieresissmall",
- "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall",
- "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall",
- "001.000", "001.001", "001.002", "001.003",
- "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
-};
-
-@ Only read header part but not body
- at c
-cff_index *cff_get_index_header(cff_font * cff)
-{
- cff_index *idx;
- card16 i, count;
- idx = xcalloc(1, sizeof(cff_index));
- if (cff->header_major == 2) {
- idx->count = count = get_card32(cff);
- } else {
- idx->count = count = get_card16(cff);
- }
- if (count > 0) {
- idx->offsize = get_card8(cff);
- if (idx->offsize < 1 || idx->offsize > 4)
- normal_error("cff","invalid offsize data (1)");
- idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
- for (i = 0; i <count + 1 ; i++) {
- (idx->offset)[i] = get_offset(cff, idx->offsize);
- if (i == USHRT_MAX)
- break;
- }
- if (idx->offset[0] != 1)
- normal_error("cff","invalid index data");
- idx->data = NULL;
- } else {
- idx->offsize = 0;
- idx->offset = NULL;
- idx->data = NULL;
- }
- return idx;
-}
-
-@ @c
-cff_index *cff_get_index(cff_font * cff)
-{
- cff_index *idx;
- card16 i, count;
- size_t length;
- idx = xcalloc(1, sizeof(cff_index));
- idx->count = count = get_card16(cff);
- if (count > 0) {
- idx->offsize = get_card8(cff);
- if (idx->offsize < 1 || idx->offsize > 4)
- normal_error("cff","invalid offsize data (2)");
- idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
- for (i = 0; i < count + 1; i++) {
- idx->offset[i] = get_offset(cff, idx->offsize);
- }
- if (idx->offset[0] != 1)
- normal_error("cff","invalid index offset data");
- length = (size_t) (idx->offset[count] - idx->offset[0]);
- idx->data = xmalloc((unsigned) length * sizeof(card8));
- memcpy(idx->data, &cff->stream[cff->offset], length);
- cff->offset += length;
- } else {
- idx->offsize = 0;
- idx->offset = NULL;
- idx->data = NULL;
- }
- return idx;
-}
-
-static cff_index *cff_empty_index(cff_font * cff)
-{
- cff_index *idx;
- idx = xcalloc(1, sizeof(cff_index));
- idx->count = 0;
- idx->offsize = 0;
- idx->offset = NULL;
- idx->data = NULL;
- return idx;
-}
-
-static cff_index *cff_get_index2(cff_font * cff)
-{
- /* we fake a dict array */
-
- cff_index *idx;
- size_t length;
-
- idx = xcalloc(1, sizeof(cff_index));
-
- length = (size_t) cff->header_offsize;
-
- idx->offsize = 2;
- idx->count = 1;
- idx->offset = xmalloc((unsigned) (((unsigned) 2) * sizeof(l_offset)));
- idx->offset[0] = 1; // get_offset(cff, idx->offsize);
- idx->offset[1] = length + 1; // idx->offset[0] + length;
-
- idx->data = xmalloc((unsigned) length * sizeof(card8));
- memcpy(idx->data, &cff->stream[cff->offset], length );
- cff->offset += length ;
-
- return idx;
-}
-
-@ @c
-long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
-{
- long len = 0;
- unsigned long datalen;
- card16 i;
- if (idx->count < 1) {
- if (destlen < 2)
- normal_error("cff","not enough space available");
- memset(dest, 0, 2);
- return 2;
- }
- len = cff_index_size(idx);
- datalen = idx->offset[idx->count] - 1;
- if (destlen < len)
- normal_error("cff","not enough space available");
- *(dest++) = (card8) ((idx->count >> 8) & 0xff);
- *(dest++) = (card8) (idx->count & 0xff);
- if (datalen < 0xffUL) {
- idx->offsize = 1;
- *(dest++) = 1;
- for (i = 0; i <= idx->count; i++) {
- *(dest++) = (card8) (idx->offset[i] & 0xff);
- }
- } else if (datalen < 0xffffUL) {
- idx->offsize = 2;
- *(dest++) = 2;
- for (i = 0; i <= idx->count; i++) {
- *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
- *(dest++) = (card8) (idx->offset[i] & 0xff);
- }
- } else if (datalen < 0xffffffUL) {
- idx->offsize = 3;
- *(dest++) = 3;
- for (i = 0; i <= idx->count; i++) {
- *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
- *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
- *(dest++) = (card8) (idx->offset[i] & 0xff);
- }
- } else {
- idx->offsize = 4;
- *(dest++) = 4;
- for (i = 0; i <= idx->count; i++) {
- *(dest++) = (card8) ((idx->offset[i] >> 24) & 0xff);
- *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
- *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
- *(dest++) = (card8) (idx->offset[i] & 0xff);
- }
- }
- memmove(dest, idx->data, idx->offset[idx->count] - 1);
- return len;
-}
-
-@ @c
-long cff_index_size(cff_index * idx)
-{
- if (idx->count > 0) {
- l_offset datalen;
- datalen = idx->offset[idx->count] - 1;
- if (datalen < 0xffUL) {
- idx->offsize = 1;
- } else if (datalen < 0xffffUL) {
- idx->offsize = 2;
- } else if (datalen < 0xffffffUL) {
- idx->offsize = 3;
- } else {
- idx->offsize = 4;
- }
- return (3 + (idx->offsize) * (idx->count + 1) + (long) datalen);
- } else {
- return 2;
- }
-}
-
-@ @c
-cff_index *cff_new_index(card16 count)
-{
- cff_index *idx;
- idx = xcalloc(1, sizeof(cff_index));
- idx->count = count;
- idx->offsize = 0;
- if (count > 0) {
- idx->offset = xcalloc((unsigned) (count + 1), sizeof(l_offset));
- (idx->offset)[0] = 1;
- } else {
- idx->offset = NULL;
- }
- idx->data = NULL;
- return idx;
-}
-
-@ @c
-void cff_release_index(cff_index * idx)
-{
- if (idx) {
- xfree(idx->data);
- xfree(idx->offset);
- xfree(idx);
- }
-}
-
-@ @c
-void cff_release_dict(cff_dict * dict)
-{
- if (dict) {
- if (dict->entries) {
- int i;
- for (i = 0; i < dict->count; i++) {
- xfree((dict->entries)[i].values);
- }
- xfree(dict->entries);
- }
- xfree(dict);
- }
-}
-
-@ @c
-void cff_release_encoding(cff_encoding * encoding)
-{
- if (encoding) {
- switch (encoding->format & (~0x80)) {
- case 0:
- xfree(encoding->data.codes);
- break;
- case 1:
- xfree(encoding->data.range1);
- break;
- default:
- normal_error("cff","unknown encoding format");
- }
- if (encoding->format & 0x80)
- xfree(encoding->supp);
- xfree(encoding);
- }
-}
-
-@ @c
-void cff_release_charsets(cff_charsets * charset)
-{
- if (charset) {
- switch (charset->format) {
- case 0:
- xfree(charset->data.glyphs);
- break;
- case 1:
- xfree(charset->data.range1);
- break;
- case 2:
- xfree(charset->data.range2);
- break;
- default:
- break;
- }
- xfree(charset);
- }
-}
-
-@ @c
-void cff_release_fdselect(cff_fdselect * fdselect)
-{
- if (fdselect) {
- if (fdselect->format == 0) {
- xfree(fdselect->data.fds);
- } else if (fdselect->format == 3) {
- xfree(fdselect->data.ranges);
- }
- xfree(fdselect);
- }
-}
-
-@ @c
-void cff_close(cff_font * cff)
-{
- card16 i;
- if (cff) {
- xfree(cff->fontname);
- if (cff->name)
- cff_release_index(cff->name);
- if (cff->topdict)
- cff_release_dict(cff->topdict);
- if (cff->string)
- cff_release_index(cff->string);
- if (cff->gsubr)
- cff_release_index(cff->gsubr);
- if (cff->encoding)
- cff_release_encoding(cff->encoding);
- if (cff->charsets)
- cff_release_charsets(cff->charsets);
- if (cff->fdselect)
- cff_release_fdselect(cff->fdselect);
- if (cff->cstrings)
- cff_release_index(cff->cstrings);
- if (cff->fdarray) {
- for (i = 0; i < cff->num_fds; i++) {
- if (cff->fdarray[i])
- cff_release_dict(cff->fdarray[i]);
- }
- xfree(cff->fdarray);
- }
- if (cff->private) {
- for (i = 0; i < cff->num_fds; i++) {
- if (cff->private[i])
- cff_release_dict(cff->private[i]);
- }
- xfree(cff->private);
- }
- if (cff->subrs) {
- for (i = 0; i < cff->num_fds; i++) {
- if (cff->subrs[i])
- cff_release_index(cff->subrs[i]);
- }
- xfree(cff->subrs);
- }
- if (cff->_string)
- cff_release_index(cff->_string);
- xfree(cff);
- }
- return;
-}
-
-@ @c
-char *cff_get_name(cff_font * cff)
-{
- char *fontname;
- l_offset len;
- cff_index *idx;
- idx = cff->name;
- len = idx->offset[cff->index + 1] - idx->offset[cff->index];
- fontname = xmalloc((unsigned) (len + 1) * sizeof(char));
- memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len);
- fontname[len] = '\0';
- return fontname;
-}
-
-@ @c
-long cff_set_name(cff_font * cff, char *name)
-{
- cff_index *idx;
- if (strlen(name) > 127)
- normal_error("cff","FontName string length too large");
- if (cff->name)
- cff_release_index(cff->name);
- cff->name = idx = xcalloc(1, sizeof(cff_index));
- idx->count = 1;
- idx->offsize = 1;
- idx->offset = xmalloc(2 * sizeof(l_offset));
- (idx->offset)[0] = 1;
- (idx->offset)[1] = strlen(name) + 1;
- idx->data = xmalloc((unsigned) strlen(name) * sizeof(card8));
- memmove(idx->data, name, strlen(name)); /* no trailing |'\0'| */
- return (long) (5 + strlen(name));
-}
-
-long cff_put_header(cff_font * cff, card8 * dest, long destlen)
-{
- if (destlen < 4)
- normal_error("cff","not enough space available");
-
- *(dest++) = 1; /* cff->header_major; */
- *(dest++) = cff->header_minor;
- *(dest++) = 4;
- /*
- Additional data in between header and Name INDEX is ignored.
-
- We will set all offset (0) to a four-byte integer.
- */
- *(dest++) = 4;
- cff->header_offsize = 4;
- return 4;
-}
-
-@ @c
-#define CFF_PARSE_OK 0
-#define CFF_CFF_ERROR_PARSE_CFF_ERROR -1
-#define CFF_CFF_ERROR_STACK_OVERFLOW -2
-#define CFF_CFF_ERROR_STACK_UNDERFLOW -3
-#define CFF_CFF_ERROR_STACK_RANGECHECK -4
-
-#define DICT_ENTRY_MAX 16
-
-cff_dict *cff_new_dict(void)
-{
- cff_dict *dict;
- dict = xcalloc(1, sizeof(cff_dict));
- dict->max = DICT_ENTRY_MAX;
- dict->count = 0;
- dict->entries = xcalloc((unsigned) dict->max, sizeof(cff_dict_entry));
- return dict;
-}
-
-@ Operand stack: only numbers are stored (as double). Operand types are:
-
-\item number: double (integer or real)
-\item boolean: stored as a number
-\item SID: stored as a number
-\item array: array of numbers
-\item delta: array of numbers
-
- at c
-#define CFF_DICT_STACK_LIMIT 64
-static int stack_top = 0;
-static double arg_stack[CFF_DICT_STACK_LIMIT];
-
-@ CFF DICT encoding.
- at c
-#define CFF_LAST_DICT_OP1 26 /* 22 */
-#define CFF_LAST_DICT_OP2 39
-#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
-
-static struct {
- const char *opname;
- int argtype;
-} dict_operator[CFF_LAST_DICT_OP] = {
- { "version", CFF_TYPE_SID },
- { "Notice", CFF_TYPE_SID },
- { "FullName", CFF_TYPE_SID },
- { "FamilyName", CFF_TYPE_SID },
- { "Weight", CFF_TYPE_SID },
- { "FontBBox", CFF_TYPE_ARRAY },
- { "BlueValues", CFF_TYPE_DELTA },
- { "OtherBlues", CFF_TYPE_DELTA },
- { "FamilyBlues", CFF_TYPE_DELTA },
- { "FamilyOtherBlues", CFF_TYPE_DELTA },
- { "StdHW", CFF_TYPE_NUMBER },
- { "StdVW", CFF_TYPE_NUMBER },
- { NULL, -1 }, /* first byte of two-byte operator 12 */
- { "UniqueID", CFF_TYPE_NUMBER },
- { "XUID", CFF_TYPE_ARRAY },
- { "charset", CFF_TYPE_OFFSET },
- { "Encoding", CFF_TYPE_OFFSET },
- { "CharStrings", CFF_TYPE_OFFSET },
- { "Private", CFF_TYPE_SZOFF }, /* two numbers (size and offset) */
- { "Subrs", CFF_TYPE_OFFSET },
- { "defaultWidthX", CFF_TYPE_NUMBER },
- { "nominalWidthX", CFF_TYPE_NUMBER },
- { NULL, -1 },
- { NULL, -1 },
- { "vstore", CFF_TYPE_OFFSET }, /* cff2 */
- { "maxstack", CFF_TYPE_NUMBER }, /* cff2 */
- /* Here we start with operator 2 of 12 */
- { "Copyright", CFF_TYPE_SID },
- { "IsFixedPitch", CFF_TYPE_BOOLEAN },
- { "ItalicAngle", CFF_TYPE_NUMBER },
- { "UnderlinePosition", CFF_TYPE_NUMBER },
- { "UnderlineThickness", CFF_TYPE_NUMBER },
- { "PaintType", CFF_TYPE_NUMBER },
- { "CharstringType", CFF_TYPE_NUMBER },
- { "FontMatrix", CFF_TYPE_ARRAY },
- { "StrokeWidth", CFF_TYPE_NUMBER },
- { "BlueScale", CFF_TYPE_NUMBER },
- { "BlueShift", CFF_TYPE_NUMBER },
- { "BlueFuzz", CFF_TYPE_NUMBER },
- { "StemSnapH", CFF_TYPE_DELTA },
- { "StemSnapV", CFF_TYPE_DELTA },
- { "ForceBold", CFF_TYPE_BOOLEAN },
- { NULL, -1 },
- { NULL, -1 },
- { "LanguageGroup", CFF_TYPE_NUMBER },
- { "ExpansionFactor", CFF_TYPE_NUMBER },
- { "InitialRandomSeed", CFF_TYPE_NUMBER },
- { "SyntheticBase", CFF_TYPE_NUMBER },
- { "PostScript", CFF_TYPE_SID },
- { "BaseFontName", CFF_TYPE_SID },
- { "BaseFontBlend", CFF_TYPE_DELTA },
- { NULL, -1 },
- { NULL, -1 },
- { NULL, -1 },
- { NULL, -1 },
- { NULL, -1 },
- { NULL, -1 },
- { "ROS", CFF_TYPE_ROS },
- { "CIDFontVersion", CFF_TYPE_NUMBER },
- { "CIDFontRevision", CFF_TYPE_NUMBER },
- { "CIDFontType", CFF_TYPE_NUMBER },
- { "CIDCount", CFF_TYPE_NUMBER },
- { "UIDBase", CFF_TYPE_NUMBER },
- { "FDArray", CFF_TYPE_OFFSET },
- { "FDSelect", CFF_TYPE_OFFSET },
- { "FontName", CFF_TYPE_SID }
-};
-
-@ Parse DICT data
- at c
-static double get_integer(card8 ** data, card8 * endptr, int *status)
-{
- long result = 0;
- card8 b0, b1, b2;
-
- b0 = *(*data)++;
- if (b0 == 28 && *data < endptr - 2) { /* shortint */
- b1 = *(*data)++;
- b2 = *(*data)++;
- result = b1 * 256 + b2;
- if (result > 0x7fffL)
- result -= 0x10000L;
- } else if (b0 == 29 && *data < endptr - 4) { /* longint */
- int i;
- result = *(*data)++;
- if (result > 0x7f)
- result -= 0x100;
- for (i = 0; i < 3; i++) {
- result = result * 256 + (**data);
- *data += 1;
- }
- } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
- result = b0 - 139;
- } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
- b1 = *(*data)++;
- result = (b0 - 247) * 256 + b1 + 108;
- } else if (b0 >= 251 && b0 <= 254) {
- b1 = *(*data)++;
- result = -(b0 - 251) * 256 - b1 - 108;
- } else {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- }
-
- return (double) result;
-}
-
-@ Simply uses strtod
- at c
-static double get_real(card8 ** data, card8 * endptr, int *status)
-{
- double result = 0.0;
- int nibble = 0, pos = 0;
- int len = 0, fail = 0;
-
- if (**data != 30 || *data >= endptr - 1) {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- return 0.0;
- }
-
- *data += 1; /* skip first byte (30) */
-
- pos = 0;
- while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
- /* get nibble */
- if (pos % 2) {
- nibble = **data & 0x0f;
- *data += 1;
- } else {
- nibble = (**data >> 4) & 0x0f;
- }
- if (nibble >= 0x00 && nibble <= 0x09) {
- work_buffer[len++] = (char) (nibble + '0');
- } else if (nibble == 0x0a) { /* . */
- work_buffer[len++] = '.';
- } else if (nibble == 0x0b || nibble == 0x0c) { /* E, E- */
- work_buffer[len++] = 'e';
- if (nibble == 0x0c)
- work_buffer[len++] = '-';
- } else if (nibble == 0x0e) { /* `-' */
- work_buffer[len++] = '-';
- } else if (nibble == 0x0d) { /* skip */
- /* do nothing */
- } else if (nibble == 0x0f) { /* end */
- work_buffer[len++] = '\0';
- if (((pos % 2) == 0) && (**data != 0xff)) {
- fail = 1;
- }
- break;
- } else { /* invalid */
- fail = 1;
- }
- pos++;
- }
-
- /* returned values */
- if (fail || nibble != 0x0f) {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- } else {
- char *s;
- /* strtod sets errno for OVERFLOW and _maybe_ UNDERFLOW */
- /* but not for an invalid conversion (as for example if we try to convert "foo" in a double )*/
- /* At least in glib sets errno also for UNDERFLOW */
- /* We don't save/restore the prev. errno */
- errno=0;
- result = strtod(work_buffer, &s);
- if ( (result==0.0 && work_buffer==s) || errno ) {
- /* conversion is not possible */
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- }
- }
- return result;
-}
-
-@ operators
- at c
-static void add_dict(cff_dict * dict,
- card8 ** data, card8 * endptr, int *status)
-{
- int id, argtype, t;
-
- id = **data;
- if (id == 0x0c) {
- *data += 1;
- if (*data >= endptr ||
- (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- return;
- }
- } else if (id >= CFF_LAST_DICT_OP1) {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- return;
- }
-
- argtype = dict_operator[id].argtype;
- if (dict_operator[id].opname == NULL || argtype < 0) {
- *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
- return;
- }
-
- if (dict->count >= dict->max) {
- dict->max += DICT_ENTRY_MAX;
- /* not zeroed! */
- dict->entries =
- xrealloc(dict->entries,
- (unsigned) ((unsigned) dict->max *
- sizeof(cff_dict_entry)));
- }
-
- (dict->entries)[dict->count].id = id;
- (dict->entries)[dict->count].key = dict_operator[id].opname;
- if (argtype == CFF_TYPE_NUMBER ||
- argtype == CFF_TYPE_BOOLEAN ||
- argtype == CFF_TYPE_SID || argtype == CFF_TYPE_OFFSET) {
- /* check for underflow here, as exactly one operand is expected */
- if (stack_top < 1) {
- *status = CFF_CFF_ERROR_STACK_UNDERFLOW;
- return;
- }
- stack_top--;
- (dict->entries)[dict->count].count = 1;
- (dict->entries)[dict->count].values = xcalloc(1, sizeof(double));
- (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
- dict->count += 1;
- } else {
- /* just ignore operator if there were no operands provided;
- don't treat this as underflow (e.g. StemSnapV in TemporaLGCUni-Italic.otf) */
- if ((t = stack_top) > 0) {
- (dict->entries)[dict->count].count = stack_top;
- (dict->entries)[dict->count].values =
- xmalloc((unsigned) ((unsigned) stack_top * sizeof(double)));
- while (stack_top > 0) {
- stack_top--;
- (dict->entries)[dict->count].values[stack_top] =
- arg_stack[stack_top];
- }
- if (t > 3 && strcmp(dict_operator[id].opname, "FontMatrix") == 0) {
- /* reset FontMatrix to [0.001 * * 0.001 * *],
- fix mantis bug \# 0000200 (acroread "feature") */
- (dict->entries)[dict->count].values[0] = 0.001;
- (dict->entries)[dict->count].values[3] = 0.001;
- }
- dict->count += 1;
- }
- }
-
- *data += 1;
-
- return;
-}
-
-
-@ All operands are treated as number or array of numbers.
- Private: two numbers, size and offset
- ROS : three numbers, SID, SID, and a number
-
- at c
-cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
-{
- cff_dict *dict;
- int status = CFF_PARSE_OK;
- stack_top = 0;
- dict = cff_new_dict();
- while (data < endptr && status == CFF_PARSE_OK) {
- if (*data < CFF_LAST_DICT_OP1) { /* operator */
- add_dict(dict, &data, endptr, &status);
- } else if (*data == 30) { /* real - First byte of a sequence (variable) */
- if (stack_top < CFF_DICT_STACK_LIMIT) {
- arg_stack[stack_top] = get_real(&data, endptr, &status);
- stack_top++;
- } else {
- status = CFF_CFF_ERROR_STACK_OVERFLOW;
- }
- } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) { /* reserved */
- data++;
- } else { /* everything else are integer */
- if (stack_top < CFF_DICT_STACK_LIMIT) {
- arg_stack[stack_top] = get_integer(&data, endptr, &status);
- stack_top++;
- } else {
- status = CFF_CFF_ERROR_STACK_OVERFLOW;
- }
- }
- }
- if (status != CFF_PARSE_OK) {
- formatted_error("cff","parsing DICT failed (error=%d)", status);
- } else if (stack_top != 0) {
- normal_warning("cff","garbage in DICT data");
- stack_top = 0;
- }
- return dict;
-}
-
-@ @c
-int cff_dict_known(cff_dict * dict, const char *key)
-{
- int i;
- for (i = 0; i < dict->count; i++) {
- if (key && strcmp(key, (dict->entries)[i].key) == 0
- && (dict->entries)[i].count > 0)
- return 1;
- }
- return 0;
-}
-
-@ @c
-double cff_dict_get(cff_dict * dict, const char *key, int idx)
-{
- double value = 0.0;
- int i;
- assert(key && dict);
- for (i = 0; i < dict->count; i++) {
- if (strcmp(key, (dict->entries)[i].key) == 0) {
- if ((dict->entries)[i].count > idx)
- value = (dict->entries)[i].values[idx];
- else
- normal_error("cff","invalid index number");
- break;
- }
- }
- if (i == dict->count)
- formatted_error("cff","DICT entry '%s' not found", key);
- return value;
-}
-
-@ @c
-card8 cff_fdselect_lookup(cff_font * cff, card16 gid)
-{
- card8 fd = 0xff;
- cff_fdselect *fdsel;
-
- if (cff->fdselect == NULL)
- normal_error("cff","FDSelect not available");
-
- fdsel = cff->fdselect;
-
- if (gid >= cff->num_glyphs)
- normal_error("cff","invalid glyph index");
-
- switch (fdsel->format) {
- case 0:
- fd = fdsel->data.fds[gid];
- break;
- case 3:
- {
- if (gid == 0) {
- fd = (fdsel->data).ranges[0].fd;
- } else {
- card16 i;
- for (i = 1; i < (fdsel->num_entries); i++) {
- if (gid < (fdsel->data).ranges[i].first)
- break;
- }
- fd = (fdsel->data).ranges[i - 1].fd;
- }
- }
- break;
- default:
- normal_error("cff","invalid FDSelect format");
- break;
- }
-
- if (fd >= cff->num_fds)
- normal_error("cff","invalid Font DICT index");
-
- return fd;
-}
-
-@ @c
-long cff_read_subrs(cff_font * cff)
-{
- long len = 0;
- long offset;
- int i;
-
- if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdselect == NULL) {
- cff_read_fdselect(cff);
- }
-
- if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) {
- cff_read_fdarray(cff);
- }
-
- if (cff->private == NULL)
- cff_read_private(cff);
-
- if (cff->gsubr == NULL) {
- cff->offset = cff->gsubr_offset;
- cff->gsubr = cff_get_index(cff);
- }
-
- cff->subrs = xcalloc(cff->num_fds, sizeof(cff_index *));
- if (cff->flag & FONTTYPE_CIDFONT) {
- for (i = 0; i < cff->num_fds; i++) {
- if (cff->private[i] == NULL ||
- !cff_dict_known(cff->private[i], "Subrs")) {
- (cff->subrs)[i] = NULL;
- } else {
- offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
- offset += (long) cff_dict_get(cff->private[i], "Subrs", 0);
- cff->offset = (l_offset) offset;
- (cff->subrs)[i] = cff_get_index(cff);
- len += cff_index_size((cff->subrs)[i]);
- }
- }
- } else if (cff->private[0] == NULL || !cff_dict_known(cff->private[0], "Subrs")) {
- (cff->subrs)[0] = NULL;
- } else {
- offset = (long) cff_dict_get(cff->topdict, "Private", 1);
- offset += (long) cff_dict_get(cff->private[0], "Subrs", 0);
- cff->offset = (l_offset) offset;
- (cff->subrs)[0] = cff_get_index(cff);
- len += cff_index_size((cff->subrs)[0]);
- }
-
- return len;
-}
-
-@ @c
-long cff_read_fdarray(cff_font * cff)
-{
- long len = 0;
- cff_index *idx;
- long offset, size;
- card16 i;
-
- if (cff->topdict == NULL)
- normal_error("cff","top DICT not found");
-
- if (!(cff->flag & FONTTYPE_CIDFONT))
- return 0;
-
- /* must exist */
- offset = (long) cff_dict_get(cff->topdict, "FDArray", 0);
- cff->offset = (l_offset) offset;
- idx = cff_get_index(cff);
- cff->num_fds = (card8) idx->count;
- cff->fdarray = xmalloc((unsigned) (idx->count * sizeof(cff_dict *)));
- for (i = 0; i < idx->count; i++) {
- card8 *data = idx->data + (idx->offset)[i] - 1;
- size = (long) ((idx->offset)[i + 1] - (idx->offset)[i]);
- if (size > 0) {
- (cff->fdarray)[i] = cff_dict_unpack(data, data + size);
- } else {
- (cff->fdarray)[i] = NULL;
- }
- }
- len = cff_index_size(idx);
- cff_release_index(idx);
-
- return len;
-}
-
-
-@ @c
-long cff_read_private(cff_font * cff)
-{
- long len = 0;
- card8 *data;
- long offset, size;
-
- if (cff->flag & FONTTYPE_CIDFONT) {
- int i;
-
- if (cff->fdarray == NULL)
- cff_read_fdarray(cff);
-
- cff->private = xmalloc((unsigned) (cff->num_fds * sizeof(cff_dict *)));
- for (i = 0; i < cff->num_fds; i++) {
- if (cff->fdarray[i] != NULL &&
- cff_dict_known(cff->fdarray[i], "Private") &&
- (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0)) > 0) {
- offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
- cff->offset = (l_offset) offset;
- data = xmalloc((unsigned) size * sizeof(card8));
- memcpy(data, &cff->stream[cff->offset], (size_t) size);
- cff->offset = (l_offset) size;
- (cff->private)[i] = cff_dict_unpack(data, data + size);
- xfree(data);
- len += size;
- } else {
- (cff->private)[i] = NULL;
- }
- }
- } else {
- cff->num_fds = 1;
- cff->private = xmalloc(sizeof(cff_dict *));
- if (cff_dict_known(cff->topdict, "Private") &&
- (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) {
- offset = (long) cff_dict_get(cff->topdict, "Private", 1);
- cff->offset = (l_offset) offset;
- data = xmalloc((unsigned) size * sizeof(card8));
- memcpy(data, &cff->stream[cff->offset], (size_t) size);
- cff->offset = (l_offset) size;
- cff->private[0] = cff_dict_unpack(data, data + size);
- xfree(data);
- len += size;
- } else {
- (cff->private)[0] = NULL;
- len = 0;
- }
- }
-
- return len;
-}
-
-
-@ @c
-cff_font *read_cff(unsigned char *buf, long buflength, int n)
-{
- cff_font *cff;
- cff_index *idx;
- long offset;
-
- cff = xcalloc(1, sizeof(cff_font));
-
- cff->stream = buf;
- cff->stream_size = (l_offset) buflength;
- cff->index = n;
-
- cff->header_major = get_card8(cff);
- cff->header_minor = get_card8(cff);
- cff->header_hdr_size = get_card8(cff);
- if (cff->header_major == 2) {
- /* we have only one top dictionary */
- cff->header_offsize = get_card16(cff);
- } else {
- cff->header_offsize = get_card8(cff);
- if (cff->header_offsize < 1 || cff->header_offsize > 4) {
- normal_warning("cff","invalid offsize data (4)");
- cff_close(cff);
- return NULL;
- }
- }
- if (cff->header_major > 2) {
- formatted_warning("cff","major version %u not supported", cff->header_major);
- cff_close(cff);
- return NULL;
- }
- cff->offset = cff->header_hdr_size;
-
- /* Name INDEX */
- if (cff->header_major == 2) {
- cff->name = cff_empty_index(cff);
- } else {
- idx = cff_get_index(cff);
- if (n > idx->count - 1) {
- normal_warning("cff","invalid fontset index number");
- cff_close(cff);
- return NULL;
- }
- cff->name = idx;
- cff->fontname = cff_get_name(cff);
- }
-
- /* Top DICT INDEX */
- if (cff->header_major == 2) {
- /* we fake an index (just one entry) */
- idx = cff_get_index2(cff);
- } else {
- idx = cff_get_index(cff);
- }
-
- if (n > idx->count - 1) {
- normal_warning("cff","top DICT not exist");
- cff_close(cff);
- return NULL;
- }
- cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1,
- idx->data + idx->offset[n + 1] - 1);
- if (!cff->topdict) {
- normal_warning("cff","parsing top DICT data failed");
- cff_close(cff);
- return NULL;
- }
- cff_release_index(idx);
-
- if (cff_dict_known(cff->topdict, "CharstringType") &&
- cff_dict_get(cff->topdict, "CharstringType", 0) != 2) {
- normal_warning("cff","only type 2 charstrings supported");
- cff_close(cff);
- return NULL;
- }
-
- if (cff_dict_known(cff->topdict, "SyntheticBase")) {
- normal_warning("cff","synthetic font not supported");
- cff_close(cff);
- return NULL;
- }
-
- /* String INDEX */
- if (cff->header_major == 2) {
- // cff->string = cff_empty_index(cff);
- } else {
- cff->string = cff_get_index(cff);
- }
-
- /* offset to GSubr */
- cff->gsubr_offset = cff->offset;
-
- /* Number of glyphs */
- offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0);
- cff->offset = (l_offset) offset;
- cff->num_glyphs = get_card16(cff);
-
- /* Check for font type */
- if (cff_dict_known(cff->topdict, "ROS")) {
- cff->flag |= FONTTYPE_CIDFONT;
- } else {
- cff->flag |= FONTTYPE_FONT;
- }
-
- /* Check for encoding */
- if (cff_dict_known(cff->topdict, "Encoding")) {
- offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
- if (offset == 0) { /* predefined */
- cff->flag |= ENCODING_STANDARD;
- } else if (offset == 1) {
- cff->flag |= ENCODING_EXPERT;
- }
- } else {
- cff->flag |= ENCODING_STANDARD;
- }
-
- cff->offset = cff->gsubr_offset; /* seek back to GSubr */
-
- return cff;
-}
-
-@* write a cff for opentype.
-
-@ Pack DICT data
- at c
-static long pack_integer(card8 * dest, long destlen, long value)
-{
- long len = 0;
-
- if (value >= -107 && value <= 107) {
- if (destlen < 1)
- normal_error("cff","buffer overflow (1)");
- dest[0] = (card8) ((value + 139) & 0xff);
- len = 1;
- } else if (value >= 108 && value <= 1131) {
- if (destlen < 2)
- normal_error("cff","buffer overflow (2)");
- value = (long) 0xf700u + value - 108;
- dest[0] = (card8) ((value >> 8) & 0xff);
- dest[1] = (card8) (value & 0xff);
- len = 2;
- } else if (value >= -1131 && value <= -108) {
- if (destlen < 2)
- normal_error("cff","buffer overflow (3)");
- value = (long) 0xfb00u - value - 108;
- dest[0] = (card8) ((value >> 8) & 0xff);
- dest[1] = (card8) (value & 0xff);
- len = 2;
- } else if (value >= -32768 && value <= 32767) { /* shortint */
- if (destlen < 3)
- normal_error("cff","buffer overflow (4)");
- dest[0] = 28;
- dest[1] = (card8) ((value >> 8) & 0xff);
- dest[2] = (card8) (value & 0xff);
- len = 3;
- } else { /* longint */
- if (destlen < 5)
- normal_error("cff","buffer overflow (5)");
- dest[0] = 29;
- dest[1] = (card8) ((value >> 24) & 0xff);
- dest[2] = (card8) ((value >> 16) & 0xff);
- dest[3] = (card8) ((value >> 8) & 0xff);
- dest[4] = (card8) (value & 0xff);
- len = 5;
- }
- return len;
-}
-
-@ @c
-static long pack_real(card8 * dest, long destlen, double value)
-{
- long e;
- int i = 0, pos = 2;
- int res;
-#define CFF_REAL_MAX_LEN 17
-
- if (destlen < 2)
- normal_error("cff","buffer overflow (6)");
-
- dest[0] = 30;
-
- if (value == 0.0) {
- dest[1] = 0x0f;
- return 2;
- }
-
- if (value < 0.0) {
- dest[1] = 0xe0;
- value *= -1.0;
- pos++;
- }
-
- e = 0;
- if (value >= 10.0) {
- while (value >= 10.0) {
- value /= 10.0;
- e++;
- }
- } else if (value < 1.0) {
- while (value < 1.0) {
- value *= 10.0;
- e--;
- }
- }
-
- res=sprintf(work_buffer, "%1.14g", value);
- if (res<0) normal_error("cff","invalid conversion");
- if (res>CFF_REAL_MAX_LEN) res=CFF_REAL_MAX_LEN;
-
- for (i = 0; i < res; i++) {
- unsigned char ch = 0;
-
- if (work_buffer[i] == '\0') {
- /* res should prevent this. */
- /* normal_error("cff","cannot happen"); */
- break;
- } else if (work_buffer[i] == '.') {
- ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
- } else {
- normal_error("cff","invalid character");
- }
-
- if (destlen < pos / 2 + 1)
- normal_error("cff","buffer overflow (7)");
-
- if (pos % 2) {
- dest[pos / 2] = (card8) (dest[pos / 2] + ch);
- } else {
- dest[pos / 2] = (card8) (ch << 4);
- }
- pos++;
- }
-
- if (e > 0) {
- if (pos % 2) {
- dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b);
- } else {
- if (destlen < pos / 2 + 1)
- normal_error("cff","buffer overflow (8)");
- dest[pos / 2] = (card8) (0xb0);
- }
- pos++;
- } else if (e < 0) {
- if (pos % 2) {
- dest[pos / 2] = (card8) (dest[pos / 2] + 0x0c);
- } else {
- if (destlen < pos / 2 + 1)
- normal_error("cff","buffer overflow (9)");
- dest[pos / 2] = (card8) (0xc0);
- }
- e *= -1;
- pos++;
- }
-
- if (e != 0) {
- sprintf(work_buffer, "%ld", e);
- for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
- unsigned char ch = 0;
- if (work_buffer[i] == '\0') {
- break;
- } else if (work_buffer[i] == '.') {
- ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
- } else {
- normal_error("cff","invalid character");
- }
-
- if (destlen < pos / 2 + 1)
- normal_error("cff","buffer overflow (10)");
-
- if (pos % 2) {
- dest[pos / 2] = (card8) (dest[pos / 2] + ch);
- } else {
- dest[pos / 2] = (card8) (ch << 4);
- }
- pos++;
- }
- }
-
- if (pos % 2) {
- dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f);
- pos++;
- } else {
- if (destlen < pos / 2 + 1)
- normal_error("cff","buffer overflow (11)");
- dest[pos / 2] = (card8) (0xff);
- pos += 2;
- }
-
- return pos / 2;
-}
-
-@ @c
-static long cff_dict_put_number(double value,
- card8 * dest, long destlen, int type)
-{
- long len = 0;
- double nearint;
-
- nearint = floor(value + 0.5);
- /* set offset to longint */
- if (type == CFF_TYPE_OFFSET) {
- long lvalue;
- lvalue = (long) value;
- if (destlen < 5)
- normal_error("cff","buffer overflow (12)");
- dest[0] = 29;
- dest[1] = (card8) ((lvalue >> 24) & 0xff);
- dest[2] = (card8) ((lvalue >> 16) & 0xff);
- dest[3] = (card8) ((lvalue >> 8) & 0xff);
- dest[4] = (card8) (lvalue & 0xff);
- len = 5;
- } else if (value > CFF_INT_MAX || value < CFF_INT_MIN || (fabs(value - nearint) > 1.0e-5)) { /* real */
- len = pack_real(dest, destlen, value);
- } else { /* integer */
- len = pack_integer(dest, destlen, (long) nearint);
- }
-
- return len;
-}
-
-@ @c
-static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen)
-{
- long len = 0;
- int i, type, id;
-
- if (de->count > 0) {
- id = de->id;
- if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
- dict_operator[id].argtype == CFF_TYPE_SZOFF) {
- type = CFF_TYPE_OFFSET;
- } else {
- type = CFF_TYPE_NUMBER;
- }
- for (i = 0; i < de->count; i++) {
- len += cff_dict_put_number(de->values[i], dest + len, destlen - len, type);
- }
- if (id >= 0 && id < CFF_LAST_DICT_OP1) {
- if (len + 1 > destlen)
- normal_error("cff","buffer overflow (13)");
- dest[len++] = (card8) id;
- } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
- if (len + 2 > destlen)
- normal_error("cff","buffer overflow (14)");
- dest[len++] = 12;
- dest[len++] = (card8) (id - CFF_LAST_DICT_OP1);
- } else {
- normal_error("cff","invalid DICT operator ID");
- }
- }
-
- return len;
-}
-
-@ @c
-long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen)
-{
- long len = 0;
- int i;
-
- for (i = 0; i < dict->count; i++) {
- if (!strcmp(dict->entries[i].key, "ROS")) {
- len += put_dict_entry(&dict->entries[i], dest, destlen);
- break;
- }
- }
- for (i = 0; i < dict->count; i++) {
- if (strcmp(dict->entries[i].key, "ROS")) {
- len += put_dict_entry(&dict->entries[i], dest + len, destlen - len);
- }
- }
-
- return len;
-}
-
-@ @c
-void cff_dict_add(cff_dict * dict, const char *key, int count)
-{
- int id, i;
-
- for (id = 0; id < CFF_LAST_DICT_OP; id++) {
- if (key && dict_operator[id].opname &&
- strcmp(dict_operator[id].opname, key) == 0)
- break;
- }
-
- if (id == CFF_LAST_DICT_OP)
- normal_error("cff","unknown DICT operator");
-
- for (i = 0; i < dict->count; i++) {
- if ((dict->entries)[i].id == id) {
- if ((dict->entries)[i].count != count)
- normal_error("cff","inconsistent DICT argument number");
- return;
- }
- }
-
- if (dict->count + 1 >= dict->max) {
- dict->max += 8;
- dict->entries =
- xrealloc(dict->entries,
- (unsigned) ((unsigned) dict->max *
- sizeof(cff_dict_entry)));
- }
-
- (dict->entries)[dict->count].id = id;
- (dict->entries)[dict->count].key = dict_operator[id].opname;
- (dict->entries)[dict->count].count = count;
- if (count > 0) {
- (dict->entries)[dict->count].values =
- xcalloc((unsigned) count, sizeof(double));
- } else {
- (dict->entries)[dict->count].values = NULL;
- }
- dict->count += 1;
-
- return;
-}
-
-@ @c
-void cff_dict_remove(cff_dict * dict, const char *key)
-{
- int i;
- for (i = 0; i < dict->count; i++) {
- if (key && strcmp(key, (dict->entries)[i].key) == 0) {
- (dict->entries)[i].count = 0;
- xfree((dict->entries)[i].values);
- }
- }
-}
-
-@ @c
-void cff_dict_set(cff_dict * dict, const char *key, int idx, double value)
-{
- int i;
-
- assert(dict && key);
-
- for (i = 0; i < dict->count; i++) {
- if (strcmp(key, (dict->entries)[i].key) == 0) {
- if ((dict->entries)[i].count > idx)
- (dict->entries)[i].values[idx] = value;
- else
- normal_error("cff","invalid index number");
- break;
- }
- }
-
- if (i == dict->count)
- formatted_error("cff","DICT entry '%s' not found", key);
-}
-
-
-@ Strings
- at c
-char *cff_get_string(cff_font * cff, s_SID id)
-{
- char *result = NULL;
- size_t len;
-
- if (id < CFF_STDSTR_MAX) {
- len = strlen(cff_stdstr[id]);
- result = xmalloc((unsigned) (len + 1) * sizeof(char));
- memcpy(result, cff_stdstr[id], len);
- result[len] = '\0';
- } else if (cff && cff->string) {
- cff_index *strings = cff->string;
- id = (s_SID) (id - CFF_STDSTR_MAX);
- if (id < strings->count) {
- len = (strings->offset)[id + 1] - (strings->offset)[id];
- result = xmalloc((unsigned) (len + 1) * sizeof(char));
- memmove(result, strings->data + (strings->offset)[id] - 1, len);
- result[len] = '\0';
- }
- }
-
- return result;
-}
-
-@ @c
-long cff_get_sid(cff_font * cff, const char *str)
-{
- card16 i;
-
- if (!cff || !str)
- return -1;
-
- /* I search String INDEX first. */
- if (cff && cff->string) {
- cff_index *idx = cff->string;
- for (i = 0; i < idx->count; i++) {
- if (strlen(str) == (idx->offset)[i + 1] - (idx->offset)[i] &&
- !memcmp(str, (idx->data) + (idx->offset)[i] - 1, strlen(str)))
- return (i + CFF_STDSTR_MAX);
- }
- }
-
- for (i = 0; i < CFF_STDSTR_MAX; i++) {
- if (!strcmp(str, cff_stdstr[i]))
- return i;
- }
-
- return -1;
-}
-
-@ @c
-void cff_update_string(cff_font * cff)
-{
- if (cff == NULL)
- normal_error("cff","CFF font not opened");
- if (cff->string)
- cff_release_index(cff->string);
- cff->string = cff->_string;
- cff->_string = NULL;
-}
-
-@ @c
-s_SID cff_add_string(cff_font * cff, const char *str)
-{
- card16 idx;
- cff_index *strings;
- l_offset offset, size;
- if (cff == NULL) {
- normal_error("cff","CFF font not opened");
- }
- if (cff->_string == NULL) {
- cff->_string = cff_new_index(0);
- }
- strings = cff->_string;
- for (idx = 0; idx < strings->count; idx++) {
- size = strings->offset[idx + 1] - strings->offset[idx];
- offset = strings->offset[idx];
- if (size == strlen(str) && !memcmp(strings->data + offset - 1, str, strlen(str))) {
- return (s_SID) (idx + CFF_STDSTR_MAX);
- }
- }
- for (idx = 0; idx < CFF_STDSTR_MAX; idx++) {
- if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str)) {
- return idx;
- }
- }
- offset = (strings->count > 0) ? strings->offset[strings->count] : 1;
- strings->offset = xrealloc(strings->offset, (unsigned) (((unsigned) strings->count + 2) * sizeof(l_offset)));
- if (strings->count == 0)
- strings->offset[0] = 1;
- idx = strings->count;
- strings->count = (card16) (strings->count + 1);
- strings->offset[strings->count] = offset + strlen(str);
- strings->data = xrealloc(strings->data, (unsigned) ((offset + strlen(str) - 1) * sizeof(card8)));
- memcpy(strings->data + offset - 1, str, strlen(str));
- return (s_SID) (idx + CFF_STDSTR_MAX);
-}
-
-@ @c
-void cff_dict_update(cff_dict * dict, cff_font * cff)
-{
- int i;
- for (i = 0; i < dict->count; i++) {
- if ((dict->entries)[i].count > 0) {
- char *str;
- int id;
- id = (dict->entries)[i].id;
- if (dict_operator[id].argtype == CFF_TYPE_SID) {
- str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
- if (str != NULL) {
- (dict->entries)[i].values[0] = cff_add_string(cff, str);
- xfree(str);
- }
- } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
- str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
- if (str != NULL) {
- (dict->entries)[i].values[0] = cff_add_string(cff, str);
- xfree(str);
- }
- str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[1]);
- if (str != NULL) {
- (dict->entries)[i].values[1] = cff_add_string(cff, str);
- xfree(str);
- }
- }
- }
- }
-}
-
-@ charsets
- at c
-long cff_read_charsets(cff_font * cff)
-{
- cff_charsets *charset;
- long offset, length;
- card16 count, i;
-
- if (cff->topdict == NULL)
- normal_error("cff","top DICT not available");
-
- if (!cff_dict_known(cff->topdict, "charset")) {
- cff->flag |= CHARSETS_ISOADOBE;
- cff->charsets = NULL;
- return 0;
- }
-
- offset = (long) cff_dict_get(cff->topdict, "charset", 0);
-
- if (offset == 0) { /* predefined */
- cff->flag |= CHARSETS_ISOADOBE;
- cff->charsets = NULL;
- return 0;
- } else if (offset == 1) {
- cff->flag |= CHARSETS_EXPERT;
- cff->charsets = NULL;
- return 0;
- } else if (offset == 2) {
- cff->flag |= CHARSETS_EXPSUB;
- cff->charsets = NULL;
- return 0;
- }
-
- cff->offset = (l_offset) offset;
- cff->charsets = charset = xcalloc(1, sizeof(cff_charsets));
- charset->format = get_card8(cff);
- charset->num_entries = 0;
-
- count = (card16) (cff->num_glyphs - 1);
- length = 1;
-
- /* Not sure. Not well documented. */
- switch (charset->format) {
- case 0:
- charset->num_entries = (card16) (cff->num_glyphs - 1); /* no .notdef */
- charset->data.glyphs =
- xmalloc((unsigned) (charset->num_entries * sizeof(s_SID)));
- length += (charset->num_entries) * 2;
- for (i = 0; i < (charset->num_entries); i++) {
- charset->data.glyphs[i] = get_card16(cff);
- }
- count = 0;
- break;
- case 1:
- {
- cff_range1 *ranges = NULL;
- while (count > 0 && charset->num_entries < cff->num_glyphs) {
- ranges =
- xrealloc(ranges,
- (unsigned) (((unsigned) charset->num_entries +
- 1) * sizeof(cff_range1)));
- ranges[charset->num_entries].first = get_card16(cff);
- ranges[charset->num_entries].n_left = get_card8(cff);
- count = (card16) (count - ranges[charset->num_entries].n_left + 1); /* no-overrap */
- charset->num_entries++;
- charset->data.range1 = ranges;
- }
- length += (charset->num_entries) * 3;
- }
- break;
- case 2:
- {
- cff_range2 *ranges = NULL;
- while (count > 0 && charset->num_entries < cff->num_glyphs) {
- ranges =
- xrealloc(ranges,
- (unsigned) (((unsigned) charset->num_entries +
- 1) * sizeof(cff_range2)));
- ranges[charset->num_entries].first = get_card16(cff);
- ranges[charset->num_entries].n_left = get_card16(cff);
- count = (card16) (count - (ranges[charset->num_entries].n_left + 1)); /* non-overrapping */
- charset->num_entries++;
- }
- charset->data.range2 = ranges;
- length += (charset->num_entries) * 4;
- }
- break;
- default:
- xfree(charset);
- normal_error("cff","unknown charset format");
- break;
- }
-
- if (count > 0) {
- normal_warning("cff","charset data possibly broken (too many glyphs)");
- }
-
- return length;
-}
-
-@ @c
-long cff_pack_charsets(cff_font * cff, card8 * dest, long destlen)
-{
- long len = 0;
- card16 i;
- cff_charsets *charset;
-
- if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL)
- return 0;
-
- if (destlen < 1)
- normal_error("cff","buffer overflow (15)");
-
- charset = cff->charsets;
-
- dest[len++] = charset->format;
- switch (charset->format) {
- case 0:
- if (destlen < len + (charset->num_entries) * 2)
- normal_error("cff","buffer overflow (16)");
- for (i = 0; i < (charset->num_entries); i++) {
- s_SID sid = (charset->data).glyphs[i]; /* or CID */
- dest[len++] = (card8) ((sid >> 8) & 0xff);
- dest[len++] = (card8) (sid & 0xff);
- }
- break;
- case 1:
- {
- if (destlen < len + (charset->num_entries) * 3)
- normal_error("cff","buffer overflow (17)");
- for (i = 0; i < (charset->num_entries); i++) {
- dest[len++] = (card8) (((charset->data).range1[i].first >> 8) & 0xff);
- dest[len++] = (card8) ((charset->data).range1[i].first & 0xff);
- dest[len++] = (card8) ((charset->data).range1[i].n_left);
- }
- }
- break;
- case 2:
- {
- if (destlen < len + (charset->num_entries) * 4)
- normal_error("cff","buffer overflow (18)");
- for (i = 0; i < (charset->num_entries); i++) {
- dest[len++] = (card8) (((charset->data).range2[i].first >> 8) & 0xff);
- dest[len++] = (card8) ((charset->data).range2[i].first & 0xff);
- dest[len++] = (card8) (((charset->data).range2[i].n_left >> 8) & 0xff);
- dest[len++] = (card8) ((charset->data).range2[i].n_left & 0xff);
- }
- }
- break;
- default:
- normal_error("cff","unknown charset format");
- break;
- }
-
- return len;
-}
-
-
-
-@* Type 2 Charstring support.
-
-Decode and encode Type 2 charstring
-
-All local/global subroutine calls in a given charstring is replace by the
-content of subroutine charstrings. We do this because some PostScript RIP
-may have problems with sparse subroutine array. Workaround for this is to
-re-order subroutine array so that no gap appears in the subroutine array,
-or put dummy charstrings that contains only `return' in the gap. However,
-re-ordering of subroutine is rather difficult for Type 2 charstrings due
-to the bias which depends on the total number of subroutines. Replacing
-callgsubr/callsubr calls with the content of the corresponding subroutine
-charstring may be more efficient than putting dummy subroutines in the
-case of subsetted font. Adobe distiller seems doing same thing.
-
-And also note that subroutine numbers within subroutines can depend on the
-content of operand stack as follows:
-
-\.{ ... l m callsubr << subr \#(m+bias): n add callsubr >> ...}
-
-I've not implemented the `random' operator which generates a pseudo-random
-number in the range (0, 1] and push them into argument stack.
-How pseudo-random sequences are generated is not documented in the Type 2
-charstring spec..
-
- at c
-#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser"
-#define CS_TYPE2_DEBUG 5
-
-/* decoder/encoder status codes */
-#define CS_BUFFER_CFF_ERROR -3
-#define CS_STACK_CFF_ERROR -2
-#define CS_PARSE_CFF_ERROR -1
-#define CS_PARSE_OK 0
-#define CS_PARSE_END 1
-#define CS_SUBR_RETURN 2
-#define CS_CHAR_END 3
-
-static int status = CS_PARSE_CFF_ERROR;
-
-#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_CFF_ERROR ; return ; }}
-#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_CFF_ERROR ; return ; }}
-#define NEED(a,b) {if ((a) < (b)) { status = CS_STACK_CFF_ERROR ; return ; }}
-
-/* hintmask and cntrmask need number of stem zones */
-static int num_stems = 0;
-static int phase = 0;
-
-/* subroutine nesting */
-static int cs2_nest = 0;
-
-/* advance width */
-static int have_width = 0;
-static double width = 0.0;
-
-@ Standard Encoding Accented Characters: Optional four arguments for
-endchar. See, CFF spec., p.35. This is obsolete feature and is no longer
-supported.
- at c
-#if 0
-/* adx ady bchar achar endchar */
-static double seac[4] = { 0.0, 0.0, 0.0, 0.0 };
-#endif
-
-@ Operand stack and Transient array
- at c
-static int cs2_stack_top = 0;
-static double cs2_arg_stack[CS_ARG_STACK_MAX];
-static double trn_array[CS_TRANS_ARRAY_MAX];
-
-@ Type 2 CharString encoding
- at c
-
-/*
- 1-byte CharString operators:
- |cs_escape| is first byte of two-byte operator
-*/
-
-/* RESERVED 0 */
-#define cs_hstem 1
-/* RESERVED 2 */
-#define cs_vstem 3
-#define cs_vmoveto 4
-#define cs_rlineto 5
-#define cs_hlineto 6
-#define cs_vlineto 7
-#define cs_rrcurveto 8
-/* |cs_closepath| 9 : TYPE1 */
-#define cs_callsubr 10
-#define cs_return 11
-#define cs_escape 12
-/* |cs_hsbw| 13 : TYPE1 */
-#define cs_endchar 14
-#define cs_setvsindex 15
-#define cs_blend 16
-/* RESERVED 17 */
-#define cs_hstemhm 18
-#define cs_hintmask 19
-#define cs_cntrmask 20
-#define cs_rmoveto 21
-#define cs_hmoveto 22
-#define cs_vstemhm 23
-#define cs_rcurveline 24
-#define cs_rlinecurve 25
-#define cs_vvcurveto 26
-#define cs_hhcurveto 27
-/* SHORTINT 28 : first byte of shortint*/
-#define cs_callgsubr 29
-#define cs_vhcurveto 30
-#define cs_hvcurveto 31
-
-/*
- 2-byte CharString operaotrs:
- "dotsection" is obsoleted in Type 2 charstring.
- */
-
-#define cs_dotsection 0
-/* |cs_vstem3| 1 : TYPE1 */
-/* |cs_hstem3| 2 : TYPE1 */
-#define cs_and 3
-#define cs_or 4
-#define cs_not 5
-/* |cs_seac| 6 : TYPE1 */
-/* |cs_sbw| 7 : TYPE1 */
-/* RESERVED 8 */
-#define cs_abs 9
-#define cs_add 10
-#define cs_sub 11
-#define cs_div 12
-/* RESERVED 13 */
-#define cs_neg 14
-#define cs_eq 15
-/* |cs_callothersubr| 16 : TYPE1 */
-/* |cs_pop| 17 : TYPE1 */
-#define cs_drop 18
-/* RESERVED 19 */
-#define cs_put 20
-#define cs_get 21
-#define cs_ifelse 22
-#define cs_random 23
-#define cs_mul 24
-/* RESERVED 25 */
-#define cs_sqrt 26
-#define cs_dup 27
-#define cs_exch 28
-#define cs_index 29
-#define cs_roll 30
-/* |cs_setcurrentpoint| 31 : TYPE1 */
-/* RESERVED 32 */
-/* RESERVED 33 */
-#define cs_hflex 34
-#define cs_flex 35
-#define cs_hflex1 36
-#define cs_flex1 37
-
-@ |clear_stack()| put all operands sotred in operand stack to dest.
- at c
-static void clear_stack(card8 ** dest, card8 * limit)
-{
- int i;
-
- for (i = 0; i < cs2_stack_top; i++) {
- double value;
- long ivalue;
- value = cs2_arg_stack[i];
- /* Nearest integer value */
- ivalue = (long) floor(value + 0.5);
- if (value >= 0x8000L || value <= (-0x8000L - 1)) {
- /*
- This number cannot be represented as a single operand. We must
- use `a b mul ...' or `a c div' to represent large values.
- */
- normal_error("cff","argument value too large (this is bug)");
- } else if (fabs(value - (double) ivalue) > 3.0e-5) {
- /* 16.16-bit signed fixed value */
- DST_NEED(limit, *dest + 5);
- *(*dest)++ = 255;
- ivalue = (long) floor(value); /* mantissa */
- *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
- *(*dest)++ = (card8) (ivalue & 0xff);
- ivalue = (long) ((value - (double) ivalue) * 0x10000l); /* fraction */
- *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
- *(*dest)++ = (card8) (ivalue & 0xff);
- /* Everything else are integers. */
- } else if (ivalue >= -107 && ivalue <= 107) {
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = (card8) (ivalue + 139);
- } else if (ivalue >= 108 && ivalue <= 1131) {
- DST_NEED(limit, *dest + 2);
- ivalue = (long) 0xf700u + ivalue - 108;
- *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
- *(*dest)++ = (card8) (ivalue & 0xff);
- } else if (ivalue >= -1131 && ivalue <= -108) {
- DST_NEED(limit, *dest + 2);
- ivalue = (long) 0xfb00u - ivalue - 108;
- *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
- *(*dest)++ = (card8) (ivalue & 0xff);
- } else if (ivalue >= -32768 && ivalue <= 32767) {
- /* shortint */
- DST_NEED(limit, *dest + 3);
- *(*dest)++ = 28;
- *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
- *(*dest)++ = (card8) ((ivalue) & 0xff);
- } else { /* Shouldn't come here */
- normal_error("cff","unexpected error");
- }
- }
- cs2_stack_top = 0; /* clear stack */
- return;
-}
-
-@ Single byte operators: Path construction, Operator for finishing a
-path, Hint operators. Phases:
-
-\item 0: inital state
-\item 1: hint declaration, first stack-clearing operator appeared
-\item 2: in path construction
-
- at c
-/*
-static int vsindex = 0;
-static int blends = 0;
-static int regions = 5;
-*/
-
-static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
-{
- card8 op = **data;
-
- *data += 1;
-
- switch (op) {
- case cs_hstemhm:
- case cs_vstemhm:
- /* charstring may have hintmask if above operator have seen */
- case cs_hstem:
- case cs_vstem:
- if (phase == 0 && (cs2_stack_top % 2)) {
- have_width = 1;
- width = cs2_arg_stack[0];
- }
- num_stems += cs2_stack_top / 2;
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- phase = 1;
- break;
- case cs_hintmask:
- case cs_cntrmask:
- if (phase < 2) {
- if (phase == 0 && (cs2_stack_top % 2)) {
- have_width = 1;
- width = cs2_arg_stack[0];
- }
- num_stems += cs2_stack_top / 2;
- }
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- if (num_stems > 0) {
- int masklen = (num_stems + 7) / 8;
- DST_NEED(limit, *dest + masklen);
- SRC_NEED(endptr, *data + masklen);
- memmove(*dest, *data, (size_t) masklen);
- *data += masklen;
- *dest += masklen;
- }
- phase = 2;
- break;
- case cs_rmoveto:
- if (phase == 0 && (cs2_stack_top % 2)) {
- have_width = 1;
- width = cs2_arg_stack[0];
- }
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- phase = 2;
- break;
- case cs_hmoveto:
- case cs_vmoveto:
- if (phase == 0 && (cs2_stack_top % 2) == 0) {
- have_width = 1;
- width = cs2_arg_stack[0];
- }
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- phase = 2;
- break;
- case cs_endchar:
- if (cs2_stack_top == 1) {
- have_width = 1;
- width = cs2_arg_stack[0];
- clear_stack(dest, limit);
- } else if (cs2_stack_top == 4 || cs2_stack_top == 5) {
- normal_warning("cff","'seac' character deprecated in type 2 charstring");
- status = CS_PARSE_CFF_ERROR;
- return;
- } else if (cs2_stack_top > 0) {
- normal_warning("cff","operand stack not empty");
- }
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- status = CS_CHAR_END;
- break;
- /* above operators are candidate for first stack-clearing operator */
- case cs_setvsindex:
- /*
- vsindex = cs2_arg_stack[cs2_stack_top-1];
- cs2_stack_top -= 1;
- */
- normal_warning("cff2","unsupported setvindex operator");
- status = CS_PARSE_CFF_ERROR;
- break;
- case cs_blend:
- /*
- blends = cs2_arg_stack[cs2_stack_top-1];
- cs2_stack_top -= 1;
- cs2_stack_top -= blends * regions ;
- */
- normal_warning("cff2","unsupported blend operator");
- status = CS_PARSE_CFF_ERROR;
- break;
- case cs_rlineto:
- case cs_hlineto:
- case cs_vlineto:
- case cs_rrcurveto:
- case cs_rcurveline:
- case cs_rlinecurve:
- case cs_vvcurveto:
- case cs_hhcurveto:
- case cs_vhcurveto:
- case cs_hvcurveto:
- if (phase < 2) {
- normal_warning("cff","broken type 2 charstring");
- status = CS_PARSE_CFF_ERROR;
- return;
- }
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 1);
- *(*dest)++ = op;
- break;
- /* all operotors above are stack-clearing operator */
- /* no output */
- case cs_return:
- case cs_callgsubr:
- case cs_callsubr:
- normal_error("cff","unexpected call(g)subr/return");
- break;
- default:
- /* no-op ? */
- formatted_warning("cff","%s: unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op);
- status = CS_PARSE_CFF_ERROR;
- break;
- }
- return;
-}
-
-@ Double byte operators: Flex, arithmetic, conditional, and storage operators.
-The following operators are not supported: random: How random ?
-
- at c
-static void do_operator2(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
-{
- card8 op;
-
- *data += 1;
-
- SRC_NEED(endptr, *data + 1);
-
- op = **data;
- *data += 1;
-
- switch (op) {
- case cs_dotsection: /* deprecated */
- normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring");
- status = CS_PARSE_CFF_ERROR;
- return;
- break;
- case cs_hflex:
- case cs_flex:
- case cs_hflex1:
- case cs_flex1:
- if (phase < 2) {
- formatted_warning("cff","%s: broken type 2 charstring", CS_TYPE2_DEBUG_STR);
- status = CS_PARSE_CFF_ERROR;
- return;
- }
- clear_stack(dest, limit);
- DST_NEED(limit, *dest + 2);
- *(*dest)++ = cs_escape;
- *(*dest)++ = op;
- break;
- /* all operator above are stack-clearing */
- /* no output */
- case cs_and:
- NEED(cs2_stack_top, 2);
- cs2_stack_top--;
- if (cs2_arg_stack[cs2_stack_top] && cs2_arg_stack[cs2_stack_top - 1]) {
- cs2_arg_stack[cs2_stack_top - 1] = 1.0;
- } else {
- cs2_arg_stack[cs2_stack_top - 1] = 0.0;
- }
- break;
- case cs_or:
- NEED(cs2_stack_top, 2);
- cs2_stack_top--;
- if (cs2_arg_stack[cs2_stack_top] || cs2_arg_stack[cs2_stack_top - 1]) {
- cs2_arg_stack[cs2_stack_top - 1] = 1.0;
- } else {
- cs2_arg_stack[cs2_stack_top - 1] = 0.0;
- }
- break;
- case cs_not:
- NEED(cs2_stack_top, 1);
- if (cs2_arg_stack[cs2_stack_top - 1]) {
- cs2_arg_stack[cs2_stack_top - 1] = 0.0;
- } else {
- cs2_arg_stack[cs2_stack_top - 1] = 1.0;
- }
- break;
- case cs_abs:
- NEED(cs2_stack_top, 1);
- cs2_arg_stack[cs2_stack_top - 1] =
- fabs(cs2_arg_stack[cs2_stack_top - 1]);
- break;
- case cs_add:
- NEED(cs2_stack_top, 2);
- cs2_arg_stack[cs2_stack_top - 2] += cs2_arg_stack[cs2_stack_top - 1];
- cs2_stack_top--;
- break;
- case cs_sub:
- NEED(cs2_stack_top, 2);
- cs2_arg_stack[cs2_stack_top - 2] -= cs2_arg_stack[cs2_stack_top - 1];
- cs2_stack_top--;
- break;
- case cs_div: /* doesn't check overflow */
- NEED(cs2_stack_top, 2);
- cs2_arg_stack[cs2_stack_top - 2] /= cs2_arg_stack[cs2_stack_top - 1];
- cs2_stack_top--;
- break;
- case cs_neg:
- NEED(cs2_stack_top, 1);
- cs2_arg_stack[cs2_stack_top - 1] *= -1.0;
- break;
- case cs_eq:
- NEED(cs2_stack_top, 2);
- cs2_stack_top--;
- if (cs2_arg_stack[cs2_stack_top] == cs2_arg_stack[cs2_stack_top - 1]) {
- cs2_arg_stack[cs2_stack_top - 1] = 1.0;
- } else {
- cs2_arg_stack[cs2_stack_top - 1] = 0.0;
- }
- break;
- case cs_drop:
- NEED(cs2_stack_top, 1);
- cs2_stack_top--;
- break;
- case cs_put:
- NEED(cs2_stack_top, 2);
- {
- int idx = (int) cs2_arg_stack[--cs2_stack_top];
- NEED(CS_TRANS_ARRAY_MAX, idx);
- trn_array[idx] = cs2_arg_stack[--cs2_stack_top];
- }
- break;
- case cs_get:
- NEED(cs2_stack_top, 1);
- {
- int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
- NEED(CS_TRANS_ARRAY_MAX, idx);
- cs2_arg_stack[cs2_stack_top - 1] = trn_array[idx];
- }
- break;
- case cs_ifelse:
- NEED(cs2_stack_top, 4);
- cs2_stack_top -= 3;
- if (cs2_arg_stack[cs2_stack_top + 1] > cs2_arg_stack[cs2_stack_top + 2]) {
- cs2_arg_stack[cs2_stack_top - 1] = cs2_arg_stack[cs2_stack_top];
- }
- break;
- case cs_mul:
- NEED(cs2_stack_top, 2);
- cs2_arg_stack[cs2_stack_top - 2] =
- cs2_arg_stack[cs2_stack_top - 2] * cs2_arg_stack[cs2_stack_top - 1];
- cs2_stack_top--;
- break;
- case cs_sqrt:
- NEED(cs2_stack_top, 1);
- cs2_arg_stack[cs2_stack_top - 1] =
- sqrt(cs2_arg_stack[cs2_stack_top - 1]);
- break;
- case cs_dup:
- NEED(cs2_stack_top, 1);
- NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
- cs2_arg_stack[cs2_stack_top] = cs2_arg_stack[cs2_stack_top - 1];
- cs2_stack_top++;
- break;
- case cs_exch:
- NEED(cs2_stack_top, 2);
- {
- double save = cs2_arg_stack[cs2_stack_top - 2];
- cs2_arg_stack[cs2_stack_top - 2] = cs2_arg_stack[cs2_stack_top - 1];
- cs2_arg_stack[cs2_stack_top - 1] = save;
- }
- break;
- case cs_index:
- NEED(cs2_stack_top, 2); /* need two arguments at least */
- {
- int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
- if (idx < 0) {
- cs2_arg_stack[cs2_stack_top - 1] =
- cs2_arg_stack[cs2_stack_top - 2];
- } else {
- NEED(cs2_stack_top, idx + 2);
- cs2_arg_stack[cs2_stack_top - 1] =
- cs2_arg_stack[cs2_stack_top - idx - 2];
- }
- }
- break;
- case cs_roll:
- NEED(cs2_stack_top, 2);
- {
- int N, J;
- J = (int) cs2_arg_stack[--cs2_stack_top];
- N = (int) cs2_arg_stack[--cs2_stack_top];
- NEED(cs2_stack_top, N);
- if (J > 0) {
- J = J % N;
- while (J-- > 0) {
- double save = cs2_arg_stack[cs2_stack_top - 1];
- int i = cs2_stack_top - 1;
- while (i > cs2_stack_top - N) {
- cs2_arg_stack[i] = cs2_arg_stack[i - 1];
- i--;
- }
- cs2_arg_stack[i] = save;
- }
- } else {
- J = (-J) % N;
- while (J-- > 0) {
- double save = cs2_arg_stack[cs2_stack_top - N];
- int i = cs2_stack_top - N;
- while (i < cs2_stack_top - 1) {
- cs2_arg_stack[i] = cs2_arg_stack[i + 1];
- i++;
- }
- cs2_arg_stack[i] = save;
- }
- }
- }
- break;
- case cs_random:
- formatted_warning("cff","%s: Charstring operator 'random' found.", CS_TYPE2_DEBUG_STR);
- NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
- cs2_arg_stack[cs2_stack_top++] = 1.0;
- break;
- default:
- /* no-op ? */
- formatted_warning("cff","%s: unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op);
- status = CS_PARSE_CFF_ERROR;
- break;
- }
- return;
-}
-
-@ integer: exactly the same as the DICT encoding (except 29)
- at c
-static void cs2_get_integer(card8 ** data, card8 * endptr)
-{
- long result = 0;
- card8 b0 = **data, b1, b2;
-
- *data += 1;
-
- if (b0 == 28) { /* shortint */
- SRC_NEED(endptr, *data + 2);
- b1 = **data;
- b2 = *(*data + 1);
- result = b1 * 256 + b2;
- if (result > 0x7fff)
- result -= 0x10000L;
- *data += 2;
- } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
- result = b0 - 139;
- } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
- SRC_NEED(endptr, *data + 1);
- b1 = **data;
- result = (b0 - 247) * 256 + b1 + 108;
- *data += 1;
- } else if (b0 >= 251 && b0 <= 254) {
- SRC_NEED(endptr, *data + 1);
- b1 = **data;
- result = -(b0 - 251) * 256 - b1 - 108;
- *data += 1;
- } else {
- status = CS_PARSE_CFF_ERROR;
- return;
- }
- NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
- cs2_arg_stack[cs2_stack_top++] = (double) result;
- return;
-}
-
-@ Signed 16.16-bits fixed number for Type 2 charstring encoding
- at c
-static void get_fixed(card8 ** data, card8 * endptr)
-{
- long ivalue;
- double rvalue;
-
- *data += 1;
-
- SRC_NEED(endptr, *data + 4);
-
- ivalue = *(*data) * 0x100 + *(*data + 1);
- rvalue = (double) ((ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue);
- ivalue = *(*data + 2) * 0x100 + *(*data + 3);
- rvalue += ((double) ivalue) / 0x10000L;
-
- NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
- cs2_arg_stack[cs2_stack_top++] = rvalue;
- *data += 4;
-
- return;
-}
-
-@ Subroutines: the bias for subroutine number is introduced in type 2
-charstrings.
-
-\item subr: set to a pointer to the subroutine charstring.
-\item len: set to the length of subroutine charstring.
-\item |subr_idx|: CFF INDEX data that contains subroutines.
-\item id: biased subroutine number.
-
- at c
-static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id)
-{
- card16 count;
-
- if (subr_idx == NULL)
- formatted_error("cff","%s: subroutine called but no subroutine found",CS_TYPE2_DEBUG_STR);
-
- count = subr_idx->count;
-
- /* Adding bias number */
- if (count < 1240) {
- id += 107;
- } else if (count < 33900) {
- id += 1131;
- } else {
- id += 32768;
- }
-
- if (id > count)
- formatted_error("cff","%s: invalid subroutine index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count);
-
- *len = (long) ((subr_idx->offset)[id + 1] - (subr_idx->offset)[id]);
- *subr = subr_idx->data + (subr_idx->offset)[id] - 1;
-
- return;
-}
-
-@ The Type 2 interpretation of a number encoded in five-bytes (those with
-an initial byte value of 255) differs from how it is interpreted in the
-Type 1 format.
-
- at c
-static void do_charstring(card8 ** dest, card8 * limit,
- card8 ** data, card8 * endptr,
- cff_index * gsubr_idx, cff_index * subr_idx, int cff2)
-{
- card8 b0 = 0, *subr;
- long len;
-
- if (cs2_nest > CS_SUBR_NEST_MAX)
- formatted_error("cff","%s: subroutine nested too deeply", CS_TYPE2_DEBUG_STR);
-
- cs2_nest++;
-
- while (*data < endptr && status == CS_PARSE_OK) {
- b0 = **data;
- if (b0 == 255) { /* 16-bit.16-bit fixed signed number */
- get_fixed(data, endptr);
- } else if (b0 == cs_return) {
- status = CS_SUBR_RETURN;
- } else if (b0 == cs_callgsubr) {
- if (cs2_stack_top < 1) {
- status = CS_STACK_CFF_ERROR;
- } else {
- cs2_stack_top--;
- get_subr(&subr, &len, gsubr_idx,
- (long) cs2_arg_stack[cs2_stack_top]);
- if (*dest + len > limit)
- formatted_error("cff","%s: possible buffer overflow (1)", CS_TYPE2_DEBUG_STR);
- do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
- *data += 1;
- }
- } else if (b0 == cs_callsubr) {
- if (cs2_stack_top < 1) {
- status = CS_STACK_CFF_ERROR;
- } else {
- cs2_stack_top--;
- get_subr(&subr, &len, subr_idx,
- (long) cs2_arg_stack[cs2_stack_top]);
- if (limit < *dest + len)
- formatted_error("cff","%s: possible buffer overflow (2)", CS_TYPE2_DEBUG_STR);
- do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
- *data += 1;
- }
- } else if (b0 == cs_escape) {
- do_operator2(dest, limit, data, endptr);
- } else if (b0 < 32 && b0 != 28) { /* 19, 20 need mask */
- do_operator1(dest, limit, data, endptr);
- } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) { /* reserved */
- status = CS_PARSE_CFF_ERROR; /* not an error ? */
- } else { /* integer */
- cs2_get_integer(data, endptr);
- }
- }
-
- if (cff2) {
- DST_NEED(limit, *dest + 1);
- ++endptr;
- *(*dest)++ = cs_endchar;
- /* no return and endchar */
- } else if (status == CS_SUBR_RETURN) {
- status = CS_PARSE_OK;
- } else if (status == CS_CHAR_END && *data < endptr) {
- formatted_warning("cff","%s: garbage after endchar", CS_TYPE2_DEBUG_STR);
- } else if (status < CS_PARSE_OK) { /* error */
- formatted_error("cff","%s: parsing charstring failed: (status=%d, stack=%d)", CS_TYPE2_DEBUG_STR, status, cs2_stack_top);
- }
-
- cs2_nest--;
-
- return;
-}
-
-@ @c
-static void cs_parse_init(void)
-{
- status = CS_PARSE_OK;
- cs2_nest = 0;
- phase = 0;
- num_stems = 0;
- cs2_stack_top = 0;
-}
-
-@ Not just copying...
- at c
-static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srclen,
- cff_index * gsubr, cff_index * subr, double default_width,
- double nominal_width, cs_ginfo * ginfo, int cff2)
-{
- card8 *save = dst;
-
- cs_parse_init();
-
- width = 0.0;
- have_width = 0;
-
- /* expand call(g)subrs */
- do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr, cff2);
-
- if (ginfo) {
- ginfo->flags = 0; /* not used */
- if (have_width) {
- ginfo->wx = nominal_width + width;
- } else {
- ginfo->wx = default_width;
- }
- }
-
- return (long) (dst - save);
-}
-
-@ CID-Keyed font specific
- at c
-long cff_read_fdselect(cff_font * cff)
-{
- cff_fdselect *fdsel;
- long offset, length;
- card16 i;
-
- if (cff->topdict == NULL)
- normal_error("cff","top DICT not available");
-
- if (!(cff->flag & FONTTYPE_CIDFONT))
- return 0;
-
- offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0);
- cff->offset = (l_offset) offset;
- cff->fdselect = fdsel = xcalloc(1, sizeof(cff_fdselect));
- fdsel->format = get_card8(cff);
-
- length = 1;
-
- switch (fdsel->format) {
- case 0:
- fdsel->num_entries = cff->num_glyphs;
- (fdsel->data).fds = xmalloc(fdsel->num_entries * sizeof(card8));
- for (i = 0; i < (fdsel->num_entries); i++) {
- (fdsel->data).fds[i] = get_card8(cff);
- }
- length += fdsel->num_entries;
- break;
- case 3:
- {
- cff_range3 *ranges;
- fdsel->num_entries = get_card16(cff);
- fdsel->data.ranges = ranges =
- xcalloc(fdsel->num_entries, sizeof(cff_range3));
- for (i = 0; i < (fdsel->num_entries); i++) {
- ranges[i].first = get_card16(cff);
- ranges[i].fd = get_card8(cff);
- }
- if (ranges[0].first != 0)
- normal_error("cff","range not starting with 0");
- if (cff->num_glyphs != get_card16(cff))
- normal_error("cff","sentinel value mismatched with number of glyphs");
- length += (fdsel->num_entries) * 3 + 4;
- }
- break;
- default:
- xfree(fdsel);
- normal_error("cff","unknown FDSelect format");
- break;
- }
-
- return length;
-}
-
-@ @c
-long cff_pack_fdselect(cff_font * cff, card8 * dest, long destlen)
-{
- cff_fdselect *fdsel;
- long len = 0;
- card16 i;
-
- if (cff->fdselect == NULL)
- return 0;
-
- if (destlen < 1)
- normal_error("cff","buffer overflow (23)");
-
- fdsel = cff->fdselect;
-
- dest[len++] = fdsel->format;
- switch (fdsel->format) {
- case 0:
- if (fdsel->num_entries != cff->num_glyphs)
- normal_error("cff","invalid data");
- if (destlen < len + fdsel->num_entries)
- normal_error("cff","buffer overflow (24)");
- for (i = 0; i < fdsel->num_entries; i++) {
- dest[len++] = (fdsel->data).fds[i];
- }
- break;
- case 3:
- {
- if (destlen < len + 2)
- normal_error("cff","buffer overflow (25)");
- len += 2;
- for (i = 0; i < (fdsel->num_entries); i++) {
- if (destlen < len + 3)
- normal_error("cff","buffer overflow (26)");
- dest[len++] =
- (card8) (((fdsel->data).ranges[i].first >> 8) & 0xff);
- dest[len++] = (card8) ((fdsel->data).ranges[i].first & 0xff);
- dest[len++] = (card8) ((fdsel->data).ranges[i].fd);
- }
- if (destlen < len + 2)
- normal_error("cff","buffer overflow (27)");
- dest[len++] = (card8) ((cff->num_glyphs >> 8) & 0xff);
- dest[len++] = (card8) (cff->num_glyphs & 0xff);
- dest[1] = (card8) (((len / 3 - 1) >> 8) & 0xff);
- dest[2] = (card8) ((len / 3 - 1) & 0xff);
- }
- break;
- default:
- normal_error("cff","unknown FDSelect format");
- break;
- }
-
- return len;
-}
-
-@ Create an instance of embeddable font.
-
- at c
-static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname)
-{
- cff_index *topdict, *fdarray, *private;
- unsigned char *dest;
- long destlen = 0, i, size;
- long offset, topdict_offset, fdarray_offset;
-
- /* DICT sizes (offset set to long int) */
- topdict = cff_new_index(1);
- fdarray = cff_new_index(cffont->num_fds);
- private = cff_new_index(cffont->num_fds);
-
- cff_dict_remove(cffont->topdict, "UniqueID");
- cff_dict_remove(cffont->topdict, "XUID");
- cff_dict_remove(cffont->topdict, "Private"); /* some bad font may have */
- cff_dict_remove(cffont->topdict, "Encoding"); /* some bad font may have */
- cff_dict_remove(cffont->topdict, "vstore"); /* cff2 */
- cff_dict_remove(cffont->topdict, "maxstack"); /* cff2 */
-
- topdict->offset[1] = (l_offset) cff_dict_pack(cffont->topdict, (card8 *) work_buffer, WORK_BUFFER_SIZE) + 1;
- for (i = 0; i < cffont->num_fds; i++) {
- size = 0;
- if (cffont->private && cffont->private[i]) {
- size = cff_dict_pack(cffont->private[i], (card8 *) work_buffer, WORK_BUFFER_SIZE);
- if (size < 1) {
- /* Private had contained only Subr. */
- cff_dict_remove(cffont->fdarray[i], "Private");
- }
- }
- (private->offset)[i + 1] = (unsigned long) ((private->offset)[i]
- + (unsigned) size);
- (fdarray->offset)[i + 1] = (unsigned long) ((fdarray->offset)[i]
- + (unsigned) cff_dict_pack(cffont->fdarray[i], (card8 *) work_buffer, WORK_BUFFER_SIZE));
- }
-
- destlen = 4; /* header size */
- destlen += cff_set_name(cffont, fullname);
- destlen += cff_index_size(topdict);
- destlen += cff_index_size(cffont->string);
- destlen += cff_index_size(cffont->gsubr);
- destlen += (cffont->charsets->num_entries) * 2 + 1; /* charset format 0 */
- destlen += (cffont->fdselect->num_entries) * 3 + 5; /* fdselect format 3 */
- destlen += cff_index_size(cffont->cstrings);
- destlen += cff_index_size(fdarray);
- destlen = (long) (destlen + (long) private->offset[private->count] - 1); /* Private is not INDEX */
- dest = xcalloc((unsigned) destlen, sizeof(card8));
-
- offset = 0;
- /* Header */
- offset += cff_put_header(cffont, dest + offset, destlen - offset);
- /* Name */
- offset += cff_pack_index(cffont->name, dest + offset, destlen - offset);
- /* Top DICT */
- topdict_offset = offset;
- offset += cff_index_size(topdict);
- /* Strings */
- offset += cff_pack_index(cffont->string, dest + offset, destlen - offset);
- /* Global Subrs */
- offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset);
- /* charset */
- cff_dict_set(cffont->topdict, "charset", 0, (double) offset);
- offset += cff_pack_charsets(cffont, dest + offset, destlen - offset);
- /* FDSelect */
- cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset);
- offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset);
- /* CharStrings */
- cff_dict_set(cffont->topdict, "CharStrings", 0, (double) offset);
- offset += cff_pack_index(cffont->cstrings, dest + offset, cff_index_size(cffont->cstrings));
- cff_release_index(cffont->cstrings);
- cffont->cstrings = NULL; /* Charstrings cosumes huge memory */
- /* FDArray and Private */
- cff_dict_set(cffont->topdict, "FDArray", 0, (double) offset);
- fdarray_offset = offset;
- offset += cff_index_size(fdarray);
-
- fdarray->data = xcalloc((unsigned) (fdarray->offset[fdarray->count] - 1), sizeof(card8));
- for (i = 0; i < cffont->num_fds; i++) {
- size = (long) (private->offset[i + 1] - private->offset[i]);
- if (cffont->private[i] && size > 0) {
- cff_dict_pack(cffont->private[i], dest + offset, size);
- cff_dict_set(cffont->fdarray[i], "Private", 0, (double) size);
- cff_dict_set(cffont->fdarray[i], "Private", 1, (double) offset);
- }
- cff_dict_pack(cffont->fdarray[i], fdarray->data + (fdarray->offset)[i] - 1, (long) (fdarray->offset[fdarray->count] - 1));
- offset += size;
- }
- cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray));
- cff_release_index(fdarray);
- cff_release_index(private);
-
- /* Finally Top DICT */
- topdict->data = xcalloc((unsigned) (topdict->offset[topdict->count] - 1), sizeof(card8));
- cff_dict_pack(cffont->topdict, topdict->data, (long) (topdict->offset[topdict->count] - 1));
- cff_pack_index(topdict, dest + topdict_offset, cff_index_size(topdict));
- cff_release_index(topdict);
-
- for (i = 0; i < offset; i++) {
-// printf("%i\n",(unsigned char)dest[i]);
- strbuf_putchar(pdf->fb, dest[i]);
- }
- xfree(dest);
- return;
-}
-
-@ @c
-void write_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
-{
- cff_index *charstrings, *cs_idx;
-
- long charstring_len, max_len;
- long size, offset = 0;
-
- card8 *data;
- card16 num_glyphs, cs_count1, code, gid, last_cid;
-
- double nominal_width, default_width;
-
- char *fontname;
- char *fullname;
-
- glw_entry *glyph, *found;
- struct avl_traverser t;
-
-cffont->_string = NULL;
-
- fontname = xcalloc((unsigned) (1 + strlen(fd->fontname)), 1);
- sprintf(fontname, "%s", fd->fontname);
-
- fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
- sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
-
- /* finish parsing the CFF */
- cff_read_private(cffont);
- cff_read_subrs(cffont);
-
- /* Widths */
- if (cffont->private[0] && cff_dict_known(cffont->private[0], "defaultWidthX")) {
- default_width = (double) cff_dict_get(cffont->private[0], "defaultWidthX", 0);
- } else {
- default_width = CFF_DEFAULTWIDTHX_DEFAULT;
- }
- if (cffont->private[0] && cff_dict_known(cffont->private[0], "nominalWidthX")) {
- nominal_width = (double) cff_dict_get(cffont->private[0], "nominalWidthX", 0);
- } else {
- nominal_width = CFF_NOMINALWIDTHX_DEFAULT;
- }
-
- num_glyphs = 0;
- last_cid = 0;
- glyph = xtalloc(1, glw_entry);
-
- /* insert notdef */
- glyph->id = 0;
- if (avl_find(fd->gl_tree, glyph) == NULL) {
- avl_insert(fd->gl_tree, glyph);
- glyph = xtalloc(1, glw_entry);
- }
-
- avl_t_init(&t, fd->gl_tree);
- for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
- found != NULL; found = (glw_entry *) avl_t_next(&t)) {
- if (found->id > last_cid)
- last_cid = (card16) found->id;
- num_glyphs++;
- }
-
- {
- cff_fdselect *fdselect;
-
- fdselect = xcalloc(1, sizeof(cff_fdselect));
- fdselect->format = 3;
- fdselect->num_entries = 1;
- fdselect->data.ranges = xcalloc(1, sizeof(cff_range3));
- fdselect->data.ranges[0].first = 0;
- fdselect->data.ranges[0].fd = 0;
- cffont->fdselect = fdselect;
- }
-
- {
- cff_charsets *charset;
-
- charset = xcalloc(1, sizeof(cff_charsets));
- charset->format = 0;
- charset->num_entries = (card16) (num_glyphs - 1);
- charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
-
- gid = 0;
-
- avl_t_init(&t, fd->gl_tree);
- for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
- found != NULL; found = (glw_entry *) avl_t_next(&t)) {
- if (found->id != 0) {
- charset->data.glyphs[gid] = (s_SID) found->id;
- gid++;
- }
- }
- cffont->charsets = charset;
-
- if (cffont->header_major == 2) {
- cff_dict_add(cffont->topdict, "charset", 1);
- }
- }
- cff_dict_add(cffont->topdict, "CIDCount", 1);
- cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1);
-
- if (cffont->header_major == 2) {
-
- cff_dict_add(cffont->topdict, "FullName", 1);
- cff_dict_set(cffont->topdict, "FullName", 0, (double) cff_add_string(cffont, fontname));
-
- cff_dict_add(cffont->topdict, "FontBBox", 4);
- cff_dict_set(cffont->topdict, "FontBBox", 0, fd->font_dim[FONTBBOX1_CODE].val);
- cff_dict_set(cffont->topdict, "FontBBox", 1, fd->font_dim[FONTBBOX2_CODE].val);
- cff_dict_set(cffont->topdict, "FontBBox", 2, fd->font_dim[FONTBBOX3_CODE].val);
- cff_dict_set(cffont->topdict, "FontBBox", 3, fd->font_dim[FONTBBOX4_CODE].val);
- }
-
- cffont->fdarray = xcalloc(1, sizeof(cff_dict *));
- cffont->fdarray[0] = cff_new_dict();
- cff_dict_add(cffont->fdarray[0], "FontName", 1);
- /* FIXME: Skip XXXXXX+ */
- cff_dict_set(cffont->fdarray[0], "FontName", 0, (double) cff_add_string(cffont, fullname));
- cff_dict_add(cffont->fdarray[0], "Private", 2);
- cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
- cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
- /* FDArray - index offset, not known yet */
- cff_dict_add(cffont->topdict, "FDArray", 1);
- cff_dict_set(cffont->topdict, "FDArray", 0, 0.0);
- /* FDSelect - offset, not known yet */
- cff_dict_add(cffont->topdict, "FDSelect", 1);
- cff_dict_set(cffont->topdict, "FDSelect", 0, 0.0);
-
- cff_dict_remove(cffont->topdict, "UniqueID");
- cff_dict_remove(cffont->topdict, "XUID");
- cff_dict_remove(cffont->topdict, "Private");
- cff_dict_remove(cffont->topdict, "Encoding");
-
- cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
- cs_idx = cff_get_index_header(cffont);
-
- offset = (long) cffont->offset;
- cs_count1 = cs_idx->count;
- if (cs_count1 < 2) {
- normal_error("cff","no valid charstring data found");
- }
-
- /* build the new charstrings entry */
- charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
- max_len = 2 * CS_STR_LEN_MAX;
- charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
- charstring_len = 0;
-
- gid = 0;
- data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
-
- {
- int i;
- int tex_font = fd->tex_font;
- int streamprovider = 0;
- int callback_id = 0 ;
- if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
- streamprovider = font_streamprovider(tex_font);
- callback_id = callback_defined(glyph_stream_provider_callback);
- }
- for (i = 0; i < cs_count1; i++) {
- code = (card16) i;
- glyph->id = code;
- if ((avl_find(fd->gl_tree,glyph) != NULL)) {
- /* this code is the same as below, apart from small details */
- if (callback_id > 0) {
- lstring * result;
- run_callback(callback_id, "ddd->L", tex_font, i, streamprovider, &result); /* this call can be sped up */
- size = (size_t) result->l ;
- if (size > 0) {
- if (charstring_len + CS_STR_LEN_MAX >= max_len) {
- max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
- charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
- }
- (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
- cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
- memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t) size);
- charstring_len += size;
- xfree(result);
- }
- } else {
- size = (long)(cs_idx->offset[code+1] - cs_idx->offset[code]);
- if (size > CS_STR_LEN_MAX) {
- formatted_error("cff","charstring too long: gid=%u, %ld bytes", code, size);
- }
- if (charstring_len + CS_STR_LEN_MAX >= max_len) {
- max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
- charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
- }
- (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
- cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
- memcpy(data,&cffont->stream[cffont->offset],(size_t)size);
- charstring_len += cs_copy_charstring(
- charstrings->data + charstring_len,
- max_len - charstring_len,
- data, size,
- cffont->gsubr, (cffont->subrs)[0],
- default_width, nominal_width, NULL,
- cffont->header_major == 2
- );
- }
- gid++;
- }
- }
- }
- /*
- CIDSet: a table of bits indexed by cid, bytes with high order bit first,
- each (set) bit is a (present) CID.
- */
- if (1) {
- int cid;
- cidset = pdf_create_obj(pdf, obj_type_others, 0);
- if (cidset != 0) {
- size_t l = (last_cid/8)+1;
- char *stream = xmalloc(l);
- memset(stream, 0, l);
- for (cid = 1; cid <= (long) last_cid; cid++) {
- glyph->id = cid;
- if (avl_find(fd->gl_tree,glyph) != NULL) {
- stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
- }
- }
- pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
- pdf_begin_dict(pdf);
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- pdf_out_block(pdf, stream, l);
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- }
- }
- /*
- This happens if the internal metrics do not agree with the actual
- disk font.
- */
- if (gid < num_glyphs) {
- formatted_warning("cff","embedded subset is smaller than expected: %d instead of %d glyphs", gid, num_glyphs);
- num_glyphs = gid;
- }
-
- xfree(data);
- cff_release_index(cs_idx);
-
- (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
- charstrings->count = num_glyphs;
- cffont->num_glyphs = num_glyphs;
- cffont->cstrings = charstrings;
- /*
- We don't use subroutines at all.
- */
- if (cffont->gsubr)
- cff_release_index(cffont->gsubr);
- cffont->gsubr = cff_new_index(0);
-
- if (cffont->subrs && cffont->subrs[0])
- cff_release_index(cffont->subrs[0]);
- cffont->subrs[0] = NULL;
-
- if (cffont->private && (cffont->private)[0]) {
- cff_dict_remove((cffont->private)[0], "Subrs"); /* no Subrs */
- }
-
- cff_dict_update(cffont->topdict, cffont);
-
- cff_add_string(cffont, "Adobe");
- cff_add_string(cffont, "Identity");
- if (cffont->header_major == 2) {
- /* crash */
- } else {
- cff_dict_update(cffont->private[0], cffont);
- }
- cff_update_string(cffont);
-
- /* CFF code need to be rewritten */
- cff_dict_add(cffont->topdict, "ROS", 3);
- cff_dict_set(cffont->topdict, "ROS", 0, (double) cff_get_sid(cffont, "Adobe"));
- cff_dict_set(cffont->topdict, "ROS", 1, (double) cff_get_sid(cffont, "Identity"));
- cff_dict_set(cffont->topdict, "ROS", 2, 0.0);
-
- write_fontfile(pdf, cffont, fullname);
- xfree(fontname);
- xfree(fullname);
- cff_close(cffont);
-}
-
-@ @c
-#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT)
-#define CID_MAX 65535
-
-void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
-{
- cff_index *charstrings, *cs_idx;
-
- long charstring_len, max_len;
- long size, offset = 0;
- int tex_font = fd->tex_font;
- int streamprovider = 0;
- int callback_id = 0 ;
-
- card8 *data;
- card16 num_glyphs, cs_count1, gid, last_cid;
-
- int fdsel, prev_fd, cid_count, cid ;
- char *fullname;
-
- glw_entry *glyph;
-
- unsigned char *CIDToGIDMap = NULL;
-
- cff_fdselect *fdselect = NULL;
- cff_charsets *charset = NULL;
-
- if (!is_cidfont(cffont)) {
- normal_error("cff","invalid CIDfont");
- return;
- }
-
- if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
- streamprovider = font_streamprovider(tex_font);
- callback_id = callback_defined(glyph_stream_provider_callback);
- }
-
- fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
- sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
-
- /* finish parsing the CFF */
-
- if (cff_dict_known(cffont->topdict, "CIDCount")) {
- cid_count = (card16) cff_dict_get(cffont->topdict, "CIDCount", 0);
- } else {
- cid_count = CFF_CIDCOUNT_DEFAULT;
- }
- if (cffont->header_major == 2) {
- /* hm */
- } else {
- cff_read_charsets(cffont);
- }
- CIDToGIDMap = xmalloc((unsigned) ((2 * (unsigned) cid_count) * sizeof(unsigned char)));
- memset(CIDToGIDMap, 0, (size_t) (2 * cid_count));
-
- glyph = xtalloc(1, glw_entry);
- /* insert notdef */
- glyph->id = 0;
- if (avl_find(fd->gl_tree, glyph) == NULL) {
- avl_insert(fd->gl_tree, glyph);
- glyph = xtalloc(1, glw_entry);
- }
-
- last_cid = 0;
- num_glyphs = 0;
- for (cid = 0; cid <= CID_MAX; cid++) {
- glyph->id = (unsigned) cid;
- if (avl_find(fd->gl_tree, glyph) != NULL) {
- gid = (card16) cid;
- CIDToGIDMap[2 * cid] = (unsigned char) ((gid >> 8) & 0xff);
- CIDToGIDMap[2 * cid + 1] = (unsigned char) (gid & 0xff);
- last_cid = (card16) cid;
- num_glyphs++;
- }
- }
- if (cffont->header_major == 2) {
- /* hm */
- } else if (last_cid >= cffont->num_glyphs) {
- formatted_error("cff font","bad glyph index %i",last_cid);
- }
- /*
- CIDSet: a table of bits indexed by cid, bytes with high order bit
- first, each (set) bit is a (present) CID.
- */
- if (1) {
- cidset = pdf_create_obj(pdf, obj_type_others, 0);
- if (cidset != 0) {
- size_t l = (last_cid / 8) + 1;
- char *stream = xmalloc(l);
- memset(stream, 0, l);
- for (cid = 1; cid <= (long) last_cid; cid++) {
- if (CIDToGIDMap[2 * cid] || CIDToGIDMap[2 * cid + 1]) {
- stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
- }
- }
- pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
- pdf_begin_dict(pdf);
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- pdf_out_block(pdf, stream, l);
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- xfree(stream);
- }
- }
-
- cff_read_fdselect(cffont);
- cff_read_fdarray(cffont);
- cff_read_private(cffont);
-
- cff_read_subrs(cffont);
-
- cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
- cs_idx = cff_get_index_header(cffont);
-
- offset = (long) cffont->offset;
- cs_count1 = cs_idx->count;
- if (cs_count1 < 2) {
- normal_error("cff","no valid charstring data found");
- }
-
- charset = xcalloc(1, sizeof(cff_charsets));
- charset->format = 0;
- charset->num_entries = 0;
- charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
-
- fdselect = xcalloc(1, sizeof(cff_fdselect));
- fdselect->format = 3;
- fdselect->num_entries = 0;
- fdselect->data.ranges = xcalloc(num_glyphs, sizeof(cff_range3));
-
- charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
- max_len = 2 * CS_STR_LEN_MAX;
- charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
- charstring_len = 0;
-
- prev_fd = -1;
- gid = 0;
- data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
- for (cid = 0; cid <= last_cid; cid++) {
- unsigned short gid_org;
-
- glyph->id = (unsigned) cid;
- if (avl_find(fd->gl_tree, glyph) == NULL)
- continue;
-
- gid_org = (short unsigned) ((CIDToGIDMap[2 * cid] << 8) | (CIDToGIDMap[2 * cid + 1]));
- fdsel = cff_fdselect_lookup(cffont, gid_org);
-
- if (callback_id > 0) {
- /* the next blob is not yet tested ... i need a font */
- lstring * result;
- run_callback(callback_id, "ddd->L", tex_font, gid_org, streamprovider, &result); /* this call can be sped up */
- size = (size_t) result->l ;
- if (size > 0) {
- if (charstring_len + CS_STR_LEN_MAX >= max_len) {
- max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
- charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
- }
- (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
- cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[gid_org] - 1);
- memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t)size);
- charstring_len += size;
- xfree(result);
- }
- } else {
- size = (long) (cs_idx->offset[gid_org + 1] - cs_idx->offset[gid_org]);
- if (size > CS_STR_LEN_MAX) {
- formatted_error("cff","charstring too long: gid=%u, %ld bytes", cid, size);
- }
- if (charstring_len + CS_STR_LEN_MAX >= max_len) {
- max_len = charstring_len + 2 * CS_STR_LEN_MAX;
- charstrings->data = xrealloc(charstrings->data, (unsigned) ((unsigned) max_len * sizeof(card8)));
- }
- (charstrings->offset)[gid] = (l_offset) (charstring_len + 1);
- cffont->offset = (l_offset) ((unsigned) offset + (cs_idx->offset)[gid_org] - 1);
- memcpy(data, &cffont->stream[cffont->offset], (size_t) size);
- charstring_len += cs_copy_charstring(
- charstrings->data + charstring_len,
- max_len - charstring_len,
- data, size,
- cffont->gsubr, (cffont->subrs)[fdsel],
- 0, 0, NULL,
- cffont->header_major == 2
- );
- }
- if (cid > 0 && gid_org > 0) {
- charset->data.glyphs[charset->num_entries] = (s_SID) cid;
- charset->num_entries++;
- }
- if (fdsel != prev_fd) {
- fdselect->data.ranges[fdselect->num_entries].first = gid;
- fdselect->data.ranges[fdselect->num_entries].fd = (card8) fdsel;
- fdselect->num_entries++;
- prev_fd = fdsel;
- }
- gid++;
- }
-
- if (gid != num_glyphs)
- formatted_error("cff","unexpected error: %i != %i", gid, num_glyphs);
- xfree(data);
- cff_release_index(cs_idx);
-
- xfree(CIDToGIDMap);
-
- (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
- charstrings->count = num_glyphs;
- cffont->num_glyphs = num_glyphs;
- cffont->cstrings = charstrings;
- cff_release_charsets(cffont->charsets);
- cffont->charsets = charset;
- cff_release_fdselect(cffont->fdselect);
- cffont->fdselect = fdselect;
- /*
- We don't use subroutines at all.
- */
- if (cffont->gsubr)
- cff_release_index(cffont->gsubr);
- cffont->gsubr = cff_new_index(0);
-
- for (fdsel = 0; fdsel < cffont->num_fds; fdsel++) {
- if (cffont->subrs && cffont->subrs[fdsel]) {
- cff_release_index(cffont->subrs[fdsel]);
- cffont->subrs[fdsel] = NULL;
- }
- if (cffont->private && (cffont->private)[fdsel]) {
- cff_dict_remove((cffont->private)[fdsel], "Subrs"); /* no Subrs */
- }
- }
- write_fontfile(pdf, cffont, fullname);
- xfree(fullname);
- cff_close(cffont);
-}
-
-@ Here is a sneaky trick: fontforge knows how to convert Type1 to CFF, so
-I have defined a utility function in luafflib.c that does exactly that.
-If it works out ok, I will clean up this code.
-
- at c
-void writetype1w(PDF pdf, fd_entry * fd)
-{
- cff_font *cff;
- int i;
- FILE *fp;
- ff_entry *ff;
- unsigned char *tfm_buffer = NULL;
- int tfm_size = 0;
-
- ff = check_ff_exist(fd->fm->ff_name, 0);
-
- fp = fopen(ff->ff_path, "rb");
- cur_file_name = ff->ff_path;
-
- if (!fp) {
- formatted_error("cff","could not open Type1 font: %s", cur_file_name);
- }
- fclose(fp);
-
- if (is_subsetted(fd->fm)) {
- report_start_file(filetype_subset,cur_file_name);
- } else {
- report_start_file(filetype_font,cur_file_name);
- }
- (void) ff_createcff(ff->ff_path, &tfm_buffer, &tfm_size);
-
- if (tfm_size > 0) {
- cff = read_cff(tfm_buffer, tfm_size, 0);
- if (cff != NULL) {
- write_cff(pdf, cff, fd);
- } else {
- for (i = 0; i < tfm_size; i++)
- strbuf_putchar(pdf->fb, tfm_buffer[i]);
- }
- fd->ff_found = 1;
- } else {
- formatted_error("cff","could not understand Type1 font: %s",cur_file_name);
- }
- if (is_subsetted(fd->fm)) {
- report_stop_file(filetype_subset);
- } else {
- report_stop_file(filetype_font);
- }
- cur_file_name = NULL;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,164 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2011 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+ All encoding entries go into AVL tree for fast search by name.
+
+*/
+
+struct avl_table *fe_tree = NULL;
+
+/* The AVL sort |fe_entry| into |fe_tree| by name. */
+
+static int comp_fe_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const fe_entry *) pa)->name, ((const fe_entry *) pb)->name);
+}
+
+static fe_entry *new_fe_entry(void)
+{
+ fe_entry *fe;
+ fe = xtalloc(1, fe_entry);
+ fe->name = NULL;
+ fe->fe_objnum = 0;
+ /*tex The encoding file is not yet read in. */
+ fe->glyph_names = NULL;
+ fe->tx_tree = NULL;
+ return fe;
+}
+
+static fe_entry *lookup_fe_entry(char *s)
+{
+ fe_entry fe;
+ assert(s != NULL);
+ fe.name = s;
+ if (fe_tree == NULL) {
+ fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
+ assert(fe_tree != NULL);
+ }
+ return (fe_entry *) avl_find(fe_tree, &fe);
+}
+
+static void register_fe_entry(fe_entry * fe)
+{
+ void **aa;
+ if (fe_tree == NULL) {
+ fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
+ assert(fe_tree != NULL);
+ }
+ assert(fe != NULL);
+ assert(fe->name != NULL);
+ /*tex The encoding is not yet registered. */
+ assert(lookup_fe_entry(fe->name) == NULL);
+ aa = avl_probe(fe_tree, fe);
+ assert(aa != NULL);
+}
+
+fe_entry *get_fe_entry(char *s)
+{
+ fe_entry *fe;
+ char **gl;
+ if ((fe = lookup_fe_entry(s)) == NULL && (gl = load_enc_file(s)) != NULL) {
+ fe = new_fe_entry();
+ fe->name = s;
+ fe->glyph_names = gl;
+ register_fe_entry(fe);
+ }
+ return fe;
+}
+
+static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree, int fe_objnum)
+{
+ int i_old, *p;
+ struct avl_traverser t;
+ assert(glyph_names != NULL);
+ assert(tx_tree != NULL);
+ assert(fe_objnum != 0);
+ pdf_begin_obj(pdf, fe_objnum, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Encoding");
+ pdf_add_name(pdf, "Differences");
+ pdf_begin_array(pdf);
+ avl_t_init(&t, tx_tree);
+ for (i_old = -2, p = (int *) avl_t_first(&t, tx_tree); p != NULL;
+ p = (int *) avl_t_next(&t)) {
+ if (*p == i_old + 1) {
+ pdf_add_name(pdf, glyph_names[*p]);
+ } else {
+ pdf_add_int(pdf, *p);
+ pdf_add_name(pdf, glyph_names[*p]);
+ }
+ i_old = *p;
+ }
+ pdf_end_array(pdf);
+ pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
+}
+
+static void write_fontencoding(PDF pdf, fe_entry * fe)
+{
+ assert(fe != NULL);
+ write_enc(pdf, fe->glyph_names, fe->tx_tree, fe->fe_objnum);
+}
+
+void write_fontencodings(PDF pdf)
+{
+ fe_entry *fe;
+ struct avl_traverser t;
+ if (fe_tree == NULL)
+ return;
+ avl_t_init(&t, fe_tree);
+ for (fe = (fe_entry *) avl_t_first(&t, fe_tree); fe != NULL;
+ fe = (fe_entry *) avl_t_next(&t))
+ if (fe->fe_objnum != 0)
+ write_fontencoding(pdf, fe);
+}
+
+/*tex Cleaning up \unknown */
+
+static void destroy_fe_entry(void *pa, void *pb)
+{
+ fe_entry *p;
+ int i;
+ (void) pb;
+ p = (fe_entry *) pa;
+ xfree(p->name);
+ if (p->glyph_names != NULL)
+ for (i = 0; i < 256; i++)
+ if (p->glyph_names[i] != notdef)
+ xfree(p->glyph_names[i]);
+ xfree(p->glyph_names);
+ if (p->tx_tree != NULL)
+ avl_destroy(p->tx_tree,NULL);
+ xfree(p);
+}
+
+void enc_free(void)
+{
+ if (fe_tree != NULL)
+ avl_destroy(fe_tree, destroy_fe_entry);
+ fe_tree = NULL;
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,162 +0,0 @@
-% writeenc.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ All encoding entries go into AVL tree for fast search by name.
- at c
-struct avl_table *fe_tree = NULL;
-
-@ AVL sort |fe_entry| into |fe_tree| by name
- at c
-static int comp_fe_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const fe_entry *) pa)->name, ((const fe_entry *) pb)->name);
-}
-
-static fe_entry *new_fe_entry(void)
-{
- fe_entry *fe;
- fe = xtalloc(1, fe_entry);
- fe->name = NULL;
- fe->fe_objnum = 0;
- fe->glyph_names = NULL; /* encoding file not yet read in */
- fe->tx_tree = NULL;
- return fe;
-}
-
-static fe_entry *lookup_fe_entry(char *s)
-{
- fe_entry fe;
- assert(s != NULL);
- fe.name = s;
- if (fe_tree == NULL) {
- fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
- assert(fe_tree != NULL);
- }
- return (fe_entry *) avl_find(fe_tree, &fe);
-}
-
-static void register_fe_entry(fe_entry * fe)
-{
- void **aa;
- if (fe_tree == NULL) {
- fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
- assert(fe_tree != NULL);
- }
- assert(fe != NULL);
- assert(fe->name != NULL);
- assert(lookup_fe_entry(fe->name) == NULL); /* encoding not yet registered */
- aa = avl_probe(fe_tree, fe);
- assert(aa != NULL);
-}
-
-fe_entry *get_fe_entry(char *s)
-{
- fe_entry *fe;
- char **gl;
- if ((fe = lookup_fe_entry(s)) == NULL && (gl = load_enc_file(s)) != NULL) {
- fe = new_fe_entry();
- fe->name = s;
- fe->glyph_names = gl;
- register_fe_entry(fe);
- }
- return fe;
-}
-
-@ @c
-static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree,
- int fe_objnum)
-{
- int i_old, *p;
- struct avl_traverser t;
- assert(glyph_names != NULL);
- assert(tx_tree != NULL);
- assert(fe_objnum != 0);
- pdf_begin_obj(pdf, fe_objnum, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Encoding");
- pdf_add_name(pdf, "Differences");
- pdf_begin_array(pdf);
- avl_t_init(&t, tx_tree);
- for (i_old = -2, p = (int *) avl_t_first(&t, tx_tree); p != NULL;
- p = (int *) avl_t_next(&t)) {
- if (*p == i_old + 1) /* consecutive */
- pdf_add_name(pdf, glyph_names[*p]);
- else {
- pdf_add_int(pdf, *p);
- pdf_add_name(pdf, glyph_names[*p]);
- }
- i_old = *p;
- }
- pdf_end_array(pdf);
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
-}
-
-static void write_fontencoding(PDF pdf, fe_entry * fe)
-{
- assert(fe != NULL);
- write_enc(pdf, fe->glyph_names, fe->tx_tree, fe->fe_objnum);
-}
-
-void write_fontencodings(PDF pdf)
-{
- fe_entry *fe;
- struct avl_traverser t;
- if (fe_tree == NULL)
- return;
- avl_t_init(&t, fe_tree);
- for (fe = (fe_entry *) avl_t_first(&t, fe_tree); fe != NULL;
- fe = (fe_entry *) avl_t_next(&t))
- if (fe->fe_objnum != 0)
- write_fontencoding(pdf, fe);
-}
-
-@ cleaning up...
- at c
-
-static void destroy_fe_entry(void *pa, void *pb)
-{
- fe_entry *p;
- int i;
- (void) pb;
- p = (fe_entry *) pa;
- xfree(p->name);
- if (p->glyph_names != NULL)
- for (i = 0; i < 256; i++)
- if (p->glyph_names[i] != notdef)
- xfree(p->glyph_names[i]);
- xfree(p->glyph_names);
- if (p->tx_tree != NULL)
- avl_destroy(p->tx_tree,NULL);
- xfree(p);
-}
-
-void enc_free(void)
-{
- if (fe_tree != NULL)
- avl_destroy(fe_tree, destroy_fe_entry);
- fe_tree = NULL;
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/writefont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writefont.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writefont.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1069 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f);
+
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f);
+
+const key_entry font_key[FONT_KEYS_NUM] = {
+ { "Ascent", "Ascender", 1 },
+ { "CapHeight", "CapHeight", 1 },
+ { "Descent", "Descender", 1 },
+ { "ItalicAngle", "ItalicAngle", 1 },
+ { "StemV", "StdVW", 1 },
+ { "XHeight", "XHeight", 1 },
+ { "FontBBox", "FontBBox", 1 },
+ { "", "", 0 },
+ { "", "", 0 },
+ { "", "", 0 },
+ { "FontName", "FontName", 1 }
+};
+
+/*tex A tree of font dictionaries: */
+
+struct avl_table *fo_tree = NULL;
+
+/*tex A tree of font descriptor objects: */
+
+struct avl_table *fd_tree = NULL;
+
+static int comp_fo_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const fo_entry *) pa)->fm->tfm_name, ((const fo_entry *) pb)->fm->tfm_name);
+}
+
+static int comp_fd_entry(const void *pa, const void *pb, void *p)
+{
+ const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb;
+ (void) p;
+ return strcmp(p1->fm->ff_name, p2->fm->ff_name);
+}
+
+/*tex We initialize data structure for |/Type| |/Font|: */
+
+static fo_entry *new_fo_entry(void)
+{
+ fo_entry *fo;
+ fo = xtalloc(1, fo_entry);
+ fo->fo_objnum = 0;
+ fo->tex_font = 0;
+ fo->fm = NULL;
+ fo->fd = NULL;
+ fo->fe = NULL;
+ fo->cw_objnum = 0;
+ fo->first_char = 1;
+ fo->last_char = 0;
+ fo->tx_tree = NULL;
+ fo->tounicode_objnum = 0;
+ return fo;
+}
+
+/*tex We initialize data structure for |/Type| |/FontDescriptor|: */
+
+fd_entry *new_fd_entry(internal_font_number f)
+{
+ fd_entry *fd;
+ int i;
+ fd = xtalloc(1, fd_entry);
+ fd->fd_objnum = 0;
+ fd->fontname = NULL;
+ fd->subset_tag = NULL;
+ fd->ff_found = false;
+ fd->ff_objnum = 0;
+ fd->all_glyphs = false;
+ fd->write_ttf_glyph_names = false;
+ for (i = 0; i < FONT_KEYS_NUM; i++) {
+ fd->font_dim[i].val = 0;
+ fd->font_dim[i].set = false;
+ }
+ fd->fe = NULL;
+ fd->builtin_glyph_names = NULL;
+ fd->fm = NULL;
+ fd->tx_tree = NULL;
+ fd->gl_tree = NULL;
+ fd->tex_font = f;
+ return fd;
+}
+
+/*tex
+
+ Only fallback values of font metrics are taken from the TFM info of |f| by
+ |preset_fontmetrics|. During reading of the font file, these values are
+ replaced by metrics from the font, if available.
+
+*/
+
+static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
+{
+ int i;
+ fd->font_dim[ITALIC_ANGLE_CODE].val = 0;
+ fd->font_dim[ASCENT_CODE].val =
+ divide_scaled(char_height(f, 'h'), font_size(f), 3);
+ fd->font_dim[CAPHEIGHT_CODE].val =
+ divide_scaled(char_height(f, 'H'), font_size(f), 3);
+ i = -divide_scaled(char_depth(f, 'y'), font_size(f), 3);
+ fd->font_dim[DESCENT_CODE].val = i < 0 ? i : 0;
+ fd->font_dim[STEMV_CODE].val =
+ divide_scaled(char_width(f, '.') / 3, font_size(f), 3);
+ fd->font_dim[XHEIGHT_CODE].val =
+ divide_scaled(get_x_height(f), font_size(f), 3);
+ fd->font_dim[FONTBBOX1_CODE].val = 0;
+ fd->font_dim[FONTBBOX2_CODE].val = fd->font_dim[DESCENT_CODE].val;
+ fd->font_dim[FONTBBOX3_CODE].val =
+ divide_scaled(get_quad(f), font_size(f), 3);
+ fd->font_dim[FONTBBOX4_CODE].val =
+ fd->font_dim[CAPHEIGHT_CODE].val > fd->font_dim[ASCENT_CODE].val ?
+ fd->font_dim[CAPHEIGHT_CODE].val : fd->font_dim[ASCENT_CODE].val;
+ for (i = 0; i < INT_KEYS_NUM; i++)
+ fd->font_dim[i].set = true;
+}
+
+static void fix_fontmetrics(fd_entry * fd)
+{
+ int i;
+ intparm *p = (intparm *) fd->font_dim;
+ /*tex Make sure there is a rectangle. */
+ if (p[FONTBBOX3_CODE].val < p[FONTBBOX1_CODE].val) {
+ i = p[FONTBBOX3_CODE].val;
+ p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val;
+ p[FONTBBOX1_CODE].val = i;
+ } else if (p[FONTBBOX3_CODE].val == p[FONTBBOX1_CODE].val)
+ p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val + 1;
+ if (p[FONTBBOX4_CODE].val < p[FONTBBOX2_CODE].val) {
+ i = p[FONTBBOX4_CODE].val;
+ p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val;
+ p[FONTBBOX2_CODE].val = i;
+ } else if (p[FONTBBOX4_CODE].val == p[FONTBBOX2_CODE].val)
+ p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val + 1;
+ if (!p[ASCENT_CODE].set) {
+ p[ASCENT_CODE].val = p[FONTBBOX4_CODE].val;
+ p[ASCENT_CODE].set = true;
+ }
+ if (!p[DESCENT_CODE].set) {
+ p[DESCENT_CODE].val = p[FONTBBOX2_CODE].val;
+ p[DESCENT_CODE].set = true;
+ }
+ if (!p[CAPHEIGHT_CODE].set) {
+ p[CAPHEIGHT_CODE].val = p[FONTBBOX4_CODE].val;
+ p[CAPHEIGHT_CODE].set = true;
+ }
+}
+
+static void write_fontmetrics(PDF pdf, fd_entry * fd)
+{
+ int i;
+ fix_fontmetrics(fd);
+ pdf_add_name(pdf, font_key[FONTBBOX1_CODE].pdfname);
+ pdf_begin_array(pdf);
+ /*
+ pdf_check_space;
+ pdf_printf(pdf, "%i %i %i %i",
+ (int) fd->font_dim[FONTBBOX1_CODE].val,
+ (int) fd->font_dim[FONTBBOX2_CODE].val,
+ (int) fd->font_dim[FONTBBOX3_CODE].val,
+ (int) fd->font_dim[FONTBBOX4_CODE].val);
+ */
+ pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX1_CODE].val);
+ pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX2_CODE].val);
+ pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX3_CODE].val);
+ pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX4_CODE].val);
+ /* */
+ pdf_end_array(pdf);
+ for (i = 0; i < GEN_KEY_NUM; i++)
+ if (fd->font_dim[i].set)
+ pdf_dict_add_int(pdf, font_key[i].pdfname, fd->font_dim[i].val);
+}
+
+static void preset_fontname(fo_entry * fo, internal_font_number f)
+{
+ if (fo->fm->ps_name != NULL) {
+ /*tex We just fallback. */
+ fo->fd->fontname = xstrdup(fo->fm->ps_name);
+ } else if (font_fullname(f) != NULL) {
+ fo->fd->fontname = xstrdup(font_fullname(f));
+ } else {
+ fo->fd->fontname = xstrdup(fo->fm->tfm_name);
+ }
+}
+
+static void pdf_dict_add_fontname(PDF pdf, const char *key, fd_entry * fd)
+{
+ char *s;
+ size_t l1 = 0, l2;
+ if (fd->subset_tag != NULL)
+ l1 = strlen(fd->subset_tag);
+ l2 = strlen(fd->fontname);
+ s = xmalloc(l1 + l2 + 2);
+ if (l1 > 0)
+ snprintf(s, l1 + l2 + 2, "%s+%s", fd->subset_tag, fd->fontname);
+ else
+ snprintf(s, l2 + 1, "%s", fd->fontname);
+ pdf_dict_add_name(pdf, key, s);
+ xfree(s);
+}
+
+fd_entry *lookup_fd_entry(char *s)
+{
+ fd_entry fd;
+ fm_entry fm;
+ fm.ff_name = s;
+ fd.fm = &fm;
+ if (fd_tree == NULL) {
+ fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+ }
+ return (fd_entry *) avl_find(fd_tree, &fd);
+}
+
+static fd_entry *lookup_fontdescriptor(fo_entry * fo)
+{
+ return lookup_fd_entry(fo->fm->ff_name);
+}
+
+void register_fd_entry(fd_entry * fd)
+{
+ void **aa;
+ if (fd_tree == NULL) {
+ fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+ }
+ /*tex The font descriptor is not yet registered: */
+ if (lookup_fd_entry(fd->fm->ff_name) == NULL) {
+ /*tex Is this a problem? */
+ } else {
+ /*tex The lookup also can create */
+ }
+ aa = avl_probe(fd_tree, fd);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+}
+
+static void create_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+ fo->fd = new_fd_entry(f);
+ preset_fontname(fo, f);
+ preset_fontmetrics(fo->fd, f);
+ /*tex An encoding is needed for \TRUETYPE\ writing: */
+ fo->fd->fe = fo->fe;
+ /*tex A map entry is needed for \TRUETYPE\ writing: */
+ fo->fd->fm = fo->fm;
+ fo->fd->gl_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+}
+
+/*tex
+
+ For all used characters of \TeX font |f|, get corresponding glyph names from
+ external reencoding (.enc) file and collect these in the glyph tree |gl_tree|
+ of font descriptor |fd| referenced by font dictionary |fo|.
+
+*/
+
+static void mark_reenc_glyphs(fo_entry * fo, internal_font_number f)
+{
+ int i;
+ char **g;
+ void **aa;
+ if (is_subsetted(fo->fm)) {
+ /*tex mark glyphs from TeX (externally reencoded characters) */
+ g = fo->fe->glyph_names;
+ for (i = fo->first_char; i <= fo->last_char; i++) {
+ if (pdf_char_marked(f, i)
+ && g[i] != notdef
+ && (char *) avl_find(fo->fd->gl_tree, g[i]) == NULL) {
+ aa = avl_probe(fo->fd->gl_tree, xstrdup(g[i]));
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ }
+ }
+ }
+}
+
+/*tex
+
+ Function |mark_chars| has 2 uses:
+
+ \startitemize[n]
+ \startitem Mark characters as chars on \TeX\ level. \stopitem
+ \startitem Mark encoding pairs used by \TeX\ to optimize encoding vector. \stopitem
+ \stopitemize
+
+*/
+
+static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree, internal_font_number f)
+{
+ int i, *j;
+ void **aa;
+ if (tx_tree == NULL) {
+ tx_tree = avl_create(comp_int_entry, NULL, &avl_xallocator);
+ assert(tx_tree != NULL);
+ }
+ for (i = fo->first_char; i <= fo->last_char; i++) {
+ if (pdf_char_marked(f, i) && (int *) avl_find(tx_tree, &i) == NULL) {
+ j = xtalloc(1, int);
+ *j = i;
+ aa = avl_probe(tx_tree, j);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ }
+ }
+ return tx_tree;
+}
+
+static void get_char_range(fo_entry * fo, internal_font_number f)
+{
+ int i;
+ assert(fo != NULL);
+ /*tex Search for |first_char| and |last_char|. */
+ for (i = font_bc(f); i <= font_ec(f); i++)
+ if (pdf_char_marked(f, i))
+ break;
+ fo->first_char = i;
+ for (i = font_ec(f); i >= font_bc(f); i--)
+ if (pdf_char_marked(f, i))
+ break;
+ fo->last_char = i;
+ if ((fo->first_char > fo->last_char) || !pdf_char_marked(f, fo->first_char)) {
+ /*tex No character has been used from this font. */
+ fo->last_char = 0;
+ fo->first_char = fo->last_char + 1;
+ }
+}
+
+static int font_has_subset(internal_font_number f)
+{
+ int i, s;
+ /*tex Search for |first_char| and |last_char|. */
+ for (i = font_bc(f); i <= font_ec(f); i++)
+ if (pdf_char_marked(f, i))
+ break;
+ s = i;
+ for (i = font_ec(f); i >= font_bc(f); i--)
+ if (pdf_char_marked(f, i))
+ break;
+ if (s > i)
+ return 0;
+ else
+ return 1;
+}
+
+static void write_charwidth_array(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+ int i, j, *ip, *fip;
+ struct avl_traverser t;
+ fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
+ avl_t_init(&t, fo->tx_tree);
+ fip = (int *) avl_t_first(&t, fo->tx_tree);
+ pdf_begin_array(pdf);
+ for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) {
+ if (ip != fip)
+ pdf_out(pdf, ' ');
+ i = *ip;
+ while (j < i - 1) {
+ pdf_puts(pdf, "0 ");
+ j++;
+ }
+ j = i;
+ pdf_print_charwidth(pdf, f, i);
+ }
+ pdf_end_array(pdf);
+ pdf_end_obj(pdf);
+}
+
+/*tex
+
+ Remark: Font objects from embedded PDF files are never registered into
+ |fo_tree|; they are individually written out.
+
+*/
+
+static fo_entry *lookup_fo_entry(char *s)
+{
+ fo_entry fo;
+ fm_entry fm;
+ fm.tfm_name = s;
+ fo.fm = &fm;
+ if (fo_tree == NULL) {
+ fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+ }
+ return (fo_entry *) avl_find(fo_tree, &fo);
+}
+
+static void register_fo_entry(fo_entry * fo)
+{
+ void **aa;
+ if (fo_tree == NULL) {
+ fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+ }
+ if (lookup_fo_entry(fo->fm->tfm_name) == NULL) {
+ /*tex Is this a problem? */
+ } else {
+ /*tex The lookup also can create */
+ }
+ aa = avl_probe(fo_tree, fo);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+}
+
+/*tex
+
+In principle we could replace the pdftex derived ttf.otf inclusion part by using
+the regular code for this and assigning indices and tounicodes to the character
+blobs, but for the moment we keep the current approach.
+
+*/
+
+static void write_fontfile(PDF pdf, fd_entry * fd)
+{
+ if (is_cidkeyed(fd->fm)) {
+ if (is_opentype(fd->fm)) {
+ writetype0(pdf, fd);
+ } else if (is_truetype(fd->fm)) {
+ if (!writetype2(pdf, fd)) {
+ writetype0(pdf,fd);
+ fd->fm->type |= F_OTF; fd->fm->type ^= F_TRUETYPE;
+ }
+ } else if (is_type1(fd->fm)) {
+ writetype1w(pdf, fd);
+ } else {
+ normal_error("fonts","there is a problem writing the font file (1)");
+ }
+ } else {
+ if (is_type1(fd->fm)) {
+ writet1(pdf, fd);
+ } else if (is_truetype(fd->fm)) {
+ writettf(pdf, fd);
+ } else if (is_opentype(fd->fm)) {
+ writeotf(pdf, fd);
+ } else {
+ normal_error("fonts","there is a problem writing the font file (2)");
+ }
+ }
+ if (!fd->ff_found)
+ return;
+ fd->ff_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ /*tex The font file stream: */
+ pdf_begin_obj(pdf, fd->ff_objnum, OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ if (is_cidkeyed(fd->fm)) {
+ /*tex No subtype is used for |TRUETYPE\ based \OPENTYPE\ fonts. */
+ if (is_opentype(fd->fm) || is_type1(fd->fm)) {
+ pdf_dict_add_name(pdf, "Subtype", "CIDFontType0C");
+ }
+ } else if (is_type1(fd->fm)) {
+ pdf_dict_add_int(pdf, "Length1", (int) t1_length1);
+ pdf_dict_add_int(pdf, "Length2", (int) t1_length2);
+ pdf_dict_add_int(pdf, "Length3", (int) t1_length3);
+ } else if (is_truetype(fd->fm)) {
+ pdf_dict_add_int(pdf, "Length1", (int) ttf_length);
+ } else if (is_opentype(fd->fm)) {
+ pdf_dict_add_name(pdf, "Subtype", "Type1C");
+ } else {
+ normal_error("fonts","there is a problem writing the font file (3)");
+ }
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ strbuf_flush(pdf, pdf->fb);
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+}
+
+int cidset = 0;
+
+static void write_fontdescriptor(PDF pdf, fd_entry * fd)
+{
+ static const int std_flags[] = {
+ 1 + 2 + (1 << 5), /* Courier */
+ 1 + 2 + (1 << 5) + (1 << 18), /* Courier-Bold */
+ 1 + 2 + (1 << 5) + (1 << 6), /* Courier-Oblique */
+ 1 + 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Courier-BoldOblique */
+ (1 << 5), /* Helvetica */
+ (1 << 5) + (1 << 18), /* Helvetica-Bold */
+ (1 << 5) + (1 << 6), /* Helvetica-Oblique */
+ (1 << 5) + (1 << 6) + (1 << 18), /* Helvetica-BoldOblique */
+ 4, /* Symbol */
+ 2 + (1 << 5), /* Times-Roman */
+ 2 + (1 << 5) + (1 << 18), /* Times-Bold */
+ 2 + (1 << 5) + (1 << 6), /* Times-Italic */
+ 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Times-BoldItalic */
+ 4 /* ZapfDingbats */
+ };
+ char *glyph;
+ struct avl_traverser t;
+ int fd_flags;
+ /*tex Possibly updated by |write_fontfile|: */
+ cidset = 0;
+ if (fd->fd_objnum == 0) {
+ int n = 0;
+ int callback_id = callback_defined(font_descriptor_objnum_provider_callback);
+ if (callback_id) {
+ run_callback(callback_id, "S->d", fd->fontname, &n);
+ }
+ if (!n) {
+ n = pdf_create_obj(pdf, obj_type_others, 0);
+ }
+ fd->fd_objnum = n;
+ }
+ if (is_fontfile(fd->fm) && is_included(fd->fm)) {
+ /*tex This will set |fd->ff_found| if font file is found: */
+ write_fontfile(pdf, fd);
+ }
+ pdf_begin_obj(pdf, fd->fd_objnum, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "FontDescriptor");
+ pdf_dict_add_fontname(pdf, "FontName", fd);
+ if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE) {
+ fd_flags = (int) fd->fm->fd_flags;
+ } else if (fd->ff_found) {
+ fd_flags = FD_FLAGS_DEFAULT_EMBED;
+ } else {
+ fd_flags = is_std_t1font(fd->fm) ? std_flags[check_std_t1font(fd->fm->ps_name)] : FD_FLAGS_DEFAULT_NON_EMBED;
+ formatted_warning("map file",
+ "No flags specified for non-embedded font '%s' (%s), I'm using %i, fix your map entry",
+ fd->fm->ps_name != NULL ? fd->fm->ps_name : "No name given",
+ fd->fm->tfm_name, fd_flags);
+ }
+ pdf_dict_add_int(pdf, "Flags", fd_flags);
+ write_fontmetrics(pdf, fd);
+ if (fd->ff_found) {
+ if (is_cidkeyed(fd->fm)) {
+ if (is_type1(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+ else if (is_truetype(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
+ else if (is_opentype(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+ else
+ normal_error("fonts","there is a problem writing the font file (4)");
+ } else {
+ if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
+ /*tex |/CharSet| is optional; names may appear in any order */
+ if ((! pdf->omit_charset) && (pdf->major_version == 1)) {
+ avl_t_init(&t, fd->gl_tree);
+ pdf_add_name(pdf, "CharSet");
+ pdf_out(pdf, '(');
+ for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL; glyph = (char *) avl_t_next(&t)) {
+ pdf_add_name(pdf, glyph);
+ }
+ pdf_out(pdf, ')');
+ pdf_set_space(pdf);
+ }
+ }
+ if (is_type1(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile", (int) fd->ff_objnum);
+ else if (is_truetype(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
+ else if (is_opentype(fd->fm))
+ pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+ else
+ normal_error("fonts","there is a problem writing the font file (5)");
+ }
+ }
+ if ((! pdf->omit_cidset) && (pdf->major_version == 1) && (cidset != 0) ) {
+ pdf_dict_add_ref(pdf, "CIDSet", cidset);
+ }
+ /*tex
+ Currently we don't export the optional keys for CID fonts like |/Style <<
+ /Panose <12-byte string> >>| and we probably never will.
+ */
+ pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
+}
+
+static void write_fontdescriptors(PDF pdf)
+{
+ fd_entry *fd;
+ struct avl_traverser t;
+ if (fd_tree == NULL)
+ return;
+ avl_t_init(&t, fd_tree);
+ for (fd = (fd_entry *) avl_t_first(&t, fd_tree); fd != NULL; fd = (fd_entry *) avl_t_next(&t))
+ write_fontdescriptor(pdf, fd);
+}
+
+static void write_fontdictionary(PDF pdf, fo_entry * fo)
+{
+ /*tex Write the |/ToUnicode| entry if needed. */
+ if (pdf->gen_tounicode > 0 && fo->fd != NULL) {
+ if (fo->fe != NULL) {
+ fo->tounicode_objnum = write_tounicode(pdf, fo->fe->glyph_names, fo->fe->name);
+ } else if (is_type1(fo->fm)) {
+ fo->tounicode_objnum = write_tounicode(pdf, fo->fd->builtin_glyph_names, fo->fm->tfm_name);
+ }
+ }
+ pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Font");
+ if (is_type1(fo->fm))
+ pdf_dict_add_name(pdf, "Subtype", "Type1");
+ else if (is_truetype(fo->fm))
+ pdf_dict_add_name(pdf, "Subtype", "TrueType");
+ else if (is_opentype(fo->fm))
+ pdf_dict_add_name(pdf, "Subtype", "Type1");
+ else
+ normal_error("fonts","there is a problem writing the font file (6)");
+ pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+ pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
+ pdf_dict_add_int(pdf, "FirstChar", (int) fo->first_char);
+ pdf_dict_add_int(pdf, "LastChar", (int) fo->last_char);
+ pdf_dict_add_ref(pdf, "Widths", (int) fo->cw_objnum);
+ if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL && fo->fe->fe_objnum != 0)
+ pdf_dict_add_ref(pdf, "Encoding", (int) fo->fe->fe_objnum);
+ if (fo->tounicode_objnum != 0)
+ pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
+ if (pdf_font_attr(fo->tex_font) != get_nullstr() && pdf_font_attr(fo->tex_font) != 0) {
+ pdf_check_space(pdf);
+ pdf_print(pdf, pdf_font_attr(fo->tex_font));
+ pdf_set_space(pdf);
+ }
+ pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
+}
+
+static void write_fontdictionaries(PDF pdf)
+{
+ fo_entry *fo;
+ struct avl_traverser t;
+ if (fo_tree == NULL)
+ return;
+ avl_t_init(&t, fo_tree);
+ for (fo = (fo_entry *) avl_t_first(&t, fo_tree); fo != NULL; fo = (fo_entry *) avl_t_next(&t)) {
+ write_fontdictionary(pdf, fo);
+ }
+}
+
+/*tex
+
+ Final flush of all font related stuff by call from \.{Output fonts
+ definitions} elsewhere.
+
+*/
+
+void write_fontstuff(PDF pdf)
+{
+ write_fontdescriptors(pdf);
+ write_fontencodings(pdf);
+ write_fontdictionaries(pdf);
+}
+
+static void create_fontdictionary(PDF pdf, internal_font_number f)
+{
+ fo_entry *fo = new_fo_entry();
+ fm_entry *fm = font_map(f);
+ /*tex set |fo->first_char| and |fo->last_char| from |f| */
+ get_char_range(fo, f);
+ if (fo->last_char > 255)
+ fo->last_char = 255;
+ fo->fm = fm;
+ fo->fo_objnum = pdf_font_num(f);
+ fo->tex_font = f;
+ if (is_reencoded(fo->fm)) {
+ /*tex
+ At least the map entry tells so but it returns |NULL| if the .enc
+ file couldn't be opened.
+ */
+ fo->fe = get_fe_entry(fo->fm->encname);
+ if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) {
+ /*tex We don't end up here for truetype fonts. */
+ if (fo->fe->fe_objnum == 0) {
+ /*tex It will be written out */
+ fo->fe->fe_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ }
+ /*tex Mark encoding pairs used by TeX to optimize encoding vector. */
+ fo->fe->tx_tree = mark_chars(fo, fo->fe->tx_tree, f);
+ }
+ }
+ /*tex For |write_charwidth_array|: */
+ fo->tx_tree = mark_chars(fo, fo->tx_tree, f);
+ write_charwidth_array(pdf, fo, f);
+ if (!is_builtin(fo->fm)) {
+ if (is_type1(fo->fm)) {
+ if ((fo->fd = lookup_fontdescriptor(fo)) == NULL) {
+ create_fontdescriptor(fo, f);
+ register_fd_entry(fo->fd);
+ }
+ } else {
+ create_fontdescriptor(fo, f);
+ }
+ if (fo->fe != NULL) {
+ mark_reenc_glyphs(fo, f);
+ if (!is_type1(fo->fm)) {
+ /*tex Mark reencoded characters as chars on TeX level. */
+ assert(fo->fd->tx_tree == NULL);
+ fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+ if (is_truetype(fo->fm)) {
+ fo->fd->write_ttf_glyph_names = true;
+ }
+ }
+ } else {
+ /*tex Mark non-reencoded characters as chars on TeX level. */
+ fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+ }
+ if (!is_type1(fo->fm)) {
+ write_fontdescriptor(pdf, fo->fd);
+ }
+ } else {
+ /*tex
+ Builtin fonts still need the \type {/Widths} array and \type
+ {/FontDescriptor} (to avoid error \quotation {font FOO contains bad
+ \type {/BBox}}).
+ */
+ create_fontdescriptor(fo, f);
+ write_fontdescriptor(pdf, fo->fd);
+ if (!is_std_t1font(fo->fm)) {
+ formatted_warning("map file", "font '%s' is not a standard font; I suppose it is available to your PDF viewer then", fo->fm->ps_name);
+ }
+ }
+ if (is_type1(fo->fm)) {
+ register_fo_entry(fo);
+ } else {
+ write_fontdictionary(pdf, fo);
+ }
+}
+
+static int has_ttf_outlines(fm_entry * fm)
+{
+ FILE *f = fopen(fm->ff_name, "rb");
+ if (f != NULL) {
+ int ch1 = getc(f);
+ int ch2 = getc(f);
+ int ch3 = getc(f);
+ int ch4 = getc(f);
+ fclose(f);
+ if (ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O')
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+void do_pdf_font(PDF pdf, internal_font_number f)
+{
+ int del_file = 0;
+ fm_entry *fm;
+ /*tex
+ This is not 100\% true: CID is actually needed whenever (and only) there
+ are more than 256 separate glyphs used. But for now, we just assume the
+ user knows what he is doing. In practice this seems to be the case.
+ */
+ if (!font_has_subset(f))
+ return;
+ if (font_encodingbytes(f) == 2) {
+ /*tex
+ Create a virtual font map entry, as this is needed by the rest of the
+ font inclusion mechanism.
+ */
+ fm = font_map(f) = new_fm_entry();
+ /*tex Set this to a name or whatever, not a real \TFM\ anyway: */
+ fm->tfm_name = font_name(f);
+ /*tex The actual file: */
+ fm->ff_name = font_filename(f);
+ /*tex The true (used) name: */
+ if (font_psname(f) != NULL) {
+ fm->ps_name = font_psname(f);
+ } else {
+ fm->ps_name = font_fullname(f);
+ }
+ if (fm->ff_name
+ && strlen(fm->ff_name) >= 6
+ && strstr(fm->ff_name,".dfont") == (fm->ff_name + strlen(fm->ff_name) - 6)) {
+ /*tex
+
+ In case of a .dfont (an obsolete format), we will extract the
+ correct ttf here, and adjust |fm->ff_name| to point to the
+ temporary file. This file will be deleted later. Todo: keep a
+ nicer name somewhere for the terminal message.
+ */
+ char *s = FindResourceTtfFont(fm->ff_name, fm->ps_name);
+ if (s != NULL) {
+ fm->ff_name = s;
+ del_file = 1;
+ } else {
+ formatted_error("font","file '%s' does not contain font '%s'",fm->ff_name, fm->ps_name);
+ }
+ }
+ /*tex Needed for the CIDSystemInfo: */
+ fm->encname = font_encodingname(f);
+ fm->slant = font_slant(f);
+ set_slantset(fm);
+ fm->extend = font_extend(f);
+ set_extendset(fm);
+ /*tex Flags can perhaps be done better. */
+ fm->fd_flags = 4;
+ set_inuse(fm);
+ switch (font_format(f)) {
+ case opentype_format:
+ if (has_ttf_outlines(fm)) {
+ set_truetype(fm);
+ } else {
+ set_opentype(fm);
+ }
+ break;
+ case truetype_format:
+ set_truetype(fm);
+ break;
+ case type1_format:
+ set_type1(fm);
+ break;
+ default:
+ formatted_error("font","file format '%s' for '%s' is incompatible with wide characters",
+ font_format_name(f), font_name(f));
+ }
+ /*tex This makes \quotation {unknown} default to subsetted inclusion. */
+ if (font_embedding(f) != no_embedding) {
+ set_included(fm);
+ if (font_embedding(f) != full_embedding) {
+ set_subsetted(fm);
+ }
+ }
+ set_cidkeyed(fm);
+ create_cid_fontdictionary(pdf, f);
+ if (del_file)
+ unlink(fm->ff_name);
+ } else {
+ /*tex By now |font_map(f)|, if any, should have been set via |pdf_init_font|. */
+ if ((fm = font_map(f)) == NULL || (fm->ps_name == NULL && fm->ff_name == NULL))
+ writet3(pdf, f);
+ else
+ create_fontdictionary(pdf, f);
+ }
+}
+
+/*tex
+
+ The glyph width is included in |glw_entry|, because that width depends on the
+ value it has in the font where it is actually typeset from, not the font that
+ is the owner of the fd entry.
+
+ It is possible that the user messes with the metric width, but handling that
+ properly would require access to the |hmtx| table at this point in the
+ program.
+
+*/
+
+static int comp_glw_entry(const void *pa, const void *pb, void *p
+ __attribute__ ((unused)))
+{
+ unsigned short i, j;
+ i = (unsigned short) (*(const glw_entry *) pa).id;
+ j = (unsigned short) (*(const glw_entry *) pb).id;
+ cmp_return(i, j);
+ return 0;
+}
+
+static void create_cid_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+ fo->fd = new_fd_entry(f);
+ preset_fontname(fo, f);
+ preset_fontmetrics(fo->fd, f);
+ /*tex Encoding needed by \TRUETYPE\ writing: */
+ fo->fd->fe = fo->fe;
+ /*tex Map entry needed by \TRUETYPE\ writing */
+ fo->fd->fm = fo->fm;
+ fo->fd->gl_tree = avl_create(comp_glw_entry, NULL, &avl_xallocator);
+ assert(fo->fd->gl_tree != NULL);
+}
+
+
+/*tex
+
+ The values |font_bc()| and |font_ec()| are potentially large character ids,
+ but the strings that are written out use CID indexes, and those are limited
+ to 16-bit values.
+
+*/
+
+static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
+{
+ glw_entry *j;
+ void *aa;
+ int l = font_size(f);
+ int i;
+ for (i = font_bc(f); i <= font_ec(f); i++) {
+ if (quick_char_exists(f, i) && char_used(f, i)) {
+ j = xtalloc(1, glw_entry);
+ j->id = (unsigned) char_index(f, i);
+ j->wd = divide_scaled_n(char_width(f, i), l, 10000.0);
+ if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
+ aa = avl_probe(fo->fd->gl_tree, j);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ } else {
+ xfree(j);
+ }
+ }
+ }
+}
+
+/*tex
+
+ It is possible to compress the widths array even better, by using the
+ alternate 'range' syntax and possibly even using /DW to set a default value.
+
+ There is a some optimization here already: glyphs that are not used do not
+ appear in the widths array at all.
+
+ We have to make sure that we do not output an (incorrect!) width for a
+ character that exists in the font, but is not used in typesetting. An
+ enormous negative width is used as sentinel value
+
+*/
+
+static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
+{
+ int i, j;
+ glw_entry *glyph;
+ struct avl_traverser t;
+ fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
+ avl_t_init(&t, fo->fd->gl_tree);
+ glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree);
+ i = (int) glyph->id;
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, i);
+ pdf_begin_array(pdf);
+ for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) {
+ j = glyph->wd;
+ if (glyph->id > (unsigned) (i + 1)) {
+ pdf_end_array(pdf);
+ pdf_add_int(pdf, glyph->id);
+ pdf_begin_array(pdf);
+ j = glyph->wd;
+ }
+ pdf_check_space(pdf);
+ if (j < 0) {
+ pdf_out(pdf, '-');
+ j = -j;
+ }
+ pdf_printf(pdf, "%i", (j / 10));
+ if ((j % 10) != 0)
+ pdf_printf(pdf, ".%i", (j % 10));
+ i = (int) glyph->id;
+ pdf_set_space(pdf);
+ }
+ pdf_end_array(pdf);
+ pdf_end_array(pdf);
+ pdf_end_obj(pdf);
+}
+
+static void destroy_glw_cid_entry(void *pa, void *pb)
+{
+ glw_entry *e = (glw_entry *) pa;
+ (void) pb;
+ xfree(e);
+}
+
+
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
+{
+ fm_entry *fm = font_map(f);
+ fo_entry *fo = new_fo_entry();
+ /*tex set |fo->first_char| and |fo->last_char| from |f| */
+ get_char_range(fo, f);
+ fo->fm = fm;
+ fo->fo_objnum = pdf_font_num(f);
+ fo->tex_font = f;
+ create_cid_fontdescriptor(fo, f);
+ mark_cid_subset_glyphs(fo, f);
+ if (is_subsetted(fo->fm)) {
+ /*tex
+ This is a bit sneaky. |make_subset_tag()| actually expects the glyph
+ tree to contain strings instead of |glw_entry| items. However, all
+ calculations are done using explicit typecasts, so it works out ok.
+ */
+ make_subset_tag(fo->fd);
+ }
+ write_cid_charwidth_array(pdf, fo);
+ write_fontdescriptor(pdf, fo->fd);
+ write_cid_fontdictionary(pdf, fo, f);
+ if (fo->fd) {
+ if (fo->fd->gl_tree) {
+ avl_destroy(fo->fd->gl_tree,destroy_glw_cid_entry);
+ }
+ xfree(fo->fd);
+ }
+ xfree(fo);
+}
+
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+ int i;
+ fo->tounicode_objnum = write_cid_tounicode(pdf, fo, f);
+ pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Font");
+ pdf_dict_add_name(pdf, "Subtype", "Type0");
+ if (font_identity(f) == vertical_identity) {
+ pdf_dict_add_name(pdf, "Encoding", "Identity-V");
+ } else {
+ pdf_dict_add_name(pdf, "Encoding", "Identity-H");
+ }
+ pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+ i = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_add_name(pdf, "DescendantFonts");
+ pdf_begin_array(pdf);
+ pdf_add_ref(pdf, i);
+ pdf_end_array(pdf);
+ if (fo->tounicode_objnum != 0)
+ pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
+ pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
+ pdf_begin_obj(pdf, i, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Font");
+ if (is_opentype(fo->fm) || is_type1(fo->fm)) {
+ pdf_dict_add_name(pdf, "Subtype", "CIDFontType0");
+ } else {
+ pdf_dict_add_name(pdf, "Subtype", "CIDFontType2");
+ pdf_dict_add_name(pdf, "CIDToGIDMap", "Identity");
+ }
+ pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+ pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
+ pdf_dict_add_ref(pdf, "W", (int) fo->cw_objnum);
+ pdf_add_name(pdf, "CIDSystemInfo");
+ pdf_begin_dict(pdf);
+ pdf_dict_add_string(pdf, "Registry", (font_cidregistry(f) ? font_cidregistry(f) : "Adobe"));
+ pdf_dict_add_string(pdf, "Ordering", (font_cidordering(f) ? font_cidordering(f) : "Identity"));
+ pdf_dict_add_int(pdf, "Supplement", (int) font_cidsupplement(f));
+ pdf_end_dict(pdf);
+ /*tex
+ I doubt there is anything useful that could be written here so for now we
+ comment this.
+ */
+ /*
+ if (pdf_font_attr(fo->tex_font) != get_nullstr()) {
+ pdf_out(pdf, '\n');
+ pdf_print(pdf_font_attr(fo->tex_font));
+ pdf_out(pdf, '\n');
+ }
+ */
+ pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writefont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writefont.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writefont.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1116 +0,0 @@
-% writefont.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f);
-static void create_cid_fontdictionary(PDF pdf, internal_font_number f);
-
-const key_entry font_key[FONT_KEYS_NUM] = {
- { "Ascent", "Ascender", 1 },
- { "CapHeight", "CapHeight", 1 },
- { "Descent", "Descender", 1 },
- { "ItalicAngle", "ItalicAngle", 1 },
- { "StemV", "StdVW", 1 },
- { "XHeight", "XHeight", 1 },
- { "FontBBox", "FontBBox", 1 },
- { "", "", 0 },
- { "", "", 0 },
- { "", "", 0 },
- { "FontName", "FontName", 1 }
-};
-
-@
- at c
-struct avl_table *fo_tree = NULL; /* tree of font dictionaries */
-struct avl_table *fd_tree = NULL; /* tree of font descriptor objects */
-
-static int comp_fo_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp(((const fo_entry *) pa)->fm->tfm_name,
- ((const fo_entry *) pb)->fm->tfm_name);
-}
-
-static int comp_fd_entry(const void *pa, const void *pb, void *p)
-{
- const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb;
- (void) p;
- assert(p1->fm != NULL && is_fontfile(p1->fm) &&
- p2->fm != NULL && is_fontfile(p2->fm));
- return strcmp(p1->fm->ff_name, p2->fm->ff_name);
-}
-
-@ initialize data structure for /Type /Font
- at c
-static fo_entry *new_fo_entry(void)
-{
- fo_entry *fo;
- fo = xtalloc(1, fo_entry);
- fo->fo_objnum = 0;
- fo->tex_font = 0;
- fo->fm = NULL;
- fo->fd = NULL;
- fo->fe = NULL;
- fo->cw_objnum = 0;
- fo->first_char = 1;
- fo->last_char = 0;
- fo->tx_tree = NULL;
- fo->tounicode_objnum = 0;
- return fo;
-}
-
-@ initialize data structure for /Type /FontDescriptor
- at c
-fd_entry *new_fd_entry(internal_font_number f)
-{
- fd_entry *fd;
- int i;
- fd = xtalloc(1, fd_entry);
- fd->fd_objnum = 0;
- fd->fontname = NULL;
- fd->subset_tag = NULL;
- fd->ff_found = false;
- fd->ff_objnum = 0;
- fd->all_glyphs = false;
- fd->write_ttf_glyph_names = false;
- for (i = 0; i < FONT_KEYS_NUM; i++) {
- fd->font_dim[i].val = 0;
- fd->font_dim[i].set = false;
- }
- fd->fe = NULL;
- fd->builtin_glyph_names = NULL;
- fd->fm = NULL;
- fd->tx_tree = NULL;
- fd->gl_tree = NULL;
- fd->tex_font = f;
- return fd;
-}
-
-@
-Only fallback values of font metrics are taken from the TFM info
-of |f| by |preset_fontmetrics|. During reading of the font file,
-these values are replaced by metrics from the font, if available.
-
- at c
-static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
-{
- int i;
- fd->font_dim[ITALIC_ANGLE_CODE].val = 0;
- fd->font_dim[ASCENT_CODE].val =
- divide_scaled(char_height(f, 'h'), font_size(f), 3);
- fd->font_dim[CAPHEIGHT_CODE].val =
- divide_scaled(char_height(f, 'H'), font_size(f), 3);
- i = -divide_scaled(char_depth(f, 'y'), font_size(f), 3);
- fd->font_dim[DESCENT_CODE].val = i < 0 ? i : 0;
- fd->font_dim[STEMV_CODE].val =
- divide_scaled(char_width(f, '.') / 3, font_size(f), 3);
- fd->font_dim[XHEIGHT_CODE].val =
- divide_scaled(get_x_height(f), font_size(f), 3);
- fd->font_dim[FONTBBOX1_CODE].val = 0;
- fd->font_dim[FONTBBOX2_CODE].val = fd->font_dim[DESCENT_CODE].val;
- fd->font_dim[FONTBBOX3_CODE].val =
- divide_scaled(get_quad(f), font_size(f), 3);
- fd->font_dim[FONTBBOX4_CODE].val =
- fd->font_dim[CAPHEIGHT_CODE].val > fd->font_dim[ASCENT_CODE].val ?
- fd->font_dim[CAPHEIGHT_CODE].val : fd->font_dim[ASCENT_CODE].val;
- for (i = 0; i < INT_KEYS_NUM; i++)
- fd->font_dim[i].set = true;
-}
-
-static void fix_fontmetrics(fd_entry * fd)
-{
- int i;
- intparm *p = (intparm *) fd->font_dim;
- assert(p[FONTBBOX1_CODE].set && p[FONTBBOX2_CODE].set
- && p[FONTBBOX3_CODE].set && p[FONTBBOX4_CODE].set);
- /* make sure there is a rectangle */
- if (p[FONTBBOX3_CODE].val < p[FONTBBOX1_CODE].val) {
- i = p[FONTBBOX3_CODE].val;
- p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val;
- p[FONTBBOX1_CODE].val = i;
- } else if (p[FONTBBOX3_CODE].val == p[FONTBBOX1_CODE].val)
- p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val + 1;
- if (p[FONTBBOX4_CODE].val < p[FONTBBOX2_CODE].val) {
- i = p[FONTBBOX4_CODE].val;
- p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val;
- p[FONTBBOX2_CODE].val = i;
- } else if (p[FONTBBOX4_CODE].val == p[FONTBBOX2_CODE].val)
- p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val + 1;
- if (!p[ASCENT_CODE].set) {
- p[ASCENT_CODE].val = p[FONTBBOX4_CODE].val;
- p[ASCENT_CODE].set = true;
- }
- if (!p[DESCENT_CODE].set) {
- p[DESCENT_CODE].val = p[FONTBBOX2_CODE].val;
- p[DESCENT_CODE].set = true;
- }
- if (!p[CAPHEIGHT_CODE].set) {
- p[CAPHEIGHT_CODE].val = p[FONTBBOX4_CODE].val;
- p[CAPHEIGHT_CODE].set = true;
- }
-}
-
-static void write_fontmetrics(PDF pdf, fd_entry * fd)
-{
- int i;
- fix_fontmetrics(fd);
- pdf_add_name(pdf, font_key[FONTBBOX1_CODE].pdfname);
- pdf_begin_array(pdf);
- pdf_printf(pdf, "%i %i %i %i", (int) fd->font_dim[FONTBBOX1_CODE].val,
- (int) fd->font_dim[FONTBBOX2_CODE].val,
- (int) fd->font_dim[FONTBBOX3_CODE].val,
- (int) fd->font_dim[FONTBBOX4_CODE].val);
- pdf_end_array(pdf);
- for (i = 0; i < GEN_KEY_NUM; i++)
- if (fd->font_dim[i].set)
- pdf_dict_add_int(pdf, font_key[i].pdfname, fd->font_dim[i].val);
-}
-
-@
- at c
-static void preset_fontname(fo_entry * fo, internal_font_number f)
-{
- if (fo->fm->ps_name != NULL)
- fo->fd->fontname = xstrdup(fo->fm->ps_name); /* just fallback */
- else if (font_fullname(f) != NULL)
- fo->fd->fontname = xstrdup(font_fullname(f));
- else
- fo->fd->fontname = xstrdup(fo->fm->tfm_name);
-}
-
-static void pdf_dict_add_fontname(PDF pdf, const char *key, fd_entry * fd)
-{
- char *s;
- size_t l1 = 0, l2;
- assert(fd->fontname != NULL);
- assert(key != NULL);
- if (fd->subset_tag != NULL)
- l1 = strlen(fd->subset_tag);
- l2 = strlen(fd->fontname);
- s = xmalloc(l1 + l2 + 2);
- if (l1 > 0)
- snprintf(s, l1 + l2 + 2, "%s+%s", fd->subset_tag, fd->fontname);
- else
- snprintf(s, l2 + 1, "%s", fd->fontname);
- pdf_dict_add_name(pdf, key, s);
- xfree(s);
-}
-
-@
- at c
-fd_entry *lookup_fd_entry(char *s)
-{
- fd_entry fd;
- fm_entry fm;
- assert(s != NULL);
- fm.ff_name = s;
- fd.fm = &fm;
- if (fd_tree == NULL) {
- fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
- assert(fd_tree != NULL);
- }
- return (fd_entry *) avl_find(fd_tree, &fd);
-}
-
-static fd_entry *lookup_fontdescriptor(fo_entry * fo)
-{
- assert(fo != NULL);
- assert(fo->fm != NULL);
- assert(is_fontfile(fo->fm));
- return lookup_fd_entry(fo->fm->ff_name);
-}
-
-void register_fd_entry(fd_entry * fd)
-{
- void **aa;
- if (fd_tree == NULL) {
- fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
- assert(fd_tree != NULL);
- }
- assert(fd != NULL && fd->fm != NULL && is_fontfile(fd->fm));
- /* font descriptor not yet registered: */
- assert(lookup_fd_entry(fd->fm->ff_name) == NULL);
- aa = avl_probe(fd_tree, fd);
- assert(aa != NULL);
-}
-
-static void create_fontdescriptor(fo_entry * fo, internal_font_number f)
-{
- assert(fo != NULL);
- assert(fo->fm != NULL);
- assert(fo->fd == NULL);
- fo->fd = new_fd_entry(f);
- preset_fontname(fo, f);
- preset_fontmetrics(fo->fd, f);
- /* encoding needed by TrueType writing: */
- fo->fd->fe = fo->fe;
- /* map entry needed by TrueType writing: */
- fo->fd->fm = fo->fm;
- fo->fd->gl_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
- assert(fo->fd->gl_tree != NULL);
-}
-
-@
-For all used characters of \TeX font |f|, get corresponding glyph names
-from external reencoding (.enc) file and collect these in the glyph
-tree |gl_tree| of font descriptor |fd| referenced by font dictionary |fo|.
-
- at c
-static void mark_reenc_glyphs(fo_entry * fo, internal_font_number f)
-{
- int i;
- char **g;
- void **aa;
- assert(fo->fe != NULL);
- if (is_subsetted(fo->fm)) {
- assert(is_included(fo->fm));
- /* mark glyphs from TeX (externally reencoded characters) */
- g = fo->fe->glyph_names;
- for (i = fo->first_char; i <= fo->last_char; i++) {
- if (pdf_char_marked(f, i)
- && g[i] != notdef
- && (char *) avl_find(fo->fd->gl_tree, g[i]) == NULL) {
- aa = avl_probe(fo->fd->gl_tree, xstrdup(g[i]));
- assert(aa != NULL);
- }
- }
- }
-}
-
-@
-Function |mark_chars| has 2 uses:
-\item 1. Mark characters as chars on \TeX\ level.
-\item 2. Mark encoding pairs used by \TeX\ to optimize encoding vector.
-
- at c
-static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree,
- internal_font_number f)
-{
- int i, *j;
- void **aa;
- if (tx_tree == NULL) {
- tx_tree = avl_create(comp_int_entry, NULL, &avl_xallocator);
- assert(tx_tree != NULL);
- }
- for (i = fo->first_char; i <= fo->last_char; i++) {
- if (pdf_char_marked(f, i) && (int *) avl_find(tx_tree, &i) == NULL) {
- j = xtalloc(1, int);
- *j = i;
- aa = avl_probe(tx_tree, j);
- assert(aa != NULL);
- }
- }
- return tx_tree;
-}
-
-@
- at c
-static void get_char_range(fo_entry * fo, internal_font_number f)
-{
- int i;
- assert(fo != NULL);
- /* search for |first_char| and |last_char| */
- for (i = font_bc(f); i <= font_ec(f); i++)
- if (pdf_char_marked(f, i))
- break;
- fo->first_char = i;
- for (i = font_ec(f); i >= font_bc(f); i--)
- if (pdf_char_marked(f, i))
- break;
- fo->last_char = i;
- if ((fo->first_char > fo->last_char) || !pdf_char_marked(f, fo->first_char)) {
- /* no character used from this font */
- fo->last_char = 0;
- fo->first_char = fo->last_char + 1;
- }
-}
-
-static int font_has_subset(internal_font_number f)
-{
- int i, s;
- /* search for |first_char| and |last_char| */
- for (i = font_bc(f); i <= font_ec(f); i++)
- if (pdf_char_marked(f, i))
- break;
- s = i;
- for (i = font_ec(f); i >= font_bc(f); i--)
- if (pdf_char_marked(f, i))
- break;
- if (s > i)
- return 0;
- else
- return 1;
-}
-
-@
- at c
-static void write_charwidth_array(PDF pdf, fo_entry * fo, internal_font_number f)
-{
- int i, j, *ip, *fip;
- struct avl_traverser t;
- assert(fo->tx_tree != NULL);
- assert(fo->cw_objnum == 0);
- fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
- avl_t_init(&t, fo->tx_tree);
- fip = (int *) avl_t_first(&t, fo->tx_tree);
- assert(fip != NULL);
- pdf_begin_array(pdf);
- for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) {
- if (ip != fip)
- pdf_out(pdf, ' ');
- i = *ip;
- while (j < i - 1) {
- pdf_puts(pdf, "0 ");
- j++;
- }
- j = i;
- pdf_print_charwidth(pdf, f, i);
- }
- pdf_end_array(pdf);
- pdf_end_obj(pdf);
-}
-
-@ Remark: Font objects from embedded PDF files are never registered
-into |fo_tree|; they are individually written out.
- at c
-static fo_entry *lookup_fo_entry(char *s)
-{
- fo_entry fo;
- fm_entry fm;
- assert(s != NULL);
- fm.tfm_name = s;
- fo.fm = &fm;
- if (fo_tree == NULL) {
- fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
- assert(fo_tree != NULL);
- }
- return (fo_entry *) avl_find(fo_tree, &fo);
-}
-
-static void register_fo_entry(fo_entry * fo)
-{
- void **aa;
- if (fo_tree == NULL) {
- fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
- assert(fo_tree != NULL);
- }
- assert(fo != NULL);
- assert(fo->fm != NULL);
- assert(fo->fm->tfm_name != NULL);
- assert(lookup_fo_entry(fo->fm->tfm_name) == NULL);
- aa = avl_probe(fo_tree, fo);
- assert(aa != NULL);
-}
-
-@
-In principle we could replace the pdftex derived ttf.otf inclusion part
-by using the regular code for this and assigning indices and tounicodes
-to the character blobs, but for the moment we keep the current approach.
- at c
-static void write_fontfile(PDF pdf, fd_entry * fd)
-{
- assert(is_included(fd->fm));
- if (is_cidkeyed(fd->fm)) {
- if (is_opentype(fd->fm)) {
- writetype0(pdf, fd);
- } else if (is_truetype(fd->fm)) {
- if (!writetype2(pdf, fd)) {
- writetype0(pdf,fd);
- fd->fm->type |= F_OTF; fd->fm->type ^= F_TRUETYPE;
- }
- } else if (is_type1(fd->fm))
- writetype1w(pdf, fd);
- else
- assert(0);
- } else {
- if (is_type1(fd->fm))
- writet1(pdf, fd);
- else if (is_truetype(fd->fm))
- writettf(pdf, fd);
- else if (is_opentype(fd->fm))
- writeotf(pdf, fd);
- else
- assert(0);
- }
- if (!fd->ff_found)
- return;
- assert(fd->ff_objnum == 0);
- fd->ff_objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, fd->ff_objnum, OBJSTM_NEVER); /* font file stream */
- pdf_begin_dict(pdf);
- if (is_cidkeyed(fd->fm)) {
- /* No subtype is used for TrueType-based OpenType fonts */
- if (is_opentype(fd->fm) || is_type1(fd->fm))
- pdf_dict_add_name(pdf, "Subtype", "CIDFontType0C");
-#if 0
- else
- pdf_dict_add_name(pdf, "Subtype", "OpenType");
-#endif
- } else if (is_type1(fd->fm)) {
- pdf_dict_add_int(pdf, "Length1", (int) t1_length1);
- pdf_dict_add_int(pdf, "Length2", (int) t1_length2);
- pdf_dict_add_int(pdf, "Length3", (int) t1_length3);
- } else if (is_truetype(fd->fm)) {
- pdf_dict_add_int(pdf, "Length1", (int) ttf_length);
- } else if (is_opentype(fd->fm)) {
- pdf_dict_add_name(pdf, "Subtype", "Type1C");
- } else {
- assert(0); /* todo: error messages */
- }
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- strbuf_flush(pdf, pdf->fb);
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
-}
-
-@
- at c
-int cidset = 0;
-static void write_fontdescriptor(PDF pdf, fd_entry * fd)
-{
- static const int std_flags[] = {
- /*
- The indices for << start with 0, but bits start with 1, so the
- numbers for << are 1 lower than the bits in table 5.20.
- */
- /* *INDENT-OFF* */
- 1 + 2 + (1 << 5), /* Courier */
- 1 + 2 + (1 << 5) + (1 << 18), /* Courier-Bold */
- 1 + 2 + (1 << 5) + (1 << 6), /* Courier-Oblique */
- 1 + 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Courier-BoldOblique */
- (1 << 5), /* Helvetica */
- (1 << 5) + (1 << 18), /* Helvetica-Bold */
- (1 << 5) + (1 << 6), /* Helvetica-Oblique */
- (1 << 5) + (1 << 6) + (1 << 18), /* Helvetica-BoldOblique */
- 4, /* Symbol */
- 2 + (1 << 5), /* Times-Roman */
- 2 + (1 << 5) + (1 << 18), /* Times-Bold */
- 2 + (1 << 5) + (1 << 6), /* Times-Italic */
- 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Times-BoldItalic */
- 4 /* ZapfDingbats */
- /* *INDENT-ON* */
- };
- char *glyph;
- struct avl_traverser t;
- int fd_flags;
- assert(fd != NULL && fd->fm != NULL);
- cidset = 0; /* possibly updated by |write_fontfile| */
- if (is_fontfile(fd->fm) && is_included(fd->fm)) {
- /* this will set |fd->ff_found| if font file is found */
- write_fontfile(pdf, fd);
- }
- if (fd->fd_objnum == 0)
- fd->fd_objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, fd->fd_objnum, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "FontDescriptor");
- pdf_dict_add_fontname(pdf, "FontName", fd);
- if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE)
- fd_flags = (int) fd->fm->fd_flags;
- else if (fd->ff_found)
- fd_flags = FD_FLAGS_DEFAULT_EMBED;
- else {
- fd_flags = is_std_t1font(fd->fm)
- ? std_flags[check_std_t1font(fd->fm->ps_name)]
- : FD_FLAGS_DEFAULT_NON_EMBED;
- formatted_warning("map file",
- "No flags specified for non-embedded font '%s' (%s), I'm using %i, fix your map entry",
- fd->fm->ps_name != NULL ? fd->fm->ps_name : "No name given",
- fd->fm->tfm_name, fd_flags);
- }
- pdf_dict_add_int(pdf, "Flags", fd_flags);
- write_fontmetrics(pdf, fd);
- if (fd->ff_found) {
- if (is_cidkeyed(fd->fm)) {
- if (is_type1(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
- else if (is_truetype(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
- else if (is_opentype(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
- else
- assert(0);
- } else {
- if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
- /* /CharSet is optional; names may appear in any order */
- assert(fd->gl_tree != NULL);
- avl_t_init(&t, fd->gl_tree);
- pdf_add_name(pdf, "CharSet");
- pdf_out(pdf, '(');
- for (glyph = (char *) avl_t_first(&t, fd->gl_tree);
- glyph != NULL; glyph = (char *) avl_t_next(&t))
- pdf_add_name(pdf, glyph);
- pdf_out(pdf, ')');
- pdf->cave = 0;
- }
- if (is_type1(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile", (int) fd->ff_objnum);
- else if (is_truetype(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
- else if (is_opentype(fd->fm))
- pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
- else
- assert(0);
- }
- }
- if ((! pdf->omit_cidset) && (pdf->major_version == 1) && (cidset != 0) ) {
- pdf_dict_add_ref(pdf, "CIDSet", cidset);
- }
- /*
- Currently we don't export the optional keys for CID fonts like
- \.{/Style << /Panose <12-byte string> >>} and we probably never
- will.
- */
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
-}
-
-static void write_fontdescriptors(PDF pdf)
-{
- fd_entry *fd;
- struct avl_traverser t;
- if (fd_tree == NULL)
- return;
- avl_t_init(&t, fd_tree);
- for (fd = (fd_entry *) avl_t_first(&t, fd_tree); fd != NULL; fd = (fd_entry *) avl_t_next(&t))
- write_fontdescriptor(pdf, fd);
-}
-
-@
- at c
-static void write_fontdictionary(PDF pdf, fo_entry * fo)
-{
- assert(fo != NULL);
- assert(fo->fm != NULL);
- /* reserved as |pdf_font_num(f)| elsewhere: */
- assert(fo->fo_objnum != 0);
-
- /* write ToUnicode entry if needed */
- if (pdf->gen_tounicode > 0 && fo->fd != NULL) {
- if (fo->fe != NULL) {
- fo->tounicode_objnum = write_tounicode(pdf, fo->fe->glyph_names, fo->fe->name);
- } else if (is_type1(fo->fm)) {
- assert(fo->fd->builtin_glyph_names != NULL);
- fo->tounicode_objnum = write_tounicode(pdf, fo->fd->builtin_glyph_names, fo->fm->tfm_name);
- }
- }
- pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Font");
- if (is_type1(fo->fm))
- pdf_dict_add_name(pdf, "Subtype", "Type1");
- else if (is_truetype(fo->fm))
- pdf_dict_add_name(pdf, "Subtype", "TrueType");
- else if (is_opentype(fo->fm))
- pdf_dict_add_name(pdf, "Subtype", "Type1");
- else
- assert(0);
- assert(fo->fd != NULL && fo->fd->fd_objnum != 0);
- pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
- pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
- assert(fo->cw_objnum != 0);
- pdf_dict_add_int(pdf, "FirstChar", (int) fo->first_char);
- pdf_dict_add_int(pdf, "LastChar", (int) fo->last_char);
- pdf_dict_add_ref(pdf, "Widths", (int) fo->cw_objnum);
- if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL && fo->fe->fe_objnum != 0)
- pdf_dict_add_ref(pdf, "Encoding", (int) fo->fe->fe_objnum);
- if (fo->tounicode_objnum != 0)
- pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
- if (pdf_font_attr(fo->tex_font) != get_nullstr() && pdf_font_attr(fo->tex_font) != 0) {
- pdf_print(pdf, pdf_font_attr(fo->tex_font));
- pdf_out(pdf, '\n');
- }
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
-}
-
-static void write_fontdictionaries(PDF pdf)
-{
- fo_entry *fo;
- struct avl_traverser t;
- if (fo_tree == NULL)
- return;
- avl_t_init(&t, fo_tree);
- for (fo = (fo_entry *) avl_t_first(&t, fo_tree); fo != NULL; fo = (fo_entry *) avl_t_next(&t))
- write_fontdictionary(pdf, fo);
-}
-
-@ Final flush of all font related stuff by call from \.{Output fonts
-definitions} elsewhere
- at c
-void write_fontstuff(PDF pdf)
-{
- write_fontdescriptors(pdf);
- write_fontencodings(pdf); /* see \.{writeenc.w} */
- write_fontdictionaries(pdf);
-}
-
-@
- at c
-static void create_fontdictionary(PDF pdf, internal_font_number f)
-{
- fo_entry *fo = new_fo_entry();
- fm_entry *fm = font_map(f);
- /* set |fo->first_char| and |fo->last_char| from |f| */
- get_char_range(fo, f);
- if (fo->last_char > 255)
- fo->last_char = 255;
- assert(fo->last_char >= fo->first_char);
- fo->fm = fm;
- fo->fo_objnum = pdf_font_num(f);
- fo->tex_font = f;
- if (is_reencoded(fo->fm)) {
- /*
- At least the map entry tells so but it returns |NULL| if the .enc
- file couldn't be opened.
- */
- fo->fe = get_fe_entry(fo->fm->encname);
- if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) {
- /* We don't end up here for truetype fonts. */
- if (fo->fe->fe_objnum == 0)
- fo->fe->fe_objnum = pdf_create_obj(pdf, obj_type_others, 0); /* then it will be written out */
- /* Mark encoding pairs used by TeX to optimize encoding vector. */
- fo->fe->tx_tree = mark_chars(fo, fo->fe->tx_tree, f);
- }
- }
- /* for |write_charwidth_array|: */
- fo->tx_tree = mark_chars(fo, fo->tx_tree, f);
- write_charwidth_array(pdf, fo, f);
- if (!is_builtin(fo->fm)) {
- if (is_type1(fo->fm)) {
- if ((fo->fd = lookup_fontdescriptor(fo)) == NULL) {
- create_fontdescriptor(fo, f);
- register_fd_entry(fo->fd);
- }
- } else {
- create_fontdescriptor(fo, f);
- }
- if (fo->fe != NULL) {
- mark_reenc_glyphs(fo, f);
- if (!is_type1(fo->fm)) {
- /* mark reencoded characters as chars on TeX level */
- assert(fo->fd->tx_tree == NULL);
- fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
- if (is_truetype(fo->fm)) {
- fo->fd->write_ttf_glyph_names = true;
- }
- }
- } else {
- /* mark non-reencoded characters as chars on TeX level */
- fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
- }
- if (!is_type1(fo->fm)) {
- write_fontdescriptor(pdf, fo->fd);
- }
- } else {
- /*
- Builtin fonts still need the /Widths array and /FontDescriptor
- (to avoid error 'font FOO contains bad /BBox').
- */
- create_fontdescriptor(fo, f);
- write_fontdescriptor(pdf, fo->fd);
- if (!is_std_t1font(fo->fm)) {
- formatted_warning("map file", "font '%s' is not a standard font; I suppose it is available to your PDF viewer then", fo->fm->ps_name);
- }
- }
- if (is_type1(fo->fm)) {
- register_fo_entry(fo);
- } else {
- write_fontdictionary(pdf, fo);
- }
-}
-
-@
- at c
-static int has_ttf_outlines(fm_entry * fm)
-{
- FILE *f = fopen(fm->ff_name, "rb");
- if (f != NULL) {
- int ch1 = getc(f);
- int ch2 = getc(f);
- int ch3 = getc(f);
- int ch4 = getc(f);
- fclose(f);
- if (ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O')
- return 0;
- return 1;
- }
- return 0;
-}
-
-void do_pdf_font(PDF pdf, internal_font_number f)
-{
- int del_file = 0;
- fm_entry *fm;
- /*
- This is not 100\% true: CID is actually needed whenever (and
- only) there are more than 256 separate glyphs used. But for
- now, we just assume the user knows what he is doing. In practice
- this seems to be the case.
- */
- if (!font_has_subset(f))
- return;
-
- if (font_encodingbytes(f) == 2) {
- /*
- Create a virtual font map entry, as this is needed by the
- rest of the font inclusion mechanism.
- */
- fm = font_map(f) = new_fm_entry();
- fm->tfm_name = font_name(f); /* or whatever, not a real tfm */
- fm->ff_name = font_filename(f); /* the actual file */
- if (font_psname(f) != NULL)
- fm->ps_name = font_psname(f); /* the true name */
- else
- fm->ps_name = font_fullname(f); /* the true name */
- if (fm->ff_name
- && strlen(fm->ff_name) >= 6
- && strstr(fm->ff_name,".dfont") == (fm->ff_name + strlen(fm->ff_name) - 6)) {
- /*
- In case of a .dfont, we will extract the correct ttf here,
- and adjust |fm->ff_name| to point to the temporary file.
- This file will be deleted later. Todo: keep a nicer name
- somewhere for the terminal message.
-
- Support for dfonts will be removed at some point anyhow.
- */
- char *s = FindResourceTtfFont(fm->ff_name, fm->ps_name);
- if (s != NULL) {
- fm->ff_name = s;
- del_file = 1;
- } else {
- formatted_error("font","file '%s' does not contain font '%s'",fm->ff_name, fm->ps_name);
- }
- }
- /* Needed for the CIDSystemInfo: */
- fm->encname = font_encodingname(f);
- fm->slant = font_slant(f);
- set_slantset(fm);
- fm->extend = font_extend(f);
- set_extendset(fm);
- /* Flags can perhaps be done better. */
- fm->fd_flags = 4;
- set_inuse(fm);
-
- switch (font_format(f)) {
- case opentype_format:
- if (has_ttf_outlines(fm)) {
- set_truetype(fm);
- } else {
- set_opentype(fm);
- }
- break;
- case truetype_format:
- set_truetype(fm);
- break;
- case type1_format:
- set_type1(fm);
- break;
- default:
- formatted_error("font","file format '%s' for '%s' is incompatible with wide characters",
- font_format_name(f), font_name(f));
- }
- /* This makes "unknown" default to subsetted inclusion */
- if (font_embedding(f) != no_embedding) {
- set_included(fm);
- if (font_embedding(f) != full_embedding) {
- set_subsetted(fm);
- }
- }
- set_cidkeyed(fm);
- create_cid_fontdictionary(pdf, f);
-
- if (del_file)
- unlink(fm->ff_name);
-
- } else {
- /*
- By now |font_map(f)|, if any, should have been set via
- |pdf_init_font()|.
- */
- if ((fm = font_map(f)) == NULL
- || (fm->ps_name == NULL && fm->ff_name == NULL))
- writet3(pdf, f);
- else
- create_fontdictionary(pdf, f);
- }
-}
-
-@ The glyph width is included in |glw_entry|, because that width
-depends on the value it has in the font where it is actually
-typeset from, not the font that is the 'owner' of the fd entry.
-
-TODO: It is possible that the user messes with the metric width,
-but handling that properly would require access to the 'hmtx' table
-at this point in the program.
-
- at c
-static int comp_glw_entry(const void *pa, const void *pb, void *p
- __attribute__ ((unused)))
-{
- unsigned short i, j;
-
- i = (unsigned short) (*(const glw_entry *) pa).id;
- j = (unsigned short) (*(const glw_entry *) pb).id;
- cmp_return(i, j);
- return 0;
-}
-
-static void create_cid_fontdescriptor(fo_entry * fo, internal_font_number f)
-{
- assert(fo != NULL);
- assert(fo->fm != NULL);
- assert(fo->fd == NULL);
- fo->fd = new_fd_entry(f);
- preset_fontname(fo, f);
- preset_fontmetrics(fo->fd, f);
- fo->fd->fe = fo->fe; /* encoding needed by TrueType writing */
- fo->fd->fm = fo->fm; /* map entry needed by TrueType writing */
- fo->fd->gl_tree = avl_create(comp_glw_entry, NULL, &avl_xallocator);
- assert(fo->fd->gl_tree != NULL);
-}
-
-
-@ The values |font_bc()| and |font_ec()| are potentially large character
-ids, but the strings that are written out use CID indexes, and those are
-limited to 16-bit values.
-
- at c
-/*
- This is old code ... it fails when the order of using the same font at
- different extends changes. Probably because widths get overwritten or
- set wrong. The loop also looks kind of weird (why a loop).
-*/
-
-/*
-static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
-{
- int i, k, l;
- glw_entry *j;
- void *aa;
- for (k = 1; k <= max_font_id(); k++) {
- if (k == f || -f == pdf_font_num(k)) {
- l = font_size(k);
- for (i = font_bc(k); i <= font_ec(k); i++) {
- if (quick_char_exists(k, i) && char_used(k, i)) {
- j = xtalloc(1, glw_entry);
- j->id = (unsigned) char_index(k, i);
- j->wd = divide_scaled_n(char_width(k, i), l, 10000.0);
- if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
- aa = avl_probe(fo->fd->gl_tree, j);
- assert(aa != NULL);
- } else {
- xfree(j);
- }
- }
- }
- }
- }
-}
-*/
-
-/*
- So, let's try the following.
-*/
-
-static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
-{
- glw_entry *j;
- void *aa;
- int l = font_size(f);
- int i;
- for (i = font_bc(f); i <= font_ec(f); i++) {
- if (quick_char_exists(f, i) && char_used(f, i)) {
- j = xtalloc(1, glw_entry);
- j->id = (unsigned) char_index(f, i);
- j->wd = divide_scaled_n(char_width(f, i), l, 10000.0);
- if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
- aa = avl_probe(fo->fd->gl_tree, j);
- assert(aa != NULL);
- } else {
- xfree(j);
- }
- }
- }
-}
-
-@ It is possible to compress the widths array even better, by using the
-alternate 'range' syntax and possibly even using /DW to set a default
-value.
-
-There is a some optimization here already: glyphs that are not used do
-not appear in the widths array at all.
-
-We have to make sure that we do not output an (incorrect!) width for a
-character that exists in the font, but is not used in typesetting. An
-enormous negative width is used as sentinel value
-
- at c
-static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
-{
- int i, j;
- glw_entry *glyph;
- struct avl_traverser t;
-
- assert(fo->cw_objnum == 0);
- fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
- avl_t_init(&t, fo->fd->gl_tree);
- glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree);
- assert(glyph != NULL);
- i = (int) glyph->id;
- pdf_begin_array(pdf);
- pdf_add_int(pdf, i);
- pdf_begin_array(pdf);
- for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) {
- j = glyph->wd;
- if (glyph->id > (unsigned) (i + 1)) {
- pdf_end_array(pdf);
- pdf_add_int(pdf, glyph->id);
- pdf_begin_array(pdf);
- j = glyph->wd;
- }
- if (glyph->id == (unsigned) (i + 1))
- pdf_out(pdf, ' ');
-
- if (j < 0) {
- pdf_out(pdf, '-');
- j = -j;
- }
-
- pdf_printf(pdf, "%i", (j / 10));
- if ((j % 10) != 0)
- pdf_printf(pdf, ".%i", (j % 10));
-
- i = (int) glyph->id;
- }
- pdf_end_array(pdf);
- pdf_end_array(pdf);
- pdf_end_obj(pdf);
-}
-
-static void destroy_glw_cid_entry(void *pa, void *pb)
-{
- glw_entry *e = (glw_entry *) pa;
- (void) pb;
- xfree(e);
-}
-
-
-static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
-{
- fm_entry *fm = font_map(f);
- fo_entry *fo = new_fo_entry();
- get_char_range(fo, f); /* set |fo->first_char| and |fo->last_char| from |f| */
- assert(fo->last_char >= fo->first_char);
- fo->fm = fm;
- fo->fo_objnum = pdf_font_num(f);
- fo->tex_font = f;
- create_cid_fontdescriptor(fo, f);
- mark_cid_subset_glyphs(fo, f);
- if (is_subsetted(fo->fm)) {
- /*
- This is a bit sneaky. |make_subset_tag()| actually expects the glyph
- tree to contain strings instead of |glw_entry| items. However, all
- calculations are done using explicit typecasts, so it works out ok.
- */
- make_subset_tag(fo->fd);
- }
- write_cid_charwidth_array(pdf, fo);
- write_fontdescriptor(pdf, fo->fd);
-
- write_cid_fontdictionary(pdf, fo, f);
- if (fo->fd) {
- if (fo->fd->gl_tree){
- avl_destroy(fo->fd->gl_tree,destroy_glw_cid_entry);
- }
- xfree(fo->fd);
- }
- xfree(fo);
-}
-
-@ @c
-void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
-{
- int i;
-
- fo->tounicode_objnum = write_cid_tounicode(pdf, fo, f);
-
- pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Font");
- pdf_dict_add_name(pdf, "Subtype", "Type0");
- if (font_identity(f) == vertical_identity) {
- pdf_dict_add_name(pdf, "Encoding", "Identity-V");
- } else {
- pdf_dict_add_name(pdf, "Encoding", "Identity-H");
- }
- pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
- i = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_add_name(pdf, "DescendantFonts");
- pdf_begin_array(pdf);
- pdf_add_ref(pdf, i);
- pdf_end_array(pdf);
- /* todo: the ToUnicode CMap */
- if (fo->tounicode_objnum != 0)
- pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
-
- pdf_begin_obj(pdf, i, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Font");
- if (is_opentype(fo->fm) || is_type1(fo->fm)) {
- pdf_dict_add_name(pdf, "Subtype", "CIDFontType0");
- } else {
- pdf_dict_add_name(pdf, "Subtype", "CIDFontType2");
- pdf_dict_add_name(pdf, "CIDToGIDMap", "Identity");
- }
- pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
- pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
- pdf_dict_add_ref(pdf, "W", (int) fo->cw_objnum);
- pdf_add_name(pdf, "CIDSystemInfo");
- pdf_begin_dict(pdf);
- pdf_dict_add_string(pdf, "Registry", (font_cidregistry(f) ? font_cidregistry(f) : "Adobe"));
- pdf_dict_add_string(pdf, "Ordering", (font_cidordering(f) ? font_cidordering(f) : "Identity"));
- pdf_dict_add_int(pdf, "Supplement", (int) font_cidsupplement(f));
- pdf_end_dict(pdf);
-
- /* I doubt there is anything useful that could be written here */
-
-#if 0
- if (pdf_font_attr(fo->tex_font) != get_nullstr()) {
- pdf_out(pdf, '\n');
- pdf_print(pdf_font_attr(fo->tex_font));
- pdf_out(pdf, '\n');
- }
-#endif
-
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
-}
Added: trunk/Build/source/texk/web2c/luatexdir/font/writet1.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writet1.c (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writet1.c 2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1693 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2009 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <string.h>
+
+#define get_length1() t1_length1 = t1_offset() - t1_save_offset
+#define get_length2() t1_length2 = t1_offset() - t1_save_offset
+#define get_length3() t1_length3 = fixedcontent? t1_offset() - t1_save_offset : 0
+#define save_offset() t1_save_offset = t1_offset()
+#define t1_putchar(A) strbuf_putchar(pdf->fb, (A))
+#define t1_offset() strbuf_offset(pdf->fb)
+#define out_eexec_char t1_putchar
+#define end_last_eexec_line() t1_eexec_encrypt = false
+#define t1_char(c) c
+#define embed_all_glyphs(tex_font) fm_cur->all_glyphs
+#define extra_charset() fm_cur->charset
+#define fixedcontent false
+
+int t1_length1, t1_length2, t1_length3;
+static int t1_save_offset;
+static int t1_fontname_offset;
+
+static unsigned char *t1_buffer = NULL;
+static int t1_size = 0;
+static int t1_curbyte = 0;
+
+#define t1_read_file() readbinfile(t1_file,&t1_buffer,&t1_size)
+#define t1_close() xfclose(t1_file,cur_file_name)
+#define t1_getchar() t1_buffer[t1_curbyte++]
+#define t1_ungetchar(c) t1_curbyte--
+#define t1_eof() (t1_curbyte>t1_size)
+
+#define t1_prefix(s) str_prefix(t1_line_array, s)
+#define t1_buf_prefix(s) str_prefix(t1_buf_array, s)
+#define t1_suffix(s) str_suffix(t1_line_array, t1_line_ptr, s)
+#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s)
+#define t1_charstrings() strstr(t1_line_array, charstringname)
+#define t1_subrs() t1_prefix("/Subrs")
+#define t1_end_eexec() t1_suffix("mark currentfile closefile")
+#define t1_cleartomark() t1_prefix("cleartomark")
+
+static unsigned char *enc_buffer = NULL;
+static int enc_size = 0;
+static int enc_curbyte = 0;
+
+#define enc_open(a) (enc_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+#define enc_read_file() readbinfile(enc_file,&enc_buffer,&enc_size)
+#define enc_close() xfclose(enc_file,cur_file_name)
+#define enc_getchar() enc_buffer[enc_curbyte++]
+#define enc_eof() (enc_curbyte>enc_size)
+
+#define valid_code(c) (c >= 0 && c < 256)
+#define fixedcontent false
+
+static const char *standard_glyph_names[256] = {
+ /* 0x00 */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* 0x10 */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* 0x20 */
+ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
+ "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
+ "plus", "comma", "hyphen", "period", "slash",
+ /* 0x30 */
+ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
+ "nine", "colon", "semicolon", "less", "equal", "greater", "question",
+ /* 0x40 */
+ "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+ "O",
+ /* 0x50 */
+ "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
+ "backslash", "bracketright", "asciicircum", "underscore",
+ /* 0x60 */
+ "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
+ "m", "n", "o",
+ /* 0x70 */
+ "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
+ "braceright", "asciitilde", notdef,
+ /* 0x80 */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* 0x90 */
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* 0xa0 */
+ notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin",
+ "section", "currency", "quotesingle", "quotedblleft", "guillemotleft",
+ "guilsinglleft", "guilsinglright", "fi", "fl",
+ /* 0xb0 */
+ notdef, "endash", "dagger", "daggerdbl", "periodcentered", notdef,
+ "paragraph", "bullet", "quotesinglbase", "quotedblbase",
+ "quotedblright", "guillemotright", "ellipsis", "perthousand", notdef,
+ "questiondown",
+ /* 0xc0 */
+ notdef, "grave", "acute", "circumflex", "tilde", "macron", "breve",
+ "dotaccent", "dieresis", notdef,
+ "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron",
+ /* 0xd0 */
+ "emdash", notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+ /* 0xe0 */
+ notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
+ "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef,
+ notdef,
+ /* 0xf0 */
+ notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef, "lslash",
+ "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
+};
+
+static fd_entry *fd_cur;
+
+static char charstringname[] = "/CharStrings";
+
+enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
+
+#define T1_BUF_SIZE 0x0010
+#define ENC_BUF_SIZE 0x1000
+
+#define CS_HSTEM 1
+#define CS_VSTEM 3
+#define CS_VMOVETO 4
+#define CS_RLINETO 5
+#define CS_HLINETO 6
+#define CS_VLINETO 7
+#define CS_RRCURVETO 8
+#define CS_CLOSEPATH 9
+#define CS_CALLSUBR 10
+#define CS_RETURN 11
+#define CS_ESCAPE 12
+#define CS_HSBW 13
+#define CS_ENDCHAR 14
+#define CS_RMOVETO 21
+#define CS_HMOVETO 22
+#define CS_VHCURVETO 30
+#define CS_HVCURVETO 31
+#define CS_1BYTE_MAX (CS_HVCURVETO + 1)
+
+#define CS_DOTSECTION CS_1BYTE_MAX + 0
+#define CS_VSTEM3 CS_1BYTE_MAX + 1
+#define CS_HSTEM3 CS_1BYTE_MAX + 2
+#define CS_SEAC CS_1BYTE_MAX + 6
+#define CS_SBW CS_1BYTE_MAX + 7
+#define CS_DIV CS_1BYTE_MAX + 12
+#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
+#define CS_POP CS_1BYTE_MAX + 17
+#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
+#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
+#define CS_MAX CS_2BYTE_MAX
+
+typedef unsigned char byte;
+
+/*tex A |CharString| command: */
+
+typedef struct {
+ /*tex number of arguments */
+ byte nargs;
+ /*tex take arguments from bottom of stack? */
+ boolean bottom;
+ /*tex clear stack? */
+ boolean clear;
+ boolean valid;
+} cc_entry;
+
+typedef struct {
+ /*tex glyph name (or |notdef| for |Subrs| entry) */
+ char *name;
+ byte *data;
+ /*tex length of the whole string */
+ unsigned short len;
+ /*tex length of the encoded part of the string */
+ unsigned short cslen;
+ boolean used;
+ boolean valid;
+} cs_entry;
+
+static unsigned short t1_dr, t1_er;
+static const unsigned short t1_c1 = 52845, t1_c2 = 22719;
+static unsigned short t1_cslen;
+static short t1_lenIV;
+static char enc_line[ENC_BUF_SIZE];
+
+#define t1_line_entry char
+define_array(t1_line);
+
+#define t1_buf_entry char
+define_array(t1_buf);
+
+static int cs_start;
+
+static cs_entry *cs_tab, *cs_ptr, *cs_notdef;
+static char *cs_dict_start, *cs_dict_end;
+static int cs_counter, cs_size, cs_size_pos;
+
+static cs_entry *subr_tab;
+static char *subr_array_start, *subr_array_end;
+static int subr_max, subr_size, subr_size_pos;
+
+/*tex
+
+ This list contains the begin/end tokens commonly used in the |/Subrs| array of
+ a Type 1 font.
+
+*/
+
+static const char *cs_token_pairs_list[][2] = {
+ { " RD", "NP" },
+ { " -|", "|" },
+ { " RD", "noaccess put" },
+ { " -|", "noaccess put" },
+ { NULL, NULL }
+};
+
+static const char **cs_token_pair;
+
+static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
+
+/*tex This one becomes 0 before 1 during and 2 after |eexec| encryption. */
+
+static int t1_in_eexec;
+
+static long t1_block_length;
+static int last_hexbyte;
+static FILE *t1_file;
+static FILE *enc_file;
+
+static void enc_getline(void)
+{
+ char *p;
+ char c;
+ restart:
+ if (enc_eof())
+ normal_error("type 1","unexpected end of file");
+ p = enc_line;
+ do {
+ c = (char) enc_getchar();
+ append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
+ }
+ while (c != 10 && !enc_eof());
+ append_eol(p, enc_line, ENC_BUF_SIZE);
+ if (p - enc_line < 2 || *enc_line == '%')
+ goto restart;
+}
+
+/*tex
+
+ Read encoding from .enc file, return |glyph_names array|, or |pdffail|.
+
+*/
+
+char **load_enc_file(char *enc_name)
+{
+ int callback_id = 0;
+ int file_opened = 0;
+ char buf[ENC_BUF_SIZE], *p, *r;
+ int i, names_count;
+ char **glyph_names;
+ cur_file_name = luatex_find_file(enc_name, find_enc_file_callback);
+ if (cur_file_name == NULL) {
+ formatted_error("type 1","cannot find encoding file '%s' for reading", enc_name);
+ }
+ callback_id = callback_defined(read_enc_file_callback);
+ enc_curbyte = 0;
+ enc_size = 0;
+ if (callback_id > 0) {
+ if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &enc_buffer, &enc_size)) {
+ if ((!file_opened) || enc_size == 0) {
+ formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
+ }
+ }
+ } else {
+ if (!enc_open(cur_file_name)) {
+ formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
+ }
+ enc_read_file();
+ enc_close();
+ }
+ glyph_names = xtalloc(256, char *);
+ for (i = 0; i < 256; i++)
+ glyph_names[i] = (char *) notdef;
+ report_start_file(filetype_map,cur_file_name);
+ enc_getline();
+ if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) {
+ remove_eol(r, enc_line);
+ formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line);
+ }
+ names_count = 0;
+ /*tex Skip |[|: */
+ r++;
+ skip_char(r, ' ');
+ for (;;) {
+ while (*r == '/') {
+ for (p = buf, r++;
+ *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
+ *p = 0;
+ skip_char(r, ' ');
+ if (names_count >= 256)
+ normal_error("type 1","encoding vector contains more than 256 names");
+ if (strcmp(buf, notdef) != 0)
+ glyph_names[names_count] = xstrdup(buf);
+ names_count++;
+ }
+ if (*r != 10 && *r != '%') {
+ if (strncmp(r, "] def", strlen("] def")) == 0)
+ goto done;
+ else {
+ remove_eol(r, enc_line);
+ formatted_error("type 1","invalid encoding vector: a name or '] def' expected: `%s'",enc_line);
+ }
+ }
+ enc_getline();
+ r = enc_line;
+ }
+ done:
+ report_stop_file(filetype_map);
+ cur_file_name = NULL;
+ xfree(enc_buffer);
+ return glyph_names;
+}
+
+static void t1_check_pfa(void)
+{
+ const int c = t1_getchar();
+ t1_pfa = (c != 128) ? true : false;
+ t1_ungetchar(c);
+}
+
+static int t1_getbyte(void)
+{
+ int c = t1_getchar();
+ if (t1_pfa)
+ return c;
+ if (t1_block_length == 0) {
+ if (c != 128)
+ normal_error("type 1","invalid marker");
+ c = t1_getchar();
+ if (c == 3) {
+ while (!t1_eof())
+ (void) t1_getchar();
+ return EOF;
+ }
+ t1_block_length = t1_getchar() & 0xff;
+ t1_block_length |= (t1_getchar() & 0xff) << 8;
+ t1_block_length |= (t1_getchar() & 0xff) << 16;
+ t1_block_length |= (t1_getchar() & 0xff) << 24;
+ c = t1_getchar();
+ }
+ t1_block_length--;
+ return c;
+}
+
+static int hexval(int c)
+{
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if (c >= '0' && c <= '9')
+ return c - '0';
+ else
+ return -1;
+}
+
+static byte edecrypt(byte cipher)
+{
+ byte plain;
+ if (t1_pfa) {
+ while (cipher == 10 || cipher == 13)
+ cipher = (byte) t1_getbyte();
+ last_hexbyte = cipher = (byte) ((hexval(cipher) << 4) + hexval(t1_getbyte()));
+ }
+ plain = (byte) (cipher ^ (t1_dr >> 8));
+ t1_dr = (unsigned short) ((cipher + t1_dr) * t1_c1 + t1_c2);
+ return plain;
+}
+
+static byte cdecrypt(byte cipher, unsigned short *cr)
+{
+ const byte plain = (byte) (cipher ^ (*cr >> 8));
+ *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
+ return plain;
+}
+
+static byte eencrypt(byte plain)
+{
+ const byte cipher = (byte) (plain ^ (t1_er >> 8));
+ t1_er = (unsigned short) ((cipher + t1_er) * t1_c1 + t1_c2);
+ return cipher;
+}
+
+static byte cencrypt(byte plain, unsigned short *cr)
+{
+ const byte cipher = (byte) (plain ^ (*cr >> 8));
+ *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
+ return cipher;
+}
+
+static char *eol(char *s)
+{
+ char *p = strend(s);
+ if (p - s > 1 && p[-1] != 10) {
+ *p++ = 10;
+ *p = 0;
+ }
+ return p;
+}
+
+static float t1_scan_num(char *p, char **r)
+{
+ float f;
+ skip_char(p, ' ');
+ if (sscanf(p, "%g", &f) != 1) {
+ remove_eol(p, t1_line_array);
+ formatted_error("type 1","a number expected: '%s'", t1_line_array);
+ }
+ if (r != NULL) {
+ for (; isdigit((unsigned char)*p) || *p == '.' ||
+ *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
+ *r = p;
+ }
+ return f;
+}
+
+static boolean str_suffix(const char *begin_buf, const char *end_buf, const char *s)
+{
+ const char *s1 = end_buf - 1, *s2 = strend(s) - 1;
+ if (*s1 == 10)
+ s1--;
+ while (s1 >= begin_buf && s2 >= s) {
+ if (*s1-- != *s2--)
+ return false;
+ }
+ return s2 < s;
+}
+
+static void t1_getline(void)
+{
+ int c, l, eexec_scan;
+ char *p;
+ static const char eexec_str[] = "currentfile eexec";
+ static int eexec_len = 17;
+ restart:
+ if (t1_eof())
+ normal_error("type 1","unexpected end of file");
+ t1_line_ptr = t1_line_array;
+ alloc_array(t1_line, 1, T1_BUF_SIZE);
+ t1_cslen = 0;
+ eexec_scan = 0;
+ c = t1_getbyte();
+ if (c == EOF)
+ goto exit;
+ while (!t1_eof()) {
+ if (t1_in_eexec == 1)
+ c = edecrypt((byte) c);
+ alloc_array(t1_line, 1, T1_BUF_SIZE);
+ {
+ char cc = (char) c;
+ append_char_to_buf(cc, t1_line_ptr, t1_line_array, t1_line_limit);
+ }
+ if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
+ if (t1_line_array[eexec_scan] == eexec_str[eexec_scan])
+ eexec_scan++;
+ else
+ eexec_scan = -1;
+ }
+ if (c == 10 || c == 13
+ || (t1_pfa && eexec_scan == eexec_len && c == 32)) {
+ break;
+ }
+ if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) &&
+ (t1_suffix(" RD ") || t1_suffix(" -| "))) {
+ p = t1_line_ptr - 5;
+ while (*p != ' ')
+ p--;
+ l = (int) t1_scan_num(p + 1, 0);
+ t1_cslen = (unsigned short) l;
+ /*tex |cs_start| is an index now */
+ cs_start = (int) (t1_line_ptr - t1_line_array);
+ alloc_array(t1_line, l, T1_BUF_SIZE);
+ while (l-- > 0)
+ *t1_line_ptr++ = (t1_line_entry) edecrypt((byte) t1_getbyte());
+ }
+ c = t1_getbyte();
+ }
+ /*tex |append_eol| can append 2 chars */
+ alloc_array(t1_line, 2, T1_BUF_SIZE);
+ append_eol(t1_line_ptr, t1_line_array, t1_line_limit);
+ if (t1_line_ptr - t1_line_array < 2)
+ goto restart;
+ if (eexec_scan == eexec_len)
+ t1_in_eexec = 1;
+ exit:
+ /*tex Ensure that |t1_buf_array| has as much room as |t1_line_array|. */
+ t1_buf_ptr = t1_buf_array;
+ alloc_array(t1_buf, t1_line_limit, t1_line_limit);
+}
+
+static void t1_putline(PDF pdf)
+{
+ char *p = t1_line_array;
+ if (t1_line_ptr - t1_line_array <= 1)
+ return;
+ if (t1_eexec_encrypt) {
+ while (p < t1_line_ptr)
+ t1_putchar((eight_bits) eencrypt((byte) * p++));
+ } else
+ while (p < t1_line_ptr)
+ t1_putchar((eight_bits) * p++);
+}
+
+static void t1_puts(PDF pdf, const char *s)
+{
+ if (s != t1_line_array)
+ strcpy(t1_line_array, s);
+ t1_line_ptr = strend(t1_line_array);
+ t1_putline(pdf);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void t1_printf(PDF pdf, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vsprintf(t1_line_array, fmt, args);
+ t1_puts(pdf, t1_line_array);
+ va_end(args);
+}
+
+static void t1_init_params(int open_name_prefix)
+{
+ report_start_file(open_name_prefix,cur_file_name);
+ t1_lenIV = 4;
+ t1_dr = 55665;
+ t1_er = 55665;
+ t1_in_eexec = 0;
+ t1_cs = false;
+ t1_scan = true;
+ t1_synthetic = false;
+ t1_eexec_encrypt = false;
+ t1_block_length = 0;
+ t1_check_pfa();
+}
+
+static void t1_close_font_file(int close_name_suffix)
+{
+ report_stop_file(close_name_suffix);
+ cur_file_name = NULL;
+}
+
+static void t1_check_block_len(boolean decrypt)
+{
+ int l, c;
+ if (t1_block_length == 0)
+ return;
+ c = t1_getbyte();
+ if (decrypt)
+ c = edecrypt((byte) c);
+ l = (int) t1_block_length;
+ if (!(l == 0 && (c == 10 || c == 13))) {
+ formatted_error("type 1","%i bytes more than expected were ignored", l + 1);
+ }
+}
+
+static void t1_start_eexec(PDF pdf)
+{
+ int i;
+ get_length1();
+ save_offset();
+ if (!t1_pfa)
+ t1_check_block_len(false);
+ for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
+ edecrypt((byte) t1_getbyte());
+ *t1_line_ptr++ = 0;
+ }
+ t1_eexec_encrypt = true;
+ /*tex To put the first four bytes: */
+ t1_putline(pdf);
+}
+
+static void t1_stop_eexec(PDF pdf)
+{
+ int c;
+ get_length2();
+ save_offset();
+ t1_eexec_encrypt = false;
+ if (!t1_pfa)
+ t1_check_block_len(true);
+ else {
+ c = edecrypt((byte) t1_getbyte());
+ if (!(c == 10 || c == 13)) {
+ if (last_hexbyte == 0)
+ t1_puts(pdf, "00");
+ else
+ normal_error("type 1","unexpected data after eexec");
+ }
+ }
+ t1_cs = false;
+ t1_in_eexec = 2;
+}
+
+/*tex Macros for various transforms; unused, left for reference: */
+
+#ifdef T1TRANSFORMMACROS
+# define do_xshift(x,a) {x[4]+=a;}
+# define do_yshift(x,a) {x[5]+=a;}
+# define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;}
+# define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;}
+# define do_extend(x,a) {do_xscale(x,a);}
+# define do_scale(x,a) {do_xscale(x,a); do_yscale(x,a);}
+# define do_slant(x,a) {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);}
+# define do_shear(x,a) {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);}
+
+# define do_rotate(x,a) { \
+ float t, u=cos(a), v=sin(a); \
+ t =x[0]*u+x[1]*-v; \
+ x[1] =x[0]*v+x[1]* u; x[0]=t; \
+ t =x[2]*u+x[3]*-v; \
+ x[3] =x[2]*v+x[3]* u; x[2]=t; \
+ t =x[4]*u+x[5]*-v; \
+ x[5] =x[4]*v+x[5]* u; x[4]=t; \
+}
+#endif
+
+static void t1_scan_keys(PDF pdf)
+{
+ int i, k;
+ char *p, *q, *r;
+ const key_entry *key;
+ if (t1_prefix("/FontType")) {
+ p = t1_line_array + strlen("FontType") + 1;
+ if ((i = (int) t1_scan_num(p, 0)) != 1)
+ formatted_error("type 1","Type%d fonts unsupported by backend", i);
+ return;
+ }
+ for (key = (const key_entry *) font_key; key - font_key < FONT_KEYS_NUM;
+ key++) {
+ if (key->t1name[0] != '\0'
+ && str_prefix(t1_line_array + 1, key->t1name))
+ break;
+ }
+ if (key - font_key == FONT_KEYS_NUM)
+ return;
+ p = t1_line_array + strlen(key->t1name) + 1;
+ skip_char(p, ' ');
+ if ((k = (int) (key - font_key)) == FONTNAME_CODE) {
+ if (*p != '/') {
+ remove_eol(p, t1_line_array);
+ formatted_error("type 1","a name expected: '%s'", t1_line_array);
+ }
+ /*tex Skip the slash. */
+ r = ++p;
+ for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++);
+ *q = 0;
+ xfree(fd_cur->fontname);
+ fd_cur->fontname = xstrdup(t1_buf_array);
+ /*tex
+
+ At this moment we cannot call |make_subset_tag| yet, as the encoding
+ is not read; thus we mark the offset of the subset tag and write it
+ later.
+
+ */
+ if (is_subsetted(fd_cur->fm)) {
+ t1_fontname_offset = (int) (t1_offset() + (r - t1_line_array));
+ strcpy(t1_buf_array, p);
+ sprintf(r, "ABCDEF+%s%s", fd_cur->fontname, t1_buf_array);
+ t1_line_ptr = eol(r);
+ }
+ return;
+ }
+ if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && (*p == '[' || *p == '{'))
+ p++;
+ if (k == FONTBBOX1_CODE) {
+ for (i = 0; i < 4; i++, k++) {
+ fd_cur->font_dim[k].val = (int) t1_scan_num(p, &r);
+ fd_cur->font_dim[k].set = true;
+ p = r;
+ }
+ return;
+ }
+ fd_cur->font_dim[k].val = (int) t1_scan_num(p, 0);
+ fd_cur->font_dim[k].set = true;
+}
+
+static void t1_scan_param(PDF pdf)
+{
+ static const char *lenIV = "/lenIV";
+ if (!t1_scan || *t1_line_array != '/')
+ return;
+ if (t1_prefix(lenIV)) {
+ t1_lenIV = (short) t1_scan_num(t1_line_array + strlen(lenIV), 0);
+ if (t1_lenIV < 0)
+ normal_error("type 1","negative value of lenIV is not supported");
+ return;
+ }
+ t1_scan_keys(pdf);
+}
+
+static void copy_glyph_names(char **glyph_names, int a, int b)
+{
+ if (glyph_names[b] != notdef) {
+ xfree(glyph_names[b]);
+ glyph_names[b] = (char *) notdef;
+ }
+ if (glyph_names[a] != notdef) {
+ glyph_names[b] = xstrdup(glyph_names[a]);
+ }
+}
+
+/*tex Read encoding from Type1 font file, return |glyph_names| array, or |pdffail|. */
+
+static char **t1_builtin_enc(void)
+{
+ int i, a, b, c, counter = 0;
+ char *r, *p, **glyph_names;
+ /*tex At this moment |/Encoding| is the prefix of |t1_line_array|. */
+ glyph_names = xtalloc(256, char *);
+ for (i = 0; i < 256; i++)
+ glyph_names[i] = (char *) notdef;
+ if (t1_suffix("def")) {
+ /*tex A predefined encoding: */
+ sscanf(t1_line_array + strlen("/Encoding"), "%255s", t1_buf_array);
+ if (strcmp(t1_buf_array, "StandardEncoding") == 0) {
+ t1_encoding = ENC_STANDARD;
+ for (i = 0; i < 256; i++) {
+ if (standard_glyph_names[i] != notdef)
+ glyph_names[i] = xstrdup(standard_glyph_names[i]);
+ }
+ return glyph_names;
+ } else
+ formatted_error("type 1","cannot subset font (unknown predefined encoding '%s')",t1_buf_array);
+ }
+ /*
+
+ At this moment |/Encoding| is the prefix of |t1_line_array|, and the
+ encoding is not a predefined encoding. We have two possible forms of
+ vector. The first case is
+
+ \starttyping
+ /Encoding [
+ /a /b /c ...
+ ] readonly def
+ \stoptyping
+
+ and the second case can look like
+
+ \starttyping
+ /Encoding 256 array 0 1 255 {
+ 1 index exch /.notdef put} for
+ dup 0 /x put
+ dup 1 /y put
+ ...
+ } readonly def
+ \stoptyping
+
+ */
+ t1_encoding = ENC_BUILTIN;
+ if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) { /* the first case */
+ r = strchr(t1_line_array, '[') + 1;
+ skip_char(r, ' ');
+ for (;;) {
+ while (*r == '/') {
+ for (p = t1_buf_array, r++; *r != 32 && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
+ *p = 0;
+ skip_char(r, ' ');
+ if (counter > 255)
+ normal_error("type 1","encoding vector contains more than 256 names");
+ if (strcmp(t1_buf_array, notdef) != 0)
+ glyph_names[counter] = xstrdup(t1_buf_array);
+ counter++;
+ }
+ if (*r != 10 && *r != '%') {
+ if (str_prefix(r, "] def") || str_prefix(r, "] readonly def"))
+ break;
+ else {
+ remove_eol(r, t1_line_array);
+ formatted_error("type 1","a name or '] def' or '] readonly def' expected: '%s'", t1_line_array);
+ }
+ }
+ t1_getline();
+ r = t1_line_array;
+ }
+ } else {
+ /*tex The second case. */
+ p = strchr(t1_line_array, 10);
+ for (;;) {
+ if (*p == 10) {
+ t1_getline();
+ p = t1_line_array;
+ }
+ /*tex Check for |dup <index> <glyph> put|. */
+ if (sscanf(p, "dup %i%255s put", &i, t1_buf_array) == 2 &&
+ *t1_buf_array == '/' && valid_code(i)) {
+ if (strcmp(t1_buf_array + 1, notdef) != 0)
+ glyph_names[i] = xstrdup(t1_buf_array + 1);
+ p = strstr(p, " put") + strlen(" put");
+ skip_char(p, ' ');
+ }
+ /*tex Check for |dup dup <to> exch <from> get put|. */
+ else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2 && valid_code(a) && valid_code(b)) {
+ copy_glyph_names(glyph_names, a, b);
+ p = strstr(p, " get put") + strlen(" get put");
+ skip_char(p, ' ');
+ }
+ /*tex Check for |dup dup <from> <size> getinterval <to> exch putinterval|. */
+ else if (sscanf(p, "dup dup %i %i getinterval %i exch putinterval",
+ &a, &c, &b) == 3 && valid_code(a) && valid_code(b) && valid_code(c)) {
+ for (i = 0; i < c; i++)
+ copy_glyph_names(glyph_names, a + i, b + i);
+ p = strstr(p, " putinterval") + strlen(" putinterval");
+ skip_char(p, ' ');
+ }
+ /*tex Check for |def or |readonly def|. */
+ else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' ')) && strcmp(p, "def\n") == 0) {
+ return glyph_names;
+ } else {
+ /*tex Skip an unrecognizable word. */
+ while (*p != ' ' && *p != 10)
+ p++;
+ skip_char(p, ' ');
+ }
+ }
+ }
+ return glyph_names;
+}
+
+static void t1_check_end(PDF pdf)
+{
+ if (t1_eof())
+ return;
+ t1_getline();
+ if (t1_prefix("{restore}"))
+ t1_putline(pdf);
+}
+
+static boolean t1_open_fontfile(int open_name_prefix)
+{
+ ff_entry *ff;
+ int callback_id = 0;
+ int file_opened = 0;
+ t1_curbyte = 0;
+ t1_size = 0;
+ ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm));
+ if (ff->ff_path == NULL) {
+ formatted_error("type 1","cannot open file for reading '%s'",fd_cur->fm->ff_name);
+ return false;
+ }
+ cur_file_name = luatex_find_file(ff->ff_path, find_type1_file_callback);
+ if (cur_file_name == NULL) {
+ formatted_error("type 1","cannot open file for reading '%s'", ff->ff_path);
+ return false;
+ }
+ callback_id = callback_defined(read_type1_file_callback);
+ if (callback_id > 0) {
+ if (!run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &t1_buffer, &t1_size)
+ && file_opened && t1_size > 0) {
+ formatted_warning("type 1","cannot open file for reading '%s'",cur_file_name);
+ return false;
+ }
+ } else {
+ t1_file = xfopen(cur_file_name, FOPEN_RBIN_MODE);
+ t1_read_file();
+ t1_close();
+ }
+ recorder_record_input(cur_file_name);
+ t1_init_params(open_name_prefix);
+ return true;
+}
+
+static void t1_include(PDF pdf)
+{
+ do {
+ t1_getline();
+ t1_scan_param(pdf);
+ t1_putline(pdf);
+ }
+ while (t1_in_eexec == 0);
+ t1_start_eexec(pdf);
+ do {
+ t1_getline();
+ t1_scan_param(pdf);
+ t1_putline(pdf);
+ }
+ while (!(t1_charstrings() || t1_subrs()));
+ t1_cs = true;
+ do {
+ t1_getline();
+ t1_putline(pdf);
+ }
+ while (!t1_end_eexec());
+ t1_stop_eexec(pdf);
+ if (fixedcontent) {
+ /*tex Copy 512 zeros (not needed for \PDF). */
+ do {
+ t1_getline();
+ t1_putline(pdf);
+ }
+ while (!t1_cleartomark());
+ /*tex Write |{restore} if| if found. */
+ t1_check_end(pdf);
+ }
+ get_length3();
+}
+
+#define check_subr(subr) \
+ if (subr >= subr_size || subr < 0) \
+ formatted_error("type 1","Subrs array: entry index out of range '%i'", subr);
+
+static const char **check_cs_token_pair(void)
+{
+ const char **p = (const char **) cs_token_pairs_list;
+ for (; p[0] != NULL; ++p)
+ if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1]))
+ return p;
+ return NULL;
+}
+
+static void cs_store(boolean is_subr)
+{
+ char *p;
+ cs_entry *ptr;
+ int subr;
+ for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' ';
+ *t1_buf_ptr++ = *p++);
+ *t1_buf_ptr = 0;
+ if (is_subr) {
+ subr = (int) t1_scan_num(p + 1, 0);
+ check_subr(subr);
+ ptr = subr_tab + subr;
+ } else {
+ ptr = cs_ptr++;
+ if (cs_ptr - cs_tab > cs_size)
+ formatted_error("type 1","CharStrings dict: more entries than dict size '%i'", cs_size);
+ if (strcmp(t1_buf_array + 1, notdef) == 0) /* skip the slash */
+ ptr->name = (char *) notdef;
+ else
+ ptr->name = xstrdup(t1_buf_array + 1);
+ }
+ /*tex Copy |" RD " + cs data| to |t1_buf_array|. */
+ memcpy(t1_buf_array, t1_line_array + cs_start - 4, (unsigned) (t1_cslen + 4));
+ /*tex Copy the end of cs data to |t1_buf_array|. */
+ for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr =
+ t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++);
+ *t1_buf_ptr++ = 10;
+ if (is_subr && cs_token_pair == NULL)
+ cs_token_pair = check_cs_token_pair();
+ ptr->len = (unsigned short) (t1_buf_ptr - t1_buf_array);
+ ptr->cslen = t1_cslen;
+ xfree(ptr->data);
+ ptr->data = xtalloc(ptr->len, byte);
+ memcpy(ptr->data, t1_buf_array, ptr->len);
+ ptr->valid = true;
+}
+
+#define store_subr() cs_store(true)
+#define store_cs() cs_store(false)
+
+#define CC_STACK_SIZE 24
+
+static int cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
+static cc_entry cc_tab[CS_MAX];
+static boolean is_cc_init = false;
+
+#define cc_pop(N) \
+ if (stack_ptr - cc_stack < (N)) \
+ stack_error(N); \
+ stack_ptr -= N
+
+#define stack_error(N) { \
+ formatted_error("type 1","CharString: invalid access '%i' to stack, '%i' entries", (int) N, (int)(stack_ptr - cc_stack)); \
+ goto cs_error; \
+}
+
+#define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
+#define cc_push(V) *stack_ptr++ = V
+#define cc_clear() stack_ptr = cc_stack
+
+#define set_cc(N, B, A, C) \
+ cc_tab[N].nargs = A; \
+ cc_tab[N].bottom = B; \
+ cc_tab[N].clear = C; \
+ cc_tab[N].valid = true
+
+static void cc_init(void)
+{
+ int i;
+ if (is_cc_init)
+ return;
+ for (i = 0; i < CS_MAX; i++)
+ cc_tab[i].valid = false;
+ set_cc(CS_HSTEM, true, 2, true);
+ set_cc(CS_VSTEM, true, 2, true);
+ set_cc(CS_VMOVETO, true, 1, true);
+ set_cc(CS_RLINETO, true, 2, true);
+ set_cc(CS_HLINETO, true, 1, true);
+ set_cc(CS_VLINETO, true, 1, true);
+ set_cc(CS_RRCURVETO, true, 6, true);
+ set_cc(CS_CLOSEPATH, false, 0, true);
+ set_cc(CS_CALLSUBR, false, 1, false);
+ set_cc(CS_RETURN, false, 0, false);
+ set_cc(CS_HSBW, true, 2, true);
+ set_cc(CS_ENDCHAR, false, 0, true);
+ set_cc(CS_RMOVETO, true, 2, true);
+ set_cc(CS_HMOVETO, true, 1, true);
+ set_cc(CS_VHCURVETO, true, 4, true);
+ set_cc(CS_HVCURVETO, true, 4, true);
+ set_cc(CS_DOTSECTION, false, 0, true);
+ set_cc(CS_VSTEM3, true, 6, true);
+ set_cc(CS_HSTEM3, true, 6, true);
+ set_cc(CS_SEAC, true, 5, true);
+ set_cc(CS_SBW, true, 4, true);
+ set_cc(CS_DIV, false, 2, false);
+ set_cc(CS_CALLOTHERSUBR, false, 0, false);
+ set_cc(CS_POP, false, 0, false);
+ set_cc(CS_SETCURRENTPOINT, true, 2, true);
+ is_cc_init = true;
+}
+
+#define cs_getchar() cdecrypt(*data++, &cr)
+
+#define mark_subr(n) cs_mark(0, n)
+#define mark_cs(s) cs_mark(s, 0)
+
+static void cs_fail(const char *cs_name, int subr, const char *fmt, ...)
+{
+ char buf[SMALL_BUF_SIZE];
+ va_list args;
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+ if (cs_name == NULL)
+ formatted_error("type 1","Subr '%i': %s", (int) subr, buf);
+ else
+ formatted_error("type 1","CharString (/%s): %s", cs_name, buf);
+}
+
+/*tex Fix a return-less subr by appending |CS_RETURN|. */
+
+static void append_cs_return(cs_entry * ptr)
+{
+ unsigned short cr;
+ int i;
+ byte *p, *q, *data, *new_data;
+ /*tex Decrypt the cs data to |t1_buf_array|, append |CS_RETURN|. */
+ p = (byte *) t1_buf_array;
+ data = ptr->data + 4;
+ cr = 4330;
+ for (i = 0; i < ptr->cslen; i++)
+ *p++ = cs_getchar();
+ *p = CS_RETURN;
+ /*tex Encrypt the new cs data to |new_data|. */
+ new_data = xtalloc((unsigned) (ptr->len + 1), byte);
+ memcpy(new_data, ptr->data, 4);
+ p = new_data + 4;
+ q = (byte *) t1_buf_array;
+ cr = 4330;
+ for (i = 0; i < ptr->cslen + 1; i++)
+ *p++ = cencrypt(*q++, &cr);
+ memcpy(p, ptr->data + 4 + ptr->cslen, (size_t) (ptr->len - ptr->cslen - 4));
+ /*tex Update |*ptr|. */
+ xfree(ptr->data);
+ ptr->data = new_data;
+ ptr->len++;
+ ptr->cslen++;
+}
+
+static void cs_mark(const char *cs_name, int subr)
+{
+ byte *data;
+ int i, b, cs_len;
+ int last_cmd = 0;
+ int a, a1, a2;
+ unsigned short cr;
+ /*tex The argument of last call to |OtherSubrs[3]|. */
+ static int lastargOtherSubr3 = 3;
+ cs_entry *ptr;
+ cc_entry *cc;
+ if (cs_name == NULL) {
+ check_subr(subr);
+ ptr = subr_tab + subr;
+ if (!ptr->valid)
+ return;
+ } else if (cs_notdef != NULL && (cs_name == notdef || strcmp(cs_name, notdef) == 0)) {
+ ptr = cs_notdef;
+ }else {
+ for (ptr = cs_tab; ptr < cs_ptr; ptr++)
+ if (strcmp(ptr->name, cs_name) == 0)
+ break;
+ if (ptr == cs_ptr) {
+ formatted_warning("type 1","glyph '%s' undefined", cs_name);
+ return;
+ }
+ if (ptr->name == notdef)
+ cs_notdef = ptr;
+ }
+ /*tex
+ Only marked CharString entries and invalid entries can be skipped; valid
+ marked subrs must be parsed to keep the stack in sync.
+ */
+ if (!ptr->valid || (ptr->used && cs_name != NULL))
+ return;
+ ptr->used = true;
+ cr = 4330;
+ cs_len = ptr->cslen;
+ data = ptr->data + 4;
+ for (i = 0; i < t1_lenIV; i++, cs_len--)
+ cs_getchar();
+ while (cs_len > 0) {
+ --cs_len;
+ b = cs_getchar();
+ if (b >= 32) {
+ if (b <= 246)
+ a = b - 139;
+ else if (b <= 250) {
+ --cs_len;
+ a = ((b - 247) << 8) + 108 + cs_getchar();
+ } else if (b <= 254) {
+ --cs_len;
+ a = -((b - 251) << 8) - 108 - cs_getchar();
+ } else {
+ cs_len -= 4;
+ a = (cs_getchar() & 0xff) << 24;
+ a |= (cs_getchar() & 0xff) << 16;
+ a |= (cs_getchar() & 0xff) << 8;
+ a |= (cs_getchar() & 0xff) << 0;
+ if (sizeof(int) > 4 && (a & 0x80000000))
+ a |= ~0x7FFFFFFF;
+ }
+ cc_push(a);
+ } else {
+ if (b == CS_ESCAPE) {
+ b = cs_getchar() + CS_1BYTE_MAX;
+ cs_len--;
+ }
+ if (b >= CS_MAX) {
+ cs_fail(cs_name, subr, "command value out of range: %i", (int) b);
+ goto cs_error;
+ }
+ cc = cc_tab + b;
+ if (!cc->valid) {
+ cs_fail(cs_name, subr, "command not valid: %i", (int) b);
+ goto cs_error;
+ }
+ if (cc->bottom) {
+ if (stack_ptr - cc_stack < cc->nargs)
+ cs_fail(cs_name, subr,
+ "less arguments on stack '%i' than required '%i'",
+ (int) (stack_ptr - cc_stack), (int) cc->nargs);
+ else if (stack_ptr - cc_stack > cc->nargs)
+ cs_fail(cs_name, subr,
+ "more arguments on stack '%i' than required '%i'",
+ (int) (stack_ptr - cc_stack), (int) cc->nargs);
+ }
+ last_cmd = b;
+ switch (cc - cc_tab) {
+ case CS_CALLSUBR:
+ a1 = cc_get(-1);
+ cc_pop(1);
+ mark_subr(a1);
+ if (!subr_tab[a1].valid) {
+ cs_fail(cs_name, subr, "cannot call subr '%i'", (int) a1);
+ goto cs_error;
+ }
+ break;
+ case CS_DIV:
+ cc_pop(2);
+ cc_push(0);
+ break;
+ case CS_CALLOTHERSUBR:
+ if (cc_get(-1) == 3)
+ lastargOtherSubr3 = cc_get(-3);
+ a1 = cc_get(-2) + 2;
+ cc_pop(a1);
+ break;
+ case CS_POP:
+ cc_push(lastargOtherSubr3);
+ /*tex
+ The only case when we care about the value being pushed
+ onto stack is when |POP| follows |CALLOTHERSUBR| changing
+ hints by |OtherSubrs[3]|.
+ */
+ break;
+ case CS_SEAC:
+ a1 = cc_get(3);
+ a2 = cc_get(4);
+ cc_clear();
+ mark_cs(standard_glyph_names[a1]);
+ mark_cs(standard_glyph_names[a2]);
+ break;
+ default:
+ if (cc->clear)
+ cc_clear();
+ }
+ }
+ }
+ if (cs_name == NULL && last_cmd != CS_RETURN) {
+ formatted_warning("type 1",
+ "last command in subr '%i' is not a RETURN; I will add it now but please consider fixing the font",
+ (int) subr);
+ append_cs_return(ptr);
+ }
+ return;
+ /*tex An error occured during parsing: */
+ cs_error:
+ cc_clear();
+ ptr->valid = false;
+ ptr->used = false;
+}
+
+/* AVL search tree for glyph code by glyph name. */
+
+static int comp_t1_glyphs(const void *pa, const void *pb, void *p
+ __attribute__ ((unused)))
+{
+ return strcmp(*(const char *const *) pa, *(const char *const *) pb);
+}
+
+static struct avl_table *create_t1_glyph_tree(char **glyph_names)
+{
+ int i;
+ void **aa;
+ static struct avl_table *gl_tree;
+ gl_tree = avl_create(comp_t1_glyphs, NULL, &avl_xallocator);
+ for (i = 0; i < 256; i++) {
+ if (glyph_names[i] != notdef &&
+ (char **) avl_find(gl_tree, &glyph_names[i]) == NULL) {
+ /*tex No |strdup| here, just point to the |glyph_names| array members. */
+ aa = avl_probe(gl_tree, &glyph_names[i]);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
+ }
+ }
+ return gl_tree;
+}
+
+static void destroy_t1_glyph_tree(struct avl_table *gl_tree)
+{
+ avl_destroy(gl_tree, NULL);
+}
+
+static void t1_subset_ascii_part(PDF pdf)
+{
+ int j, *p;
+ char *glyph, **gg, **glyph_names;
+ struct avl_table *gl_tree;
+ struct avl_traverser t;
+ void **aa;
+ t1_getline();
+ while (!t1_prefix("/Encoding")) {
+ t1_scan_param(pdf);
+ t1_putline(pdf);
+ t1_getline();
+ }
+ glyph_names = t1_builtin_enc();
+ fd_cur->builtin_glyph_names = glyph_names;
+ if (is_subsetted(fd_cur->fm)) {
+ if (fd_cur->tx_tree != NULL) {
+ /*tex Take over collected non-reencoded characters from \TeX. */
+ avl_t_init(&t, fd_cur->tx_tree);
+ for (p = (int *) avl_t_first(&t, fd_cur->tx_tree); p != NULL;
+ p = (int *) avl_t_next(&t)) {
+ if ((char *) avl_find(fd_cur->gl_tree, glyph_names[*p]) == NULL) {
+ glyph = xstrdup(glyph_names[*p]);
+ aa = avl_probe(fd_cur->gl_tree, glyph);
+ assert(aa != NULL);
+ }
+ }
+ }
+ make_subset_tag(fd_cur);
+ strncpy((char *) pdf->fb->data + t1_fontname_offset, fd_cur->subset_tag,6);
+ }
+ /*tex Now really all glyphs needed from this font are in the |fd_cur->gl_tree|. */
+ if (t1_encoding == ENC_STANDARD)
+ t1_puts(pdf, "/Encoding StandardEncoding def\n");
+ else {
+ t1_puts(pdf,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
+ gl_tree = create_t1_glyph_tree(glyph_names);
+ avl_t_init(&t, fd_cur->gl_tree);
+ j = 0;
+ for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL;
+ glyph = (char *) avl_t_next(&t)) {
+ if ((gg = (char **) avl_find(gl_tree, &glyph)) != NULL) {
+ t1_printf(pdf, "dup %i /%s put\n", (int) (gg - glyph_names),*gg);
+ j++;
+ }
+ }
+ destroy_t1_glyph_tree(gl_tree);
+ if (j == 0) {
+ /*tex
+ We didn't mark anything for the Encoding array. We add |{dup 0
+ /.notdef put}| for compatibility with Acrobat 5.0.
+ */
+ t1_puts(pdf, "dup 0 /.notdef put\n");
+ }
+ t1_puts(pdf, "readonly def\n");
+ }
+ do {
+ t1_getline();
+ t1_scan_param(pdf);
+ if (!t1_prefix("/UniqueID")) {
+ /*tex Ignore |/UniqueID| for subsetted fonts. */
+ t1_putline(pdf);
+ }
+ }
+ while (t1_in_eexec == 0);
+}
+
+static void cs_init(void)
+{
+ cs_ptr = cs_tab = NULL;
+ cs_dict_start = cs_dict_end = NULL;
+ cs_counter = cs_size = cs_size_pos = 0;
+ cs_token_pair = NULL;
+ subr_tab = NULL;
+ subr_array_start = subr_array_end = NULL;
+ subr_max = subr_size = subr_size_pos = 0;
+}
+
+static void init_cs_entry(cs_entry * cs)
+{
+ cs->data = NULL;
+ cs->name = NULL;
+ cs->len = 0;
+ cs->cslen = 0;
+ cs->used = false;
+ cs->valid = false;
+}
+
+static void t1_read_subrs(PDF pdf)
+{
+ int i, s;
+ cs_entry *ptr;
+ t1_getline();
+ while (!(t1_charstrings() || t1_subrs())) {
+ t1_scan_param(pdf);
+ if (!t1_prefix("/UniqueID")) {
+ /*tex Ignore |/UniqueID| for subsetted fonts. */
+ t1_putline(pdf);
+ }
+ t1_getline();
+ }
+ found:
+ t1_cs = true;
+ t1_scan = false;
+ if (!t1_subrs())
+ return;
+ subr_size_pos = strlen("/Subrs") + 1;
+ /*tex |subr_size_pos| points to the number indicating dict size after |Subrs|. */
+ subr_size = (int) t1_scan_num(t1_line_array + subr_size_pos, 0);
+ if (subr_size == 0) {
+ while (!t1_charstrings())
+ t1_getline();
+ return;
+ }
+ subr_tab = xtalloc((unsigned) subr_size, cs_entry);
+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+ init_cs_entry(ptr);
+ subr_array_start = xstrdup(t1_line_array);
+ t1_getline();
+ while (t1_cslen) {
+ store_subr();
+ t1_getline();
+ }
+ /*tex Mark the first four entries without parsing. */
+ for (i = 0; i < subr_size && i < 4; i++)
+ subr_tab[i].used = true;
+ /*tex
+
+ The end of the |Subrs| array might have more than one line so we need to
+ concatenate them to |subr_array_end|. Unfortunately some fonts don't have
+ the |Subrs| array followed by the |CharStrings| dict immediately (synthetic
+ fonts). If we cannot find |CharStrings| in next |POST_SUBRS_SCAN| lines
+ then we will treat the font as synthetic and ignore everything until next
+ |Subrs| is found.
+
+ */
+#define POST_SUBRS_SCAN 5
+ s = 0;
+ *t1_buf_array = 0;
+ for (i = 0; i < POST_SUBRS_SCAN; i++) {
+ if (t1_charstrings())
+ break;
+ s = (int) (s + t1_line_ptr - t1_line_array);
+ alloc_array(t1_buf, s, T1_BUF_SIZE);
+ strcat(t1_buf_array, t1_line_array);
+ t1_getline();
+ }
+ subr_array_end = xstrdup(t1_buf_array);
+ if (i == POST_SUBRS_SCAN) {
+ /*tex |CharStrings| not found: assume a synthetic font. */
+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+ if (ptr->valid)
+ xfree(ptr->data);
+ xfree(subr_tab);
+ xfree(subr_array_start);
+ xfree(subr_array_end);
+ cs_init();
+ t1_cs = false;
+ t1_synthetic = true;
+ while (!(t1_charstrings() || t1_subrs()))
+ t1_getline();
+ goto found;
+ }
+}
+
+#define t1_subr_flush() t1_flush_cs(pdf, true)
+#define t1_cs_flush() t1_flush_cs(pdf, false)
+
+static void t1_flush_cs(PDF pdf, boolean is_subr)
+{
+ char *p;
+ byte *r, *return_cs = NULL;
+ cs_entry *tab, *end_tab, *ptr;
+ char *start_line, *line_end;
+ int count, size_pos;
+ unsigned short cr, cs_len;
+ if (is_subr) {
+ start_line = subr_array_start;
+ line_end = subr_array_end;
+ size_pos = subr_size_pos;
+ tab = subr_tab;
+ count = subr_max + 1;
+ end_tab = subr_tab + count;
+ } else {
+ start_line = cs_dict_start;
+ line_end = cs_dict_end;
+ size_pos = cs_size_pos;
+ tab = cs_tab;
+ end_tab = cs_ptr;
+ count = cs_counter;
+ }
+ t1_line_ptr = t1_line_array;
+ for (p = start_line; p - start_line < size_pos;)
+ *t1_line_ptr++ = *p++;
+ while (isdigit((unsigned char)*p))
+ p++;
+ sprintf(t1_line_ptr, "%u", count);
+ strcat(t1_line_ptr, p);
+ t1_line_ptr = eol(t1_line_array);
+ t1_putline(pdf);
+ /*tex For |-Wall|. */
+ cs_len = 0;
+ /*tex Create |return_cs| to replace unsused |subr|s. */
+ if (is_subr) {
+ cr = 4330;
+ cs_len = 0;
+ /*tex
+ At this point we have |t1_lenIV >= 0;| a negative value would be
+ caught in |t1_scan_param|.
+ */
+ return_cs = xtalloc((unsigned) (t1_lenIV + 1), byte);
+ for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++)
+ *r = cencrypt(0x00, &cr);
+ *r = cencrypt(CS_RETURN, &cr);
+ cs_len++;
+ }
+ for (ptr = tab; ptr < end_tab; ptr++) {
+ if (ptr->used) {
+ if (is_subr)
+ sprintf(t1_line_array, "dup %li %u", (long int) (ptr - tab),
+ ptr->cslen);
+ else
+ sprintf(t1_line_array, "/%s %u", ptr->name, ptr->cslen);
+ p = strend(t1_line_array);
+ memcpy(p, ptr->data, ptr->len);
+ t1_line_ptr = p + ptr->len;
+ t1_putline(pdf);
+ } else {
+ /*tex Replace unsused subr's by |return_cs|. */
+ if (is_subr) {
+ sprintf(t1_line_array, "dup %li %u%s ", (long int) (ptr - tab),
+ cs_len, cs_token_pair[0]);
+ p = strend(t1_line_array);
+ memcpy(p, return_cs, cs_len);
+ t1_line_ptr = p + cs_len;
+ t1_putline(pdf);
+ sprintf(t1_line_array, " %s", cs_token_pair[1]);
+ t1_line_ptr = eol(t1_line_array);
+ t1_putline(pdf);
+ }
+ }
+ xfree(ptr->data);
+ if (is_subr)
+ ptr->valid = false;
+ if (ptr->name != notdef)
+ xfree(ptr->name);
+ }
+ sprintf(t1_line_array, "%s", line_end);
+ t1_line_ptr = eol(t1_line_array);
+ t1_putline(pdf);
+ if (is_subr) {
+ end_tab = subr_tab + subr_size;
+ for (ptr = tab; ptr < end_tab; ptr++) {
+ if (ptr->valid) {
+ xfree(ptr->data);
+ if (ptr->name != notdef)
+ xfree(ptr->name);
+ }
+ }
+ xfree(return_cs);
+ }
+ xfree(tab);
+ xfree(start_line);
+ xfree(line_end);
+}
+
+static void t1_mark_glyphs(void)
+{
+ char *glyph;
+ struct avl_traverser t;
+ cs_entry *ptr;
+ if (t1_synthetic || fd_cur->all_glyphs) {
+ /*tex Mark everything. */
+ if (cs_tab != NULL)
+ for (ptr = cs_tab; ptr < cs_ptr; ptr++)
+ if (ptr->valid)
+ ptr->used = true;
+ if (subr_tab != NULL) {
+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+ if (ptr->valid)
+ ptr->used = true;
+ subr_max = subr_size - 1;
+ }
+ return;
+ }
+ mark_cs(notdef);
+ avl_t_init(&t, fd_cur->gl_tree);
+ for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL;
+ glyph = (char *) avl_t_next(&t)) {
+ mark_cs(glyph);
+ }
+ if (subr_tab != NULL)
+ for (subr_max = -1, ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+ if (ptr->used && ptr - subr_tab > subr_max)
+ subr_max = (int) (ptr - subr_tab);
+}
+
+
+/*tex
+
+ When |t1_subset_charstrings| is called, the |t1_line_array| contains
+ |/CharStrings|. When we hit a case like this:
+
+ \starttyping
+ dup/CharStrings
+ 229 dict dup begin
+ \stoptyping
+
+ we read the next line and concatenate to |t1_line_array| before moving on.
+ That is what |t1_check_unusual_charstring| is for.
+
+*/
+
+static void t1_check_unusual_charstring(void)
+{
+ char *p = strstr(t1_line_array, charstringname) + strlen(charstringname);
+ int i;
+ /*tex If no number follows |/CharStrings|, let's read the next line. */
+ if (sscanf(p, "%i", &i) != 1) {
+ strcpy(t1_buf_array, t1_line_array);
+ t1_getline();
+ strcat(t1_buf_array, t1_line_array);
+ strcpy(t1_line_array, t1_buf_array);
+ t1_line_ptr = eol(t1_line_array);
+ }
+}
+
+static void t1_subset_charstrings(PDF pdf)
+{
+ cs_entry *ptr;
+ t1_check_unusual_charstring();
+ cs_size_pos = (int) (strstr(t1_line_array, charstringname) + strlen(charstringname) - t1_line_array + 1);
+ /*tex |cs_size_pos| points to the number indicating dict size after |/CharStrings|. */
+ cs_size = (int) t1_scan_num(t1_line_array + cs_size_pos, 0);
+ cs_ptr = cs_tab = xtalloc((unsigned) cs_size, cs_entry);
+ for (ptr = cs_tab; ptr - cs_tab < cs_size; ptr++)
+ init_cs_entry(ptr);
+ cs_notdef = NULL;
+ cs_dict_start = xstrdup(t1_line_array);
+ t1_getline();
+ while (t1_cslen) {
+ store_cs();
+ t1_getline();
+ }
+ cs_dict_end = xstrdup(t1_line_array);
+ t1_mark_glyphs();
+ if (subr_tab != NULL) {
+ if (cs_token_pair == NULL)
+ formatted_error("type 1","mismatched subroutine begin/end token pairs");
+ t1_subr_flush();
+ }
+ for (cs_counter = 0, ptr = cs_tab; ptr < cs_ptr; ptr++)
+ if (ptr->used)
+ cs_counter++;
+ t1_cs_flush();
+}
+
+static void t1_subset_end(PDF pdf)
+{
+ if (t1_synthetic) {
+ /*tex Copy to |dup /FontName get exch definefont pop|. */
+ while (!strstr(t1_line_array, "definefont")) {
+ t1_getline();
+ t1_putline(pdf);
+ }
+ while (!t1_end_eexec()) {
+ /*tex Ignore the rest. */
+ t1_getline();
+ }
+ /*tex Write \.{mark currentfile closefile}. */
+ t1_putline(pdf);
+ } else {
+ while (!t1_end_eexec()) {
+ /*tex Copy to \.{mark currentfile closefile}. */
+ t1_getline();
+ t1_putline(pdf);
+ }
+ }
+ t1_stop_eexec(pdf);
+ if (fixedcontent) {
+ /*tex Copy 512 zeros (not needed for PDF). */
+ while (!t1_cleartomark()) {
+ t1_getline();
+ t1_putline(pdf);
+ }
+ /*tex Don't check \.{{restore}if} for synthetic fonts. */
+ if (!t1_synthetic) {
+ /*tex Write \.{{restore}if} if found. */
+ t1_check_end(pdf);
+ }
+ }
+ get_length3();
+}
+
+void writet1(PDF pdf, fd_entry * fd)
+{
+ /*tex |fd_cur| is global inside |writet1.c|. */
+ fd_cur = fd;
+ assert(fd_cur->fm != NULL);
+ assert(is_type1(fd->fm));
+ assert(is_included(fd->fm));
+
+ t1_save_offset = 0;
+ if (!is_subsetted(fd_cur->fm)) {
+ /*tex Include entire font. */
+ if (!(fd->ff_found = t1_open_fontfile(filetype_font)))
+ return;
+ t1_include(pdf);
+ t1_close_font_file(filetype_font);
+ xfree(t1_buffer);
+ return;
+ }
+ /*tex Partial downloading. */
+ if (!(fd->ff_found = t1_open_fontfile(filetype_subset)))
+ return;
+ t1_subset_ascii_part(pdf);
+ t1_start_eexec(pdf);
+ cc_init();
+ cs_init();
+ t1_read_subrs(pdf);
+ t1_subset_charstrings(pdf);
+ t1_subset_end(pdf);
+ t1_close_font_file(filetype_subset);
+ xfree(t1_buffer);
+}
+
+void t1_free(void)
+{
+ xfree(t1_line_array);
+ xfree(t1_buf_array);
+}
Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writet1.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writet1.w 2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writet1.w 2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1739 +0,0 @@
-% writet1.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2009 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <string.h>
-
-#define get_length1() t1_length1 = t1_offset() - t1_save_offset
-#define get_length2() t1_length2 = t1_offset() - t1_save_offset
-#define get_length3() t1_length3 = fixedcontent? t1_offset() - t1_save_offset : 0
-#define save_offset() t1_save_offset = t1_offset()
-
-#define t1_putchar(A) strbuf_putchar(pdf->fb, (A))
-#define t1_offset() strbuf_offset(pdf->fb)
-#define out_eexec_char t1_putchar
-
-#define end_last_eexec_line() \
- t1_eexec_encrypt = false
-#define t1_char(c) c
-#define embed_all_glyphs(tex_font) fm_cur->all_glyphs
-#define extra_charset() fm_cur->charset
-#define fixedcontent false
-
-int t1_length1, t1_length2, t1_length3;
-static int t1_save_offset;
-static int t1_fontname_offset;
-
-static unsigned char *t1_buffer = NULL;
-static int t1_size = 0;
-static int t1_curbyte = 0;
-@ @c
-#define t1_read_file() \
- readbinfile(t1_file,&t1_buffer,&t1_size)
-#define t1_close() xfclose(t1_file,cur_file_name)
-#define t1_getchar() t1_buffer[t1_curbyte++]
-#define t1_ungetchar(c) t1_curbyte--
-#define t1_eof() (t1_curbyte>t1_size)
-
-#define t1_prefix(s) str_prefix(t1_line_array, s)
-#define t1_buf_prefix(s) str_prefix(t1_buf_array, s)
-#define t1_suffix(s) str_suffix(t1_line_array, t1_line_ptr, s)
-#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s)
-#define t1_charstrings() strstr(t1_line_array, charstringname)
-#define t1_subrs() t1_prefix("/Subrs")
-#define t1_end_eexec() t1_suffix("mark currentfile closefile")
-#define t1_cleartomark() t1_prefix("cleartomark")
-
-static unsigned char *enc_buffer = NULL;
-static int enc_size = 0;
-static int enc_curbyte = 0;
-
-@ @c
-#define enc_open(a) \
- (enc_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-#define enc_read_file() \
- readbinfile(enc_file,&enc_buffer,&enc_size)
-#define enc_close() xfclose(enc_file,cur_file_name)
-#define enc_getchar() enc_buffer[enc_curbyte++]
-#define enc_eof() (enc_curbyte>enc_size)
-
-#define valid_code(c) (c >= 0 && c < 256)
-#define fixedcontent false
-
-@ @c
-static const char *standard_glyph_names[256] = {
- /* 0x00 */
- notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- /* 0x10 */
- notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- /* 0x20 */
- "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
- "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
- "plus", "comma", "hyphen", "period", "slash",
- /* 0x30 */
- "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
- "nine", "colon", "semicolon", "less", "equal", "greater", "question",
- /* 0x40 */
- "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
- "O",
- /* 0x50 */
- "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
- "backslash", "bracketright", "asciicircum", "underscore",
- /* 0x60 */
- "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
- "m", "n", "o",
- /* 0x70 */
- "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
- "braceright", "asciitilde", notdef,
- /* 0x80 */
- notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- /* 0x90 */
- notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- /* 0xa0 */
- notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin",
- "section", "currency", "quotesingle", "quotedblleft", "guillemotleft",
- "guilsinglleft", "guilsinglright", "fi", "fl",
- /* 0xb0 */
- notdef, "endash", "dagger", "daggerdbl", "periodcentered", notdef,
- "paragraph", "bullet", "quotesinglbase", "quotedblbase",
- "quotedblright", "guillemotright", "ellipsis", "perthousand", notdef,
- "questiondown",
- /* 0xc0 */
- notdef, "grave", "acute", "circumflex", "tilde", "macron", "breve",
- "dotaccent", "dieresis", notdef,
- "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron",
- /* 0xd0 */
- "emdash", notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- notdef, notdef, notdef, notdef, notdef, notdef, notdef,
- /* 0xe0 */
- notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
- "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef,
- notdef,
- /* 0xf0 */
- notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef, "lslash",
- "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
-};
-
-@ @c
-static fd_entry *fd_cur;
-
-static char charstringname[] = "/CharStrings";
-
-enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
-
-#define T1_BUF_SIZE 0x10
-#define ENC_BUF_SIZE 0x1000
-
-@ @c
-#define CS_HSTEM 1
-#define CS_VSTEM 3
-#define CS_VMOVETO 4
-#define CS_RLINETO 5
-#define CS_HLINETO 6
-#define CS_VLINETO 7
-#define CS_RRCURVETO 8
-#define CS_CLOSEPATH 9
-#define CS_CALLSUBR 10
-#define CS_RETURN 11
-#define CS_ESCAPE 12
-#define CS_HSBW 13
-#define CS_ENDCHAR 14
-#define CS_RMOVETO 21
-#define CS_HMOVETO 22
-#define CS_VHCURVETO 30
-#define CS_HVCURVETO 31
-#define CS_1BYTE_MAX (CS_HVCURVETO + 1)
-
-#define CS_DOTSECTION CS_1BYTE_MAX + 0
-#define CS_VSTEM3 CS_1BYTE_MAX + 1
-#define CS_HSTEM3 CS_1BYTE_MAX + 2
-#define CS_SEAC CS_1BYTE_MAX + 6
-#define CS_SBW CS_1BYTE_MAX + 7
-#define CS_DIV CS_1BYTE_MAX + 12
-#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
-#define CS_POP CS_1BYTE_MAX + 17
-#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
-#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
-#define CS_MAX CS_2BYTE_MAX
-
-@ @c
-typedef unsigned char byte;
-
-typedef struct {
- byte nargs; /* number of arguments */
- boolean bottom; /* take arguments from bottom of stack? */
- boolean clear; /* clear stack? */
- boolean valid;
-} cc_entry; /* CharString Command */
-
-typedef struct {
- char *name; /* glyph name (or notdef for Subrs entry) */
- byte *data;
- unsigned short len; /* length of the whole string */
- unsigned short cslen; /* length of the encoded part of the string */
- boolean used;
- boolean valid;
-} cs_entry;
-
-static unsigned short t1_dr, t1_er;
-static const unsigned short t1_c1 = 52845, t1_c2 = 22719;
-static unsigned short t1_cslen;
-static short t1_lenIV;
-static char enc_line[ENC_BUF_SIZE];
-
-@ define |t1_line_ptr|, |t1_line_array|, and |t1_line_limit|
- at c
-#define t1_line_entry char
-define_array(t1_line);
-
-@ define |t1_buf_ptr|, |t1_buf_array|, and |t1_buf_limit|
- at c
-#define t1_buf_entry char
-define_array(t1_buf);
-
-static int cs_start;
-
-static cs_entry *cs_tab, *cs_ptr, *cs_notdef;
-static char *cs_dict_start, *cs_dict_end;
-static int cs_counter, cs_size, cs_size_pos;
-
-static cs_entry *subr_tab;
-static char *subr_array_start, *subr_array_end;
-static int subr_max, subr_size, subr_size_pos;
-
-@ This list contains the begin/end tokens commonly used in the
-/Subrs array of a Type 1 font.
-
- at c
-static const char *cs_token_pairs_list[][2] = {
- {" RD", "NP"},
- {" -|", "|"},
- {" RD", "noaccess put"},
- {" -|", "noaccess put"},
- {NULL, NULL}
-};
-
-@ @c
-static const char **cs_token_pair;
-
-static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
-static int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
-static long t1_block_length;
-static int last_hexbyte;
-static FILE *t1_file;
-static FILE *enc_file;
-
-@ @c
-static void enc_getline(void)
-{
- char *p;
- char c;
- restart:
- if (enc_eof())
- normal_error("type 1","unexpected end of file");
- p = enc_line;
- do {
- c = (char) enc_getchar();
- append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
- }
- while (c != 10 && !enc_eof());
- append_eol(p, enc_line, ENC_BUF_SIZE);
- if (p - enc_line < 2 || *enc_line == '%')
- goto restart;
-}
-
-@ read encoding from .enc file, return |glyph_names array|, or |pdffail()|
- at c
-char **load_enc_file(char *enc_name)
-{
- int callback_id = 0;
- int file_opened = 0;
-
- char buf[ENC_BUF_SIZE], *p, *r;
- int i, names_count;
- char **glyph_names;
-
- cur_file_name = luatex_find_file(enc_name, find_enc_file_callback);
-
- if (cur_file_name == NULL) {
- formatted_error("type 1","cannot find encoding file '%s' for reading", enc_name);
- }
- callback_id = callback_defined(read_enc_file_callback);
- enc_curbyte = 0;
- enc_size = 0;
- if (callback_id > 0) {
- if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &enc_buffer, &enc_size)) {
- if ((!file_opened) || enc_size == 0) {
- formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
- }
- }
- } else {
- if (!enc_open(cur_file_name)) {
- formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
- }
- enc_read_file();
- enc_close();
- }
- glyph_names = xtalloc(256, char *);
- for (i = 0; i < 256; i++)
- glyph_names[i] = (char *) notdef;
- report_start_file(filetype_map,cur_file_name);
- enc_getline();
- if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) {
- remove_eol(r, enc_line);
- formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line);
- }
- names_count = 0;
- r++; /* skip '[' */
- skip_char(r, ' ');
- for (;;) {
- while (*r == '/') {
- for (p = buf, r++;
- *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
- *p = 0;
- skip_char(r, ' ');
- if (names_count >= 256)
- normal_error("type 1","encoding vector contains more than 256 names");
- if (strcmp(buf, notdef) != 0)
- glyph_names[names_count] = xstrdup(buf);
- names_count++;
- }
- if (*r != 10 && *r != '%') {
- if (strncmp(r, "] def", strlen("] def")) == 0)
- goto done;
- else {
- remove_eol(r, enc_line);
- formatted_error("type 1","invalid encoding vector: a name or '] def' expected: `%s'",enc_line);
- }
- }
- enc_getline();
- r = enc_line;
- }
- done:
- report_stop_file(filetype_map);
- cur_file_name = NULL;
- xfree(enc_buffer);
- return glyph_names;
-}
-
-@ @c
-#if 0
-static void free_glyph_names(char **glyph_names)
-{
- int i;
- assert(glyph_names != NULL);
- for (i = 0; i < 256; i++)
- if (glyph_names[i] != notdef)
- xfree(glyph_names[i]);
- xfree(glyph_names);
-}
-#endif
-
-static void t1_check_pfa(void)
-{
- const int c = t1_getchar();
- t1_pfa = (c != 128) ? true : false;
- t1_ungetchar(c);
-}
-
-static int t1_getbyte(void)
-{
- int c = t1_getchar();
- if (t1_pfa)
- return c;
- if (t1_block_length == 0) {
- if (c != 128)
- normal_error("type 1","invalid marker");
- c = t1_getchar();
- if (c == 3) {
- while (!t1_eof())
- (void) t1_getchar();
- return EOF;
- }
- t1_block_length = t1_getchar() & 0xff;
- t1_block_length |= (t1_getchar() & 0xff) << 8;
- t1_block_length |= (t1_getchar() & 0xff) << 16;
- t1_block_length |= (t1_getchar() & 0xff) << 24;
- c = t1_getchar();
- }
- t1_block_length--;
- return c;
-}
-
-static int hexval(int c)
-{
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- else if (c >= '0' && c <= '9')
- return c - '0';
- else
- return -1;
-}
-
-static byte edecrypt(byte cipher)
-{
- byte plain;
- if (t1_pfa) {
- while (cipher == 10 || cipher == 13)
- cipher = (byte) t1_getbyte();
- last_hexbyte = cipher =
- (byte) ((hexval(cipher) << 4) + hexval(t1_getbyte()));
- }
- plain = (byte) (cipher ^ (t1_dr >> 8));
- t1_dr = (unsigned short) ((cipher + t1_dr) * t1_c1 + t1_c2);
- return plain;
-}
-
-static byte cdecrypt(byte cipher, unsigned short *cr)
-{
- const byte plain = (byte) (cipher ^ (*cr >> 8));
- *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
- return plain;
-}
-
-static byte eencrypt(byte plain)
-{
- const byte cipher = (byte) (plain ^ (t1_er >> 8));
- t1_er = (unsigned short) ((cipher + t1_er) * t1_c1 + t1_c2);
- return cipher;
-}
-
-static byte cencrypt(byte plain, unsigned short *cr)
-{
- const byte cipher = (byte) (plain ^ (*cr >> 8));
- *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
- return cipher;
-}
-
-static char *eol(char *s)
-{
- char *p = strend(s);
- if (p - s > 1 && p[-1] != 10) {
- *p++ = 10;
- *p = 0;
- }
- return p;
-}
-
-static float t1_scan_num(char *p, char **r)
-{
- float f;
- skip_char(p, ' ');
- if (sscanf(p, "%g", &f) != 1) {
- remove_eol(p, t1_line_array);
- formatted_error("type 1","a number expected: '%s'", t1_line_array);
- }
- if (r != NULL) {
- for (; isdigit((unsigned char)*p) || *p == '.' ||
- *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
- *r = p;
- }
- return f;
-}
-
-static boolean str_suffix(const char *begin_buf, const char *end_buf,
- const char *s)
-{
- const char *s1 = end_buf - 1, *s2 = strend(s) - 1;
- if (*s1 == 10)
- s1--;
- while (s1 >= begin_buf && s2 >= s) {
- if (*s1-- != *s2--)
- return false;
- }
- return s2 < s;
-}
-
-@ @c
-static void t1_getline(void)
-{
- int c, l, eexec_scan;
- char *p;
- static const char eexec_str[] = "currentfile eexec";
- static int eexec_len = 17; /* |strlen(eexec_str)| */
- restart:
- if (t1_eof())
- normal_error("type 1","unexpected end of file");
- t1_line_ptr = t1_line_array;
- alloc_array(t1_line, 1, T1_BUF_SIZE);
- t1_cslen = 0;
- eexec_scan = 0;
- c = t1_getbyte();
- if (c == EOF)
- goto exit;
- while (!t1_eof()) {
- if (t1_in_eexec == 1)
- c = edecrypt((byte) c);
- alloc_array(t1_line, 1, T1_BUF_SIZE);
- {
- char cc = (char) c;
- append_char_to_buf(cc, t1_line_ptr, t1_line_array, t1_line_limit);
- }
- if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
- if (t1_line_array[eexec_scan] == eexec_str[eexec_scan])
- eexec_scan++;
- else
- eexec_scan = -1;
- }
- if (c == 10 || c == 13
- || (t1_pfa && eexec_scan == eexec_len && c == 32)) {
- break;
- }
- if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) &&
- (t1_suffix(" RD ") || t1_suffix(" -| "))) {
- p = t1_line_ptr - 5;
- while (*p != ' ')
- p--;
- l = (int) t1_scan_num(p + 1, 0);
- t1_cslen = (unsigned short) l;
- cs_start = (int) (t1_line_ptr - t1_line_array); /* |cs_start| is an index now */
- alloc_array(t1_line, l, T1_BUF_SIZE);
- while (l-- > 0)
- *t1_line_ptr++ = (t1_line_entry) edecrypt((byte) t1_getbyte());
- }
- c = t1_getbyte();
- }
- alloc_array(t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
- append_eol(t1_line_ptr, t1_line_array, t1_line_limit);
- if (t1_line_ptr - t1_line_array < 2)
- goto restart;
- if (eexec_scan == eexec_len)
- t1_in_eexec = 1;
- exit:
- /* ensure that |t1_buf_array| has as much room as |t1_line_array| */
- t1_buf_ptr = t1_buf_array;
- alloc_array(t1_buf, t1_line_limit, t1_line_limit);
-}
-
-@ @c
-static void t1_putline(PDF pdf)
-{
- char *p = t1_line_array;
- if (t1_line_ptr - t1_line_array <= 1)
- return;
- if (t1_eexec_encrypt) {
- while (p < t1_line_ptr)
- t1_putchar((eight_bits) eencrypt((byte) * p++));
- } else
- while (p < t1_line_ptr)
- t1_putchar((eight_bits) * p++);
-}
-
-static void t1_puts(PDF pdf, const char *s)
-{
- if (s != t1_line_array)
- strcpy(t1_line_array, s);
- t1_line_ptr = strend(t1_line_array);
- t1_putline(pdf);
-}
-
-__attribute__ ((format(printf, 2, 3)))
-static void t1_printf(PDF pdf, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vsprintf(t1_line_array, fmt, args);
- t1_puts(pdf, t1_line_array);
- va_end(args);
-}
-
-@ @c
-static void t1_init_params(int open_name_prefix)
-{
- report_start_file(open_name_prefix,cur_file_name);
- t1_lenIV = 4;
- t1_dr = 55665;
- t1_er = 55665;
- t1_in_eexec = 0;
- t1_cs = false;
- t1_scan = true;
- t1_synthetic = false;
- t1_eexec_encrypt = false;
- t1_block_length = 0;
- t1_check_pfa();
-}
-
-static void t1_close_font_file(int close_name_suffix)
-{
- report_stop_file(close_name_suffix);
- cur_file_name = NULL;
-}
-
-static void t1_check_block_len(boolean decrypt)
-{
- int l, c;
- if (t1_block_length == 0)
- return;
- c = t1_getbyte();
- if (decrypt)
- c = edecrypt((byte) c);
- l = (int) t1_block_length;
- if (!(l == 0 && (c == 10 || c == 13))) {
- formatted_error("type 1","%i bytes more than expected were ignored", l + 1);
- }
-}
-
-@ @c
-static void t1_start_eexec(PDF pdf)
-{
- int i;
- assert(is_included(fd_cur->fm));
- get_length1();
- save_offset();
-
- if (!t1_pfa)
- t1_check_block_len(false);
- for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
- edecrypt((byte) t1_getbyte());
- *t1_line_ptr++ = 0;
- }
- t1_eexec_encrypt = true;
- t1_putline(pdf); /* to put the first four bytes */
-}
-
-static void t1_stop_eexec(PDF pdf)
-{
- int c;
- assert(is_included(fd_cur->fm));
- get_length2();
- save_offset();
- t1_eexec_encrypt = false;
- if (!t1_pfa)
- t1_check_block_len(true);
- else {
- c = edecrypt((byte) t1_getbyte());
- if (!(c == 10 || c == 13)) {
- if (last_hexbyte == 0)
- t1_puts(pdf, "00");
- else
- normal_error("type 1","unexpected data after eexec");
- }
- }
- t1_cs = false;
- t1_in_eexec = 2;
-}
-
-@ macros for various transforms; unused, left for reference
-
- at c
-#ifdef T1TRANSFORMMACROS
-# define do_xshift(x,a) {x[4]+=a;}
-# define do_yshift(x,a) {x[5]+=a;}
-# define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;}
-# define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;}
-# define do_extend(x,a) {do_xscale(x,a);}
-# define do_scale(x,a) {do_xscale(x,a); do_yscale(x,a);}
-# define do_slant(x,a) {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);}
-# define do_shear(x,a) {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);}
-# define do_rotate(x,a) \
- {float t, u=cos(a), v=sin(a); \
- t =x[0]*u+x[1]*-v; \
- x[1] =x[0]*v+x[1]* u; x[0]=t; \
- t =x[2]*u+x[3]*-v; \
- x[3] =x[2]*v+x[3]* u; x[2]=t; \
- t =x[4]*u+x[5]*-v; \
- x[5] =x[4]*v+x[5]* u; x[4]=t;}
-#endif
-
-@ @c
-static void t1_scan_keys(PDF pdf)
-{
- int i, k;
- char *p, *q, *r;
- const key_entry *key;
- if (t1_prefix("/FontType")) {
- p = t1_line_array + strlen("FontType") + 1;
- if ((i = (int) t1_scan_num(p, 0)) != 1)
- formatted_error("type 1","Type%d fonts unsupported by backend", i);
- return;
- }
- for (key = (const key_entry *) font_key; key - font_key < FONT_KEYS_NUM;
- key++) {
- if (key->t1name[0] != '\0'
- && str_prefix(t1_line_array + 1, key->t1name))
- break;
- }
- if (key - font_key == FONT_KEYS_NUM)
- return;
- p = t1_line_array + strlen(key->t1name) + 1;
- skip_char(p, ' ');
- if ((k = (int) (key - font_key)) == FONTNAME_CODE) {
- if (*p != '/') {
- remove_eol(p, t1_line_array);
- formatted_error("type 1","a name expected: '%s'", t1_line_array);
- }
- r = ++p; /* skip the slash */
- for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++);
- *q = 0;
- xfree(fd_cur->fontname);
- fd_cur->fontname = xstrdup(t1_buf_array);
- /* at this moment we cannot call |make_subset_tag()| yet, as the encoding
- is not read; thus we mark the offset of the subset tag and write it
- later */
- if (is_subsetted(fd_cur->fm)) {
- assert(is_included(fd_cur->fm));
- t1_fontname_offset = (int) (t1_offset() + (r - t1_line_array));
- strcpy(t1_buf_array, p);
- sprintf(r, "ABCDEF+%s%s", fd_cur->fontname, t1_buf_array);
- t1_line_ptr = eol(r);
- }
- return;
- }
- if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && (*p == '[' || *p == '{'))
- p++;
- if (k == FONTBBOX1_CODE) {
- for (i = 0; i < 4; i++, k++) {
- fd_cur->font_dim[k].val = (int) t1_scan_num(p, &r);
- fd_cur->font_dim[k].set = true;
- p = r;
- }
- return;
- }
- fd_cur->font_dim[k].val = (int) t1_scan_num(p, 0);
- fd_cur->font_dim[k].set = true;
-}
-
-@ @c
-static void t1_scan_param(PDF pdf)
-{
- static const char *lenIV = "/lenIV";
- if (!t1_scan || *t1_line_array != '/')
- return;
- if (t1_prefix(lenIV)) {
- t1_lenIV = (short) t1_scan_num(t1_line_array + strlen(lenIV), 0);
- if (t1_lenIV < 0)
- normal_error("type 1","negative value of lenIV is not supported");
- return;
- }
- t1_scan_keys(pdf);
-}
-
-static void copy_glyph_names(char **glyph_names, int a, int b)
-{
- if (glyph_names[b] != notdef) {
- xfree(glyph_names[b]);
- glyph_names[b] = (char *) notdef;
- }
- if (glyph_names[a] != notdef) {
- glyph_names[b] = xstrdup(glyph_names[a]);
- }
-}
-
-@ read encoding from Type1 font file, return |glyph_names| array, or |pdffail()|
-
- at c
-static char **t1_builtin_enc(void)
-{
- int i, a, b, c, counter = 0;
- char *r, *p, **glyph_names;
- /* At this moment \.{/Encoding} is the prefix of |t1_line_array| */
- glyph_names = xtalloc(256, char *);
- for (i = 0; i < 256; i++)
- glyph_names[i] = (char *) notdef;
- if (t1_suffix("def")) { /* predefined encoding */
- sscanf(t1_line_array + strlen("/Encoding"), "%255s", t1_buf_array);
- if (strcmp(t1_buf_array, "StandardEncoding") == 0) {
- t1_encoding = ENC_STANDARD;
- for (i = 0; i < 256; i++) {
- if (standard_glyph_names[i] != notdef)
- glyph_names[i] = xstrdup(standard_glyph_names[i]);
- }
- return glyph_names;
- } else
- formatted_error("type 1","cannot subset font (unknown predefined encoding '%s')",t1_buf_array);
- }
- /* At this moment \.{/Encoding} is the prefix of |t1_line_array|, and the encoding is
- not a predefined encoding.
-
- We have two possible forms of Encoding vector. The first case is
-
- \.{/Encoding [/a /b /c...] readonly def}
-
- and the second case can look like
-
- {\obeylines
- \.{/Encoding 256 array 0 1 255 {1 index exch /.notdef put} for}
- \.{dup 0 /x put}
- \.{dup 1 /y put}
- \.{...}
- \.{readonly def}}
- */
- t1_encoding = ENC_BUILTIN;
- if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) { /* the first case */
- r = strchr(t1_line_array, '[') + 1;
- skip_char(r, ' ');
- for (;;) {
- while (*r == '/') {
- for (p = t1_buf_array, r++;
- *r != 32 && *r != 10 && *r != ']' && *r != '/';
- *p++ = *r++);
- *p = 0;
- skip_char(r, ' ');
- if (counter > 255)
- normal_error("type 1","encoding vector contains more than 256 names");
- if (strcmp(t1_buf_array, notdef) != 0)
- glyph_names[counter] = xstrdup(t1_buf_array);
- counter++;
- }
- if (*r != 10 && *r != '%') {
- if (str_prefix(r, "] def") || str_prefix(r, "] readonly def"))
- break;
- else {
- remove_eol(r, t1_line_array);
- formatted_error("type 1","a name or '] def' or '] readonly def' expected: '%s'", t1_line_array);
- }
- }
- t1_getline();
- r = t1_line_array;
- }
- } else { /* the second case */
- p = strchr(t1_line_array, 10);
- for (;;) {
- if (*p == 10) {
- t1_getline();
- p = t1_line_array;
- }
- /*
- check for \.{dup <index> <glyph> put}
- */
- if (sscanf(p, "dup %i%255s put", &i, t1_buf_array) == 2 &&
- *t1_buf_array == '/' && valid_code(i)) {
- if (strcmp(t1_buf_array + 1, notdef) != 0)
- glyph_names[i] = xstrdup(t1_buf_array + 1);
- p = strstr(p, " put") + strlen(" put");
- skip_char(p, ' ');
- }
- /*
- check for \.{dup dup <to> exch <from> get put}
- */
- else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2
- && valid_code(a) && valid_code(b)) {
- copy_glyph_names(glyph_names, a, b);
- p = strstr(p, " get put") + strlen(" get put");
- skip_char(p, ' ');
- }
- /*
- check for \.{dup dup <from> <size> getinterval <to> exch putinterval}
- */
- else if (sscanf
- (p, "dup dup %i %i getinterval %i exch putinterval",
- &a, &c, &b) == 3 && valid_code(a) && valid_code(b)
- && valid_code(c)) {
- for (i = 0; i < c; i++)
- copy_glyph_names(glyph_names, a + i, b + i);
- p = strstr(p, " putinterval") + strlen(" putinterval");
- skip_char(p, ' ');
- }
- /*
- check for \.{def} or \.{readonly def}
- */
- else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' '))
- && strcmp(p, "def\n") == 0)
- return glyph_names;
- /*
- skip an unrecognizable word
- */
- else {
- while (*p != ' ' && *p != 10)
- p++;
- skip_char(p, ' ');
- }
- }
- }
- return glyph_names;
-}
-
-
-@
- at c
-static void t1_check_end(PDF pdf)
-{
- if (t1_eof())
- return;
- t1_getline();
- if (t1_prefix("{restore}"))
- t1_putline(pdf);
-}
-
-@
- at c
-static boolean t1_open_fontfile(int open_name_prefix)
-{
- ff_entry *ff;
- int callback_id = 0;
- int file_opened = 0;
- t1_curbyte = 0;
- t1_size = 0;
- ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm));
- if (ff->ff_path == NULL) {
- formatted_error("type 1","cannot open file for reading '%s'",fd_cur->fm->ff_name);
- return false;
- }
- cur_file_name = luatex_find_file(ff->ff_path, find_type1_file_callback);
- if (cur_file_name == NULL) {
- formatted_error("type 1","cannot open file for reading '%s'", ff->ff_path);
- return false;
- }
- callback_id = callback_defined(read_type1_file_callback);
- if (callback_id > 0) {
- if (!run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &t1_buffer, &t1_size)
- && file_opened && t1_size > 0) {
- formatted_warning("type 1","cannot open file for reading '%s'",cur_file_name);
- return false;
- }
- } else {
- t1_file = xfopen(cur_file_name, FOPEN_RBIN_MODE);
- t1_read_file();
- t1_close();
- }
- recorder_record_input(cur_file_name);
- t1_init_params(open_name_prefix);
- return true;
-}
-
-static void t1_include(PDF pdf)
-{
- do {
- t1_getline();
- t1_scan_param(pdf);
- t1_putline(pdf);
- }
- while (t1_in_eexec == 0);
- t1_start_eexec(pdf);
- do {
- t1_getline();
- t1_scan_param(pdf);
- t1_putline(pdf);
- }
- while (!(t1_charstrings() || t1_subrs()));
- t1_cs = true;
- do {
- t1_getline();
- t1_putline(pdf);
- }
- while (!t1_end_eexec());
- t1_stop_eexec(pdf);
- if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
- do {
- t1_getline();
- t1_putline(pdf);
- }
- while (!t1_cleartomark());
- t1_check_end(pdf); /* write "{restore}if" if found */
- }
- get_length3();
-}
-
-@
- at c
-#define check_subr(subr) \
- if (subr >= subr_size || subr < 0) \
- formatted_error("type 1","Subrs array: entry index out of range '%i'", subr);
-
-static const char **check_cs_token_pair(void)
-{
- const char **p = (const char **) cs_token_pairs_list;
- for (; p[0] != NULL; ++p)
- if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1]))
- return p;
- return NULL;
-}
-
-static void cs_store(boolean is_subr)
-{
- char *p;
- cs_entry *ptr;
- int subr;
- for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' ';
- *t1_buf_ptr++ = *p++);
- *t1_buf_ptr = 0;
- if (is_subr) {
- subr = (int) t1_scan_num(p + 1, 0);
- check_subr(subr);
- ptr = subr_tab + subr;
- } else {
- ptr = cs_ptr++;
- if (cs_ptr - cs_tab > cs_size)
- formatted_error("type 1","CharStrings dict: more entries than dict size '%i'", cs_size);
- if (strcmp(t1_buf_array + 1, notdef) == 0) /* skip the slash */
- ptr->name = (char *) notdef;
- else
- ptr->name = xstrdup(t1_buf_array + 1);
- }
- /* copy |" RD " + cs data| to |t1_buf_array| */
- memcpy(t1_buf_array, t1_line_array + cs_start - 4,
- (unsigned) (t1_cslen + 4));
- /* copy the end of cs data to |t1_buf_array| */
- for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr =
- t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++);
- *t1_buf_ptr++ = 10;
- if (is_subr && cs_token_pair == NULL)
- cs_token_pair = check_cs_token_pair();
- ptr->len = (unsigned short) (t1_buf_ptr - t1_buf_array);
- ptr->cslen = t1_cslen;
- xfree(ptr->data); /* mem leak? */
- ptr->data = xtalloc(ptr->len, byte);
- memcpy(ptr->data, t1_buf_array, ptr->len);
- ptr->valid = true;
-}
-
-@
- at c
-#define store_subr() cs_store(true)
-#define store_cs() cs_store(false)
-
-#define CC_STACK_SIZE 24
-
-static int cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
-static cc_entry cc_tab[CS_MAX];
@@ Diff output truncated at 1234567 characters. @@
More information about the tex-live-commits
mailing list