Commit | Line | Data |
---|---|---|
c6feef46 WJ |
1 | /* Copyright (C) 1991 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zfont0.c */ | |
21 | /* Composite font creation operator for Ghostscript */ | |
22 | #include "ghost.h" | |
23 | #include "errors.h" | |
24 | #include "oper.h" | |
25 | /* | |
26 | * The following lines used to say: | |
27 | * #include "gsmatrix.h" | |
28 | * #include "gxdevice.h" /. for gxfont.h ./ | |
29 | * Tony Li says the longer list is necessary to keep the GNU compiler | |
30 | * happy, but this is pretty hard to understand.... | |
31 | */ | |
32 | #include "gxfixed.h" | |
33 | #include "gxmatrix.h" | |
34 | #include "gzstate.h" /* must precede gxdevice */ | |
35 | #include "gxdevice.h" /* must precede gxfont */ | |
36 | #include "gschar.h" | |
37 | #include "gxfont.h" | |
38 | #include "alloc.h" | |
39 | #include "font.h" | |
40 | #include "dict.h" | |
41 | #include "name.h" | |
42 | #include "state.h" | |
43 | #include "store.h" | |
44 | ||
45 | /* Imports */ | |
46 | extern int build_gs_font(P4(os_ptr, gs_font **, font_type, ref *)); | |
47 | extern ref name_FID; | |
48 | ||
49 | /* Forward references */ | |
50 | private int ensure_char_entry(P4(os_ptr, ref *, byte *, int)); | |
51 | ||
52 | /* Names of system-known keys in type 0 font dictionaries: */ | |
53 | private ref name_EscChar; | |
54 | private ref name_FDepVector; | |
55 | private ref name_FMapType; | |
56 | private ref name_PrefEnc; | |
57 | private ref name_ShiftIn; | |
58 | private ref name_ShiftOut; | |
59 | private ref name_SubsVector; | |
60 | private ref name_Type0BuildChar; | |
61 | ||
62 | /* Initialize the composite font operators */ | |
63 | private void | |
64 | zfont0_init() | |
65 | { static names_def fnd0[] = { | |
66 | { "EscChar", &name_EscChar }, | |
67 | { "FDepVector", &name_FDepVector }, | |
68 | { "FMapType", &name_FMapType }, | |
69 | { "PrefEnc", &name_PrefEnc }, | |
70 | { "ShiftIn", &name_ShiftIn }, | |
71 | { "ShiftOut", &name_ShiftOut }, | |
72 | { "SubsVector", &name_SubsVector }, | |
73 | { "Type0BuildChar", &name_Type0BuildChar }, | |
74 | names_def_end | |
75 | }; | |
76 | init_names(fnd0); | |
77 | ||
78 | /* Make the standard BuildChar procedure executable. */ | |
79 | r_set_attrs(&name_Type0BuildChar, a_executable); | |
80 | } | |
81 | ||
82 | /* .buildfont0 */ | |
83 | /* Build a type 0 (composite) font. */ | |
84 | int | |
85 | zbuildfont0(os_ptr op) | |
86 | { ref *pfmaptype; | |
87 | gs_type0_data data; | |
88 | ref *pfdepvector; | |
89 | ref *pprefenc; | |
90 | ref *psubsvector; | |
91 | gs_font *pfont; | |
92 | font_data *pdata; | |
93 | int i; | |
94 | int code; | |
95 | check_type(*op, t_dictionary); | |
96 | if ( dict_find(op, &name_FMapType, &pfmaptype) <= 0 || | |
97 | !r_has_type(pfmaptype, t_integer) || | |
98 | pfmaptype->value.intval < (int)fmap_type_min || | |
99 | pfmaptype->value.intval > (int)fmap_type_max || | |
100 | dict_find(op, &name_FDepVector, &pfdepvector) <= 0 || | |
101 | !r_has_type(pfdepvector, t_array) | |
102 | ) | |
103 | return e_invalidfont; | |
104 | data.FMapType = (fmap_type)pfmaptype->value.intval; | |
105 | /* Check that every element of the FDepVector is a font. */ | |
106 | data.fdep_size = r_size(pfdepvector); | |
107 | for ( i = 0; i < data.fdep_size; i++ ) | |
108 | { ref *pdep = pfdepvector->value.refs + i; | |
109 | ref *pfid; | |
110 | gs_font *psub; | |
111 | if ( !r_has_type(pdep, t_dictionary) || | |
112 | dict_find(pdep, &name_FID, &pfid) <= 0 || | |
113 | !r_has_type(pfid, t_fontID) | |
114 | ) | |
115 | return e_invalidfont; | |
116 | /* | |
117 | * Check the inheritance rules. Allowed configurations | |
118 | * (paths from root font) are defined by the regular | |
119 | * expression: | |
120 | * (shift | double_escape escape* | escape*) | |
121 | * non_modal* non_composite | |
122 | */ | |
123 | psub = pfid->value.pfont; | |
124 | if ( psub->FontType == ft_composite ) | |
125 | { fmap_type fmt = psub->data.type0_data.FMapType; | |
126 | if ( fmt == fmap_double_escape || | |
127 | fmt == fmap_shift || | |
128 | fmt == fmap_escape && | |
129 | !(data.FMapType == fmap_escape || | |
130 | data.FMapType == fmap_double_escape) | |
131 | ) | |
132 | return e_invalidfont; | |
133 | } | |
134 | } | |
135 | switch ( data.FMapType ) | |
136 | { | |
137 | case fmap_escape: case fmap_double_escape: /* need EscChar */ | |
138 | code = ensure_char_entry(op, &name_EscChar, &data.EscChar, 255); | |
139 | break; | |
140 | case fmap_shift: /* need ShiftIn & ShiftOut */ | |
141 | code = ensure_char_entry(op, &name_ShiftIn, &data.ShiftIn, 15); | |
142 | if ( code == 0 ) | |
143 | code = ensure_char_entry(op, &name_ShiftOut, &data.ShiftOut, 14); | |
144 | break; | |
145 | case fmap_SubsVector: /* need SubsVector */ | |
146 | if ( dict_find(op, &name_SubsVector, &psubsvector) <= 0 || | |
147 | !r_has_type(psubsvector, t_string) || | |
148 | r_size(psubsvector) == 0 || | |
149 | (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 || | |
150 | (r_size(psubsvector) - 1) % data.subs_width != 0 | |
151 | ) | |
152 | return e_invalidfont; | |
153 | default: | |
154 | code = 0; | |
155 | } | |
156 | if ( code < 0 ) return code; | |
157 | code = build_gs_font(op, &pfont, ft_composite, &name_Type0BuildChar); | |
158 | if ( code != 0 ) return code; | |
159 | if ( dict_find(op, &name_PrefEnc, &pprefenc) <= 0 ) | |
160 | { ref nul; | |
161 | make_null_new(&nul); | |
162 | if ( (code = dict_put(op, &name_PrefEnc, &nul)) < 0 ) | |
163 | return code; | |
164 | } | |
165 | /* Fill in the font data */ | |
166 | pdata = (font_data *)(pfont->client_data); | |
167 | data.subs_size = (r_size(psubsvector) - 1) / data.subs_width; | |
168 | data.SubsVector = psubsvector->value.bytes + 1; | |
169 | data.encoding_size = r_size(&pdata->Encoding); | |
170 | data.Encoding = | |
171 | (uint *)alloc(data.encoding_size, sizeof(uint), | |
172 | "buildfont0(Encoding)"); | |
173 | /* Fill in the encoding vector, checking to make sure that */ | |
174 | /* each element is an integer between 0 and fdep_size-1. */ | |
175 | for ( i = 0; i < data.encoding_size; i++ ) | |
176 | { ref *penc = pdata->Encoding.value.refs + i; | |
177 | if ( !r_has_type(penc, t_integer) || | |
178 | (ulong)penc->value.intval >= data.fdep_size | |
179 | ) | |
180 | return e_invalidfont; | |
181 | data.Encoding[i] = (uint)penc->value.intval; | |
182 | } | |
183 | data.FDepVector = | |
184 | (gs_font **)alloc(data.fdep_size, sizeof(gs_font *), | |
185 | "buildfont0(FDepVector)"); | |
186 | for ( i = 0; i < data.fdep_size; i++ ) | |
187 | { ref *pfid; | |
188 | /* The lookup can't fail, because of the pre-check above. */ | |
189 | dict_find(pfdepvector->value.refs + i, &name_FID, &pfid); | |
190 | data.FDepVector[i] = pfid->value.pfont; | |
191 | } | |
192 | pfont->data.type0_data = data; | |
193 | return 0; | |
194 | } | |
195 | /* Private routine to find or add an integer entry in a font dictionary. */ | |
196 | private int | |
197 | ensure_char_entry(os_ptr op, ref *pname, byte *pvalue, int default_value) | |
198 | { ref *pentry; | |
199 | if ( dict_find(op, pname, &pentry) <= 0 ) | |
200 | { ref ent; | |
201 | make_int(&ent, default_value); | |
202 | return dict_put(op, pname, &ent); | |
203 | } | |
204 | else | |
205 | if ( !r_has_type(pentry, t_integer) || | |
206 | (ulong)(pentry->value.intval) > 255 | |
207 | ) | |
208 | return e_invalidfont; | |
209 | *pvalue = (byte)pentry->value.intval; | |
210 | return 0; | |
211 | } | |
212 | ||
213 | /* ------ Initialization procedure ------ */ | |
214 | ||
215 | op_def zfont0_op_defs[] = { | |
216 | {"1.buildfont0", zbuildfont0}, | |
217 | op_def_end(zfont0_init) | |
218 | }; |