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