3 Copyright 1990, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
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.
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
30 * Author: Keith Packard, MIT X Consortium
37 #include <X11/fonts/fntfilst.h>
38 #include <X11/fonts/bitmap.h>
39 #include <X11/fonts/pcf.h>
42 #define MAX(a,b) (((a)>(b)) ? a : b)
49 pcfError(const char* message, ...)
53 va_start(args, message);
55 fprintf(stderr, "PCF Error: ");
56 vfprintf(stderr, message, args);
60 /* Read PCF font files */
62 static void pcfUnloadFont ( FontPtr pFont );
66 #define IS_EOF(file) ((file)->eof == BUFFILEEOF)
68 #define FONT_FILE_GETC_ERR(f) (tmp = FontFileGetc(f), BAIL_ON_EOF)
71 pcfGetLSB32(FontFilePtr file)
75 c = FontFileGetc(file);
76 c |= FontFileGetc(file) << 8;
77 c |= FontFileGetc(file) << 16;
78 c |= FontFileGetc(file) << 24;
84 pcfGetINT32(FontFilePtr file, CARD32 format)
88 if (PCF_BYTE_ORDER(format) == MSBFirst) {
89 c = FontFileGetc(file) << 24;
90 c |= FontFileGetc(file) << 16;
91 c |= FontFileGetc(file) << 8;
92 c |= FontFileGetc(file);
94 c = FontFileGetc(file);
95 c |= FontFileGetc(file) << 8;
96 c |= FontFileGetc(file) << 16;
97 c |= FontFileGetc(file) << 24;
104 pcfGetINT16(FontFilePtr file, CARD32 format)
108 if (PCF_BYTE_ORDER(format) == MSBFirst) {
109 c = FontFileGetc(file) << 8;
110 c |= FontFileGetc(file);
112 c = FontFileGetc(file);
113 c |= FontFileGetc(file) << 8;
119 #define pcfGetINT8(file, format) (position++, FontFileGetc(file))
122 pcfReadTOC(FontFilePtr file, int *countp)
130 version = pcfGetLSB32(file);
131 if (version != PCF_FILE_VERSION)
132 return (PCFTablePtr) NULL;
133 count = pcfGetLSB32(file);
134 if (IS_EOF(file)) return (PCFTablePtr) NULL;
135 if (count < 0 || count > INT32_MAX / sizeof(PCFTableRec)) {
136 pcfError("pcfReadTOC(): invalid file format\n");
139 tables = malloc(count * sizeof(PCFTableRec));
141 pcfError("pcfReadTOC(): Couldn't allocate tables (%d*%d)\n", count, sizeof(PCFTableRec));
142 return (PCFTablePtr) NULL;
144 for (i = 0; i < count; i++) {
145 tables[i].type = pcfGetLSB32(file);
146 tables[i].format = pcfGetLSB32(file);
147 tables[i].size = pcfGetLSB32(file);
148 tables[i].offset = pcfGetLSB32(file);
149 if (IS_EOF(file)) goto Bail;
157 return (PCFTablePtr) NULL;
161 * PCF supports two formats for metrics, both the regular
162 * jumbo size, and 'lite' metrics, which are useful
163 * for most fonts which have even vaguely reasonable
168 pcfGetMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
170 metric->leftSideBearing = pcfGetINT16(file, format);
171 metric->rightSideBearing = pcfGetINT16(file, format);
172 metric->characterWidth = pcfGetINT16(file, format);
173 metric->ascent = pcfGetINT16(file, format);
174 metric->descent = pcfGetINT16(file, format);
175 metric->attributes = pcfGetINT16(file, format);
176 if (IS_EOF(file)) return FALSE;
182 pcfGetCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
184 metric->leftSideBearing = pcfGetINT8(file, format) - 0x80;
185 metric->rightSideBearing = pcfGetINT8(file, format) - 0x80;
186 metric->characterWidth = pcfGetINT8(file, format) - 0x80;
187 metric->ascent = pcfGetINT8(file, format) - 0x80;
188 metric->descent = pcfGetINT8(file, format) - 0x80;
189 metric->attributes = 0;
190 if (IS_EOF(file)) return FALSE;
196 * Position the file to the begining of the specified table
200 pcfSeekToType(FontFilePtr file, PCFTablePtr tables, int ntables,
201 CARD32 type, CARD32 *formatp, CARD32 *sizep)
205 for (i = 0; i < ntables; i++)
206 if (tables[i].type == type) {
207 if (position > tables[i].offset)
209 if (!FontFileSkip(file, tables[i].offset - position))
211 position = tables[i].offset;
212 *sizep = tables[i].size;
213 *formatp = tables[i].format;
220 pcfHasType (PCFTablePtr tables, int ntables, CARD32 type)
224 for (i = 0; i < ntables; i++)
225 if (tables[i].type == type)
233 * Reads the font properties from the font file, filling in the FontInfo rec
234 * supplied. Used by by both ReadFont and ReadFontInfo routines.
238 pcfGetProperties(FontInfoPtr pFontInfo, FontFilePtr file,
239 PCFTablePtr tables, int ntables)
241 FontPropPtr props = 0;
243 char *isStringProp = 0;
250 /* font properties */
252 if (!pcfSeekToType(file, tables, ntables, PCF_PROPERTIES, &format, &size))
254 format = pcfGetLSB32(file);
255 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
257 nprops = pcfGetINT32(file, format);
258 if (nprops <= 0 || nprops > INT32_MAX / sizeof(FontPropRec)) {
259 pcfError("pcfGetProperties(): invalid nprops value (%d)\n", nprops);
262 if (IS_EOF(file)) goto Bail;
263 props = malloc(nprops * sizeof(FontPropRec));
265 pcfError("pcfGetProperties(): Couldn't allocate props (%d*%d)\n", nprops, sizeof(FontPropRec));
268 isStringProp = malloc(nprops * sizeof(char));
270 pcfError("pcfGetProperties(): Couldn't allocate isStringProp (%d*%d)\n", nprops, sizeof(char));
273 for (i = 0; i < nprops; i++) {
274 props[i].name = pcfGetINT32(file, format);
275 isStringProp[i] = pcfGetINT8(file, format);
276 props[i].value = pcfGetINT32(file, format);
277 if (props[i].name < 0
278 || (isStringProp[i] != 0 && isStringProp[i] != 1)
279 || (isStringProp[i] && props[i].value < 0)) {
280 pcfError("pcfGetProperties(): invalid file format %d %d %d\n",
281 props[i].name, isStringProp[i], props[i].value);
284 if (IS_EOF(file)) goto Bail;
286 /* pad the property array */
288 * clever here - nprops is the same as the number of odd-units read, as
289 * only isStringProp are odd length
293 i = 4 - (nprops & 3);
294 (void)FontFileSkip(file, i);
297 if (IS_EOF(file)) goto Bail;
298 string_size = pcfGetINT32(file, format);
299 if (string_size < 0) goto Bail;
300 if (IS_EOF(file)) goto Bail;
301 strings = malloc(string_size);
303 pcfError("pcfGetProperties(): Couldn't allocate strings (%d)\n", string_size);
306 FontFileRead(file, strings, string_size);
307 if (IS_EOF(file)) goto Bail;
308 position += string_size;
309 for (i = 0; i < nprops; i++) {
310 props[i].name = MakeAtom(strings + props[i].name,
311 strlen(strings + props[i].name), TRUE);
312 if (isStringProp[i]) {
313 props[i].value = MakeAtom(strings + props[i].value,
314 strlen(strings + props[i].value), TRUE);
318 pFontInfo->isStringProp = isStringProp;
319 pFontInfo->props = props;
320 pFontInfo->nprops = nprops;
332 * Fill in the accelerator information from the font file; used
333 * to read both BDF_ACCELERATORS and old style ACCELERATORS
337 pcfGetAccel(FontInfoPtr pFontInfo, FontFilePtr file,
338 PCFTablePtr tables, int ntables, CARD32 type)
343 if (!pcfSeekToType(file, tables, ntables, type, &format, &size) ||
346 format = pcfGetLSB32(file);
347 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
348 !PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS))
352 pFontInfo->noOverlap = pcfGetINT8(file, format);
353 pFontInfo->constantMetrics = pcfGetINT8(file, format);
354 pFontInfo->terminalFont = pcfGetINT8(file, format);
355 pFontInfo->constantWidth = pcfGetINT8(file, format);
356 pFontInfo->inkInside = pcfGetINT8(file, format);
357 pFontInfo->inkMetrics = pcfGetINT8(file, format);
358 pFontInfo->drawDirection = pcfGetINT8(file, format);
359 pFontInfo->anamorphic = FALSE;
360 pFontInfo->cachable = TRUE;
361 /* natural alignment */ pcfGetINT8(file, format);
362 pFontInfo->fontAscent = pcfGetINT32(file, format);
363 pFontInfo->fontDescent = pcfGetINT32(file, format);
364 pFontInfo->maxOverlap = pcfGetINT32(file, format);
365 if (IS_EOF(file)) goto Bail;
366 if (!pcfGetMetric(file, format, &pFontInfo->minbounds))
368 if (!pcfGetMetric(file, format, &pFontInfo->maxbounds))
370 if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
371 if (!pcfGetMetric(file, format, &pFontInfo->ink_minbounds))
373 if (!pcfGetMetric(file, format, &pFontInfo->ink_maxbounds))
376 pFontInfo->ink_minbounds = pFontInfo->minbounds;
377 pFontInfo->ink_maxbounds = pFontInfo->maxbounds;
385 pcfReadFont(FontPtr pFont, FontFilePtr file,
386 int bit, int byte, int glyph, int scan)
390 BitmapFontPtr bitmapFont = 0;
392 PCFTablePtr tables = 0;
398 CharInfoPtr metrics = 0;
399 xCharInfo *ink_metrics = 0;
401 CharInfoPtr **encoding = 0;
404 CARD32 bitmapSizes[GLYPHPADOPTIONS];
406 Bool hasBDFAccelerators;
408 pFont->info.nprops = 0;
409 pFont->info.props = 0;
410 if (!(tables = pcfReadTOC(file, &ntables)))
415 if (!pcfGetProperties(&pFont->info, file, tables, ntables))
418 /* Use the old accelerators if no BDF accelerators are in the file */
420 hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
421 if (!hasBDFAccelerators)
422 if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_ACCELERATORS))
427 if (!pcfSeekToType(file, tables, ntables, PCF_METRICS, &format, &size)) {
430 format = pcfGetLSB32(file);
431 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
432 !PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
435 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
436 nmetrics = pcfGetINT32(file, format);
438 nmetrics = pcfGetINT16(file, format);
439 if (IS_EOF(file)) goto Bail;
440 if (nmetrics < 0 || nmetrics > INT32_MAX / sizeof(CharInfoRec)) {
441 pcfError("pcfReadFont(): invalid file format\n");
444 metrics = malloc(nmetrics * sizeof(CharInfoRec));
446 pcfError("pcfReadFont(): Couldn't allocate metrics (%d*%d)\n", nmetrics, sizeof(CharInfoRec));
449 for (i = 0; i < nmetrics; i++)
450 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
451 if (!pcfGetMetric(file, format, &(metrics + i)->metrics))
454 if (!pcfGetCompressedMetric(file, format, &(metrics + i)->metrics))
460 if (!pcfSeekToType(file, tables, ntables, PCF_BITMAPS, &format, &size))
462 format = pcfGetLSB32(file);
463 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
466 nbitmaps = pcfGetINT32(file, format);
467 if (nbitmaps != nmetrics || IS_EOF(file))
469 /* nmetrics is already ok, so nbitmap also is */
470 offsets = malloc(nbitmaps * sizeof(CARD32));
472 pcfError("pcfReadFont(): Couldn't allocate offsets (%d*%d)\n", nbitmaps, sizeof(CARD32));
475 for (i = 0; i < nbitmaps; i++) {
476 offsets[i] = pcfGetINT32(file, format);
477 if (IS_EOF(file)) goto Bail;
480 for (i = 0; i < GLYPHPADOPTIONS; i++) {
481 bitmapSizes[i] = pcfGetINT32(file, format);
482 if (IS_EOF(file)) goto Bail;
483 if (bitmapSizes[i] < 0) goto Bail;
486 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX(format)];
487 /* guard against completely empty font */
488 bitmaps = malloc(sizebitmaps ? sizebitmaps : 1);
490 pcfError("pcfReadFont(): Couldn't allocate bitmaps (%d)\n", sizebitmaps ? sizebitmaps : 1);
493 FontFileRead(file, bitmaps, sizebitmaps);
494 if (IS_EOF(file)) goto Bail;
495 position += sizebitmaps;
497 if (PCF_BIT_ORDER(format) != bit)
498 BitOrderInvert((unsigned char *)bitmaps, sizebitmaps);
499 if ((PCF_BYTE_ORDER(format) == PCF_BIT_ORDER(format)) != (bit == byte)) {
500 switch (bit == byte ? PCF_SCAN_UNIT(format) : scan) {
504 TwoByteSwap((unsigned char *)bitmaps, sizebitmaps);
507 FourByteSwap((unsigned char *)bitmaps, sizebitmaps);
511 if (PCF_GLYPH_PAD(format) != glyph) {
518 sizepadbitmaps = bitmapSizes[PCF_SIZE_TO_INDEX(glyph)];
519 padbitmaps = malloc(sizepadbitmaps);
521 pcfError("pcfReadFont(): Couldn't allocate padbitmaps (%d)\n", sizepadbitmaps);
525 for (i = 0; i < nbitmaps; i++) {
527 metric = &metrics[i].metrics;
529 new += RepadBitmap(bitmaps + old, padbitmaps + new,
530 PCF_GLYPH_PAD(format), glyph,
531 metric->rightSideBearing - metric->leftSideBearing,
532 metric->ascent + metric->descent);
535 bitmaps = padbitmaps;
537 for (i = 0; i < nbitmaps; i++)
538 metrics[i].bits = bitmaps + offsets[i];
546 if (pcfSeekToType(file, tables, ntables, PCF_INK_METRICS, &format, &size)) {
547 format = pcfGetLSB32(file);
548 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
549 !PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
552 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
553 nink_metrics = pcfGetINT32(file, format);
555 nink_metrics = pcfGetINT16(file, format);
556 if (IS_EOF(file)) goto Bail;
557 if (nink_metrics != nmetrics)
559 /* nmetrics already checked */
560 ink_metrics = malloc(nink_metrics * sizeof(xCharInfo));
562 pcfError("pcfReadFont(): Couldn't allocate ink_metrics (%d*%d)\n", nink_metrics, sizeof(xCharInfo));
565 for (i = 0; i < nink_metrics; i++)
566 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
567 if (!pcfGetMetric(file, format, ink_metrics + i))
570 if (!pcfGetCompressedMetric(file, format, ink_metrics + i))
577 if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
579 format = pcfGetLSB32(file);
580 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
583 pFont->info.firstCol = pcfGetINT16(file, format);
584 pFont->info.lastCol = pcfGetINT16(file, format);
585 pFont->info.firstRow = pcfGetINT16(file, format);
586 pFont->info.lastRow = pcfGetINT16(file, format);
587 pFont->info.defaultCh = pcfGetINT16(file, format);
588 if (IS_EOF(file)) goto Bail;
589 if (pFont->info.firstCol > pFont->info.lastCol ||
590 pFont->info.firstRow > pFont->info.lastRow ||
591 pFont->info.lastCol-pFont->info.firstCol > 255) goto Bail;
593 nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
594 (pFont->info.lastRow - pFont->info.firstRow + 1);
596 encoding = calloc(NUM_SEGMENTS(nencoding), sizeof(CharInfoPtr*));
598 pcfError("pcfReadFont(): Couldn't allocate encoding (%d*%d)\n", nencoding, sizeof(CharInfoPtr));
602 pFont->info.allExist = TRUE;
603 for (i = 0; i < nencoding; i++) {
604 encodingOffset = pcfGetINT16(file, format);
605 if (IS_EOF(file)) goto Bail;
606 if (encodingOffset == 0xFFFF) {
607 pFont->info.allExist = FALSE;
609 if(!encoding[SEGMENT_MAJOR(i)]) {
610 encoding[SEGMENT_MAJOR(i)]=
611 calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr));
612 if(!encoding[SEGMENT_MAJOR(i)])
615 ACCESSENCODINGL(encoding, i) = metrics + encodingOffset;
619 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
621 if (hasBDFAccelerators)
622 if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_BDF_ACCELERATORS))
625 bitmapFont = malloc(sizeof *bitmapFont);
627 pcfError("pcfReadFont(): Couldn't allocate bitmapFont (%d)\n", sizeof *bitmapFont);
631 bitmapFont->version_num = PCF_FILE_VERSION;
632 bitmapFont->num_chars = nmetrics;
633 bitmapFont->num_tables = ntables;
634 bitmapFont->metrics = metrics;
635 bitmapFont->ink_metrics = ink_metrics;
636 bitmapFont->bitmaps = bitmaps;
637 bitmapFont->encoding = encoding;
638 bitmapFont->pDefault = (CharInfoPtr) 0;
639 if (pFont->info.defaultCh != (unsigned short) NO_SUCH_CHAR) {
644 r = pFont->info.defaultCh >> 8;
645 c = pFont->info.defaultCh & 0xFF;
646 if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
647 pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
648 cols = pFont->info.lastCol - pFont->info.firstCol + 1;
649 r = r - pFont->info.firstRow;
650 c = c - pFont->info.firstCol;
651 bitmapFont->pDefault = ACCESSENCODING(encoding, r * cols + c);
654 bitmapFont->bitmapExtra = (BitmapExtraPtr) 0;
655 pFont->fontPrivate = (pointer) bitmapFont;
656 pFont->get_glyphs = bitmapGetGlyphs;
657 pFont->get_metrics = bitmapGetMetrics;
658 pFont->unload_font = pcfUnloadFont;
659 pFont->unload_glyphs = NULL;
662 pFont->glyph = glyph;
669 for(i=0; i<NUM_SEGMENTS(nencoding); i++)
675 free(pFont->info.props);
676 pFont->info.nprops = 0;
677 pFont->info.props = 0;
678 free (pFont->info.isStringProp);
686 pcfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
693 Bool hasBDFAccelerators;
695 pFontInfo->isStringProp = NULL;
696 pFontInfo->props = NULL;
697 pFontInfo->nprops = 0;
699 if (!(tables = pcfReadTOC(file, &ntables)))
704 if (!pcfGetProperties(pFontInfo, file, tables, ntables))
707 /* Use the old accelerators if no BDF accelerators are in the file */
709 hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
710 if (!hasBDFAccelerators)
711 if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_ACCELERATORS))
716 if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
718 format = pcfGetLSB32(file);
719 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
722 pFontInfo->firstCol = pcfGetINT16(file, format);
723 pFontInfo->lastCol = pcfGetINT16(file, format);
724 pFontInfo->firstRow = pcfGetINT16(file, format);
725 pFontInfo->lastRow = pcfGetINT16(file, format);
726 pFontInfo->defaultCh = pcfGetINT16(file, format);
727 if (IS_EOF(file)) goto Bail;
728 if (pFontInfo->firstCol > pFontInfo->lastCol ||
729 pFontInfo->firstRow > pFontInfo->lastRow ||
730 pFontInfo->lastCol-pFontInfo->firstCol > 255) goto Bail;
732 nencoding = (pFontInfo->lastCol - pFontInfo->firstCol + 1) *
733 (pFontInfo->lastRow - pFontInfo->firstRow + 1);
735 pFontInfo->allExist = TRUE;
736 while (nencoding--) {
737 if (pcfGetINT16(file, format) == 0xFFFF)
738 pFontInfo->allExist = FALSE;
739 if (IS_EOF(file)) goto Bail;
741 if (IS_EOF(file)) goto Bail;
743 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
745 if (hasBDFAccelerators)
746 if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_BDF_ACCELERATORS))
752 pFontInfo->nprops = 0;
753 free (pFontInfo->props);
754 free (pFontInfo->isStringProp);
760 pcfUnloadFont(FontPtr pFont)
762 BitmapFontPtr bitmapFont;
765 bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
766 free(bitmapFont->ink_metrics);
767 if(bitmapFont->encoding) {
768 nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
769 (pFont->info.lastRow - pFont->info.firstRow + 1);
770 for(i=0; i<NUM_SEGMENTS(nencoding); i++)
771 free(bitmapFont->encoding[i]);
773 free(bitmapFont->encoding);
774 free(bitmapFont->bitmaps);
775 free(bitmapFont->metrics);
776 free(pFont->info.isStringProp);
777 free(pFont->info.props);
779 DestroyFontRec(pFont);