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",
142 count, (int) sizeof(PCFTableRec));
143 return (PCFTablePtr) NULL;
145 for (i = 0; i < count; i++) {
146 tables[i].type = pcfGetLSB32(file);
147 tables[i].format = pcfGetLSB32(file);
148 tables[i].size = pcfGetLSB32(file);
149 tables[i].offset = pcfGetLSB32(file);
150 if (IS_EOF(file)) goto Bail;
158 return (PCFTablePtr) NULL;
162 * PCF supports two formats for metrics, both the regular
163 * jumbo size, and 'lite' metrics, which are useful
164 * for most fonts which have even vaguely reasonable
169 pcfGetMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
171 metric->leftSideBearing = pcfGetINT16(file, format);
172 metric->rightSideBearing = pcfGetINT16(file, format);
173 metric->characterWidth = pcfGetINT16(file, format);
174 metric->ascent = pcfGetINT16(file, format);
175 metric->descent = pcfGetINT16(file, format);
176 metric->attributes = pcfGetINT16(file, format);
177 if (IS_EOF(file)) return FALSE;
183 pcfGetCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
185 metric->leftSideBearing = pcfGetINT8(file, format) - 0x80;
186 metric->rightSideBearing = pcfGetINT8(file, format) - 0x80;
187 metric->characterWidth = pcfGetINT8(file, format) - 0x80;
188 metric->ascent = pcfGetINT8(file, format) - 0x80;
189 metric->descent = pcfGetINT8(file, format) - 0x80;
190 metric->attributes = 0;
191 if (IS_EOF(file)) return FALSE;
197 * Position the file to the begining of the specified table
201 pcfSeekToType(FontFilePtr file, PCFTablePtr tables, int ntables,
202 CARD32 type, CARD32 *formatp, CARD32 *sizep)
206 for (i = 0; i < ntables; i++)
207 if (tables[i].type == type) {
208 if (position > tables[i].offset)
210 if (!FontFileSkip(file, tables[i].offset - position))
212 position = tables[i].offset;
213 *sizep = tables[i].size;
214 *formatp = tables[i].format;
221 pcfHasType (PCFTablePtr tables, int ntables, CARD32 type)
225 for (i = 0; i < ntables; i++)
226 if (tables[i].type == type)
234 * Reads the font properties from the font file, filling in the FontInfo rec
235 * supplied. Used by by both ReadFont and ReadFontInfo routines.
239 pcfGetProperties(FontInfoPtr pFontInfo, FontFilePtr file,
240 PCFTablePtr tables, int ntables)
242 FontPropPtr props = 0;
244 char *isStringProp = 0;
251 /* font properties */
253 if (!pcfSeekToType(file, tables, ntables, PCF_PROPERTIES, &format, &size))
255 format = pcfGetLSB32(file);
256 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
258 nprops = pcfGetINT32(file, format);
259 if (nprops <= 0 || nprops > INT32_MAX / sizeof(FontPropRec)) {
260 pcfError("pcfGetProperties(): invalid nprops value (%d)\n", nprops);
263 if (IS_EOF(file)) goto Bail;
264 props = malloc(nprops * sizeof(FontPropRec));
266 pcfError("pcfGetProperties(): Couldn't allocate props (%d*%d)\n",
267 nprops, (int) sizeof(FontPropRec));
270 isStringProp = malloc(nprops * sizeof(char));
272 pcfError("pcfGetProperties(): Couldn't allocate isStringProp (%d*%d)\n",
273 nprops, (int) sizeof(char));
276 for (i = 0; i < nprops; i++) {
277 props[i].name = pcfGetINT32(file, format);
278 isStringProp[i] = pcfGetINT8(file, format);
279 props[i].value = pcfGetINT32(file, format);
280 if (props[i].name < 0
281 || (isStringProp[i] != 0 && isStringProp[i] != 1)
282 || (isStringProp[i] && props[i].value < 0)) {
283 pcfError("pcfGetProperties(): invalid file format %ld %d %ld\n",
284 props[i].name, isStringProp[i], props[i].value);
287 if (IS_EOF(file)) goto Bail;
289 /* pad the property array */
291 * clever here - nprops is the same as the number of odd-units read, as
292 * only isStringProp are odd length
296 i = 4 - (nprops & 3);
297 (void)FontFileSkip(file, i);
300 if (IS_EOF(file)) goto Bail;
301 string_size = pcfGetINT32(file, format);
302 if (string_size < 0) goto Bail;
303 if (IS_EOF(file)) goto Bail;
304 strings = malloc(string_size);
306 pcfError("pcfGetProperties(): Couldn't allocate strings (%d)\n", string_size);
309 FontFileRead(file, strings, string_size);
310 if (IS_EOF(file)) goto Bail;
311 position += string_size;
312 for (i = 0; i < nprops; i++) {
313 props[i].name = MakeAtom(strings + props[i].name,
314 strlen(strings + props[i].name), TRUE);
315 if (isStringProp[i]) {
316 props[i].value = MakeAtom(strings + props[i].value,
317 strlen(strings + props[i].value), TRUE);
321 pFontInfo->isStringProp = isStringProp;
322 pFontInfo->props = props;
323 pFontInfo->nprops = nprops;
335 * Fill in the accelerator information from the font file; used
336 * to read both BDF_ACCELERATORS and old style ACCELERATORS
340 pcfGetAccel(FontInfoPtr pFontInfo, FontFilePtr file,
341 PCFTablePtr tables, int ntables, CARD32 type)
346 if (!pcfSeekToType(file, tables, ntables, type, &format, &size) ||
349 format = pcfGetLSB32(file);
350 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
351 !PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS))
355 pFontInfo->noOverlap = pcfGetINT8(file, format);
356 pFontInfo->constantMetrics = pcfGetINT8(file, format);
357 pFontInfo->terminalFont = pcfGetINT8(file, format);
358 pFontInfo->constantWidth = pcfGetINT8(file, format);
359 pFontInfo->inkInside = pcfGetINT8(file, format);
360 pFontInfo->inkMetrics = pcfGetINT8(file, format);
361 pFontInfo->drawDirection = pcfGetINT8(file, format);
362 pFontInfo->anamorphic = FALSE;
363 pFontInfo->cachable = TRUE;
364 /* natural alignment */ pcfGetINT8(file, format);
365 pFontInfo->fontAscent = pcfGetINT32(file, format);
366 pFontInfo->fontDescent = pcfGetINT32(file, format);
367 pFontInfo->maxOverlap = pcfGetINT32(file, format);
368 if (IS_EOF(file)) goto Bail;
369 if (!pcfGetMetric(file, format, &pFontInfo->minbounds))
371 if (!pcfGetMetric(file, format, &pFontInfo->maxbounds))
373 if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
374 if (!pcfGetMetric(file, format, &pFontInfo->ink_minbounds))
376 if (!pcfGetMetric(file, format, &pFontInfo->ink_maxbounds))
379 pFontInfo->ink_minbounds = pFontInfo->minbounds;
380 pFontInfo->ink_maxbounds = pFontInfo->maxbounds;
388 pcfReadFont(FontPtr pFont, FontFilePtr file,
389 int bit, int byte, int glyph, int scan)
393 BitmapFontPtr bitmapFont = 0;
395 PCFTablePtr tables = 0;
401 CharInfoPtr metrics = 0;
402 xCharInfo *ink_metrics = 0;
404 CharInfoPtr **encoding = 0;
407 CARD32 bitmapSizes[GLYPHPADOPTIONS];
409 Bool hasBDFAccelerators;
411 pFont->info.nprops = 0;
412 pFont->info.props = 0;
413 pFont->info.isStringProp=0;
415 if (!(tables = pcfReadTOC(file, &ntables)))
420 if (!pcfGetProperties(&pFont->info, file, tables, ntables))
423 /* Use the old accelerators if no BDF accelerators are in the file */
425 hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
426 if (!hasBDFAccelerators)
427 if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_ACCELERATORS))
432 if (!pcfSeekToType(file, tables, ntables, PCF_METRICS, &format, &size)) {
435 format = pcfGetLSB32(file);
436 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
437 !PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
440 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
441 nmetrics = pcfGetINT32(file, format);
443 nmetrics = pcfGetINT16(file, format);
444 if (IS_EOF(file)) goto Bail;
445 if (nmetrics < 0 || nmetrics > INT32_MAX / sizeof(CharInfoRec)) {
446 pcfError("pcfReadFont(): invalid file format\n");
449 metrics = malloc(nmetrics * sizeof(CharInfoRec));
451 pcfError("pcfReadFont(): Couldn't allocate metrics (%d*%d)\n",
452 nmetrics, (int) sizeof(CharInfoRec));
455 for (i = 0; i < nmetrics; i++)
456 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
457 if (!pcfGetMetric(file, format, &(metrics + i)->metrics))
460 if (!pcfGetCompressedMetric(file, format, &(metrics + i)->metrics))
466 if (!pcfSeekToType(file, tables, ntables, PCF_BITMAPS, &format, &size))
468 format = pcfGetLSB32(file);
469 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
472 nbitmaps = pcfGetINT32(file, format);
473 if (nbitmaps != nmetrics || IS_EOF(file))
475 /* nmetrics is already ok, so nbitmap also is */
476 offsets = malloc(nbitmaps * sizeof(CARD32));
478 pcfError("pcfReadFont(): Couldn't allocate offsets (%d*%d)\n",
479 nbitmaps, (int) sizeof(CARD32));
482 for (i = 0; i < nbitmaps; i++) {
483 offsets[i] = pcfGetINT32(file, format);
484 if (IS_EOF(file)) goto Bail;
487 for (i = 0; i < GLYPHPADOPTIONS; i++) {
488 bitmapSizes[i] = pcfGetINT32(file, format);
489 if (IS_EOF(file)) goto Bail;
490 if (bitmapSizes[i] < 0) goto Bail;
493 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX(format)];
494 /* guard against completely empty font */
495 bitmaps = malloc(sizebitmaps ? sizebitmaps : 1);
497 pcfError("pcfReadFont(): Couldn't allocate bitmaps (%d)\n", sizebitmaps ? sizebitmaps : 1);
500 FontFileRead(file, bitmaps, sizebitmaps);
501 if (IS_EOF(file)) goto Bail;
502 position += sizebitmaps;
504 if (PCF_BIT_ORDER(format) != bit)
505 BitOrderInvert((unsigned char *)bitmaps, sizebitmaps);
506 if ((PCF_BYTE_ORDER(format) == PCF_BIT_ORDER(format)) != (bit == byte)) {
507 switch (bit == byte ? PCF_SCAN_UNIT(format) : scan) {
511 TwoByteSwap((unsigned char *)bitmaps, sizebitmaps);
514 FourByteSwap((unsigned char *)bitmaps, sizebitmaps);
518 if (PCF_GLYPH_PAD(format) != glyph) {
525 sizepadbitmaps = bitmapSizes[PCF_SIZE_TO_INDEX(glyph)];
526 padbitmaps = malloc(sizepadbitmaps);
528 pcfError("pcfReadFont(): Couldn't allocate padbitmaps (%d)\n", sizepadbitmaps);
532 for (i = 0; i < nbitmaps; i++) {
534 metric = &metrics[i].metrics;
536 new += RepadBitmap(bitmaps + old, padbitmaps + new,
537 PCF_GLYPH_PAD(format), glyph,
538 metric->rightSideBearing - metric->leftSideBearing,
539 metric->ascent + metric->descent);
542 bitmaps = padbitmaps;
544 for (i = 0; i < nbitmaps; i++)
545 metrics[i].bits = bitmaps + offsets[i];
553 if (pcfSeekToType(file, tables, ntables, PCF_INK_METRICS, &format, &size)) {
554 format = pcfGetLSB32(file);
555 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
556 !PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
559 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
560 nink_metrics = pcfGetINT32(file, format);
562 nink_metrics = pcfGetINT16(file, format);
563 if (IS_EOF(file)) goto Bail;
564 if (nink_metrics != nmetrics)
566 /* nmetrics already checked */
567 ink_metrics = malloc(nink_metrics * sizeof(xCharInfo));
569 pcfError("pcfReadFont(): Couldn't allocate ink_metrics (%d*%d)\n",
570 nink_metrics, (int) sizeof(xCharInfo));
573 for (i = 0; i < nink_metrics; i++)
574 if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
575 if (!pcfGetMetric(file, format, ink_metrics + i))
578 if (!pcfGetCompressedMetric(file, format, ink_metrics + i))
585 if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
587 format = pcfGetLSB32(file);
588 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
591 pFont->info.firstCol = pcfGetINT16(file, format);
592 pFont->info.lastCol = pcfGetINT16(file, format);
593 pFont->info.firstRow = pcfGetINT16(file, format);
594 pFont->info.lastRow = pcfGetINT16(file, format);
595 pFont->info.defaultCh = pcfGetINT16(file, format);
596 if (IS_EOF(file)) goto Bail;
597 if (pFont->info.firstCol > pFont->info.lastCol ||
598 pFont->info.firstRow > pFont->info.lastRow ||
599 pFont->info.lastCol-pFont->info.firstCol > 255) goto Bail;
601 nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
602 (pFont->info.lastRow - pFont->info.firstRow + 1);
604 encoding = calloc(NUM_SEGMENTS(nencoding), sizeof(CharInfoPtr*));
606 pcfError("pcfReadFont(): Couldn't allocate encoding (%d*%d)\n",
607 nencoding, (int) sizeof(CharInfoPtr));
611 pFont->info.allExist = TRUE;
612 for (i = 0; i < nencoding; i++) {
613 encodingOffset = pcfGetINT16(file, format);
614 if (IS_EOF(file)) goto Bail;
615 if (encodingOffset == 0xFFFF) {
616 pFont->info.allExist = FALSE;
618 if(!encoding[SEGMENT_MAJOR(i)]) {
619 encoding[SEGMENT_MAJOR(i)]=
620 calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr));
621 if(!encoding[SEGMENT_MAJOR(i)])
624 ACCESSENCODINGL(encoding, i) = metrics + encodingOffset;
628 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
630 if (hasBDFAccelerators)
631 if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_BDF_ACCELERATORS))
634 bitmapFont = malloc(sizeof *bitmapFont);
636 pcfError("pcfReadFont(): Couldn't allocate bitmapFont (%d)\n",
637 (int) sizeof *bitmapFont);
641 bitmapFont->version_num = PCF_FILE_VERSION;
642 bitmapFont->num_chars = nmetrics;
643 bitmapFont->num_tables = ntables;
644 bitmapFont->metrics = metrics;
645 bitmapFont->ink_metrics = ink_metrics;
646 bitmapFont->bitmaps = bitmaps;
647 bitmapFont->encoding = encoding;
648 bitmapFont->pDefault = (CharInfoPtr) 0;
649 if (pFont->info.defaultCh != (unsigned short) NO_SUCH_CHAR) {
654 r = pFont->info.defaultCh >> 8;
655 c = pFont->info.defaultCh & 0xFF;
656 if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
657 pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
658 cols = pFont->info.lastCol - pFont->info.firstCol + 1;
659 r = r - pFont->info.firstRow;
660 c = c - pFont->info.firstCol;
661 bitmapFont->pDefault = ACCESSENCODING(encoding, r * cols + c);
664 bitmapFont->bitmapExtra = (BitmapExtraPtr) 0;
665 pFont->fontPrivate = (pointer) bitmapFont;
666 pFont->get_glyphs = bitmapGetGlyphs;
667 pFont->get_metrics = bitmapGetMetrics;
668 pFont->unload_font = pcfUnloadFont;
669 pFont->unload_glyphs = NULL;
672 pFont->glyph = glyph;
679 for(i=0; i<NUM_SEGMENTS(nencoding); i++)
685 free(pFont->info.props);
686 pFont->info.nprops = 0;
687 pFont->info.props = 0;
688 free (pFont->info.isStringProp);
696 pcfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
703 Bool hasBDFAccelerators;
705 pFontInfo->isStringProp = NULL;
706 pFontInfo->props = NULL;
707 pFontInfo->nprops = 0;
709 if (!(tables = pcfReadTOC(file, &ntables)))
714 if (!pcfGetProperties(pFontInfo, file, tables, ntables))
717 /* Use the old accelerators if no BDF accelerators are in the file */
719 hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
720 if (!hasBDFAccelerators)
721 if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_ACCELERATORS))
726 if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
728 format = pcfGetLSB32(file);
729 if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
732 pFontInfo->firstCol = pcfGetINT16(file, format);
733 pFontInfo->lastCol = pcfGetINT16(file, format);
734 pFontInfo->firstRow = pcfGetINT16(file, format);
735 pFontInfo->lastRow = pcfGetINT16(file, format);
736 pFontInfo->defaultCh = pcfGetINT16(file, format);
737 if (IS_EOF(file)) goto Bail;
738 if (pFontInfo->firstCol > pFontInfo->lastCol ||
739 pFontInfo->firstRow > pFontInfo->lastRow ||
740 pFontInfo->lastCol-pFontInfo->firstCol > 255) goto Bail;
742 nencoding = (pFontInfo->lastCol - pFontInfo->firstCol + 1) *
743 (pFontInfo->lastRow - pFontInfo->firstRow + 1);
745 pFontInfo->allExist = TRUE;
746 while (nencoding--) {
747 if (pcfGetINT16(file, format) == 0xFFFF)
748 pFontInfo->allExist = FALSE;
749 if (IS_EOF(file)) goto Bail;
751 if (IS_EOF(file)) goto Bail;
753 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
755 if (hasBDFAccelerators)
756 if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_BDF_ACCELERATORS))
762 pFontInfo->nprops = 0;
763 free (pFontInfo->props);
764 free (pFontInfo->isStringProp);
770 pcfUnloadFont(FontPtr pFont)
772 BitmapFontPtr bitmapFont;
775 bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
776 free(bitmapFont->ink_metrics);
777 if(bitmapFont->encoding) {
778 nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
779 (pFont->info.lastRow - pFont->info.firstRow + 1);
780 for(i=0; i<NUM_SEGMENTS(nencoding); i++)
781 free(bitmapFont->encoding[i]);
783 free(bitmapFont->encoding);
784 free(bitmapFont->bitmaps);
785 free(bitmapFont->metrics);
786 free(pFont->info.isStringProp);
787 free(pFont->info.props);
789 DestroyFontRec(pFont);