write.c revision d2f28e1b
1/* 2Copyright (c) 2002-2003 by Juliusz Chroboczek 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21*/ 22/* $XFree86: xc/programs/fonttosfnt/write.c,v 1.4tsi Exp $ */ 23 24#if defined(linux) && !defined(_GNU_SOURCE) 25/* for fwrite_unlocked and fread_unlocked */ 26#define _GNU_SOURCE 1 27#endif 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <sys/types.h> 32#include <netinet/in.h> 33#include "X11/Xos.h" 34 35#include "fonttosfnt.h" 36 37#if !defined(I_LOVE_POSIX) && \ 38 defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 39#define DO_FWRITE fwrite_unlocked 40#define DO_FREAD fread_unlocked 41#else 42#define DO_FWRITE fwrite 43#define DO_FREAD fread 44#endif 45 46static int writeDir(FILE*, FontPtr, int, unsigned*); 47static int fixupDir(FILE*, FontPtr, int, int*, int*); 48static int fixupChecksum(FILE*, int, int); 49 50static int writeEBDT(FILE*, FontPtr); 51static int writeEBLC(FILE*, FontPtr); 52static int writeOS2(FILE*, FontPtr); 53static int writePCLT(FILE*, FontPtr); 54static int writecmap(FILE*, FontPtr); 55static int writeglyf(FILE*, FontPtr); 56static int writehead(FILE*, FontPtr); 57static int writehhea(FILE*, FontPtr); 58static int writehmtx(FILE*, FontPtr); 59static int writeloca(FILE*, FontPtr); 60static int writemaxp(FILE*, FontPtr); 61static int writename(FILE*, FontPtr); 62static int writepost(FILE*, FontPtr); 63 64static CmapPtr current_cmap = NULL; 65static int numglyphs, nummetrics; 66static int write_error_occurred, read_error_occurred; 67 68/* floor(log2(x)) */ 69static int 70log2_floor(int x) 71{ 72 int i, j; 73 74 if(x <= 0) 75 abort(); 76 77 i = 0; 78 j = 1; 79 while(2 * j < x) { 80 i++; 81 j *= 2; 82 } 83 return i; 84} 85 86/* 2 ** floor(log2(x)) */ 87static int 88two_log2_floor(int x) 89{ 90 int j; 91 92 if(x <= 0) 93 abort(); 94 95 j = 1; 96 while(2 * j < x) { 97 j *= 2; 98 } 99 return j; 100} 101 102static void 103write_error(int rc) 104{ 105 /* Real Men program in C and don't use exceptions. */ 106 if(write_error_occurred) 107 return; 108 write_error_occurred = 1; 109 if(rc < 0) 110 perror("Couldn't write"); 111 else 112 fprintf(stderr, "Short write.\n"); 113} 114 115static void 116read_error(int rc) 117{ 118 if(read_error_occurred) 119 return; 120 read_error_occurred = 1; 121 if(rc < 0) 122 perror("Couldn't read"); 123 else 124 fprintf(stderr, "Short read.\n"); 125} 126 127static void 128writeBYTE(FILE *out, unsigned char val) 129{ 130 int rc; 131 rc = DO_FWRITE(&val, 1, 1, out); 132 if(rc != 1) write_error(rc); 133} 134 135static void 136writeBYTEs(FILE *out, unsigned char *chars, int n) 137{ 138 int rc; 139 rc = DO_FWRITE(chars, 1, n, out); 140 if(rc != n) write_error(rc); 141} 142 143static void 144writeCHAR(FILE *out, char val) 145{ 146 int rc; 147 rc = DO_FWRITE(&val, 1, 1, out); 148 if(rc != 1) write_error(rc); 149} 150 151static void 152writeCHARs(FILE *out, char *chars, int n) 153{ 154 int rc; 155 rc = DO_FWRITE(chars, 1, n, out); 156 if(rc != n) write_error(rc); 157} 158 159static void 160writeUSHORT(FILE *out, unsigned short val) 161{ 162 int rc; 163 val = htons(val); 164 rc = DO_FWRITE(&val, 2, 1, out); 165 if(rc != 1) write_error(rc); 166} 167 168static void 169writeSHORT(FILE *out, short val) 170{ 171 int rc; 172 val = htons(val); 173 rc = DO_FWRITE(&val, 2, 1, out); 174 if(rc != 1) write_error(rc); 175} 176 177static void 178writeULONG(FILE *out, unsigned int val) 179{ 180 int rc; 181 val = htonl(val); 182 rc = DO_FWRITE(&val, 4, 1, out); 183 if(rc != 1) write_error(rc); 184} 185 186static void 187writeLONG(FILE *out, int val) 188{ 189 int rc; 190 val = htonl(val); 191 rc = DO_FWRITE(&val, 4, 1, out); 192 if(rc != 1) write_error(rc); 193} 194 195static unsigned 196readULONG(FILE *out) 197{ 198 int rc; 199 unsigned val; 200 rc = DO_FREAD(&val, 4, 1, out); 201 if(rc != 1) { 202 read_error(rc); 203 return 0xDEADBEEF; 204 } 205 return ntohl(val); 206} 207 208void 209fontMetrics(FontPtr font) 210{ 211 int i, rc; 212 double sumAwidth = 0; 213 unsigned count = 0; 214 215 font->metrics.maxAwidth = 0; 216 font->metrics.maxX = -10000 * TWO_SIXTEENTH; 217 font->metrics.maxY = -10000 * TWO_SIXTEENTH; 218 font->metrics.minX = 10000 * TWO_SIXTEENTH; 219 font->metrics.minY = 10000 * TWO_SIXTEENTH; 220 221 for(i = 0; i < FONT_CODES; i++) { 222 int awidth, x0, y0, x1, y1; 223 rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1); 224 if(rc < 0) 225 continue; 226 227 if(awidth > font->metrics.maxAwidth) font->metrics.maxAwidth = awidth; 228 if(x0 < font->metrics.minX) font->metrics.minX = x0; 229 if(y0 < font->metrics.minY) font->metrics.minY = y0; 230 if(x1 > font->metrics.maxX) font->metrics.maxX = x1; 231 if(y1 > font->metrics.maxY) font->metrics.maxY = y1; 232 233 if(awidth > 0) { 234 sumAwidth += awidth; 235 count++; 236 } 237 } 238 239 if (count) font->metrics.awidth = sumAwidth / count; 240 241 font->metrics.height = TWO_SIXTEENTH; 242 243 if(font->pxMetrics.size == UNDEF) { 244 font->pxMetrics.size = font->pxMetrics.height; 245 font->metrics.size = font->metrics.height; 246 } 247 248 font->metrics.size = font->pxMetrics.size 249 * TWO_SIXTEENTH / font->pxMetrics.height; 250 251 if(font->pxMetrics.ascent == UNDEF) { 252 font->metrics.ascent = font->metrics.maxY; 253 font->pxMetrics.ascent = 254 font->metrics.ascent 255 * font->pxMetrics.height / TWO_SIXTEENTH; 256 } 257 else 258 font->metrics.ascent = 259 font->pxMetrics.ascent 260 * TWO_SIXTEENTH / font->pxMetrics.height; 261 262 if(font->pxMetrics.descent == UNDEF) { 263 font->metrics.descent = - font->metrics.minY; 264 font->pxMetrics.descent = 265 font->metrics.descent 266 * font->pxMetrics.height / TWO_SIXTEENTH; 267 } 268 else 269 font->metrics.descent = 270 font->pxMetrics.descent 271 * TWO_SIXTEENTH / font->pxMetrics.height; 272 273 if(font->pxMetrics.capHeight == UNDEF) { 274 if(glyphMetrics(font, 'X', NULL, NULL, NULL, NULL, &font->metrics.capHeight) != 1) 275 font->metrics.capHeight = font->metrics.ascent; 276 font->pxMetrics.capHeight = 277 font->metrics.capHeight * font->pxMetrics.height / TWO_SIXTEENTH; 278 } 279 else 280 font->metrics.capHeight = 281 font->pxMetrics.capHeight 282 * TWO_SIXTEENTH / font->pxMetrics.height; 283 284 if(font->pxMetrics.xHeight == UNDEF) { 285 if(glyphMetrics(font, 'x', NULL, NULL, NULL, NULL, &font->metrics.xHeight) != 1) 286 font->metrics.xHeight = font->metrics.capHeight * 2 / 3; 287 font->pxMetrics.xHeight = 288 font->metrics.xHeight * font->pxMetrics.height / TWO_SIXTEENTH; 289 } 290 else 291 font->metrics.xHeight = 292 font->pxMetrics.xHeight 293 * TWO_SIXTEENTH / font->pxMetrics.height; 294 295 if(font->pxMetrics.underlinePosition == UNDEF) 296 font->metrics.underlinePosition = - font->metrics.descent * 2; 297 else { 298 font->metrics.underlinePosition = 299 font->pxMetrics.underlinePosition 300 * TWO_SIXTEENTH / font->pxMetrics.height; 301 } 302 303 if(font->pxMetrics.underlineThickness == UNDEF) 304 /* make sure thickness is at least one pixel. */ 305 /* TODO: this could be refined according to 306 * X Logical Font Description Conventions (xlfd.txt) 307 * by also considering the font weight. */ 308 font->metrics.underlineThickness = 309 TWO_SIXTEENTH 310 / (font->pxMetrics.height < 9 ? font->pxMetrics.height : 9); 311 else 312 font->metrics.underlineThickness = 313 font->pxMetrics.underlineThickness 314 * TWO_SIXTEENTH / font->pxMetrics.height; 315} 316 317int 318writeFile(char *filename, FontPtr font) 319{ 320 int rc; 321 FILE *out; 322 unsigned tables[15]; 323 int head_position = 0; 324 int full_length; 325 int (*(table_writers[15]))(FILE*, FontPtr); 326 int i, j; 327 int offset[15], length[15]; 328 StrikePtr strike; 329 330 out = fopen(filename, "wb+"); 331 if(out == NULL) 332 return -1; 333 334 current_cmap = makeCmap(font); 335 if(current_cmap == NULL) { 336 fprintf(stderr, "Couldn't build cmap.\n"); 337 goto fail; 338 } 339 340 fontMetrics(font); 341 342 write_error_occurred = 0; 343 read_error_occurred = 0; 344 345 if(glyph_flag >= 2) { 346 numglyphs = maxIndex(current_cmap) + 1; 347 if(metrics_flag >= 2) 348 nummetrics = numglyphs - 1; 349 else if(metrics_flag >= 1) 350 nummetrics = 1; 351 else 352 nummetrics = 0; 353 } else if(glyph_flag == 1) { 354 numglyphs = 1; 355 nummetrics = (metrics_flag >= 1) ? 1 : 0; 356 } else { 357 numglyphs = 0; 358 nummetrics = 0; 359 } 360 361 strike = font->strikes; 362 while(strike) { 363 strike->indexSubTables = makeIndexSubTables(strike, current_cmap); 364 if(!strike->indexSubTables) { 365 fprintf(stderr, "Couldn't build indexSubTable.\n"); 366 goto fail; 367 } 368 strike = strike->next; 369 } 370 371 /* These must be sorted lexicographically */ 372 i = 0; 373 tables[i] = makeName("EBDT"); table_writers[i] = writeEBDT; i++; 374 tables[i] = makeName("EBLC"); table_writers[i] = writeEBLC; i++; 375 tables[i] = makeName("OS/2"); table_writers[i] = writeOS2; i++; 376 tables[i] = makeName("PCLT"); table_writers[i] = writePCLT; i++; 377 tables[i] = makeName("cmap"); table_writers[i] = writecmap; i++; 378 if(numglyphs >= 1) { 379 tables[i] = makeName("glyf"); 380 table_writers[i] = writeglyf; i++; 381 } 382 tables[i] = makeName("head"); table_writers[i] = writehead; i++; 383 tables[i] = makeName("hhea"); table_writers[i] = writehhea; i++; 384 if(nummetrics >= 1) { 385 tables[i] = makeName("hmtx"); 386 table_writers[i] = writehmtx; i++; 387 } 388 if(numglyphs >= 1) { 389 tables[i] = makeName("loca"); 390 table_writers[i] = writeloca; i++; 391 } 392 tables[i] = makeName("maxp"); table_writers[i] = writemaxp; i++; 393 tables[i] = makeName("name"); table_writers[i] = writename; i++; 394 tables[i] = makeName("post"); table_writers[i] = writepost; i++; 395 396 rc = writeDir(out, font, i, tables); 397 if(rc < 0) 398 goto fail; 399 400 for(j = 0; j < i; j++) { 401 offset[j] = ftell(out); 402 if(offset[j] < 0) { 403 perror("Couldn't compute table offset"); 404 goto fail; 405 } 406 if(tables[j] == makeName("head")) 407 head_position = offset[j]; 408 rc = table_writers[j](out, font); 409 if(rc < 0 || write_error_occurred || read_error_occurred) 410 goto fail; 411 length[j] = ftell(out) - offset[j]; 412 if(length[j] < 0) { 413 perror("Couldn't compute table size"); 414 goto fail; 415 } 416 if(length[j] % 4 != 0) { 417 /* Pad -- recommended by the spec, and assumed by 418 computeChecksum. */ 419 int k; 420 for(k = 0; k < (4 - length[j] % 4); k++) { 421 /* This must be 0 -- see computeChecksum. */ 422 writeBYTE(out, 0); 423 } 424 if(write_error_occurred || read_error_occurred) 425 goto fail; 426 } 427 } 428 429 rc = fixupDir(out, font, i, offset, length); 430 if(rc < 0) 431 goto fail; 432 433 full_length = ftell(out); 434 if(full_length < 0) { 435 perror("Couldn't compute file size"); 436 goto fail; 437 } 438 while(full_length % 4 != 0) { 439 /* pad for computeChecksum */ 440 writeBYTE(out, 0); 441 full_length++; 442 } 443 if(write_error_occurred || read_error_occurred) 444 goto fail; 445 rc = fixupChecksum(out, full_length, head_position); 446 if(rc < 0) 447 goto fail; 448 fclose(out); 449 return 0; 450 451 fail: 452 fclose(out); 453 unlink(filename); 454 return -1; 455} 456 457static int 458writeDir(FILE *out, FontPtr font, int numTables, unsigned *tables) 459{ 460 int i, ti; 461 i = 0; ti = 1; 462 while(2 * ti < numTables) { 463 i++; 464 ti = 2 * ti; 465 } 466 467 writeULONG(out, 0x10000); /* version */ 468 writeUSHORT(out, numTables); /* numTables */ 469 writeUSHORT(out, 16 * ti); /* searchRange */ 470 writeUSHORT(out, i); /* entrySelector */ 471 writeUSHORT(out, 16 * (numTables - ti)); /* rangeShift */ 472 473 /* see fixupDir */ 474 for(i = 0; i < numTables; i++) { 475 writeULONG(out, tables[i]); 476 writeULONG(out, 0xDEADFACE); /* checkSum */ 477 writeULONG(out, 0xDEADFACE); /* offset */ 478 writeULONG(out, 0xDEADFACE); /* length */ 479 } 480 return 0; 481} 482 483static unsigned 484computeChecksum(FILE *out, int offset, int length) 485{ 486 int rc; 487 int i; 488 unsigned sum = 0; 489 490 if(offset % 4 != 0) { 491 fprintf(stderr, "Offset %d is not a multiple of 4\n", offset); 492 return ~0; 493 } 494 495 rc = fseek(out, offset, SEEK_SET); 496 if(rc < 0) { 497 perror("Couldn't seek"); 498 return ~0; 499 } 500 501 /* This relies on the fact that we always pad tables with zeroes. */ 502 for(i = 0; i < length; i += 4) { 503 sum += readULONG(out); 504 } 505 return sum; 506} 507 508static int 509fixupDir(FILE *out, FontPtr font, int numTables, int *offset, int *length) 510{ 511 int rc, i; 512 unsigned sum; 513 514 for(i = 0; i < numTables; i++) { 515 sum = computeChecksum(out, offset[i], length[i]); 516 rc = fseek(out, 12 + 16 * i + 4, SEEK_SET); 517 if(rc != 0) { 518 perror("Couldn't seek"); 519 return -1; 520 } 521 writeULONG(out, sum); 522 writeULONG(out, offset[i]); 523 writeULONG(out, length[i]); 524 } 525 return 0; 526} 527 528static int 529fixupChecksum(FILE *out, int full_length, int head_position) 530{ 531 int rc, checksum; 532 checksum = computeChecksum(out, 0, full_length); 533 rc = fseek(out, head_position + 8, SEEK_SET); 534 if(rc != 0) { 535 perror("Couldn't seek"); 536 return -1; 537 } 538 writeULONG(out, 0xB1B0AFBA - checksum); /* checkSumAdjustment */ 539 return 0; 540} 541 542 543static int 544writehead(FILE* out, FontPtr font) 545{ 546 int time_hi = 0; 547 unsigned time_lo = 0; 548 549 macTime(&time_hi, &time_lo); 550 551 writeULONG(out, 0x00010000); 552 writeULONG(out, 0x00010000); /* fontRevision */ 553 writeULONG(out, 0); /* checkSumAdjustment -- filled in later */ 554 writeULONG(out,0x5F0F3CF5); /* magicNumber */ 555 writeUSHORT(out, 1); /* flags */ 556 writeUSHORT(out, UNITS_PER_EM); /* unitsPerEm */ 557 558 writeLONG(out, time_hi); /* created */ 559 writeULONG(out, time_lo); 560 writeLONG(out, time_hi); /* modified */ 561 writeULONG(out, time_lo); 562 563 /* bounding box for all glyphs */ 564 writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); 565 writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minY)); 566 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX)); 567 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY)); 568 569 writeUSHORT(out, font->flags); /* macStyle */ 570 writeUSHORT(out, 1); /* lowestRecPPEM */ 571 writeSHORT(out, 0); /* fontDirectionHint */ 572 writeSHORT(out, 0); /* indexToLocFormat */ 573 writeSHORT(out, 0); /* glyphDataFormat */ 574 return 0; 575} 576 577static int 578outputRaster(FILE *out, char *raster, int width, int height, int stride, 579 int bit_aligned) 580{ 581 int i, j; 582 int len = 0; 583 584 if(!bit_aligned || width % 8 == 0) { 585 for(i = 0; i < height; i++) { 586 writeCHARs(out, raster + i * stride, (width + 7) / 8); 587 len += (width + 7) / 8; 588 } 589 } else { 590 int bit = 0; 591 unsigned char v = 0; 592 for(i = 0; i < height; i++) { 593 for(j = 0; j < width; j++) { 594 if(BITREF(raster, stride, j, i)) 595 v |= 1 << (7 - bit); 596 bit++; 597 if(bit >= 8) { 598 writeBYTE(out, v); 599 len++; 600 bit = 0; 601 v = 0; 602 } 603 } 604 } 605 if(bit > 0) { 606 writeBYTE(out, v); 607 len++; 608 } 609 } 610 return len; 611} 612 613static int 614writeEBDT(FILE* out, FontPtr font) 615{ 616 StrikePtr strike; 617 BitmapPtr bitmap; 618 IndexSubTablePtr table; 619 int i; 620 int offset; 621 int ebdt_start; 622 623 ebdt_start = ftell(out); 624 625 writeULONG(out, 0x00020000); /* version */ 626 offset = 4; 627 628 strike = font->strikes; 629 while(strike) { 630 table = strike->indexSubTables; 631 while(table) { 632 for(i = table->firstGlyphIndex; i <= table->lastGlyphIndex; i++) { 633 bitmap = strikeBitmapIndex(strike, current_cmap, i); 634 bitmap->location = offset; 635 if(bit_aligned_flag && table->constantMetrics) { 636 /* image format 5 */ 637 ; 638 } else { 639 /* image format 1 or 2 */ 640 writeBYTE(out, bitmap->height); 641 writeBYTE(out, bitmap->width); 642 writeCHAR(out, bitmap->horiBearingX); 643 writeCHAR(out, bitmap->horiBearingY); 644 writeBYTE(out, bitmap->advanceWidth); 645 offset += 5; 646 } 647 offset += outputRaster(out, 648 bitmap->raster, 649 bitmap->width, bitmap->height, 650 bitmap->stride, 651 bit_aligned_flag); 652 } 653 table->lastLocation = offset; 654 table = table->next; 655 } 656 strike = strike->next; 657 } 658 if(ftell(out) != ebdt_start + offset) 659 abort(); 660 return 0; 661} 662 663static int 664writeEBLC(FILE* out, FontPtr font) 665{ 666 int i, rc, numstrikes, eblc_start, num, den; 667 StrikePtr strike; 668 IndexSubTablePtr table; 669 670 degreesToFraction(font->italicAngle, &num, &den); 671 672 numstrikes = 0; 673 strike = font->strikes; 674 while(strike) { 675 numstrikes++; 676 strike = strike->next; 677 } 678 679 eblc_start = ftell(out); 680 681 writeULONG(out, 0x00020000); /* version */ 682 writeULONG(out, numstrikes); /* numSizes */ 683 684 /* bitmapSizeTable */ 685 strike = font->strikes; 686 while(strike) { 687 strike->bitmapSizeTableLocation = ftell(out); 688 writeULONG(out, 0xDEADFACE); /* indexSubTableArrayOffset */ 689 writeULONG(out, 0xDEADFACE); /* indexTablesSize */ 690 writeULONG(out, 0xDEADFACE); /* numberOfIndexSubTables */ 691 writeULONG(out, 0); /* colorRef */ 692 for (i = 0; i <= 1; i++) { 693 writeCHAR(out, font->pxMetrics.ascent); /* ascender */ 694 writeCHAR(out, -font->pxMetrics.descent); /* descender */ 695 writeBYTE(out, strikeMaxWidth(strike)); /* widthMax */ 696 writeCHAR(out, num); /* caretSlopeNumerator */ 697 writeCHAR(out, den); /* caretSlopeDenominator */ 698 writeCHAR(out, 0); /* caretOffset */ 699 writeCHAR(out, 0); /* minOriginSB */ 700 writeCHAR(out, 0); /* minAdvanceSB */ 701 writeCHAR(out, 0); /* maxBeforeBL */ 702 writeCHAR(out, 0); /* minAfterBL */ 703 writeCHAR(out, 0); /* pad1 */ 704 writeCHAR(out, 0); /* pad2 */ 705 } 706 writeUSHORT(out, 0); /* startGlyphIndex */ 707 writeUSHORT(out, 0xFFFD); /* endGlyphIndex */ 708 writeBYTE(out, strike->sizeX); /* ppemX */ 709 writeBYTE(out, strike->sizeY); /* ppemY */ 710 writeBYTE(out, 1); /* bitDepth */ 711 writeCHAR(out, 1); /* flags */ 712 strike = strike->next; 713 } 714 715 /* indexSubTableArray, one per strike */ 716 strike = font->strikes; 717 while(strike) { 718 int endoffset; 719 int numtables = 0; 720 721 strike->indexSubTableLocation = ftell(out); 722 table = strike->indexSubTables; 723 while(table) { 724 table->location = ftell(out); 725 writeUSHORT(out, table->firstGlyphIndex); 726 writeUSHORT(out, table->lastGlyphIndex); 727 writeULONG(out, 0xDEADFACE); /* additionalOffsetToIndexSubtable */ 728 numtables++; 729 table = table->next; 730 } 731 endoffset = ftell(out); 732 rc = fseek(out, strike->bitmapSizeTableLocation, SEEK_SET); 733 if(rc != 0) { 734 perror("Couldn't seek"); 735 return -1; 736 } 737 writeULONG(out, strike->indexSubTableLocation - eblc_start); 738 /* indexSubTableArrayOffset */ 739 writeULONG(out, endoffset - strike->indexSubTableLocation); 740 /* indexTablesSize */ 741 writeULONG(out, numtables); /* numberOfIndexSubTables */ 742 rc = fseek(out, endoffset, SEEK_SET); 743 if(rc != 0) { 744 perror("Couldn't seek"); 745 return -1; 746 } 747 strike = strike->next; 748 } 749 750 /* actual indexSubTables */ 751 strike = font->strikes; 752 while(strike) { 753 table = strike->indexSubTables; 754 while(table) { 755 int location; 756 int data_location; 757 int short_offsets; 758 int offset; 759 760 location = ftell(out); 761 rc = fseek(out, table->location + 4, SEEK_SET); 762 if(rc != 0) { 763 perror("Couldn't seek"); 764 return -1; 765 } 766 /* additionalOffsetToIndexSubtable */ 767 writeULONG(out, location - strike->indexSubTableLocation); 768 rc = fseek(out, location, SEEK_SET); 769 if(rc != 0) { 770 perror("Couldn't seek"); 771 return -1; 772 } 773 data_location = 774 strikeBitmapIndex(strike, current_cmap, 775 table->firstGlyphIndex)->location; 776 short_offsets = 1; 777 for(i = table->firstGlyphIndex; i <= table->lastGlyphIndex; i++) { 778 if(strikeBitmapIndex(strike, current_cmap, i)->location - 779 data_location > 0xFFFF) { 780 short_offsets = 0; 781 break; 782 } 783 } 784 /* indexFormat */ 785 if(table->constantMetrics) 786 writeUSHORT(out, 2); 787 else if(short_offsets) 788 writeUSHORT(out, 3); 789 else 790 writeUSHORT(out, 1); 791 /* imageFormat */ 792 if(bit_aligned_flag) { 793 if(table->constantMetrics) 794 writeUSHORT(out, 5); 795 else 796 writeUSHORT(out, 2); 797 } else { 798 writeUSHORT(out, 1); 799 } 800 writeULONG(out, data_location); 801 if(table->constantMetrics) { 802 int size; 803 BitmapPtr bitmap = 804 strikeBitmapIndex(strike, current_cmap, 805 table->firstGlyphIndex); 806 807 size = 808 strikeBitmapIndex(strike, current_cmap, 809 table->firstGlyphIndex + 1)->location - 810 bitmap->location; 811 writeULONG(out, size); /* imageSize */ 812 /* bigMetrics */ 813 writeBYTE(out, bitmap->height); 814 writeBYTE(out, bitmap->width); 815 writeCHAR(out, bitmap->horiBearingX); 816 writeCHAR(out, bitmap->horiBearingY); 817 writeBYTE(out, bitmap->advanceWidth); 818 writeCHAR(out, bitmap->horiBearingX); /* vertBearingX */ 819 writeCHAR(out, bitmap->horiBearingY); /* vertBearingY */ 820 writeBYTE(out, font->metrics.maxAwidth); /* vertAdvance */ 821 } else { 822 for(i = table->firstGlyphIndex; 823 i <= table->lastGlyphIndex; i++) { 824 offset = 825 strikeBitmapIndex(strike, current_cmap, i)->location - 826 data_location; 827 if(short_offsets) 828 writeUSHORT(out, offset); 829 else 830 writeULONG(out, offset); 831 } 832 /* Dummy glyph of size 0 to mark the end of the table */ 833 if(short_offsets) { 834 writeUSHORT(out, table->lastLocation - data_location); 835 writeUSHORT(out, table->lastLocation - data_location); 836 } else { 837 writeULONG(out, table->lastLocation - data_location); 838 writeULONG(out, table->lastLocation - data_location); 839 } 840 } 841 location = ftell(out); 842 while(location % 4 != 0) { 843 writeCHAR(out, 0); 844 location--; 845 } 846 table = table->next; 847 } 848 strike = strike->next; 849 } 850 return 0; 851} 852 853static int 854writecmap(FILE* out, FontPtr font) 855{ 856 int rc, cmap_start, cmap_end; 857 CmapPtr cmap; 858 int segcount; 859 860 segcount = 0; 861 cmap = current_cmap; 862 while(cmap) { 863 segcount++; 864 cmap = cmap->next; 865 } 866 867 segcount++; /* dummy segment to end table */ 868 869 cmap_start = ftell(out); 870 871 writeUSHORT(out, 0); /* version */ 872 writeUSHORT(out, 1); /* number of encoding tables */ 873 writeUSHORT(out, 3); /* platform ID */ 874 writeUSHORT(out, (font->flags & FACE_SYMBOL) ? 0 : 1); 875 /* encoding ID */ 876 writeULONG(out, 12); /* offset to beginning of subtable */ 877 878 /* subtable */ 879 writeUSHORT(out, 4); /* format */ 880 writeUSHORT(out, 0xDEAD); /* length */ 881 writeUSHORT(out, 0); /* language */ 882 /* How baroque can you get? */ 883 writeUSHORT(out, segcount * 2); /* segCountX2 */ 884 writeUSHORT(out, 2 * two_log2_floor(segcount)); /* searchRange */ 885 writeUSHORT(out, 1 + log2_floor(segcount)); /* entrySelector */ 886 writeUSHORT(out, 2 * (segcount - two_log2_floor(segcount))); 887 /* rangeShift */ 888 889 cmap = current_cmap; 890 while(cmap) { 891 writeUSHORT(out, cmap->endCode); 892 cmap = cmap->next; 893 } 894 writeUSHORT(out, 0xFFFF); 895 896 writeUSHORT(out, 0); /* reservedPad */ 897 898 cmap = current_cmap; 899 while(cmap) { 900 writeUSHORT(out, cmap->startCode); 901 cmap = cmap->next; 902 } 903 writeUSHORT(out, 0xFFFF); 904 905 /* idDelta */ 906 cmap = current_cmap; 907 while(cmap) { 908 writeUSHORT(out, (cmap->index - cmap->startCode) & 0xFFFF); 909 cmap = cmap->next; 910 } 911 writeUSHORT(out, 1); 912 913 /* idRangeOffset */ 914 cmap = current_cmap; 915 while(cmap) { 916 writeUSHORT(out, 0); 917 cmap = cmap->next; 918 } 919 writeUSHORT(out, 0); 920 921 /* glyphIDArray is empty */ 922 923 cmap_end = ftell(out); 924 rc = fseek(out, cmap_start + 12 + 2, SEEK_SET); 925 if(rc != 0) { 926 perror("Couldn't seek"); 927 return -1; 928 } 929 writeUSHORT(out, cmap_end - cmap_start - 12); /* length */ 930 rc = fseek(out, cmap_end, SEEK_SET); 931 if(rc != 0) { 932 perror("Couldn't seek"); 933 return -1; 934 } 935 return 0; 936} 937 938static int 939writeglyf(FILE* out, FontPtr font) 940{ 941 return 0; 942} 943 944int 945writehhea(FILE* out, FontPtr font) 946{ 947 int num, den; 948 degreesToFraction(font->italicAngle, &num, &den); 949 950 writeULONG(out, 0x00010000); /* version */ 951 writeSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* ascender */ 952 writeSHORT(out, -FONT_UNITS_CEIL(font->metrics.descent)); /* descender */ 953 writeSHORT(out, FONT_UNITS(font->metrics.size - font->metrics.ascent - font->metrics.descent)); /* lineGap */ 954 writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* advanceWidthMax */ 955 /* TODO: the next three are not calculated according to spec, are they ? 956 * https://docs.microsoft.com/en-us/typography/opentype/spec/hhea */ 957 writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minLeftSideBearing */ 958 writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minRightSideBearing */ 959 writeSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX)); /* xMaxExtent */ 960 writeSHORT(out, den); /* caretSlopeRise */ 961 writeSHORT(out, num); /* caretSlopeRun */ 962 writeSHORT(out, 0); /* reserved */ 963 writeSHORT(out, 0); /* reserved */ 964 writeSHORT(out, 0); /* reserved */ 965 writeSHORT(out, 0); /* reserved */ 966 writeSHORT(out, 0); /* reserved */ 967 writeSHORT(out, 0); /* metricDataFormat */ 968 writeSHORT(out, nummetrics); /* numberOfHMetrics */ 969 return 0; 970} 971 972static int 973writehmtx(FILE* out, FontPtr font) 974{ 975 int rc, i; 976 977 for(i = 0; i <= numglyphs; i++) { 978 int code, width, lsb; 979 code = findCode(current_cmap, i); 980 if(code < 0) 981 rc = -1; 982 else 983 rc = glyphMetrics(font, code, &width, &lsb, NULL, NULL, NULL); 984 if(rc < 0) { 985 width = UNITS_PER_EM / 3; 986 lsb = 0; 987 } 988 if(i < nummetrics) { 989 writeSHORT(out, FONT_UNITS(width)); 990 writeSHORT(out, FONT_UNITS(lsb)); 991 } else { 992 writeSHORT(out, FONT_UNITS(lsb)); 993 } 994 } 995 return 0; 996} 997 998static int 999writeloca(FILE* out, FontPtr font) 1000{ 1001 int i; 1002 1003 /* All glyphs undefined -- loca table is empty, so offset 0 */ 1004 for(i = 0; i < numglyphs; i++) { 1005 writeSHORT(out, 0); 1006 } 1007 writeSHORT(out, 0); 1008 return 0; 1009} 1010 1011static int 1012writemaxp(FILE* out, FontPtr font) 1013{ 1014 writeLONG(out, 0x00010000); /* version */ 1015 writeUSHORT(out, numglyphs); /* numGlyphs */ 1016 writeUSHORT(out, 0); /* maxPoints */ 1017 writeUSHORT(out, 0); /* maxContours */ 1018 writeUSHORT(out, 0); /* maxCompositePoints */ 1019 writeUSHORT(out, 0); /* maxCompositeContours */ 1020 writeUSHORT(out, 1); /* maxZones */ 1021 writeUSHORT(out, 0); /* maxTwilightPoints */ 1022 writeUSHORT(out, 0); /* maxStorage */ 1023 writeUSHORT(out, 0); /* maxFunctionDefs */ 1024 writeUSHORT(out, 0); /* maxInstructionDefs */ 1025 writeUSHORT(out, 0); /* maxStackElements */ 1026 writeUSHORT(out, 0); /* maxSizeOfInstructions */ 1027 writeUSHORT(out, 0); /* maxComponentElements */ 1028 writeUSHORT(out, 0); /* maxComponentDepth */ 1029 return 0; 1030} 1031 1032static int 1033writename(FILE* out, FontPtr font) 1034{ 1035 int i; 1036 int offset; 1037 1038 writeUSHORT(out, 0); /* format selector */ 1039 writeUSHORT(out, font->numNames); 1040 writeUSHORT(out, 6 + font->numNames * 12); /* offset to string storage */ 1041 offset = 0; 1042 for(i = 0; i < font->numNames; i++) { 1043 writeUSHORT(out, 3); /* platform id -- Microsoft */ 1044 writeUSHORT(out, 1); /* encoding -- Unicode */ 1045 writeUSHORT(out, 0x409); /* language id -- American English */ 1046 writeUSHORT(out, font->names[i].nid); /* name id */ 1047 writeUSHORT(out, font->names[i].size); /* string length */ 1048 writeUSHORT(out, offset); /* string offset */ 1049 offset += font->names[i].size; 1050 } 1051 for(i = 0; i < font->numNames; i++) 1052 writeCHARs(out, font->names[i].value, font->names[i].size); 1053 return 0; 1054} 1055 1056static int 1057writepost(FILE* out, FontPtr font) 1058{ 1059 int i, rc, previous_width, width, fixed_pitch; 1060 1061 fixed_pitch = 1; 1062 previous_width = -1; 1063 for(i = 0; i < FONT_CODES; i++) { 1064 rc = glyphMetrics(font, i, &width, NULL, NULL, NULL, NULL); 1065 if(rc < 0) 1066 continue; 1067 if(previous_width >= 0) { 1068 if(width != previous_width) { 1069 fixed_pitch = 0; 1070 break; 1071 } 1072 } 1073 previous_width = width; 1074 } 1075 1076 writeULONG(out, 0x00030000); /* FormatType */ 1077 writeULONG(out, font->italicAngle); /* italicAngle */ 1078 writeSHORT(out, FONT_UNITS(font->metrics.underlinePosition)); 1079 writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness)); 1080 writeULONG(out, fixed_pitch); /* isFixedPitch */ 1081 writeULONG(out, 0); /* minMemType42 */ 1082 writeULONG(out, 0); /* maxMemType42 */ 1083 writeULONG(out, 0); /* minMemType1 */ 1084 writeULONG(out, 0); /* maxMemType1 */ 1085 return 0; 1086} 1087 1088static int 1089writeOS2(FILE* out, FontPtr font) 1090{ 1091 int i; 1092 1093 writeUSHORT(out, 5); /* version */ 1094 writeSHORT(out, FONT_UNITS(font->metrics.awidth)); /* xAvgCharWidth; */ 1095 writeUSHORT(out, font->weight); /* usWeightClass; */ 1096 writeUSHORT(out, font->width); /* usWidthClass; */ 1097 writeSHORT(out, 0); /* fsType; */ 1098 writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptXSize; */ 1099 writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptYSize; */ 1100 writeSHORT(out, 0); /* ySubscriptXOffset; */ 1101 writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptYOffset; */ 1102 writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptXSize; */ 1103 writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYSize; */ 1104 writeSHORT(out, 0); /* ySuperscriptXOffset; */ 1105 writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYOffset; */ 1106 writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness)); 1107 /* yStrikeoutSize; */ 1108 writeSHORT(out, UNITS_PER_EM / 4); /* yStrikeoutPosition; */ 1109 writeSHORT(out, 0); /* sFamilyClass; */ 1110 for(i = 0; i < 10; i++) 1111 writeBYTE(out, 0); /* panose; */ 1112 writeULONG(out, 0xFFFF); /* ulUnicodeRange1; */ 1113 writeULONG(out, 0xFFFF); /* ulUnicodeRange2; */ 1114 writeULONG(out, 0x03FF); /* ulUnicodeRange3; */ 1115 writeULONG(out, 0U); /* ulUnicodeRange4; */ 1116 writeULONG(out, font->foundry); /* achVendID[4]; */ 1117 i = 0; 1118 if (font->flags & FACE_ITALIC) 1119 i |= 1 << 0; 1120 if (font->flags & FACE_BOLD) 1121 i |= 1 << 5; 1122 if (!i) 1123 i |= 1 << 6; 1124#ifndef NO_TYPO_METRICS 1125 i |= 1 << 7; /* USE_TYPO_METRICS instead usWin metrics for line spacing. */ 1126#endif 1127 writeUSHORT(out, i); /* fsSelection; */ 1128 writeUSHORT(out, 0x20); /* usFirstCharIndex; */ 1129 writeUSHORT(out, 0xFFFD); /* usLastCharIndex; */ 1130 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* sTypoAscender; */ 1131 writeSHORT(out, -FONT_UNITS_CEIL(font->metrics.descent)); /* sTypoDescender; */ 1132 writeSHORT(out, FONT_UNITS(font->metrics.size - font->metrics.ascent - font->metrics.descent)); /* sTypoLineGap */ 1133#ifdef NO_TYPO_METRICS 1134 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* usWinAscent; */ 1135 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.descent)); /* usWinDescent; */ 1136#else 1137 writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY)); /* usWinAscent; */ 1138 writeUSHORT(out, -FONT_UNITS_FLOOR(font->metrics.minY)); /* usWinDescent; */ 1139#endif 1140 writeULONG(out, 3); /* ulCodePageRange1; */ 1141 writeULONG(out, 0); /* ulCodePageRange2; */ 1142 writeSHORT(out, FONT_UNITS_CEIL(font->metrics.xHeight)); /* sxHeight; */ 1143 writeSHORT(out, FONT_UNITS_CEIL(font->metrics.capHeight)); /* sCapHeight; */ 1144 writeUSHORT(out, 0); /* usDefaultChar; */ 1145 writeUSHORT(out, 20); /* usBreakChar; */ 1146 writeUSHORT(out, 0); /* usMaxContext; */ 1147 writeUSHORT(out, 0); /* usLowerOpticalPointSize; */ 1148 writeUSHORT(out, 0xffff); /* usUpperOpticalPointSize; */ 1149 return 0; 1150} 1151 1152static int 1153writePCLT(FILE* out, FontPtr font) 1154{ 1155 char name[16] = "X11 font "; 1156 char filename[6] = "X11R00"; 1157 unsigned char charComplement[8] = 1158 {0xFF, 0xFF, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF, 0xFE}; 1159 int style, w, strokeWeight, widthType; 1160 1161 style = 0; 1162 if(font->flags & FACE_ITALIC) 1163 style = 1; 1164 1165 w = (font->weight + 50) / 100; 1166 if(w < 5) 1167 strokeWeight = w - 6; 1168 else if(w == 5) 1169 strokeWeight = 0; 1170 else 1171 strokeWeight = w - 4; 1172 1173 if(font->width <= 2) 1174 widthType = -3; 1175 else if(font->width <= 4) 1176 widthType = -2; 1177 else if(font->width <= 6) 1178 widthType = 0; 1179 else if(font->width <= 7) 1180 widthType = 2; 1181 else 1182 widthType = 3; 1183 1184 writeULONG(out, 0x00010000); /* version */ 1185 writeULONG(out, 0); /* FontNumber */ 1186 writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* pitch */ 1187 writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* xHeight */ 1188 writeUSHORT(out, style); /* style */ 1189 writeUSHORT(out, 6 << 12); /* TypeFamily */ 1190 writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* CapHeight */ 1191 writeUSHORT(out, 0); /* SymbolSet */ 1192 writeCHARs(out, name, 16); /* TypeFace */ 1193 writeBYTEs(out, charComplement, 8); /* CharacterComplement */ 1194 writeCHARs(out, filename, 6); /* FileName */ 1195 writeCHAR(out, strokeWeight); /* StrokeWeight */ 1196 writeCHAR(out, widthType); /* WidthType */ 1197 writeCHAR(out, 1 << 6); /* SerifStyle */ 1198 writeCHAR(out, 0); /* Reserved */ 1199 return 0; 1200} 1201