Git init
[framework/uifw/xorg/lib/libxfont.git] / src / bitmap / pcfwrite.c
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
37 #include <X11/fonts/fntfilst.h>
38 #include <X11/fonts/bitmap.h>
39 #include <X11/fonts/pcf.h>
40
41 /* Write PCF font files */
42
43 static CARD32  current_position;
44
45 static int
46 pcfWrite(FontFilePtr file, char *b, int c)
47 {
48     current_position += c;
49     return FontFileWrite(file, b, c);
50 }
51
52 static int
53 pcfPutLSB32(FontFilePtr file, int c)
54 {
55     current_position += 4;
56     (void) FontFilePutc(c, file);
57     (void) FontFilePutc(c >> 8, file);
58     (void) FontFilePutc(c >> 16, file);
59     return FontFilePutc(c >> 24, file);
60 }
61
62 static int
63 pcfPutINT32(FontFilePtr file, CARD32 format, int c)
64 {
65     current_position += 4;
66     if (PCF_BYTE_ORDER(format) == MSBFirst) {
67         (void) FontFilePutc(c >> 24, file);
68         (void) FontFilePutc(c >> 16, file);
69         (void) FontFilePutc(c >> 8, file);
70         return FontFilePutc(c, file);
71     } else {
72         (void) FontFilePutc(c, file);
73         (void) FontFilePutc(c >> 8, file);
74         (void) FontFilePutc(c >> 16, file);
75         return FontFilePutc(c >> 24, file);
76     }
77 }
78
79 static int
80 pcfPutINT16(FontFilePtr file, CARD32 format, int c)
81 {
82     current_position += 2;
83     if (PCF_BYTE_ORDER(format) == MSBFirst) {
84         (void) FontFilePutc(c >> 8, file);
85         return FontFilePutc(c, file);
86     } else {
87         (void) FontFilePutc(c, file);
88         return FontFilePutc(c >> 8, file);
89     }
90 }
91
92 /*ARGSUSED*/
93 static int
94 pcfPutINT8(FontFilePtr file, CARD32 format, int c)
95 {
96     current_position += 1;
97     return FontFilePutc(c, file);
98 }
99
100 static void
101 pcfWriteTOC(FontFilePtr file, PCFTablePtr table, int count)
102 {
103     CARD32      version;
104     int         i;
105
106     version = PCF_FILE_VERSION;
107     pcfPutLSB32(file, version);
108     pcfPutLSB32(file, count);
109     for (i = 0; i < count; i++) {
110         pcfPutLSB32(file, table->type);
111         pcfPutLSB32(file, table->format);
112         pcfPutLSB32(file, table->size);
113         pcfPutLSB32(file, table->offset);
114         table++;
115     }
116 }
117
118 static void
119 pcfPutCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
120 {
121     pcfPutINT8(file, format, metric->leftSideBearing + 0x80);
122     pcfPutINT8(file, format, metric->rightSideBearing + 0x80);
123     pcfPutINT8(file, format, metric->characterWidth + 0x80);
124     pcfPutINT8(file, format, metric->ascent + 0x80);
125     pcfPutINT8(file, format, metric->descent + 0x80);
126 }
127
128 static void
129 pcfPutMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
130 {
131     pcfPutINT16(file, format, metric->leftSideBearing);
132     pcfPutINT16(file, format, metric->rightSideBearing);
133     pcfPutINT16(file, format, metric->characterWidth);
134     pcfPutINT16(file, format, metric->ascent);
135     pcfPutINT16(file, format, metric->descent);
136     pcfPutINT16(file, format, metric->attributes);
137 }
138
139 static void
140 pcfPutBitmap(FontFilePtr file, CARD32 format, CharInfoPtr pCI)
141 {
142     int         count;
143     unsigned char *bits;
144
145     count = BYTES_FOR_GLYPH(pCI, PCF_GLYPH_PAD(format));
146     bits = (unsigned char *) pCI->bits;
147     current_position += count;
148     while (count--)
149         FontFilePutc(*bits++, file);
150 }
151
152 static void
153 pcfPutAccel(FontFilePtr file, CARD32 format, FontInfoPtr pFontInfo)
154 {
155     pcfPutINT8(file, format, pFontInfo->noOverlap);
156     pcfPutINT8(file, format, pFontInfo->constantMetrics);
157     pcfPutINT8(file, format, pFontInfo->terminalFont);
158     pcfPutINT8(file, format, pFontInfo->constantWidth);
159     pcfPutINT8(file, format, pFontInfo->inkInside);
160     pcfPutINT8(file, format, pFontInfo->inkMetrics);
161     pcfPutINT8(file, format, pFontInfo->drawDirection);
162     pcfPutINT8(file, format, 0);
163     pcfPutINT32(file, format, pFontInfo->fontAscent);
164     pcfPutINT32(file, format, pFontInfo->fontDescent);
165     pcfPutINT32(file, format, pFontInfo->maxOverlap);
166     pcfPutMetric(file, format, &pFontInfo->minbounds);
167     pcfPutMetric(file, format, &pFontInfo->maxbounds);
168     if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
169         pcfPutMetric(file, format, &pFontInfo->ink_minbounds);
170         pcfPutMetric(file, format, &pFontInfo->ink_maxbounds);
171     }
172 }
173
174 #define S32 4
175 #define S16 2
176 #define S8 1
177
178 #define Pad(s)      (RoundUp(s) - (s))
179 #define RoundUp(s)  (((s) + 3) & ~3)
180
181 #define Compressable(i) (-128 <= (i) && (i) <= 127)
182
183 #define CanCompressMetric(m)    (Compressable((m)->leftSideBearing) && \
184                                  Compressable((m)->rightSideBearing) && \
185                                  Compressable((m)->characterWidth) && \
186                                  Compressable((m)->ascent) && \
187                                  Compressable((m)->descent) && \
188                                  (m)->attributes == 0)
189
190 #define CanCompressMetrics(min,max) (CanCompressMetric(min) && CanCompressMetric(max))
191
192 static char *
193 pcfNameForAtom(Atom a)
194 {
195     return NameForAtom(a);
196 }
197
198 int
199 pcfWriteFont(FontPtr pFont, FontFilePtr file)
200 {
201     PCFTableRec tables[32],
202                *table;
203     CARD32      mask,
204                 bit;
205     int         ntables;
206     int         size;
207     CARD32      format;
208     int         i;
209     int         cur_table;
210     int         prop_string_size;
211     int         glyph_string_size;
212     xCharInfo  *minbounds,
213                *maxbounds;
214     xCharInfo  *ink_minbounds,
215                *ink_maxbounds;
216     BitmapFontPtr  bitmapFont;
217     int         nencodings = 0;
218     int         header_size;
219     FontPropPtr offsetProps;
220     int         prop_pad = 0;
221     char       *atom_name;
222     int         glyph;
223     CARD32      offset;
224
225     bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
226     if (bitmapFont->bitmapExtra) {
227         minbounds = &bitmapFont->bitmapExtra->info.minbounds;
228         maxbounds = &bitmapFont->bitmapExtra->info.maxbounds;
229         ink_minbounds = &bitmapFont->bitmapExtra->info.ink_minbounds;
230         ink_maxbounds = &bitmapFont->bitmapExtra->info.ink_maxbounds;
231     } else {
232         minbounds = &pFont->info.minbounds;
233         maxbounds = &pFont->info.maxbounds;
234         ink_minbounds = &pFont->info.ink_minbounds;
235         ink_maxbounds = &pFont->info.ink_maxbounds;
236     }
237     offsetProps = malloc(pFont->info.nprops * sizeof(FontPropRec));
238     if (!offsetProps) {
239       pcfError("pcfWriteFont(): Couldn't allocate offsetProps (%d*%d)", pFont->info.nprops, sizeof(FontPropRec));
240         return AllocError;
241     }
242     prop_string_size = 0;
243     for (i = 0; i < pFont->info.nprops; i++) {
244         offsetProps[i].name = prop_string_size;
245         prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].name)) + 1;
246         if (pFont->info.isStringProp[i]) {
247             offsetProps[i].value = prop_string_size;
248             prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].value)) + 1;
249         } else
250             offsetProps[i].value = pFont->info.props[i].value;
251     }
252     format = PCF_FORMAT(pFont->bit, pFont->byte, pFont->glyph, pFont->scan);
253     mask = 0xFFFFFFF;
254     ntables = 0;
255     table = tables;
256     while (mask) {
257         bit = lowbit(mask);
258         mask &= ~bit;
259         table->type = bit;
260         switch (bit) {
261         case PCF_PROPERTIES:
262             table->format = PCF_DEFAULT_FORMAT | format;
263             size = S32 + S32 + (S32 + S8 + S32) * pFont->info.nprops;
264             prop_pad = Pad(size);
265             table->size = RoundUp(size) + S32 +
266                 RoundUp(prop_string_size);
267             table++;
268             break;
269         case PCF_ACCELERATORS:
270             if (bitmapFont->bitmapExtra->info.inkMetrics)
271                 table->format = PCF_ACCEL_W_INKBOUNDS | format;
272             else
273                 table->format = PCF_DEFAULT_FORMAT | format;
274             table->size = 100;
275             table++;
276             break;
277         case PCF_METRICS:
278             if (CanCompressMetrics(minbounds, maxbounds)) {
279                 table->format = PCF_COMPRESSED_METRICS | format;
280                 size = S32 + S16 + bitmapFont->num_chars * (5 * S8);
281                 table->size = RoundUp(size);
282             } else {
283                 table->format = PCF_DEFAULT_FORMAT | format;
284                 table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16);
285             }
286             table++;
287             break;
288         case PCF_BITMAPS:
289             table->format = PCF_DEFAULT_FORMAT | format;
290             size = S32 + S32 + bitmapFont->num_chars * S32 +
291                 GLYPHPADOPTIONS * S32 +
292                 bitmapFont->bitmapExtra->bitmapsSizes[PCF_GLYPH_PAD_INDEX(format)];
293             table->size = RoundUp(size);
294             table++;
295             break;
296         case PCF_INK_METRICS:
297             if (bitmapFont->ink_metrics) {
298                 if (CanCompressMetrics(ink_minbounds, ink_maxbounds)) {
299                     table->format = PCF_COMPRESSED_METRICS | format;
300                     size = S32 + S16 + bitmapFont->num_chars * (5 * S8);
301                     table->size = RoundUp(size);
302                 } else {
303                     table->format = PCF_DEFAULT_FORMAT | format;
304                     table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16);
305                 }
306                 table++;
307             }
308             break;
309         case PCF_BDF_ENCODINGS:
310             table->format = PCF_DEFAULT_FORMAT | format;
311             nencodings = (pFont->info.lastRow - pFont->info.firstRow + 1) *
312                 (pFont->info.lastCol - pFont->info.firstCol + 1);
313             size = S32 + 5 * S16 + nencodings * S16;
314             table->size = RoundUp(size);
315             table++;
316             break;
317         case PCF_SWIDTHS:
318             table->format = PCF_DEFAULT_FORMAT | format;
319             table->size = S32 + S32 + bitmapFont->num_chars * S32;
320             table++;
321             break;
322         case PCF_GLYPH_NAMES:
323             table->format = PCF_DEFAULT_FORMAT | format;
324             glyph_string_size = 0;
325             for (i = 0; i < bitmapFont->num_chars; i++)
326                 glyph_string_size += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1;
327             table->size = S32 + S32 + bitmapFont->num_chars * S32 +
328                 S32 + RoundUp(glyph_string_size);
329             table++;
330             break;
331         case PCF_BDF_ACCELERATORS:
332             if (pFont->info.inkMetrics)
333                 table->format = PCF_ACCEL_W_INKBOUNDS | format;
334             else
335                 table->format = PCF_DEFAULT_FORMAT | format;
336             table->size = 100;
337             table++;
338             break;
339         }
340     }
341     ntables = table - tables;
342     offset = 0;
343     header_size = S32 + S32 + ntables * (4 * S32);
344     offset = header_size;
345     for (cur_table = 0, table = tables;
346             cur_table < ntables;
347             cur_table++, table++) {
348         table->offset = offset;
349         offset += table->size;
350     }
351     current_position = 0;
352     pcfWriteTOC(file, tables, ntables);
353     for (cur_table = 0, table = tables;
354             cur_table < ntables;
355             cur_table++, table++) {
356         if (current_position > table->offset) {
357             printf("can't go backwards... %d > %d\n",
358                    (int)current_position, (int)table->offset);
359             free(offsetProps);
360             return BadFontName;
361         }
362         while (current_position < table->offset)
363             pcfPutINT8(file, format, '\0');
364         pcfPutLSB32(file, table->format);
365         switch (table->type) {
366         case PCF_PROPERTIES:
367             pcfPutINT32(file, format, pFont->info.nprops);
368             for (i = 0; i < pFont->info.nprops; i++) {
369                 pcfPutINT32(file, format, offsetProps[i].name);
370                 pcfPutINT8(file, format, pFont->info.isStringProp[i]);
371                 pcfPutINT32(file, format, offsetProps[i].value);
372             }
373             for (i = 0; i < prop_pad; i++)
374                 pcfPutINT8(file, format, 0);
375             pcfPutINT32(file, format, prop_string_size);
376             for (i = 0; i < pFont->info.nprops; i++) {
377                 atom_name = pcfNameForAtom(pFont->info.props[i].name);
378                 pcfWrite(file, atom_name, strlen(atom_name) + 1);
379                 if (pFont->info.isStringProp[i]) {
380                     atom_name = pcfNameForAtom(pFont->info.props[i].value);
381                     pcfWrite(file, atom_name, strlen(atom_name) + 1);
382                 }
383             }
384             break;
385         case PCF_ACCELERATORS:
386             pcfPutAccel(file, table->format, &bitmapFont->bitmapExtra->info);
387             break;
388         case PCF_METRICS:
389             if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) {
390                 pcfPutINT16(file, format, bitmapFont->num_chars);
391                 for (i = 0; i < bitmapFont->num_chars; i++)
392                     pcfPutCompressedMetric(file, format, &bitmapFont->metrics[i].metrics);
393             } else {
394                 pcfPutINT32(file, format, bitmapFont->num_chars);
395                 for (i = 0; i < bitmapFont->num_chars; i++)
396                     pcfPutMetric(file, format, &bitmapFont->metrics[i].metrics);
397             }
398             break;
399         case PCF_BITMAPS:
400             pcfPutINT32(file, format, bitmapFont->num_chars);
401             glyph = PCF_GLYPH_PAD(format);
402             offset = 0;
403             for (i = 0; i < bitmapFont->num_chars; i++) {
404                 pcfPutINT32(file, format, offset);
405                 offset += BYTES_FOR_GLYPH(&bitmapFont->metrics[i], glyph);
406             }
407             for (i = 0; i < GLYPHPADOPTIONS; i++) {
408                 pcfPutINT32(file, format,
409                             bitmapFont->bitmapExtra->bitmapsSizes[i]);
410             }
411             for (i = 0; i < bitmapFont->num_chars; i++)
412                 pcfPutBitmap(file, format, &bitmapFont->metrics[i]);
413             break;
414         case PCF_INK_METRICS:
415             if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) {
416                 pcfPutINT16(file, format, bitmapFont->num_chars);
417                 for (i = 0; i < bitmapFont->num_chars; i++)
418                     pcfPutCompressedMetric(file, format, &bitmapFont->ink_metrics[i]);
419             } else {
420                 pcfPutINT32(file, format, bitmapFont->num_chars);
421                 for (i = 0; i < bitmapFont->num_chars; i++)
422                     pcfPutMetric(file, format, &bitmapFont->ink_metrics[i]);
423             }
424             break;
425         case PCF_BDF_ENCODINGS:
426             pcfPutINT16(file, format, pFont->info.firstCol);
427             pcfPutINT16(file, format, pFont->info.lastCol);
428             pcfPutINT16(file, format, pFont->info.firstRow);
429             pcfPutINT16(file, format, pFont->info.lastRow);
430             pcfPutINT16(file, format, pFont->info.defaultCh);
431             for (i = 0; i < nencodings; i++) {
432                 if (ACCESSENCODING(bitmapFont->encoding,i))
433                     pcfPutINT16(file, format, 
434                                 ACCESSENCODING(bitmapFont->encoding, i) - 
435                                   bitmapFont->metrics);
436                 else
437                     pcfPutINT16(file, format, 0xFFFF);
438             }
439             break;
440         case PCF_SWIDTHS:
441             pcfPutINT32(file, format, bitmapFont->num_chars);
442             for (i = 0; i < bitmapFont->num_chars; i++)
443                 pcfPutINT32(file, format, bitmapFont->bitmapExtra->sWidths[i]);
444             break;
445         case PCF_GLYPH_NAMES:
446             pcfPutINT32(file, format, bitmapFont->num_chars);
447             offset = 0;
448             for (i = 0; i < bitmapFont->num_chars; i++) {
449                 pcfPutINT32(file, format, offset);
450                 offset += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1;
451             }
452             pcfPutINT32(file, format, offset);
453             for (i = 0; i < bitmapFont->num_chars; i++) {
454                 atom_name = pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i]);
455                 pcfWrite(file, atom_name, strlen(atom_name) + 1);
456             }
457             break;
458         case PCF_BDF_ACCELERATORS:
459             pcfPutAccel(file, table->format, &pFont->info);
460             break;
461         }
462     }
463
464     free(offsetProps);
465     return Successful;
466 }