1 /*
2 
3 Copyright 1990, 1994, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26 
27 */
28 
29 /*
30  * Author:  Keith Packard, MIT X Consortium
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 #include "libxfontint.h"
37 #include "src/util/replace.h"
38 
39 #include <X11/fonts/fntfilst.h>
40 #include <X11/fonts/bitmap.h>
41 #include <X11/fonts/pcf.h>
42 
43 /* Write PCF font files */
44 
45 static CARD32  current_position;
46 
47 static int
pcfWrite(FontFilePtr file,const char * b,int c)48 pcfWrite(FontFilePtr file, const char *b, int c)
49 {
50     current_position += c;
51     return FontFileWrite(file, b, c);
52 }
53 
54 static int
pcfPutLSB32(FontFilePtr file,int c)55 pcfPutLSB32(FontFilePtr file, int c)
56 {
57     current_position += 4;
58     (void) FontFilePutc(c, file);
59     (void) FontFilePutc(c >> 8, file);
60     (void) FontFilePutc(c >> 16, file);
61     return FontFilePutc(c >> 24, file);
62 }
63 
64 static int
pcfPutINT32(FontFilePtr file,CARD32 format,int c)65 pcfPutINT32(FontFilePtr file, CARD32 format, int c)
66 {
67     current_position += 4;
68     if (PCF_BYTE_ORDER(format) == MSBFirst) {
69 	(void) FontFilePutc(c >> 24, file);
70 	(void) FontFilePutc(c >> 16, file);
71 	(void) FontFilePutc(c >> 8, file);
72 	return FontFilePutc(c, file);
73     } else {
74 	(void) FontFilePutc(c, file);
75 	(void) FontFilePutc(c >> 8, file);
76 	(void) FontFilePutc(c >> 16, file);
77 	return FontFilePutc(c >> 24, file);
78     }
79 }
80 
81 static int
pcfPutINT16(FontFilePtr file,CARD32 format,int c)82 pcfPutINT16(FontFilePtr file, CARD32 format, int c)
83 {
84     current_position += 2;
85     if (PCF_BYTE_ORDER(format) == MSBFirst) {
86 	(void) FontFilePutc(c >> 8, file);
87 	return FontFilePutc(c, file);
88     } else {
89 	(void) FontFilePutc(c, file);
90 	return FontFilePutc(c >> 8, file);
91     }
92 }
93 
94 /*ARGSUSED*/
95 static int
pcfPutINT8(FontFilePtr file,CARD32 format,int c)96 pcfPutINT8(FontFilePtr file, CARD32 format, int c)
97 {
98     current_position += 1;
99     return FontFilePutc(c, file);
100 }
101 
102 static void
pcfWriteTOC(FontFilePtr file,PCFTablePtr table,int count)103 pcfWriteTOC(FontFilePtr file, PCFTablePtr table, int count)
104 {
105     CARD32      version;
106     int         i;
107 
108     version = PCF_FILE_VERSION;
109     pcfPutLSB32(file, version);
110     pcfPutLSB32(file, count);
111     for (i = 0; i < count; i++) {
112 	pcfPutLSB32(file, table->type);
113 	pcfPutLSB32(file, table->format);
114 	pcfPutLSB32(file, table->size);
115 	pcfPutLSB32(file, table->offset);
116 	table++;
117     }
118 }
119 
120 static void
pcfPutCompressedMetric(FontFilePtr file,CARD32 format,xCharInfo * metric)121 pcfPutCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
122 {
123     pcfPutINT8(file, format, metric->leftSideBearing + 0x80);
124     pcfPutINT8(file, format, metric->rightSideBearing + 0x80);
125     pcfPutINT8(file, format, metric->characterWidth + 0x80);
126     pcfPutINT8(file, format, metric->ascent + 0x80);
127     pcfPutINT8(file, format, metric->descent + 0x80);
128 }
129 
130 static void
pcfPutMetric(FontFilePtr file,CARD32 format,xCharInfo * metric)131 pcfPutMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
132 {
133     pcfPutINT16(file, format, metric->leftSideBearing);
134     pcfPutINT16(file, format, metric->rightSideBearing);
135     pcfPutINT16(file, format, metric->characterWidth);
136     pcfPutINT16(file, format, metric->ascent);
137     pcfPutINT16(file, format, metric->descent);
138     pcfPutINT16(file, format, metric->attributes);
139 }
140 
141 static void
pcfPutBitmap(FontFilePtr file,CARD32 format,CharInfoPtr pCI)142 pcfPutBitmap(FontFilePtr file, CARD32 format, CharInfoPtr pCI)
143 {
144     int         count;
145     unsigned char *bits;
146 
147     count = BYTES_FOR_GLYPH(pCI, PCF_GLYPH_PAD(format));
148     bits = (unsigned char *) pCI->bits;
149     current_position += count;
150     while (count--)
151 	FontFilePutc(*bits++, file);
152 }
153 
154 static void
pcfPutAccel(FontFilePtr file,CARD32 format,FontInfoPtr pFontInfo)155 pcfPutAccel(FontFilePtr file, CARD32 format, FontInfoPtr pFontInfo)
156 {
157     pcfPutINT8(file, format, pFontInfo->noOverlap);
158     pcfPutINT8(file, format, pFontInfo->constantMetrics);
159     pcfPutINT8(file, format, pFontInfo->terminalFont);
160     pcfPutINT8(file, format, pFontInfo->constantWidth);
161     pcfPutINT8(file, format, pFontInfo->inkInside);
162     pcfPutINT8(file, format, pFontInfo->inkMetrics);
163     pcfPutINT8(file, format, pFontInfo->drawDirection);
164     pcfPutINT8(file, format, 0);
165     pcfPutINT32(file, format, pFontInfo->fontAscent);
166     pcfPutINT32(file, format, pFontInfo->fontDescent);
167     pcfPutINT32(file, format, pFontInfo->maxOverlap);
168     pcfPutMetric(file, format, &pFontInfo->minbounds);
169     pcfPutMetric(file, format, &pFontInfo->maxbounds);
170     if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
171 	pcfPutMetric(file, format, &pFontInfo->ink_minbounds);
172 	pcfPutMetric(file, format, &pFontInfo->ink_maxbounds);
173     }
174 }
175 
176 #define S32 4
177 #define S16 2
178 #define S8 1
179 
180 #define Pad(s)	    (RoundUp(s) - (s))
181 #define RoundUp(s)  (((s) + 3) & ~3)
182 
183 #define Compressable(i)	(-128 <= (i) && (i) <= 127)
184 
185 #define CanCompressMetric(m)	(Compressable((m)->leftSideBearing) && \
186 				 Compressable((m)->rightSideBearing) && \
187 				 Compressable((m)->characterWidth) && \
188 				 Compressable((m)->ascent) && \
189 				 Compressable((m)->descent) && \
190 				 (m)->attributes == 0)
191 
192 #define CanCompressMetrics(min,max) (CanCompressMetric(min) && CanCompressMetric(max))
193 
194 static const char *
pcfNameForAtom(Atom a)195 pcfNameForAtom(Atom a)
196 {
197     return NameForAtom(a);
198 }
199 
200 int
pcfWriteFont(FontPtr pFont,FontFilePtr file)201 pcfWriteFont(FontPtr pFont, FontFilePtr file)
202 {
203     PCFTableRec tables[32],
204                *table;
205     CARD32      mask,
206                 bit;
207     int         ntables;
208     int         size;
209     CARD32      format;
210     int         i;
211     int         cur_table;
212     int         prop_string_size;
213     int         glyph_string_size;
214     xCharInfo  *minbounds,
215                *maxbounds;
216     xCharInfo  *ink_minbounds,
217                *ink_maxbounds;
218     BitmapFontPtr  bitmapFont;
219     int         nencodings = 0;
220     int         header_size;
221     FontPropPtr offsetProps;
222     int         prop_pad = 0;
223     const char  *atom_name;
224     int         glyph;
225     CARD32      offset;
226 
227     bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
228     if (bitmapFont->bitmapExtra) {
229 	minbounds = &bitmapFont->bitmapExtra->info.minbounds;
230 	maxbounds = &bitmapFont->bitmapExtra->info.maxbounds;
231 	ink_minbounds = &bitmapFont->bitmapExtra->info.ink_minbounds;
232 	ink_maxbounds = &bitmapFont->bitmapExtra->info.ink_maxbounds;
233     } else {
234 	minbounds = &pFont->info.minbounds;
235 	maxbounds = &pFont->info.maxbounds;
236 	ink_minbounds = &pFont->info.ink_minbounds;
237 	ink_maxbounds = &pFont->info.ink_maxbounds;
238     }
239     offsetProps = mallocarray(pFont->info.nprops, sizeof(FontPropRec));
240     if (!offsetProps) {
241 	pcfError("pcfWriteFont(): Couldn't allocate offsetProps (%d*%d)",
242 		 pFont->info.nprops, (int) sizeof(FontPropRec));
243 	return AllocError;
244     }
245     prop_string_size = 0;
246     for (i = 0; i < pFont->info.nprops; i++) {
247 	offsetProps[i].name = prop_string_size;
248 	prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].name)) + 1;
249 	if (pFont->info.isStringProp[i]) {
250 	    offsetProps[i].value = prop_string_size;
251 	    prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].value)) + 1;
252 	} else
253 	    offsetProps[i].value = pFont->info.props[i].value;
254     }
255     format = PCF_FORMAT(pFont->bit, pFont->byte, pFont->glyph, pFont->scan);
256     mask = 0xFFFFFFF;
257     ntables = 0;
258     table = tables;
259     while (mask) {
260 	bit = lowbit(mask);
261 	mask &= ~bit;
262 	table->type = bit;
263 	switch (bit) {
264 	case PCF_PROPERTIES:
265 	    table->format = PCF_DEFAULT_FORMAT | format;
266 	    size = S32 + S32 + (S32 + S8 + S32) * pFont->info.nprops;
267 	    prop_pad = Pad(size);
268 	    table->size = RoundUp(size) + S32 +
269 		RoundUp(prop_string_size);
270 	    table++;
271 	    break;
272 	case PCF_ACCELERATORS:
273 	    if (bitmapFont->bitmapExtra->info.inkMetrics)
274 		table->format = PCF_ACCEL_W_INKBOUNDS | format;
275 	    else
276 		table->format = PCF_DEFAULT_FORMAT | format;
277 	    table->size = 100;
278 	    table++;
279 	    break;
280 	case PCF_METRICS:
281 	    if (CanCompressMetrics(minbounds, maxbounds)) {
282 		table->format = PCF_COMPRESSED_METRICS | format;
283 		size = S32 + S16 + bitmapFont->num_chars * (5 * S8);
284 		table->size = RoundUp(size);
285 	    } else {
286 		table->format = PCF_DEFAULT_FORMAT | format;
287 		table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16);
288 	    }
289 	    table++;
290 	    break;
291 	case PCF_BITMAPS:
292 	    table->format = PCF_DEFAULT_FORMAT | format;
293 	    size = S32 + S32 + bitmapFont->num_chars * S32 +
294 		GLYPHPADOPTIONS * S32 +
295 		bitmapFont->bitmapExtra->bitmapsSizes[PCF_GLYPH_PAD_INDEX(format)];
296 	    table->size = RoundUp(size);
297 	    table++;
298 	    break;
299 	case PCF_INK_METRICS:
300 	    if (bitmapFont->ink_metrics) {
301 		if (CanCompressMetrics(ink_minbounds, ink_maxbounds)) {
302 		    table->format = PCF_COMPRESSED_METRICS | format;
303 		    size = S32 + S16 + bitmapFont->num_chars * (5 * S8);
304 		    table->size = RoundUp(size);
305 		} else {
306 		    table->format = PCF_DEFAULT_FORMAT | format;
307 		    table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16);
308 		}
309 		table++;
310 	    }
311 	    break;
312 	case PCF_BDF_ENCODINGS:
313 	    table->format = PCF_DEFAULT_FORMAT | format;
314 	    nencodings = (pFont->info.lastRow - pFont->info.firstRow + 1) *
315 		(pFont->info.lastCol - pFont->info.firstCol + 1);
316 	    size = S32 + 5 * S16 + nencodings * S16;
317 	    table->size = RoundUp(size);
318 	    table++;
319 	    break;
320 	case PCF_SWIDTHS:
321 	    table->format = PCF_DEFAULT_FORMAT | format;
322 	    table->size = S32 + S32 + bitmapFont->num_chars * S32;
323 	    table++;
324 	    break;
325 	case PCF_GLYPH_NAMES:
326 	    table->format = PCF_DEFAULT_FORMAT | format;
327 	    glyph_string_size = 0;
328 	    for (i = 0; i < bitmapFont->num_chars; i++)
329 		glyph_string_size += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1;
330 	    table->size = S32 + S32 + bitmapFont->num_chars * S32 +
331 		S32 + RoundUp(glyph_string_size);
332 	    table++;
333 	    break;
334 	case PCF_BDF_ACCELERATORS:
335 	    if (pFont->info.inkMetrics)
336 		table->format = PCF_ACCEL_W_INKBOUNDS | format;
337 	    else
338 		table->format = PCF_DEFAULT_FORMAT | format;
339 	    table->size = 100;
340 	    table++;
341 	    break;
342 	}
343     }
344     ntables = table - tables;
345     offset = 0;
346     header_size = S32 + S32 + ntables * (4 * S32);
347     offset = header_size;
348     for (cur_table = 0, table = tables;
349 	    cur_table < ntables;
350 	    cur_table++, table++) {
351 	table->offset = offset;
352 	offset += table->size;
353     }
354     current_position = 0;
355     pcfWriteTOC(file, tables, ntables);
356     for (cur_table = 0, table = tables;
357 	    cur_table < ntables;
358 	    cur_table++, table++) {
359 	if (current_position > table->offset) {
360 	    printf("can't go backwards... %d > %d\n",
361 		   (int)current_position, (int)table->offset);
362 	    free(offsetProps);
363 	    return BadFontName;
364 	}
365 	while (current_position < table->offset)
366 	    pcfPutINT8(file, format, '\0');
367 	pcfPutLSB32(file, table->format);
368 	switch (table->type) {
369 	case PCF_PROPERTIES:
370 	    pcfPutINT32(file, format, pFont->info.nprops);
371 	    for (i = 0; i < pFont->info.nprops; i++) {
372 		pcfPutINT32(file, format, offsetProps[i].name);
373 		pcfPutINT8(file, format, pFont->info.isStringProp[i]);
374 		pcfPutINT32(file, format, offsetProps[i].value);
375 	    }
376 	    for (i = 0; i < prop_pad; i++)
377 		pcfPutINT8(file, format, 0);
378 	    pcfPutINT32(file, format, prop_string_size);
379 	    for (i = 0; i < pFont->info.nprops; i++) {
380 		atom_name = pcfNameForAtom(pFont->info.props[i].name);
381 		pcfWrite(file, atom_name, strlen(atom_name) + 1);
382 		if (pFont->info.isStringProp[i]) {
383 		    atom_name = pcfNameForAtom(pFont->info.props[i].value);
384 		    pcfWrite(file, atom_name, strlen(atom_name) + 1);
385 		}
386 	    }
387 	    break;
388 	case PCF_ACCELERATORS:
389 	    pcfPutAccel(file, table->format, &bitmapFont->bitmapExtra->info);
390 	    break;
391 	case PCF_METRICS:
392 	    if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) {
393 		pcfPutINT16(file, format, bitmapFont->num_chars);
394 		for (i = 0; i < bitmapFont->num_chars; i++)
395 		    pcfPutCompressedMetric(file, format, &bitmapFont->metrics[i].metrics);
396 	    } else {
397 		pcfPutINT32(file, format, bitmapFont->num_chars);
398 		for (i = 0; i < bitmapFont->num_chars; i++)
399 		    pcfPutMetric(file, format, &bitmapFont->metrics[i].metrics);
400 	    }
401 	    break;
402 	case PCF_BITMAPS:
403 	    pcfPutINT32(file, format, bitmapFont->num_chars);
404 	    glyph = PCF_GLYPH_PAD(format);
405 	    offset = 0;
406 	    for (i = 0; i < bitmapFont->num_chars; i++) {
407 		pcfPutINT32(file, format, offset);
408 		offset += BYTES_FOR_GLYPH(&bitmapFont->metrics[i], glyph);
409 	    }
410 	    for (i = 0; i < GLYPHPADOPTIONS; i++) {
411 		pcfPutINT32(file, format,
412 			    bitmapFont->bitmapExtra->bitmapsSizes[i]);
413 	    }
414 	    for (i = 0; i < bitmapFont->num_chars; i++)
415 		pcfPutBitmap(file, format, &bitmapFont->metrics[i]);
416 	    break;
417 	case PCF_INK_METRICS:
418 	    if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) {
419 		pcfPutINT16(file, format, bitmapFont->num_chars);
420 		for (i = 0; i < bitmapFont->num_chars; i++)
421 		    pcfPutCompressedMetric(file, format, &bitmapFont->ink_metrics[i]);
422 	    } else {
423 		pcfPutINT32(file, format, bitmapFont->num_chars);
424 		for (i = 0; i < bitmapFont->num_chars; i++)
425 		    pcfPutMetric(file, format, &bitmapFont->ink_metrics[i]);
426 	    }
427 	    break;
428 	case PCF_BDF_ENCODINGS:
429 	    pcfPutINT16(file, format, pFont->info.firstCol);
430 	    pcfPutINT16(file, format, pFont->info.lastCol);
431 	    pcfPutINT16(file, format, pFont->info.firstRow);
432 	    pcfPutINT16(file, format, pFont->info.lastRow);
433 	    pcfPutINT16(file, format, pFont->info.defaultCh);
434 	    for (i = 0; i < nencodings; i++) {
435 		if (ACCESSENCODING(bitmapFont->encoding,i))
436 		    pcfPutINT16(file, format,
437                                 ACCESSENCODING(bitmapFont->encoding, i) -
438                                   bitmapFont->metrics);
439 		else
440 		    pcfPutINT16(file, format, 0xFFFF);
441 	    }
442 	    break;
443 	case PCF_SWIDTHS:
444 	    pcfPutINT32(file, format, bitmapFont->num_chars);
445 	    for (i = 0; i < bitmapFont->num_chars; i++)
446 		pcfPutINT32(file, format, bitmapFont->bitmapExtra->sWidths[i]);
447 	    break;
448 	case PCF_GLYPH_NAMES:
449 	    pcfPutINT32(file, format, bitmapFont->num_chars);
450 	    offset = 0;
451 	    for (i = 0; i < bitmapFont->num_chars; i++) {
452 		pcfPutINT32(file, format, offset);
453 		offset += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1;
454 	    }
455 	    pcfPutINT32(file, format, offset);
456 	    for (i = 0; i < bitmapFont->num_chars; i++) {
457 		atom_name = pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i]);
458 		pcfWrite(file, atom_name, strlen(atom_name) + 1);
459 	    }
460 	    break;
461 	case PCF_BDF_ACCELERATORS:
462 	    pcfPutAccel(file, table->format, &pFont->info);
463 	    break;
464 	}
465     }
466 
467     free(offsetProps);
468     return Successful;
469 }
470