Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include <stdio.h>
28 : #include <stdlib.h>
29 : #include <string.h>
30 : #include <dirent.h>
31 :
32 : #ifndef X_DISPLAY_MISSING
33 : # include <X11/Xatom.h>
34 : #else
35 : # define XA_X_HEIGHT 1
36 : # define XA_CAP_HEIGHT 2
37 : #endif
38 :
39 : #include "fontP.h"
40 : #include "gpsdrawP.h"
41 : #include "ustring.h"
42 : #include "charset.h"
43 : #include "utype.h"
44 : #include "gresource.h"
45 : #include "fileutil.h"
46 :
47 : /* standard 35 lazy printer afm files may be found at ftp://ftp.adobe.com/pub/adobe/type/win/all/afmfiles/base35 */
48 :
49 : struct temp_font {
50 : XCharStruct *per_char;
51 : struct kern_info **kerns;
52 : int max_alloc;
53 : int font_as, font_ds;
54 : float llx, lly, urx, ury;
55 : int cap_h, x_h;
56 : int ch_width, ch_height; /* fixed width fonts may not have the width in the char metrics */
57 : XCharStruct max_b;
58 : XCharStruct min_b;
59 : unsigned int is_8859_1:1;
60 : unsigned int is_adobe:1;
61 : unsigned int any_kerns: 1;
62 : unsigned int prop: 1;
63 : char *names[256];
64 : int min_ch, max_ch;
65 : int min_ch2, max_ch2;
66 : char family_name[200];
67 : };
68 :
69 : static char *iso_8859_1_names[256] = {
70 : "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
71 : "", "", "", "", "", "", "", "", "", "", "", "",
72 : "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand",
73 : "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "minus",
74 : "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
75 : "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question",
76 : "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
77 : "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
78 : "backslash", "bracketright", "asciicircum", "underscore", "quoteleft",
79 : "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
80 : "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
81 : "braceright", "asciitilde", "", "", "", "", "", "", "", "", "", "", "",
82 : "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
83 : "", "", "", "", "nbspace", "exclamdown", "cent", "sterling", "currency", "yen",
84 : "brokenbar", "section", "eresis", "copyright", "ordfeminine", "guillemotleft",
85 : "logicalnot", "hyphen", "registered", "cron", "degree", "plusminus",
86 : "twosuperior", "threesuperior", "ute", "mu", "paragraph", "periodcentered",
87 : "dilla", "onesuperior", "ordmasculine", "guillemotright", "onequarter",
88 : "onehalf", "threequarters", "questiondown", "Agrave", "Aacute", "Acircumflex",
89 : "Atilde", "Adieresis", "Aring", "AE", "Ccedilla", "Egrave", "Eacute",
90 : "Ecircumflex", "Edieresis", "Igrave", "Iacute", "Icircumflex", "Idieresis",
91 : "Eth", "Ntilde", "Ograve", "Oacute", "Ocircumflex", "Otilde", "Odieresis",
92 : "multiply", "Oslash", "Ugrave", "Uacute", "Ucircumflex", "Udieresis",
93 : "Yacute", "Thorn", "germandbls", "agrave", "aacute", "acircumflex",
94 : "atilde", "adieresis", "aring", "ae", "ccedilla", "egrave", "eacute",
95 : "ecircumflex", "edieresis", "igrave", "iacute", "icircumflex", "idieresis",
96 : "eth", "ntilde", "ograve", "oacute", "ocircumflex", "otilde", "odieresis",
97 : "divide", "oslash", "ugrave", "uacute", "ucircumflex", "udieresis", "yacute",
98 : "thorn", "ydieresis"
99 : };
100 :
101 0 : static int find_char(struct temp_font *tf,char *name) {
102 : int i;
103 0 : if ( tf->is_adobe ) {
104 0 : for ( i=0; i<256; ++i )
105 0 : if ( iso_8859_1_names[i]!=NULL && strcmp(name,iso_8859_1_names[i])==0 )
106 0 : return( i );
107 : } else {
108 0 : for ( i=0; i<256; ++i )
109 0 : if ( tf->names[i]!=NULL && strcmp(name,tf->names[i])==0 )
110 0 : return( i );
111 : }
112 :
113 0 : return( -1 );
114 : }
115 :
116 0 : static int name_char(struct temp_font *tf,int ch, char *name) {
117 :
118 0 : if ( tf->is_adobe )
119 0 : return( find_char(tf,name));
120 0 : if ( ch>=tf->max_alloc ) {
121 0 : if ( tf->max_alloc==256 ) tf->max_alloc = 128*256; else tf->max_alloc = 65536;
122 0 : tf->per_char = realloc(tf->per_char,tf->max_alloc*sizeof(XCharStruct));
123 0 : tf->kerns = realloc(tf->kerns,tf->max_alloc*sizeof(struct kern_info *));
124 : }
125 0 : if ( ch!=-1 && ch<256 && name[0]!='\0')
126 0 : tf->names[ch] = copy(name);
127 0 : return( ch );
128 : }
129 :
130 0 : static void parse_CharMetric_line(struct temp_font *tf, char *line) {
131 : int ch, ch2, wid; float a1, a2, a3, a4;
132 : char name[201], *pt;
133 :
134 0 : while ( isspace(*line)) ++line;
135 0 : if ( *line=='\0' )
136 0 : return;
137 0 : wid = tf->ch_width; ch= -1; name[0]='\0';
138 0 : for ( pt=line; pt && *pt ; ) {
139 0 : if ( isspace(*pt) || *pt==';' )
140 0 : ++pt;
141 : else {
142 0 : if ( pt[0]=='C' && isspace(pt[1]))
143 0 : sscanf( pt, "C %d", &ch );
144 0 : else if ( pt[0]=='C' && pt[1]=='H' && isspace(pt[2]))
145 0 : sscanf( pt, "CH <%x>", (unsigned *) &ch );
146 0 : else if ( pt[0]=='W' && pt[1]=='X' && isspace(pt[2]))
147 0 : sscanf( pt, "WX %d", &wid );
148 0 : else if ( pt[0]=='W' && pt[1]=='0' && pt[2]=='X' && isspace(pt[3]))
149 0 : sscanf( pt, "W0X %d", &wid );
150 0 : else if ( pt[0]=='N' && isspace(pt[1]))
151 0 : sscanf( pt, "N %200s", name );
152 0 : else if ( pt[0]=='B' && isspace(pt[1]))
153 0 : sscanf( pt, "B %g %g %g %g", &a1, &a2, &a3, &a4 );
154 0 : pt = strchr(pt,';');
155 : }
156 : }
157 :
158 0 : if ( (ch2 = name_char(tf,ch,name))== -1 ) {
159 0 : if ( tf->is_8859_1 )
160 0 : fprintf( stderr, "Unknown character name <%s>\n", name );
161 0 : return;
162 : }
163 0 : if ( ch2>=tf->max_ch ) tf->max_ch = ch2;
164 0 : if ( ch2<=tf->min_ch ) tf->min_ch = ch2;
165 0 : if ( (ch2&0xff)>=tf->max_ch2 ) tf->max_ch2 = (ch2&0xff);
166 0 : if ( (ch2&0xff)<=tf->min_ch2 ) tf->min_ch2 = (ch2&0xff);
167 0 : a2 = -a2; /* a descent of 1 == a bbox of -1 */
168 0 : tf->per_char[ch2].width = wid;
169 0 : tf->per_char[ch2].lbearing = a1+.5;
170 0 : tf->per_char[ch2].rbearing = a3+.5;
171 0 : tf->per_char[ch2].ascent = a4+.5;
172 0 : tf->per_char[ch2].descent = a2+.5;
173 0 : tf->per_char[ch2].attributes |= AFM_EXISTS;
174 0 : if ( tf->max_b.lbearing<a1 ) tf->max_b.lbearing = a1;
175 0 : if ( tf->max_b.rbearing<a1 ) tf->max_b.rbearing = a3;
176 0 : if ( tf->max_b.ascent<a1 ) tf->max_b.ascent = a2;
177 0 : if ( tf->max_b.descent<a1 ) tf->max_b.descent = a4;
178 0 : if ( tf->max_b.width<wid ) tf->max_b.width = wid;
179 0 : if ( tf->min_b.lbearing>a1 ) tf->min_b.lbearing = a1;
180 0 : if ( tf->min_b.rbearing>a1 ) tf->min_b.rbearing = a3;
181 0 : if ( tf->min_b.ascent>a1 ) tf->min_b.ascent = a2;
182 0 : if ( tf->min_b.descent>a1 ) tf->min_b.descent = a4;
183 0 : if ( tf->min_b.width>wid ) tf->min_b.width = wid;
184 : }
185 :
186 0 : static char *skipwhite(char *pt) {
187 0 : while ( isspace(*pt)) ++pt;
188 0 : return( pt );
189 : }
190 :
191 0 : static void parse_KernData_line(struct temp_font *tf, char *line) {
192 : int ch, ch2, kern;
193 : char name[200], name2[200];
194 : struct kern_info *ki;
195 :
196 0 : while ( isspace(*line)) ++line;
197 0 : if ( *line=='\0' )
198 0 : return;
199 0 : if ( sscanf(line,"KPX %s %s %d", name, name2, &kern )!= 3 ) {
200 0 : if ( sscanf(line,"KP %s %s %d", name, name2, &kern )!= 3 ) {
201 0 : fprintf( stderr, "Bad afm kern line <%s>\n", line );
202 0 : return;
203 : }
204 : }
205 0 : if ( (ch = find_char(tf,name))== -1 ) {
206 0 : if ( tf->is_8859_1 )
207 0 : fprintf( stderr, "Unknown character name <%s>\n", name );
208 0 : return;
209 : }
210 0 : if ( (ch2 = find_char(tf,name2))== -1 ) {
211 0 : if ( tf->is_8859_1 )
212 0 : fprintf( stderr, "Unknown character name <%s>\n", name2 );
213 0 : return;
214 : }
215 0 : tf->per_char[ch].attributes |= AFM_KERN;
216 0 : ki = malloc(sizeof(struct kern_info));
217 0 : ki->next = tf->kerns[ch];
218 0 : tf->kerns[ch] = ki;
219 0 : ki->following = ch2;
220 0 : ki->kern = kern;
221 : }
222 :
223 0 : static void ParseCharMetrics(FILE *file,struct temp_font *tf, char *line, char *pt) {
224 : int cnt,i;
225 :
226 0 : cnt = strtol(skipwhite(pt),NULL,10);
227 0 : for ( i=0; i<cnt && fgets(line,400,file)!=NULL; ++i ) {
228 0 : int len = strlen(line);
229 0 : if ( line[len-1]=='\n' ) line[--len]='\0';
230 0 : if ( line[len-1]=='\r' ) line[--len]='\0';
231 0 : parse_CharMetric_line(tf,line);
232 : }
233 0 : }
234 :
235 0 : static void ParseKernData(FILE *file,struct temp_font *tf, char *line, char *pt) {
236 : int cnt,i;
237 :
238 0 : while ( fgets(line,400,file)!=NULL ) {
239 0 : if ( strstartmatch("EndKernData",line))
240 0 : return;
241 0 : else if (( pt = strstartmatch("StartKernPairs",line))!=NULL )
242 0 : break;
243 : }
244 0 : cnt = strtol(skipwhite(pt),NULL,10);
245 0 : for ( i=0; i<cnt && fgets(line,400,file)!=NULL; ++i ) {
246 0 : int len = strlen(line);
247 0 : if ( line[len-1]=='\n' ) line[--len]='\0';
248 0 : if ( line[len-1]=='\r' ) line[--len]='\0';
249 0 : parse_KernData_line(tf,line);
250 : }
251 : }
252 :
253 0 : static void buildXFont(struct temp_font *tf,struct font_data *fd) {
254 : XFontStruct *info;
255 : int i;
256 :
257 0 : fd->info = info = malloc(sizeof(XFontStruct));
258 : /* Where do I get the ascent and descent out of a postscript font???? */
259 0 : if ( tf->font_as!=0 && tf->font_ds!=0 ) {
260 0 : info->ascent = tf->font_as + (1000-tf->font_as+tf->font_ds)/2;
261 : } else
262 0 : info->ascent = tf->ury + (1000-tf->ury+tf->lly)/2;
263 0 : info->descent = 1000-info->ascent;
264 0 : info->min_bounds = tf->min_b;
265 0 : info->max_bounds = tf->max_b;
266 0 : if ( tf->x_h!=0 || tf->cap_h!=0 ) {
267 0 : info->n_properties = (tf->x_h!=0)+(tf->cap_h!=0);
268 0 : info->properties = malloc( info->n_properties*sizeof( XFontProp));
269 0 : i=0;
270 0 : if ( tf->x_h!=0 ) {
271 0 : info->properties[i].name = XA_X_HEIGHT;
272 0 : info->properties[i++].card32 = tf->x_h;
273 : }
274 0 : if ( tf->cap_h!=0 ) {
275 0 : info->properties[i].name = XA_CAP_HEIGHT;
276 0 : info->properties[i++].card32 = tf->cap_h;
277 : }
278 : }
279 0 : if ( tf->max_ch>=256 ) {
280 : int i,row;
281 0 : info->min_byte1 = tf->min_ch>>8;
282 0 : info->max_byte1 = tf->max_ch>>8;
283 0 : info->min_char_or_byte2 = tf->min_ch2;
284 0 : info->max_char_or_byte2 = tf->max_ch2;
285 0 : row = (info->max_char_or_byte2-info->min_char_or_byte2+1);
286 0 : info->per_char = malloc((info->max_byte1-info->min_byte1+1)*
287 : row*sizeof(XCharStruct));
288 0 : for ( i=info->min_byte1; i<info->max_byte1; ++i )
289 0 : memcpy(info->per_char+(i-info->min_byte1)*row,
290 0 : tf->per_char+i*256+info->min_char_or_byte2,
291 : row*sizeof(XCharStruct));
292 : /* Don't support kerns here */
293 : } else {
294 0 : info->min_char_or_byte2 = tf->min_ch;
295 0 : info->max_char_or_byte2 = tf->max_ch;
296 0 : info->per_char = malloc((tf->max_ch-tf->min_ch+1)*sizeof(XCharStruct));
297 0 : memcpy(info->per_char,tf->per_char+tf->min_ch,(tf->max_ch-tf->min_ch+1)*sizeof(XCharStruct));
298 0 : if ( tf->any_kerns ) {
299 0 : fd->kerns = malloc((tf->max_ch-tf->min_ch+1)*sizeof(struct kern_info *));
300 0 : memcpy(fd->kerns,tf->per_char+tf->min_ch,(tf->max_ch-tf->min_ch+1)*sizeof(struct kern_info *));
301 : }
302 : }
303 0 : }
304 :
305 : /* if fd is NULL, then don't read the font metrics stuff */
306 : /* but create the fd and hash it into the fontstate */
307 0 : static void parse_afm(FState *fonts, char *filename, struct font_data *fd) {
308 : FILE *file;
309 : char line[400];
310 : struct temp_font ti;
311 : char *pt;
312 0 : int full = (fd!=NULL);
313 : struct font_name *fn;
314 : unichar_t ubuf[300];
315 :
316 0 : if (( file=fopen(filename,"r"))==NULL ) {
317 0 : GDrawIError( "Can't open afm file %s\n", filename);
318 0 : return;
319 : }
320 0 : memset(&ti,'\0',sizeof(ti));
321 0 : ti.min_ch = 65535;
322 0 : ti.prop = true;
323 0 : if ( fd==NULL )
324 0 : fd = calloc(1,sizeof(*fd));
325 :
326 0 : while ( fgets(line,sizeof(line),file)!=NULL ) {
327 0 : int len = strlen(line);
328 0 : if ( line[len-1]=='\n' ) line[--len]='\0';
329 0 : if ( line[len-1]=='\r' ) line[--len]='\0';
330 0 : if (( pt = strstartmatch("FontName", line))!=NULL ) {
331 0 : if ( !full ) {
332 0 : fd->localname = copy(skipwhite(pt));
333 0 : fd->weight = _GDraw_FontFigureWeights(def2u_strncpy(ubuf,fd->localname,sizeof(ubuf)/sizeof(ubuf[0])));
334 0 : if ( strstrmatch(fd->localname,"Italic") || strstrmatch(fd->localname,"Oblique"))
335 0 : fd->style = fs_italic;
336 0 : if ( strstrmatch(fd->localname,"SmallCaps") )
337 0 : fd->style = fs_smallcaps;
338 0 : if ( strstrmatch(fd->localname,"condensed") )
339 0 : fd->style = fs_condensed;
340 0 : if ( strstrmatch(fd->localname,"extended") )
341 0 : fd->style = fs_extended;
342 : }
343 0 : } else if (( pt = strstartmatch("FamilyName", line))!=NULL )
344 0 : strcpy(ti.family_name,skipwhite(pt));
345 0 : else if (( pt = strstartmatch("Weight", line))!=NULL )
346 : /*fd->weight = 3*/ /* !!!! */;
347 0 : else if (( pt = strstartmatch("EncodingScheme", line))!=NULL ) {
348 0 : if ( full )
349 : /* Don't bother, we've done it before */;
350 0 : else if ( strcmp(skipwhite(pt),"AdobeStandardEncoding")==0 ) {
351 0 : fd->map = em_iso8859_1;
352 0 : fd->needsremap = true;
353 0 : ti.is_adobe = 1;
354 0 : } else if ( strcmp(skipwhite(pt),"SymbolEncoding")==0 ) {
355 0 : fd->map = em_symbol;
356 0 : } else if ( strcmp(skipwhite(pt),"FontSpecific")==0 &&
357 0 : fd->localname!=NULL && strcmp(fd->localname,"Symbol")==0 ) {
358 0 : fd->map = em_symbol;
359 0 : } else if ( strcmp(skipwhite(pt),"DingbatsEncoding")==0 ) {
360 0 : fd->map = em_zapfding;
361 0 : } else if ( strcmp(skipwhite(pt),"FontSpecific")==0 &&
362 0 : fd->localname!=NULL && strcmp(fd->localname,"ZapfDingbats")==0 ) {
363 0 : fd->map = em_zapfding;
364 : } else {
365 0 : fd->map = _GDraw_ParseMapping(def2u_strncpy(ubuf,skipwhite(pt),sizeof(ubuf)/sizeof(ubuf[0])));
366 0 : if ( fd->map==em_none ) {
367 0 : if ( !full )
368 0 : fd->charmap_name = uc_copy(skipwhite(pt));
369 0 : fd->map = em_max;
370 : /* Might turn out to be a user specified mapping later */
371 : }
372 0 : ti.is_8859_1 = (fd->map == em_iso8859_1);
373 : }
374 0 : } else if (( pt = strstartmatch("Ascender", line))!=NULL )
375 0 : sscanf(pt, "%d", &ti.font_as );
376 0 : else if (( pt = strstartmatch("Descender", line))!=NULL )
377 0 : sscanf(pt, "%d", &ti.font_ds );
378 0 : else if (( pt = strstartmatch("CapHeight", line))!=NULL ) {
379 0 : sscanf(pt, "%d", &ti.cap_h );
380 0 : fd->cap_height = ti.cap_h;
381 0 : } else if (( pt = strstartmatch("XHeight", line))!=NULL ) {
382 0 : sscanf(pt, "%d", &ti.x_h );
383 0 : fd->cap_height = ti.x_h;
384 0 : } else if (( pt = strstartmatch("FontBBox", line))!=NULL )
385 0 : sscanf(pt, "%g %g %g %g", &ti.llx, &ti.lly, &ti.urx, &ti.ury );
386 0 : else if (( pt = strstartmatch("CharWidth", line))!=NULL ) {
387 0 : ti.prop = false;
388 0 : sscanf(pt, "%d %d", &ti.ch_width, &ti.ch_height );
389 0 : } else if (( pt = strstartmatch("IsFixedPitch", line))!=NULL )
390 0 : ti.prop = strstrmatch(pt,"true")==NULL;
391 0 : else if (( pt = strstartmatch("MetricSets", line))!=NULL ) {
392 : int val;
393 0 : sscanf(pt, "%d", &val );
394 0 : if ( val==1 ) { /* Can't handle vertical printing */
395 0 : fclose(file);
396 0 : free(fd);
397 0 : return;
398 : }
399 0 : } else if (( pt = strstartmatch("MappingScheme", line))!=NULL ) {
400 : int val;
401 0 : sscanf(pt, "%d", &val );
402 0 : if ( val!=2 ) { /* Can only handle 8/8 mapping (ie. 2 byte chars) */
403 0 : fclose(file);
404 0 : free(fd);
405 0 : return;
406 : }
407 0 : } else if (( pt = strstartmatch("IsCIDFont", line))!=NULL ) {
408 0 : if ( strstrmatch(pt,"true")!=NULL ) { /* I need a mapping! */
409 0 : fclose(file);
410 0 : free(fd);
411 0 : return;
412 : }
413 0 : } else if (( pt = strstartmatch("StartCharMetrics", line))!=NULL ) {
414 0 : if ( !full )
415 0 : break;
416 0 : ti.max_alloc = 256;
417 0 : ti.per_char = malloc(256*sizeof(XCharStruct));
418 0 : ti.kerns = malloc(256*sizeof(struct kern_info *));
419 0 : ParseCharMetrics(file,&ti,line,pt);
420 0 : } else if (( pt = strstartmatch("StartKernData", line))!=NULL ) {
421 0 : if ( !full )
422 0 : break;
423 0 : ParseKernData(file,&ti,line,pt);
424 : }
425 : }
426 0 : fclose(file);
427 :
428 0 : if ( !full ) {
429 : static char *extensions[] = { ".pfa", ".PFA", ".pfb", ".PFB", ".ps", ".PS", NULL };
430 : int i;
431 0 : strcpy(line,filename);
432 0 : fd->metricsfile = copy(filename);
433 : /* some directory trees put the afm files in their own sub-directory */
434 0 : if (( pt = strstr(line,"/afm/"))!=NULL )
435 0 : strcpy(pt,pt+4);
436 0 : pt = strrchr(line,'.');
437 0 : if ( pt!=NULL ) {
438 0 : for ( i=0; extensions[i]!=NULL; ++i ) {
439 0 : strcpy(pt,extensions[i]);
440 0 : if ( GFileExists(line)) {
441 0 : fd->fontfile = copy(line);
442 0 : break;
443 : }
444 : }
445 : }
446 0 : fn = _GDraw_HashFontFamily(fonts,
447 : def2u_strncpy(ubuf,ti.family_name,sizeof(ubuf)/sizeof(ubuf[0])),
448 0 : ti.prop);
449 0 : fd->next = fn->data[fd->map];
450 0 : fn->data[fd->map] = fd;
451 0 : fd->parent = fn;
452 0 : fd->is_scalable = true;
453 : } else
454 0 : buildXFont(&ti,fd);
455 0 : free(ti.kerns); free(ti.per_char);
456 : }
457 :
458 0 : int _GPSDraw_InitFonts(FState *fonts) {
459 : char *pt, *path, *pp, *epp;
460 : char dirname[1025], filename[1200];
461 : DIR *file;
462 : struct dirent *rec;
463 : int offset;
464 :
465 0 : if ( fonts->names_loaded!=0 )
466 0 : return( true );
467 :
468 0 : path = GResourceFindString("PSFontPath");
469 0 : if ( path==NULL )
470 0 : path = copy(getenv("PSFONTPATH"));
471 0 : if ( path==NULL ) {
472 0 : path = copy(GFileBuildName(GResourceProgramDir,"print",filename,sizeof(filename)));
473 : /* append /print to program directory */
474 : }
475 :
476 0 : for ( pp = path; *pp; pp = epp ) {
477 0 : if (( epp = strchr(pp,':'))==NULL )
478 0 : epp = pp+strlen(pp);
479 0 : strncpy(dirname,pp,epp-pp);
480 0 : GFileBuildName(dirname,"afm",dirname,sizeof(dirname));
481 0 : if ( !GFileExists(dirname))
482 0 : dirname[epp-pp] = '\0';
483 0 : file = opendir(dirname);
484 0 : if ( file!=NULL ) {
485 0 : if (( rec = readdir(file))==NULL ) { /* Must have "." */
486 0 : closedir(file);
487 0 : continue;
488 : }
489 : /* There's a bug in some solaris readdir libs, so that the structure */
490 : /* returned doesn't match the include file alignment */
491 0 : offset = 0;
492 0 : if ( strcmp(rec->d_name,".")!=0 && strcmp(rec->d_name-2,".")==0 )
493 0 : offset = -2;
494 0 : while ( (rec = readdir(file))!=NULL ) {
495 0 : char *name = rec->d_name+offset;
496 0 : if ( (pt = strstrmatch(name,".afm"))!=NULL && pt[4]=='\0' ) { /* don't find "*.afm~" */
497 0 : GFileBuildName(dirname,name,filename,sizeof(filename));
498 0 : parse_afm(fonts,filename,NULL);
499 : /* I don't understand acfm files, but I think I can skip 'em */
500 : }
501 : }
502 0 : closedir(file);
503 : }
504 : }
505 0 : fonts->names_loaded = true;
506 0 : return( fonts->names_loaded );
507 : }
508 :
509 0 : void _GPSDraw_ResetFonts(FState *fonts) {
510 : int j;
511 : struct font_name *fn;
512 : struct font_data *fd, *prev, *next;
513 : int map;
514 :
515 : /* After we are done printing we need to reset the font state (if we start another*/
516 : /* print job and we leave the old state hanging around we will think fonts have */
517 : /* been downloaded that are long forgotten by the printer */
518 0 : for ( j=0; j<26; ++j ) {
519 0 : for ( fn = fonts->font_names[j]; fn!=NULL; fn=fn->next ) {
520 0 : for ( map=0; map<em_max; ++map ) {
521 0 : prev = NULL;
522 0 : for ( fd=fn->data[map]; fd!=NULL; fd=next ) {
523 0 : next = fd->next;
524 0 : if ( fd->point_size!=0 ) {
525 0 : _GDraw_FreeFD(fd);
526 0 : if ( prev==NULL )
527 0 : fn->data[map] = next;
528 : else
529 0 : prev->next = next;
530 : } else {
531 0 : prev = fd;
532 0 : fd->copiedtoprinter = false;
533 0 : fd->includenoted = false;
534 0 : fd->remapped = false;
535 : }
536 : }
537 : }
538 : }
539 : }
540 0 : }
541 :
542 :
543 0 : void _GPSDraw_ListNeededFonts(GPSWindow ps) {
544 0 : FState *fonts = ps->display->fontstate;
545 : int j;
546 : struct font_name *fn;
547 : struct font_data *fd, *prev, *next;
548 : int map;
549 0 : int first = true;
550 :
551 : /* After we are done printing we need to tell postscript what fonts we expect */
552 : /* to be on the printer */
553 0 : for ( j=0; j<26; ++j ) {
554 0 : for ( fn = fonts->font_names[j]; fn!=NULL; fn=fn->next ) {
555 0 : for ( map=0; map<em_max; ++map ) {
556 0 : prev = NULL;
557 0 : for ( fd=fn->data[map]; fd!=NULL; fd=next ) {
558 0 : next = fd->next;
559 0 : if ( fd->point_size==0 && fd->includenoted ) {
560 0 : if ( first )
561 0 : fprintf(ps->output_file, "%%%%DocumentNeededResources: font %s\n",
562 : fd->localname );
563 : else
564 0 : fprintf(ps->output_file, "%%%%+ font %s\n",
565 : fd->localname );
566 0 : first = false;
567 : }
568 : }
569 : }
570 : }
571 : }
572 0 : if ( first ) {
573 : /* not sure how to say we don't need anything, but the PS Ref Man */
574 : /* says there must be a line at end if there's an (atend) at start */
575 0 : fprintf(ps->output_file, "%%%%DocumentNeededResources:\n" );
576 : }
577 :
578 0 : first = true;
579 0 : for ( j=0; j<26; ++j ) {
580 0 : for ( fn = fonts->font_names[j]; fn!=NULL; fn=fn->next ) {
581 0 : for ( map=0; map<em_max; ++map ) {
582 0 : prev = NULL;
583 0 : for ( fd=fn->data[map]; fd!=NULL; fd=next ) {
584 0 : next = fd->next;
585 0 : if ( fd->point_size==0 && fd->copiedtoprinter ) {
586 0 : if ( first )
587 0 : fprintf(ps->output_file, "%%%%DocumentSuppliedResources: font %s\n",
588 : fd->localname );
589 : else
590 0 : fprintf(ps->output_file, "%%%%+ font %s\n",
591 : fd->localname );
592 0 : first = false;
593 : }
594 : }
595 : }
596 : }
597 : }
598 0 : if ( first ) {
599 : /* not sure how to say we don't use anything, but the PS Ref Man */
600 : /* says there must be a line at end if there's an (atend) at start */
601 0 : fprintf(ps->output_file, "%%%%DocumentSuppliedResources:\n" );
602 : }
603 0 : }
604 :
605 0 : void _GPSDraw_CopyFile(FILE *to, FILE *from) {
606 : char buffer[8*1024], *buf;
607 : int len, ch, flag, i;
608 :
609 0 : ch = getc(from);
610 0 : if ( ch== (unsigned char) '\200' ) {
611 : /* Is it a postscript binary font file? */
612 : /* strip out the binary headers and de-binary it */
613 0 : while ( ch== (unsigned char) '\200' ) {
614 0 : flag = getc(from);
615 0 : if ( flag==3 ) /* eof mark */
616 0 : break;
617 0 : len = getc(from);
618 0 : len |= getc(from)<<8;
619 0 : len |= getc(from)<<16;
620 0 : len |= getc(from)<<24;
621 0 : buf = malloc(len);
622 0 : if ( flag==1 ) {
623 : /* ascii section */
624 0 : len = fread(buf,sizeof(char),len,from);
625 0 : fwrite(buf,sizeof(char),len,to);
626 0 : } else if ( flag==2 ) {
627 : /* binary section */
628 0 : len = fread(buf,sizeof(char),len,from);
629 0 : for ( i=0; i<len; ++i ) {
630 0 : ch = buf[i];
631 0 : if ( ((ch>>4)&0xf) <= 9 )
632 0 : putc('0'+((ch>>4)&0xf),to);
633 : else
634 0 : putc('A'-10+((ch>>4)&0xf),to);
635 0 : if ( (ch&0xf) <= 9 )
636 0 : putc('0'+(ch&0xf),to);
637 : else
638 0 : putc('A'-10+(ch&0xf),to);
639 0 : if ( (i&0x1f)==0x1f )
640 0 : putc('\n',to);
641 : }
642 : }
643 0 : free(buf);
644 0 : ch = getc(from);
645 : }
646 : } else {
647 0 : ungetc(ch,from);
648 0 : while ((len=fread(buffer,sizeof(char),sizeof(buffer),from))>0 )
649 0 : fwrite(buffer,sizeof(char),len,to);
650 : }
651 0 : fputc('\n',to);
652 0 : }
653 :
654 0 : void _GPSDraw_ProcessFont(GPSWindow ps, struct font_data *fd) {
655 : char buffer[100];
656 0 : struct font_data *base = fd->base;
657 0 : FILE *output_file = ps->init_file;
658 0 : double skew = 0.0, factor = 1.0;
659 0 : int style = fd->style;
660 0 : int point = fd->point_size;
661 :
662 0 : if ( base->base!=NULL && base->needsprocessing )
663 0 : _GPSDraw_ProcessFont(ps,base);
664 0 : else if ( base->base==NULL ) {
665 0 : if ( base->fontfile!=NULL && !base->copiedtoprinter ) {
666 0 : FILE *ff = fopen( base->fontfile,"rb");
667 0 : if ( ff==NULL ) GDrawIError("Can't download font: %s", base->localname );
668 : else {
669 0 : fprintf( output_file, "%%%%BeginResource: font %s\n", base->localname );
670 0 : _GPSDraw_CopyFile(output_file,ff);
671 0 : fclose(ff);
672 0 : fprintf( output_file, "%%%%EndResource\n" );
673 : }
674 0 : base->copiedtoprinter = true;
675 0 : } else if ( base->fontfile==NULL && !base->includenoted ) {
676 0 : fprintf( output_file, "%%%%IncludeResource: font %s\n", base->localname );
677 0 : base->includenoted = true;
678 : }
679 :
680 0 : if ( base->needsremap && !base->remapped ) {
681 0 : fprintf( output_file, "/%s-ISO-8859-1 /%s findfont ISOLatin1Encoding g_font_remap definefont\n",
682 : base->localname, base->localname );
683 0 : base->remapped = true;
684 : }
685 : }
686 :
687 0 : if ( ((style&fs_italic) && !(base->style&fs_italic)) ||
688 0 : ((style&fs_extended) && !(base->style&fs_extended)) ||
689 0 : ((style&fs_condensed) && !(base->style&fs_condensed)) ) {
690 : /* Let's do some skewing. It's not real italic, but it's the best we gots */
691 0 : if ( base->base==NULL )
692 0 : sprintf( buffer, "%s__%d_%s%s%s", base->localname, point,
693 0 : ((style&fs_italic) && !(base->style&fs_italic))? "O":"",
694 0 : ((style&fs_extended) && !(base->style&fs_extended))? "E":"",
695 0 : ((style&fs_condensed) && !(base->style&fs_condensed))? "C":"");
696 : else
697 0 : sprintf( buffer, "%s_%s%s%s", base->localname,
698 0 : ((style&fs_italic) && !(base->style&fs_italic))? "O":"",
699 0 : ((style&fs_extended) && !(base->style&fs_extended))? "E":"",
700 0 : ((style&fs_condensed) && !(base->style&fs_condensed))? "C":"");
701 0 : if ( (style&fs_italic) && !(base->style&fs_italic) )
702 0 : skew = point/10.0;
703 0 : if ( (style&fs_extended) && !(base->style&fs_extended) )
704 0 : factor = 1.1;
705 0 : if ( (style&fs_condensed) && !(base->style&fs_condensed) )
706 0 : factor = .9;
707 0 : fprintf( output_file, "MyFontDict /%s /%s%s findfont [%g 0 %g %d 0 0] makefont put\n",
708 0 : buffer, base->localname, base->remapped?"-ISO-8859-1":"",
709 : factor*point, skew, point );
710 : } else {
711 0 : sprintf( buffer, "%s__%d", base->localname, point );
712 0 : fprintf( output_file, "MyFontDict /%s /%s%s findfont %d scalefont put\n",
713 0 : buffer, base->localname, base->remapped?"-ISO-8859-1":"", point );
714 : }
715 :
716 0 : fd->needsprocessing = false;
717 0 : }
|