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