diff options
author | Martin Schröder <martin@oneiros.de> | 2008-03-24 15:47:15 +0000 |
---|---|---|
committer | Martin Schröder <martin@oneiros.de> | 2008-03-24 15:47:15 +0000 |
commit | 0b5550c241229764120d133af80a0cbab5937ddd (patch) | |
tree | 81309c18d6f0deba7407813cf15b9add2db375d1 /Build/source/texk/web2c/luatexdir/font | |
parent | 51f55df6a36ce376952a1f2b30bdb4dd0e06548d (diff) |
First step of importing luatex (up to r1121)
git-svn-id: svn://tug.org/texlive/trunk@7124 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font')
30 files changed, 20316 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/.indent.pro b/Build/source/texk/web2c/luatexdir/font/.indent.pro new file mode 100644 index 00000000000..e9e690f1ba8 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/.indent.pro @@ -0,0 +1,12 @@ +/* $Id$ */ +--k-and-r-style +--blank-lines-after-procedures +--line-length 80 +--procnames-start-lines +--no-space-after-function-call-names +--dont-break-procedure-type +--space-after-cast +/* this does not work in indent 2.2.6 :-( */ +--no-tabs +/* this is new in indent 2.2.9 */ +--preprocessor-indentation 2 diff --git a/Build/source/texk/web2c/luatexdir/font/dofont.c b/Build/source/texk/web2c/luatexdir/font/dofont.c new file mode 100644 index 00000000000..fbe44c29ba9 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/dofont.c @@ -0,0 +1,183 @@ +/* +Copyright (c) 1996-2006 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LuaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: dofont.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +#include "luatex-api.h" + +#define TIMERS 0 + +#if TIMERS +#include <sys/time.h> +#endif + + +/* 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(zget_cs_text(u)); + 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); + } + return str; +} + +static int +do_define_font (integer f, char *cnom, char *caire, scaled s, integer natural_dir) { + + boolean res; /* was the callback successful? */ + integer callback_id; + char *cnam; +#if TIMERS + struct timeval tva; + struct timeval tvb; + double tvdiff; +#endif + int r; + res = 0; + + callback_id=callback_defined(define_font_callback); + if (callback_id>0) { + if (caire == NULL || strlen(caire)==0) { + cnam = xstrdup(cnom); + } else { + cnam = xmalloc(strlen(cnom)+strlen(caire)+2); + sprintf(cnam,"%s/%s",caire,cnom); + } +#if TIMERS + gettimeofday(&tva,NULL); +#endif + callback_id = run_and_save_callback(callback_id,"Sdd->",cnam,s,f); +#if TIMERS + gettimeofday(&tvb,NULL); + tvdiff = tvb.tv_sec*1000000.0; + tvdiff += (double)tvb.tv_usec; + tvdiff -= (tva.tv_sec*1000000.0); + tvdiff -= (double)tva.tv_usec; + tvdiff /= 1000000; + fprintf(stdout,"\ncallback('define_font',%s,%i): %f seconds\n", cnam,f,tvdiff); +#endif + free(cnam); + if (callback_id>0) { /* success */ + luaL_checkstack(Luas[0],1,"out of stack space"); + lua_rawgeti(Luas[0],LUA_REGISTRYINDEX, callback_id); + if (lua_istable(Luas[0],-1)) { +#if TIMERS + gettimeofday(&tva,NULL); +#endif + res = font_from_lua(Luas[0],f); + destroy_saved_callback (callback_id); +#if TIMERS + gettimeofday(&tvb,NULL); + tvdiff = tvb.tv_sec*1000000.0; + tvdiff += (double)tvb.tv_usec; + tvdiff -= (tva.tv_sec*1000000.0); + tvdiff -= (double)tva.tv_usec; + tvdiff /= 1000000; + fprintf(stdout,"font_from_lua(%s,%i): %f seconds\n", font_name(f),f,tvdiff); +#endif + lua_pop(Luas[0],1); + } else if (lua_isnumber(Luas[0],-1)) { + r = lua_tonumber(Luas[0],-1); + destroy_saved_callback (callback_id); + delete_font(f); + lua_pop(Luas[0],1); + return r; + } else { + lua_pop(Luas[0],1); + delete_font(f); + return 0; + } + } + } else { + res = read_tfm_info(f,cnom,caire,s); + if (res) { + set_hyphen_char(f,get_default_hyphen_char()); + set_skew_char(f,get_default_skew_char()); + } + } + if (res) { + do_vf(f); + set_font_natural_dir(f,natural_dir); + return f; + } else { + delete_font(f); + return 0; + } + +} + +int +read_font_info(pointer u, strnumber nom, strnumber aire, scaled s, + integer natural_dir) { + integer f; + char *cnom, *caire = NULL; + char *msg; + cnom = xstrdup(makecstring(nom)); + if (aire != 0) + caire = xstrdup(makecstring(aire)); + + f = new_font(); + if ((f = do_define_font(f, cnom,caire,s,natural_dir))) { + if (caire != NULL) free(caire); + free(cnom); + return f; + } else { + 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(!get_suppress_fontnotfound_error()) { + msg = font_error_message(u, cnom, s); + tex_error(msg,help); + free(msg); + } + if (caire != NULL) free(caire); + free(cnom); + 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 +*/ + +int +find_font_id (char *nom, char *aire, scaled s) { + integer f; + f = new_font(); + if ((f = do_define_font(f, nom, aire,s,-1))) { + return f; + } else { + return 0; + } +} + diff --git a/Build/source/texk/web2c/luatexdir/font/luafont.c b/Build/source/texk/web2c/luatexdir/font/luafont.c new file mode 100644 index 00000000000..be32e39de9f --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/luafont.c @@ -0,0 +1,1733 @@ + +#include "luatex-api.h" +#include <ptexlib.h> + +#include "nodes.h" + +#define noVERBOSE + +#define SAVE_REF 1 + +char *font_type_strings[] = {"unknown","virtual","real", NULL}; +char *font_format_strings[] = {"unknown","type1","type3","truetype", "opentype", NULL}; +char *font_embedding_strings[] = {"unknown","no","subset", "full", NULL}; +char *ligature_type_strings[] = {"=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL }; + +void +font_char_to_lua (lua_State *L, internalfontnumber f, charinfo *co) { + int i; + liginfo *l; + kerninfo *ki; + + lua_createtable(L,0,10); + + lua_pushstring(L,"width"); + lua_pushnumber(L,get_charinfo_width(co)); + lua_rawset(L,-3); + + lua_pushstring(L,"height"); + lua_pushnumber(L,get_charinfo_height(co)); + lua_rawset(L,-3); + + lua_pushstring(L,"depth"); + lua_pushnumber(L,get_charinfo_depth(co)); + lua_rawset(L,-3); + + lua_pushstring(L,"italic"); + lua_pushnumber(L,get_charinfo_italic(co)); + lua_rawset(L,-3); + + if (get_charinfo_ef(co)!=0) { + lua_pushstring(L,"expansion_factor"); + lua_pushnumber(L,get_charinfo_ef(co)); + lua_rawset(L,-3); + } + + if (get_charinfo_lp(co)!=0) { + lua_pushstring(L,"left_protruding"); + lua_pushnumber(L,get_charinfo_lp(co)); + lua_rawset(L,-3); + } + + if (get_charinfo_lp(co)!=0) { + lua_pushstring(L,"right_protruding"); + lua_pushnumber(L,get_charinfo_rp(co)); + lua_rawset(L,-3); + } + + + if (font_encodingbytes(f) == 2 ) { + lua_pushstring(L,"index"); + lua_pushnumber(L,get_charinfo_index(co)); + lua_rawset(L,-3); + } + + if (get_charinfo_name(co)!=NULL) { + lua_pushstring(L,"name"); + lua_pushstring(L,get_charinfo_name(co)); + lua_rawset(L,-3); + } + + if (get_charinfo_tounicode(co)!=NULL) { + lua_pushstring(L,"tounicode"); + lua_pushstring(L,get_charinfo_tounicode(co)); + lua_rawset(L,-3); + } + + if (get_charinfo_tag(co) == list_tag) { + lua_pushstring(L,"next"); + lua_pushnumber(L,get_charinfo_remainder(co)); + lua_rawset(L,-3); + } + + lua_pushstring(L,"used"); + lua_pushboolean(L,(get_charinfo_used(co) ? true : false)); + lua_rawset(L,-3); + + if (get_charinfo_tag(co) == ext_tag) { + lua_pushstring(L,"extensible"); + lua_createtable(L,0,4); + lua_pushnumber(L,get_charinfo_extensible(co,EXT_TOP)); + lua_setfield(L,-2,"top"); + lua_pushnumber(L,get_charinfo_extensible(co,EXT_BOT)); + lua_setfield(L,-2,"bot"); + lua_pushnumber(L,get_charinfo_extensible(co,EXT_MID)); + lua_setfield(L,-2,"mid"); + lua_pushnumber(L,get_charinfo_extensible(co,EXT_REP)); + lua_setfield(L,-2,"rep"); + lua_rawset(L,-3); + } + ki = get_charinfo_kerns(co); + if (ki != NULL) { + lua_pushstring(L,"kerns"); + lua_createtable(L,10,1); + for (i=0;!kern_end(ki[i]);i++) { + if (kern_char(ki[i]) == right_boundarychar) { + lua_pushstring(L,"right_boundary"); + } else { + lua_pushnumber(L,kern_char(ki[i])); + } + lua_pushnumber(L,kern_kern(ki[i])); + lua_rawset(L,-3); + } + lua_rawset(L,-3); + } + l = get_charinfo_ligatures(co); + if (l!=NULL) { + lua_pushstring(L,"ligatures"); + lua_createtable(L,10,1); + for (i=0;!lig_end(l[i]);i++) { + if (lig_char(l[i]) == right_boundarychar) { + lua_pushstring(L,"right_boundary"); + } else { + lua_pushnumber(L,lig_char(l[i])); + } + lua_createtable(L,0,2); + lua_pushstring(L,"type"); + lua_pushnumber(L,lig_type(l[i])); + lua_rawset(L,-3); + lua_pushstring(L,"char"); + lua_pushnumber(L,lig_replacement(l[i])); + lua_rawset(L,-3); + lua_rawset(L,-3); + } + lua_rawset(L,-3); + } +} + +static void +write_lua_parameters (lua_State *L, int f) { + int k; + lua_newtable(L); + for (k=1;k<=font_params(f);k++) { + lua_pushnumber(L,font_param(f,k)); + switch (k) { + case slant_code: lua_setfield(L,-2,"slant"); break; + case space_code: lua_setfield(L,-2,"space"); break; + case space_stretch_code: lua_setfield(L,-2,"space_stretch"); break; + case space_shrink_code: lua_setfield(L,-2,"space_shrink"); break; + case x_height_code: lua_setfield(L,-2,"x_height"); break; + case quad_code: lua_setfield(L,-2,"quad"); break; + case extra_space_code: lua_setfield(L,-2,"extra_space"); break; + default: + lua_rawseti(L,-2,k); + } + } + lua_setfield(L,-2,"parameters"); +} + + +int +font_to_lua (lua_State *L, int f) { + int k; + charinfo *co; + if (font_cache_id(f)) { + /* 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_pushstring(L,font_name(f)); + lua_setfield(L,-2,"name"); + if(font_area(f)!=NULL) { + lua_pushstring(L,font_area(f)); + lua_setfield(L,-2,"area"); + } + if(font_filename(f)!=NULL) { + lua_pushstring(L,font_filename(f)); + lua_setfield(L,-2,"filename"); + } + if(font_fullname(f)!=NULL) { + lua_pushstring(L,font_fullname(f)); + lua_setfield(L,-2,"fullname"); + } + if(font_encodingname(f)!=NULL) { + lua_pushstring(L,font_encodingname(f)); + lua_setfield(L,-2,"encodingname"); + } + + lua_pushboolean(L,(font_used(f) ? true : false)); + lua_setfield(L,-2,"used"); + + + lua_pushstring(L,font_type_strings[font_type(f)]); + lua_setfield(L,-2,"type"); + lua_pushstring(L,font_format_strings[font_format(f)]); + lua_setfield(L,-2,"format"); + lua_pushstring(L,font_embedding_strings[font_embedding(f)]); + lua_setfield(L,-2,"embedding"); + + lua_pushnumber(L,font_size(f)); + lua_setfield(L,-2,"size"); + lua_pushnumber(L,font_dsize(f)); + lua_setfield(L,-2,"designsize"); + lua_pushnumber(L,font_checksum(f)); + lua_setfield(L,-2,"checksum"); + lua_pushnumber(L,font_slant(f)); + lua_setfield(L,-2,"slant"); + lua_pushnumber(L,font_extend(f)); + lua_setfield(L,-2,"extend"); + lua_pushnumber(L,font_natural_dir(f)); + lua_setfield(L,-2,"direction"); + lua_pushnumber(L,font_encodingbytes(f)); + lua_setfield(L,-2,"encodingbytes"); + lua_pushnumber(L,font_tounicode(f)); + lua_setfield(L,-2,"tounicode"); + + /* pdf parameters */ + /* skip the first four for now, that are very much interal */ + /* + if (pdf_font_size(f) != 0) { + lua_pushnumber(L,pdf_font_size(f)); + lua_setfield(L,-2,"pdf_size"); + } + if (pdf_font_num(f) != 0) { + lua_pushnumber(L,pdf_font_num(f)); + lua_setfield(L,-2,"pdf_num"); + } + if (pdf_font_blink(f) != 0) { + lua_pushnumber(L,pdf_font_blink(f)); + lua_setfield(L,-2,"pdf_blink"); + } + if (pdf_font_elink(f) != 0) { + lua_pushnumber(L,pdf_font_elink(f)); + lua_setfield(L,-2,"pdf_elink"); + } + */ + /* the next one is read only */ + if (pdf_font_expand_ratio(f) != 0) { + lua_pushnumber(L,pdf_font_expand_ratio(f)); + lua_setfield(L,-2,"expand_ratio"); + } + if (pdf_font_shrink(f) != 0) { + lua_pushnumber(L,pdf_font_shrink(f)); + lua_setfield(L,-2,"shrink"); + } + if (pdf_font_stretch(f) != 0) { + lua_pushnumber(L,pdf_font_stretch(f)); + lua_setfield(L,-2,"stretch"); + } + if (pdf_font_step(f) != 0) { + lua_pushnumber(L,pdf_font_step(f)); + lua_setfield(L,-2,"step"); + } + if (pdf_font_auto_expand(f) != 0) { + lua_pushboolean(L,pdf_font_auto_expand(f)); + lua_setfield(L,-2,"auto_expand"); + } + if (pdf_font_attr(f) != 0) { + lua_pushstring(L,makecstring(pdf_font_attr(f))); + lua_setfield(L,-2,"attributes"); + } + + /* params */ + write_lua_parameters(L,f); + + /* chars */ + lua_createtable(L,font_tables[f]->charinfo_size,0); /* all characters */ + + if (has_left_boundary(f)) { + co = get_charinfo(f,left_boundarychar); + font_char_to_lua(L,f,co); + lua_setfield(L,-2,"left_boundary"); + } + if (has_right_boundary(f)) { + co = get_charinfo(f,right_boundarychar); + font_char_to_lua(L,f,co); + lua_setfield(L,-2,"right_boundary"); + } + + for (k=font_bc(f);k<=font_ec(f);k++) { + if (char_exists(f,k)) { + lua_pushnumber(L,k); + co = get_charinfo(f,k); + font_char_to_lua(L,f,co); + lua_rawset(L,-3); + } + } + lua_setfield(L,-2,"characters"); + return 1; +} + +static int +count_hash_items (lua_State *L, int name_index){ + int n = -1; + lua_rawgeti(L,LUA_REGISTRYINDEX,name_index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) { + if (lua_istable(L,-1)) { + n = 0; + /* now find the number */ + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + n++; + lua_pop(L,1); + } + } + } + lua_pop(L,1); + return n; +} + +#define streq(a,b) (strcmp(a,b)==0) + +#define append_packet(k) { cpackets[np++] = 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)); } + +/* +*/ + +#define lua_roundnumber(a,b) (int)floor((double)lua_tonumber(L,-1)+0.5) + +static int +numeric_field (lua_State *L, char *name, int dflt) { + int i = dflt; + lua_pushstring(L,name); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + i = lua_roundnumber(L,-1); + } + lua_pop(L,1); + return i; +} + +static int +n_numeric_field (lua_State *L, int name_index, int dflt) { + register int i = dflt; + lua_rawgeti(L,LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L,-2); + if (lua_type(L,-1)==LUA_TNUMBER) { + i = lua_roundnumber(L,-1); + } + lua_pop(L,1); + return i; +} + + +static int +enum_field (lua_State *L, char *name, int dflt, char **values) { + int k; + char *s; + int i = dflt; + lua_pushstring(L,name); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + i = lua_tonumber(L,-1); + } else if (lua_isstring(L,-1)) { + s = (char *)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 +boolean_field (lua_State *L, char *name, int dflt) { + int i = dflt; + lua_pushstring(L,name); + lua_rawget(L,-2); + if (lua_isboolean(L,-1)) { + i = lua_toboolean(L,-1); + } + 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 * +string_field (lua_State *L, char *name, char *dflt) { + char *i; + lua_pushstring(L,name); + lua_rawget(L,-2); + if (lua_isstring(L,-1)) { + i = xstrdup(lua_tostring(L,-1)); + } else if (dflt==NULL) { + i = NULL; + } else { + i = xstrdup(dflt); + } + lua_pop(L,1); + return i; +} + +static char * +n_string_field (lua_State *L, int name_index, char *dflt) { + char *i; + lua_rawgeti(L,LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */ + lua_rawget(L,-2); + if (lua_isstring(L,-1)) { + i = xstrdup(lua_tostring(L,-1)); + } else if (dflt==NULL) { + i = NULL; + } else { + i = xstrdup(dflt); + } + lua_pop(L,1); + return i; +} + +#define init_luaS_index(a) do { \ + lua_pushliteral(L,#a); \ + luaS_##a##_ptr = (char *)lua_tostring(L,-1); \ + luaS_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ + } while (0) + +#define make_luaS_index(a) \ + static int luaS_##a##_index = 0; \ + static char * luaS_##a##_ptr = NULL + +#define luaS_index(a) luaS_##a##_index + +#define luaS_ptr_eq(a,b) (a==luaS_##b##_ptr) + +make_luaS_index(width); +make_luaS_index(height); +make_luaS_index(depth); +make_luaS_index(italic); +make_luaS_index(index); +make_luaS_index(left_protruding); +make_luaS_index(right_protruding); +make_luaS_index(expansion_factor); +make_luaS_index(top); +make_luaS_index(bot); +make_luaS_index(rep); +make_luaS_index(mid); +make_luaS_index(next); +make_luaS_index(used); +make_luaS_index(name); +make_luaS_index(tounicode); +make_luaS_index(font); +make_luaS_index(char); +make_luaS_index(slot); +make_luaS_index(comment); +make_luaS_index(push); +make_luaS_index(pop); +make_luaS_index(rule); +make_luaS_index(right); +make_luaS_index(node); +make_luaS_index(down); +make_luaS_index(special); +make_luaS_index(slant); +make_luaS_index(space); +make_luaS_index(space_stretch); +make_luaS_index(space_shrink); +make_luaS_index(x_height); +make_luaS_index(quad); +make_luaS_index(extra_space); +make_luaS_index(left_boundary); +make_luaS_index(right_boundary); +make_luaS_index(kerns); +make_luaS_index(ligatures); +make_luaS_index(fonts); + +void init_font_string_pointers (lua_State *L) { + init_luaS_index(width); + init_luaS_index(height); + init_luaS_index(depth); + init_luaS_index(italic); + init_luaS_index(index); + init_luaS_index(left_protruding); + init_luaS_index(right_protruding); + init_luaS_index(expansion_factor); + init_luaS_index(top); + init_luaS_index(bot); + init_luaS_index(rep); + init_luaS_index(mid); + init_luaS_index(next); + init_luaS_index(used); + init_luaS_index(name); + init_luaS_index(tounicode); + init_luaS_index(font); + init_luaS_index(char); + init_luaS_index(slot); + init_luaS_index(comment); + init_luaS_index(push); + init_luaS_index(pop); + init_luaS_index(rule); + init_luaS_index(right); + init_luaS_index(node); + init_luaS_index(down); + init_luaS_index(special); + + init_luaS_index(slant); + init_luaS_index(space); + init_luaS_index(space_stretch); + init_luaS_index(space_shrink); + init_luaS_index(x_height); + init_luaS_index(quad); + init_luaS_index(extra_space); + + init_luaS_index(left_boundary); + init_luaS_index(right_boundary); + init_luaS_index(kerns); + init_luaS_index(ligatures); + init_luaS_index(fonts); +} + +static int +count_char_packet_bytes (lua_State *L) { + register int i; + register int l = 0; + int ff = 0; + for (i=1;i<=lua_objlen(L,-1);i++) { + lua_rawgeti(L,-1,i); + if (lua_istable(L,-1)) { + lua_rawgeti(L,-1,1); + if (lua_isstring(L,-1)) { + char *s = (char *)lua_tostring(L,-1); + if (luaS_ptr_eq(s,font)) { l+= 5; ff =1; } + else if (luaS_ptr_eq(s,char)) { if (ff==0) { l+=5; } l += 5; ff = 1; } + else if (luaS_ptr_eq(s,slot)) { l += 10; ff = 1;} + else if (luaS_ptr_eq(s,comment)) { ; } + else if (luaS_ptr_eq(s,push) || + luaS_ptr_eq(s,pop)) { l++; } + else if (luaS_ptr_eq(s,rule)) { l+=9; } + else if (luaS_ptr_eq(s,right) || + luaS_ptr_eq(s,node) || + luaS_ptr_eq(s,down)) { l+=5; } + else if (luaS_ptr_eq(s,special)) { + size_t len; + lua_rawgeti(L,-2,2); + (void)lua_tolstring(L,-1,&len); + lua_pop(L,1); + if (len>0) { l = l + 5 + len; } + } + else { fprintf(stdout,"unknown packet command %s!\n",s); } + } else { + fprintf(stdout,"no packet command!\n"); + } + lua_pop(L,1); /* command name */ + } + lua_pop(L,1); /* item */ + } + return l; +} + + + +scaled +sp_to_dvi (halfword sp, halfword atsize) { + double result, mult; + mult = (double)(atsize>>16); + result = (sp << 4); + return floor (result/mult ); +} + + +static void +read_char_packets (lua_State *L, integer *l_fonts, charinfo *co, int atsize) { + int i, n, m; + size_t l; + int cmd; + char *s; + real_eight_bits *cpackets; + int ff = 0; + int np = 0; + int max_f = 0; + int pc = count_char_packet_bytes (L); + if (pc<=0) + return; + assert(l_fonts != NULL); + assert(l_fonts[1] != 0); + while (l_fonts[(max_f+1)]!=0) + max_f++; + + cpackets = xmalloc(pc+1); + for (i=1;i<=lua_objlen(L,-1);i++) { + lua_rawgeti(L,-1,i); + if (lua_istable(L,-1)) { + /* fetch the command code */ + lua_rawgeti(L,-1,1); + if (lua_isstring(L,-1)) { + s = (char *)lua_tostring(L,-1); + cmd = 0; + if (luaS_ptr_eq(s,font)) { + cmd = packet_font_code; + } else if (luaS_ptr_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 (luaS_ptr_eq(s,slot)) { + cmd = packet_nop_code; + lua_rawgeti(L,-2,2); n = lua_tointeger(L,-1); + ff = (n>max_f ? l_fonts[1] : l_fonts[n]); + lua_rawgeti(L,-3,3); n = lua_tointeger(L,-1); + lua_pop(L,2); + append_packet(packet_font_code); + do_store_four(ff); + append_packet(packet_char_code); + do_store_four(n); + } + else if (luaS_ptr_eq(s,comment)) { cmd = packet_nop_code; } + else if (luaS_ptr_eq(s,node)) { cmd = packet_node_code; } + else if (luaS_ptr_eq(s,push)) { cmd = packet_push_code; } + else if (luaS_ptr_eq(s,pop)) { cmd = packet_pop_code; } + else if (luaS_ptr_eq(s,rule)) { cmd = packet_rule_code; } + else if (luaS_ptr_eq(s,right)) { cmd = packet_right_code; } + else if (luaS_ptr_eq(s,down)) { cmd = packet_down_code; } + else if (luaS_ptr_eq(s,special)) { cmd = packet_special_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 = lua_tointeger(L,-1); + 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 = lua_tointeger(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 = lua_tointeger(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 = lua_tointeger(L,-1); + do_store_four(sp_to_dvi(n,atsize)); + lua_rawgeti(L,-3,3); + n = lua_tointeger(L,-1); + do_store_four(sp_to_dvi(n,atsize)); + lua_pop(L,2); + break; + case packet_special_code: + append_packet(cmd); + lua_rawgeti(L,-2,2); + s = (char *)lua_tolstring(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_nop_code: + break; + default: + fprintf(stdout,"Unknown char packet code %s (char %d in font %s)\n",s,(int)c,font_name(f)); + } + } + lua_pop(L,1); /* command code */ + } else { + fprintf(stdout,"Found a `commands' item that is not a table (char %d in font %s)\n",(int)c,font_name(f)); + } + lua_pop(L,1); /* command table */ + } + 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_getfield(L,-1,"cidinfo"); + if (lua_istable(L,-1)) { + i = numeric_field(L,"version",0); + set_font_cidversion(f,i); + i = numeric_field(L,"supplement",0); + set_font_cidsupplement(f,i); + s = string_field(L,"registry","Adobe"); /* Adobe-Identity-0 */ + set_font_cidregistry(f,s); + s = string_field(L,"ordering","Identity"); + set_font_cidordering(f,s); + } + lua_pop(L,1); +} + + +static void +read_lua_parameters (lua_State *L, int f) { + int i, n; + char *s; + lua_getfield(L,-1,"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_isnumber(L,-2)) { + i = lua_tonumber(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_isnumber(L,-1)) { + n = lua_roundnumber(L,-1); + set_font_param(f,i, n); + } + lua_pop(L,1); + } + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L,-2)) { + i = lua_tointeger(L,-2); + if (i>=8) { + n = (lua_isnumber(L,-1) ? lua_roundnumber(L,-1) : 0); + set_font_param(f,i, n); + } + } else if (lua_isstring(L,-2)) { + s = (char *)lua_tostring(L,-2); + n = (lua_isnumber(L,-1) ? lua_roundnumber(L,-1) : 0); + if (luaS_ptr_eq(s,slant)) { set_font_param(f,slant_code,n); } + else if (luaS_ptr_eq(s,space)) { set_font_param(f,space_code,n); } + else if (luaS_ptr_eq(s,space_stretch)) { set_font_param(f,space_stretch_code,n); } + else if (luaS_ptr_eq(s,space_shrink)) { set_font_param(f,space_shrink_code,n); } + else if (luaS_ptr_eq(s,x_height)) { set_font_param(f,x_height_code,n); } + else if (luaS_ptr_eq(s,quad)) { set_font_param(f,quad_code,n); } + else if (luaS_ptr_eq(s,extra_space)) { set_font_param(f,extra_space_code,n); } + } + lua_pop(L,1); + } + } + lua_pop(L,1); + +} + +void +font_char_from_lua (lua_State *L, internal_font_number f, integer i, integer *l_fonts) { + int k,r,t; + charinfo *co; + kerninfo *ckerns; + liginfo *cligs; + scaled j; + 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 = n_numeric_field(L,luaS_width_index,0); set_charinfo_width (co,j); + j = n_numeric_field(L,luaS_height_index,0); set_charinfo_height (co,j); + j = n_numeric_field(L,luaS_depth_index,0); set_charinfo_depth (co,j); + j = n_numeric_field(L,luaS_italic_index,0); set_charinfo_italic (co,j); + j = n_numeric_field(L,luaS_index_index,0); set_charinfo_index(co,j); + j = n_numeric_field(L,luaS_expansion_factor_index,0); set_charinfo_ef(co,j); + j = n_numeric_field(L,luaS_left_protruding_index,0); set_charinfo_lp(co,j); + j = n_numeric_field(L,luaS_right_protruding_index,0); set_charinfo_rp(co,j); + k = n_boolean_field(L,luaS_used_index,0); set_charinfo_used(co,k); + s = n_string_field (L,luaS_name_index,NULL); set_charinfo_name(co,s); + s = n_string_field (L,luaS_tounicode_index,NULL); set_charinfo_tounicode(co,s); + k = n_numeric_field(L,luaS_next_index,-1); + if (k>=0) { + set_charinfo_tag (co,list_tag); + set_charinfo_remainder (co,k); + } + lua_getfield(L,-1,"extensible"); + if (lua_istable(L,-1)){ + int top, bot,mid, rep; + top = n_numeric_field(L,luaS_top_index,0); + bot = n_numeric_field(L,luaS_bot_index,0); + mid = n_numeric_field(L,luaS_mid_index,0); + rep = n_numeric_field(L,luaS_rep_index,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 { + pdftex_warn("lua-loaded font %s char [%d] has an invalid extensible field!",font_name(f),(int)i); + } + } + lua_pop(L,1); + + nk = count_hash_items(L,luaS_index(kerns)); + if (nk>0) { + ckerns = xcalloc((nk+1),sizeof(kerninfo)); + lua_rawgeti(L,LUA_REGISTRYINDEX,luaS_index(kerns)); + lua_rawget(L,-2); + if (lua_istable(L,-1)) { /* there are kerns */ + ctr = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + if (lua_isnumber(L,-2)) { + k = lua_tonumber(L,-2); /* adjacent char */ + if (k<0) + k = non_boundarychar; + } else if (lua_isstring(L,-2)) { + s = (char *)lua_tostring(L,-2); + if (luaS_ptr_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 { + pdftex_warn("lua-loaded font %s char [%d] 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 { + pdftex_warn("lua-loaded font %s char [%d] has an invalid kerns field!",font_name(f),(int)i); + } + } + lua_pop(L,1); + } + + /* packet commands */ + lua_getfield(L,-1,"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,(integer *)l_fonts,co,atsize); + } + } + lua_pop(L,1); + + /* ligatures */ + nl = count_hash_items(L,luaS_index(ligatures)); + + if (nl>0) { + cligs = xcalloc((nl+1),sizeof(liginfo)); + lua_rawgeti(L,LUA_REGISTRYINDEX,luaS_index(ligatures)); + lua_rawget(L,-2); + if (lua_istable(L,-1)){/* do ligs */ + ctr = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + k = non_boundarychar; + if (lua_isnumber(L,-2)) { + k = lua_tonumber(L,-2); /* adjacent char */ + if (k<0) { + k = non_boundarychar; + } + } else if (lua_isstring(L,-2)) { + s = (char *)lua_tostring(L,-2); + if (luaS_ptr_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 = n_numeric_field(L,luaS_char_index,-1); /* ligature */ + } + if (r != -1 && k != non_boundarychar) { + t = enum_field(L,"type",0,ligature_type_strings); + set_ligature_item(cligs[ctr],(t*2)+1,k,r); + ctr++; + } else { + pdftex_warn("lua-loaded font %s char [%d] 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 { + pdftex_warn("lua-loaded font %s char [%d] 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! */ + + +int +font_from_lua (lua_State *L, int f) { + int i,n,r,t; + int s_top; /* lua stack top */ + int bc; /* first char index */ + int ec; /* last char index */ + char *s; + integer *l_fonts = NULL; + /* the table is at stack index -1 */ + + if (luaS_width_index==0) + init_font_string_pointers(L); + + s = string_field(L,"area",""); set_font_area(f,s); + s = string_field(L,"filename",NULL); set_font_filename(f,s); + s = string_field(L,"encodingname",NULL); set_font_encodingname(f,s); + + s = string_field(L,"name",NULL); set_font_name(f,s); + s = string_field(L,"fullname",font_name(f)); set_font_fullname(f,s); + + if (s==NULL) { + pdftex_fail("lua-loaded font [%d] has no name!",f); + return false; + } + + i = numeric_field(L,"designsize",655360); set_font_dsize(f,i); + i = numeric_field(L,"size",font_dsize(f)); set_font_size(f,i); + i = numeric_field(L,"checksum",0); set_font_checksum(f,i); + i = numeric_field(L,"direction",0); set_font_natural_dir(f,i); + i = numeric_field(L,"encodingbytes",0); set_font_encodingbytes(f,i); + i = numeric_field(L,"tounicode",0); set_font_tounicode(f,i); + + i = numeric_field(L,"extend",0); + if (i<-2000) i = -2000; if (i>2000) i = 2000; if (i==1000) i = 0; + set_font_extend(f,i); + i = numeric_field(L,"slant",0); + if (i<-1000) i = -1000; if (i>1000) i = 1000; + set_font_slant(f,i); + + i = numeric_field(L,"hyphenchar",get_default_hyphen_char()); set_hyphen_char(f,i); + i = numeric_field(L,"skewchar",get_default_skew_char()); set_skew_char(f,i); + i = boolean_field(L,"used",0); set_font_used(f,i); + + s = string_field (L,"attributes",NULL); + if (s!=NULL && strlen(s)>0) { + i = maketexstring(s); + set_pdf_font_attr(f,i); + } + + i = enum_field(L,"type", unknown_font_type,font_type_strings); set_font_type(f,i); + i = enum_field(L,"format", unknown_format, font_format_strings); set_font_format(f,i); + i = enum_field(L,"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 */ + n = count_hash_items(L,luaS_index(fonts)); + if (n>0) { + l_fonts = xmalloc((n+2)*sizeof(integer)); + memset (l_fonts,0,(n+2)*sizeof(integer)); + lua_rawgeti(L,LUA_REGISTRYINDEX,luaS_index(fonts)); + lua_rawget(L,-2); + for (i=1;i<=n;i++) { + lua_rawgeti(L,-1,i); + if (lua_istable(L,-1)) { + lua_getfield(L,-1,"id"); + if (lua_isnumber(L,-1)) { + l_fonts[i] = lua_tonumber(L,-1); + lua_pop(L,2); /* pop id and entry */ + continue; + } + lua_pop(L,1); /* pop id */ + }; + s = NULL; + if (lua_istable(L,-1)) { + lua_getfield(L,-1,"name"); + if (lua_isstring(L,-1)) { + s = (char *)lua_tostring(L,-1); + } + lua_pop(L,1); /* pop name */ + } + if (s!= NULL) { + lua_getfield(L,-1,"size"); + t = (lua_isnumber(L,-1) ? lua_roundnumber(L,-1) : -1000); + lua_pop(L,1); + + /* TODO: the stack is messed up, otherwise this + * explicit resizing would not be needed + */ + s_top = lua_gettop(L); + l_fonts[i] = find_font_id(s,"",t); + lua_settop(L,s_top); + } else { + pdftex_fail("Invalid local font in font %s!\n", font_name(f)); + } + lua_pop(L,1); /* pop list entry */ + } + lua_pop(L,1); /* pop list entry */ + } else { + if(font_type(f) == virtual_font_type) { + pdftex_fail("Invalid local fonts in font %s!\n", font_name(f)); + } else { + l_fonts = xmalloc(3*sizeof(integer)); + l_fonts[0] = 0; + l_fonts[1] = f; + l_fonts[2] = 0; + } + } + + /* parameters */ + read_lua_parameters(L,f); + read_lua_cidinfo(L,f); + + /* characters */ + lua_getfield(L,-1,"characters"); + if (lua_istable(L,-1)) { + /* find the array size values */ + ec = 0; bc = -1; + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L,-2)) { + i = lua_tointeger(L,-2); + if (i>=0) { + if (lua_istable(L,-1)) { + if (i>ec) ec = i; + if (bc<0) bc = i; + if (bc>=0 && i<bc) bc = i; + } + } + } + lua_pop(L, 1); + } + + if (bc != -1) { + /* fprintf(stdout,"defined a font at %d with %d-%d\n",f,bc,ec); */ + set_font_bc(f,bc); + set_font_ec(f,ec); + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + if (lua_isnumber(L,-2)) { + i = lua_tonumber(L,-2); + if (i>=0) { + font_char_from_lua(L,f, i, l_fonts); + } + } else if (lua_isstring(L,-2)) { + s = (char *)lua_tostring(L,-2); + if (luaS_ptr_eq(s,left_boundary)) { + font_char_from_lua(L,f, left_boundarychar, l_fonts); + } else if (luaS_ptr_eq(s,right_boundary)) { + font_char_from_lua(L,f, right_boundarychar, l_fonts); + } + } + 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 = numeric_field(L,"step",0); + if (fstep<0) fstep = 0; + if (fstep>100) fstep = 100; + if (fstep!=0) { + int fshrink = numeric_field(L,"shrink",0); + int fstretch = numeric_field(L,"stretch",0); + int fexpand = boolean_field(L,"auto_expand",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, fexpand, fstretch, fshrink, fstep, 0); + } + } + + } else { /* jikes, no characters */ + pdftex_warn("lua-loaded font [%d] (%s) has no characters!",f, font_name(f)); + } + +#if SAVE_REF + r = luaL_ref(Luas[0],LUA_REGISTRYINDEX); /* pops the table */ + set_font_cache_id(f,r); +#else + lua_pop(Luas[0],1); +#endif + } else { /* jikes, no characters */ + pdftex_warn("lua-loaded font [%d] (%s) has no character table!",f, font_name(f)); + } + + if (l_fonts!=NULL) + free(l_fonts); + return true; +} + +/* ==================================================================== + * + * L I G A T U R I N G + * + * ==================================================================== */ + + +#define assert_disc(a) \ + assert(pre_break(a)!=null); /* expect head_node */ \ + assert(type(pre_break(a))==nesting_node); \ + assert((vlink_pre_break(a)==null && tlink_pre_break(a)==null) || tail_of_list(vlink_pre_break(a))==tlink_pre_break(a)); \ + assert(post_break(a)!=null); /* expect head_node */ \ + assert(type(post_break(a))==nesting_node); \ + assert((vlink_post_break(a)==null && tlink_post_break(a)==null) || tail_of_list(vlink_post_break(a))==tlink_post_break(a)); \ + assert(no_break(a)!=null); /* expect head_node */ \ + assert(type(no_break(a))==nesting_node); \ + assert((vlink_no_break(a)==null && tlink_no_break(a)==null) || tail_of_list(vlink_no_break(a))==tlink_no_break(a)); + +static void +nesting_append (halfword nest, halfword newn) { + halfword tail = tlink(nest); + assert(alink(nest)==null); + assert(vlink(newn)==null); + assert(alink(newn)==null); + if (tail==null) { + assert(vlink(nest)==null); + couple_nodes(nest,newn); + } else { + assert(vlink(tail)==null); + assert(tail_of_list(vlink(nest))==tail); + couple_nodes(tail,newn); + } + tlink(nest) = newn; +} + + +static void +nesting_prepend (halfword nest, halfword newn) { + halfword head = vlink(nest); + assert(alink(nest)==null); + assert(vlink(newn)==null); + assert(alink(newn)==null); + couple_nodes(nest,newn); + if (head==null) { + assert(tlink(nest)==null); + tlink(nest) = newn; + } else { + assert(alink(head)==nest); + assert(tail_of_list(head)==tlink(nest)); + couple_nodes(newn,head); + } +} + + +static int +test_ligature( liginfo *lig, halfword left, halfword right ) { + if (type(left)!=glyph_node) + return 0; + assert(type(right)==glyph_node); + 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; + assert(prev!=null); + couple_nodes(prev,newgl); + cur = newgl; /* as cur has disappeared */ + } + /* right side */ + if (keep_right) { + halfword new_second = copy_node(fwd); + /* correct, because we _know_ lig_ptr points to _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 _know_ lig_ptr points to _one_ node */ + couple_nodes(lig_ptr(newgl),fwd); + if (next!=null) {couple_nodes(newgl,next);} + } + + /* check and return */ + /* assert(move_after==0);*/ + *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 */ +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); + assert(vlink(alink(cur))==cur); + } + tlink(root) = cur; + return root; +} + + +static halfword +handle_lig_word(halfword cur) { + halfword right=null; + + if (type(cur)==whatsit_node && subtype(cur)==cancel_boundary_node) { + halfword prev= alink(cur); + halfword fwd = vlink(cur); +/* uncouple_node(cur); */ /* not needed, 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; + couple_nodes(cur,right); + right = null; + continue; + } + assert(alink(fwd)==cur); + 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); + liginfo lig; + assert_disc(fwd); + /* 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); + assert(vlink(prev)==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}*/ + halfword 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); + assert(alink(next)==fwd); + assert(vlink(prev)==cur); + uncouple_node(cur); + couple_nodes(prev,fwd); + couple_nodes(no_break(fwd),cur); /* we _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 */ + halfword tail = vlink(next); + uncouple_node(next); + try_couple_nodes(fwd,tail); + couple_nodes(cur,next); /* we _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)==whatsit_node && subtype(fwd)==cancel_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 */ + /* right = null; */ /* no need, 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) { + assert_disc(cur); + /* If {?}{x}{?} or {?}{?}{y} then ... */ + if (vlink_no_break(cur)!=null || vlink_post_break(cur)!=null) { + halfword fwd; + halfword lists[511]; /* max 8 levels */ + + int i, max_depth=0; + lists[max_depth++] = handle_lig_nest(post_break(cur),vlink_post_break(cur)); + lists[max_depth++] = handle_lig_nest(no_break(cur),vlink_no_break(cur)); + while (1) { + if ((fwd = vlink(cur))==null) return cur; + if ( type(fwd)==glyph_node) { + for (i=0; i<max_depth; i++) { + liginfo lig; + halfword tail = tlink(lists[i]); + if ( tail!=null && test_ligature(&lig,tail,fwd)) + goto add_glyph_to_all; + } + /* if we get here, nothing had a ligature, so we stop */ + break; +add_glyph_to_all: + for (i=0; i<max_depth; i++) { + halfword copy = copy_node(fwd); + halfword tail = tlink(lists[i]); + nesting_append(lists[i],copy); + if (tail==null) continue; /* first character - never a ligature */ + handle_lig_nest(lists[i],tail); + } + halfword next = vlink(fwd); + uncouple_node(fwd); + try_couple_nodes(cur,next); + flush_node(fwd); + } else if ( type(fwd)==disc_node) { + /* MAGIC WARNING + * A disc followed by a disc can have different kernings + * depending on which path is choosen, and it is impossible to + * store the possible kernings: fe {}{A}{W} {V}{}{A} + * So we _always_ add discs so only a simple path remains. */ + int m=max_depth; /* as max_depth changes in this loop */ + for (i=0; i<m; i++) { + halfword copy = copy_node(fwd); + halfword tail = tlink(lists[i]); + if (tail!=null) { + halfword prev = alink(tail); + assert(alink(tail)!=null); + uncouple_node(tail); + vlink(prev) = null; + if (prev==lists[i]) { + tlink(prev) = null; + } else { + tlink(lists[i]) = prev; + } + nesting_prepend(pre_break(copy),tail); + nesting_prepend(no_break(copy),copy_node(tail)); + } + nesting_append(lists[i],copy); + handle_lig_nest(pre_break(copy),vlink_pre_break(copy)); + assert(max_depth<256); + lists[max_depth++] = handle_lig_nest(no_break(copy),vlink_no_break(copy)); + lists[i] = handle_lig_nest(post_break(copy),vlink_post_break(copy)); + } + halfword next = vlink(fwd); + uncouple_node(fwd); + try_couple_nodes(cur,next); + flush_node(fwd); + } else { + return cur; + } + } + } + } else { /* NO GLYPH NOR DISC */ + /* fprintf(stdout,"This is a %d node\n",type(cur));*/ + /* assert(0);*/ /* TODO howcome there can be a glue here? */ + return cur; + } + /* step-to-next-node */ + { + halfword prev = cur; + cur = vlink(cur); + assert(cur!=null); + assert(alink(cur)==prev); + /* alink(cur) = prev;*/ + } + } + + return cur; +} + +/* return = new tail, head should be a dummy */ + +halfword +handle_ligaturing(halfword head, halfword tail) { + halfword save_tail ; /* trick to allow explicit node==null tests */ + halfword cur, prev; + + if (vlink(head)==null) + return tail; + save_tail = 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)==whatsit_node && subtype(cur)==cancel_boundary_node)) { + cur = handle_lig_word(cur); + } + prev = cur; + cur = vlink(cur); + assert(cur==null||alink(cur) == prev); + } + if (valid_node(save_tail)) { + try_couple_nodes(prev,save_tail); + } + return prev; +} + + +/* ==================================================================== + * + * K E R N I N G + * + * ==================================================================== */ + +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 = get_kern(font(left),character(left),character(right)); + if (k!=0) { + halfword kern = new_kern(k); + halfword prev = alink(right); + assert(vlink(prev)==right); + couple_nodes(prev,kern); + couple_nodes(kern,right); + } + } +} + + +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 = get_kern(font(left),character(left),character(right)); + if (k!=0) { + halfword kern = new_kern(k); + halfword next = vlink(aft); + assert(next==null||alink(next)==aft); + couple_nodes(aft,kern); + try_couple_nodes(kern,next); + } + } +} + + +static void +do_handle_kerning (halfword root, halfword init_left, halfword init_right) { + halfword cur = vlink(root); + halfword left = null; + assert(init_left==null || type(init_left)==glyph_node); + assert(init_right==null || type(init_right)==glyph_node); + 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); + do_handle_kerning(post_break(cur),null,right); + do_handle_kerning(no_break(cur),left,right); + } + 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; + assert(vlink(next)==null); + assert(type(next)==kern_node); + } 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; +} + +/* ==================================================================== + * + * L I G A T U R I N G and K E R N I N G : L U A - I N T E R F A C E + * + * ==================================================================== */ + +static halfword +run_lua_ligkern_callback (halfword head, halfword tail, int callback_id){ + lua_State *L = Luas[0]; + lua_rawgeti(L,LUA_REGISTRYINDEX,callback_callbacks_id); + lua_rawgeti(L,-1, callback_id); + if (!lua_isfunction(L,-1)) { + lua_pop(L,2); + return tail; + } + nodelist_to_lua(L,head); + nodelist_to_lua(L,tail); + if (lua_pcall(L,2,1,0) != 0) { + fprintf(stdout,"error: %s\n",lua_tostring(L,-1)); + lua_pop(L,2); + lua_error(L); + return tail; + } + tail = nodelist_from_lua(L); + if (fix_node_lists) + fix_node_list(head); + lua_pop(L,2); + return tail; +} + + +halfword +new_ligkern(halfword head, halfword tail) { + int callback_id = 0; + + assert(head!=null); + 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 { + 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 { + halfword nest = new_node(nesting_node,1); + halfword cur = vlink(head); + halfword aft = vlink(tail); + couple_nodes(nest,cur); + tlink(nest)=tail; + vlink(tail)=null; + do_handle_kerning(nest,null,null); + couple_nodes(head,vlink(nest)); + tail = tlink(nest); + try_couple_nodes(tail,aft); + flush_node(nest); + } + return tail; +} + diff --git a/Build/source/texk/web2c/luatexdir/font/macnames.c b/Build/source/texk/web2c/luatexdir/font/macnames.c new file mode 100644 index 00000000000..941f087ef56 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/macnames.c @@ -0,0 +1,312 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: macnames.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +const char notdef[] = ".notdef"; + +const char *mac_glyph_names[] = { +/* 0x00 */ + notdef, + ".null", + "CR", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", +/* 0x10 */ + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", +/* 0x20 */ + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", +/* 0x30 */ + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", +/* 0x40 */ + "bracketright", + "asciicircum", + "underscore", + "grave", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", +/* 0x50 */ + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", +/* 0x60 */ + "braceright", + "asciitilde", + "Adieresis", + "Aring", + "Ccedilla", + "Eacute", + "Ntilde", + "Odieresis", + "Udieresis", + "aacute", + "agrave", + "acircumflex", + "adieresis", + "atilde", + "aring", + "ccedilla", +/* 0x70 */ + "eacute", + "egrave", + "ecircumflex", + "edieresis", + "iacute", + "igrave", + "icircumflex", + "idieresis", + "ntilde", + "oacute", + "ograve", + "ocircumflex", + "odieresis", + "otilde", + "uacute", + "ugrave", +/* 0x80 */ + "ucircumflex", + "udieresis", + "dagger", + "degree", + "cent", + "sterling", + "section", + "bullet", + "paragraph", + "germandbls", + "registered", + "copyright", + "trademark", + "acute", + "dieresis", + "notequal", +/* 0x90 */ + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu", + "partialdiff", + "Sigma", + "Pi", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Omega", +/* 0xa0 */ + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "Delta", + "guillemotleft", + "guillemotright", + "ellipsis", + "nbspace", + "Agrave", + "Atilde", + "Otilde", +/* 0xb0 */ + "OE", + "oe", + "endash", + "emdash", + "quotedblleft", + "quotedblright", + "quoteleft", + "quoteright", + "divide", + "lozenge", + "ydieresis", + "Ydieresis", + "fraction", + "currency", + "guilsinglleft", + "guilsinglright", +/* 0xc0 */ + "fi", + "fl", + "daggerdbl", + "periodcentered", + "quotesinglbase", + "quotedblbase", + "perthousand", + "Acircumflex", + "Ecircumflex", + "Aacute", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", +/* 0xd0 */ + "Oacute", + "Ocircumflex", + "applelogo", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", +/* 0xe0 */ + "ogonek", + "caron", + "Lslash", + "lslash", + "Scaron", + "scaron", + "Zcaron", + "zcaron", + "brokenbar", + "Eth", + "eth", + "Yacute", + "yacute", + "Thorn", + "thorn", + "minus", +/* 0xf0 */ + "multiply", + "onesuperior", + "twosuperior", + "threesuperior", + "onehalf", + "onequarter", + "threequarters", + "franc", + "Gbreve", + "gbreve", + "Idot", + "Scedilla", + "scedilla", + "Cacute", + "cacute", + "Ccaron", +/* 0x100 */ + "ccaron", + "dmacron" +}; + +const char *ambiguous_names[] = { + "Delta", /* increment */ + "Omega", /* Ohm */ + "Pi", /* product */ + "Sigma", /* summation */ + "dmacron", /* dslash */ + "macron", /* overscore */ + "periodcentered", /* middot */ + NULL +}; diff --git a/Build/source/texk/web2c/luatexdir/font/mapfile.c b/Build/source/texk/web2c/luatexdir/font/mapfile.c new file mode 100644 index 00000000000..1c444e5c1d4 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/mapfile.c @@ -0,0 +1,967 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: mapfile.c 1013 2008-02-14 00:09:02Z oneiros $ + +*/ + +#include <math.h> +#include "ptexlib.h" +#include <kpathsea/c-auto.h> +#include <kpathsea/c-memstr.h> +#include <string.h> +#include "luatex-api.h" + +#define FM_BUF_SIZE 1024 + +static FILE *fm_file; + +static unsigned char *fm_buffer = NULL; +static integer fm_size = 0; +static integer fm_curbyte = 0; + +#define fm_open() \ + open_input (&fm_file, kpse_fontmap_format, 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) + +typedef enum { FM_DUPIGNORE, FM_REPLACE, FM_DELETE } updatemode; +typedef enum { MAPFILE, MAPLINE } maptype; + +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; + +static const char nontfm[] = "<nontfm>"; + +#define read_field(r, q, buf) do { \ + q = buf; \ + while (*r != ' ' && *r != '<' && *r != '"' && *r != '\0') \ + *q++ = *r++; \ + *q = '\0'; \ + skip (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->sfd_name = NULL; + fm->ps_name = NULL; + fm->fd_flags = 4; + fm->ff_name = NULL; + fm->encname = NULL; + fm->type = 0; + fm->slant = 0; + fm->extend = 0; + fm->links = 0; + fm->pid = -1; + fm->eid = -1; + fm->subfont = NULL; + fm->in_use = false; + return fm; +} + +void delete_fm_entry(fm_entry * fm) +{ + xfree(fm->tfm_name); + xfree(fm->sfd_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 fm_entry *dummy_fm_entry () +{ + static const fm_entry const_fm_entry; + return (fm_entry *) & const_fm_entry; +} + +/**********************************************************************/ + +struct avl_table *tfm_tree = NULL; +struct avl_table *ps_tree = NULL; +struct avl_table *ff_tree = NULL; +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) +{ + return strcmp (((const fm_entry *) pa)->tfm_name, + ((const fm_entry *) pb)->tfm_name); +} + +/* AVL sort fm_entry into ps_tree by ps_name, slant, and extend */ + +static int comp_fm_entry_ps(const void *pa, const void *pb, void *p) +{ + int i; + const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb; + assert(p1->ps_name != NULL && p2->ps_name != NULL); + if ((i = strcmp(p1->ps_name, p2->ps_name))) + return i; + cmp_return(p1->slant, p2->slant); + cmp_return(p1->extend, p2->extend); + return 0; +} + +/* AVL sort ff_entry into ff_tree by ff_name */ + +static int comp_ff_entry (const void *pa, const void *pb, void *p) +{ + return strcmp (((const ff_entry *) pa)->ff_name, + ((const ff_entry *) pb)->ff_name); +} + +static void create_avl_trees () +{ + assert(tfm_tree == NULL); + tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator); + assert(tfm_tree != NULL); + assert(ps_tree == NULL); + ps_tree = avl_create(comp_fm_entry_ps, NULL, &avl_xallocator); + assert(ps_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); +} + +/* +The function avl_do_entry() is not completely symmetrical with regards +to tfm_name and ps_name handling, e. g. a duplicate tfm_name gives a +"goto exit", and no ps_name link is tried. This is to keep it compatible +with the original version. +*/ + +int avl_do_entry(fm_entry * fm, int mode) +{ + fm_entry *p; + void *a; + void **aa; + + /* handle tfm_name link */ + + if (strcmp(fm->tfm_name, nontfm)) { + p = (fm_entry *) avl_find(tfm_tree, fm); + if (p != NULL) { + switch (mode) { + case FM_DUPIGNORE: + pdftex_warn + ("fontmap entry for `%s' already exists, duplicates ignored", + fm->tfm_name); + goto exit; + break; + case FM_REPLACE: + case FM_DELETE: + if (p->in_use) { + pdftex_warn + ("fontmap entry for `%s' has been used, replace/delete not allowed", + fm->tfm_name); + goto exit; + } + a = avl_delete(tfm_tree, p); + assert(a != NULL); + unset_tfmlink(p); + if (!has_pslink(p)) + delete_fm_entry(p); + break; + default: + assert(0); + } + } + if (mode != FM_DELETE) { + aa = avl_probe(tfm_tree, fm); + assert(aa != NULL); + set_tfmlink(fm); + } + } + + /* handle ps_name link */ + + if (fm->ps_name != NULL) { + p = (fm_entry *) avl_find(ps_tree, fm); + if (p != NULL) { + switch (mode) { + case FM_DUPIGNORE: + goto exit; + break; + case FM_REPLACE: + case FM_DELETE: + if (p->in_use) + goto exit; + a = avl_delete(ps_tree, p); + assert(a != NULL); + unset_pslink(p); + if (!has_tfmlink(p)) + delete_fm_entry(p); + break; + default: + assert(0); + } + } + if (mode != FM_DELETE && is_t1fontfile(fm) && is_included(fm)) { + aa = avl_probe(ps_tree, fm); + assert(aa != NULL); + set_pslink(fm); + } + } + exit: + if (!has_tfmlink(fm) && !has_pslink(fm)) /* e. g. after FM_DELETE */ + return 1; /* deallocation of fm_entry structure required */ + else + return 0; +} + +/* add the encoding name to an AVL tree. this has nothing to do with writeenc.c */ + +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 */ + +int check_fm_entry(fm_entry * fm, boolean warn) +{ + int a = 0; + assert(fm != NULL); + + if (is_fontfile(fm) && !is_included(fm)) { + if (warn) + pdftex_warn + ("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) + pdftex_warn + ("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) + pdftex_warn + ("invalid entry for `%s': only subsetted TrueType font can be reencoded", + fm->tfm_name); + a += 2; + } + + /* SlantFont and ExtendFont can be used only with Type1 fonts */ + if ((fm->slant != 0 || fm->extend != 0) + && !(is_t1fontfile(fm) && is_included(fm))) { + if (warn) + pdftex_warn + ("invalid entry for `%s': SlantFont/ExtendFont can be used only with embedded Type1 fonts", + fm->tfm_name); + a += 4; + } + + /* the value of SlantFont and ExtendFont must be reasonable */ + if (abs(fm->slant) > 1000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of SlantFont (%g)", + fm->tfm_name, fm->slant / 1000.0); + a += 8; + } + if (abs(fm->extend) > 2000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of ExtendFont (%g)", + fm->tfm_name, fm->extend / 1000.0); + a += 16; + } + + /* subfonts must be used with subsetted non-reencoded TrueType fonts */ + if (fm->pid != -1 && + !(is_truetype(fm) && is_subsetted(fm) && !is_reencoded(fm))) { + if (warn) + pdftex_warn + ("invalid entry for `%s': PidEid can be used only with subsetted non-reencoded TrueType fonts", + fm->tfm_name); + a += 32; + } + + return a; +} + +/**********************************************************************/ +/* returns true if s is one of the 14 std. font names; speed-trimmed. */ + +boolean 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 + }; + const size_t n = strlen(s); + int k = -1; + if (n > 21) + return false; + 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 false; + } + } else + k = index[n]; + if (k > -1 && !strcmp(std_t1font_names[k], s)) + return true; + return false; +}; + +/**********************************************************************/ + +static void fm_scan_line() +{ + int a, b, c, j, u = 0, v = 0; + float d; + fm_entry *fm; + char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE]; + char *p, *q, *r, *s; + switch (mitem->type) { + case MAPFILE: + p = fm_line; + do { + c = fm_getchar(); + append_char_to_buf(c, p, fm_line, FM_BUF_SIZE); + } + while (c != 10 && !fm_eof()); + *(--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(*r)) { /* 2nd field ps_name may not start with a digit */ + read_field(r, q, buf); + set_field(ps_name); + } + if (isdigit(*r)) { /* font descriptor /Flags given? */ + for (s = r; isdigit(*s); s++); + if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') { /* not e. g. 8r.enc */ + fm->fd_flags = atoi(r); + while (isdigit(*r)) + r++; + } + } + while (1) { /* loop through "specials", encoding, font file */ + skip(r, ' '); + switch (*r) { + case '\0': + goto done; + case '"': /* opening quote */ + r++; + u = v = 0; + do { + skip(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 *= 1000.0; /* correct rounding also for neg. numbers */ + fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5); + r = s + strlen("SlantFont"); + } else if (str_prefix(s, "ExtendFont")) { + d *= 1000.0; + fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5); + if (fm->extend == 1000) + fm->extend = 0; + 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'; + pdftex_warn + ("invalid entry for `%s': unknown name `%s' ignored", + fm->tfm_name, s); + *r = c; + } + } else + for (; *r != ' ' && *r != '"' && *r != '\0'; r++); + } + while (*r == ' '); + if (*r == '"') /* closing quote */ + r++; + else { + pdftex_warn + ("invalid entry for `%s': closing quote missing", + fm->tfm_name); + goto bad_line; + } + break; + case 'P': /* handle cases for subfonts like 'PidEid=3,1' */ + if (sscanf(r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) { + fm->pid = a; + fm->eid = b; + r += c; + 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)) + set_std_t1font(fm); + if (is_fontfile(fm)) { + if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 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 (handle_subfont_fm(fm, mitem->mode)) /* is this a subfont? */ + return; + if (avl_do_entry(fm, mitem->mode) == 0) /* if success */ + return; + bad_line: + delete_fm_entry(fm); +} + +/**********************************************************************/ + +void fm_read_info () +{ + int callback_id; + int file_opened = 0; + char *ftemp = NULL; + if (tfm_tree == NULL) + create_avl_trees (); + if (mitem->line == NULL) /* nothing to do */ + return; + mitem->lineno = 1; + switch (mitem->type) { + case MAPFILE: + set_cur_file_name (mitem->line); + if (fm_buffer!=NULL) { + xfree(fm_buffer); + fm_buffer=NULL; + } + fm_curbyte=0; + fm_size=0; + callback_id=callback_defined(find_map_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } + } + } + callback_id=callback_defined(read_map_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",(char *)(nameoffile+1), + &file_opened, &fm_buffer,&fm_size)) { + if(file_opened) { + if (fm_size>0) { + cur_file_name = (char *) nameoffile + 1; + if (tracefilenames) + tex_printf ("{%s", cur_file_name); + while (!fm_eof ()) { + fm_scan_line (); + mitem->lineno++; + } + if (tracefilenames) + tex_printf ("}"); + fm_file = NULL; + } + } else { + pdftex_warn ("cannot open font map file"); + } + } else { + pdftex_warn ("cannot open font map file"); + } + } else { + if (!fm_open ()) { + pdftex_warn ("cannot open font map file"); + } else { + fm_read_file(); + cur_file_name = (char *) nameoffile + 1; + tex_printf ("{%s", cur_file_name); + while (!fm_eof ()) { + fm_scan_line (); + mitem->lineno++; + } + fm_close (); + tex_printf ("}"); + fm_file = NULL; + } + } + break; + case MAPLINE: + cur_file_name = NULL; /* makes pdftex_warn() shorter */ + fm_scan_line (); + break; + default: + assert (0); + } + mitem->line = NULL; /* done with this line */ + cur_file_name = NULL; + return; +} + +/**********************************************************************/ + +static fm_entry_ptr fmlookup(internalfontnumber f) +{ + char *tfm; + fm_entry *fm; + fm_entry tmp; + if (tfm_tree == NULL) + fm_read_info(); /* only to read default map file */ + tfm = font_name(f); + assert(strcmp(tfm, nontfm)); + + /* Look up for full <tfmname>[+-]<expand> */ + tmp.tfm_name = tfm; + fm = (fm_entry *) avl_find(tfm_tree, &tmp); + if (fm != NULL) { + fm->in_use = true; + return (fm_entry_ptr) fm; + } + return (fm_entry_ptr) dummy_fm_entry(); +} + +boolean hasfmentry(internalfontnumber f) +{ + if (font_map(f) == NULL) + set_font_map(f, (fm_entry_ptr) fmlookup(f)); + assert(font_map(f) != NULL); + return font_map(f) != (fm_entry_ptr) dummy_fm_entry(); +} + +/* check whether a map entry is valid for font replacement */ + +static boolean fm_valid_for_font_replacement(fm_entry * fm) +{ + ff_entry *ff; + + assert(fm != NULL); + assert(is_fontfile(fm)); /* ps_tree should contain only entries with font file */ + assert(is_type1(fm)); /* ps_tree should contain only Type1 entries */ + + ff = check_ff_exist(fm->ff_name, false); + assert(ff != NULL); + if (ff->ff_path == NULL) /* ...there is no font file available */ + return false; + return true; /* all tests passed */ +} + +/**********************************************************************/ +/* + * lookup fontmap by ps_name; + * used for Type1 font replacement when embedding of PDF files + */ + +fm_entry *lookup_fontmap(char *ps_name) +{ + fm_entry *fm, *fm2, tmp; + char *a, *b, *c, *d, *e, *s; + int i, sl, ex; + struct avl_traverser t, t2; + if (tfm_tree == NULL) + fm_read_info(); /* only to read default map file */ + assert(ps_name != NULL); + s = ps_name; + if (strlen(ps_name) > 7) { /* check for subsetted name tag */ + for (i = 0; i < 6; i++, s++) + if (*s < 'A' || *s > 'Z') + break; + if (i == 6 && *s == '+') + s++; /* if name tag found, skip behind it */ + else + s = ps_name; + } + + /* + * Scan -Slant_<slant> and -Extend_<extend> font name extensions; + * three valid formats: + * <fontname>-Slant_<slant> + * <fontname>-Slant_<slant>-Extend_<extend> + * <fontname>-Extend_<extend> + * Slant entry must come _before_ Extend entry + */ + + tmp.slant = 0; + tmp.extend = 0; + if ((a = strstr(s, "-Slant_")) != NULL) { + b = a + strlen("-Slant_"); + sl = (int) strtol(b, &e, 10); + if ((e != b) && (e == strend(b))) { + tmp.slant = sl; + *a = '\0'; /* ps_name string ends before "-Slant_" */ + } else { + if (e != b) { /* only if <slant> is valid number */ + if ((c = strstr(e, "-Extend_")) != NULL) { + d = c + strlen("-Extend_"); + ex = (int) strtol(d, &e, 10); + if ((e != d) && (e == strend(d))) { + tmp.slant = sl; + tmp.extend = ex; + *a = '\0'; /* ps_name string ends before "-Slant_" */ + } + } + } + } + } else { + if ((a = strstr(s, "-Extend_")) != NULL) { + b = a + strlen("-Extend_"); + ex = (int) strtol(b, &e, 10); + if ((e != b) && (e == strend(b))) { + tmp.extend = ex; + *a = '\0'; /* ps_name string ends before "-Extend_" */ + } + } + } + tmp.ps_name = s; + + fm = (fm_entry *) avl_t_find(&t, ps_tree, &tmp); + if (fm == NULL) + return NULL; /* no entry found */ + + /* at this point we know there is at least one fm_entry with given ps_name; + * we test all such entries and return the first one that is valid for font + * replacement */ + + t2 = t; + fm2 = (fm_entry *) avl_t_prev(&t2); + + /* search forward */ + do { + if (fm_valid_for_font_replacement(fm)) + return fm; + fm = (fm_entry *) avl_t_next(&t); + } while (fm != NULL && comp_fm_entry_ps(fm, &tmp, NULL) == 0); + + /* search backward */ + while (fm2 != NULL && comp_fm_entry_ps(fm2, &tmp, NULL) == 0) { + if (fm_valid_for_font_replacement(fm2)) + return fm2; + fm2 = (fm_entry *) avl_t_prev(&t2); + } + + return NULL; +} + +/**********************************************************************/ +/* + * 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(integer t) +{ + process_map_item(makecstring(tokens_to_string(t)), MAPFILE); + flush_str(last_tokens_string); +} + +void pdfmapline(integer t) +{ + process_map_item(makecstring(tokens_to_string(t)), MAPLINE); + flush_str(last_tokens_string); +} + +void pdf_init_map_file(string 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 or ps_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; +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_fm_entry_tfm(void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_pslink(fm)) + delete_fm_entry(fm); + else + unset_tfmlink(fm); +} + +static void destroy_fm_entry_ps(void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_tfmlink(fm)) + delete_fm_entry(fm); + else + unset_pslink(fm); +} + +static void destroy_ff_entry(void *pa, void *pb) +{ + ff_entry *ff; + 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 (ps_tree != NULL) { + avl_destroy(ps_tree, destroy_fm_entry_ps); + ps_tree = NULL; + } + if (ff_tree != NULL) { + avl_destroy(ff_tree, destroy_ff_entry); + ff_tree = NULL; + } +} + +/**********************************************************************/ +/* end of mapfile.c */ diff --git a/Build/source/texk/web2c/luatexdir/font/pkin.c b/Build/source/texk/web2c/luatexdir/font/pkin.c new file mode 100644 index 00000000000..5067d6dbd66 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/pkin.c @@ -0,0 +1,439 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: pkin.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +/* + * 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>. + */ + +#include "ptexlib.h" + +/* + * Now we have some routines to get stuff from the pk file. pkbyte returns + * the next byte from the pk file. + */ + + +/* +static FILE *pkfile ; +*/ + +extern FILE *t3_file; +#define pkfile t3_file + +static shalfword pkbyte(void) +{ + register shalfword i; + + if ((i = xgetc(pkfile)) == EOF) + pdftex_fail("unexpected eof in pk file"); + return (i); +} + +static integer pkduo(void) +{ + register integer i; + + i = pkbyte(); + if (i > 127) + i -= 256; + i = i * 256 + pkbyte(); + return (i); +} + +static integer pktrio(void) +{ + register integer i; + + i = pkbyte(); + if (i > 127) + i -= 256; + i = i * 256 + pkbyte(); + i = i * 256 + pkbyte(); + return (i); +} + +static integer pkquad(void) +{ + register integer 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. + */ + +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 (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 *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 = pk_remainder; + pk_remainder = 0; + realfunc = pkpackednum; + return (i); + } + } else { + pdftex_fail("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. + */ + +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 integer i, j; + register halfword word, wordweight; + halfword *raster; + shalfword rowsleft; + boolean turnon; + shalfword hbit; + halfword count; + shalfword wordwidth; + + wordwidth = (cd->cwidth + 15) / 16; + i = 2 * cd->cheight * (long) wordwidth; + if (i <= 0) + i = 2; + if (i > cd->rastersize) { + xfree(cd->raster); + cd->rastersize = i; + cd->raster = xtalloc(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 = cd->cheight; + hbit = cd->cwidth; + repeatcount = 0; + wordweight = 16; + word = 0; + bitweight = 0; + while (rowsleft > 0) { + count = (*realfunc) (); +#ifdef DEBUG + if (turnon) + printf("(%d) ", (int) count); + else + printf("%d ", (int) count); +#endif + while (count != 0) { + if ((count < wordweight) && (count < hbit)) { + if (turnon) + word += gpower[wordweight] - gpower[wordweight - count]; + 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 -= repeatcount + 1; + repeatcount = 0; + word = 0; + wordweight = 16; + count -= hbit; + hbit = cd->cwidth; + } else { + if (turnon) + word += gpower[wordweight]; + *raster++ = word; + word = 0; + count -= wordweight; + hbit -= wordweight; + wordweight = 16; + } + } + turnon = !turnon; + } + if ((rowsleft != 0) || ((integer) hbit != cd->cwidth)) + pdftex_fail("error while unpacking; more bits than required"); + } +} + +/* + * readchar(): the main routine + * Reads the character definition of character `c' into `cd' if available, + * return FALSE (0) otherwise. + */ + +/* + * readchar(): the main routine + * check pk preamble if necessary, + * read the next character definition into `cd', + * return EOF if no character definition is available + */ + +int readchar(boolean check_preamble, chardesc * cd) +{ + register shalfword i; + register integer k; + register integer length = 0; + +/* + * Check the preamble of the pkfile + */ + if (check_preamble) { + if (pkbyte() != 247) + pdftex_fail("bad pk file, expected pre"); + if (pkbyte() != 89) + pdftex_fail("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 = (flagbyte & 3) * 65536L + pkbyte() * 256L; + length = 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 = 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) + pdftex_fail("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: + pdftex_fail("unexpected command (%i)", (int) flagbyte); + } + } + } + return 0; /* character not found */ +} diff --git a/Build/source/texk/web2c/luatexdir/font/sfnt.c b/Build/source/texk/web2c/luatexdir/font/sfnt.c new file mode 100644 index 00000000000..95453a531a0 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/sfnt.c @@ -0,0 +1,647 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/sfnt.c,v 1.12 2004/09/11 14:50:29 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +/* Based on dvipdfmx-0.13.2c */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H_ */ + +#include <string.h> + +#ifndef pdfTeX +#include "system.h" + +#include "error.h" +#include "mem.h" +#include "mfileio.h" +#else +extern void pdftex_fail (const char *fmt, ...); /* utils.c */ +#endif + +#include "sfnt.h" + +#ifdef XETEX +UNSIGNED_BYTE +ft_unsigned_byte(sfnt* f) +{ + unsigned char byte; + unsigned long length = 1; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, &byte, &length) != 0) + TT_ERROR("sfnt: Freetype failure..."); + f->loc += 1; + + return byte; +} + +SIGNED_BYTE +ft_signed_byte(sfnt* f) +{ + int b = ft_unsigned_byte(f); + if (b >= 0x80) + b -= 0x100; + return (SIGNED_BYTE)b; +} + +UNSIGNED_PAIR +ft_unsigned_pair(sfnt* f) +{ + unsigned char buf[2]; + unsigned long length = 2; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + TT_ERROR("sfnt: Freetype failure..."); + f->loc += 2; + + return (UNSIGNED_PAIR)((unsigned)buf[0] << 8) + buf[1]; +} + +SIGNED_PAIR +ft_signed_pair(sfnt* f) +{ + int p = ft_unsigned_pair(f); + if (p >= 0x8000U) + p -= 0x10000U; + + return (SIGNED_PAIR)p; +} + +UNSIGNED_QUAD +ft_unsigned_quad(sfnt* f) +{ + unsigned char buf[4]; + unsigned long length = 4; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + TT_ERROR("sfnt: Freetype failure..."); + f->loc += 4; + + return ((unsigned long)buf[0] << 24) + ((unsigned long)buf[1] << 16) + + ((unsigned long)buf[2] << 8) + (unsigned long)buf[3]; +} + +unsigned long +ft_read(unsigned char* buf, unsigned long len, sfnt* f) +{ + unsigned long length = len; + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + TT_ERROR("sfnt: Freetype failure..."); + f->loc += len; + + return length; +} +#endif + + +/* + * 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 +*/ +#define SFNT_TRUETYPE 0x00010000UL +#define SFNT_MAC_TRUE 0x74727565UL +#define SFNT_OPENTYPE 0x00010000UL +#define SFNT_POSTSCRIPT 0x4f54544fUL +#define SFNT_TTC 0x74746366UL + +#ifdef XETEX +sfnt * +sfnt_open (FT_Face face, int accept_types) +{ + sfnt *sfont; + ULONG type; + + if (!face || !FT_IS_SFNT(face)) + return NULL; + + sfont = NEW(1, sfnt); + sfont->ft_face = face; + sfont->loc = 0; + sfont->type = 0; + + 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; + } + + if ((sfont->type & accept_types) == 0) { + RELEASE(sfont); + return NULL; + } + + sfont->loc = 0; + + sfont->directory = NULL; + + return sfont; +} +#else /* not XETEX */ +#ifdef pdfTeX +sfnt * +sfnt_open (unsigned char *buffer, integer buflen) +{ + sfnt *sfont; + ULONG type; + + sfont = xmalloc(sizeof(sfnt)); + sfont->loc = 0; + sfont->buffer = buffer; + 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; +} +#else +sfnt * +sfnt_open (FILE *fp) +{ + sfnt *sfont; + ULONG type; + + ASSERT(fp); + + rewind(fp); + + sfont = NEW(1, sfnt); + + sfont->stream = fp; + + 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; + } + + rewind(sfont->stream); + + sfont->directory = NULL; + + return sfont; +} +#endif +#endif + +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. + */ +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 + */ +static unsigned +max2floor (unsigned n) +{ + int val = 1; + + while (n > 1) { + n /= 2; + val *= 2; + } + + return val; +} + +/* + * 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; + int count = 0; + + p = (BYTE *) data; + endptr = p + length; + while (p < endptr) { + chksum += (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; + + 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; +} + +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; +} + +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; +} + +ULONG +sfnt_locate_table (sfnt *sfont, const char *tag) +{ + ULONG offset; + + ASSERT(sfont && tag); + + offset = sfnt_find_table_pos(sfont, tag); + if (offset == 0) + TT_ERROR("sfnt: table not found..."); + + sfnt_seek_set(sfont, offset); + + return offset; +} + +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); + +#ifdef XETEX + ASSERT(sfont->ft_face); +#elif defined(pdfTeX) + ASSERT(sfont->buffer); +#else + ASSERT(sfont->stream); +#endif + + sfnt_seek_set(sfont, 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; + + 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; +} + +#ifndef pdfTeX +#include "pdfobj.h" +#endif + +/* + * o All tables begin on four byte boundries, and pad any remaining space + * between tables with zeros + * + * o Entries in the Table Directory must be sorted in ascending order by tag + * + * o 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. + */ + +#ifdef pdfTeX +extern pdf_obj *pdf_new_stream(void); +extern void pdf_add_stream(pdf_obj *, unsigned char *, long); +extern void pdf_release_obj(pdf_obj *); +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define STREAM_COMPRESS +#endif + +static unsigned char wbuf[1024], padbytes[4] = {0, 0, 0, 0}; + +pdf_obj * +sfnt_create_FontFile_stream (sfnt *sfont) +{ + pdf_obj *stream; +#ifndef pdfTeX + pdf_obj *stream_dict; +#endif + 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, td->version); + p += sfnt_put_ushort(p, td->num_kept_tables); + sr = 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, td->tables[i].check_sum); + p += sfnt_put_ulong(p, offset); + p += sfnt_put_ulong(p, td->tables[i].length); + pdf_add_stream(stream, wbuf, 16); + + offset += 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) { +#ifdef XETEX + if (!sfont->ft_face) +#elif defined(pdfTeX) + if (!sfont->buffer) +#else + if (!sfont->stream) +#endif + { + pdf_release_obj(stream); + TT_ERROR("Font file not opened or already closed..."); + return NULL; + } + + length = td->tables[i].length; + sfnt_seek_set(sfont, td->tables[i].offset); + while (length > 0) { + nb_read = sfnt_read(wbuf, MIN(length, 1024), sfont); + if (nb_read < 0) { + pdf_release_obj(stream); + TT_ERROR("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, + td->tables[i].length); + RELEASE(td->tables[i].data); + td->tables[i].data = NULL; + } + /* Set offset for next table */ + offset += td->tables[i].length; + } + } + +#ifndef pdfTeX + stream_dict = pdf_stream_dict(stream); + pdf_add_dict(stream_dict, + pdf_new_name("Length1"), + pdf_new_number(offset)); +#endif + return stream; +} diff --git a/Build/source/texk/web2c/luatexdir/font/sfnt.h b/Build/source/texk/web2c/luatexdir/font/sfnt.h new file mode 100644 index 00000000000..8db54dd9c39 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/sfnt.h @@ -0,0 +1,197 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/sfnt.h,v 1.9 2004/09/11 14:50:29 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef _SFNT_H_ +#define _SFNT_H_ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H_ */ + +#ifndef pdfTeX +#include "mfileio.h" +#include "numbers.h" +#include "pdfobj.h" +#endif + +#ifdef XETEX +#include "ft2build.h" +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H +#endif + +/* Data Types as described in Apple's TTRefMan */ +typedef unsigned char BYTE; +typedef signed char ICHAR; +typedef unsigned short USHORT; +typedef signed short SHORT; +typedef unsigned long ULONG; +typedef signed long LONG; +typedef unsigned long Fixed; /* 16.16-bit signed fixed-point number */ +typedef short FWord; +typedef unsigned short uFWord; +typedef short F2Dot14; /* 16-bit signed fixed number with the low + 14 bits representing fraction. */ + +struct sfnt_table +{ + /* table header */ + char tag[4]; + ULONG check_sum; + ULONG offset; + ULONG length; + char *data; /* table data */ +}; + +#define SFNT_TABLE_REQUIRED (1 << 0) + +struct sfnt_table_directory +{ + ULONG version; /* Fixed for Win */ + USHORT num_tables; + USHORT search_range; + USHORT entry_selector; + USHORT range_shift; + USHORT num_kept_tables; /* number of kept tables */ + char *flags; /* keep or omit */ + struct sfnt_table *tables; +}; + +/* sfnt resource */ +#define SFNT_TYPE_TRUETYPE (1 << 0) +#define SFNT_TYPE_OPENTYPE (1 << 1) +#define SFNT_TYPE_POSTSCRIPT (1 << 2) +#define SFNT_TYPE_TTC (1 << 4) + +typedef struct +{ + int type; + struct sfnt_table_directory *directory; +#ifdef XETEX + FT_Face ft_face; + long loc; +#elif defined(pdfTeX) + BYTE *buffer; + long buflen; + long loc; +#else + FILE *stream; +#endif +} sfnt; + +/* Convert sfnt "fixed" type to double */ +#define fixed(a) ((double)((a)%0x10000L)/(double)(0x10000L) + \ + (a)/0x10000L - (((a)/0x10000L > 0x7fffL) ? 0x10000L : 0)) + +#ifdef XETEX +UNSIGNED_BYTE ft_unsigned_byte(sfnt* f); +SIGNED_BYTE ft_signed_byte(sfnt* f); +UNSIGNED_PAIR ft_unsigned_pair(sfnt* f); +SIGNED_PAIR ft_signed_pair(sfnt* f); +UNSIGNED_QUAD ft_unsigned_quad(sfnt* f); +unsigned long ft_read(unsigned char* buf, unsigned long len, sfnt* f); + +#define sfnt_get_byte(s) ((BYTE) ft_unsigned_byte(s)) +#define sfnt_get_char(s) ((ICHAR) ft_signed_byte (s)) +#define sfnt_get_ushort(s) ((USHORT) ft_unsigned_pair(s)) +#define sfnt_get_short(s) ((SHORT) ft_signed_pair (s)) +#define sfnt_get_ulong(s) ((ULONG) ft_unsigned_quad(s)) +#define sfnt_get_long(s) ((LONG) ft_signed_quad (s)) + +#define sfnt_seek_set(s,o) (s)->loc = (o) +#define sfnt_read(b,l,s) ft_read((b), (l), (s)) +#elif defined(pdfTeX) +BYTE get_unsigned_byte(sfnt* f); +ICHAR get_signed_byte(sfnt* f); +USHORT get_unsigned_pair(sfnt* f); +SHORT get_signed_pair(sfnt* f); +ULONG get_unsigned_quad(sfnt* f); +int do_sfnt_read (unsigned char *dest, int len, sfnt *f); + +#define sfnt_get_byte(s) ((BYTE) get_unsigned_byte(s)) +#define sfnt_get_char(s) ((ICHAR) get_signed_byte (s)) +#define sfnt_get_ushort(s) ((USHORT) get_unsigned_pair(s)) +#define sfnt_get_short(s) ((SHORT) get_signed_pair (s)) +#define sfnt_get_ulong(s) ((ULONG) get_unsigned_quad(s)) +#define sfnt_get_long(s) ((LONG) get_signed_quad (s)) + +#define sfnt_seek_set(s,o) (s)->loc = (o) +#define sfnt_read(b,l,s) do_sfnt_read((b), (l), (s)) +#else +/* get_***_*** from numbers.h */ +#define sfnt_get_byte(s) ((BYTE) get_unsigned_byte((s)->stream)) +#define sfnt_get_char(s) ((ICHAR) get_signed_byte ((s)->stream)) +#define sfnt_get_ushort(s) ((USHORT) get_unsigned_pair((s)->stream)) +#define sfnt_get_short(s) ((SHORT) get_signed_pair ((s)->stream)) +#define sfnt_get_ulong(s) ((ULONG) get_unsigned_quad((s)->stream)) +#define sfnt_get_long(s) ((LONG) get_signed_quad ((s)->stream)) + +#define sfnt_seek_set(s,o) seek_absolute((s)->stream, (o)) +#define sfnt_read(b,l,s) fread((b), 1, (l), (s)->stream) +#endif + +extern int put_big_endian (void *s, LONG q, int n); + +#define sfnt_put_ushort(s,v) put_big_endian((s), v, 2); +#define sfnt_put_short(s,v) put_big_endian((s), v, 2); +#define sfnt_put_ulong(s,v) put_big_endian((s), v, 4); +#define sfnt_put_long(s,v) put_big_endian((s), v, 4); + +#ifdef XETEX +extern sfnt *sfnt_open (FT_Face face, int accept_types); +#elif defined(pdfTeX) +extern sfnt *sfnt_open (unsigned char *buffer, integer buflen); +#else +extern sfnt *sfnt_open (FILE *fp); +#endif +extern void sfnt_close (sfnt *sfont); + +/* table directory */ +extern int sfnt_read_table_directory (sfnt *sfont, ULONG offset); +extern ULONG sfnt_find_table_len (sfnt *sfont, const char *tag); +extern ULONG sfnt_find_table_pos (sfnt *sfont, const char *tag); +extern ULONG sfnt_locate_table (sfnt *sfont, const char *tag); + +extern void sfnt_set_table (sfnt *sfont, + const char *tag, void *data, ULONG length); +extern int sfnt_require_table (sfnt *sfont, const char *tag, int must_exist); + +#ifdef pdfTeX +typedef struct +{ + ULONG length; + BYTE *data; +} pdf_obj; + +#define ASSERT(a) assert(a) +#define RELEASE(a) free(a) +#define NEW(a,b) xmalloc((a)*sizeof(b)) +#define RENEW(a,b,c) xrealloc(a, ((b)*sizeof(c))) +#define TT_ERROR pdftex_fail +#define WARN printf + + +#endif + +extern pdf_obj *sfnt_create_FontFile_stream (sfnt *sfont); + +#endif /* _SFNT_H_ */ diff --git a/Build/source/texk/web2c/luatexdir/font/subfont.c b/Build/source/texk/web2c/luatexdir/font/subfont.c new file mode 100644 index 00000000000..836985c10fd --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/subfont.c @@ -0,0 +1,264 @@ +/* +Copyright (c) 2005-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ptexlib.h" +#include <string.h> + +static struct avl_table *sfd_tree = NULL; + +static unsigned char *sfd_buffer = NULL; +static integer sfd_size = 0; +static integer sfd_curbyte = 0; + +#define SFD_BUF_SIZE SMALL_BUF_SIZE + +#define sfd_close() xfclose(sfd_file, cur_file_name) +#define sfd_open() open_input(&sfd_file, kpse_sfd_format, 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; + 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) +{ + 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; + int c; + restart: + if (sfd_eof ()) { + if (expect_eof) + return; + else + pdftex_fail ("unexpected end of file"); + } + p = sfd_line; + do { + c = 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 *ftemp = NULL; + 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; + set_cur_file_name (sfd_name); + if (sfd_buffer!=NULL) { + xfree(sfd_buffer); + sfd_buffer=NULL; + } + sfd_curbyte=0; + sfd_size=0; + + callback_id=callback_defined(find_sfd_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",cur_file_name,&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + if (cur_file_name) + free(cur_file_name); + cur_file_name = xstrdup(ftemp); + free(ftemp); + } + } + } + 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 ) ) { + pdftex_warn ("cannot open SFD file for reading"); + cur_file_name = NULL; + return NULL; + } + sfd_read_file(); + sfd_close(); + } + tex_printf ("{"); + tex_printf (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) + pdftex_fail ("invalid token:\n%s", p); + p += n; + if (*p == ':') { /* offset */ + k = i; + p++; + } else if (*p == '_') { /* range */ + if (sscanf (p + 1, " %li %n", &j, &n) == 0) + pdftex_fail ("invalid token:\n%s", p); + if (i > j || k + (j - i) > 255) + pdftex_fail ("invalid range:\n%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; +} + +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 != strlen (p) - 1) /* or the second '@' is not the last char yet */ + return false; + l = 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); + fm->ps_name = NULL; + /* set default values for PidEid */ + if (fm->pid == -1) { + fm->pid = 3; + fm->eid = 1; + } + l = 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; +} diff --git a/Build/source/texk/web2c/luatexdir/font/subfont.txt b/Build/source/texk/web2c/luatexdir/font/subfont.txt new file mode 100644 index 00000000000..9fe053cbb9c --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/subfont.txt @@ -0,0 +1,74 @@ +map entry: + +cyberb@Unicode@ <cyberbit.ttf PidEid=3,1 + +means + +cyberb<INFIX> => look at Unicode.sfd => find the mapping => charcode + => PidEid=3,1 => glyphs + +eg cyberb01 => subfont 01 in Unicode.sfd => charcodes + +Infix can be anything, thus the question: given a tfm name, how to find out +whether this is a subfont? + +It is safe to limit the infix to be composed from hexadecimal digits only? + +If so, one possibility is: + +(1) +while last-char-of-tfmname is a hexdigit do + remove the last char from tfmname + do a lookup for the tfmname + if found an entry with subfont flag then + break +enddo + +(2) +Or, when a map entry with subfont flag is scanned, let pdftex create all +the relevant entries. Which may be a safer and faster solution (but wastes more +memory) + + +Let's do (2), as infix can be any word. + + + +Implementation: + +- let's have a map entry: + +cyberb@Unicode@ <cyberbit.ttf PidEid=3,1 + +- actions: + - read Unicode.sfd + - create corresponding sfd mapping like ("01", "Unicode") => long[256] + - added those subfont to an AVL tree + - create map entries for cyberb01--cyberbff, each has a pointer to the + corresponding sfd mapping entry + +- extended attributes for map entry: + - Pid + - Eid + - sfd_map + +- sfd_mapping: + - name: sfd name, eg "Unicode" + - infix, eg "01" + - mapping: long[256] + +- how to find out whether a sfd has been loaded: + - lookup for any entry with the given sfd name + +- functions: + - load_sfd + - lookup_subfont + - extend reading map entries + +- when writting ttf: + - if re-encoded --> process like in case of type1 fonts + - if PidEid is being used: + - read cmap tables: store (ttfname, pid, eid) + - search for used chars + - use sfd to find the charcodes + - look into cmap to diff --git a/Build/source/texk/web2c/luatexdir/font/texfont.c b/Build/source/texk/web2c/luatexdir/font/texfont.c new file mode 100644 index 00000000000..150c2cba769 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/texfont.c @@ -0,0 +1,1094 @@ +/* + Copyright (c) 1996-2006 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LuaTeX; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + $Id: texfont.c 1013 2008-02-14 00:09:02Z oneiros $ */ + +/* Main font API implementation for the pascal parts */ + +/* stuff to watch out for: + * + * - 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. + * + * - 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. + */ + +#include "ptexlib.h" +#include "luatex-api.h" + +#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f)) +#define dxfree(a,b) { xfree(a); a = b ; } +#define do_realloc(a,b,d) a = xrealloc(a,(b)*sizeof(d)) + +texfont **font_tables = NULL; + +static integer font_arr_max = 0; +static integer font_id_maxval = 0; + +static void grow_font_table (integer id) { + int j; + if (id>=font_arr_max) { + font_bytes += (font_arr_max-id+8)*sizeof(texfont *); + font_tables = xrealloc(font_tables,(id+8)*sizeof(texfont *)); + j = 8; + while (j--) { + font_tables[id+j] = NULL; + } + font_arr_max = id+8; + } +} + +integer +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; +} + +integer +max_font_id (void) { + return font_id_maxval; +} + +void +set_max_font_id (integer i) { + font_id_maxval = i; +} + +integer +new_font (void) { + int k; + int id; + charinfo *ci; + id = new_font_id(); + font_bytes += 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_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; + + set_font_bc(id, 1); /* ec = 0 */ + set_hyphen_char(id,'-'); + set_skew_char(id,-1); + + /* 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, 0); /* 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_cache = NULL; + + return id; +} + +#define Charinfo_count(a) font_tables[a]->charinfo_count +#define Charinfo_size(a) font_tables[a]->charinfo_size +#define Characters(a) font_tables[a]->characters + +charinfo * +get_charinfo (internal_font_number f, integer c) { + sa_tree_item glyph; + charinfo *ci; + if (proper_char_index(c)) { + glyph = get_sa_item(Characters(f), c); + if (!glyph) { + /* this could be optimized using controlled growth */ + font_bytes += sizeof(charinfo); + glyph = ++font_tables[f]->charinfo_count; + do_realloc(font_tables[f]->charinfo, (glyph+1), charinfo); + memset (&(font_tables[f]->charinfo[glyph]),0,sizeof(charinfo)); + font_tables[f]->charinfo[glyph].ef = 1000; /* init */ + font_tables[f]->charinfo_size = glyph; + set_sa_item(font_tables[f]->characters, c, glyph, 1); /* 1= global */ + } + return &(font_tables[f]->charinfo[glyph]); + } else if (c == left_boundarychar) { + if (left_boundary(f)==NULL) { + ci = xcalloc(1,sizeof(charinfo)); + font_bytes += 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 += sizeof(charinfo); + set_right_boundary(f,ci); + } + return right_boundary(f); + } + return &(font_tables[f]->charinfo[0]); +} + +void +set_charinfo (internal_font_number f, integer c, charinfo *ci) { + sa_tree_item glyph; + if (proper_char_index(c)) { + glyph = get_sa_item(Characters(f), c); + if (glyph) { + font_tables[f]->charinfo[glyph] = *ci; + } else { + pdftex_fail("font: %s","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; + kerninfo *kern; + liginfo *lig; + real_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->extensible = 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 (x*sizeof(kerninfo)); + memcpy(co->kerns,ci->kerns,(x*sizeof(kerninfo))); + } + /* ligs */ + if ((lig = get_charinfo_ligatures(ci)) != NULL) { + x = 0; + while (!lig_end(lig[x])) { x++; } x++; + co->ligatures = xmalloc (x*sizeof(liginfo)); + memcpy(co->ligatures,ci->ligatures,(x*sizeof(liginfo))); + } + /* packets */ + if ((packet = get_charinfo_packets(ci)) != NULL) { + x = vf_packet_bytes(ci); + co->packets = xmalloc (x); + memcpy(co->packets,ci->packets,x); + } + if (get_charinfo_tag(ci)==ext_tag) { + int top, bot, rep, mid; + top = get_charinfo_extensible(ci,EXT_TOP); + bot = get_charinfo_extensible(ci,EXT_BOT); + mid = get_charinfo_extensible(ci,EXT_MID); + rep = get_charinfo_extensible(ci,EXT_REP); + set_charinfo_extensible(co,top,bot,mid,rep); + } + return co; +} + +#if 0 +int +find_charinfo_id (internal_font_number f, integer c) { + register int g=0; + if (font_tables[f]->charinfo_cache==NULL) { + int i = (font_ec(f)+1)*sizeof(int); + font_tables[f]->charinfo_cache = xmalloc(i); + memset(font_tables[f]->charinfo_cache,0,i); + } else { + g = font_tables[f]->charinfo_cache[c]; + } + if (g==0) { + g = get_sa_item(font_tables[f]->characters, c); + font_tables[f]->charinfo_cache[c] = g; + } + return g; +} +#else +#define find_charinfo_id(f,c) get_sa_item(font_tables[f]->characters,c) +#endif + + +charinfo * +char_info (internal_font_number f, integer c) { + if (f>font_id_maxval) + return 0; + if (proper_char_index(c)) { + register int glyph = 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]); +} + +charinfo_short +char_info_short (internal_font_number f, integer c) { + charinfo_short s; + charinfo *i; + i = char_info(f,c); + s.ci_wd = i->width; + s.ci_dp = i->depth; + s.ci_ht = i->height; + return s; +} + +integer +char_exists (internal_font_number f, integer c) { + if (f>font_id_maxval) + return 0; + if (proper_char_index(c)) { + return 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_char_exists_callback (internal_font_number f, integer c) { + integer callback_id ; + lua_State *L = Luas[0]; + int ret=0; + callback_id = callback_defined(char_exists_callback); + if (callback_id!=0) { + lua_rawgeti(L,LUA_REGISTRYINDEX,callback_callbacks_id); + lua_rawgeti(L,-1, callback_id); + if (!lua_isfunction(L,-1)) { + lua_pop(L,2); + return 0; + } + lua_pushnumber(L,f); + lua_pushnumber(L,c); + if (lua_pcall(L,2,1,0) != 0) { /* two args, 1 result */ + fprintf(stdout,"error: %s\n",lua_tostring(L,-1)); + lua_pop(L,2); + error(); + } else { + ret = lua_toboolean(L,-1); + } + } + return ret; +} + + +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_tag (charinfo *ci, scaled val) { ci->tag = val; } +void set_charinfo_remainder (charinfo *ci, scaled val) { ci->remainder = val; } +void set_charinfo_used (charinfo *ci, scaled val) { ci->used = val; } +void set_charinfo_index (charinfo *ci, scaled val) { ci->index = val; } +void set_charinfo_name (charinfo *ci, char *val) { dxfree(ci->name,val); } +void set_charinfo_tounicode (charinfo *ci, char *val) { dxfree(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, real_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_extensible (charinfo *ci, int top, int bot, int mid, int rep) { + if (top == 0 && bot == 0 && mid == 0 && rep == 0) { + if (ci->extensible != NULL) { + free(ci->extensible); + ci->extensible = NULL; + } + } else { + if (ci->extensible == NULL) { + ci->extensible = xmalloc(4*sizeof(integer)); + } + ci->extensible[EXT_TOP] = top; + ci->extensible[EXT_BOT] = bot; + ci->extensible[EXT_MID] = mid; + ci->extensible[EXT_REP] = rep; + } +} + +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; } +char get_charinfo_tag (charinfo *ci) { return ci->tag; } +integer get_charinfo_remainder (charinfo *ci) { return ci->remainder; } +char get_charinfo_used (charinfo *ci) { return ci->used; } +integer 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; } +real_eight_bits *get_charinfo_packets (charinfo *ci) { return ci->packets; } +integer get_charinfo_ef (charinfo *ci) { return ci->ef; } +integer get_charinfo_rp (charinfo *ci) { return ci->rp; } +integer get_charinfo_lp (charinfo *ci) { return ci->lp; } + +integer get_charinfo_extensible (charinfo *ci, int whch) { + int w = 0; + if (ci->extensible != NULL) + w = ci->extensible[whch]; + return w; +} + +integer ext_top (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + integer w = get_charinfo_extensible(ci,EXT_TOP); + /* fprintf(stdout,"top of char 0x%4x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} + +integer ext_bot (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + integer w = get_charinfo_extensible(ci,EXT_BOT); + /*fprintf(stdout,"bot of char 0x%4x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} +integer ext_mid (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + integer w = get_charinfo_extensible(ci,EXT_MID); + /*fprintf(stdout,"mid of char 0x%4x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} +integer ext_rep (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + integer w = get_charinfo_extensible(ci,EXT_REP); + /*fprintf(stdout,"rep of char 0x%4x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} + +scaled char_width (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + scaled w = get_charinfo_width(ci); + /*fprintf(stdout,"width of char 0x%x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} + +scaled char_depth (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + scaled w = get_charinfo_depth(ci); + /*fprintf(stdout,"depth of char 0x%x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} + +scaled char_height (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + scaled w = get_charinfo_height(ci); + /*fprintf(stdout,"height of char 0x%x in font %s: %i\n",c,font_name(f),w);*/ + return w; +} + +scaled char_italic (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_italic(ci); +} + +integer char_remainder (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_remainder(ci); +} + +char char_tag (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_tag(ci); +} + +char char_used (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_used(ci); +} + +char *char_name (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_name(ci); +} + +integer char_index (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_index(ci); +} + +liginfo * char_ligatures (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_ligatures(ci); +} + +kerninfo * char_kerns (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_kerns(ci); +} + +real_eight_bits * char_packets (internal_font_number f, integer 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 += (b-font_params(f))*sizeof(scaled); + do_realloc(param_base(f), (b+1), integer); + font_params(f) = b; + if (b>i) { + while (i<b) { + i++; + set_font_param(f,i,0); + } + } + } +} + + +integer +copy_font (integer f) { + int i; + charinfo *ci , *co; + integer k = new_font(); + memcpy(font_tables[k],font_tables[f],sizeof(texfont)); + + 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_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_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 = sizeof(*param_base(f))*font_params(f); + font_bytes += i; + param_base(k) = xmalloc (i); + memcpy(param_base(k),param_base(f), i); + + i = sizeof(charinfo)*(Charinfo_size(f)+1); + font_bytes += i; + font_tables[k]->charinfo = xmalloc(i); + memset(font_tables[k]->charinfo,0,i); + for(i=0;i<=Charinfo_size(k);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); + } + return k; +} + +void delete_font (integer 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_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 (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_extensible(co,0,0,0,0); + } + } + /* 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)); + 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 (integer id) { + int ret=0; + if (id>=0 && id<=font_id_maxval && font_tables[id]!=NULL) + ret=1; + return ret; +} + +/* return 1 == identical */ +boolean +cmp_font_name (integer id, strnumber t) { + char *tid , *tt; + if (!is_valid_font(id)) + return 0; + tt = makecstring(t); + tid = font_name(id); + if (tt == NULL && tid == NULL) + return 1; + if (tt == NULL || tid == NULL || strcmp(tid,tt)!=0) + return 0; + return 1; +} + +boolean +cmp_font_area (integer id, strnumber 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; + return 1; +} + + +static boolean +same_font_name (integer id, integer t) { + int ret = 0; + if (font_name(t) == NULL || + font_name(id) == NULL || + strcmp(font_name(t),font_name(id))!=0) { + ; + } else { + ret =1 ; + } + return ret; +} + +boolean +font_shareable (internal_font_number f, internal_font_number k) { + int ret = 0; + if (font_cidregistry(f) == NULL) { + if ( hasfmentry ( k ) + && ( font_map ( k ) == font_map ( f ) ) + && ( same_font_name ( k , f ) + || + ( pdf_font_auto_expand (f) + && ( pdf_font_blink (f) != 0 ) /* 0 = nullfont */ + && same_font_name ( k , pdf_font_blink (f) ) ) ) ) { + ret = 1; + } + } else { + if ((font_filename(k) != NULL && font_filename(f) != NULL && + strcmp(font_filename(k),font_filename(f)) == 0) + || + ( pdf_font_auto_expand (f) + && ( pdf_font_blink (f) != 0 ) /* 0 = nullfont */ + && same_font_name ( k , pdf_font_blink (f) ) ) ) { + ret = 1; + } + } + return ret; +} + +integer +test_no_ligatures (internal_font_number f) { + integer c; + for (c=font_bc(f);c<=font_ec(f);c++) { + if (has_lig(f,c)) /* char_exists(f,c) */ + return 0; + } + return 1; +} + +integer +get_tag_code (internal_font_number f, integer 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; +} + +integer +get_lp_code (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_lp(ci); +} + +integer +get_rp_code (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_rp(ci); +} + +integer +get_ef_code (internal_font_number f, integer c) { + charinfo *ci = char_info(f,c); + return get_charinfo_ef(ci); +} + +void +set_tag_code (internal_font_number f, integer c, integer i) { + integer 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); + } + } +} + + +void +set_lp_code(internal_font_number f, integer c, integer 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, integer c, integer 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, integer c, integer 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) { + integer 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; +} + +liginfo +get_ligature (internal_font_number f, integer lc, integer rc) { + 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; + k = 0; + 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 +get_kern(internal_font_number f, integer lc, integer rc) +{ + integer k; + kerninfo u; + charinfo * co; + if (lc == non_boundarychar || rc == non_boundarychar || (!has_kern(f,lc)) ) + return 0; + k = 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; +} + + +/* dumping and undumping fonts */ + +#define dump_string(a) \ + if (a!=NULL) { \ + x = strlen(a)+1; \ + dump_int(x); dump_things(*a, x); \ + } else { \ + x = 0; dump_int(x); \ + } + +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_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) { + x = get_charinfo_extensible(co,EXT_TOP); dump_int(x); + x = get_charinfo_extensible(co,EXT_BOT); dump_int(x); + x = get_charinfo_extensible(co,EXT_MID); dump_int(x); + x = get_charinfo_extensible(co,EXT_REP); dump_int(x); + } +} + +void +dump_font (int f) { + int i,x; + + set_font_used(f,0); + font_tables[f]->charinfo_cache = NULL; + dump_things(*(font_tables[f]), 1); + dump_string(font_name(f)); + dump_string(font_area(f)); + dump_string(font_filename(f)); + dump_string(font_fullname(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 (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 (char_exists(f,i)) { + dump_charinfo(f,i); + } + } +} + +int +undump_charinfo (int f) { + charinfo *co; + int x,i; + char *s = NULL; + liginfo *lig = NULL; + kerninfo *kern = NULL; + real_eight_bits *packet = NULL; + int top = 0, bot = 0, mid = 0, rep = 0; + + 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_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(x); + undump_things(*s,x); + } + set_charinfo_name(co,s); + + /* tounicode */ + undump_int (x); + if (x>0) { + font_bytes += x; + s = xmalloc(x); + undump_things(*s,x); + } + set_charinfo_tounicode(co,s); + + /* ligatures */ + undump_int (x); + if (x>0) { + font_bytes += x*sizeof(liginfo); + lig = xmalloc(x*sizeof(liginfo)); + undump_things(*lig,x); + } + set_charinfo_ligatures(co,lig); + + /* kerns */ + undump_int (x); + if (x>0) { + font_bytes += x*sizeof(kerninfo); + kern = xmalloc(x*sizeof(kerninfo)); + undump_things(*kern,x); + } + set_charinfo_kerns(co,kern); + + /* packets */ + undump_int (x); + if (x>0) { + font_bytes += x; + packet = xmalloc(x); + undump_things(*packet,x); + } + set_charinfo_packets(co,packet); + + if (get_charinfo_tag(co)==ext_tag) { + undump_int(top); + undump_int(bot); + undump_int(mid); + undump_int(rep); + set_charinfo_extensible(co,top,bot,mid,rep); + } + return i; +} + +#define undump_font_string(a) undump_int (x); \ + if (x>0) { \ + font_bytes += x; \ + s = xmalloc(x); undump_things(*s,x); \ + a(f,s); } + + +void +undump_font(int f) +{ + int x, i; + texfont *tt; + charinfo *ci; + char *s; + grow_font_table (f); + font_tables[f] = NULL; + font_bytes += sizeof(texfont); + tt = xmalloc(sizeof(texfont)); + undump_things(*tt,1); + 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_encodingname); + undump_font_string(set_font_cidregistry); + undump_font_string(set_font_cidordering); + + i = sizeof(*param_base(f))*(font_params(f)+1); + font_bytes += i; + param_base(f) = xmalloc (i); + undump_things(*param_base(f), (font_params(f)+1)); + + font_tables[f]->_left_boundary = NULL; + undump_int(x); + if (x) { i = undump_charinfo(f); } /* left boundary */ + + font_tables[f]->_right_boundary = NULL; + undump_int(x); + if (x) { i = undump_charinfo(f); } /* right boundary */ + + + font_tables[f]->characters = new_sa_tree(1, 0); /* stack size 1, default item value 0 */ + ci = xcalloc(1,sizeof(charinfo)); + set_charinfo_name(ci,xstrdup(".notdef")); + font_tables[f]->charinfo = ci; + + i = font_bc(f); + while(i<font_ec(f)) { + i = undump_charinfo(f); + } +} + diff --git a/Build/source/texk/web2c/luatexdir/font/texfont.h b/Build/source/texk/web2c/luatexdir/font/texfont.h new file mode 100644 index 00000000000..21b79f1e876 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/texfont.h @@ -0,0 +1,524 @@ +/* + Copyright (c) 1996-2006 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LuaTeX; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + $Id: texfont.h 1117 2008-03-21 15:26:12Z hhenkel $ */ + +/* Here we have the interface to LuaTeX's font system, as seen from the + main pascal program. There is a companion list in luatex.defines to + keep web2c happy */ + +/* this file is read at the end of ptexlib.h, which is called for at + the end of luatexcoerce.h, as well as from the C sources +*/ + +#ifndef TEXFONT_H +#define TEXFONT_H 1 + +#include "luatexdir/managed-sa.h" + +#define pointer halfword + +typedef struct liginfo { + integer adj; + integer lig; + char type; +} liginfo; + +typedef struct kerninfo { + integer adj; + scaled sc; +} kerninfo; + +typedef struct charinfo { + char *name; /* postscript character name */ + liginfo *ligatures; /* ligature items */ + kerninfo *kerns; /* kern items */ + real_eight_bits *packets; /* virtual commands. */ + integer *extensible; /* extensible recipe (if any) */ + unsigned short index; /* CID index */ + integer remainder; /* spare value for odd items, could be union-ed with extensible */ + scaled width; /* width */ + scaled height; /* height */ + scaled depth; /* depth */ + scaled italic; /* italic correction */ + integer ef; /* font expansion factor */ + integer lp; /* left protruding factor */ + integer rp; /* right protruding factor */ + char tag ; /* list / ext taginfo */ + char used ; /* char is typeset ? */ + char *tounicode; /* unicode equivalent */ +} charinfo; + + +/* this is for speed reasons, it is called from the web source + when more than two of the traditional four char values are needed + at the same time. the structure |charinfo_short| is defined in + web */ + +#ifndef luaTeX +typedef struct charinfo_short { + scaled ci_wd; /* width */ + scaled ci_ht; /* height */ + scaled ci_dp; /* depth */ +} charinfo_short; +#endif + + +extern charinfo_short char_info_short (internal_font_number f, integer c); + + + +typedef struct texfont { + integer _font_size ; + integer _font_dsize ; + char * _font_name ; + char * _font_area ; + char * _font_filename ; + char * _font_fullname ; + char * _font_encodingname ; + char * _font_cidregistry ; + char * _font_cidordering ; + integer _font_cidversion ; + integer _font_cidsupplement ; + + integer _font_ec ; + integer _font_checksum ; /* internal information */ + char _font_used ; /* internal information */ + char _font_touched ; /* internal information */ + integer _font_cache_id ; /* internal information */ + char _font_encodingbytes ; /* 1 or 2 bytes */ + integer _font_slant ; /* a slant in ppt */ + integer _font_extend ; /* an extension in ppt, or 0 */ + char _font_tounicode ; /* 1 if info is present */ + fm_entry_ptr _font_map; + integer _font_type; + integer _font_format; + integer _font_embedding; + integer _font_bc ; + integer _hyphen_char ; + integer _skew_char ; + integer _font_natural_dir; + + charinfo *_left_boundary; + charinfo *_right_boundary; + + integer _font_params; + scaled *_param_base; + + sa_tree characters; + integer charinfo_count; + integer charinfo_size; + charinfo *charinfo; + int *charinfo_cache; + integer ligatures_disabled; + + integer _pdf_font_num; /* maps to a PDF resource ID */ + scaled _pdf_font_size; /* maps to a PDF font size */ + internal_font_number _pdf_font_blink; /* link to base font for expanded fonts */ + internal_font_number _pdf_font_elink; /* link to expanded fonts for base font */ + integer _pdf_font_expand_ratio; /* expansion ratio of a particular font */ + internal_font_number _pdf_font_shrink; /* font at limit of shrinking */ + internal_font_number _pdf_font_stretch; /* font at limit of stretching */ + integer _pdf_font_step; /* amount of one step of expansion */ + boolean _pdf_font_auto_expand; /* this font is auto-expanded? */ + str_number _pdf_font_attr; /* pointer to additional attributes */ +} texfont; + +typedef enum { + unknown_font_type=0, /* new font (has not been used yet) */ + virtual_font_type, /* virtual font */ + real_font_type, /* real font */ +} font_types; + +typedef enum { + unknown_format=0, + type1_format, + type3_format, + truetype_format, + opentype_format, +} font_formats; + +typedef enum { + unknown_embedding=0, + no_embedding, + subset_embedding, + full_embedding, +} font_embedding_option; + +extern char *font_type_strings[]; +extern char *font_format_strings[]; +extern char *font_embedding_strings[]; + + +#define font_checksum(a) font_tables[a]->_font_checksum +#define set_font_checksum(a,b) font_checksum(a) = b + +#define font_check_0(a) ((font_tables[a]->_font_checksum&0xFF000000)>>24) +#define font_check_1(a) ((font_tables[a]->_font_checksum&0x00FF0000)>>16) +#define font_check_2(a) ((font_tables[a]->_font_checksum&0x0000FF00)>>8) +#define font_check_3(a) (font_tables[a]->_font_checksum&0x000000FF) + +#define font_size(a) font_tables[a]->_font_size +#define set_font_size(a,b) font_size(a) = b +#define font_dsize(a) font_tables[a]->_font_dsize +#define set_font_dsize(a,b) font_dsize(a) = b + +#define font_name(a) font_tables[a]->_font_name +#define get_font_name(a) (unsigned char *)font_name(a) +#define set_font_name(f,b) font_name(f) = b +#define tex_font_name(a) maketexstring(font_name(a)) + +boolean cmp_font_name (integer, strnumber); + +#define font_area(a) font_tables[a]->_font_area +#define get_font_area(a) (unsigned char *)font_area(a) +#define set_font_area(f,b) font_area(f) = b +#define tex_font_area(a) maketexstring(font_area(a)) + +boolean cmp_font_area (integer, strnumber); + +#define font_reassign(a,b) { if (a!=NULL) free(a); a = b; } + +#define font_filename(a) font_tables[a]->_font_filename +#define set_font_filename(f,b) font_reassign(font_filename(f),b) + +#define font_fullname(a) font_tables[a]->_font_fullname +#define set_font_fullname(f,b) font_reassign(font_fullname(f),b) + +#define font_encodingname(a) font_tables[a]->_font_encodingname +#define set_font_encodingname(f,b) font_reassign(font_encodingname(f),b) + +boolean font_shareable(internal_font_number,internal_font_number); + +#define cmp_font_filename(a,b) (!(font_filename(a)!=NULL || font_filename(b)!=NULL || \ + strcmp(font_filename(a),font_filename(b)))) +#define cmp_font_fullname(a,b) (!(font_fullname(a)!=NULL || font_fullname(b)!=NULL || \ + strcmp(font_fullname(a),font_fullname(b)))) +#define cmp_font_encodingname(a,b) (!(font_encoding(a)!=NULL || font_encodingname(b)!=NULL || \ + strcmp(font_encodingname(a),font_encodingname(b)))) + +#define font_bc(a) font_tables[a]->_font_bc +#define set_font_bc(f,b) font_bc(f) = b + +#define font_ec(a) font_tables[a]->_font_ec +#define set_font_ec(f,b) font_ec(f) = b + +#define font_used(a) (font_tables[a]!=NULL && font_tables[a]->_font_used) +#define set_font_used(a,b) font_tables[a]->_font_used = b + +#define font_touched(a) font_tables[a]->_font_touched +#define set_font_touched(a,b) font_touched(a) = b + +#define font_type(a) font_tables[a]->_font_type +#define set_font_type(a,b) { /* fprintf(stdout,"set font type of %s to %i: %s\n",font_name(a),b,__FILE__); */ \ + font_type(a) = b; } + +#define font_format(a) font_tables[a]->_font_format +#define font_format_name(a) font_format_strings[font_tables[a]->_font_format] +#define set_font_format(a,b) font_format(a) = b + +#define font_embedding(a) font_tables[a]->_font_embedding +#define set_font_embedding(a,b) font_embedding(a) = b + +#define font_cidversion(a) font_tables[a]->_font_cidversion +#define set_font_cidversion(a,b) font_cidversion(a) = b + +#define font_cidsupplement(a) font_tables[a]->_font_cidsupplement +#define set_font_cidsupplement(a,b) font_cidsupplement(a) = b + +#define font_cidordering(a) font_tables[a]->_font_cidordering +#define set_font_cidordering(f,b) font_reassign(font_cidordering(f),b) + +#define font_cidregistry(a) font_tables[a]->_font_cidregistry +#define set_font_cidregistry(f,b) font_reassign(font_cidregistry(f),b) + +#define font_map(a) font_tables[a]->_font_map +#define set_font_map(a,b) font_map(a) = b + +#define font_cache_id(a) font_tables[a]->_font_cache_id +#define set_font_cache_id(a,b) font_cache_id(a) = b + +#define font_encodingbytes(a) font_tables[a]->_font_encodingbytes +#define set_font_encodingbytes(a,b) font_encodingbytes(a) = b + +#define font_slant(a) font_tables[a]->_font_slant +#define set_font_slant(a,b) font_slant(a) = b + +#define font_extend(a) font_tables[a]->_font_extend +#define set_font_extend(a,b) font_extend(a) = b + +#define font_tounicode(a) font_tables[a]->_font_tounicode +#define set_font_tounicode(a,b) font_tounicode(a) = b + +#define hyphen_char(a) font_tables[a]->_hyphen_char +#define set_hyphen_char(a,b) hyphen_char(a) = b + +#define skew_char(a) font_tables[a]->_skew_char +#define set_skew_char(a,b) skew_char(a) = b + +#define font_natural_dir(a) font_tables[a]->_font_natural_dir +#define set_font_natural_dir(a,b) font_natural_dir(a) = b + +#define pdf_font_size(a) font_tables[a]->_pdf_font_size +#define set_pdf_font_size(a,b) pdf_font_size(a) = b + +#define pdf_font_num(a) font_tables[a]->_pdf_font_num +#define set_pdf_font_num(a,b) pdf_font_num(a) = b + +#define pdf_font_blink(a) font_tables[a]->_pdf_font_blink +#define set_pdf_font_blink(a,b) pdf_font_blink(a) = b + +#define pdf_font_elink(a) font_tables[a]->_pdf_font_elink +#define set_pdf_font_elink(a,b) pdf_font_elink(a) = b + +#define pdf_font_expand_ratio(a) font_tables[a]->_pdf_font_expand_ratio +#define set_pdf_font_expand_ratio(a,b) pdf_font_expand_ratio(a) = b + +#define pdf_font_shrink(a) font_tables[a]->_pdf_font_shrink +#define set_pdf_font_shrink(a,b) pdf_font_shrink(a) = b + +#define pdf_font_stretch(a) font_tables[a]->_pdf_font_stretch +#define set_pdf_font_stretch(a,b) pdf_font_stretch(a) = b + +#define pdf_font_step(a) font_tables[a]->_pdf_font_step +#define set_pdf_font_step(a,b) pdf_font_step(a) = b + +#define pdf_font_auto_expand(a) font_tables[a]->_pdf_font_auto_expand +#define set_pdf_font_auto_expand(a,b) pdf_font_auto_expand(a) = b + +#define pdf_font_attr(a) font_tables[a]->_pdf_font_attr +#define set_pdf_font_attr(a,b) pdf_font_attr(a) = b + + +#define left_boundarychar -1 +#define right_boundarychar -2 +#define non_boundarychar -3 + +#define left_boundary(a) font_tables[a]->_left_boundary +#define has_left_boundary(a) (left_boundary(a)!=NULL) +#define set_left_boundary(a,b) font_reassign(left_boundary(a),b) + +#define right_boundary(a) font_tables[a]->_right_boundary +#define has_right_boundary(a) (right_boundary(a)!=NULL) +#define set_right_boundary(a,b) font_reassign(right_boundary(a),b) + +#define font_bchar(a) (right_boundary(a)!=NULL ? right_boundarychar : non_boundarychar) + +/* font parameters */ + +#define font_params(a) font_tables[a]->_font_params +#define param_base(a) font_tables[a]->_param_base +#define font_param(a,b) font_tables[a]->_param_base[b] + +extern void set_font_params(internal_font_number f, int b); + +#define set_font_param(f,n,b) \ + { if (font_params(f)<n) set_font_params(f,n); \ + font_param(f,n) = b; } + +/* Font parameters are sometimes referred to as |slant(f)|, |space(f)|, etc.*/ + +typedef enum { + slant_code = 1, + space_code = 2, + space_stretch_code = 3, + space_shrink_code = 4, + x_height_code = 5, + quad_code = 6, + extra_space_code = 7 } font_parameter_codes ; + +#define slant(f) font_param(f,slant_code) +#define space(f) font_param(f,space_code) +#define space_stretch(f) font_param(f,space_stretch_code) +#define space_shrink(f) font_param(f,space_shrink_code) +#define x_height(f) font_param(f,x_height_code) +#define quad(f) font_param(f,quad_code) +#define extra_space(f) font_param(f,extra_space_code) + +/* now for characters */ + +extern charinfo *get_charinfo (internal_font_number f, integer c) ; +extern integer char_exists (internal_font_number f, integer c); +extern charinfo *char_info (internal_font_number f, integer c); + + +extern void set_charinfo_width (charinfo *ci, scaled val); +extern void set_charinfo_height (charinfo *ci, scaled val); +extern void set_charinfo_depth (charinfo *ci, scaled val); +extern void set_charinfo_italic (charinfo *ci, scaled val); +extern void set_charinfo_tag (charinfo *ci, scaled val); +extern void set_charinfo_remainder (charinfo *ci, scaled val); +extern void set_charinfo_used (charinfo *ci, scaled val); +extern void set_charinfo_index (charinfo *ci, scaled val); +extern void set_charinfo_name (charinfo *ci, char *val) ; +extern void set_charinfo_tounicode (charinfo *ci, char *val) ; +extern void set_charinfo_ligatures (charinfo *ci, liginfo *val); +extern void set_charinfo_kerns (charinfo *ci, kerninfo *val); +extern void set_charinfo_packets (charinfo *ci, real_eight_bits *val); +extern void set_charinfo_extensible (charinfo *ci, int a, int b, int c, int d); + +#define set_char_used(f,a,b) set_charinfo_used(get_charinfo(f,a),b) + +extern scaled get_charinfo_width (charinfo *ci); +extern scaled get_charinfo_height (charinfo *ci); +extern scaled get_charinfo_depth (charinfo *ci); +extern scaled get_charinfo_italic (charinfo *ci); +extern char get_charinfo_tag (charinfo *ci); +extern integer get_charinfo_remainder (charinfo *ci); +extern char get_charinfo_used (charinfo *ci); +extern integer get_charinfo_index (charinfo *ci); +extern char * get_charinfo_name (charinfo *ci) ; +extern char * get_charinfo_tounicode (charinfo *ci) ; +extern liginfo * get_charinfo_ligatures (charinfo *ci); +extern kerninfo *get_charinfo_kerns (charinfo *ci); +extern real_eight_bits *get_charinfo_packets (charinfo *ci); +extern integer get_charinfo_extensible (charinfo *ci, int which); + +extern integer ext_top (internal_font_number f, integer c); +extern integer ext_bot (internal_font_number f, integer c); +extern integer ext_rep (internal_font_number f, integer c); +extern integer ext_mid (internal_font_number f, integer c); + +#define set_ligature_item(f,b,c,d) { f.type = b; f.adj = c; f.lig = d; } + +#define set_kern_item(f,b,c) { f.adj = b; f.sc = c; } + + +/* character information */ + +#define non_char 65536 /* a code that can't match a real character */ +#define non_address 0 /* a spurious |bchar_label| */ + + +/* character kerns and ligatures */ + +#define end_kern 0x7FFFFF /* otherchar value meaning "stop" */ +#define ignored_kern 0x800000 /* otherchar value meaning "disabled" */ + +#define charinfo_kern(b,c) b->kerns[c] + +#define kern_char(b) (b).adj +#define kern_kern(b) (b).sc +#define kern_end(b) ((b).adj == end_kern) +#define kern_disabled(b) ((b).adj > end_kern) + +/* character ligatures */ + +#define end_ligature 0x7FFFFF /* otherchar value meaning "stop" */ +#define ignored_ligature 0x800000 /* otherchar value meaning "disabled" */ + +#define charinfo_ligature(b,c) b->ligatures[c] + +#define is_valid_ligature(a) ((a).type!=0) +#define lig_type(a) ((a).type>>1) +#define lig_char(a) (a).adj +#define lig_replacement(a) (a).lig +#define lig_end(a) (lig_char(a) == end_ligature) +#define lig_disabled(a) (lig_char(a) > end_ligature) + +#define no_tag 0 /* vanilla character */ +#define lig_tag 1 /* character has a ligature/kerning program */ +#define list_tag 2 /* character has a successor in a charlist */ +#define ext_tag 3 /* character is extensible */ + +extern scaled char_height (internal_font_number f, integer c); +extern scaled char_width (internal_font_number f, integer c); +extern scaled char_depth (internal_font_number f, integer c); +extern scaled char_italic (internal_font_number f, integer c); + +extern liginfo * char_ligatures (internal_font_number f, integer c); +extern kerninfo * char_kerns (internal_font_number f, integer c); +extern real_eight_bits * char_packets (internal_font_number f, integer c); + +#define has_lig(f,b) (char_exists(f,b) &&( char_ligatures(f,b) != NULL)) +#define has_kern(f,b) (char_exists(f,b) && (char_kerns(f,b) != NULL)) +#define has_packet(f,b) (char_exists(f,b) && (char_packets(f,b) != NULL)) + +extern integer char_remainder (internal_font_number f, integer c); +extern char char_tag (internal_font_number f, integer c); +extern char char_used (internal_font_number f, integer c); +extern char * char_name (internal_font_number f, integer c); +extern integer char_index (internal_font_number f, integer c); + +scaled get_kern(internalfontnumber f, integer lc, integer rc); +liginfo get_ligature(internalfontnumber f, integer lc, integer rc); + +#define EXT_TOP 0 +#define EXT_BOT 1 +#define EXT_MID 2 +#define EXT_REP 3 + +extern texfont **font_tables; + +integer new_font (void) ; +integer copy_font (integer id) ; +integer scale_font (integer id, integer atsize) ; +integer max_font_id (void); +void set_max_font_id (integer id); +integer new_font_id (void); +void create_null_font (void); +void delete_font(integer id); +boolean is_valid_font (integer id); + +void dump_font (int font_number); +void undump_font (int font_number); + +integer test_no_ligatures (internal_font_number f) ; +void set_no_ligatures (internal_font_number f) ; + +extern integer get_tag_code (internal_font_number f, integer c); +extern integer get_lp_code (internal_font_number f, integer c); +extern integer get_rp_code (internal_font_number f, integer c); +extern integer get_ef_code (internal_font_number f, integer c); + +extern void set_tag_code (internal_font_number f, integer c, integer i) ; +extern void set_lp_code(internal_font_number f, integer c, integer i) ; +extern void set_rp_code(internal_font_number f, integer c, integer i) ; +extern void set_ef_code(internal_font_number f, integer c, integer i) ; + +int read_tfm_info(internal_font_number f, char *nom, char *aire, scaled s); + + +/* from dofont.c */ + +extern int read_font_info (pointer u, strnumber nom, strnumber aire, scaled s, integer ndir); +extern int find_font_id (char *nom, char *aire, scaled s); + +/* for and from vfpacket.c */ + +#define scan_special 3 /* look into special text */ /* this is a hack */ + +typedef enum { packet_char_code, + packet_font_code, + packet_pop_code, + packet_push_code, + packet_special_code, + packet_right_code, + packet_down_code, + packet_rule_code, + packet_node_code, + packet_nop_code, + packet_end_code } packet_command_codes; + +extern scaled sqxfw (scaled sq, integer fw); + +extern void do_vf_packet (internal_font_number vf_f, integer c); +extern int vf_packet_bytes (charinfo *co); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/font/tfmofm.c b/Build/source/texk/web2c/luatexdir/font/tfmofm.c new file mode 100644 index 00000000000..db82f94deba --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tfmofm.c @@ -0,0 +1,1005 @@ +/* +Copyright (c) 1996-2006 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LuaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: tfmofm.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +#include "luatex-api.h" + +/* Here are some macros that help process ligatures and kerns */ + +#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} +\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr +header&|[0..lh-1]@t\\{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&|[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. + +@d bad_tfm=11 {label for |read_font_info|} +@d abort==goto bad_tfm {do this when the \.{TFM} data is wrong} + +*/ + +/* +The |tag| field in a |char_info_word| has four values that explain how to +interpret the |remainder| field. + +\yskip\hangg|tag=0| (|no_tag|) means that |remainder| is unused.\par +\hangg|tag=1| (|lig_tag|) means that this character has a ligature/kerning +program starting at position |remainder| in the |lig_kern| array.\par +\hangg|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 +\hangg|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. + +*/ + +#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; } + + +int +open_tfm_file(char *nom, char *aire, unsigned char **tfm_buf, integer *tfm_siz) { + boolean res; /* was the callback successful? */ + boolean opened; /* was |tfm_file| successfully opened?*/ + integer callback_id; + FILE *tfm_file; + /* packfilename(nom,aire,getnullstr()); */ + if(nameoffile != NULL) + xfree(nameoffile); + nameoffile = malloc(strlen(nom)+2); + strcpy(stringcast(nameoffile+1),nom); + namelength = strlen(nom); + callback_id=callback_defined(read_font_file_callback); + if (callback_id>0) { + res = run_callback(callback_id,"S->bSd",stringcast(nameoffile+1), + &opened, tfm_buf, tfm_siz); + if (res && opened && (*tfm_siz>0)) { + return 1; + } + if (!opened) + return -1; + } else { + if (ofm_open_in(tfm_file)) { + res = read_tfm_file(tfm_file,tfm_buf,tfm_siz); + b_close(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@> +*/ + +#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=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=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=a; \ + fget; read_sixteen_unsigned(b); q.b1=b; \ + fget; read_sixteen_unsigned(c); q.b2=c; \ + fget; read_sixteen_unsigned(d); q.b3=d; \ + } else { \ + a=tfm_buffer[++tfm_byte]; q.b0=a; \ + b=tfm_buffer[++tfm_byte]; q.b1=b; \ + c=tfm_buffer[++tfm_byte]; q.b2=c; \ + d=tfm_buffer[++tfm_byte]; q.b3=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; \ + } + +#define check_existence(z) \ + { check_byte_range(z); \ + if (!char_exists(f,z)) tfm_abort; \ + } + +typedef struct tfmcharacterinfo { + integer _kern_index; + integer _lig_index; + integer _width_index; + integer _height_index; + integer _depth_index; + integer _italic_index; + integer _remainder; + unsigned char _tag ; +} tfmcharacterinfo; + +extern charinfo *copy_charinfo(charinfo *ci); + +int +read_tfm_info(internalfontnumber f, char *cnom, char *caire, scaled s) { + integer 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; + integer a,b,c,d; /* byte variables */ + integer i; /* counter */ + integer font_level,header_length; + integer nco,ncw,npc,nlw,neew; + tfmcharacterinfo ci; + charinfo *co; + four_quarters qw; + four_quarters *lig_kerns, *extens; + scaled sw; /* accumulators */ + integer bch_label; /* left boundary start location, or infinity */ + int bchar; /* :0..too_big_char; */ /* right boundary character, or |too_big_char| */ + integer first_two; + scaled z; /* the design size or the ``at'' size */ + integer alpha; + char beta; /* :1..16*/ + integer *xligs, *xkerns; /* aux. for ligkern processing */ + liginfo *cligs; + kerninfo *ckerns; + int fligs, fkerns; + char *tmpnam; + integer tfm_byte = 0; /* index into |tfm_buffer| */ + integer saved_tfm_byte = 0; /* saved index into |tfm_buffer| */ + unsigned char *tfm_buffer = NULL; /* byte buffer for tfm files */ + integer tfm_size = 0; /* total size of the tfm file */ + + 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,caire,&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) { + *(tmpnam+strlen(tmpnam)-4) =0; + } + set_font_name(f,tmpnam); + set_font_area(f,xstrdup(caire)); /* perhaps it leaks, but it doesnt crash */ + + /* @<Read the {\.{TFM}} size fields@>; */ + nco=0; ncw=0; npc=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; + + /* @<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(nw*sizeof(scaled)); + heights = xmalloc(nh*sizeof(scaled)); + depths = xmalloc(nd*sizeof(scaled)); + italics = xmalloc(ni*sizeof(scaled)); + extens = xmalloc(ne*sizeof(four_quarters)); + lig_kerns = xmalloc(nl*sizeof(four_quarters)); + kerns = xmalloc(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(font_checksum(f)); + 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=256/alpha; 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 (b!=bchar) check_existence(b); */ + if (c<128) { + /* check_existence(d); */ /* check ligature */ + } 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)); + } + } + + /* + 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 (tfm_byte<tfm_size-1) tfm_abort; + + tfm_byte = saved_tfm_byte ; + + /* fix up the left boundary character */ + fligs = 0; + fkerns = 0; + if (bch_label != nl ) { + k = bch_label; + /* + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + */ + 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((fligs+1),sizeof(liginfo)); + if (fkerns>0) ckerns = xcalloc((fkerns+1),sizeof(kerninfo)); + fligs = 0; + fkerns = 0; + k = bch_label; + /* + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + */ + 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],(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((ec+1),sizeof(integer)); + xkerns = xcalloc((ec+1),sizeof(integer)); + + 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((xligs[i]+1),sizeof(liginfo)); + if (xkerns[i]>0) ckerns = xcalloc((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],(op_byte(k)*2+1),right_boundarychar,rem_byte(k)); + fligs++; + } + set_ligature_item(cligs[fligs],(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; +} + diff --git a/Build/source/texk/web2c/luatexdir/font/tounicode.c b/Build/source/texk/web2c/luatexdir/font/tounicode.c new file mode 100644 index 00000000000..ff86a8512e2 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tounicode.c @@ -0,0 +1,604 @@ +/* +Copyright (c) 2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ptexlib.h" + +#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) +{ + 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; + 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); +} + +void def_tounicode(strnumber glyph, strnumber unistr) +{ + char buf[SMALL_BUF_SIZE], *p; + 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); /* copy the result to buf before next call of makecstring() */ + p = makecstring(unistr); + while (*p == ' ') + p++; /* ignore leading spaces */ + l = 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(p[i])) { + valid_unistr = 0; + break; + } + } + if (l == 0 || valid_unistr == 0 || strlen(buf) == 0 + || strcmp(buf, notdef) == 0) { + pdftex_warn("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); +} + + +static long check_unicode_value(char *s, boolean multiple_value) +{ + int l = strlen(s); + int i; + long code; + + 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(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; +} + +static char *utf16be_str(long code) +{ + static char buf[SMALL_BUF_SIZE]; + long v; + unsigned vh, vl; + + assert(code >= 0); + + if (code <= 0xFFFF) + sprintf(buf, "%04lX", code); + else { + v = code - 0x10000; + vh = v / 0x400 + 0xD800; + vl = v % 0x400 + 0xDC00; + sprintf(buf, "%04X%04X", vh, vl); + } + return buf; +} + + +/* 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; + + /* 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, 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; + } + } +} + +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,index)))!=NULL) { + gp->code = UNI_EXTRA_STRING; + gp->unicode_seq = xstrdup(s); + } + } else { + gp->code = index; /* fallback */ + } +} + + +integer write_tounicode(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]; + integer 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) { + pdftex_warn("no GlyphToUnicode entry has been inserted yet!"); + fixed_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_new_objnum(); + pdf_begin_dict(objnum, 0); + pdf_begin_stream(); + pdf_printf("%%!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] = 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("%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("<%02X> <%02X> <%s>\n", i, i + range_size[i] - 1, + utf16be_str(gtab[i].code)); + i += range_size[i]; + } + pdf_printf("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("%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("<%02X> <%s>\n", i, gtab[i].unicode_seq); + } else + pdf_printf("<%02X> <%s>\n", i, utf16be_str(gtab[i].code)); + i++; + } + pdf_printf("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("endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n"); + pdf_end_stream(); + return objnum; +} + +integer write_cid_tounicode(fo_entry * fo, internalfontnumber f) { + + int range_size[65537]; + glyph_unicode_entry gtab[65537]; + integer objnum; + int i, j, k; + int bfchar_count, bfrange_count, subrange_count; + char *buf; + + assert(fo->fd->fontname); + buf = xmalloc(strlen(fo->fd->fontname)+8); + sprintf(buf,"%s-%s",(fo->fd->subset_tag!=NULL ? fo->fd->subset_tag : "UCS"), + fo->fd->fontname); + + objnum = pdf_new_objnum(); + pdf_begin_dict(objnum, 0); + pdf_begin_stream(); + pdf_printf("%%!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 (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; + while (i < 65536 && 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] = 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("%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("<%04X> <%04X> <%s>\n", i, i + range_size[i] - 1, + utf16be_str(gtab[i].code)); + i += range_size[i]; + } + pdf_printf("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("%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("<%04X> <%s>\n", i, gtab[i].unicode_seq); + } else + pdf_printf("<%04X> <%s>\n", i, utf16be_str(gtab[i].code)); + i++; + } + pdf_printf("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("endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n"); + pdf_end_stream(); + return objnum; +} diff --git a/Build/source/texk/web2c/luatexdir/font/tt_glyf.c b/Build/source/texk/web2c/luatexdir/font/tt_glyf.c new file mode 100644 index 00000000000..bf21e58c49a --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tt_glyf.c @@ -0,0 +1,658 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/tt_glyf.c,v 1.2 2005/06/09 14:31:11 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +/* + * Subsetting glyf, updating loca, hmtx, ... + * + */ + +#include "ptexlib.h" + +#include "sfnt.h" +#include "tt_table.h" +#include "tt_glyf.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; + + 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) + TT_ERROR("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)))) { + WARN("Slot %u already used.", new_gid); + } else { + if (g->num_glyphs+1 >= NUM_GLYPH_LIMIT) + TT_ERROR("Too many glyphs."); + + if (g->num_glyphs >= g->max_glyphs) { + 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] |= (1 << (7 - (new_gid % 8))); + g->num_glyphs += 1; + } + + if (new_gid > g->last_gid) { + g->last_gid = new_gid; + } + + return new_gid; +} + +/* + * 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; + struct tt_glyph_desc *sv1, *sv2; + + sv1 = (struct tt_glyph_desc *) v1; + sv2 = (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; +} + +/* + * TrueType outline data. + */ +#define ARG_1_AND_2_ARE_WORDS (1 << 0) +#define ARGS_ARE_XY_VALUES (1 << 1) +#define ROUND_XY_TO_GRID (1 << 2) +#define WE_HAVE_A_SCALE (1 << 3) +#define RESERVED (1 << 4) +#define MORE_COMPONENT (1 << 5) +#define WE_HAVE_AN_X_AND_Y_SCALE (1 << 6) +#define WE_HAVE_A_TWO_BY_TWO (1 << 7) +#define WE_HAVE_INSTRUCTIONS (1 << 8) +#define USE_MY_METRICS (1 << 9) + +int +tt_build_tables (sfnt *sfont, struct tt_glyphs *g) +{ + char *hmtx_table_data = NULL, *loca_table_data = NULL; + char *glyf_table_data = NULL; + ULONG hmtx_table_size, loca_table_size, glyf_table_size; + /* 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 */ + + ASSERT(g); + + if (sfont->type != SFNT_TYPE_TRUETYPE && + sfont->type != SFNT_TYPE_TTC) + TT_ERROR("Invalid font type"); + + if (g->num_glyphs > NUM_GLYPH_LIMIT) + TT_ERROR("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) + TT_ERROR("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 = os2->sTypoAscender - os2->sTypoDescender; + g->default_tsb = 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 { + TT_ERROR("Unknown IndexToLocFormat."); + } + + w_stat = NEW(g->emsize+2, USHORT); + memset(w_stat, 0, sizeof(USHORT)*(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) + TT_ERROR("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] += 1; + } else { + w_stat[g->emsize+1] += 1; /* larger than em */ + } + + if (len == 0) { /* Does not contains any data. */ + continue; + } else if (len < 10) { + TT_ERROR("Invalid TrueType glyph data (gid %u).", gid); + } + + g->gd[i].data = p = NEW(len, BYTE); + endptr = p + len; + + sfnt_seek_set(sfont, 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 = 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, 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) + TT_ERROR("Invalid TrueType glyph data (gid %u): %u bytes", gid, (unsigned int)len); + /* + * Flags and gid of component glyph are both USHORT. + */ + flags = ((*p) << 8)| *(p+1); + p += 2; + cgid = ((*p) << 8)| *(p+1); + if (cgid >= maxp->numGlyphs) { + TT_ERROR("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_COMPONENT); + /* + * 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 = 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 = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0; + glyf_table_size += g->gd[i].length + padlen; + if (!num_hm_known && last_advw != g->gd[i].advw) { + hhea->numberOfHMetrics = g->gd[i].gid + 2; + num_hm_known = 1; + } + } + /* All advance widths are same. */ + if (!num_hm_known) { + hhea->numberOfHMetrics = 1; + } + hmtx_table_size = 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 = (g->last_gid + 2)*2; + } else { + head->indexToLocFormat = 1; + loca_table_size = (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); + + 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, offset); + } + } + padlen = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0; + 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, offset); + } + memset(glyf_table_data + offset, 0, g->gd[i].length + padlen); + memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length); + offset += g->gd[i].length + padlen; + prev = g->gd[i].gid; + /* free data here since it consume much memory */ + RELEASE(g->gd[i].data); + 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, 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); + sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size); + } + + head->checkSumAdjustment = 0; + maxp->numGlyphs = 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 + ) + TT_ERROR("File not opened."); + + if (sfont->type != SFNT_TYPE_TRUETYPE && + sfont->type != SFNT_TYPE_TTC) + TT_ERROR("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) + TT_ERROR("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 = os2->sTypoAscender - os2->sTypoDescender; + g->default_tsb = 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 { + TT_ERROR("Unknown IndexToLocFormat."); + } + + w_stat = NEW(g->emsize+2, USHORT); + memset(w_stat, 0, 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) + TT_ERROR("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] += 1; + } else { + w_stat[g->emsize+1] += 1; /* larger than em */ + } + + if (len == 0) { /* Does not contains any data. */ + continue; + } else if (len < 10) { + TT_ERROR("Invalid TrueType glyph data (gid %u).", gid); + } + + sfnt_seek_set(sfont, offset+loc); + number_of_contours = 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 = 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 = i; + } + } + } + RELEASE(w_stat); + + + return 0; +} diff --git a/Build/source/texk/web2c/luatexdir/font/tt_glyf.h b/Build/source/texk/web2c/luatexdir/font/tt_glyf.h new file mode 100644 index 00000000000..cf33af6733f --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tt_glyf.h @@ -0,0 +1,60 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/tt_glyf.h,v 1.1 2004/09/11 14:50:29 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef _TT_GLYF_H_ +#define _TT_GLYF_H_ + +struct tt_glyph_desc +{ + USHORT gid; + USHORT ogid; /* GID in original font */ + USHORT advw, advh; + SHORT lsb, tsb; + SHORT llx, lly, urx, ury; + ULONG length; + BYTE *data; +}; + +struct tt_glyphs +{ + USHORT num_glyphs; + USHORT max_glyphs; + USHORT last_gid; + USHORT emsize; + USHORT dw; /* optimal value for DW */ + USHORT default_advh; /* default value */ + SHORT default_tsb; /* default value */ + struct tt_glyph_desc *gd; + unsigned char *used_slot; +}; + +extern struct tt_glyphs *tt_build_init (void); +extern void tt_build_finish (struct tt_glyphs *g); + +extern USHORT tt_add_glyph (struct tt_glyphs *g, USHORT gid, USHORT new_gid); +extern USHORT tt_get_index (struct tt_glyphs *g, USHORT gid); +extern USHORT tt_find_glyph (struct tt_glyphs *g, USHORT gid); + +extern int tt_build_tables (sfnt *sfont, struct tt_glyphs *g); +extern int tt_get_metrics (sfnt *sfont, struct tt_glyphs *g); + +#endif /* _TT_GLYF_H_ */ diff --git a/Build/source/texk/web2c/luatexdir/font/tt_table.c b/Build/source/texk/web2c/luatexdir/font/tt_table.c new file mode 100644 index 00000000000..4f82552d9df --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tt_table.c @@ -0,0 +1,483 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/tt_table.c,v 1.7 2004/09/11 14:50:29 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#include <stdio.h> + +#ifndef pdfTeX +#include "system.h" +#include "error.h" +#include "mem.h" +#include "mfileio.h" +#else +extern void pdftex_fail (const char *fmt, ...); /* utils.c */ +#endif + +#include "sfnt.h" +#include "tt_table.h" + +/* + tables contains information refered by other tables + maxp->numGlyphs, etc --> loca, etc + hhea->numberOfHMetrics --> hmtx + head->indexToLocFormat --> loca + head->glyphDataFormat --> glyf +*/ + +char *tt_pack_head_table (struct tt_head_table *table) +{ + int i; + char *p, *data; + + if (table == NULL) + TT_ERROR("passed NULL pointer\n"); + + p = data = NEW(TT_HEAD_TABLE_SIZE, char); + p += sfnt_put_ulong(p, table->version); + p += sfnt_put_ulong(p, table->fontRevision); + p += sfnt_put_ulong(p, table->checkSumAdjustment); + p += sfnt_put_ulong(p, table->magicNumber); + p += sfnt_put_ushort(p, table->flags); + p += sfnt_put_ushort(p, table->unitsPerEm); + for (i=0; i<8; i++) { + *(p++) = (table->created)[i]; + } + for (i=0; i<8; i++) { + *(p++) = (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 = sfnt_get_short(sfont); + table->lowestRecPPEM = 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, 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, 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) + TT_ERROR("unknown metricDaraFormat"); + table->numberOfHMetrics = sfnt_get_ushort(sfont); + + return table; +} + +/* vhea */ +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, 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) + TT_ERROR("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. + */ + +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 */ +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)) + TT_ERROR ("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) { + fprintf(stderr, "\n** Notice: Name string too long. Truncating **\n"); + length = destlen - 1; + } + sfnt_seek_set (sfont, 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; + +#ifdef XETEX + + const char* name = FT_Get_Postscript_Name(sfont->ft_face); + namelen = strlen(name); + if (namelen > destlen - 1) { + strncpy(dest, name, destlen - 1); + dest[destlen] = 0; + } + else + strcpy(dest, name); + +#else + + /* 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; + + fprintf(stderr, "\n** Warning: No valid PostScript name available **\n"); + /* + 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); + } + +#endif + + return namelen; +} diff --git a/Build/source/texk/web2c/luatexdir/font/tt_table.h b/Build/source/texk/web2c/luatexdir/font/tt_table.h new file mode 100644 index 00000000000..ffb2c5b8f45 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tt_table.h @@ -0,0 +1,193 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/tt_table.h,v 1.6 2004/09/11 14:50:29 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef _TT_TABLE_H_ +#define _TT_TABLE_H_ + +#include "sfnt.h" + +#define TT_HEAD_TABLE_SIZE 54UL +#define TT_MAXP_TABLE_SIZE 32UL +#define TT_HHEA_TABLE_SIZE 36UL +#define TT_VHEA_TABLE_SIZE 36UL + +struct tt_head_table +{ + Fixed version; + Fixed fontRevision; + ULONG checkSumAdjustment; + ULONG magicNumber; + USHORT flags; + USHORT unitsPerEm; + BYTE created[8]; + BYTE modified[8]; + FWord xMin, yMin, xMax, yMax; + USHORT macStyle; + USHORT lowestRecPPEM; + SHORT fontDirectionHint; + SHORT indexToLocFormat; + SHORT glyphDataFormat; +}; + +struct tt_hhea_table +{ + Fixed version; + FWord Ascender; + FWord Descender; + FWord LineGap; + uFWord advanceWidthMax; + FWord minLeftSideBearing; + FWord minRightSideBearing; + FWord xMaxExtent; + SHORT caretSlopeRise; + SHORT caretSlopeRun; + SHORT reserved[5]; /* set to 0 */ + SHORT metricDataFormat; + USHORT numberOfHMetrics; +}; + +struct tt_vhea_table +{ + Fixed version; + SHORT vertTypoAscender; /* v.1.1 name */ + SHORT vertTypoDescender; /* v.1.1 name */ + SHORT vertTypoLineGap; /* v.1.1 name */ + SHORT advanceHeightMax; + SHORT minTopSideBearing; + SHORT minBottomSideBearing; + SHORT yMaxExtent; + SHORT caretSlopeRise; + SHORT caretSlopeRun; + SHORT caretOffset; + SHORT reserved[5]; /* set to 0 */ + USHORT numOfLongVerMetrics; +}; + +struct tt_maxp_table +{ + Fixed version; + USHORT numGlyphs; + USHORT maxPoints; + USHORT maxContours; + USHORT maxComponentPoints; + USHORT maxComponentContours; + USHORT maxZones; + USHORT maxTwilightPoints; + USHORT maxStorage; + USHORT maxFunctionDefs; + USHORT maxInstructionDefs; + USHORT maxStackElements; + USHORT maxSizeOfInstructions; + USHORT maxComponentElements; + USHORT maxComponentDepth; +}; + +struct tt_os2__table +{ + USHORT version; /* 0x0001 or 0x0002 */ + SHORT xAvgCharWidth; + USHORT usWeightClass; + USHORT usWidthClass; + SHORT fsType; /* if (faType & 0x08) editable_embedding */ + SHORT ySubscriptXSize; + SHORT ySubscriptYSize; + SHORT ySubscriptXOffset; + SHORT ySubscriptYOffset; + SHORT ySuperscriptXSize; + SHORT ySuperscriptYSize; + SHORT ySuperscriptXOffset; + SHORT ySuperscriptYOffset; + SHORT yStrikeoutSize; + SHORT yStrikeoutPosition; + SHORT sFamilyClass; + BYTE panose[10]; + ULONG ulUnicodeRange1; + ULONG ulUnicodeRange2; + ULONG ulUnicodeRange3; + ULONG ulUnicodeRange4; + ICHAR achVendID[4]; + USHORT fsSelection; + USHORT usFirstCharIndex; + USHORT usLastCharIndex; + SHORT sTypoAscender; /* TTF spec. from MS is wrong */ + SHORT sTypoDescender; /* TTF spec. from MS is wrong */ + SHORT sTypoLineGap; /* TTF spec. from MS is wrong */ + USHORT usWinAscent; + USHORT usWinDescent; + ULONG ulCodePageRange1; + ULONG ulCodePageRange2; + /* version 0x0002 */ + SHORT sxHeight; + SHORT sCapHeight; + USHORT usDefaultChar; + USHORT usBreakChar; + USHORT usMaxContext; +}; + +struct tt_vertOriginYMetrics { + USHORT glyphIndex; + SHORT vertOriginY; +}; + +struct tt_VORG_table { + SHORT defaultVertOriginY; + USHORT numVertOriginYMetrics; + struct tt_vertOriginYMetrics *vertOriginYMetrics; +}; + +/* hmtx and vmtx */ +struct tt_longMetrics +{ + USHORT advance; + SHORT sideBearing; +}; + + +/* head, hhea, maxp */ +extern char *tt_pack_head_table (struct tt_head_table *table); +extern struct tt_head_table *tt_read_head_table (sfnt *sfont); +extern char *tt_pack_hhea_table (struct tt_hhea_table *table); +extern struct tt_hhea_table *tt_read_hhea_table (sfnt *sfont); +extern char *tt_pack_maxp_table (struct tt_maxp_table *table); +extern struct tt_maxp_table *tt_read_maxp_table (sfnt *sfont); + +/* vhea */ +extern char *tt_pack_vhea_table (struct tt_vhea_table *table); +extern struct tt_vhea_table *tt_read_vhea_table (sfnt *sfont); + +/* VORG */ +extern struct tt_VORG_table *tt_read_VORG_table (sfnt *sfont); + +/* hmtx and vmtx */ +extern struct tt_longMetrics *tt_read_longMetrics (sfnt *sfont, + USHORT numGlyphs, USHORT numLongMetrics); + +/* OS/2 table */ +extern struct tt_os2__table *tt_read_os2__table (sfnt *sfont); + +/* name table */ +extern USHORT tt_get_name (sfnt *sfont, char *dest, USHORT destlen, + USHORT plat_id, USHORT enco_id, + USHORT lang_id, USHORT name_id); +extern USHORT tt_get_ps_fontname (sfnt *sfont, char *dest, USHORT destlen); + +#endif /* _TT_TABLE_H_ */ diff --git a/Build/source/texk/web2c/luatexdir/font/vfovf.c b/Build/source/texk/web2c/luatexdir/font/vfovf.c new file mode 100644 index 00000000000..0f23cb07b94 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/vfovf.c @@ -0,0 +1,1349 @@ +/* +Copyright (c) 1996-2006 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LuaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: vfovf.c 1022 2008-02-14 11:49:30Z taco $ +*/ + +#include "ptexlib.h" + +#include "luatex-api.h" + +/* 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 */ +#define bad_vf(a) { xfree(vf_buffer); print_nlp(); \ + print_string("Error in processing VF font ("); \ + print_string(font_name(f)); \ + print_string(".vf): "); \ + print_string(a); \ + print_string(", virtual font will be ignored"); \ + 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 */ + +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; + +boolean auto_expand_vf(internal_font_number f); /* forward */ + +/* get a byte from\.{VF} file */ + +#define vf_byte(a) { real_eight_bits vf_tmp_b; \ + if (vf_cur>=vf_size) { \ + pdftex_fail("unexpected eof on virtual font"); \ + } \ + 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; \ + } \ + vf_beta=256 / vf_alpha; \ + vf_alpha=vf_alpha*vf_z; } + +/* read |k| bytes as an integer from \.{VF} file */ + +#define vf_read(k,l) { integer itmp = 0, dtmp = k, jtmp = 0; \ + while (dtmp > 0) { \ + vf_byte(jtmp); \ + if ((dtmp==k) && jtmp>127) \ + jtmp = jtmp - 256; \ + itmp = itmp*256 + jtmp; \ + decr(dtmp); \ + } \ + l = itmp; } + +#define vf_read_u(k,l) { unsigned int dtmp=k, itmp = 0, jtmp = 0; \ + while (dtmp-- > 0) { \ + vf_byte(jtmp); \ + itmp = itmp*256 + jtmp; \ + } \ + l = itmp; } + +void +pdf_check_vf_cur_val (void) { + internal_font_number f; + f = cur_val; + if (font_type(f) == virtual_font_type) + pdf_error("font", "command cannot be used with virtual font"); +} + +static void +vf_local_font_warning(internal_font_number f, internal_font_number k, char *s, integer a, integer b) { + print_nlp(); + print_string(s); + print_string(" in local font "); + print_string(font_name(k)); + print_string(" ("); + print_int(b); + print_string(" != "); + print_int(a); + print_string(") in virtual font "); + print_string(font_name(f)); + print_string(".vf ignored."); +} + + +/* process a local font in \.{VF} file */ + +internal_font_number +vf_def_font(internal_font_number f,unsigned char *vf_buffer, integer *vf_cr) { + internal_font_number k; + str_number s; + scaled ds,fs; + four_quarters cs; + memory_word tmp_w; /* accumulator */ + integer junk; + unsigned long 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 = 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 = sqxfw(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 */ + } + string_room(tmp_b1); + while (tmp_b1 > 0) { + tmp_b1--; + junk = vf_buffer[(*vf_cr)] ; (*vf_cr)++; + append_pool_char(junk); + } + s = make_string(); + k = tfm_lookup(s, fs); + if (k == null_font) + k = read_font_info(get_nullcs(), s, get_nullstr(), fs, -1); + if (k != null_font) { + if (checksum!=0 && font_checksum(k)!=0 && checksum!= font_checksum(k)) + vf_local_font_warning(f, k, "checksum mismatch",checksum,font_checksum(k)); + if (ds != font_dsize(k)) + vf_local_font_warning(f, k, "design size mismatch",ds,font_dsize(k)); + } + if (pdf_font_expand_ratio(f) != 0) + set_expand_params(k, pdf_font_auto_expand(f), + pdf_font_expand_ratio(pdf_font_stretch(f)), + -pdf_font_expand_ratio(pdf_font_shrink(f)), + pdf_font_step(f), pdf_font_expand_ratio(f)); + return k; +} + + +int +open_vf_file (char *fn, unsigned char **vbuffer, integer *vsize) { + boolean res; /* was the callback successful? */ + integer callback_id; + boolean file_read; /* was |vf_file| successfully read? */ + FILE *vf_file; + char *fnam = NULL; + + + + + namelength = strlen(fn); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),fn); + + callback_id=callback_defined(find_vf_file_callback); + if (callback_id>0) { + res = run_callback(callback_id,"S->S",fn, &fnam); + if (res && (fnam!=NULL) && (strlen(fnam)>0)) { + /* @<Fixup |nameoffile| after callback@>; */ + free(nameoffile); + namelength = strlen(fnam); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),fnam); + } else { + return 0; + } + } + callback_id=callback_defined(read_vf_file_callback); + if (callback_id>0) { + file_read = false; + res = run_callback(callback_id,"S->bSd",stringcast(nameoffile+1), + &file_read, vbuffer,vsize); + if (res && file_read && (*vsize>0)) { + return 1; + } + if (!file_read) + return 0; /* -1 */ + } else { + if (ovf_b_open_in(vf_file) || vf_b_open_in(vf_file)) { + res = read_vf_file(vf_file,vbuffer,vsize); + b_close(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|. +*/ + +#define append_packet(k) vpackets[vf_np++] = k + +/* 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)); } + +/* 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(); \ + print_string("checksum mismatch in font "); \ + print_string(font_name(f)); \ + print_string(".vf ignored "); } } + +#define test_dsize() { int read_tmp; vf_read(4,read_tmp); \ + if ((read_tmp / 16) != font_dsize(f)) { \ + print_nlp(); \ + print_string("design size mismatch in font "); \ + print_string(font_name(f)); \ + print_string(".vf ignored"); \ + } } + + +int count_packet_bytes (real_eight_bits *vf_buf, int cur_bute, int count) { + int k = 0; + int ff = 0; + int acc = 0; + unsigned int cmd = 0; + unsigned int d = 0; + while (k<count) { + cmd = vf_buf[cur_bute+k]; k++; + if ((cmd >= set_char_0) && (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+k]; k++; + k += d; acc += 5 + d; + break; + case xxx2: + d = vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + k += d; acc += 5 + d; + break; + case xxx3: + d = vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + k += d; acc += 5 + d; + break; + case xxx4: + d = vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + d = d*256 + vf_buf[cur_bute+k]; k++; + k += d; acc += 5 + 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) { + integer k, n, i; + unsigned cmd; + scaled x,y,w,z,h,v; + integer cc, cmd_length, packet_length; + charinfo *co; + scaled tfm_width; + integer save_cur_byte; + vf_stack_index stack_level; + integer vf_z; /* multiplier */ + integer vf_alpha; /* correction for negative values */ + char vf_beta; /* divisor */ + integer vf_np; + real_eight_bits *vpackets; + memory_word tmp_w; /* accumulator */ + vf_stack_record vf_stack[256]; + integer junk; + unsigned char *vf_buffer; + integer vf_size; + integer vf_cur; + integer *vf_local_fnts = NULL; /* external font ids */ + integer *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); + if (auto_expand_vf(f)) + return; /* auto-expanded virtual font */ + 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(); + /* update_terminal;*/ + 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((cmd - fnt_def1 + 1),junk); + 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) { + i = vf_nf*sizeof(integer); + vf_local_fnts= xmalloc(i); + memset(vf_local_fnts,0,i); + vf_real_fnts= xmalloc(i); + memset(vf_real_fnts,0,i); + 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] = 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,cc); + if (!char_exists(f,cc)) { + bad_vf("invalid character code"); + } + vf_read(4,k); + tfm_width = sqxfw(k, font_size(f)); + } else { + packet_length = cmd; + vf_byte(cc); + if (!char_exists(f,cc)) { + bad_vf("invalid character code"); + } + vf_read(3,k); + tfm_width = sqxfw(k, font_size(f)); + } + if (packet_length < 0) + bad_vf("negative packet length"); + if (tfm_width != char_width(f,cc)) { + /* precisely 'one off' errors are rampant */ + if (abs(tfm_width - char_width(f,cc))>1) { + print_nlp(); + print_string("character width mismatch in font "); + print_string(font_name(f)); + print_string(".vf ignored"); + } + } + k = count_packet_bytes(vf_buffer,vf_cur,packet_length); + vpackets = xmalloc(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 >= set_char_0) && (cmd < set1)) { + if (k == 0) { + k = 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),k); + packet_length -= (cmd - fnt1 + 1); + } else { + k = cmd - fnt_num_0; + } + + /* change from local to external font id */ + n = 0; + while ((n < vf_nf) && (vf_local_fnts[n] != k)) + n++; + if (n==vf_nf) + bad_vf("undefined local font"); + + k = 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 = vf_real_fnts[0]; + append_fnt_set(k); + } + vf_read_u((cmd - set1 + 1),i); + 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 = vf_real_fnts[0]; + append_fnt_set(k); + } + vf_read_u((cmd - put1 + 1),i); + 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),cmd_length); + packet_length -= (cmd - xxx1 + 1); + if (cmd_length <= 0) + bad_vf("special of negative length"); + packet_length -= cmd_length; + + append_packet(packet_special_code); + append_four(cmd_length); + while (cmd_length > 0) { + cmd_length--; + vf_byte(i); + append_packet(i); + } + append_packet(0); + 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_string("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); +} + +#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_pushnumber(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_pushnumber(L, V); \ + lua_rawseti(L,-2, 2); \ + lua_pushnumber(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, char *cnom, scaled atsize) { + integer cmd, k, i; + integer cc, cmd_length, packet_length; + scaled tfm_width; + vf_stack_index stack_level; + integer vf_z; /* multiplier */ + integer vf_alpha; /* correction for negative values */ + char vf_beta; /* divisor */ + char *s; + scaled h,v; + scaled w, x, y, z; + integer s_top; /* lua stack */ + integer 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; + integer vf_size; + integer vf_cur; + + + 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<= cmd_length;k++) + vf_byte(s[(k-1)]); + + lua_pushlstring(L,s,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_pushnumber(L, (unsigned long)(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"); + + + /* update_terminal;*/ + 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),vf_nf); + vf_nf++; + /* checksum */ + vf_byte(cs.b0); vf_byte(cs.b1); vf_byte(cs.b2); vf_byte(cs.b3); + + vf_read(4,k); + fs = sqxfw(k, atsize); + lua_pushstring(L,"size"); + lua_pushnumber(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(tmp_b1+1); k = 0; + while (tmp_b1-- > 0) + vf_byte(s[k++]); + s[k]=0; + lua_pushstring(L,"name"); + lua_pushstring(L,xstrdup(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,cc); + vf_read(4,tfm_width); + } else { + packet_length = cmd; + vf_byte(cc); + vf_read(3,tfm_width); + } + if (packet_length < 0) + lua_bad_vf("negative packet length"); + + lua_newtable(L); /* for this character */ + + lua_pushnumber(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),vf_nf); vf_nf++; + packet_length -= (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",sqxfw(h,atsize),sqxfw(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",sqxfw(h,atsize),sqxfw(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),i); + make_command1("char",i,k); + packet_length -= (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),i); + make_command0("push",k); + make_command1("char",i,k); + make_command0("pop",k); + packet_length -= (cmd - put1 + 1); + break; + case right1: + case right2: + case right3: + case right4: + vf_read((cmd - right1 + 1),i); + make_command1("right",sqxfw(i,atsize),k); + packet_length -= (cmd - right1 + 1); + break; + case w1: + case w2: + case w3: + case w4: + vf_read((cmd - w1 + 1),w); + make_command1("right",sqxfw(w,atsize),k); + packet_length -= (cmd - w1 + 1); + break; + case x1: + case x2: + case x3: + case x4: + vf_read((cmd - x1 + 1),x); + make_command1("right",sqxfw(x,atsize),k); + packet_length -= (cmd - x1 + 1); + break; + case down1: + case down2: + case down3: + case down4: + vf_read((cmd - down1 + 1),i); + make_command1("down",sqxfw(i,atsize),k); + packet_length -= (cmd - down1 + 1); + break; + case y1: + case y2: + case y3: + case y4: + vf_read((cmd - y1 + 1),y); + make_command1("down",sqxfw(y,atsize),k); + packet_length -= (cmd - y1 + 1); + break; + case z1: + case z2: + case z3: + case z4: + vf_read((cmd - z1 + 1),z); + make_command1("down",sqxfw(z,atsize),k); + packet_length -= (cmd - z1 + 1); + break; + case xxx1: + case xxx2: + case xxx3: + case xxx4: + vf_read_u((cmd - xxx1 + 1),cmd_length); + packet_length -= (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",strdup(s),i,k); + free(s); + break; + case w0: + make_command1("right",sqxfw(w,atsize),k); + break; + case x0: + make_command1("right",sqxfw(x,atsize),k); + break; + case y0: + make_command1("down",sqxfw(y,atsize),k); + break; + case z0: + make_command1("down",sqxfw(z,atsize),k); + break; + case nop: + break; + case push: + if (stack_level == vf_stack_size) { + overflow_string("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; +} + + +extern void replace_packet_fonts(internal_font_number f, integer *old_fontid, integer *new_fontid, int count) ; +extern integer *packet_local_fonts(internal_font_number f, integer *num); +extern internal_font_number auto_expand_font (internal_font_number f, integer e) ; + + +/* This function is called from |do_vf|, and fixes up the virtual data + inside an auto-expanded virtual font */ + +boolean +auto_expand_vf(internal_font_number f) { + + internal_font_number bf; + integer e, k; + integer *vf_old_fonts, *vf_new_fonts; + integer num = 0; + + if ((! pdf_font_auto_expand(f)) || (pdf_font_blink(f) == null_font)) + return false ; /* not an auto-expanded font */ + bf = pdf_font_blink(f); + + if (font_type(bf) != virtual_font_type) + return false; /* not a virtual font */ + + e = pdf_font_expand_ratio(f); + + vf_old_fonts = packet_local_fonts(bf,&num); + if (num>0) { + vf_new_fonts = xmalloc(num*sizeof(integer)); + for (k=0;k<num;k++) { + vf_new_fonts[k] = auto_expand_font(vf_old_fonts[k], e); + copy_expand_params(vf_new_fonts[k], vf_old_fonts[k], e); + } + replace_packet_fonts(f,vf_old_fonts,vf_new_fonts,num); + xfree(vf_new_fonts); + xfree(vf_old_fonts); + } + set_font_type(f,virtual_font_type); + return true; +} + +/* this function is not always safe, because it needs makecstring() */ +str_number +expand_font_name (internal_font_number f, integer e) { + int old_setting; + old_setting=selector; + selector=new_string; + print_string(font_name(f)); + if (e > 0) { + print_char('+'); + } + print_int(e); + selector=old_setting; + return make_string(); +} + + +internal_font_number +auto_expand_font (internal_font_number f, integer e) { + internal_font_number k; + kerninfo *krn; + charinfo *co, *ci; + char *fn; + integer i; + scaled w; + k = copy_font(f); + i = strlen(font_name(f))+12; + fn = xmalloc(i); + snprintf(fn,i,"%s%s%d",font_name(f),(e>0 ? "+" : ""), (int)e); + set_font_name(k,fn); + for (i = font_bc(k);i<=font_ec(k);i++) { + if (char_exists(k,i)) { + co = get_charinfo(k,i); + w = round_xn_over_d(char_width(f,i), 1000 + e, 1000); + set_charinfo_width (co, w); + w = round_xn_over_d(char_italic(f,i), 1000 + e, 1000); + set_charinfo_italic(co, w); + krn = get_charinfo_kerns(co); + if (krn != NULL) { + while (!kern_end((*krn))) { + kern_kern(*krn) = round_xn_over_d(kern_kern(*krn), 1000 + e, 1000); + krn++; + } + } + } + } + return k; +} + +void +vf_expand_local_fonts(internal_font_number f) { + internal_font_number lf; + integer k, num; + integer *vf_old_fonts; + pdfassert(font_type(f) == virtual_font_type); + num = 0; + vf_old_fonts = packet_local_fonts(f,&num); + if (num>0) { + for (k = 0;k<num;k++) { + lf = vf_old_fonts[k]; + set_expand_params(lf, pdf_font_auto_expand(f), + pdf_font_expand_ratio(pdf_font_stretch(f)), + -pdf_font_expand_ratio(pdf_font_shrink(f)), + pdf_font_step(f), pdf_font_expand_ratio(f)); + if (font_type(lf) == virtual_font_type) + vf_expand_local_fonts(lf); + } + xfree(vf_old_fonts); + } +} + +internal_font_number +letter_space_font (halfword u, internal_font_number f, integer e) { + internal_font_number k; + scaled w, r; + + char *new_font_name; + integer vf_z; + integer vf_alpha; + integer vf_beta; + memory_word tmp_w; /* accumulator */ + + + /* read a new font and expand the character widths */ + k = read_font_info(u, tex_font_name(f), get_nullstr(), font_size(f), font_natural_dir(f)); + set_no_ligatures(k); /* disable ligatures for letter-spaced fonts */ +/* + for (i = 0;i <= font_widths(k);i++) { + set_font_width(k,i,font_width(f,i)+round_xn_over_d(quad(k), e, 1000)); + } +*/ + /* append eg '+100ls' to font name */ + new_font_name = xmalloc(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); + + vf_z = font_size(f); + vf_replace_z(); + w = round_xn_over_d(quad(f), e, 2000); + if (w > 0) { + tmp_b0 = 0; + } else { + tmp_b0 = 255; + w = vf_alpha + w; + } + r = w*vf_beta; + tmp_b1 = r / vf_z; + r = r % vf_z; + if (r == 0) { + tmp_b2 = 0; + } else { + r = r * 256; + tmp_b2 = r / vf_z; + r = r % vf_z; + } + if (r == 0) { + tmp_b3 = 0; + } else { + r = r * 256; + tmp_b3 = r / vf_z; + } + /* + vf_packet_base[k] = new_vf_packet(k); + + for (c=font_bc(k);c<=font_ec(k);c++) { + string_room(17); + append_fnt_set(f); + append_packet(right1 + 3); + append_packet(tmp_b0); + append_packet(tmp_b1); + append_packet(tmp_b2); + append_packet(tmp_b3); + + append_packet(set1); + append_packet(c); + + append_packet(right1 + 3); + append_packet(tmp_b0); + append_packet(tmp_b1); + append_packet(tmp_b2); + append_packet(tmp_b3); + s = make_string(); + store_packet(k, c, s); + flush_str(s); + } +*/ + return k; +} + + diff --git a/Build/source/texk/web2c/luatexdir/font/vfpacket.c b/Build/source/texk/web2c/luatexdir/font/vfpacket.c new file mode 100644 index 00000000000..4d8445f2227 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/vfpacket.c @@ -0,0 +1,377 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: vfpacket.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +/* + 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|. +*/ + +#define packet_max_recursion 100 + +typedef unsigned char packet_stack_index ; /* an index into the stack */ + +typedef struct packet_stack_record { + scaled stack_h; + scaled stack_v; +} packet_stack_record; + + +static packet_stack_index packet_cur_s = 0; /* current recursion level */ +static packet_stack_record packet_stack [packet_max_recursion]; +static packet_stack_index packet_stack_ptr = 0; /* pointer into |packet_stack| */ + + +/* Some macros for processing character packets. */ + +#define do_packet_byte() vf_packets[cur_packet_byte++] + +#define packet_number(fw) { \ + fw = do_packet_byte(); \ + fw = fw*256 + do_packet_byte(); \ + fw = fw*256 + do_packet_byte(); \ + fw = fw*256 + do_packet_byte(); } + +#define packet_scaled(a,fs) { integer fw; \ + fw = do_packet_byte(); \ + if (fw>127) fw = fw - 256; \ + fw = fw*256 + do_packet_byte(); \ + fw = fw*256 + do_packet_byte(); \ + fw = fw*256 + do_packet_byte(); \ + a = sqxfw(fw, fs); } + + +/* count the number of bytes in a command packet */ +int +vf_packet_bytes (charinfo *co) { + real_eight_bits *vf_packets; + integer cur_packet_byte; + unsigned k; + int cmd; + + vf_packets = get_charinfo_packets(co); + if (vf_packets == NULL) { + return 0; + } + cur_packet_byte = 0; + while ((cmd = vf_packets[cur_packet_byte]) != packet_end_code) { + cur_packet_byte++; + switch (cmd) { + case packet_char_code: + case packet_font_code: + case packet_right_code: + case packet_down_code: + case packet_node_code: + cur_packet_byte += 4; + break; + case packet_push_code: + case packet_pop_code: + break; + case packet_rule_code: + cur_packet_byte += 8; + break; + case packet_special_code: + packet_number(k); /* +4 */ + cur_packet_byte += k; + break; + case packet_nop_code: + break; + default: + pdf_error("vf", "invalid DVI command"); + } + }; + return (cur_packet_byte +1); +} + + +/* typeset the \.{DVI} commands in the + character packet for character |c| in current font |f| */ + +char *packet_command_names[] = { + "char", "font","pop", "push", "special", + "right","down","rule","node", "nop","end", NULL}; + + +void +do_vf_packet (internal_font_number vf_f, integer c) { + internal_font_number lf; + charinfo *co; + scaled save_cur_h, save_cur_v; + real_eight_bits *vf_packets; + integer cur_packet_byte; + integer cmd, fs_f; + scaled i; + unsigned k; + str_number s; + + packet_cur_s++; + if (packet_cur_s >= packet_max_recursion) + overflow_string("max level recursion of virtual fonts", packet_max_recursion); + save_cur_v = cur_v; + save_cur_h = cur_h; + + lf = 0; /* for -Wall */ + co = get_charinfo(vf_f,c); + vf_packets = get_charinfo_packets(co); + if (vf_packets == NULL) { + packet_cur_s--; + return ; + } + cur_packet_byte = 0; + fs_f = font_size(vf_f); + while ((cmd = vf_packets[cur_packet_byte]) != packet_end_code) { + cur_packet_byte++; + /* + 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]); + } + */ + switch (cmd) { + case packet_font_code: + packet_number(lf); + break; + case packet_push_code: + packet_stack[packet_stack_ptr].stack_h = cur_h; + packet_stack[packet_stack_ptr].stack_v = cur_v; + packet_stack_ptr++; + break; + case packet_pop_code: + packet_stack_ptr--; + cur_h = packet_stack[packet_stack_ptr].stack_h; + cur_v = packet_stack[packet_stack_ptr].stack_v; + break; + case packet_char_code: + packet_number(k); + if (!char_exists(lf,k)) { + char_warning(lf, k); + } else { + output_one_char(lf, k); + } + cur_h = cur_h + char_width(lf,k); + break; + case packet_rule_code: + packet_scaled(rule_ht,fs_f); + packet_scaled(rule_wd,fs_f); + if ((rule_wd > 0) && (rule_ht > 0)) { + pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); + cur_h = cur_h + rule_wd; + } + break; + case packet_right_code: + packet_scaled(i,fs_f); + cur_h = cur_h + i; + break; + case packet_down_code: + packet_scaled(i,fs_f); + cur_v = cur_v + i; + break; + case packet_special_code: + packet_number(k); + string_room(k); + while (k > 0) { + k--; + append_pool_char(do_packet_byte()); + } + s = make_string(); + literal(s, scan_special, false); + flush_str(s); + break; + case packet_node_code: + packet_number(k); + temp_ptr = k; + pdf_hlist_out(); + break; + case packet_nop_code: + break; + default: + pdf_error("vf", "invalid DVI command"); + } + }; + cur_h = save_cur_h; + cur_v = save_cur_v; + packet_cur_s--; +} + + +integer *packet_local_fonts(internal_font_number f, integer *num) { + int c, cmd, cur_packet_byte, lf, k,l, i; + integer localfonts[256] = {0}; + integer *lfs; + charinfo *co; + + real_eight_bits *vf_packets; + k = 0; + for (c = font_bc(f);c <= font_ec(f);c++) { + if (char_exists(f,c)) { + co = get_charinfo(f,c); + vf_packets = get_charinfo_packets(co); + if (vf_packets == NULL) + continue; + cur_packet_byte = 0; + while ((cmd = vf_packets[cur_packet_byte]) != packet_end_code) { + cur_packet_byte++; + 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_push_code: + case packet_pop_code: + case packet_nop_code: + break; + case packet_char_code: + case packet_right_code: + case packet_down_code: + case packet_node_code: + cur_packet_byte+=4; + break; + case packet_rule_code: + cur_packet_byte+=8; + break; + case packet_special_code: + packet_number(i); + while (i-- > 0) + (void)do_packet_byte(); + break; + default: + pdf_error("vf", "invalid DVI command"); + } + } + } + } + *num = k; + if (k>0) { + lfs = xmalloc (k*sizeof(integer)); + memcpy(lfs,localfonts,k*sizeof(integer)); + return lfs; + } + return NULL; +} + + +void +replace_packet_fonts(internal_font_number f, integer *old_fontid, integer *new_fontid, int count) { + int c, cmd, cur_packet_byte, lf, k,l; + charinfo *co; + real_eight_bits *vf_packets; + + k = 0; + for (c = font_bc(f);c <= font_ec(f);c++) { + if (char_exists(f,c)) { + co = get_charinfo(f,c); + vf_packets = get_charinfo_packets(co); + if (vf_packets == NULL) + continue; + cur_packet_byte = 0; + while ((cmd = vf_packets[cur_packet_byte]) != packet_end_code) { + cur_packet_byte++; + 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]; + vf_packets[(cur_packet_byte-4)] = (k&0xFF000000)>>24; + vf_packets[(cur_packet_byte-3)] = (k&0x00FF0000)>>16; + vf_packets[(cur_packet_byte-2)] = (k&0x0000FF00)>>8; + vf_packets[(cur_packet_byte-1)] = (k&0x000000FF); + } + break; + case packet_push_code: + case packet_pop_code: + case packet_nop_code: + break; + case packet_char_code: + case packet_right_code: + case packet_down_code: + case packet_node_code: + cur_packet_byte+=4; + break; + case packet_rule_code: + cur_packet_byte+=8; + break; + case packet_special_code: + packet_number(k); + while (k-- > 0) + (void)do_packet_byte(); + break; + default: + pdf_error("vf", "invalid DVI command"); + } + } + } + } +} + +/* this function was copied/borrowed/stolen from dvipdfm code */ + +scaled sqxfw (scaled sq, integer fw) +{ + int sign = 1; + unsigned long a, b, c, d, ad, bd, bc, ac; + unsigned long e, f, g, h, i, j, k; + unsigned long result; + /* Make positive. */ + if (sq < 0) { + sign = -sign; + sq = -sq; + } + if (fw < 0) { + sign = -sign; + fw = -fw; + } + a = ((unsigned long) sq) >> 16u; + b = ((unsigned long) sq) & 0xffffu; + c = ((unsigned long) fw) >> 16u; + d = ((unsigned long) fw) & 0xffffu; + ad = a*d; bd = b*d; bc = b*c; ac = a*c; + e = bd >> 16u; + f = ad >> 16u; + g = ad & 0xffffu; + h = bc >> 16u; + i = bc & 0xffffu; + j = ac >> 16u; + k = ac & 0xffffu; + result = (e+g+i + (1<<3)) >> 4u; /* 1<<3 is for rounding */ + result += (f+h+k) << 12u; + result += j << 28u; + return (sign>0)?result:-result; +} diff --git a/Build/source/texk/web2c/luatexdir/font/writecff.c b/Build/source/texk/web2c/luatexdir/font/writecff.c new file mode 100644 index 00000000000..69c35c6950e --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writecff.c @@ -0,0 +1,3381 @@ +/* +Copyright (c) 2007 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with luaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writecff.c 1021 2008-02-14 10:24:34Z taco $ +*/ + +#include "ptexlib.h" + +#include "writecff.h" + +#define get_offset(s,n) get_unsigned(s, (n)) +#define get_card8(a) a->stream[a->offset++] +#define get_card16(a) get_unsigned(a,2) + +#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; +} + +#define CFF_ERROR pdftex_fail +#define WARN pdftex_warn + + +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 */ +cff_index * +cff_get_index_header (cff_font *cff) +{ + cff_index *idx; + card16 i, count; + + 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) + CFF_ERROR("invalid offsize data"); + + idx->offset = xcalloc(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) + CFF_ERROR("cff_get_index(): 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; + long 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) + CFF_ERROR("invalid offsize data"); + + idx->offset = xcalloc((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) + CFF_ERROR("Invalid CFF Index offset data"); + + length = idx->offset[count] - idx->offset[0]; + + idx->data = xcalloc(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; +} + + +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) + CFF_ERROR("Not enough space available..."); + memset(dest, 0, 2); + return 2; + } + + len = cff_index_size(idx); + datalen = idx->offset[idx->count] - 1; + + if (destlen < len) + CFF_ERROR("Not enough space available..."); + + *(dest++) = (idx->count >> 8) & 0xff; + *(dest++) = 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) + 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(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: CFF_ERROR("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) { + if (cff->fontname) 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((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) + CFF_ERROR("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 = xcalloc(strlen(name), sizeof(card8)); + memmove(idx->data, name, strlen(name)); /* no trailing '\0' */ + + return 5 + strlen(name); +} + +long +cff_put_header (cff_font *cff, card8 *dest, long destlen) +{ + if (destlen < 4) + CFF_ERROR("Not enough space available..."); + + *(dest++) = cff->header_major; + *(dest++) = cff->header_minor; + *(dest++) = 4; /* Additional data in between header and + * Name INDEX ignored. + */ + /* We will set all offset (0) to 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(dict->max, sizeof(cff_dict_entry)); + return dict; +} + +/* + * Operand stack: + * only numbers are stored (as double) + * + * Operand types: + * + * number : double (integer or real) + * boolean: stored as a number + * SID : stored as a number + * array : array of numbers + * delta : array of numbers + */ + +#define CFF_DICT_STACK_LIMIT 64 +static int stack_top = 0; +static double arg_stack[CFF_DICT_STACK_LIMIT]; + +/* + * CFF DICT encoding: + * TODO: default values + */ + +#define CFF_LAST_DICT_OP1 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 */ + /* Top */ + {"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) */ + /* Private */ + {"Subrs", CFF_TYPE_OFFSET}, + {"defaultWidthX", CFF_TYPE_NUMBER}, + {"nominalWidthX", CFF_TYPE_NUMBER}, + /* Operator 2 */ + {"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}, /* MMaster ? */ + {NULL, -1}, + {NULL, -1}, + {NULL, -1}, + {NULL, -1}, + {NULL, -1}, + {NULL, -1}, + /* CID-Keyed font */ + {"ROS", CFF_TYPE_ROS}, /* SID SID number */ + {"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 */ +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 */ +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++] = 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; + result = strtod(work_buffer, &s); + if (*s != 0 || errno == ERANGE) { + *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; + } + } + + return result; +} + +/* operators */ +static void add_dict (cff_dict *dict, + card8 **data, card8 *endptr, int *status) +{ + int id, argtype; + + 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; + } else if (stack_top < 1) { + *status = CFF_CFF_ERROR_STACK_UNDERFLOW; + return; + } + + if (dict->count >= dict->max) { + dict->max += DICT_ENTRY_MAX; + /* not zeroed! */ + dict->entries = xrealloc(dict->entries, dict->max*sizeof(cff_dict_entry)); + } + + (dict->entries)[dict->count].id = id; + (dict->entries)[dict->count].key = (char *) dict_operator[id].opname; + if (argtype == CFF_TYPE_NUMBER || + argtype == CFF_TYPE_BOOLEAN || + argtype == CFF_TYPE_SID || + argtype == CFF_TYPE_OFFSET) { + 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]; + } else { + (dict->entries)[dict->count].count = stack_top; + (dict->entries)[dict->count].values = xcalloc(stack_top, sizeof(double)); + while (stack_top > 0) { + stack_top--; + (dict->entries)[dict->count].values[stack_top] = arg_stack[stack_top]; + } + } + + 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 + */ +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 < 22) { /* 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 >= 22 && *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) { + pdftex_fail("Parsing CFF DICT failed. (error=%d)", status); + } else if (stack_top != 0) { + WARN("Garbage in CFF 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 + pdftex_fail("Invalid index number."); + break; + } + } + + if (i == dict->count) + pdftex_fail("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) + CFF_ERROR("in cff_fdselect_lookup(): FDSelect not available"); + + fdsel = cff->fdselect; + + if (gid >= cff->num_glyphs) + CFF_ERROR("in cff_fdselect_lookup(): 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: + CFF_ERROR("in cff_fdselect_lookup(): Invalid FDSelect format"); + break; + } + + if (fd >= cff->num_fds) + CFF_ERROR("in cff_fdselect_lookup(): 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 = 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 = 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) + CFF_ERROR("in cff_read_fdarray(): Top DICT not found"); + + if (!(cff->flag & FONTTYPE_CIDFONT)) + return 0; + + /* must exist */ + offset = (long) cff_dict_get(cff->topdict, "FDArray", 0); + cff->offset = offset; + idx = cff_get_index(cff); + cff->num_fds = (card8)idx->count; + cff->fdarray = xcalloc(idx->count, sizeof(cff_dict *)); + for (i=0;i<idx->count;i++) { + card8 *data = idx->data + (idx->offset)[i] - 1; + size = (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 = xcalloc(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 = offset; + data = xcalloc(size, sizeof(card8)); + memcpy(data,&cff->stream[cff->offset],size); + cff->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 = xcalloc(1, 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 = offset; + data = xcalloc(size, sizeof(card8)); + memcpy(data,&cff->stream[cff->offset],size); + cff->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 = buflength; + cff->index = n; + + cff->header_major = get_card8(cff); + cff->header_minor = get_card8(cff); + cff->header_hdr_size = get_card8(cff); + cff->header_offsize = get_card8(cff); + if (cff->header_offsize < 1 || cff->header_offsize > 4) { + WARN("invalid offsize data"); + cff_close(cff); + return NULL; + } + if (cff->header_major > 1) { + pdftex_warn("CFF major version %u not supported.",cff->header_major); + cff_close(cff); + return NULL; + } + cff->offset = cff->header_hdr_size; + + /* Name INDEX */ + idx = cff_get_index(cff); + if (n > idx->count - 1) { + pdftex_warn("Invalid CFF fontset index number."); + cff_close(cff); + return NULL; + } + + cff->name = idx; + + cff->fontname = cff_get_name(cff); + + /* Top DICT INDEX */ + idx = cff_get_index(cff); + if (n > idx->count - 1) { + WARN("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) { + WARN("Parsing CFF 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) { + WARN("Only Type 2 Charstrings supported..."); + cff_close(cff); + return NULL; + } + + if (cff_dict_known(cff->topdict, "SyntheticBase")) { + WARN("CFF Synthetic font not supported."); + cff_close(cff); + return NULL; + } + + /* String INDEX */ + 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 = 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 */ +static long pack_integer (card8 *dest, long destlen, long value) +{ + long len = 0; + + if (value >= -107 && value <= 107) { + if (destlen < 1) + CFF_ERROR("Buffer overflow."); + dest[0] = (value + 139) & 0xff; + len = 1; + } else if (value >= 108 && value <= 1131) { + if (destlen < 2) + CFF_ERROR("Buffer overflow."); + value = 0xf700u + value - 108; + dest[0] = (value >> 8) & 0xff; + dest[1] = value & 0xff; + len = 2; + } else if (value >= -1131 && value <= -108) { + if (destlen < 2) + CFF_ERROR("Buffer overflow."); + value = 0xfb00u - value - 108; + dest[0] = (value >> 8) & 0xff; + dest[1] = value & 0xff; + len = 2; + } else if (value >= -32768 && value <= 32767) { /* shortint */ + if (destlen < 3) + CFF_ERROR("Buffer overflow."); + dest[0] = 28; + dest[1] = (value >> 8) & 0xff; + dest[2] = value & 0xff; + len = 3; + } else { /* longint */ + if (destlen < 5) + CFF_ERROR("Buffer overflow."); + dest[0] = 29; + dest[1] = (value >> 24) & 0xff; + dest[2] = (value >> 16) & 0xff; + dest[3] = (value >> 8) & 0xff; + dest[4] = value & 0xff; + len = 5; + } + return len; +} + +static long pack_real (card8 *dest, long destlen, double value) +{ + long e; + int i = 0, pos = 2; +#define CFF_REAL_MAX_LEN 17 + + if (destlen < 2) + CFF_ERROR("Buffer overflow."); + + 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--; + } + } + + sprintf(work_buffer, "%1.14g", value); + 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 = work_buffer[i] - '0'; + } else { + CFF_ERROR("Invalid character."); + } + + if (destlen < pos/2 + 1) + CFF_ERROR("Buffer overflow."); + + if (pos % 2) { + dest[pos/2] += ch; + } else { + dest[pos/2] = (ch << 4); + } + pos++; + } + + if (e > 0) { + if (pos % 2) { + dest[pos/2] += 0x0b; + } else { + if (destlen < pos/2 + 1) + CFF_ERROR("Buffer overflow."); + dest[pos/2] = 0xb0; + } + pos++; + } else if (e < 0) { + if (pos % 2) { + dest[pos/2] += 0x0c; + } else { + if (destlen < pos/2 + 1) + CFF_ERROR("Buffer overflow."); + dest[pos/2] = 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 = work_buffer[i] - '0'; + } else { + CFF_ERROR("Invalid character."); + } + + if (destlen < pos/2 + 1) + CFF_ERROR("Buffer overflow."); + + if (pos % 2) { + dest[pos/2] += ch; + } else { + dest[pos/2] = (ch << 4); + } + pos++; + } + } + + if (pos % 2) { + dest[pos/2] += 0x0f; + pos++; + } else { + if (destlen < pos/2 + 1) + CFF_ERROR("Buffer overflow."); + dest[pos/2] = 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); + /* set offset to longint */ + if (type == CFF_TYPE_OFFSET) { + long lvalue; + + lvalue = (long) value; + if (destlen < 5) + CFF_ERROR("Buffer overflow."); + dest[0] = 29; + dest[1] = (lvalue >> 24) & 0xff; + dest[2] = (lvalue >> 16) & 0xff; + dest[3] = (lvalue >> 8) & 0xff; + dest[4] = 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; +} + +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) + CFF_ERROR("Buffer overflow."); + dest[len++] = id; + } else if (id >= 0 && id < CFF_LAST_DICT_OP) { + if (len + 2 > destlen) + CFF_ERROR("in cff_dict_pack(): Buffer overflow"); + dest[len++] = 12; + dest[len++] = id - CFF_LAST_DICT_OP1; + } else { + CFF_ERROR("Invalid CFF 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) + CFF_ERROR("Unknown CFF DICT operator."); + + for (i=0;i<dict->count;i++) { + if ((dict->entries)[i].id == id) { + if ((dict->entries)[i].count != count) + CFF_ERROR("Inconsistent DICT argument number."); + return; + } + } + + if (dict->count + 1 >= dict->max) { + dict->max += 8; + dict->entries = xrealloc(dict->entries, (dict->max)*sizeof(cff_dict_entry)); + } + + (dict->entries)[dict->count].id = id; + (dict->entries)[dict->count].key = (char *) dict_operator[id].opname; + (dict->entries)[dict->count].count = count; + if (count > 0) { + (dict->entries)[dict->count].values = xcalloc(count, sizeof(double)); + memset((dict->entries)[dict->count].values, + 0, sizeof(double)*count); + } 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; + if ((dict->entries)[i].values) + xfree((dict->entries)[i].values); + (dict->entries)[i].values = NULL; + } + } +} + +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 + CFF_ERROR("Invalid index number."); + break; + } + } + + if (i == dict->count) + pdftex_fail("DICT entry \"%s\" not found.", key); +} + + +/* Strings */ +char *cff_get_string (cff_font *cff, s_SID id) +{ + char *result = NULL; + long len; + + if (id < CFF_STDSTR_MAX) { + len = strlen(cff_stdstr[id]); + result = xcalloc(len+1, sizeof(char)); + memcpy(result, cff_stdstr[id], len); + result[len] = '\0'; + } else if (cff && cff->string) { + cff_index *strings = cff->string; + id -= CFF_STDSTR_MAX; + if (id < strings->count) { + len = (strings->offset)[id+1] - (strings->offset)[id]; + result = xcalloc(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, 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; +} + + +void cff_update_string (cff_font *cff) +{ + if (cff == NULL) + CFF_ERROR("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, char *str) +{ + card16 idx; + cff_index *strings; + l_offset offset, size; + + if (cff == NULL) + CFF_ERROR("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 (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, (strings->count+2)*sizeof(l_offset)); + if (strings->count == 0) + strings->offset[0] = 1; + idx = strings->count; + strings->count += 1; + strings->offset[strings->count] = offset + strlen(str); + strings->data = xrealloc(strings->data, (offset+strlen(str)-1)*sizeof(card8)); + memcpy(strings->data+offset-1, str, strlen(str)); + + return (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, (dict->entries)[i].values[0]); + (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, (dict->entries)[i].values[0]); + (dict->entries)[i].values[0] = cff_add_string(cff, str); + xfree(str); + str = cff_get_string(cff, (dict->entries)[i].values[1]); + (dict->entries)[i].values[1] = cff_add_string(cff, str); + xfree(str); + } + + } + } +} + +/* charsets */ + +long cff_read_charsets (cff_font *cff) +{ + cff_charsets *charset; + long offset, length; + card16 count, i; + + if (cff->topdict == NULL) + CFF_ERROR("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 = offset; + cff->charsets = charset = xcalloc(1, sizeof(cff_charsets)); + charset->format = get_card8(cff); + charset->num_entries = 0; + + count = cff->num_glyphs - 1; + length = 1; + + /* Not sure. Not well documented. */ + switch (charset->format) { + case 0: + charset->num_entries = cff->num_glyphs - 1; /* no .notdef */ + charset->data.glyphs = xcalloc(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, (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 -= ranges[charset->num_entries].n_left + 1; /* no-overrap */ + charset->num_entries += 1; + 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, (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 -= ranges[charset->num_entries].n_left + 1; /* non-overrapping */ + charset->num_entries += 1; + } + charset->data.range2 = ranges; + length += (charset->num_entries) * 4; + } + break; + default: + xfree(charset); + CFF_ERROR("Unknown Charset format"); + break; + } + + if (count > 0) + CFF_ERROR("Charset data possibly broken"); + + 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) + CFF_ERROR("in cff_pack_charsets(): Buffer overflow"); + + charset = cff->charsets; + + dest[len++] = charset->format; + switch (charset->format) { + case 0: + if (destlen < len + (charset->num_entries)*2) + CFF_ERROR("in cff_pack_charsets(): Buffer overflow"); + for (i=0;i<(charset->num_entries);i++) { + s_SID sid = (charset->data).glyphs[i]; /* or CID */ + dest[len++] = (sid >> 8) & 0xff; + dest[len++] = sid & 0xff; + } + break; + case 1: + { + if (destlen < len + (charset->num_entries)*3) + CFF_ERROR("in cff_pack_charsets(): Buffer overflow"); + for (i=0;i<(charset->num_entries);i++) { + dest[len++] = ((charset->data).range1[i].first >> 8) & 0xff; + dest[len++] = (charset->data).range1[i].first & 0xff; + dest[len++] = (charset->data).range1[i].n_left; + } + } + break; + case 2: + { + if (destlen < len + (charset->num_entries)*4) + CFF_ERROR("in cff_pack_charsets(): Buffer overflow"); + for (i=0;i<(charset->num_entries);i++) { + dest[len++] = ((charset->data).range2[i].first >> 8) & 0xff; + dest[len++] = (charset->data).range2[i].first & 0xff; + dest[len++] = ((charset->data).range2[i].n_left >> 8) & 0xff; + dest[len++] = (charset->data).range2[i].n_left & 0xff; + } + } + break; + default: + CFF_ERROR("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.. + */ + + +#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. + */ +#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 */ +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 + */ + +/* + * 1-byte CharString operaotrs: + * 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 +/* RESERVED 15 */ +/* RESERVED 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. + */ +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. + */ + CFF_ERROR("Argument value too large. (This is bug)"); + } else if (fabs(value - ivalue) > 3.0e-5) { + /* 16.16-bit signed fixed value */ + DST_NEED(limit, *dest + 5); + *(*dest)++ = 255; + ivalue = (long) floor(value); /* mantissa */ + *(*dest)++ = (ivalue >> 8) & 0xff; + *(*dest)++ = ivalue & 0xff; + ivalue = (long)((value - ivalue) * 0x10000l); /* fraction */ + *(*dest)++ = (ivalue >> 8) & 0xff; + *(*dest)++ = ivalue & 0xff; + /* Everything else are integers. */ + } else if (ivalue >= -107 && ivalue <= 107) { + DST_NEED(limit, *dest + 1); + *(*dest)++ = ivalue + 139; + } else if (ivalue >= 108 && ivalue <= 1131) { + DST_NEED(limit, *dest + 2); + ivalue = 0xf700u + ivalue - 108; + *(*dest)++ = (ivalue >> 8) & 0xff; + *(*dest)++ = ivalue & 0xff; + } else if (ivalue >= -1131 && ivalue <= -108) { + DST_NEED(limit, *dest + 2); + ivalue = 0xfb00u - ivalue - 108; + *(*dest)++ = (ivalue >> 8) & 0xff; + *(*dest)++ = ivalue & 0xff; + } else if (ivalue >= -32768 && ivalue <= 32767) { /* shortint */ + DST_NEED(limit, *dest + 3); + *(*dest)++ = 28; + *(*dest)++ = (ivalue >> 8) & 0xff; + *(*dest)++ = (ivalue) & 0xff; + } else { /* Shouldn't come here */ + CFF_ERROR("Unexpected error."); + } + } + + cs2_stack_top = 0; /* clear stack */ + + return; +} + +/* + * Single byte operators: + * Path construction, Operator for finishing a path, Hint operators. + * + * phase: + * 0: inital state + * 1: hint declaration, first stack-clearing operator appeared + * 2: in path construction + */ + +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, 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) { + WARN("\"seac\" character deprecated in Type 2 charstring."); + status = CS_PARSE_CFF_ERROR; + return; + } else if (cs2_stack_top > 0) { + WARN("Operand stack not empty."); + } + DST_NEED(limit, *dest + 1); + *(*dest)++ = op; + status = CS_CHAR_END; + break; + /* above oprators are candidate for first stack-clearing operator */ + 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) { + WARN("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: + CFF_ERROR("Unexpected call(g)subr/return"); + break; + default: + /* no-op ? */ + WARN("%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. + * + * Following operators are not supported: + * random: 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: /* deprecated */ + WARN("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) { + WARN("%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: + WARN("%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 ? */ + WARN("%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) + */ +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 + */ +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 = (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. + * + * subr: set to a pointer to the subroutine charstring. + * len: set to the length of subroutine charstring. + * subr_idx: CFF INDEX data that contains subroutines. + * id: biased subroutine number. + */ +static void +get_subr (card8 **subr, long *len, cff_index *subr_idx, long id) +{ + card16 count; + + if (subr_idx == NULL) + CFF_ERROR("%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) + CFF_ERROR("%s: Invalid Subr index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count); + + *len = (subr_idx->offset)[id + 1] - (subr_idx->offset)[id]; + *subr = subr_idx->data + (subr_idx->offset)[id] - 1; + + return; +} + +/* + * NOTE: + * 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) +{ + card8 b0 = 0, *subr; + long len; + + if (cs2_nest > CS_SUBR_NEST_MAX) + CFF_ERROR("%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) + CFF_ERROR("%s: Possible buffer overflow.", CS_TYPE2_DEBUG_STR); + do_charstring(dest, limit, &subr, subr + len, + gsubr_idx, subr_idx); + *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) + CFF_ERROR("%s: Possible buffer overflow.", CS_TYPE2_DEBUG_STR); + do_charstring(dest, limit, &subr, subr + len, + gsubr_idx, subr_idx); + *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 (status == CS_SUBR_RETURN) { + status = CS_PARSE_OK; + } else if (status == CS_CHAR_END && *data < endptr) { + WARN("%s: Garbage after endchar.", CS_TYPE2_DEBUG_STR); + } else if (status < CS_PARSE_OK) { /* error */ + CFF_ERROR("%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; +} + +/* + * Not just copying... + */ +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) +{ + 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); + + if (ginfo) { + ginfo->flags = 0; /* not used */ + if (have_width) { + ginfo->wx = nominal_width + width; + } else { + ginfo->wx = default_width; + } + } + + return (long)(dst - save); +} + +/* encodings */ + +/* + * Encoding and Charset + * + * Encoding and Charset arrays always begin with GID = 1. + */ +long cff_read_encoding (cff_font *cff) +{ + cff_encoding *encoding; + long offset, length; + card8 i; + + if (cff->topdict == NULL) { + CFF_ERROR("Top DICT data not found"); + } + + if (!cff_dict_known(cff->topdict, "Encoding")) { + cff->flag |= ENCODING_STANDARD; + cff->encoding = NULL; + return 0; + } + + offset = (long) cff_dict_get(cff->topdict, "Encoding", 0); + if (offset == 0) { /* predefined */ + cff->flag |= ENCODING_STANDARD; + cff->encoding = NULL; + return 0; + } else if (offset == 1) { + cff->flag |= ENCODING_EXPERT; + cff->encoding = NULL; + return 0; + } + + cff->offset= offset; + cff->encoding = encoding = xcalloc(1, sizeof(cff_encoding)); + encoding->format = get_card8(cff); + length = 1; + + switch (encoding->format & (~0x80)) { + case 0: + encoding->num_entries = get_card8(cff); + (encoding->data).codes = xcalloc(encoding->num_entries, sizeof(card8)); + for (i=0;i<(encoding->num_entries);i++) { + (encoding->data).codes[i] = get_card8(cff); + } + length += encoding->num_entries + 1; + break; + case 1: + { + cff_range1 *ranges; + encoding->num_entries = get_card8(cff); + encoding->data.range1 = ranges + = xcalloc(encoding->num_entries, sizeof(cff_range1)); + for (i=0;i<(encoding->num_entries);i++) { + ranges[i].first = get_card8(cff); + ranges[i].n_left = get_card8(cff); + } + length += (encoding->num_entries) * 2 + 1; + } + break; + default: + xfree(encoding); + CFF_ERROR("Unknown Encoding format"); + break; + } + + /* Supplementary data */ + if ((encoding->format) & 0x80) { + cff_map *map; + encoding->num_supps = get_card8(cff); + encoding->supp = map = xcalloc(encoding->num_supps, sizeof(cff_map)); + for (i=0;i<(encoding->num_supps);i++) { + map[i].code = get_card8(cff); + map[i].glyph = get_card16(cff); /* SID */ + } + length += (encoding->num_supps) * 3 + 1; + } else { + encoding->num_supps = 0; + encoding->supp = NULL; + } + + return length; +} + +long cff_pack_encoding (cff_font *cff, card8 *dest, long destlen) +{ + long len = 0; + cff_encoding *encoding; + card16 i; + + if (cff->flag & HAVE_STANDARD_ENCODING || cff->encoding == NULL) + return 0; + + if (destlen < 2) + CFF_ERROR("in cff_pack_encoding(): Buffer overflow"); + + encoding = cff->encoding; + + dest[len++] = encoding->format; + dest[len++] = encoding->num_entries; + switch (encoding->format & (~0x80)) { + case 0: + if (destlen < len + encoding->num_entries) + CFF_ERROR("in cff_pack_encoding(): Buffer overflow"); + for (i=0;i<(encoding->num_entries);i++) { + dest[len++] = (encoding->data).codes[i]; + } + break; + case 1: + { + if (destlen < len + (encoding->num_entries)*2) + CFF_ERROR("in cff_pack_encoding(): Buffer overflow"); + for (i=0;i<(encoding->num_entries);i++) { + dest[len++] = (encoding->data).range1[i].first & 0xff; + dest[len++] = (encoding->data).range1[i].n_left; + } + } + break; + default: + CFF_ERROR("Unknown Encoding format"); + break; + } + + if ((encoding->format) & 0x80) { + if (destlen < len + (encoding->num_supps)*3 + 1) + CFF_ERROR("in cff_pack_encoding(): Buffer overflow"); + dest[len++] = encoding->num_supps; + for (i=0;i<(encoding->num_supps);i++) { + dest[len++] = (encoding->supp)[i].code; + dest[len++] = ((encoding->supp)[i].glyph >> 8) & 0xff; + dest[len++] = (encoding->supp)[i].glyph & 0xff; + } + } + + return len; +} + +/* CID-Keyed font specific */ +long cff_read_fdselect (cff_font *cff) +{ + cff_fdselect *fdsel; + long offset, length; + card16 i; + + if (cff->topdict == NULL) + CFF_ERROR("Top DICT not available"); + + if (!(cff->flag & FONTTYPE_CIDFONT)) + return 0; + + offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0); + cff->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 = xcalloc(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) + CFF_ERROR("Range not starting with 0."); + if (cff->num_glyphs != get_card16(cff)) + CFF_ERROR("Sentinel value mismatched with number of glyphs."); + length += (fdsel->num_entries) * 3 + 4; + } + break; + default: + xfree(fdsel); + CFF_ERROR("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) + CFF_ERROR("in cff_pack_fdselect(): Buffur overflow"); + + fdsel = cff->fdselect; + + dest[len++] = fdsel->format; + switch (fdsel->format) { + case 0: + if (fdsel->num_entries != cff->num_glyphs) + CFF_ERROR("in cff_pack_fdselect(): Invalid data"); + if (destlen < len + fdsel->num_entries) + CFF_ERROR("in cff_pack_fdselect(): Buffer overflow"); + for (i=0;i<fdsel->num_entries;i++) { + dest[len++] = (fdsel->data).fds[i]; + } + break; + case 3: + { + if (destlen < len + 2) + CFF_ERROR("in cff_pack_fdselect(): Buffer overflow"); + len += 2; + for (i=0;i<(fdsel->num_entries);i++) { + if (destlen < len + 3) + CFF_ERROR("in cff_pack_fdselect(): Buffer overflow"); + dest[len++] = ((fdsel->data).ranges[i].first >> 8) & 0xff; + dest[len++] = (fdsel->data).ranges[i].first & 0xff; + dest[len++] = (fdsel->data).ranges[i].fd; + } + if (destlen < len + 2) + CFF_ERROR("in cff_pack_fdselect(): Buffer overflow"); + dest[len++] = (cff->num_glyphs >> 8) & 0xff; + dest[len++] = cff->num_glyphs & 0xff; + dest[1] = ((len/3 - 1) >> 8) & 0xff; + dest[2] = (len/3 - 1) & 0xff; + } + break; + default: + CFF_ERROR("Unknown FDSelect format."); + break; + } + + return len; +} + + + +/* + * Create an instance of embeddable font. + */ +static void +write_fontfile (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 */ + + topdict->offset[1] = 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] = (private->offset)[i] + size; + (fdarray->offset)[i+1] = (fdarray->offset)[i] + + 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 += private->offset[private->count] - 1; /* Private is not INDEX */ + + dest = xcalloc(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, offset); + offset += cff_pack_charsets(cffont, dest + offset, destlen - offset); + + /* FDSelect */ + cff_dict_set(cffont->topdict, "FDSelect", 0, offset); + offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset); + + /* CharStrings */ + cff_dict_set(cffont->topdict, "CharStrings", 0, 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, offset); + fdarray_offset = offset; + offset += cff_index_size(fdarray); + + fdarray->data = xcalloc(fdarray->offset[fdarray->count] - 1, sizeof(card8)); + for (i = 0; i < cffont->num_fds; i++) { + size = 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, size); + cff_dict_set(cffont->fdarray[i], "Private", 1, offset); + } + cff_dict_pack(cffont->fdarray[i], + fdarray->data + (fdarray->offset)[i] - 1, + 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(topdict->offset[topdict->count] - 1, sizeof(card8)); + cff_dict_pack(cffont->topdict, + topdict->data, 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++) + fb_putchar (dest[i]); + + /*fprintf(stdout," (%i/%i)",offset,cffont->stream_size);*/ + xfree(dest); + return ; +} + + +/* if the CFF data was converted from an old type1 font, then the .notdef + glyph may not be at id 0, so in that case |uglytype1fix| is nonzero */ + +void write_cff(cff_font *cffont, fd_entry *fd, int uglytype1fix) { + cff_index *charstrings, *cs_idx; + + long charstring_len, max_len; + long size, offset = 0; + + card8 *data; + card16 num_glyphs, cs_count, code, gid, last_cid; + + double nominal_width, default_width; + + char *fullname; + + glw_entry *glyph, *found; + struct avl_traverser t; + + + + + fullname = xcalloc(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 = uglytype1fix; + if (avl_find(fd->gl_tree, glyph)==NULL) { + /*fprintf(stderr,"seeding .notdef at %i\n",uglytype1fix);*/ + 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 = 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 = 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] = found->id; + gid++; + } + } + cffont->charsets = charset; + } + + cff_dict_add(cffont->topdict, "CIDCount", 1); + cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1); + + cffont->fdarray = xcalloc(1, sizeof(cff_dict *)); + cffont->fdarray[0] = cff_new_dict(); + cff_dict_add(cffont->fdarray[0], "FontName", 1); + cff_dict_set(cffont->fdarray[0], "FontName", 0, + (double) cff_add_string(cffont, fullname)); /* FIXME: Skip XXXXXX+ */ + 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 = cff_dict_get(cffont->topdict, "CharStrings", 0); + cs_idx = cff_get_index_header(cffont); + + offset = cffont->offset; + cs_count = cs_idx->count; + if (cs_count < 2) { + CFF_ERROR("No valid charstring data found."); + } + + /* build the new charstrings entry */ + charstrings = cff_new_index(cs_count+1); + max_len = 2 * CS_STR_LEN_MAX; + charstrings->data = xcalloc(max_len, sizeof(card8)); + charstring_len = 0; + + gid = 0; + data = xcalloc(CS_STR_LEN_MAX, sizeof(card8)); + + for (code=0; code < cs_count; code++) { + glyph->id = code; + if ((avl_find(fd->gl_tree,glyph) != NULL)) { + size = cs_idx->offset[code+1] - cs_idx->offset[code]; + + if (size > CS_STR_LEN_MAX) { + pdftex_fail("Charstring too long: gid=%u, %ld bytes", code, size); + } + if (charstring_len + CS_STR_LEN_MAX >= max_len) { + max_len = charstring_len + 2 * CS_STR_LEN_MAX; + charstrings->data = xrealloc(charstrings->data, max_len*sizeof(card8)); + } + (charstrings->offset)[gid] = charstring_len + 1; + cffont->offset= offset + (cs_idx->offset)[code] - 1; + memcpy(data,&cffont->stream[cffont->offset],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); + gid++; + } + } + + /* this happens if the internal metrics do not agree with the actual disk font */ + if (gid < num_glyphs) { + WARN("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] = 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_add_string(cffont, (char *)"Adobe"); + cff_add_string(cffont, (char *)"Identity"); + + cff_dict_update(cffont->topdict, cffont); + cff_dict_update(cffont->private[0], cffont); + cff_update_string(cffont); + + /* CFF code need to be rewrote... */ + cff_dict_add(cffont->topdict, "ROS", 3); + cff_dict_set(cffont->topdict, "ROS", 0, + (double) cff_get_sid(cffont, (char *)"Adobe")); + cff_dict_set(cffont->topdict, "ROS", 1, + (double) cff_get_sid(cffont, (char *)"Identity")); + cff_dict_set(cffont->topdict, "ROS", 2, 0.0); + + write_fontfile(cffont,fullname); + xfree(fullname); + cff_close (cffont); + +} + +#define ERROR(a) { perror(a); return 0; } + +/* Input : SID or CID (16-bit unsigned int) + * Output: glyph index + */ +card16 +cff_charsets_lookup (cff_font *cff, card16 cid) +{ + card16 gid = 0; + cff_charsets *charset; + card16 i; + + if (cff->flag & (CHARSETS_ISOADOBE|CHARSETS_EXPERT|CHARSETS_EXPSUB)) { + ERROR("Predefined CFF charsets not supported yet"); + } else if (cff->charsets == NULL) { + ERROR("Charsets data not available"); + } + + if (cid == 0) { + return 0; /* GID 0 (.notdef) */ + } + + charset = cff->charsets; + + gid = 0; + switch (charset->format) { + case 0: + for (i = 0; i <charset->num_entries; i++) { + if (cid == charset->data.glyphs[i]) { + gid = i + 1; + return gid; + } + } + break; + case 1: + for (i = 0; i < charset->num_entries; i++) { + if (cid >= charset->data.range1[i].first && + cid <= charset->data.range1[i].first + charset->data.range1[i].n_left) { + gid += cid - charset->data.range1[i].first + 1; + return gid; + } + gid += charset->data.range1[i].n_left + 1; + } + break; + case 2: + for (i = 0; i < charset->num_entries; i++) { + if (cid >= charset->data.range2[i].first && + cid <= charset->data.range2[i].first + charset->data.range2[i].n_left) { + gid += cid - charset->data.range2[i].first + 1; + return gid; + } + gid += charset->data.range2[i].n_left + 1; + } + break; + default: + ERROR("Unknown Charset format"); + } + + return 0; /* not found */ +} + + +#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT) +#define CID_MAX 65535 + +void write_cid_cff(cff_font *cffont, fd_entry *fd, int uglytype1fix) { + cff_index *charstrings, *cs_idx; + + long charstring_len, max_len; + long size, offset = 0; + + card8 *data; + card16 num_glyphs, cs_count, 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)) { + perror("Not a CIDfont."); + return; + } + + fullname = xcalloc(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; + } + cff_read_charsets(cffont); + CIDToGIDMap = xmalloc((2*cid_count) * sizeof(unsigned char)); + memset(CIDToGIDMap, 0, 2*cid_count); + + + glyph = xtalloc(1,glw_entry); + /* insert notdef */ + glyph->id = uglytype1fix; + if (avl_find(fd->gl_tree, glyph)==NULL) { + avl_insert(fd->gl_tree, glyph); + glyph = xtalloc(1,glw_entry); + } + + cid = 0; last_cid = 0; num_glyphs = 0; + for (cid = 0; cid <= CID_MAX; cid++) { + glyph->id = cid; + if (avl_find(fd->gl_tree,glyph) != NULL) { + gid = cff_charsets_lookup(cffont, cid); + CIDToGIDMap[2*cid] = (gid >> 8) & 0xff; + CIDToGIDMap[2*cid+1] = gid & 0xff; + last_cid = cid; + num_glyphs++; + } + } + + cff_read_fdselect(cffont); + cff_read_fdarray(cffont); + cff_read_private(cffont); + + cff_read_subrs (cffont); + + + cffont->offset = cff_dict_get(cffont->topdict, "CharStrings", 0); + cs_idx = cff_get_index_header(cffont); + + offset = cffont->offset; + cs_count = cs_idx->count; + if (cs_count < 2) { + CFF_ERROR("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(cs_count+1); + max_len = 2 * CS_STR_LEN_MAX; + charstrings->data = xcalloc(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 = cid; + if (avl_find(fd->gl_tree,glyph) == NULL) + continue; + + gid_org = (CIDToGIDMap[2*cid] << 8)|(CIDToGIDMap[2*cid+1]); + size = cs_idx->offset[gid_org+1] - cs_idx->offset[gid_org]; + if (size > CS_STR_LEN_MAX) { + pdftex_fail("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, max_len*sizeof(card8)); + } + (charstrings->offset)[gid] = charstring_len + 1; + cffont->offset= offset + (cs_idx->offset)[gid_org] - 1; + memcpy(data,&cffont->stream[cffont->offset],size); + fdsel = cff_fdselect_lookup(cffont, gid_org); + charstring_len += cs_copy_charstring(charstrings->data + charstring_len, + max_len - charstring_len, + data, size, + cffont->gsubr, (cffont->subrs)[fdsel], + 0, 0, NULL); + + if (cid>0 && gid_org > 0) { + charset->data.glyphs[charset->num_entries] = cid; + charset->num_entries += 1; + } + if (fdsel != prev_fd) { + fdselect->data.ranges[fdselect->num_entries].first = gid; + fdselect->data.ranges[fdselect->num_entries].fd = fdsel; + fdselect->num_entries += 1; + prev_fd = fdsel; + } + gid++; + } + + if (gid != num_glyphs) + CFF_ERROR("Unexpected error: %i != %i", gid, num_glyphs); + xfree(data); + cff_release_index(cs_idx); + + xfree(CIDToGIDMap); + + (charstrings->offset)[num_glyphs] = 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(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. + */ + +extern int ff_createcff (char *, unsigned char **, integer *); + +void writetype1w (fd_entry *fd) { + cff_font *cff; + int i; + FILE *fp; + ff_entry *ff; + unsigned char *tfm_buffer = NULL; + integer tfm_size = 0; + int notdefpos = 0; + + ff = check_ff_exist(fd->fm->ff_name, 0); + + fp = fopen (ff->ff_path, "rb"); + cur_file_name = ff->ff_path; + + if (!fp) { + fprintf(stderr,"Type1: Could not open Type1 font: %s", cur_file_name); + uexit(1); + } + fclose(fp); + + if (tracefilenames) { + if (is_subsetted(fd->fm)) + tex_printf ("<%s", cur_file_name); + else + tex_printf ("<<%s", cur_file_name); + } + + notdefpos = 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(cff,fd,notdefpos); + } else { + for (i = 0; i < tfm_size ; i++) + fb_putchar (tfm_buffer[i]); + } + fd->ff_found = 1; + } else { + fprintf(stderr,"Type1: Could not understand Type1 font: %s", cur_file_name); + uexit(1); + } + if (tracefilenames) { + if (is_subsetted (fd->fm)) + tex_printf (">"); + else + tex_printf (">>"); + } + cur_file_name = NULL; +} + + diff --git a/Build/source/texk/web2c/luatexdir/font/writecff.h b/Build/source/texk/web2c/luatexdir/font/writecff.h new file mode 100644 index 00000000000..8cb93024f7a --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writecff.h @@ -0,0 +1,349 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/cff_limits.h,v 1.3 2002/10/30 02:27:05 chofchof Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef _CFF_LIMITS_H_ +#define _CFF_LIMITS_H_ + +#include <limits.h> + +#define CFF_INT_MAX 0x7fffffff +#define CFF_INT_MIN (-0x7fffffff - 1) + +#if (LONG_MAX < CFF_INT_MAX || LONG_MIN > CFF_INT_MIN) +#error "CFF support won't work on this system." +#endif + +#define CFF_SID_MAX 64999 +#define CFF_STDSTR_MAX 391 + +/* Type 2 Charstring */ +#define CS_NUM_SUBR_MAX 65536 +#define CS_STR_LEN_MAX 65536 +#define CS_STEM_ZONE_MAX 96 +#define CS_ARG_STACK_MAX 48 +#define CS_TRANS_ARRAY_MAX 32 +#define CS_SUBR_NEST_MAX 10 + +#endif /* _CFF_LIMITS_H_ */ + +#ifndef _CFF_TYPES_H_ +#define _CFF_TYPES_H_ + +/* CFF Data Types */ + +#define CFF_TYPE_UNKNOWN 0 +#define CFF_TYPE_INTEGER (1 << 0) +#define CFF_TYPE_REAL (1 << 1) +#define CFF_TYPE_NUMBER (CFF_TYPE_INTEGER|CFF_TYPE_REAL) +#define CFF_TYPE_BOOLEAN (1 << 2) +#define CFF_TYPE_SID (1 << 3) +#define CFF_TYPE_ARRAY (1 << 4) +#define CFF_TYPE_DELTA (1 << 5) + +/* SID SID number */ +#define CFF_TYPE_ROS (1 << 6) +/* offset(0) */ +#define CFF_TYPE_OFFSET (1 << 7) +/* size offset(0) */ +#define CFF_TYPE_SZOFF (1 << 8) + +typedef unsigned char card8; /* 1-byte unsigned number */ +typedef unsigned short card16; /* 2-byte unsigned number */ +typedef unsigned char c_offsize; /* 1-byte unsigned number specifies the size + of an Offset field or fields, range 1-4 */ +typedef unsigned long l_offset; /* 1, 2, 3, or 4-byte offset */ +typedef unsigned short s_SID; /* 2-byte string identifier */ + +typedef unsigned long l_size; + +typedef struct { + card16 count; /* number of objects stored in INDEX */ + c_offsize offsize; /* Offset array element size, 1-4 */ + l_offset *offset; /* Offset array, count + 1 offsets */ + card8 *data; /* Object data */ +} cff_index; + + +/* Dictionary */ +typedef struct { + int id; /* encoded data value (as card8 or card16) */ + char *key; /* opname */ + int count; /* number of values */ + double *values; /* values */ +} cff_dict_entry; + +typedef struct { + int max; + int count; + cff_dict_entry *entries; +} cff_dict; + +/* Encoding, Charset and FDSelect */ +typedef struct +{ + s_SID first; /* SID or CID, or card8 for Encoding */ + card8 n_left; /* no. of remaining gids/codes in this range */ +} cff_range1; + +typedef struct +{ + s_SID first; /* SID or CID (card16) */ + card16 n_left; /* card16-version of range1 */ +} cff_range2; + +typedef struct +{ + card8 code; + s_SID glyph; +} cff_map; + +typedef struct +{ + card8 format; /* if (format & 0x80) then have supplement */ + card8 num_entries; /* number of entries */ + union { + card8 *codes; /* format 0 */ + cff_range1 *range1; /* format 1 */ + } data; + card8 num_supps; /* number of supplementary data */ + cff_map *supp; /* supplement */ +} cff_encoding; + +typedef struct +{ + card8 format; + card16 num_entries; + union { + s_SID *glyphs; /* format 0 */ + cff_range1 *range1; /* format 1 */ + cff_range2 *range2; /* format 2 */ + } data; +} cff_charsets; + +/* CID-Keyed font specific */ +typedef struct +{ + card16 first; + card8 fd; +} cff_range3; + +typedef struct +{ + card8 format; + card16 num_entries; /* number of glyphs/ranges */ + union { + card8 *fds; /* format 0 */ + cff_range3 *ranges; /* format 3 */ + } data; + /* card16 sentinel; */ /* format 3 only, must be equals to num_glyphs */ +} cff_fdselect; + +#endif /* _CFF_TYPES_H_ */ + +#ifndef _CFF_STDSTR_H_ +#define _CFF_STDSTR_H_ + +#define CFF_STDSTR_MAX 391 + +extern const char *const cff_stdstr[]; +#endif /* _CFF_STDSTR_H_ */ + +#ifndef _CFF_H_ +#define _CFF_H_ + +/*#include "mfileio.h"*/ + +/* Flag */ +#define FONTTYPE_CIDFONT (1 << 0) +#define FONTTYPE_FONT (1 << 1) +#define FONTTYPE_MMASTER (1 << 2) + +#define ENCODING_STANDARD (1 << 3) +#define ENCODING_EXPERT (1 << 4) + +#define CHARSETS_ISOADOBE (1 << 5) +#define CHARSETS_EXPERT (1 << 6) +#define CHARSETS_EXPSUB (1 << 7) + +#define HAVE_STANDARD_ENCODING (ENCODING_STANDARD|ENCODING_EXPERT) +#define HAVE_STANDARD_CHARSETS \ + (CHARSETS_ISOADOBE|CHARSETS_EXPERT|CHARSETS_EXPSUB) + +#define CFF_STRING_NOTDEF 65535 + +typedef struct +{ + char *fontname; /* FontName */ + + /* - CFF structure - */ + + card8 header_major; /* major version */ + card8 header_minor; /* minor version */ + card8 header_hdr_size; /* Header size (bytes) */ + c_offsize header_offsize; /* Absolute offset (0) size */ + + cff_index *name; /* Name INDEX */ + cff_dict *topdict; /* Top DICT (single) */ + cff_index *string; /* String INDEX */ + cff_index *gsubr; /* Global Subr INDEX */ + cff_encoding *encoding; /* Encodings */ + cff_charsets *charsets; /* Charsets */ + cff_fdselect *fdselect; /* FDSelect, CIDFont only */ + cff_index *cstrings; /* CharStrings */ + cff_dict **fdarray; /* CIDFont only */ + cff_dict **private; /* per-Font DICT */ + cff_index **subrs; /* Local Subr INDEX, per-Private DICT */ + + /* -- extra data -- */ + l_offset gsubr_offset; + card16 num_glyphs; /* number of glyphs (CharString INDEX count) */ + card8 num_fds; /* number of Font DICT */ + + /* Updated String INDEX. + * Please fix this. We should separate input and output. + */ + cff_index *_string; + + unsigned char *stream; + l_offset offset; + l_offset stream_size; + + int index; /* CFF fontset index */ + int flag; /* Flag: see above */ +} cff_font; + +extern cff_font *cff_open(unsigned char *stream, long stream_size, int n); +extern void cff_close (cff_font *cff); + +#define cff_seek_set(c, p) seek_absolute (((c)->stream), ((c)->offset) + (p)); + +/* CFF Header */ +extern long cff_put_header (cff_font *cff, card8 *dest, long destlen); + +/* CFF INDEX */ +extern cff_index *cff_get_index (cff_font *cff); +extern cff_index *cff_get_index_header (cff_font *cff); +extern void cff_release_index (cff_index *idx); +extern cff_index *cff_new_index (card16 count); +extern long cff_index_size (cff_index *idx); +extern long cff_pack_index (cff_index *idx, card8 *dest, long destlen); + +/* Name INDEX */ +extern char *cff_get_name (cff_font *cff); +extern long cff_set_name (cff_font *cff, char *name); + +/* Global and Local Subrs INDEX */ +extern long cff_read_subrs (cff_font *cff); + +/* Encoding */ +extern long cff_read_encoding (cff_font *cff); +extern long cff_pack_encoding (cff_font *cff, card8 *dest, long destlen); +extern card16 cff_encoding_lookup (cff_font *cff, card8 code); +extern void cff_release_encoding (cff_encoding *encoding); + +/* Charsets */ +extern long cff_read_charsets (cff_font *cff); +extern long cff_pack_charsets (cff_font *cff, card8 *dest, long destlen); + +/* Returns GID of PS name "glyph" */ +extern card16 cff_glyph_lookup (cff_font *cff, const char *glyph); +/* Returns GID of glyph with SID/CID "cid" */ +extern card16 cff_charsets_lookup (cff_font *cff, card16 cid); +extern void cff_release_charsets (cff_charsets *charset); +/* Returns SID or CID */ +extern card16 cff_charsets_lookup_inverse (cff_font *cff, card16 gid); + +/* FDSelect */ +extern long cff_read_fdselect (cff_font *cff); +extern long cff_pack_fdselect (cff_font *cff, card8 *dest, long destlen); +extern card8 cff_fdselect_lookup (cff_font *cff, card16 gid); +extern void cff_release_fdselect (cff_fdselect *fdselect); + +/* Font DICT(s) */ +extern long cff_read_fdarray (cff_font *cff); + +/* Private DICT(s) */ +extern long cff_read_private (cff_font *cff); + +/* String */ +extern int cff_match_string (cff_font *cff, const char *str, s_SID sid); +extern char *cff_get_string (cff_font *cff, s_SID id); +extern long cff_get_sid (cff_font *cff, char *str); +extern s_SID cff_add_string (cff_font *cff, char *str); +extern void cff_update_string (cff_font *cff); + +#define cff_is_stdstr(s) (cff_get_sid(NULL, (s)) >= 0) + +#endif /* _CFF_H_ */ + +#ifndef _CFF_DICT_H_ +#define _CFF_DICT_H_ + +#define CFF_CIDCOUNT_DEFAULT 8720 +#define CFF_NOMINALWIDTHX_DEFAULT 0.0 +#define CFF_DEFAULTWIDTHX_DEFAULT 0.0 + +extern cff_dict *cff_new_dict (void); +extern void cff_release_dict (cff_dict *dict); + +extern void cff_dict_set (cff_dict *dict, const char *key, int idx, double value); +extern double cff_dict_get (cff_dict *dict, const char *key, int idx); +extern void cff_dict_add (cff_dict *dict, const char *key, int count); +extern void cff_dict_remove (cff_dict *dict, const char *key); +extern int cff_dict_known (cff_dict *dict, const char *key); + +/* decode/encode DICT */ +extern cff_dict *cff_dict_unpack (card8 *data, card8 *endptr); +extern long cff_dict_pack (cff_dict *dict, card8 *dest, long destlen); + +extern void cff_dict_update (cff_dict *dict, cff_font *cff); + +#endif /* _CFF_DICT_H_ */ + +#ifndef _CS_TYPE2_H_ +#define _CS_TYPE2_H_ + +typedef struct { + int flags; /* unused in Type 2 charstring */ + double wx, wy; + struct { + double llx, lly, urx, ury; + } bbox; + struct { + double asb, adx, ady; + card8 bchar, achar; + } seac; /* unused in Type 2 charstring */ +} cs_ginfo; + +extern long cs_copy_charstring (card8 *dest, long destlen, + card8 *src, long srclen, + cff_index *gsubr, cff_index *subr, + double default_width, double nominal_width, cs_ginfo *ginfo); +#endif /* _CS_TYPE2_H_ */ + +#define cff_is_cidfont(a) (a->flag & FONTTYPE_CIDFONT) +#define cff_understandable(a) (a->header_major==1) + +extern cff_font *read_cff(unsigned char *buf,long buflength, int subf); + +extern void write_cff(cff_font *cff, fd_entry *fd, int hack); +extern void write_cid_cff(cff_font *cffont, fd_entry *fd, int uglytype1fix) ; diff --git a/Build/source/texk/web2c/luatexdir/font/writeenc.c b/Build/source/texk/web2c/luatexdir/font/writeenc.c new file mode 100644 index 00000000000..feaf1407d1e --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writeenc.c @@ -0,0 +1,183 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writeenc.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +/**********************************************************************/ +/* All encoding entries go into AVL tree for fast search by name. */ + +struct avl_table *fe_tree = NULL; + +/* AVL sort fe_entry into fe_tree by name */ + +static int comp_fe_entry(const void *pa, const void *pb, void *p) +{ + return strcmp(((const fe_entry *) pa)->name, ((const fe_entry *) pb)->name); +} + +fe_entry *new_fe_entry() +{ + 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; +} + +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); +} + +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; +} + +/**********************************************************************/ + +void epdf_write_enc(char **glyph_names, integer fe_objnum) +{ + int i, i_old; + assert(glyph_names != NULL); + assert(fe_objnum != 0); + pdf_begin_dict(fe_objnum, 1); + pdf_puts("/Type /Encoding\n"); + pdf_printf("/Differences ["); + for (i = 0, i_old = -2; i < 256; i++) + if (glyph_names[i] != notdef) { + if (i == i_old + 1) /* no gap */ + pdf_printf("/%s", glyph_names[i]); + else { + if (i_old == -2) + pdf_printf("%i/%s", i, glyph_names[i]); + else + pdf_printf(" %i/%s", i, glyph_names[i]); + } + i_old = i; + } + pdf_puts("]\n"); + pdf_end_dict(); +} + +void write_enc(char **glyph_names, struct avl_table *tx_tree, integer fe_objnum) +{ + int i_old, *p; + struct avl_traverser t; + assert(glyph_names != NULL); + assert(tx_tree != NULL); + assert(fe_objnum != 0); + pdf_begin_dict(fe_objnum, 1); + pdf_puts("/Type /Encoding\n"); + pdf_printf("/Differences ["); + 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) /* no gap */ + pdf_printf("/%s", glyph_names[*p]); + else { + if (i_old == -2) + pdf_printf("%i/%s", *p, glyph_names[*p]); + else + pdf_printf(" %i/%s", *p, glyph_names[*p]); + } + i_old = *p; + } + pdf_puts("]\n"); + pdf_end_dict(); +} + +void write_fontencoding(fe_entry * fe) +{ + assert(fe != NULL); + write_enc(fe->glyph_names, fe->tx_tree, fe->fe_objnum); +} + +void write_fontencodings() +{ + 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(fe); +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_fe_entry(void *pa, void *pb) +{ + fe_entry *p; + int i; + 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); + xfree(p); +} + +void enc_free() +{ + if (fe_tree != NULL) + avl_destroy(fe_tree, destroy_fe_entry); + fe_tree = NULL; +} + +/**********************************************************************/ diff --git a/Build/source/texk/web2c/luatexdir/font/writefont.c b/Build/source/texk/web2c/luatexdir/font/writefont.c new file mode 100644 index 00000000000..05257746889 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writefont.c @@ -0,0 +1,885 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writefont.c 1112 2008-03-20 14:46:32Z taco $ +*/ + +#include "ptexlib.h" + +extern void writetype0 (fd_entry * fd) ; +extern void writetype2 (fd_entry * fd) ; +extern unsigned long cidtogid_obj; + +#ifdef DO_TYPE1C +extern void writet1c(fd_entry * fd); /* in writecff.c */ +#endif + +extern void writet1w (fd_entry * fd); /* in writecff.c */ +extern void writetype1w (fd_entry * fd); +extern integer write_cid_tounicode(fo_entry * fo, internalfontnumber f); /* in tounicode.c */ + + +void write_cid_fontdictionary(fo_entry * fo, internalfontnumber f); +void create_cid_fontdictionary(fm_entry * fm, integer font_objnum, internalfontnumber f); + +/**********************************************************************/ + +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) +{ + 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) +{ + int i; + const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb; + assert(p1->fm != NULL && is_fontfile(p1->fm) && + p2->fm != NULL && is_fontfile(p2->fm)); + if ((i = strcmp(p1->fm->ff_name, p2->fm->ff_name)) != 0) + return i; + cmp_return(p1->fm->slant, p2->fm->slant); + cmp_return(p1->fm->extend, p2->fm->extend); + return 0; +} + +/**********************************************************************/ +/* initialize data structure for /Type /Font */ + +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 */ + +fd_entry *new_fd_entry(void) +{ + 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->fn_objnum = 0; + fd->all_glyphs = false; + fd->write_ttf_glyph_names = false; + for (i = 0; i < INT_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; + 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. + */ + +static void preset_fontmetrics(fd_entry * fd, internalfontnumber f) +{ + int i; + fd->font_dim[ITALIC_ANGLE_CODE].val = + divide_scaled(-atan(get_slant(f) / 65536.0) * (180 / M_PI), + pdf_font_size(f), 3); + fd->font_dim[ASCENT_CODE].val = + divide_scaled(char_height(f, 'h'), pdf_font_size(f), 3); + fd->font_dim[CAPHEIGHT_CODE].val = + divide_scaled(char_height(f, 'H'), pdf_font_size(f), 3); + i = -divide_scaled(char_depth(f, 'y'), pdf_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, pdf_font_size(f), 3); + fd->font_dim[XHEIGHT_CODE].val = + divide_scaled(get_x_height(f), pdf_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), pdf_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 write_fontmetrics(fd_entry * fd) +{ + int i; + if (fd->font_dim[FONTBBOX1_CODE].set && fd->font_dim[FONTBBOX2_CODE].set + && fd->font_dim[FONTBBOX3_CODE].set && fd->font_dim[FONTBBOX4_CODE].set) + pdf_printf("/%s [%i %i %i %i]\n", font_key[FONTBBOX1_CODE].pdfname, + (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); + for (i = 0; i < GEN_KEY_NUM; i++) + if (fd->font_dim[i].set) + pdf_printf("/%s %i\n", font_key[i].pdfname, fd->font_dim[i].val); +} + +/**********************************************************************/ + +static void preset_fontname(fo_entry * fo) +{ + if (fo->fm->ps_name != NULL) + fo->fd->fontname = xstrdup(fo->fm->ps_name); /* just fallback */ + else + fo->fd->fontname = xstrdup(fo->fm->tfm_name); +} + +static void write_fontname(fd_entry * fd, char *key) +{ + assert(fd->fontname != NULL); + pdf_puts("/"); + if (key != NULL) + pdf_printf("%s /", key); + if (fd->subset_tag != NULL) + pdf_printf("%s+", fd->subset_tag); + pdf_printf("%s\n", fd->fontname); +} + +static void write_fontname_object(fd_entry * fd) +{ + assert(fd->fn_objnum != 0); + pdf_begin_obj(fd->fn_objnum, 1); + write_fontname(fd, NULL); + pdf_end_obj(); +} + +/**********************************************************************/ + +fd_entry *lookup_fd_entry(char *s, integer slant, integer extend) +{ + fd_entry fd; + fm_entry fm; + assert(s != NULL); + fm.ff_name = s; + fm.slant = slant; + fm.extend = extend; + 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); +} + +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, fo->fm->slant, fo->fm->extend); +} + +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)); + assert(lookup_fd_entry(fd->fm->ff_name, fd->fm->slant, fd->fm->extend) == NULL); /* font descriptor not yet registered */ + aa = avl_probe(fd_tree, fd); + assert(aa != NULL); +} + +void create_fontdescriptor(fo_entry * fo, internalfontnumber f) +{ + assert(fo != NULL); + assert(fo->fm != NULL); + assert(fo->fd == NULL); + fo->fd = new_fd_entry(); + preset_fontname(fo); + 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_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. + */ + +void mark_reenc_glyphs(fo_entry * fo, internalfontnumber 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: + * 1. Mark characters as chars on TeX level. + * 2. Mark encoding pairs used by TeX to optimize encoding vector. + */ + +struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree, + internalfontnumber 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; +} + +/**********************************************************************/ + +void get_char_range(fo_entry * fo, internalfontnumber f) +{ + int i; + assert(fo != NULL); + for (i = font_bc(f); i <= font_ec(f); i++) /* search for first_char and last_char */ + 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 void write_charwidth_array(fo_entry * fo, internalfontnumber f) +{ + int i, j, *ip, *fip, width; + struct avl_traverser t; + assert(fo->tx_tree != NULL); + assert(fo->cw_objnum == 0); + fo->cw_objnum = pdf_new_objnum(); + pdf_begin_obj(fo->cw_objnum, 1); + avl_t_init(&t, fo->tx_tree); + fip = (int *) avl_t_first(&t, fo->tx_tree); + assert(fip != NULL); + pdf_puts("["); + for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) { + if (ip != fip) + pdf_puts(" "); + i = *ip; + while (j < i - 1) { + pdf_puts("0 "); + j++; + } + j = i; + width = divide_scaled(char_width(f, i), pdf_font_size(f), 4); + pdf_printf("%i", (int) width / 10); /* see adv_char_width() in pdftex.web */ + if ((width = width % 10) != 0) + pdf_printf(".%i", width); + } + pdf_puts("]\n"); + pdf_end_obj(); +} + +/**********************************************************************/ +/* + * Remark: Font objects from embedded PDF files are never registered + * into fo_tree; they are individually written out. + */ + +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); +} + +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); +} + +/**********************************************************************/ + +static void write_fontfile(fd_entry * fd) +{ + assert(is_included(fd->fm)); + if (is_cidkeyed(fd->fm)) { + if (is_opentype(fd->fm)) + writetype0(fd); + else if (is_truetype(fd->fm)) + writetype2(fd); + else if (is_type1(fd->fm)) + writetype1w(fd); + else + assert(0); + } else { + if (is_type1(fd->fm)) +#ifdef DO_TYPE1C + writet1c(fd); +#else + writet1(fd); +#endif + else if (is_truetype(fd->fm)) + writettf(fd); + else if (is_opentype(fd->fm)) + writeotf(fd); + else + assert(0); + } + if (!fd->ff_found) + return; + assert(fd->ff_objnum == 0); + fd->ff_objnum = pdf_new_objnum(); + pdf_begin_dict(fd->ff_objnum, 0); /* font file stream */ + if (is_cidkeyed(fd->fm)) { + /* No subtype is used for TrueType-based OpenType fonts */ + if (is_opentype(fd->fm) || is_type1(fd->fm)) + pdf_puts("/Subtype /CIDFontType0C\n"); + /* else + pdf_puts("/Subtype /OpenType\n");*/ + } else { + if (is_type1(fd->fm)) + pdf_printf("/Length1 %i\n/Length2 %i\n/Length3 %i\n", + (int) t1_length1, (int) t1_length2, (int) t1_length3); + else if (is_truetype(fd->fm)) + pdf_printf("/Length1 %i\n", (int) ttf_length); + else if (is_opentype(fd->fm)) + pdf_puts("/Subtype /Type1C\n"); + else + assert(0); + } + pdf_begin_stream(); + fb_flush(); + pdf_end_stream(); +} + +/**********************************************************************/ + +static void write_fontdescriptor(fd_entry * fd) +{ + char *glyph; + struct avl_traverser t; + assert(fd != NULL && fd->fm != NULL); + + if (is_fontfile(fd->fm)) + write_fontfile(fd); /* this will set fd->ff_found if font file is found */ + if (fd->fn_objnum != 0) + write_fontname_object(fd); + if (fd->fd_objnum == 0) + fd->fd_objnum = pdf_new_objnum(); + pdf_begin_dict(fd->fd_objnum, 1); + pdf_puts("/Type /FontDescriptor\n"); + write_fontname(fd, "FontName"); + if (!fd->ff_found && fd->fm->fd_flags == 4) + pdf_puts("/Flags 34\n"); /* assumes a roman sans serif font */ + else + pdf_printf("/Flags %i\n", (int) fd->fm->fd_flags); + write_fontmetrics(fd); + if (is_cidkeyed(fd->fm)) { + if (is_type1(fd->fm)) + pdf_printf("/FontFile3 %i 0 R\n", (int) fd->ff_objnum); + else if (is_truetype(fd->fm)) + pdf_printf("/FontFile2 %i 0 R\n", (int) fd->ff_objnum); + else if (is_opentype(fd->fm)) + pdf_printf("/FontFile3 %i 0 R\n", (int) fd->ff_objnum); + else + assert(0); + } else { + if (fd->ff_found) { + 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_puts("/CharSet ("); + for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL; + glyph = (char *) avl_t_next(&t)) + pdf_printf("/%s", glyph); + pdf_puts(")\n"); + } + if (is_type1(fd->fm)) + pdf_printf("/FontFile %i 0 R\n", (int) fd->ff_objnum); + else if (is_truetype(fd->fm)) + pdf_printf("/FontFile2 %i 0 R\n", (int) fd->ff_objnum); + else if (is_opentype(fd->fm)) + pdf_printf("/FontFile3 %i 0 R\n", (int) fd->ff_objnum); + else + assert(0); + } + } + /* TODO: Optional keys for CID fonts. + + The most interesting ones are + /Style << /Panose <12-byte string>>> + and + /CIDSET <stream> + the latter can be used in subsets, to give the included CIDs + as a bitmap on the whole list. + */ + pdf_end_dict(); +} + +void write_fontdescriptors() +{ + 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(fd); +} + +/**********************************************************************/ + +void write_fontdictionary(fo_entry * fo) +{ + assert(fo != NULL); + assert(fo->fm != NULL); + assert(fo->fo_objnum != 0); /* reserved as pdf_font_num(f) in pdftex.web */ + + /* write ToUnicode entry if needed */ + if (fixed_gen_tounicode > 0 && fo->fd != NULL) { + if (fo->fe != NULL) { + fo->tounicode_objnum = + write_tounicode(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(fo->fd->builtin_glyph_names, fo->fm->tfm_name); + } + } + + pdf_begin_dict(fo->fo_objnum, 1); + pdf_puts("/Type /Font\n"); + pdf_puts("/Subtype /"); + if (is_type1(fo->fm)) +#ifdef DO_TYPE1C + pdf_printf("%s\n", "Type1C"); +#else + pdf_printf("%s\n", "Type1"); +#endif + else if (is_truetype(fo->fm)) + pdf_printf("%s\n", "TrueType"); + else if (is_opentype(fo->fm)) + pdf_printf("%s\n", "Type1"); + else + assert(0); + assert(fo->fd != NULL && fo->fd->fd_objnum != 0); + write_fontname(fo->fd, "BaseFont"); + pdf_printf("/FontDescriptor %i 0 R\n", (int) fo->fd->fd_objnum); + assert(fo->cw_objnum != 0); + pdf_printf("/FirstChar %i\n/LastChar %i\n/Widths %i 0 R\n", + (int) fo->first_char, (int) fo->last_char, + (int) fo->cw_objnum); + if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL && fo->fe->fe_objnum != 0) + pdf_printf("/Encoding %i 0 R\n", (int) fo->fe->fe_objnum); + if (fo->tounicode_objnum != 0) + pdf_printf("/ToUnicode %i 0 R\n", (int) fo->tounicode_objnum); + if (pdf_font_attr(fo->tex_font) != get_nullstr()) { + pdf_print(pdf_font_attr(fo->tex_font)); + pdf_puts("\n"); + } + pdf_end_dict(); +} + +void write_fontdictionaries() +{ + 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(fo); +} + +/**********************************************************************/ +/* + * Final flush of all font related stuff by call from + * @<Output fonts definition@>= in pdftex.web. + */ + +void write_fontstuff() +{ + write_fontdescriptors(); + write_fontencodings(); /* see writeenc.c */ + write_fontdictionaries(); +} + +/**********************************************************************/ + +void create_fontdictionary(fm_entry * fm, integer font_objnum, + internalfontnumber 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 = font_objnum; + fo->tex_font = f; + if (is_reencoded(fo->fm)) { /* at least the map entry tells so */ + fo->fe = get_fe_entry(fo->fm->encname); /* returns NULL if .enc file couldn't be opened */ + if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) { + if (fo->fe->fe_objnum == 0) + fo->fe->fe_objnum = pdf_new_objnum(); /* 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); + } + } + fo->tx_tree = mark_chars(fo, fo->tx_tree, f); /* for write_charwidth_array() */ + write_charwidth_array(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(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(fo->fd); + if (!is_std_t1font(fo->fm)) + pdftex_warn("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(fo); +} + +/**********************************************************************/ + + +void do_pdf_font(integer font_objnum, internalfontnumber f) +{ + 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, just assume the user knows what he is doing; + */ + if (font_encodingbytes(f)==2) { + /* Create a virtual font map entry, as this is needed by the + * rest of the font inclusion mechanism. + */ + fm = new_fm_entry(); + fm->tfm_name = font_name(f); /* or whatever, not a real tfm */ + fm->ff_name = font_filename(f); /* the actual file */ + fm->encname = font_encodingname(f); /* for the CIDSystemInfo */ + fm->ps_name = font_fullname(f); /* the true name */ + fm->slant = font_slant(f); /* slant factor */ + fm->extend = font_extend(f); /* extension factor */ + fm->fd_flags = 4; /* can perhaps be done better */ + fm->in_use = true; + + switch (font_format(f)) { + case opentype_format: set_opentype(fm); break; + case truetype_format: set_truetype(fm); break; + case type1_format: set_type1(fm); break; + default: + pdftex_fail("writefont.c: The file format (%s) for font `%s' is incompatible with wide characters\n", + 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(fm, font_objnum, f); + + } else { + fm = hasfmentry(f) ? (fm_entry *) font_map(f) : NULL; + if (fm == NULL || (fm->ps_name == NULL && fm->ff_name == NULL)) + writet3(font_objnum, f); + else + create_fontdictionary(fm, font_objnum, 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. +*/ + +int comp_glw_entry(const void *pa, const void *pb, void *p) +{ + unsigned short i, j; + i = (*(glw_entry *)pa).id; + j = (*(glw_entry *)pb).id; + cmp_return(i,j); + return 0; +} + +void create_cid_fontdescriptor(fo_entry * fo, internalfontnumber f) +{ + assert(fo != NULL); + assert(fo->fm != NULL); + assert(fo->fd == NULL); + fo->fd = new_fd_entry(); + preset_fontname(fo); + 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. +*/ + +static void mark_cid_subset_glyphs(fo_entry *fo, internal_font_number f) +{ + int i, k; + glw_entry *j; + void *aa; + 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 (char_exists(k,i) && char_used(k,i)) { + j = xtalloc(1,glw_entry); + j->id = char_index(k,i); + j->wd = divide_scaled_n(char_width(k, i), pdf_font_size(k), 10000.0); + if ((glw_entry *)avl_find(fo->fd->gl_tree,j) == NULL) { + aa = avl_probe(fo->fd->gl_tree, j); + assert(aa != NULL); + } + } + } + } + } +} + +/* + 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(fo_entry * fo) +{ + int i, j; + glw_entry *glyph; + struct avl_traverser t; + + assert(fo->cw_objnum == 0); + fo->cw_objnum = pdf_new_objnum(); + pdf_begin_obj(fo->cw_objnum, 1); + avl_t_init(&t, fo->fd->gl_tree); + glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree); + assert(glyph != NULL); + i = glyph->id; + pdf_printf("[ %i [", i); + for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) { + j = glyph->wd; + if (glyph->id>(i+1)) { + pdf_printf("] %i [", glyph->id); + j = glyph->wd; + } + if (glyph->id==(i+1)) + pdf_puts(" "); + pdf_printf("%i", (j/10)); + if ((j % 10) != 0) + pdf_printf(".%i", (j % 10)); + i = glyph->id; + } + pdf_puts("]]\n"); + pdf_end_obj(); +} + + +void create_cid_fontdictionary(fm_entry * fm, integer font_objnum, + internalfontnumber 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 = font_objnum; + 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(fo); + write_fontdescriptor(fo->fd); + + write_cid_fontdictionary(fo,f); +} + +void write_cid_fontdictionary(fo_entry * fo, internalfontnumber f) +{ + int i; + + fo->tounicode_objnum = write_cid_tounicode(fo,f); + + pdf_begin_dict(fo->fo_objnum, 1); + pdf_puts("/Type /Font\n"); + pdf_puts("/Subtype /Type0\n"); + pdf_puts("/Encoding /Identity-H\n"); + write_fontname(fo->fd, "BaseFont"); + i = pdf_new_objnum(); + pdf_printf("/DescendantFonts [%i 0 R]\n", i); + /* todo: the ToUnicode CMap */ + if (fo->tounicode_objnum != 0) + pdf_printf("/ToUnicode %i 0 R\n", (int) fo->tounicode_objnum); + + pdf_end_dict(); + + pdf_begin_dict(i, 1); + pdf_puts("/Type /Font\n"); + if (is_opentype(fo->fm) || is_type1(fo->fm)) { + pdf_puts("/Subtype /CIDFontType0\n"); + } else { + pdf_puts("/Subtype /CIDFontType2\n"); + pdf_printf("/CIDToGIDMap /Identity\n"); + } + write_fontname(fo->fd, "BaseFont"); + pdf_printf("/FontDescriptor %i 0 R\n", (int) fo->fd->fd_objnum); + pdf_printf("/W %i 0 R\n",(int) fo->cw_objnum); + pdf_printf("/CIDSystemInfo <<\n"); + pdf_printf("/Registry (%s)\n", (font_cidregistry(f)? font_cidregistry(f): "Adobe")); + pdf_printf("/Ordering (%s)\n",(font_cidordering(f)? font_cidordering(f) : "Identity")) ; + pdf_printf("/Supplement %u\n",(unsigned int)font_cidsupplement(f)); + pdf_printf(">>\n"); + + /* I doubt there is anything useful that could be written here */ + /* + if (pdf_font_attr(fo->tex_font) != get_nullstr()) { + pdf_print(pdf_font_attr(fo->tex_font)); + pdf_puts("\n"); + } + */ + pdf_end_dict(); + +} + diff --git a/Build/source/texk/web2c/luatexdir/font/writet1.c b/Build/source/texk/web2c/luatexdir/font/writet1.c new file mode 100644 index 00000000000..376135dc8be --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writet1.c @@ -0,0 +1,1768 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id $ + +*/ + +# include "ptexlib.h" +# include <kpathsea/c-vararg.h> +# include <kpathsea/c-proto.h> +# include <string.h> +# include "luatex-api.h" + +# define t1_log(s) if(tracefilenames) tex_printf(s) +# 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 fb_putchar +# define t1_offset fb_offset +# 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 update_subset_tag() \ + strncpy(fb_array + t1_fontname_offset, fm_cur->subset_tag, 6) +# define fixedcontent false + +integer t1_length1, t1_length2, t1_length3; +static integer t1_save_offset; +static integer t1_fontname_offset; +extern char *fb_array; + +static unsigned char *t1_buffer = NULL; +static integer t1_size = 0; +static integer 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 integer enc_size = 0; +static integer enc_curbyte = 0; + +#define enc_open() \ + open_input(&enc_file, kpse_enc_format, 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 +}; + + +integer t1_length1, t1_length2, t1_length3; +static integer t1_save_offset; +static integer t1_fontname_offset; +extern char *fb_array; +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 + +#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; + +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 & t1_line_limit */ +typedef char t1_line_entry; +define_array (t1_line); + +/* define t1_buf_ptr, t1_buf_array & t1_buf_limit */ +typedef char t1_buf_entry; +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. */ + +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; +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; + +static void enc_getline (void) +{ + char *p; + int c; + restart: + if (enc_eof ()) + pdftex_fail ("unexpected end of file"); + p = enc_line; + do { + c = 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() */ + +char **load_enc_file(char *enc_name) +{ + int callback_id = 0; + int file_opened = 0; + char *ftemp = NULL; + char buf[ENC_BUF_SIZE], *p, *r; + int i, names_count; + char **glyph_names; + char *tempname ; + set_cur_file_name (enc_name); + callback_id=callback_defined(find_enc_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } else { + return NULL; + } + } + } + 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",(char *)(nameoffile+1), + &file_opened, &enc_buffer,&enc_size)) { + if((!file_opened) || enc_size==0) { + pdftex_warn ("cannot open encoding file for reading"); + cur_file_name = NULL; + return NULL; + } + } + } else { + if (!enc_open ()) { + pdftex_warn ("cannot open encoding file for reading"); + cur_file_name = NULL; + return NULL; + } + enc_read_file(); + enc_close(); + } + glyph_names = xtalloc(256, char *); + for (i = 0; i < 256; i++) + glyph_names[i] = (char *) notdef; + t1_log ("{"); + + tempname = xmalloc(namelength+2); + strcpy(tempname,(char *)(nameoffile+1)); + set_cur_file_name (tempname); + t1_log (cur_file_name); + enc_getline (); + if (*enc_line != '/' || (r = strchr (enc_line, '[')) == NULL) { + remove_eol (r, enc_line); + pdftex_fail + ("invalid encoding vector (a name or `[' missing): `%s'", enc_line); + } + names_count = 0; + r++; /* skip '[' */ + skip (r, ' '); + for (;;) { + while (*r == '/') { + for (p = buf, r++; + *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); + *p = 0; + skip (r, ' '); + if (names_count > 256) + pdftex_fail ("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); + pdftex_fail + ("invalid encoding vector: a name or `] def' expected: `%s'", + enc_line); + } + } + enc_getline (); + r = enc_line; + } + done: + t1_log ("}"); + cur_file_name = NULL; + return glyph_names; +} + +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); +} + + +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) + pdftex_fail ("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 = t1_getbyte (); + last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte ()); + } + plain = (cipher ^ (t1_dr >> 8)); + t1_dr = (cipher + t1_dr) * t1_c1 + t1_c2; + return plain; +} + +static byte cdecrypt (byte cipher, unsigned short *cr) +{ + const byte plain = (cipher ^ (*cr >> 8)); + *cr = (cipher + *cr) * t1_c1 + t1_c2; + return plain; +} + +static byte eencrypt (byte plain) +{ + const byte cipher = (plain ^ (t1_er >> 8)); + t1_er = (cipher + t1_er) * t1_c1 + t1_c2; + return cipher; +} + +static byte cencrypt (byte plain, unsigned short *cr) +{ + const byte cipher = (plain ^ (*cr >> 8)); + *cr = (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 (p, ' '); + if (sscanf (p, "%g", &f) != 1) { + remove_eol (p, t1_line_array); + pdftex_fail ("a number expected: `%s'", t1_line_array); + } + if (r != NULL) { + for (; isdigit (*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; /* strlen(eexec_str) */ + restart: + if (t1_eof ()) + pdftex_fail ("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 (c); + alloc_array (t1_line, 1, T1_BUF_SIZE); + append_char_to_buf (c, 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 || (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--; + t1_cslen = l = t1_scan_num (p + 1, 0); + cs_start = 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++ = edecrypt (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); +} + +static void t1_putline (void) +{ + 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 (eencrypt (*p++)); + } else + while (p < t1_line_ptr) + t1_putchar (*p++); +} + +static void t1_puts (const char *s) +{ + if (s != t1_line_array) + strcpy (t1_line_array, s); + t1_line_ptr = strend (t1_line_array); + t1_putline (); +} + +__attribute__ ((format (printf, 1, 2))) +static void t1_printf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + vsprintf (t1_line_array, fmt, args); + t1_puts (t1_line_array); + va_end (args); +} + +static void t1_init_params (const char *open_name_prefix) +{ + t1_log (open_name_prefix); + t1_log (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 (const char *close_name_suffix) +{ + t1_log (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 (c); + l = t1_block_length; + if (!(l == 0 && (c == 10 || c == 13))) { + pdftex_warn ("%i bytes more than expected were ignored", l + 1); + while (l-- > 0) + t1_getbyte (); + } +} + +static void t1_start_eexec (void) +{ + 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 (t1_getbyte ()); + *t1_line_ptr++ = 0; + } + t1_eexec_encrypt = true; + t1_putline (); /* to put the first four bytes */ +} + +static void t1_stop_eexec (void) +{ + 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 (t1_getbyte ()); + if (!(c == 10 || c == 13)) { + if (last_hexbyte == 0) + t1_puts ("00"); + else + pdftex_warn ("unexpected data after eexec"); + } + } + t1_cs = false; + t1_in_eexec = 2; +} + +/* macros for various transforms; currently only slant and extend are used */ + +# 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;} + +static void t1_modify_fm (void) +{ + /* + * font matrix is given as six numbers a0..a5, which stands for the matrix + * + * a0 a1 0 + * M = a2 a3 0 + * a4 a5 1 + * + * ExtendFont is given as + * + * e 0 0 + * E = 0 1 0 + * 0 0 1 + * + * SlantFont is given as + * + * 1 0 0 + * S = s 1 0 + * 0 0 1 + * + * The slant transform must be done _before_ the extend transform + * for compatibility! + */ + float a[6]; + int i, c; + char *p, *q, *r; + if ((p = strchr (t1_line_array, '[')) == 0) + if ((p = strchr (t1_line_array, '{')) == 0) { + remove_eol (p, t1_line_array); + pdftex_fail ("FontMatrix: an array expected: `%s'", t1_line_array); + } + c = *p++; /* save the character '[' resp. '{' */ + strncpy (t1_buf_array, t1_line_array, (size_t) (p - t1_line_array)); + r = t1_buf_array + (p - t1_line_array); + for (i = 0; i < 6; i++) { + a[i] = t1_scan_num (p, &q); + p = q; + } + if (fm_slant(fd_cur->fm) != 0) + do_slant(a, fm_slant(fd_cur->fm) * 1E-3); + if (fm_extend(fd_cur->fm) != 0) + do_extend(a, fm_extend(fd_cur->fm) * 1E-3); + for (i = 0; i < 6; i++) { + sprintf (r, "%g ", a[i]); + r = strend (r); + } + if (c == '[') { + while (*p != ']' && *p != 0) + p++; + } else { + while (*p != '}' && *p != 0) + p++; + } + if (*p == 0) { + remove_eol (p, t1_line_array); + pdftex_fail + ("FontMatrix: cannot find the corresponding character to '%c': `%s'", + c, t1_line_array); + } + strcpy (r, p); + strcpy (t1_line_array, t1_buf_array); + t1_line_ptr = eol (t1_line_array); +} + +static void t1_modify_italic (void) +{ + float a; + char *p, *r; + if (fm_slant(fd_cur->fm) == 0) + return; + p = strchr (t1_line_array, ' '); + strncpy (t1_buf_array, t1_line_array, (size_t) (p - t1_line_array + 1)); + a = t1_scan_num (p + 1, &r); + a -= atan (fm_slant(fd_cur->fm) * 1E-3) * (180 / M_PI); + sprintf (t1_buf_array + (p - t1_line_array + 1), "%g", a); + strcpy (strend (t1_buf_array), r); + strcpy (t1_line_array, t1_buf_array); + t1_line_ptr = eol (t1_line_array); + fd_cur->font_dim[ITALIC_ANGLE_CODE].val = round(a); + fd_cur->font_dim[ITALIC_ANGLE_CODE].set = true; +} + +static void t1_scan_keys (void) +{ + int i, k; + char *p, *q, *r; + key_entry *key; + if (fm_extend(fd_cur->fm) != 0 || fm_slant(fd_cur->fm) != 0) { + if (t1_prefix ("/FontMatrix")) { + t1_modify_fm (); + return; + } + if (t1_prefix ("/ItalicAngle")) { + t1_modify_italic (); + return; + } + } + if (t1_prefix ("/FontType")) { + p = t1_line_array + strlen ("FontType") + 1; + if ((i = t1_scan_num (p, 0)) != 1) + pdftex_fail ("Type%d fonts unsupported by pdfTeX", i); + return; + } + for (key = (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 (p, ' '); + if ((k = key - font_key) == FONTNAME_CODE) { + if (*p != '/') { + remove_eol (p, t1_line_array); + pdftex_fail ("a name expected: `%s'", t1_line_array); + } + r = ++p; /* skip the slash */ + for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++); + *q = 0; + if (fm_slant(fd_cur->fm) != 0) { + sprintf(q, "-Slant_%i", (int) fm_slant(fd_cur->fm)); + q = strend (q); + } + if (fm_extend(fd_cur->fm) != 0) { + sprintf(q, "-Extend_%i", (int) fm_extend(fd_cur->fm)); + } + 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 = 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 = t1_scan_num(p, &r); + fd_cur->font_dim[k].set = true; + p = r; + } + return; + } + fd_cur->font_dim[k].val = t1_scan_num(p, 0); + fd_cur->font_dim[k].set = true; +} + +static void t1_scan_param (void) +{ + static const char *lenIV = "/lenIV"; + if (!t1_scan || *t1_line_array != '/') + return; + if (t1_prefix (lenIV)) { + t1_lenIV = t1_scan_num (t1_line_array + strlen (lenIV), 0); + return; + } + t1_scan_keys (); +} + +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() */ + +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"), "%256s", 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 + pdftex_fail + ("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 + * + * /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(r, ' '); + for (;;) { + while (*r == '/') { + for (p = t1_buf_array, r++; + *r != 32 && *r != 10 && *r != ']' && *r != '/'; + *p++ = *r++); + *p = 0; + skip(r, ' '); + if (counter > 255) + pdftex_fail("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); + pdftex_fail + ("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%256s 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(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(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(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(p, ' '); + } + } + } + return glyph_names; +} + + +static void t1_check_end (void) +{ + if (t1_eof ()) + return; + t1_getline (); + if (t1_prefix ("{restore}")) + t1_putline (); +} + +static boolean t1_open_fontfile (const char *open_name_prefix) +{ + int callback_id = 0; + int file_opened = 0; + char *ftemp = NULL; + ff_entry *ff; + ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm)); + t1_curbyte = 0; + t1_size = 0; + if (ff->ff_path != NULL) { + callback_id=callback_defined(find_type1_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",ff->ff_path,&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + strcpy(ff->ff_path,ftemp); + } + } + } + callback_id=callback_defined(read_type1_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",ff->ff_path, + &file_opened, &t1_buffer,&t1_size) + && file_opened && t1_size>0) { + cur_file_name = ff->ff_path; + } else { + set_cur_file_name (fd_cur->fm->ff_name); + pdftex_warn ("cannot open Type 1 font file for reading"); + return false; + } + } else { + t1_file = xfopen (cur_file_name = ff->ff_path, FOPEN_RBIN_MODE); + t1_read_file(); + t1_close(); + } + } + else { + set_cur_file_name (fd_cur->fm->ff_name); + pdftex_warn ("cannot open Type 1 font file for reading"); + return false; + } + t1_init_params (open_name_prefix); + return true; +} + +static void t1_include (void) +{ + do { + t1_getline (); + t1_scan_param (); + t1_putline (); + } + while (t1_in_eexec == 0); + t1_start_eexec (); + do { + t1_getline (); + t1_scan_param (); + t1_putline (); + } + while (!(t1_charstrings () || t1_subrs ())); + t1_cs = true; + do { + t1_getline (); + t1_putline (); + } + while (!t1_end_eexec ()); + t1_stop_eexec (); + if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ + do { + t1_getline (); + t1_putline (); + } + while (!t1_cleartomark ()); + t1_check_end (); /* write "{restore}if" if found */ + } + get_length3 (); +} + +#define check_subr(subr) \ + if (subr >= subr_size || subr < 0) \ + pdftex_fail("Subrs array: entry index out of range (%i)", subr); + +static const char **check_cs_token_pair () +{ + 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 = t1_scan_num (p + 1, 0); + check_subr (subr); + ptr = subr_tab + subr; + } else { + ptr = cs_ptr++; + if (cs_ptr - cs_tab > cs_size) + pdftex_fail + ("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 = t1_buf_ptr - t1_buf_array; + ptr->cslen = t1_cslen; + 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 integer 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) { \ + pdftex_warn("CharString: invalid access (%i) to stack (%i entries)", \ + (int) N, (int)(stack_ptr - cc_stack)); \ + goto cs_error; \ +} + +/* +static integer cc_get(integer index) +{ + if (index < 0) { + if (stack_ptr + index < cc_stack ) + stack_error(stack_ptr - cc_stack + index); + return *(stack_ptr + index); + } + else { + if (cc_stack + index >= stack_ptr) + stack_error(index); + return cc_stack[index]; + } +} +*/ + +#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_ESCAPE, 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) + +__attribute__ ((format (printf, 3, 4))) +static void cs_warn (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) + pdftex_warn ("Subr (%i): %s", (int) subr, buf); + else + pdftex_warn ("CharString (/%s): %s", cs_name, buf); +} + +static void cs_mark (const char *cs_name, int subr) +{ + byte *data; + int i, b, cs_len; + integer a, a1, a2; + unsigned short cr; + static integer lastargOtherSubr3 = 3; /* the argument of last call to + OtherSubrs[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) { + pdftex_warn ("glyph `%s' undefined", cs_name); + return; + } + if (ptr->name == notdef) + cs_notdef = ptr; + } + } + /* 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 (integer) > 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_warn (cs_name, subr, "command value out of range: %i", + (int) b); + goto cs_error; + } + cc = cc_tab + b; + if (!cc->valid) { + cs_warn (cs_name, subr, "command not valid: %i", (int) b); + goto cs_error; + } + if (cc->bottom) { + if (stack_ptr - cc_stack < cc->nargs) + cs_warn (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_warn (cs_name, subr, + "more arguments on stack (%i) than required (%i)", + (int) (stack_ptr - cc_stack), (int) cc->nargs); + } + switch (cc - cc_tab) { + case CS_CALLSUBR: + a1 = cc_get (-1); + cc_pop (1); + mark_subr (a1); + if (!subr_tab[a1].valid) { + cs_warn (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); + /* 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 (); + } + } + } + return; + cs_error: /* an error occured during parsing */ + 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) +{ + return strcmp(*((const char **) pa), *((const char **) pb)); +} + +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); + assert(gl_tree != NULL); + for (i = 0; i < 256; i++) { + if (glyph_names[i] != notdef && + (char **) avl_find(gl_tree, &glyph_names[i]) == NULL) { + /* no strdup here, just point to the glyph_names array members */ + aa = avl_probe(gl_tree, &glyph_names[i]); + assert(aa != NULL); + } + } + return gl_tree; +} + +void destroy_t1_glyph_tree(struct avl_table *gl_tree) +{ + assert(gl_tree != NULL); + avl_destroy(gl_tree, NULL); +} + +/**********************************************************************/ + +static void t1_subset_ascii_part(void) +{ + int j, *p; + char *glyph, **gg, **glyph_names; + struct avl_table *gl_tree; + struct avl_traverser t; + void **aa; + assert(fd_cur != NULL); + assert(fd_cur->gl_tree != NULL); + t1_getline(); + while (!t1_prefix("/Encoding")) { + t1_scan_param(); + t1_putline(); + t1_getline(); + } + glyph_names = t1_builtin_enc(); + fd_cur->builtin_glyph_names = glyph_names; + if (is_subsetted(fd_cur->fm)) { + assert(is_included(fd_cur->fm)); + if (fd_cur->tx_tree != NULL) { + /* 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); + assert(t1_fontname_offset != 0); + strncpy(fb_array + t1_fontname_offset, fd_cur->subset_tag, 6); + } + /* now really all glyphs needed from this font are in the fd_cur->gl_tree */ + if (t1_encoding == ENC_STANDARD) + t1_puts("/Encoding StandardEncoding def\n"); + else { + t1_puts + ("/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("dup %i /%s put\n", (int) (gg - glyph_names), *gg); + j++; + } + } + destroy_t1_glyph_tree(gl_tree); + if (j == 0) + /* We didn't mark anything for the Encoding array. */ + /* We add "dup 0 /.notdef put" for compatibility */ + /* with Acrobat 5.0. */ + t1_puts("dup 0 /.notdef put\n"); + t1_puts("readonly def\n"); + } + do { + t1_getline(); + t1_scan_param(); + if (!t1_prefix("/UniqueID")) /* ignore UniqueID for subsetted fonts */ + t1_putline(); + } + 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 (void) +{ + int i, s; + cs_entry *ptr; + t1_getline (); + while (!(t1_charstrings () || t1_subrs ())) { + t1_scan_param (); + t1_putline (); + t1_getline (); + } + found: + t1_cs = true; + t1_scan = false; + if (!t1_subrs ()) + return; + subr_size_pos = strlen ("/Subrs") + 1; + /* subr_size_pos points to the number indicating dict size after "/Subrs" */ + subr_size = t1_scan_num (t1_line_array + subr_size_pos, 0); + if (subr_size == 0) { + while (!t1_charstrings ()) + t1_getline (); + return; + } + subr_tab = xtalloc (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 (); + } + /* mark the first four entries without parsing */ + for (i = 0; i < subr_size && i < 4; i++) + subr_tab[i].used = true; + /* the end of the Subrs array might have more than one line so we need to + concatnate 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 += 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) { /* CharStrings not found; + suppose 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(true) +#define t1_cs_flush() t1_flush_cs(false) + +static void t1_flush_cs (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 (*p)) + p++; + sprintf (t1_line_ptr, "%u", count); + strcat (t1_line_ptr, p); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + + cs_len = 0; /* for -Wall */ + /* create return_cs to replace unsused subr's */ + if (is_subr) { + cr = 4330; + cs_len = 0; + return_cs = xtalloc (t1_lenIV + 1, byte); + if (t1_lenIV > 0) { + for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++) + *r = cencrypt (0x00, &cr); + *r = cencrypt (CS_RETURN, &cr); + } else { + *return_cs = CS_RETURN; + } + 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 (); + } else { + /* 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 (); + sprintf (t1_line_array, " %s", cs_token_pair[1]); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + } + } + xfree (ptr->data); + if (ptr->name != notdef) + xfree (ptr->name); + } + sprintf (t1_line_array, "%s", line_end); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + if (is_subr) + 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) { /* 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 = ptr - subr_tab; +} + + +static void t1_subset_charstrings (void) +{ + cs_entry *ptr; + cs_size_pos = + strstr (t1_line_array, charstringname) + strlen (charstringname) + - t1_line_array + 1; + /* cs_size_pos points to the number indicating + dict size after "/CharStrings" */ + cs_size = t1_scan_num (t1_line_array + cs_size_pos, 0); + cs_ptr = cs_tab = xtalloc (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) + pdftex_fail + ("This Type 1 font uses 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 (void) +{ + if (t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */ + while (!strstr (t1_line_array, "definefont")) { + t1_getline (); + t1_putline (); + } + while (!t1_end_eexec ()) + t1_getline (); /* ignore the rest */ + t1_putline (); /* write "mark currentfile closefile" */ + } else + while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */ + t1_getline (); + t1_putline (); + } + t1_stop_eexec (); + if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ + while (!t1_cleartomark ()) { + t1_getline (); + t1_putline (); + } + if (!t1_synthetic) /* don't check "{restore}if" for synthetic fonts */ + t1_check_end (); /* write "{restore}if" if found */ + } + get_length3 (); +} + +void writet1(fd_entry * fd) +{ + fd_cur = fd; /* fd_cur is global inside writet1.c */ + 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)) { /* include entire font */ + if (!(fd->ff_found = t1_open_fontfile("<<"))) + return; + t1_include (); + t1_close_font_file (">>"); + return; + } + /* partial downloading */ + if (!(fd->ff_found = t1_open_fontfile("<"))) + return; + t1_subset_ascii_part (); + t1_start_eexec (); + cc_init (); + cs_init (); + t1_read_subrs (); + t1_subset_charstrings (); + t1_subset_end (); + t1_close_font_file (">"); +} + +void t1_free () +{ + xfree (t1_line_array); + xfree (t1_buf_array); +} + diff --git a/Build/source/texk/web2c/luatexdir/font/writet3.c b/Build/source/texk/web2c/luatexdir/font/writet3.c new file mode 100644 index 00000000000..42827d1b124 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writet3.c @@ -0,0 +1,348 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writet3.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" +#include <kpathsea/tex-glyph.h> +#include <kpathsea/magstep.h> +#include <string.h> + +#define T3_BUF_SIZE 1024 + +typedef char t3_line_entry; +define_array (t3_line); + +FILE *t3_file; +static boolean t3_image_used; + +static integer t3_char_procs[256]; +static float t3_char_widths[256]; +static int t3_glyph_num; +static float t3_font_scale; +static integer t3_b0, t3_b1, t3_b2, t3_b3; +static boolean is_pk_font; + +static unsigned char *t3_buffer = NULL; +static integer t3_size = 0; +static integer t3_curbyte = 0; + + +#define t3_open() \ + open_input(&t3_file, kpse_miscfonts_format, FOPEN_RBIN_MODE) +#define t3_read_file() readbinfile(t3_file,&t3_buffer,&t3_size) +#define t3_close() xfclose(t3_file, cur_file_name) +#define t3_getchar() t3_buffer[t3_curbyte++] +#define t3_eof() (t3_curbyte>t3_size) + +#define t3_prefix(s) (!strncmp(t3_line_array, s, strlen(s))) +#define t3_putchar(c) pdfout(c) + + + +#define t3_check_eof() \ + if (t3_eof()) \ + pdftex_fail("unexpected end of file"); + + +static void update_bbox (integer llx, integer lly, integer urx, integer ury, + boolean is_first_glyph) +{ + if (is_first_glyph) { + t3_b0 = llx; + t3_b1 = lly; + t3_b2 = urx; + t3_b3 = ury; + } else { + if (llx < t3_b0) + t3_b0 = llx; + if (lly < t3_b1) + t3_b1 = lly; + if (urx > t3_b2) + t3_b2 = urx; + if (ury > t3_b3) + t3_b3 = ury; + } +} + +static integer get_pk_font_scale (internalfontnumber f) +{ + return + divide_scaled (pk_scale_factor, + divide_scaled (pdf_font_size(f), one_hundred_bp, + fixed_decimal_digits + 2), 0); +} + +static integer pk_char_width (internalfontnumber f, scaled w) +{ + return + divide_scaled (divide_scaled (w, pdf_font_size(f), 7), + get_pk_font_scale (f), 0); +} + +scaled get_pk_char_width (internalfontnumber f, scaled w) +{ + return (get_pk_font_scale (f) / 100000.0) * + (pk_char_width (f, w) / 100.0) * pdf_font_size(f); +} + +static boolean writepk (internalfontnumber f) +{ + kpse_glyph_file_type font_ret; + integer llx, lly, urx, ury; + integer cw, rw, i, j; + halfword *row; + char *name; + char *ftemp = NULL; + chardesc cd; + boolean is_null_glyph, check_preamble; + integer dpi; + int callback_id=0; + int file_opened=0; + int mallocsize=0; + if (t3_buffer!=NULL) { + xfree(t3_buffer); + t3_buffer=NULL; + } + t3_curbyte=0; + t3_size=0; + + callback_id=callback_defined(find_pk_file_callback); + + if (callback_id>0) { + dpi = round (fixed_pk_resolution * + (((float) pdf_font_size(f)) / font_dsize(f))); + /* <base>.dpi/<fontname>.<tdpi>pk */ + cur_file_name = font_name(f); + mallocsize = strlen(cur_file_name)+24+9; + name = xmalloc(mallocsize); + snprintf(name,mallocsize,"%ddpi/%s.%dpk",(int)fixed_pk_resolution,cur_file_name,(int)dpi); + if(run_callback(callback_id,"S->S",name,&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(name); + name = xstrdup(ftemp); + free(ftemp); + } + } + } else { + dpi = + kpse_magstep_fix (round + (fixed_pk_resolution * + (((float) pdf_font_size(f)) / font_dsize(f))), + fixed_pk_resolution, NULL); + cur_file_name = font_name(f); + name = kpse_find_pk (cur_file_name, (unsigned) dpi, &font_ret); + if (name == NULL || + !FILESTRCASEEQ (cur_file_name, font_ret.name) || + !kpse_bitmap_tolerance ((float) font_ret.dpi, (float) dpi)) { + pdftex_warn ("Font %s at %i not found", cur_file_name, (int) dpi); + cur_file_name = NULL; + return false; + } + } + callback_id=callback_defined(read_pk_file_callback); + if (callback_id>0) { + if(! ( run_callback(callback_id,"S->bSd",name, &file_opened, &t3_buffer,&t3_size) && + file_opened && + t3_size>0 ) ) { + pdftex_warn ("Font %s at %i not found", cur_file_name, (int)dpi); + cur_file_name = NULL; + return false; + } + } else { + t3_file = xfopen (name, FOPEN_RBIN_MODE); + t3_read_file(); + t3_close(); + } + t3_image_used = true; + is_pk_font = true; + if (tracefilenames) + tex_printf (" <%s", (char *) name); + cd.rastersize = 256; + cd.raster = xtalloc (cd.rastersize, halfword); + check_preamble = true; + while (readchar (check_preamble, &cd) != 0) { + check_preamble = false; + if (!pdf_char_marked (f, cd.charcode)) + continue; + t3_char_widths[cd.charcode] = + pk_char_width (f, get_charwidth (f, cd.charcode)); + if (cd.cwidth < 1 || cd.cheight < 1) { + cd.xescape = cd.cwidth = + round (t3_char_widths[cd.charcode] / 100.0); + cd.cheight = 1; + cd.xoff = 0; + cd.yoff = 0; + is_null_glyph = true; + } else + is_null_glyph = false; + llx = -cd.xoff; + lly = cd.yoff - cd.cheight + 1; + urx = cd.cwidth + llx + 1; + ury = cd.cheight + lly; + update_bbox (llx, lly, urx, ury, t3_glyph_num == 0); + t3_glyph_num++; + pdf_new_dict (0, 0, 0); + t3_char_procs[cd.charcode] = obj_ptr; + pdf_begin_stream (); + pdf_print_real (t3_char_widths[cd.charcode], 2); + pdf_printf (" 0 %i %i %i %i d1\n", + (int) llx, (int) lly, (int) urx, (int) ury); + if (is_null_glyph) + goto end_stream; + pdf_printf ("q\n%i 0 0 %i %i %i cm\nBI\n", (int) cd.cwidth, + (int) cd.cheight, (int) llx, (int) lly); + pdf_printf ("/W %i\n/H %i\n", (int) cd.cwidth, (int) cd.cheight); + pdf_puts ("/IM true\n/BPC 1\n/D [1 0]\nID "); + cw = (cd.cwidth + 7) / 8; + rw = (cd.cwidth + 15) / 16; + row = cd.raster; + for (i = 0; i < cd.cheight; i++) { + for (j = 0; j < rw - 1; j++) { + pdfout (*row / 256); + pdfout (*row % 256); + row++; + } + pdfout (*row / 256); + if (2 * rw == cw) + pdfout (*row % 256); + row++; + } + pdf_puts ("\nEI\nQ\n"); + end_stream: + pdf_end_stream (); + } + xfree (cd.raster); + cur_file_name = NULL; + return true; +} + +void writet3 (int objnum, internalfontnumber f) +{ + + int i; + integer wptr, eptr, cptr; + int first_char, last_char; + integer pk_font_scale; + boolean is_notdef; + + + t3_glyph_num = 0; + t3_image_used = false; + for (i = 0; i < 256; i++) { + t3_char_procs[i] = 0; + t3_char_widths[i] = 0; + } + pack_file_name (tex_font_name(f), get_nullstr (), maketexlstring (".pgc",4)); + cur_file_name = makecstring (make_name_string ()); + is_pk_font = false; + + if (t3_buffer!=NULL) { + xfree(t3_buffer); + t3_buffer=NULL; + } + t3_curbyte=0; + t3_size=0; + if (!writepk (f)) { + cur_file_name = NULL; + return; + } + for (i = font_bc(f); i <= font_ec(f); i++) + if (pdf_char_marked (f, i)) + break; + first_char = i; + for (i = font_ec(f); i > first_char; i--) + if (pdf_char_marked (f, i)) + break; + last_char = i; + pdf_begin_dict (objnum, 1); /* Type 3 font dictionary */ + pdf_puts ("/Type /Font\n/Subtype /Type3\n"); + pdf_printf ("/Name /F%i\n", (int) f); + if (pdf_font_attr(f) != get_nullstr ()) { + pdf_print (pdf_font_attr(f)); + pdf_puts ("\n"); + } + if (is_pk_font) { + pk_font_scale = get_pk_font_scale (f); + pdf_puts ("/FontMatrix ["); + pdf_print_real (pk_font_scale, 5); + pdf_puts (" 0 0 "); + pdf_print_real (pk_font_scale, 5); + pdf_puts (" 0 0]\n"); + } else + pdf_printf ("/FontMatrix [%g 0 0 %g 0 0]\n", + (double) t3_font_scale, (double) t3_font_scale); + pdf_printf ("/%s [ %i %i %i %i ]\n", + font_key[FONTBBOX1_CODE].pdfname, + (int) t3_b0, (int) t3_b1, (int) t3_b2, (int) t3_b3); + pdf_printf ("/Resources << /ProcSet [ /PDF %s] >>\n", + t3_image_used ? "/ImageB " : ""); + pdf_printf ("/FirstChar %i\n/LastChar %i\n", first_char, last_char); + wptr = pdf_new_objnum (); + eptr = pdf_new_objnum (); + cptr = pdf_new_objnum (); + pdf_printf ("/Widths %i 0 R\n/Encoding %i 0 R\n/CharProcs %i 0 R\n", + (int)wptr, (int)eptr, (int)cptr); + pdf_end_dict (); + pdf_begin_obj (wptr, 1); /* chars width array */ + pdf_puts ("["); + if (is_pk_font) + for (i = first_char; i <= last_char; i++) { + pdf_print_real (t3_char_widths[i], 2); + pdf_puts (" "); + } else + for (i = first_char; i <= last_char; i++) + pdf_printf ("%i ", (int) t3_char_widths[i]); + pdf_puts ("]\n"); + pdf_end_obj (); + pdf_begin_dict (eptr, 1); /* encoding dictionary */ + pdf_printf ("/Type /Encoding\n/Differences [%i", first_char); + if (t3_char_procs[first_char] == 0) { + pdf_printf ("/%s", notdef); + is_notdef = true; + } else { + pdf_printf ("/a%i", first_char); + is_notdef = false; + } + for (i = first_char + 1; i <= last_char; i++) { + if (t3_char_procs[i] == 0) { + if (!is_notdef) { + pdf_printf (" %i/%s", i, notdef); + is_notdef = true; + } + } else { + if (is_notdef) { + pdf_printf (" %i", i); + is_notdef = false; + } + pdf_printf ("/a%i", i); + } + } + pdf_puts ("]\n"); + pdf_end_dict (); + pdf_begin_dict (cptr, 1); /* CharProcs dictionary */ + for (i = first_char; i <= last_char; i++) + if (t3_char_procs[i] != 0) + pdf_printf ("/a%i %i 0 R\n", (int) i, (int) t3_char_procs[i]); + pdf_end_dict (); + if (tracefilenames) + tex_printf (">"); + cur_file_name = NULL; +} diff --git a/Build/source/texk/web2c/luatexdir/font/writettf.c b/Build/source/texk/web2c/luatexdir/font/writettf.c new file mode 100644 index 00000000000..2a92706a0de --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writettf.c @@ -0,0 +1,1509 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writettf.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" +#include "writettf.h" +#include <string.h> + +#define DEFAULT_NTABS 14 +#define NEW_CMAP_SIZE 2 + +#define ttf_putchar fb_putchar +#define ttf_offset fb_offset +#define ttf_seek_outbuf fb_seek + + /* #define INFILE ttf_file*/ + +unsigned char *ttf_buffer = NULL; +integer ttf_size = 0; +integer ttf_curbyte = 0; + +typedef struct { + char *name; /* name of glyph */ + long code; /* charcode in case of subfonts */ + short newindex; /* new index of glyph in output file */ + +} ttfenc_entry; + +typedef struct { + TTF_USHORT platform_id; + TTF_USHORT encoding_id; + TTF_USHORT language_id; + TTF_USHORT name_id; + TTF_USHORT length; + TTF_USHORT offset; + TTF_USHORT new_offset; + TTF_USHORT new_length; +} name_record; + +typedef struct { + char *ttf_name; + TTF_USHORT pid; + TTF_USHORT eid; + short *table; +} ttf_cmap_entry; + +static TTF_USHORT ntabs; +static TTF_USHORT upem; +static TTF_FIXED post_format; +static TTF_SHORT loca_format; +static TTF_ULONG last_glyf_offset; +static TTF_USHORT glyphs_count; +static TTF_USHORT new_glyphs_count; +static TTF_USHORT nhmtxs; +static TTF_USHORT new_ntabs; + +glyph_entry *glyph_tab; +dirtab_entry *dir_tab; + +static long *glyph_index; +static cmap_entry *cmap_tab, new_cmap_tab[NEW_CMAP_SIZE]; +static name_record *name_tab; +static int name_record_num; +static char *name_buf; +static int name_buf_size; +static char *glyph_name_buf; +static TTF_ULONG checksum; +static TTF_ULONG tab_length; +static TTF_ULONG tmp_ulong; +static TTF_ULONG checkSumAdjustment_offset; +FILE *ttf_file; +static ttfenc_entry ttfenc_tab[256]; + +fd_entry *fd_cur; /* pointer to the current font descriptor */ + +static struct avl_table *ttf_cmap_tree = NULL; + +integer ttf_length; + +#include "macnames.c" + +extern char *fb_array; +extern char charsetstr[]; + +static const char *newtabnames[] = { + "OS/2", + "PCLT", + "cmap", + "cvt ", + "fpgm", + "glyf", + "head", + "hhea", + "hmtx", + "loca", + "maxp", + "name", + "post", + "prep" +}; + +ttf_cmap_entry *new_ttf_cmap_entry (void) +{ + ttf_cmap_entry *e; + e = xtalloc (1, ttf_cmap_entry); + e->ttf_name = NULL; + e->table = NULL; + return e; +} + +static void destroy_ttf_cmap_entry (void *pa, void *pb) +{ + ttf_cmap_entry *p; + p = (ttf_cmap_entry *) pa; + xfree (p->ttf_name); + xfree (p->table); + xfree (p); +} + +void ttf_free (void) +{ + if (ttf_cmap_tree != NULL) + avl_destroy (ttf_cmap_tree, destroy_ttf_cmap_entry); +} + +static int comp_ttf_cmap_entry (const void *pa, const void *pb, void *p) +{ + const ttf_cmap_entry *p1 = (const ttf_cmap_entry *) pa, + *p2 = (const ttf_cmap_entry *) pb; + int i; + assert (p1->ttf_name != NULL && p2->ttf_name != NULL); + if ((i = strcmp (p1->ttf_name, p2->ttf_name)) != 0) + return i; + cmp_return (p1->pid, p2->pid); + cmp_return (p1->eid, p2->eid); + return 0; +} + +static unsigned char ttf_addchksm (unsigned char b) +{ + tmp_ulong = (tmp_ulong << 8) + b; + tab_length++; + if (tab_length % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + return b; +} + +static TTF_ULONG ttf_getchksm (void) +{ + while (tab_length % 4 != 0) + ttf_putchar (ttf_addchksm (0)); /* ttf_addchksm updates tab_length */ + return checksum; +} + +long ttf_putnum (int s, long n) +{ + long i = n; + char buf[TTF_LONG_SIZE + 1], *p = buf; + while (s-- > 0) { + *p++ = i & 0xFF; + i >>= 8; + } + p--; + while (p >= buf) + ttf_putchar (ttf_addchksm (*p--)); + return n; +} + +long ttf_getnum (int s) +{ + long i = 0; + int c; + while (s > 0) { + if (ttf_eof()) + pdftex_fail ("unexpected EOF"); + c = ttf_getchar (); + i = (i << 8) + c; + s--; + } + return i; +} + +static long ttf_funit (long n) +{ + if (n < 0) + return -((-n / upem) * 1000 + ((-n % upem) * 1000) / upem); + else + return (n / upem) * 1000 + ((n % upem) * 1000) / upem; +} + +static void ttf_ncopy (int n) +{ + while (n-- > 0) + copy_byte (); +} + +dirtab_entry *ttf_name_lookup (const char *s, boolean required) +{ + dirtab_entry *tab; + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) + if (strncmp (tab->tag, s, 4) == 0) + break; + if (tab - dir_tab == ntabs) { + if (required) + pdftex_fail ("can't find table `%s'", s); + else + tab = NULL; + } + return tab; +} + +dirtab_entry *ttf_seek_tab (const char *name, TTF_LONG offset) +{ + dirtab_entry *tab = ttf_name_lookup (name, true); + /*xfseek (INFILE, tab->offset + offset, SEEK_SET, cur_file_name);*/ + ttf_curbyte = tab->offset + offset; + return tab; +} + +static void ttf_seek_off (TTF_LONG offset) +{ + ttf_curbyte = offset; + //xfseek (INFILE, offset, SEEK_SET, cur_file_name); +} + +static void ttf_copy_encoding(void) +{ + int i, *q; + void **aa; + char **glyph_names; + long *charcodes; + static char buf[SMALL_BUF_SIZE]; + struct avl_traverser t; + ttfenc_entry *e = ttfenc_tab; + + assert(fd_cur->tx_tree != NULL); /* this must be set in create_fontdictionary */ + + if (fd_cur->fe != NULL) { + glyph_names = fd_cur->fe->glyph_names; + assert(glyph_names != NULL); + + for (i = 0; i < 256; i++) + ttfenc_tab[i].name = (char *) notdef; + + /* a workaround for a bug of AcroReader 4.0 */ + if (strcmp(glyph_names[97], "a") == 0) { + q = xtalloc(1, int); + *q = 'a'; + aa = avl_probe(fd_cur->tx_tree, q); + assert(aa != NULL); + } + /* end of workaround */ + + /* take over collected characters from TeX, reencode them */ + avl_t_init(&t, fd_cur->tx_tree); + for (q = (int *) avl_t_first(&t, fd_cur->tx_tree); q != NULL; + q = (int *) avl_t_next(&t)) { + assert(*q >= 0 && *q < 256); + ttfenc_tab[*q].name = glyph_names[*q]; + } + make_subset_tag(fd_cur); + } else if (is_subfont(fd_cur->fm)) { + charcodes = fd_cur->fm->subfont->charcodes; + assert(charcodes != NULL); + + for (i = 0; i < 256; i++) + ttfenc_tab[i].code = -1; + + /* take over collected characters from TeX */ + avl_t_init(&t, fd_cur->tx_tree); + for (q = (int *) avl_t_first(&t, fd_cur->tx_tree); q != NULL; + q = (int *) avl_t_next(&t)) { + assert(*q >= 0 && *q < 256); + e = ttfenc_tab + *q; + e->code = charcodes[*q]; + if (e->code == -1) + pdftex_warn("character %i is not mapped to any charcode", *q); + else { + assert(e->code < 0x10000); + sprintf(buf, "/c%4.4X", (int) e->code); + aa = avl_probe(fd_cur->gl_tree, xstrdup(buf)); + assert(aa != NULL); + } + } + make_subset_tag(fd_cur); + } else + assert(0); +} + +#define ttf_append_byte(B)\ +do {\ + if (name_tab[i].platform_id == 3)\ + *q++ = 0;\ + *q++ = B;\ +} while (0) + +static char *strip_spaces_and_delims(char *s, int l) +{ + static char buf[SMALL_BUF_SIZE]; + char *p = buf; + int i; + + assert(l >= 0 && l < (int) sizeof(buf)); + + for (i = 0; i < l; s++, i++) { + if (*s == '(' || *s == ')' || *s == '<' || *s == '>' || + *s == '[' || *s == ']' || *s == '{' || *s == '}' || + *s == '/' || *s == '%' || isspace(*s)) + continue; + *p++ = *s; + } + *p = 0; + return buf; +} + +static void ttf_read_name (void) +{ + int i, j; + dirtab_entry *tab = ttf_seek_tab ("name", TTF_USHORT_SIZE); + char *p; + name_record_num = get_ushort (); + name_tab = xtalloc (name_record_num, name_record); + name_buf_size = tab->length - + (3 * TTF_USHORT_SIZE + name_record_num * 6 * TTF_USHORT_SIZE); + name_buf = xtalloc (name_buf_size, char); + ttf_skip (TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + name_tab[i].platform_id = get_ushort (); + name_tab[i].encoding_id = get_ushort (); + name_tab[i].language_id = get_ushort (); + name_tab[i].name_id = get_ushort (); + name_tab[i].length = get_ushort (); + name_tab[i].offset = get_ushort (); + } + for (p = name_buf; p - name_buf < name_buf_size; p++) + *p = get_char (); + /* look for PS font name */ + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 1 && + name_tab[i].encoding_id == 0 && name_tab[i].name_id == 6) { + xfree(fd_cur->fontname); + fd_cur->fontname = + xstrdup(strip_spaces_and_delims(name_buf + name_tab[i].offset, + name_tab[i].length)); + fd_cur->font_dim[FONTNAME_CODE].set = true; + break; + } + } + if (!fd_cur->font_dim[FONTNAME_CODE].set) { + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 3 && + (name_tab[i].encoding_id == 0 || + name_tab[i].encoding_id == 1) && name_tab[i].name_id == 6) { + for (j = 0, p = fd_cur->fontname; j < name_tab[i].length; + j += 2) + *p++ = name_buf[name_tab[i].offset + j + 1]; + *p = 0; + fd_cur->font_dim[FONTNAME_CODE].set = true; + break; + } + } + } +} + +static void ttf_read_mapx (void) +{ + glyph_entry *glyph; + ttf_seek_tab ("maxp", TTF_FIXED_SIZE); + glyph_tab = xtalloc (1 + (glyphs_count = get_ushort ()), glyph_entry); + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) { + glyph->newindex = -1; + glyph->newoffset = 0; + glyph->name_index = 0; + glyph->name = (char *) notdef; + } + glyph_index = xtalloc (glyphs_count, long); + glyph_index[0] = 0; /* index of ".notdef" glyph */ + glyph_index[1] = 1; /* index of ".null" glyph */ +} + +void ttf_read_head (void) +{ + ttf_seek_tab ("head", + 2 * TTF_FIXED_SIZE + 2 * TTF_ULONG_SIZE + TTF_USHORT_SIZE); + upem = get_ushort (); + ttf_skip (16); + fd_cur->font_dim[FONTBBOX1_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX2_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX3_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX4_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX1_CODE].set = true; + fd_cur->font_dim[FONTBBOX2_CODE].set = true; + fd_cur->font_dim[FONTBBOX3_CODE].set = true; + fd_cur->font_dim[FONTBBOX4_CODE].set = true; + ttf_skip (2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE); + loca_format = get_short (); +} + +void ttf_read_hhea (void) +{ + ttf_seek_tab ("hhea", TTF_FIXED_SIZE); + fd_cur->font_dim[ASCENT_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[DESCENT_CODE].val = ttf_funit(get_fword()); + fd_cur->font_dim[ASCENT_CODE].set = true; + fd_cur->font_dim[DESCENT_CODE].set = true; + ttf_skip (TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE + + 8 * TTF_SHORT_SIZE); + nhmtxs = get_ushort (); +} + +void ttf_read_pclt (void) +{ + if (ttf_name_lookup ("PCLT", false) == NULL) + return; + ttf_seek_tab ("PCLT", TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE); + fd_cur->font_dim[XHEIGHT_CODE].val = ttf_funit(get_ushort()); + ttf_skip(2 * TTF_USHORT_SIZE); + fd_cur->font_dim[CAPHEIGHT_CODE].val = ttf_funit(get_ushort()); + fd_cur->font_dim[XHEIGHT_CODE].set = true; + fd_cur->font_dim[CAPHEIGHT_CODE].set = true; +} + +static void ttf_read_hmtx (void) +{ + glyph_entry *glyph; + TTF_UFWORD last_advWidth; + ttf_seek_tab ("hmtx", 0); + for (glyph = glyph_tab; glyph - glyph_tab < nhmtxs; glyph++) { + glyph->advWidth = get_ufword (); + glyph->lsb = get_ufword (); + } + if (nhmtxs < glyphs_count) { + last_advWidth = glyph[-1].advWidth; + for (; glyph - glyph_tab < glyphs_count; glyph++) { + glyph->advWidth = last_advWidth; + glyph->lsb = get_ufword (); + } + } +} + +void ttf_read_post (void) +{ + int k, nnames; + long length; + long int_part, frac_part; + int sign = 1; + TTF_FIXED italic_angle; + char *p; + glyph_entry *glyph; + const dirtab_entry *tab = ttf_seek_tab ("post", 0); + post_format = get_fixed (); + italic_angle = get_fixed (); + int_part = italic_angle >> 16; + if (int_part > 0x7FFF) { /* a negative number */ + int_part = 0x10000 - int_part; + sign = -1; + } + frac_part = italic_angle % 0x10000; + fd_cur->font_dim[ITALIC_ANGLE_CODE].val = + sign * (int_part + frac_part * 1.0 / 0x10000); + fd_cur->font_dim[ITALIC_ANGLE_CODE].set = true; + if (glyph_tab == NULL) + return; /* being called from writeotf() */ + ttf_skip (2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + switch (post_format) { + case 0x10000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name = (char *) mac_glyph_names[glyph - glyph_tab]; + glyph->name_index = glyph - glyph_tab; + } + break; + case 0x20000: + nnames = get_ushort (); /* some fonts have this value different from nglyphs */ + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) + glyph->name_index = get_ushort (); + /*length = tab->length - (xftell (INFILE, cur_file_name) - tab->offset);*/ + length = tab->length - (ttf_curbyte - tab->offset); + glyph_name_buf = xtalloc (length, char); + for (p = glyph_name_buf; p - glyph_name_buf < length;) { + for (k = get_byte (); k > 0; k--) + *p++ = get_char (); + *p++ = 0; + } + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) { + if (glyph->name_index < NMACGLYPHS) + glyph->name = (char *) mac_glyph_names[glyph->name_index]; + else { + p = glyph_name_buf; + k = glyph->name_index - NMACGLYPHS; + for (; k > 0; k--) + p = strend (p) + 1; + glyph->name = p; + } + } + break; + case 0x00030000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name_index = glyph - glyph_tab; + } + break; + default: + pdftex_fail ("unsupported format (%.8X) of `post' table", + (unsigned int) post_format); + } +} + +static void ttf_read_loca (void) +{ + glyph_entry *glyph; + ttf_seek_tab ("loca", 0); + if (loca_format != 0) + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = get_ulong (); + else + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = get_ushort () << 1; +} + +void ttf_read_tabdir (void) +{ + int i; + dirtab_entry *tab; + ttf_skip (TTF_FIXED_SIZE); /* ignore the sfnt number */ + dir_tab = xtalloc (ntabs = get_ushort (), dirtab_entry); + ttf_skip (3 * TTF_USHORT_SIZE); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (i = 0; i < 4; i++) + tab->tag[i] = get_char (); + tab->checksum = get_ulong (); + tab->offset = get_ulong (); + tab->length = get_ulong (); + } +} + +static ttf_cmap_entry *ttf_read_cmap (char *ttf_name, int pid, int eid, + boolean warn) +{ + seg_entry *seg_tab, *s; + TTF_USHORT *glyphId, format, segCount; + TTF_USHORT ncmapsubtabs, tmp_pid, tmp_eid; + TTF_ULONG cmap_offset, tmp_offset; + long n, i, k, length, index; + ttf_cmap_entry tmp_e, *p; + void **aa; + + /* loop up in ttf_cmap_tree first, return if found */ + tmp_e.ttf_name = ttf_name; + tmp_e.pid = pid; + tmp_e.eid = eid; + if (ttf_cmap_tree == NULL) { + ttf_cmap_tree = avl_create (comp_ttf_cmap_entry, NULL, &avl_xallocator); + assert (ttf_cmap_tree != NULL); + } + p = (ttf_cmap_entry *) avl_find (ttf_cmap_tree, &tmp_e); + if (p != NULL) + return p; + + /* not found, have to read it */ + ttf_seek_tab ("cmap", TTF_USHORT_SIZE); /* skip the table vesrion number (=0) */ + ncmapsubtabs = get_ushort (); + /* cmap_offset = xftell (INFILE, cur_file_name) - 2 * TTF_USHORT_SIZE;*/ + cmap_offset = ttf_curbyte - 2 * TTF_USHORT_SIZE; + cmap_tab = xtalloc (ncmapsubtabs, cmap_entry); + for (i = 0; i < ncmapsubtabs; ++i) { + tmp_pid = get_ushort (); + tmp_eid = get_ushort (); + tmp_offset = get_ulong (); + if (tmp_pid == pid && tmp_eid == eid) { + ttf_seek_off (cmap_offset + tmp_offset); + format = get_ushort (); + if (format == 4) + goto read_cmap_format_4; + else { + if (warn) + pdftex_warn ("cmap format %i unsupported", format); + return NULL; + } + } + } + if (warn) + pdftex_warn ("cannot find cmap subtable for (pid,eid) = (%i, %i)", + pid, eid); + return NULL; + read_cmap_format_4: + /* initialize the new entry */ + p = new_ttf_cmap_entry (); + p->ttf_name = xstrdup (ttf_name); + p->pid = pid; + p->eid = eid; + p->table = xtalloc (0x10000, short); + for (i = 0; i < 0x10000; ++i) + p->table[i] = -1; /* unassigned yet */ + + /* read the subtable */ + length = get_ushort (); /* length of subtable */ + (void) get_ushort (); /* skip the version number */ + segCount = get_ushort () / 2; + (void) get_ushort (); /* skip searchRange */ + (void) get_ushort (); /* skip entrySelector */ + (void) get_ushort (); /* skip rangeShift */ + seg_tab = xtalloc (segCount, seg_entry); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->endCode = get_ushort (); + (void) get_ushort (); /* skip reversedPad */ + for (s = seg_tab; s - seg_tab < segCount; s++) + s->startCode = get_ushort (); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idDelta = get_ushort (); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idRangeOffset = get_ushort (); + length -= 8 * TTF_USHORT_SIZE + 4 * segCount * TTF_USHORT_SIZE; + n = length / TTF_USHORT_SIZE; /* number of glyphID's */ + glyphId = xtalloc (n, TTF_USHORT); + for (i = 0; i < n; i++) + glyphId[i] = get_ushort (); + for (s = seg_tab; s - seg_tab < segCount; s++) { + for (i = s->startCode; i <= s->endCode; i++) { + if (i == 0xFFFF) + break; + if (s->idRangeOffset != 0xFFFF) { + if (s->idRangeOffset == 0) + index = (s->idDelta + i) & 0xFFFF; + else { + k = (i - s->startCode) + s->idRangeOffset / 2 + + (s - seg_tab) - segCount; + assert (k >= 0 && k < n); + index = glyphId[k]; + if (index != 0) + index = (index + s->idDelta) & 0xFFFF; + } + if (index >= glyphs_count) + pdftex_fail ("cmap: glyph index %li out of range [0..%i)", + index, glyphs_count); + if (p->table[i] != -1) + pdftex_warn + ("cmap: multiple glyphs are mapped to unicode %.4lX, " + "only %i will be used (glyph %li being ignored)", i, + p->table[i], index); + else + p->table[i] = index; + } + } + } + xfree (seg_tab); + xfree (glyphId); + aa = avl_probe (ttf_cmap_tree, p); + assert (aa != NULL); + return p; +} + +static void ttf_read_font (void) +{ + ttf_read_tabdir (); + if (ttf_name_lookup ("PCLT", false) == NULL) + new_ntabs--; + if (ttf_name_lookup ("fpgm", false) == NULL) + new_ntabs--; + if (ttf_name_lookup ("cvt ", false) == NULL) + new_ntabs--; + if (ttf_name_lookup ("prep", false) == NULL) + new_ntabs--; + ttf_read_mapx (); + ttf_read_head (); + ttf_read_hhea (); + ttf_read_pclt (); + ttf_read_hmtx (); + ttf_read_post (); + ttf_read_loca (); + ttf_read_name (); +} + +static void ttf_reset_chksm (dirtab_entry * tab) +{ + checksum = 0; + tab_length = 0; + tmp_ulong = 0; + tab->offset = ttf_offset (); + if (tab->offset % 4 != 0) + pdftex_warn ("offset of `%4.4s' is not a multiple of 4", tab->tag); +} + + +static void ttf_set_chksm (dirtab_entry * tab) +{ + tab->length = ttf_offset () - tab->offset; + tab->checksum = ttf_getchksm (); +} + +static void ttf_copytab (const char *name) +{ + long i; + dirtab_entry *tab = ttf_seek_tab (name, 0); + ttf_reset_chksm (tab); + for (i = tab->length; i > 0; i--) + copy_char (); + ttf_set_chksm (tab); +} + +#define BYTE_ENCODING_LENGTH \ + ((256)*TTF_BYTE_SIZE + 3*TTF_USHORT_SIZE) + +static void ttf_byte_encoding (void) +{ + ttfenc_entry *e; + (void) put_ushort (0); /* format number (0: byte encoding table) */ + (void) put_ushort (BYTE_ENCODING_LENGTH); /* length of table */ + (void) put_ushort (0); /* version number */ + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) + if (e->newindex < 256) { + put_byte (e->newindex); + } else { + if (e->name != notdef) + pdftex_warn + ("glyph `%s' has been mapped to `%s' in `ttf_byte_encoding' cmap table", + e->name, notdef); + put_byte (0); /* notdef */ + } +} + +#define TRIMMED_TABLE_MAP_LENGTH (TTF_USHORT_SIZE*(5 + (256))) + +static void ttf_trimmed_table_map (void) +{ + ttfenc_entry *e; + (void) put_ushort (6); /* format number (6): trimmed table mapping */ + (void) put_ushort (TRIMMED_TABLE_MAP_LENGTH); + (void) put_ushort (0); /* version number (0) */ + (void) put_ushort (0); /* first character code */ + (void) put_ushort (256); /* number of character code in table */ + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) + (void) put_ushort (e->newindex); +} + +#define SEG_MAP_DELTA_LENGTH ((16 + (256))*TTF_USHORT_SIZE) + +static void ttf_seg_map_delta (void) +{ + ttfenc_entry *e; + (void) put_ushort (4); /* format number (4: segment mapping to delta values) */ + (void) put_ushort (SEG_MAP_DELTA_LENGTH); + (void) put_ushort (0); /* version number */ + (void) put_ushort (4); /* 2*segCount */ + (void) put_ushort (4); /* searchRange */ + (void) put_ushort (1); /* entrySelector */ + (void) put_ushort (0); /* rangeShift */ + (void) put_ushort (0xF0FF); /* endCount[0] */ + (void) put_ushort (0xFFFF); /* endCount[1] */ + (void) put_ushort (0); /* reversedPad */ + (void) put_ushort (0xF000); /* startCount[0] */ + (void) put_ushort (0xFFFF); /* startCount[1] */ + (void) put_ushort (0); /* idDelta[0] */ + (void) put_ushort (1); /* idDelta[1] */ + (void) put_ushort (2 * TTF_USHORT_SIZE); /* idRangeOffset[0] */ + (void) put_ushort (0); /* idRangeOffset[1] */ + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) + (void) put_ushort (e->newindex); +} + +#define CMAP_ENTRY_LENGTH (2*TTF_USHORT_SIZE + TTF_ULONG_SIZE) + +static void ttf_select_cmap (void) +{ + assert (sizeof (new_cmap_tab) <= NEW_CMAP_SIZE * sizeof (cmap_entry)); + new_cmap_tab[0].platform_id = 1; /* Macintosh */ + new_cmap_tab[0].encoding_id = 0; /* Symbol; ignore code page */ + new_cmap_tab[0].format = new_glyphs_count < 256 ? 0 /* byte encoding */ + : 6; /* trimmed table mapping */ + new_cmap_tab[1].platform_id = 3; /* Microsoft */ + new_cmap_tab[1].encoding_id = 0; /* Symbol; ignore code page */ + new_cmap_tab[1].format = 4; /* segment mapping to delta */ +} + +static void ttf_write_cmap (void) +{ + cmap_entry *ce; + long offset; + dirtab_entry *tab = ttf_name_lookup ("cmap", true); + ttf_select_cmap (); + ttf_reset_chksm (tab); + (void) put_ushort (0); /* table version number (0) */ + (void) put_ushort (NEW_CMAP_SIZE); /* number of encoding tables */ + offset = 2 * TTF_USHORT_SIZE + NEW_CMAP_SIZE * CMAP_ENTRY_LENGTH; + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + ce->offset = offset; + switch (ce->format) { + case 0: + offset += BYTE_ENCODING_LENGTH; + break; + case 4: + offset += SEG_MAP_DELTA_LENGTH; + break; + case 6: + offset += TRIMMED_TABLE_MAP_LENGTH; + break; + default: + pdftex_fail ("invalid format (it should not have happened)"); + } + (void) put_ushort (ce->platform_id); + (void) put_ushort (ce->encoding_id); + put_ulong (ce->offset); + } + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + switch (ce->format) { + case 0: + ttf_byte_encoding (); + break; + case 4: + ttf_seg_map_delta (); + break; + case 6: + ttf_trimmed_table_map (); + break; + } + } + ttf_set_chksm (tab); +} + +static int prepend_subset_tags (int index, char *p) +{ + const boolean is_unicode = (name_tab[index].platform_id == 3); + int i; + assert (index > 0 && index < name_record_num && fd_cur->subset_tag != NULL); + if (is_unicode) { + for (i = 0; i < 6; ++i) { + *p++ = 0; + *p++ = fd_cur->subset_tag[i]; + } + *p++ = 0; + *p++ = '+'; + return 14; + } else { + strncpy (p, fd_cur->subset_tag, 6); + p += 6; + *p++ = '+'; + return 7; + } +} + + +static void ttf_write_name (void) +{ + int i, l; + char *p; + int new_name_buf_size; + char *new_name_buf; + name_record *n; + dirtab_entry *tab = ttf_name_lookup ("name", true); + if (is_subsetted (fd_cur->fm)) { + l = 0; + for (i = 0; i < name_record_num; i++) + l += name_tab[i].length + 14; /* maximum lengh of new stogare area */ + new_name_buf = xtalloc (l, char); + /* additional space for subset tags */ + p = new_name_buf; + for (i = 0; i < name_record_num; i++) { + n = name_tab + i; + n->new_offset = p - new_name_buf; + if ((n->name_id == 1 || n->name_id == 3 || + n->name_id == 4 || n->name_id == 6) && + ((n->platform_id == 1 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 1))) { + l = prepend_subset_tags (i, p); + p += l; + } else + l = 0; + memcpy (p, name_buf + n->offset, n->length); + p += n->length; + n->new_length = n->length + l; + } + new_name_buf_size = p - new_name_buf; + } else { + new_name_buf = name_buf; + new_name_buf_size = name_buf_size; + } + ttf_reset_chksm (tab); + (void) put_ushort (0); /* Format selector */ + (void) put_ushort (name_record_num); + (void) put_ushort (3 * TTF_USHORT_SIZE + + name_record_num * 6 * TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + (void) put_ushort (name_tab[i].platform_id); + (void) put_ushort (name_tab[i].encoding_id); + (void) put_ushort (name_tab[i].language_id); + (void) put_ushort (name_tab[i].name_id); + (void) put_ushort (name_tab[i].new_length); + (void) put_ushort (name_tab[i].new_offset); + } + for (p = new_name_buf; p - new_name_buf < new_name_buf_size; p++) + put_char (*p); + ttf_set_chksm (tab); + if (new_name_buf != name_buf) + xfree (new_name_buf); +} + +static void ttf_write_dirtab (void) +{ + dirtab_entry *tab; + TTF_ULONG i, k; + char *p; + const integer save_offset = ttf_offset (); + ttf_seek_outbuf (TABDIR_OFF); + if (is_subsetted (fd_cur->fm)) { + for (i = 0; i < DEFAULT_NTABS; i++) { + tab = ttf_name_lookup (newtabnames[i], false); + if (tab == NULL) + continue; + for (k = 0; k < 4; k++) + put_char (tab->tag[k]); + put_ulong (tab->checksum); + put_ulong (tab->offset); + put_ulong (tab->length); + } + } else { + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (k = 0; k < 4; k++) + put_char (tab->tag[k]); + put_ulong (tab->checksum); + put_ulong (tab->offset); + put_ulong (tab->length); + } + } + /* adjust checkSumAdjustment */ + tmp_ulong = 0; + checksum = 0; + for (p = fb_array, i = 0; i < (unsigned) save_offset;) { + tmp_ulong = (tmp_ulong << 8) + *p++; + i++; + if (i % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + } + if (i % 4 != 0) { + pdftex_warn ("font length is not a multiple of 4 (%li)", i); + checksum <<= 8 * (4 - i % 4); + } + k = 0xB1B0AFBA - checksum; + ttf_seek_outbuf (checkSumAdjustment_offset); + put_ulong (k); + ttf_seek_outbuf (save_offset); +} + +static void ttf_write_glyf (void) +{ + long *id, k; + TTF_USHORT idx; + TTF_USHORT flags; + dirtab_entry *tab = ttf_name_lookup ("glyf", true); + const long glyf_offset = tab->offset; + const long new_glyf_offset = ttf_offset (); + ttf_reset_chksm (tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph_tab[*id].newoffset = ttf_offset () - new_glyf_offset; + if (glyph_tab[*id].offset != glyph_tab[*id + 1].offset) { + ttf_seek_off (glyf_offset + glyph_tab[*id].offset); + k = copy_short (); + ttf_ncopy (4 * TTF_FWORD_SIZE); + if (k < 0) { + do { + flags = copy_ushort (); + idx = get_ushort (); + if (glyph_tab[idx].newindex < 0) { + glyph_tab[idx].newindex = new_glyphs_count; + glyph_index[new_glyphs_count++] = idx; + /* + N.B.: Here we change `new_glyphs_count', + which appears in the condition of the `for' loop + */ + } + (void) put_ushort (glyph_tab[idx].newindex); + if (flags & ARG_1_AND_2_ARE_WORDS) + ttf_ncopy (2 * TTF_SHORT_SIZE); + else + ttf_ncopy (TTF_USHORT_SIZE); + if (flags & WE_HAVE_A_SCALE) + ttf_ncopy (TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + ttf_ncopy (2 * TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_A_TWO_BY_TWO) + ttf_ncopy (4 * TTF_F2DOT14_SIZE); + } while (flags & MORE_COMPONENTS); + if (flags & WE_HAVE_INSTRUCTIONS) + ttf_ncopy (copy_ushort ()); + } else + ttf_ncopy (glyph_tab[*id + 1].offset - glyph_tab[*id].offset - + TTF_USHORT_SIZE - 4 * TTF_FWORD_SIZE); + } + } + last_glyf_offset = ttf_offset () - new_glyf_offset; + ttf_set_chksm (tab); +} + +static void ttf_reindex_glyphs(void) +{ + ttfenc_entry *e; + glyph_entry *glyph; + int index; + short *t; + ttf_cmap_entry *cmap = NULL; + boolean cmap_not_found = false; + + /* + * reindexing glyphs: we append index of used glyphs to `glyph_index' + * while going through `ttfenc_tab'. After appending a new entry to + * `glyph_index' we set field `newindex' of corresponding entries in both + * `glyph_tab' and `ttfenc_tab' to the newly created index + */ + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) { + e->newindex = 0; /* index of ".notdef" glyph */ + + /* handle case of subfonts first */ + if (is_subfont(fd_cur->fm)) { + if (e->code == -1) + continue; + assert(fd_cur->fm->pid != -1 && fd_cur->fm->eid != -1); + if (cmap == NULL && !cmap_not_found) { + cmap = + ttf_read_cmap(fd_cur->fm->ff_name, fd_cur->fm->pid, + fd_cur->fm->eid, true); + if (cmap == NULL) + cmap_not_found = true; + } + if (cmap == NULL) + continue; + t = cmap->table; + assert(t != NULL && e->code < 0x10000); + if (t[e->code] < 0) { + pdftex_warn + ("subfont %s: wrong mapping: character %li --> 0x%4.4lX --> .notdef", + fd_cur->fm->tfm_name, (long) (e - ttfenc_tab), e->code); + continue; + } + assert(t[e->code] >= 0 && t[e->code] < glyphs_count); /* t has been read from ttf */ + glyph = glyph_tab + t[e->code]; + goto append_new_glyph; + } + + /* handle case of reencoded fonts */ + if (e->name == notdef) + continue; + /* scan form `index123' */ + if (sscanf(e->name, GLYPH_PREFIX_INDEX "%i", &index) == 1) { + if (index >= glyphs_count) { + pdftex_warn("`%s' out of valid range [0..%i)", + e->name, glyphs_count); + continue; + } + glyph = glyph_tab + index; + goto append_new_glyph; + } + /* scan form `uniABCD' */ + if (sscanf(e->name, GLYPH_PREFIX_UNICODE "%X", &index) == 1) { + if (cmap == NULL && !cmap_not_found) { + /* need to read the unicode mapping, ie (pid,eid) = (3,1) or (0,3) */ + cmap = ttf_read_cmap(fd_cur->fm->ff_name, 3, 1, false); + if (cmap == NULL) + cmap = ttf_read_cmap(fd_cur->fm->ff_name, 0, 3, false); + if (cmap == NULL) { + pdftex_warn + ("no unicode mapping found, all `uniXXXX' names will be ignored"); + cmap_not_found = true; /* once only */ + } + } + if (cmap == NULL) + continue; + t = cmap->table; + assert(t != NULL); + if (t[index] != -1) { + if (t[index] >= glyphs_count) { + pdftex_warn + ("`%s' is mapped to index %i which is out of valid range [0..%i)", + e->name, t[index], glyphs_count); + continue; + } + glyph = glyph_tab + t[index]; + goto append_new_glyph; + } else { + pdftex_warn("`unicode %s%.4X' is not mapped to any glyph", + GLYPH_PREFIX_UNICODE, index); + continue; + } + } + /* look up by name */ + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) + if (glyph->name != notdef && strcmp(glyph->name, e->name) == 0) + break; + if (!(glyph - glyph_tab < glyphs_count)) { + pdftex_warn("glyph `%s' not found", e->name); + continue; + } + append_new_glyph: + assert(glyph > glyph_tab && glyph - glyph_tab < glyphs_count); + if (glyph->newindex < 0) { + glyph_index[new_glyphs_count] = (short) (glyph - glyph_tab); + glyph->newindex = new_glyphs_count; + new_glyphs_count++; + } + e->newindex = glyph->newindex; + } +} + +static void ttf_write_head () +{ + dirtab_entry *tab; + tab = ttf_seek_tab ("head", 0); + ttf_reset_chksm (tab); + ttf_ncopy (2 * TTF_FIXED_SIZE); + checkSumAdjustment_offset = ttf_offset (); + put_ulong (0); + ttf_skip (TTF_ULONG_SIZE); /* skip checkSumAdjustment */ + ttf_ncopy (TTF_ULONG_SIZE + 2 * TTF_USHORT_SIZE + 16 + + 4 * TTF_FWORD_SIZE + 2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE); + if (is_subsetted(fd_cur->fm)) { + (void) put_short (loca_format); + (void) put_short (0); + } else + ttf_ncopy (2 * TTF_SHORT_SIZE); + ttf_set_chksm (tab); +} + +static void ttf_write_hhea (void) +{ + dirtab_entry *tab; + tab = ttf_seek_tab ("hhea", 0); + ttf_reset_chksm (tab); + ttf_ncopy (TTF_FIXED_SIZE + 3 * TTF_FWORD_SIZE + TTF_UFWORD_SIZE + + 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE); + (void) put_ushort (new_glyphs_count); + ttf_set_chksm (tab); +} + +static void ttf_write_htmx (void) +{ + long *id; + dirtab_entry *tab = ttf_seek_tab ("hmtx", 0); + ttf_reset_chksm (tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + put_ufword (glyph_tab[*id].advWidth); + put_ufword (glyph_tab[*id].lsb); + } + ttf_set_chksm (tab); +} + +static void ttf_write_loca (void) +{ + long *id; + dirtab_entry *tab = ttf_seek_tab ("loca", 0); + ttf_reset_chksm (tab); + loca_format = 0; + if (last_glyf_offset >= 0x00020000 || (last_glyf_offset & 1)) + loca_format = 1; + else + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + if (glyph_tab[*id].newoffset & 1) { + loca_format = 1; + break; + } + if (loca_format != 0) { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + put_ulong (glyph_tab[*id].newoffset); + put_ulong (last_glyf_offset); + } else { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + (void) put_ushort (glyph_tab[*id].newoffset / 2); + (void) put_ushort (last_glyf_offset / 2); + } + ttf_set_chksm (tab); +} + +static void ttf_write_mapx (void) +{ + dirtab_entry *tab = ttf_seek_tab ("maxp", TTF_FIXED_SIZE + TTF_USHORT_SIZE); + ttf_reset_chksm (tab); + put_fixed (0x00010000); + (void) put_ushort (new_glyphs_count); + ttf_ncopy (13 * TTF_USHORT_SIZE); + ttf_set_chksm (tab); +} + +static void ttf_write_OS2 (void) +{ + dirtab_entry *tab = ttf_seek_tab ("OS/2", 0); + TTF_USHORT version; + ttf_reset_chksm (tab); + version = get_ushort (); + if (version > 3) + pdftex_fail ("unknown version of OS/2 table (%.4X)", version); + (void) put_ushort (0x0001); /* fix version to 1 */ + ttf_ncopy (2 * TTF_USHORT_SIZE + 13 * TTF_SHORT_SIZE + 10 * TTF_BYTE_SIZE); + ttf_skip (4 * TTF_ULONG_SIZE); /* ulUnicodeRange 1--4 */ + put_ulong (0x00000003); /* Basic Latin + Latin-1 Supplement (0x0000--0x00FF) */ + put_ulong (0x10000000); /* Private Use (0xE000--0xF8FF) */ + put_ulong (0x00000000); + put_ulong (0x00000000); + ttf_ncopy (4 * TTF_CHAR_SIZE + TTF_USHORT_SIZE); /* achVendID + fsSelection */ + ttf_skip (2 * TTF_USHORT_SIZE); + (void) put_ushort (0x0000); /* usFirstCharIndex */ + (void) put_ushort (0xF0FF); /* usLastCharIndex */ + ttf_ncopy (5 * TTF_USHORT_SIZE); + /* for version 0 the OS/2 table ends here, the rest is for version 1 */ + put_ulong (0x80000000); /* Symbol Character Set---don't use any code page */ + put_ulong (0x00000000); + ttf_set_chksm (tab); +} + +static boolean unsafe_name (char *s) +{ + const char **p; + for (p = ambiguous_names; *p != NULL; p++) + if (strcmp (s, *p) == 0) + return true; + return false; +} + +static void ttf_write_post (void) +{ + dirtab_entry *tab = ttf_seek_tab ("post", TTF_FIXED_SIZE); + glyph_entry *glyph; + char *s; + long *id; + int l; + ttf_reset_chksm (tab); + if (!fd_cur->write_ttf_glyph_names || post_format == 0x00030000) { + put_fixed (0x00030000); + ttf_ncopy (TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + } else { + put_fixed (0x00020000); + ttf_ncopy (TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + (void) put_ushort (new_glyphs_count); + k = 0; + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS || unsafe_name (glyph->name)) + glyph->name_index = NMACGLYPHS + k++; + (void) put_ushort (glyph->name_index); + } + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS) { + s = glyph->name; + l = strlen (s); + put_byte (l); + while (l-- > 0) + put_char (*s++); + } + } + } + ttf_set_chksm (tab); +} + +static void ttf_init_font (int n) +{ + int i, k; + for (i = 1, k = 0; i <= n; i <<= 1, k++); + put_fixed (0x00010000); /* font version */ + (void) put_ushort (n); /* number of tables */ + (void) put_ushort (i << 3); /* search range */ + (void) put_ushort (k - 1); /* entry selector */ + (void) put_ushort ((n << 4) - (i << 3)); /* range shift */ + ttf_seek_outbuf (TABDIR_OFF + n * 4 * TTF_ULONG_SIZE); +} + +static void ttf_subset_font (void) +{ + ttf_init_font (new_ntabs); + if (ttf_name_lookup ("PCLT", false) != NULL) + ttf_copytab ("PCLT"); + if (ttf_name_lookup ("fpgm", false) != NULL) + ttf_copytab ("fpgm"); + if (ttf_name_lookup ("cvt ", false) != NULL) + ttf_copytab ("cvt "); + if (ttf_name_lookup ("prep", false) != NULL) + ttf_copytab ("prep"); + ttf_reindex_glyphs (); + ttf_write_glyf (); + ttf_write_loca (); + ttf_write_OS2 (); + ttf_write_head (); + ttf_write_hhea (); + ttf_write_htmx (); + ttf_write_mapx (); + ttf_write_name (); + ttf_write_post (); + ttf_write_cmap (); + ttf_write_dirtab (); +} + +static void ttf_copy_font (void) +{ + dirtab_entry *tab; + ttf_init_font (ntabs); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + if (strncmp (tab->tag, "head", 4) == 0) + ttf_write_head (); + else + ttf_copytab (tab->tag); + } + ttf_write_dirtab (); +} + +void writettf(fd_entry * fd) +{ + int callback_id; + int file_opened = 0; + char *ftemp = NULL; + fd_cur = fd; /* fd_cur is global inside writettf.c */ + assert(fd_cur->fm != NULL); + assert(is_truetype(fd_cur->fm)); + assert(is_included(fd_cur->fm)); + + set_cur_file_name(fd_cur->fm->ff_name); + + if (is_subsetted(fd_cur->fm) && (fd_cur->fe == NULL) + && !is_subfont(fd_cur->fm)) { + pdftex_warn ("Subset TrueType must be a reencoded or a subfont"); + cur_file_name = NULL; + return; + } + ttf_curbyte=0; + ttf_size=0; + callback_id=callback_defined(find_truetype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } + } + } + + callback_id=callback_defined(read_truetype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",(char *)(nameoffile+1), + &file_opened, &ttf_buffer,&ttf_size) && + file_opened && ttf_size>0) { + } else { + pdftex_fail ("cannot open TrueType font file for reading"); + } + } else { + if (!ttf_open ()) { + pdftex_fail ("cannot open TrueType font file for reading"); + } + ttf_read_file(); + ttf_close(); + } + cur_file_name = (char *) nameoffile + 1; + if (tracefilenames) { + if (is_subsetted(fd_cur->fm)) + tex_printf ("<%s", cur_file_name); + else + tex_printf ("<<%s", cur_file_name); + } + fd_cur->ff_found = true; + new_glyphs_count = 2; + new_ntabs = DEFAULT_NTABS; + dir_tab = NULL; + glyph_tab = NULL; + glyph_index = NULL; + glyph_name_buf = NULL; + name_tab = NULL; + name_buf = NULL; + ttf_read_font (); + + pdf_save_offset = pdfoffset (); + pdf_flush (); + + if (is_subsetted(fd_cur->fm)) { + ttf_copy_encoding (); + ttf_subset_font (); + } else + ttf_copy_font (); + ttf_length = ttf_offset (); + + xfree (dir_tab); + xfree (glyph_tab); + xfree (glyph_index); + xfree (glyph_name_buf); + xfree (name_tab); + xfree (name_buf); + if (tracefilenames) { + if (is_subsetted (fd_cur->fm)) + tex_printf (">"); + else + tex_printf (">>"); + } + cur_file_name = NULL; +} + +void do_writeotf(fd_entry * fd) +{ + long i; + dirtab_entry *tab; + dir_tab = NULL; + glyph_tab = NULL; + if (tracefilenames) + tex_printf ("<<%s", cur_file_name); + ttf_read_tabdir (); + /* read font parameters */ + if (ttf_name_lookup ("head", false) != NULL) + ttf_read_head (); + if (ttf_name_lookup ("hhea", false) != NULL) + ttf_read_hhea (); + if (ttf_name_lookup ("PCLT", false) != NULL) + ttf_read_pclt (); + if (ttf_name_lookup ("post", false) != NULL) + ttf_read_post (); + /* copy font file */ + tab = ttf_seek_tab ("CFF ", 0); + for (i = tab->length; i > 0; i--) + copy_char (); + xfree (dir_tab); + /* ttf_close ();*/ + if (tracefilenames) + tex_printf (">>"); +} + +void writeotf (fd_entry * fd) { + int callback_id; + int file_opened = 0; + char *ftemp = NULL; + + + fd_cur = fd; /* fd_cur is global inside writettf.c */ + assert(fd_cur->fm != NULL); + assert(is_opentype(fd_cur->fm)); + assert(is_included(fd_cur->fm)); + + set_cur_file_name(fd_cur->fm->ff_name); + ttf_curbyte=0; + ttf_size=0; + callback_id=callback_defined(find_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } + } + } + callback_id=callback_defined(read_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",(char *)(nameoffile+1), + &file_opened, &ttf_buffer,&ttf_size) && + file_opened && ttf_size>0) { + } else { + pdftex_fail ("cannot open OpenType font file for reading"); + } + } else { + if (!otf_open ()) { + pdftex_fail ("cannot open OpenType font file for reading"); + } + ttf_read_file(); + ttf_close(); + } + + cur_file_name = (char *) nameoffile + 1; + fd_cur->ff_found = true; + do_writeotf(fd); + cur_file_name = NULL; +} + +/* + To calculate the checkSum for the 'head' table which itself includes the + checkSumAdjustment entry for the entire font, do the following: + + * Set the checkSumAdjustment to 0. + * Calculate the checksum for all the tables including the 'head' table + and enter that value into the table directory. + * Calculate the checksum for the entire font. + * Subtract that value from the hex value B1B0AFBA. + * Store the result in checkSumAdjustment. + + The checkSum for the 'head table which includes the checkSumAdjustment + entry for the entire font is now incorrect. That is not a problem. Do not + change it. An application attempting to verify that the 'head' table has + not changed should calculate the checkSum for that table by not including + the checkSumAdjustment value, and compare the result with the entry in the + table directory. + + The table directory also includes the offset of the associated tagged + table from the beginning of the font file and the length of that table. + */ diff --git a/Build/source/texk/web2c/luatexdir/font/writettf.h b/Build/source/texk/web2c/luatexdir/font/writettf.h new file mode 100644 index 00000000000..ecfaa2c37e3 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writettf.h @@ -0,0 +1,172 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writettf.h 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +typedef signed char TTF_CHAR; +typedef unsigned char TTF_BYTE; +typedef signed short TTF_SHORT; +typedef unsigned short TTF_USHORT; +typedef signed long TTF_LONG; +typedef unsigned long TTF_ULONG; +typedef unsigned long TTF_FIXED; +typedef unsigned short TTF_FUNIT; +typedef signed short TTF_FWORD; +typedef unsigned short TTF_UFWORD; +typedef unsigned short TTF_F2DOT14; + +#define TTF_CHAR_SIZE 1 +#define TTF_BYTE_SIZE 1 +#define TTF_SHORT_SIZE 2 +#define TTF_USHORT_SIZE 2 +#define TTF_LONG_SIZE 4 +#define TTF_ULONG_SIZE 4 +#define TTF_FIXED_SIZE 4 +#define TTF_FWORD_SIZE 2 +#define TTF_UFWORD_SIZE 2 +#define TTF_F2DOT14_SIZE 2 + +#define ARG_1_AND_2_ARE_WORDS (1<<0) +#define ARGS_ARE_XY_VALUES (1<<1) +#define ROUND_XY_TO_GRID (1<<2) +#define WE_HAVE_A_SCALE (1<<3) +#define RESERVED (1<<4) +#define MORE_COMPONENTS (1<<5) +#define WE_HAVE_AN_X_AND_Y_SCALE (1<<6) +#define WE_HAVE_A_TWO_BY_TWO (1<<7) +#define WE_HAVE_INSTRUCTIONS (1<<8) +#define USE_MY_METRICS (1<<9) + +#define get_type(t) ((t)ttf_getnum(t##_SIZE)) +#define ttf_skip(n) ttf_getnum(n) + +#define get_byte() get_type(TTF_BYTE) +#define get_char() get_type(TTF_CHAR) +#define get_ushort() get_type(TTF_USHORT) +#define get_short() get_type(TTF_SHORT) +#define get_ulong() get_type(TTF_ULONG) +#define get_long() get_type(TTF_LONG) +#define get_fixed() get_type(TTF_FIXED) +#define get_funit() get_type(TTF_FUNIT) +#define get_fword() get_type(TTF_FWORD) +#define get_ufword() get_type(TTF_UFWORD) +#define get_f2dot14() get_type(TTF_F2DOT14) + +#define put_num(t,n) ((t)ttf_putnum(t##_SIZE, n)) + +#define put_char(n) (void)put_num(TTF_CHAR, n) +#define put_byte(n) (void)put_num(TTF_BYTE, n) +#define put_short(n) put_num(TTF_SHORT, n) +#define put_ushort(n) put_num(TTF_USHORT, n) +#define put_long(n) put_num(TTF_LONG, n) +#define put_ulong(n) (void)put_num(TTF_ULONG, n) +#define put_fixed(n) (void)put_num(TTF_FIXED, n) +#define put_funit(n) put_num(TTF_FUNIT, n) +#define put_fword(n) put_num(TTF_FWORD, n) +#define put_ufword(n) (void)put_num(TTF_UFWORD, n) +#define put_f2dot14(n) put_num(TTF_F2DOT14, n) + +#define copy_byte() put_byte(get_byte()) +#define copy_char() put_char(get_char()) +#define copy_ushort() put_ushort(get_ushort()) +#define copy_short() put_short(get_short()) +#define copy_ulong() put_ulong(get_ulong()) +#define copy_long() put_long(get_long()) +#define copy_fixed() put_fixed(get_fixed()) +#define copy_funit() put_funit(get_funit()) +#define copy_fword() put_fword(get_fword()) +#define copy_ufword() put_ufword(get_ufword()) +#define copy_f2dot14() put_f2dot14(get_f2dot14()) + +#define is_unicode_mapping(e) \ + (e->platform_id == 0 || (e->platform_id == 3 || e->encoding_id == 1)) + + +#define NMACGLYPHS 258 +#define TABDIR_OFF 12 +#define ENC_BUF_SIZE 1024 + +#define GLYPH_PREFIX_INDEX "index" +#define GLYPH_PREFIX_UNICODE "uni" + +typedef struct { + char tag[4]; + TTF_ULONG checksum; + TTF_ULONG offset; + TTF_ULONG length; +} dirtab_entry; + +typedef struct { + TTF_USHORT platform_id; + TTF_USHORT encoding_id; + TTF_ULONG offset; + TTF_USHORT format; +} cmap_entry; + +typedef struct { + TTF_USHORT endCode; + TTF_USHORT startCode; + TTF_USHORT idDelta; + TTF_USHORT idRangeOffset; +} seg_entry; + +typedef struct { + TTF_LONG offset; + TTF_LONG newoffset; + TTF_UFWORD advWidth; + TTF_FWORD lsb; + char *name; /* name of glyph */ + TTF_SHORT newindex; /* new index of glyph in output file */ + TTF_USHORT name_index; /* index of name as read from font file */ +} glyph_entry; + +/* some functions and variables are used by writetype0.c */ + +extern fd_entry *fd_cur; /* pointer to the current font descriptor */ +extern unsigned char *ttf_buffer; +extern integer ttf_size; +extern integer ttf_curbyte; +extern glyph_entry *glyph_tab; +extern dirtab_entry *dir_tab; +extern dirtab_entry *ttf_name_lookup (const char *s, boolean required); +extern dirtab_entry *ttf_seek_tab (const char *name, TTF_LONG offset); + +extern void ttf_read_tabdir (void); +extern void ttf_read_head (void); +extern void ttf_read_hhea (void); +extern void ttf_read_pclt (void); +extern void ttf_read_post (void); + +extern FILE *ttf_file; + +#define ttf_open() \ + open_input(&ttf_file, kpse_truetype_format, FOPEN_RBIN_MODE) +#define otf_open() \ + open_input(&ttf_file, kpse_opentype_format, FOPEN_RBIN_MODE) +#define ttf_read_file() \ + readbinfile(ttf_file,&ttf_buffer,&ttf_size) +#define ttf_close() xfclose(ttf_file,cur_file_name) +#define ttf_getchar() ttf_buffer[ttf_curbyte++] +#define ttf_eof() (ttf_curbyte>ttf_size) + +extern long ttf_putnum (int s, long n); +extern long ttf_getnum (int s); + + diff --git a/Build/source/texk/web2c/luatexdir/font/writetype0.c b/Build/source/texk/web2c/luatexdir/font/writetype0.c new file mode 100644 index 00000000000..0f9eecaac7c --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writetype0.c @@ -0,0 +1,124 @@ +/* +Copyright (c) 2007 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with luaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writetype0.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +#include "writettf.h" + +#include "writecff.h" + +void writetype0 (fd_entry * fd) { + int callback_id; + int file_opened = 0; + char *ftemp = NULL; + long i; + dirtab_entry *tab; + cff_font *cff; + + dir_tab = NULL; + glyph_tab = NULL; + + fd_cur = fd; /* fd_cur is global inside writettf.c */ + assert(fd_cur->fm != NULL); + assert(is_opentype(fd_cur->fm)); + assert(is_included(fd_cur->fm)); + + set_cur_file_name(fd_cur->fm->ff_name); + ttf_curbyte=0; + ttf_size=0; + callback_id=callback_defined(find_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } + } + } + callback_id=callback_defined(read_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",(char *)(nameoffile+1), + &file_opened, &ttf_buffer,&ttf_size) && + file_opened && ttf_size>0) { + } else { + pdftex_fail ("cannot open OpenType font file for reading"); + } + } else { + if (!otf_open ()) { + pdftex_fail ("cannot open OpenType font file for reading"); + } + ttf_read_file(); + ttf_close(); + } + + cur_file_name = (char *) nameoffile + 1; + fd_cur->ff_found = true; + + if (tracefilenames) { + if (is_subsetted(fd_cur->fm)) + tex_printf ("<%s", cur_file_name); + else + tex_printf ("<<%s", cur_file_name); + } + ttf_read_tabdir (); + /* read font parameters */ + if (ttf_name_lookup ("head", false) != NULL) + ttf_read_head (); + if (ttf_name_lookup ("hhea", false) != NULL) + ttf_read_hhea (); + if (ttf_name_lookup ("PCLT", false) != NULL) + ttf_read_pclt (); + if (ttf_name_lookup ("post", false) != NULL) + ttf_read_post (); + + /* copy font file */ + tab = ttf_seek_tab ("CFF ", 0); + + /* TODO the next 0 is a subfont index */ + cff = read_cff(ttf_buffer+ttf_curbyte,tab->length,0); + if (cff != NULL) { + if (cff_is_cidfont(cff)) { + write_cid_cff(cff,fd_cur,0); + /* + for (i = tab->length; i > 0; i--) + fb_putchar (ttf_getnum(1)); + */ + } else { + write_cff(cff,fd_cur,0); + } + } else { + /* not understood, just do a copy */ + for (i = tab->length; i > 0; i--) + fb_putchar (ttf_getnum(1)); + } + xfree (dir_tab); + if (tracefilenames) { + if (is_subsetted (fd_cur->fm)) + tex_printf (">"); + else + tex_printf (">>"); + } + cur_file_name = NULL; +} diff --git a/Build/source/texk/web2c/luatexdir/font/writetype2.c b/Build/source/texk/web2c/luatexdir/font/writetype2.c new file mode 100644 index 00000000000..649c350b707 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writetype2.c @@ -0,0 +1,422 @@ + +/* +Copyright (c) 2007 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with luaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writetype2.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" +#include "writettf.h" +#include "writecff.h" + +#include "sfnt.h" +#include "tt_glyf.h" + +/* forward*/ +void make_tt_subset (fd_entry * fd,unsigned char *buffer, integer buflen) ; + +unsigned long cidtogid_obj = 0; + +/* low-level helpers */ + +#define test_loc(l) \ + if ((f->loc+l)>f->buflen) { \ + fprintf (stderr,"File ended prematurely\n"); \ + uexit(1); \ + } + + +BYTE get_unsigned_byte(sfnt* f) { + test_loc(1); + return (BYTE)f->buffer[(f->loc++)]; +}; + +ICHAR get_signed_byte(sfnt* f) { + test_loc(1); + return (ICHAR)f->buffer[(f->loc++)]; +}; + +USHORT get_unsigned_pair(sfnt* f){ + USHORT l; + test_loc(2); + l = f->buffer[(f->loc++)]; + l = l*0x100 + f->buffer[(f->loc++)]; + return l; +}; + +SHORT get_signed_pair(sfnt* f){ + long l; + test_loc(2); + l = f->buffer[(f->loc++)]; + if (l>0x80) l -= 0x100; + l = l*0x100 + f->buffer[(f->loc++)]; + return l; +}; + +ULONG get_unsigned_quad(sfnt* f){ + ULONG l; + test_loc(4); + l = f->buffer[(f->loc++)]; + l = l*0x100 + f->buffer[(f->loc++)]; + l = l*0x100 + f->buffer[(f->loc++)]; + l = l*0x100 + f->buffer[(f->loc++)]; + return l; +}; + +int do_sfnt_read (unsigned char *dest, int len, sfnt *f) { + int i; + test_loc(len); + for (i=0;i<len;i++) { + *(dest+i)=f->buffer[f->loc+i]; + } + f->loc += len; + return len; +}; + +pdf_obj *pdf_new_stream(void) { + pdf_obj *stream = xmalloc(sizeof(pdf_obj)) ; + stream->length =0; + stream->data=NULL; + return stream; +}; + +void pdf_add_stream(pdf_obj *stream, unsigned char *buf, long len) { + int i; + assert (stream!=NULL); + if (stream->data==NULL) { + stream->data = xmalloc(len); + } else { + stream->data = xrealloc(stream->data,len+stream->length); + } + for (i=0;i<len;i++) { + *(stream->data+stream->length+i)=*(buf+i); + } + stream->length+=len; +}; + +void pdf_release_obj(pdf_obj *stream) { + if (stream!=NULL) { + if (stream->data!=NULL) { + xfree(stream->data); + } + xfree(stream); + } +}; + + +void +writetype2 (fd_entry * fd) { + int callback_id; + int file_opened = 0; + char *ftemp = NULL; + + glyph_tab = NULL; + + fd_cur = fd; /* fd_cur is global inside writettf.c */ + assert(fd_cur->fm != NULL); + assert(is_truetype(fd_cur->fm)); + + if (!is_subsetted(fd_cur->fm)) { + writettf(fd); + return; + } + + assert(is_included(fd_cur->fm)); + + set_cur_file_name(fd_cur->fm->ff_name); + ttf_curbyte=0; + ttf_size=0; + callback_id=callback_defined(find_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->S",(char *)(nameoffile+1),&ftemp)) { + if(ftemp!=NULL&&strlen(ftemp)) { + free(nameoffile); + namelength = strlen(ftemp); + nameoffile = xmalloc(namelength+2); + strcpy((char *)(nameoffile+1),ftemp); + free(ftemp); + } + } + } + callback_id=callback_defined(read_opentype_file_callback); + if (callback_id>0) { + if(run_callback(callback_id,"S->bSd",(char *)(nameoffile+1), + &file_opened, &ttf_buffer,&ttf_size) && + file_opened && ttf_size>0) { + } else { + pdftex_fail ("cannot open OpenType font file for reading"); + } + } else { + if (!otf_open ()) { + pdftex_fail ("cannot open OpenType font file for reading"); + } + ttf_read_file(); + ttf_close(); + } + + cur_file_name = (char *) nameoffile + 1; + fd_cur->ff_found = true; + + if (tracefilenames) { + if (is_subsetted(fd_cur->fm)) + tex_printf ("<%s", cur_file_name); + else + tex_printf ("<<%s", cur_file_name); + } + + /* here is the real work */ + + make_tt_subset(fd,ttf_buffer,ttf_size); + + /*xfree (dir_tab);*/ + if (tracefilenames) { + if (is_subsetted (fd_cur->fm)) + tex_printf (">"); + else + tex_printf (">>"); + } + cur_file_name = NULL; +} + +/* + * PDF viewer applications use following tables (CIDFontType 2) + * + * head, hhea, loca, maxp, glyf, hmtx, fpgm, cvt_, prep + * + * - from PDF Ref. v.1.3, 2nd ed. + * + * The fpgm, cvt_, and prep tables appears only when TrueType instructions + * requires them. Those tables must be preserved if they exist. + * We use must_exist flag to indicate `preserve it if present' + * and to make sure not to cause an error when it does not exist. + * + * post and name table must exist in ordinary TrueType font file, + * but when a TrueType font is converted to CIDFontType 2 font, those tables + * are no longer required. + * + * The OS/2 table (required for TrueType font for Windows and OS/2) contains + * liscencing information, but PDF viewers seems not using them. + * + * The 'name' table added. See comments in ttf.c. + */ + +static struct +{ + const char *name; + int must_exist; +} required_table[] = { + {"OS/2", 0}, {"head", 1}, {"hhea", 1}, {"loca", 1}, {"maxp", 1}, + {"name", 1}, {"glyf", 1}, {"hmtx", 1}, {"fpgm", 0}, {"cvt ", 0}, + {"prep", 0}, {NULL, 0} +}; + + +unsigned long ttc_read_offset (sfnt *sfont, int ttc_idx) +{ + long version; + unsigned long offset = 0; + unsigned long num_dirs = 0; + + sfnt_seek_set (sfont, 4); /* skip version tag */ + + version = sfnt_get_ulong(sfont); + num_dirs = sfnt_get_ulong(sfont); + if (ttc_idx < 0 || ttc_idx > num_dirs - 1) { + fprintf(stderr,"Invalid TTC index number\n"); + uexit(1); + } + + sfnt_seek_set (sfont, 12 + ttc_idx * 4); + offset = sfnt_get_ulong (sfont); + + return offset; +} + +extern int ff_get_ttc_index(char *ffname, char*psname); + +void make_tt_subset (fd_entry * fd,unsigned char *buffer, integer buflen) { + + long i, cid; + unsigned int last_cid; + glw_entry *glyph, *found; + struct avl_traverser t; + unsigned char *cidtogidmap ; + unsigned short num_glyphs, gid; + struct tt_glyphs *glyphs; + char *used_chars; + sfnt *sfont; + pdf_obj *fontfile; + int verbose = 0, error = 0; + + cidtogidmap = NULL; + + sfont = sfnt_open(buffer, buflen); + + if (sfont->type == SFNT_TYPE_TTC) { + i = ff_get_ttc_index(fd->fm->ff_name,fd->fm->ps_name); + error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, i)); + } else { + error = sfnt_read_table_directory(sfont, 0); + } + + if (error < 0) { + fprintf(stderr,"Could not parse the ttf directory.\n"); + uexit(1); + } + + glyphs = tt_build_init(); + + last_cid = 0; + num_glyphs = 1; /* .notdef */ + + 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 = found->id; + } + +#ifndef NO_GHOSTSCRIPT_BUG + cidtogidmap = NULL; +#else + cidtogidmap = xmalloc(((last_cid + 1) * 2) * sizeof(unsigned char)); + memset(cidtogidmap, 0, (last_cid + 1) * 2); +#endif + + /* fill used_chars */ + used_chars = xmalloc((last_cid + 1) * sizeof(char)); + memset(used_chars, 0, (last_cid + 1)); + 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)) { + used_chars[found->id] = 1; + } + + /* + * Map CIDs to GIDs. + */ + + num_glyphs = 1; /* .notdef */ + for (cid = 1; cid <= last_cid; cid++) { + if (used_chars[cid]==0) + continue; + gid = cid; + + +#ifndef NO_GHOSTSCRIPT_BUG + gid = tt_add_glyph(glyphs, gid, cid); +#else + gid = tt_add_glyph(glyphs, gid, num_glyphs); + cidtogidmap[2*cid ] = gid >> 8; + cidtogidmap[2*cid+1] = gid & 0xff; +#endif /* !NO_GHOSTSCRIPT_BUG */ + + num_glyphs++; + } + + if (num_glyphs==1) { + fprintf(stderr,"No glyphs in subset?.\n"); + uexit(1); + } + + if (tt_build_tables(sfont, glyphs) < 0) { + fprintf(stderr,"Could not parse the ttf buffer.\n"); + uexit(1); + } + + if (verbose > 1) { + fprintf(stdout,"[%u glyphs (Max CID: %u)]", glyphs->num_glyphs, last_cid); + } + + tt_build_finish(glyphs); + + /* Create font file */ + + for (i = 0; required_table[i].name; i++) { + if (sfnt_require_table(sfont, + required_table[i].name, + required_table[i].must_exist) < 0) { + fprintf(stderr,"Some required TrueType table does not exist."); + uexit(1); + } + } + + fontfile = sfnt_create_FontFile_stream(sfont); + + if (verbose > 1) { + fprintf(stdout,"[%ld bytes]", fontfile->length); + } + + /* squeeze in the cidgidmap */ + if (cidtogidmap!=NULL) { + cidtogid_obj = pdf_new_objnum(); + pdf_begin_dict(cidtogid_obj, 0); + pdf_printf("/Length %i\n",((last_cid + 1) * 2)); + pdf_end_dict(); + pdf_printf("stream\n"); + pdfroom ((last_cid + 1) * 2); + for (i = 0; i<((last_cid + 1) * 2); i++ ) { + pdf_buf[pdf_ptr++] = cidtogidmap[i]; + } + pdf_printf("\nendstream\n"); + } + + /* the tff subset */ + for (i = 0; i<fontfile->length; i++ ) + fb_putchar (fontfile->data[i]); + + + /* other stuff that needs fixing: */ + + /* + * DW, W, DW2, and W2 + */ + /* + if (opt_flags & CIDFONT_FORCE_FIXEDPITCH) { + pdf_add_dict(font->fontdict, + pdf_new_name("DW"), pdf_new_number(1000.0)); + } else { + add_TTCIDHMetrics(font->fontdict, glyphs, used_chars, cidtogidmap, last_cid); + if (v_used_chars) + add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, cidtogidmap, last_cid); + } + */ + + /* + * CIDSet + */ + /* + { + pdf_obj *cidset; + + cidset = pdf_new_stream(STREAM_COMPRESS); + pdf_add_stream(cidset, used_chars, last_cid/8 + 1); + pdf_add_dict(font->descriptor, + pdf_new_name("CIDSet"), + pdf_ref_obj(cidset)); + pdf_release_obj(cidset); + } + */ + + return; +} |