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