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 <X11/fonts/fntfilst.h> 38#include <X11/fonts/bitmap.h> 39#include <X11/fonts/pcf.h> 40 41/* Write PCF font files */ 42 43static CARD32 current_position; 44 45static int 46pcfWrite(FontFilePtr file, char *b, int c) 47{ 48 current_position += c; 49 return FontFileWrite(file, b, c); 50} 51 52static int 53pcfPutLSB32(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 62static int 63pcfPutINT32(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 79static int 80pcfPutINT16(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*/ 93static int 94pcfPutINT8(FontFilePtr file, CARD32 format, int c) 95{ 96 current_position += 1; 97 return FontFilePutc(c, file); 98} 99 100static void 101pcfWriteTOC(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 118static void 119pcfPutCompressedMetric(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 128static void 129pcfPutMetric(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 139static void 140pcfPutBitmap(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 152static void 153pcfPutAccel(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 192static char * 193pcfNameForAtom(Atom a) 194{ 195 return NameForAtom(a); 196} 197 198int 199pcfWriteFont(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)", 240 pFont->info.nprops, (int) sizeof(FontPropRec)); 241 return AllocError; 242 } 243 prop_string_size = 0; 244 for (i = 0; i < pFont->info.nprops; i++) { 245 offsetProps[i].name = prop_string_size; 246 prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].name)) + 1; 247 if (pFont->info.isStringProp[i]) { 248 offsetProps[i].value = prop_string_size; 249 prop_string_size += strlen(pcfNameForAtom(pFont->info.props[i].value)) + 1; 250 } else 251 offsetProps[i].value = pFont->info.props[i].value; 252 } 253 format = PCF_FORMAT(pFont->bit, pFont->byte, pFont->glyph, pFont->scan); 254 mask = 0xFFFFFFF; 255 ntables = 0; 256 table = tables; 257 while (mask) { 258 bit = lowbit(mask); 259 mask &= ~bit; 260 table->type = bit; 261 switch (bit) { 262 case PCF_PROPERTIES: 263 table->format = PCF_DEFAULT_FORMAT | format; 264 size = S32 + S32 + (S32 + S8 + S32) * pFont->info.nprops; 265 prop_pad = Pad(size); 266 table->size = RoundUp(size) + S32 + 267 RoundUp(prop_string_size); 268 table++; 269 break; 270 case PCF_ACCELERATORS: 271 if (bitmapFont->bitmapExtra->info.inkMetrics) 272 table->format = PCF_ACCEL_W_INKBOUNDS | format; 273 else 274 table->format = PCF_DEFAULT_FORMAT | format; 275 table->size = 100; 276 table++; 277 break; 278 case PCF_METRICS: 279 if (CanCompressMetrics(minbounds, maxbounds)) { 280 table->format = PCF_COMPRESSED_METRICS | format; 281 size = S32 + S16 + bitmapFont->num_chars * (5 * S8); 282 table->size = RoundUp(size); 283 } else { 284 table->format = PCF_DEFAULT_FORMAT | format; 285 table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16); 286 } 287 table++; 288 break; 289 case PCF_BITMAPS: 290 table->format = PCF_DEFAULT_FORMAT | format; 291 size = S32 + S32 + bitmapFont->num_chars * S32 + 292 GLYPHPADOPTIONS * S32 + 293 bitmapFont->bitmapExtra->bitmapsSizes[PCF_GLYPH_PAD_INDEX(format)]; 294 table->size = RoundUp(size); 295 table++; 296 break; 297 case PCF_INK_METRICS: 298 if (bitmapFont->ink_metrics) { 299 if (CanCompressMetrics(ink_minbounds, ink_maxbounds)) { 300 table->format = PCF_COMPRESSED_METRICS | format; 301 size = S32 + S16 + bitmapFont->num_chars * (5 * S8); 302 table->size = RoundUp(size); 303 } else { 304 table->format = PCF_DEFAULT_FORMAT | format; 305 table->size = S32 + S32 + bitmapFont->num_chars * (6 * S16); 306 } 307 table++; 308 } 309 break; 310 case PCF_BDF_ENCODINGS: 311 table->format = PCF_DEFAULT_FORMAT | format; 312 nencodings = (pFont->info.lastRow - pFont->info.firstRow + 1) * 313 (pFont->info.lastCol - pFont->info.firstCol + 1); 314 size = S32 + 5 * S16 + nencodings * S16; 315 table->size = RoundUp(size); 316 table++; 317 break; 318 case PCF_SWIDTHS: 319 table->format = PCF_DEFAULT_FORMAT | format; 320 table->size = S32 + S32 + bitmapFont->num_chars * S32; 321 table++; 322 break; 323 case PCF_GLYPH_NAMES: 324 table->format = PCF_DEFAULT_FORMAT | format; 325 glyph_string_size = 0; 326 for (i = 0; i < bitmapFont->num_chars; i++) 327 glyph_string_size += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1; 328 table->size = S32 + S32 + bitmapFont->num_chars * S32 + 329 S32 + RoundUp(glyph_string_size); 330 table++; 331 break; 332 case PCF_BDF_ACCELERATORS: 333 if (pFont->info.inkMetrics) 334 table->format = PCF_ACCEL_W_INKBOUNDS | format; 335 else 336 table->format = PCF_DEFAULT_FORMAT | format; 337 table->size = 100; 338 table++; 339 break; 340 } 341 } 342 ntables = table - tables; 343 offset = 0; 344 header_size = S32 + S32 + ntables * (4 * S32); 345 offset = header_size; 346 for (cur_table = 0, table = tables; 347 cur_table < ntables; 348 cur_table++, table++) { 349 table->offset = offset; 350 offset += table->size; 351 } 352 current_position = 0; 353 pcfWriteTOC(file, tables, ntables); 354 for (cur_table = 0, table = tables; 355 cur_table < ntables; 356 cur_table++, table++) { 357 if (current_position > table->offset) { 358 printf("can't go backwards... %d > %d\n", 359 (int)current_position, (int)table->offset); 360 free(offsetProps); 361 return BadFontName; 362 } 363 while (current_position < table->offset) 364 pcfPutINT8(file, format, '\0'); 365 pcfPutLSB32(file, table->format); 366 switch (table->type) { 367 case PCF_PROPERTIES: 368 pcfPutINT32(file, format, pFont->info.nprops); 369 for (i = 0; i < pFont->info.nprops; i++) { 370 pcfPutINT32(file, format, offsetProps[i].name); 371 pcfPutINT8(file, format, pFont->info.isStringProp[i]); 372 pcfPutINT32(file, format, offsetProps[i].value); 373 } 374 for (i = 0; i < prop_pad; i++) 375 pcfPutINT8(file, format, 0); 376 pcfPutINT32(file, format, prop_string_size); 377 for (i = 0; i < pFont->info.nprops; i++) { 378 atom_name = pcfNameForAtom(pFont->info.props[i].name); 379 pcfWrite(file, atom_name, strlen(atom_name) + 1); 380 if (pFont->info.isStringProp[i]) { 381 atom_name = pcfNameForAtom(pFont->info.props[i].value); 382 pcfWrite(file, atom_name, strlen(atom_name) + 1); 383 } 384 } 385 break; 386 case PCF_ACCELERATORS: 387 pcfPutAccel(file, table->format, &bitmapFont->bitmapExtra->info); 388 break; 389 case PCF_METRICS: 390 if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) { 391 pcfPutINT16(file, format, bitmapFont->num_chars); 392 for (i = 0; i < bitmapFont->num_chars; i++) 393 pcfPutCompressedMetric(file, format, &bitmapFont->metrics[i].metrics); 394 } else { 395 pcfPutINT32(file, format, bitmapFont->num_chars); 396 for (i = 0; i < bitmapFont->num_chars; i++) 397 pcfPutMetric(file, format, &bitmapFont->metrics[i].metrics); 398 } 399 break; 400 case PCF_BITMAPS: 401 pcfPutINT32(file, format, bitmapFont->num_chars); 402 glyph = PCF_GLYPH_PAD(format); 403 offset = 0; 404 for (i = 0; i < bitmapFont->num_chars; i++) { 405 pcfPutINT32(file, format, offset); 406 offset += BYTES_FOR_GLYPH(&bitmapFont->metrics[i], glyph); 407 } 408 for (i = 0; i < GLYPHPADOPTIONS; i++) { 409 pcfPutINT32(file, format, 410 bitmapFont->bitmapExtra->bitmapsSizes[i]); 411 } 412 for (i = 0; i < bitmapFont->num_chars; i++) 413 pcfPutBitmap(file, format, &bitmapFont->metrics[i]); 414 break; 415 case PCF_INK_METRICS: 416 if (PCF_FORMAT_MATCH(table->format, PCF_COMPRESSED_METRICS)) { 417 pcfPutINT16(file, format, bitmapFont->num_chars); 418 for (i = 0; i < bitmapFont->num_chars; i++) 419 pcfPutCompressedMetric(file, format, &bitmapFont->ink_metrics[i]); 420 } else { 421 pcfPutINT32(file, format, bitmapFont->num_chars); 422 for (i = 0; i < bitmapFont->num_chars; i++) 423 pcfPutMetric(file, format, &bitmapFont->ink_metrics[i]); 424 } 425 break; 426 case PCF_BDF_ENCODINGS: 427 pcfPutINT16(file, format, pFont->info.firstCol); 428 pcfPutINT16(file, format, pFont->info.lastCol); 429 pcfPutINT16(file, format, pFont->info.firstRow); 430 pcfPutINT16(file, format, pFont->info.lastRow); 431 pcfPutINT16(file, format, pFont->info.defaultCh); 432 for (i = 0; i < nencodings; i++) { 433 if (ACCESSENCODING(bitmapFont->encoding,i)) 434 pcfPutINT16(file, format, 435 ACCESSENCODING(bitmapFont->encoding, i) - 436 bitmapFont->metrics); 437 else 438 pcfPutINT16(file, format, 0xFFFF); 439 } 440 break; 441 case PCF_SWIDTHS: 442 pcfPutINT32(file, format, bitmapFont->num_chars); 443 for (i = 0; i < bitmapFont->num_chars; i++) 444 pcfPutINT32(file, format, bitmapFont->bitmapExtra->sWidths[i]); 445 break; 446 case PCF_GLYPH_NAMES: 447 pcfPutINT32(file, format, bitmapFont->num_chars); 448 offset = 0; 449 for (i = 0; i < bitmapFont->num_chars; i++) { 450 pcfPutINT32(file, format, offset); 451 offset += strlen(pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i])) + 1; 452 } 453 pcfPutINT32(file, format, offset); 454 for (i = 0; i < bitmapFont->num_chars; i++) { 455 atom_name = pcfNameForAtom(bitmapFont->bitmapExtra->glyphNames[i]); 456 pcfWrite(file, atom_name, strlen(atom_name) + 1); 457 } 458 break; 459 case PCF_BDF_ACCELERATORS: 460 pcfPutAccel(file, table->format, &pFont->info); 461 break; 462 } 463 } 464 465 free(offsetProps); 466 return Successful; 467} 468