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