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