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