1 /* Copyright (C) 2003 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: ttfmain.c,v 1.34 2005/08/02 11:12:32 igor Exp $ */ 18 /* A Free Type interface adapter. */ 19 /* Uses code fragments from the FreeType project. */ 20 21 #include "ttmisc.h" 22 #include "ttfoutl.h" 23 #include "ttfmemd.h" 24 25 #include "ttfinp.h" 26 #include "ttfsfnt.h" 27 #include "ttobjs.h" 28 #include "ttinterp.h" 29 #include "ttcalc.h" 30 31 private const bool skip_instructions = 0; /* Debug purpose only. */ 32 33 typedef struct { 34 Fixed a, b, c, d, tx, ty; 35 } FixMatrix; 36 37 struct ttfSubGlyphUsage_s { 38 FixMatrix m; 39 int index; 40 int flags; 41 short arg1, arg2; 42 }; 43 44 /*------------------------------------------------------------------- */ 45 46 private Fixed AVE(F26Dot6 a, F26Dot6 b) 47 { return (a + b) / 2; 48 } 49 50 private F26Dot6 shortToF26Dot6(short a) 51 { return (F26Dot6)a << 6; 52 } 53 54 private F26Dot6 floatToF26Dot6(float a) 55 { return (F26Dot6)(a * (1 << 6) + 0.5); 56 } 57 58 private Fixed floatToF16Dot16(float a) 59 { return (F26Dot6)(a * (1 << 16) + 0.5); 60 } 61 62 private void TransformF26Dot6PointFix(F26Dot6Point *pt, F26Dot6 dx, F26Dot6 dy, FixMatrix *m) 63 { pt->x = MulDiv(dx, m->a, 65536) + MulDiv(dy, m->c, 65536) + (m->tx >> 10); 64 pt->y = MulDiv(dx, m->b, 65536) + MulDiv(dy, m->d, 65536) + (m->ty >> 10); 65 } 66 67 private void TransformF26Dot6PointFloat(FloatPoint *pt, F26Dot6 dx, F26Dot6 dy, FloatMatrix *m) 68 { pt->x = dx * m->a / 64 + dy * m->c / 64 + m->tx; 69 pt->y = dx * m->b / 64 + dy * m->d / 64 + m->ty; 70 } 71 72 /*-------------------------------------------------------------------*/ 73 74 private ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id) 75 { 76 if (!memcmp(id, "cvt ", 4)) 77 return &f->t_cvt_; 78 if (!memcmp(id, "fpgm", 4)) 79 return &f->t_fpgm; 80 if (!memcmp(id, "glyf", 4)) 81 return &f->t_glyf; 82 if (!memcmp(id, "head", 4)) 83 return &f->t_head; 84 if (!memcmp(id, "hhea", 4)) 85 return &f->t_hhea; 86 if (!memcmp(id, "hmtx", 4)) 87 return &f->t_hmtx; 88 if (!memcmp(id, "vhea", 4)) 89 return &f->t_vhea; 90 if (!memcmp(id, "vmtx", 4)) 91 return &f->t_vmtx; 92 if (!memcmp(id, "loca", 4)) 93 return &f->t_loca; 94 if (!memcmp(id, "maxp", 4)) 95 return &f->t_maxp; 96 if (!memcmp(id, "prep", 4)) 97 return &f->t_prep; 98 if (!memcmp(id, "cmap", 4)) 99 return &f->t_cmap; 100 return 0; 101 } 102 103 /*-------------------------------------------------------------------*/ 104 105 TT_Error TT_Set_Instance_CharSizes(TT_Instance instance, 106 TT_F26Dot6 charWidth, 107 TT_F26Dot6 charHeight) 108 { 109 PInstance ins = instance.z; 110 111 if ( !ins ) 112 return TT_Err_Invalid_Instance_Handle; 113 114 if (charWidth < 1*64) 115 charWidth = 1*64; 116 117 if (charHeight < 1*64) 118 charHeight = 1*64; 119 120 ins->metrics.x_scale1 = charWidth; 121 ins->metrics.y_scale1 = charHeight; 122 ins->metrics.x_scale2 = ins->face->font->nUnitsPerEm; 123 ins->metrics.y_scale2 = ins->face->font->nUnitsPerEm; 124 125 if (ins->face->font->nFlags & 8) { 126 ins->metrics.x_scale1 = (ins->metrics.x_scale1+32) & -64; 127 ins->metrics.y_scale1 = (ins->metrics.y_scale1+32) & -64; 128 } 129 130 ins->metrics.x_ppem = ins->metrics.x_scale1 / 64; 131 ins->metrics.y_ppem = ins->metrics.y_scale1 / 64; 132 133 if (charWidth > charHeight) 134 ins->metrics.pointSize = charWidth; 135 else 136 ins->metrics.pointSize = charHeight; 137 138 ins->valid = FALSE; 139 return Instance_Reset(ins, FALSE); 140 } 141 142 /*-------------------------------------------------------------------*/ 143 144 int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti) 145 { 146 ttfInterpreter *tti; 147 148 if (*ptti) { 149 (*ptti)->lock++; 150 return 0; 151 } 152 tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain"); 153 if (!tti) 154 return fMemoryError; 155 tti->usage = 0; 156 tti->usage_size = 0; 157 tti->ttf_memory = mem; 158 tti->lock = 1; 159 tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain"); 160 if (!tti->exec) { 161 mem->free(mem, tti, "ttfInterpreter__obtain"); 162 return fMemoryError; 163 } 164 memset(tti->exec, 0, sizeof(*tti->exec)); 165 *ptti = tti; 166 return 0; 167 } 168 169 void ttfInterpreter__release(ttfInterpreter **ptti) 170 { 171 ttfInterpreter *tti = *ptti; 172 ttfMemory *mem = tti->ttf_memory; 173 174 if(--tti->lock) 175 return; 176 mem->free(mem, tti->usage, "ttfInterpreter__release"); 177 mem->free(mem, tti->exec, "ttfInterpreter__release"); 178 mem->free(mem, *ptti, "ttfInterpreter__release"); 179 mem->free(mem, mem, "ttfInterpreter__release"); 180 *ptti = 0; 181 } 182 183 /*-------------------------------------------------------------------*/ 184 185 void ttfFont__init(ttfFont *this, ttfMemory *mem, 186 void (*DebugRepaint)(ttfFont *), 187 int (*DebugPrint)(ttfFont *, const char *s, ...)) 188 { 189 memset(this, 0, sizeof(*this)); 190 this->DebugRepaint = DebugRepaint; 191 this->DebugPrint = DebugPrint; 192 } 193 194 void ttfFont__finit(ttfFont *this) 195 { ttfMemory *mem = this->tti->ttf_memory; 196 197 if (this->exec) 198 Context_Destroy(this->exec); 199 this->exec = NULL; 200 if (this->inst) 201 Instance_Destroy(this->inst); 202 mem->free(mem, this->inst, "ttfFont__finit"); 203 this->inst = NULL; 204 if (this->face) 205 Face_Destroy(this->face); 206 mem->free(mem, this->face, "ttfFont__finit"); 207 this->face = NULL; 208 } 209 210 #define MAX_SUBGLYPH_NESTING 3 /* Arbitrary. We need this because we don't want 211 a ttfOutliner__BuildGlyphOutline recursion 212 while a glyph is loaded in ttfReader. */ 213 214 FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *this, ttfReader *r, 215 unsigned int nTTC, float w, float h, 216 bool design_grid) 217 { char sVersion[4], sVersion0[4] = {0, 1, 0, 0}; 218 unsigned int nNumTables, i; 219 TT_Error code; 220 int k; 221 TT_Instance I; 222 ttfMemory *mem = tti->ttf_memory; 223 F26Dot6 ww, hh; 224 225 this->tti = tti; 226 this->design_grid = design_grid; 227 r->Read(r, sVersion, 4); 228 if(!memcmp(sVersion, "ttcf", 4)) { 229 unsigned int nFonts; 230 unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */ 231 232 r->Read(r, sVersion, 4); 233 if(memcmp(sVersion, sVersion0, 4)) 234 return fUnimplemented; 235 nFonts = ttfReader__UInt(r); 236 if (nFonts == 0) 237 return fBadFontData; 238 if(nTTC >= nFonts) 239 return fTableNotFound; 240 for(i = 0; i <= nTTC; i++) 241 nPos = ttfReader__UInt(r); 242 r->Seek(r, nPos); 243 r->Read(r, sVersion, 4); 244 } 245 if(memcmp(sVersion, sVersion0, 4) && memcmp(sVersion, "true", 4)) 246 return fUnimplemented; 247 nNumTables = ttfReader__UShort(r); 248 ttfReader__UShort(r); /* nSearchRange */ 249 ttfReader__UShort(r); /* nEntrySelector */ 250 ttfReader__UShort(r); /* nRangeShift */ 251 for (i = 0; i < nNumTables; i++) { 252 char sTag[5]; 253 unsigned int nOffset, nLength; 254 ttfPtrElem *e; 255 256 sTag[4] = 0; 257 r->Read(r, sTag, 4); 258 ttfReader__UInt(r); /* nCheckSum */ 259 nOffset = ttfReader__UInt(r); 260 nLength = ttfReader__UInt(r); 261 e = ttfFont__get_table_ptr(this, sTag); 262 if (e != NULL) { 263 e->nPos = nOffset; 264 e->nLen = nLength; 265 } 266 } 267 r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, flags)); 268 this->nFlags = ttfReader__UShort(r); 269 r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, unitsPerEm)); 270 this->nUnitsPerEm = ttfReader__UShort(r); 271 r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, indexToLocFormat)); 272 this->nIndexToLocFormat = ttfReader__UShort(r); 273 r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, numGlyphs)); 274 this->nNumGlyphs = ttfReader__UShort(r); 275 r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, maxComponentElements)); 276 this->nMaxComponents = ttfReader__UShort(r); 277 if(this->nMaxComponents < 10) 278 this->nMaxComponents = 10; /* work around DynaLab bug in lgoth.ttf */ 279 r->Seek(r, this->t_hhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics)); 280 this->nLongMetricsHorz = ttfReader__UShort(r); 281 if (this->t_vhea.nPos != 0) { 282 r->Seek(r, this->t_vhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics)); 283 this->nLongMetricsVert = ttfReader__UShort(r); 284 } else 285 this->nLongMetricsVert = 0; 286 if (tti->usage_size < this->nMaxComponents * MAX_SUBGLYPH_NESTING) { 287 tti->ttf_memory->free(tti->ttf_memory, tti->usage, "ttfFont__Open"); 288 tti->usage_size = 0; 289 tti->usage = mem->alloc_bytes(mem, 290 sizeof(ttfSubGlyphUsage) * this->nMaxComponents * MAX_SUBGLYPH_NESTING, 291 "ttfFont__Open"); 292 if (tti->usage == NULL) 293 return fMemoryError; 294 tti->usage_size = this->nMaxComponents * MAX_SUBGLYPH_NESTING; 295 } 296 this->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open"); 297 if (this->face == NULL) 298 return fMemoryError; 299 memset(this->face, 0, sizeof(*this->face)); 300 this->face->r = r; 301 this->face->font = this; 302 this->exec = tti->exec; 303 code = Face_Create(this->face); 304 if (code) 305 return fMemoryError; 306 code = r->Error(r); 307 if (code < 0) 308 return fBadFontData; 309 this->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open"); 310 if (this->inst == NULL) 311 return fMemoryError; 312 memset(this->inst, 0, sizeof(*this->inst)); 313 code = Context_Create(this->exec, this->face); /* See comment in the implementation of Context_Create. */ 314 if (code == TT_Err_Out_Of_Memory) 315 return fMemoryError; 316 code = Instance_Create(this->inst, this->face); 317 if (code == TT_Err_Out_Of_Memory) 318 return fMemoryError; 319 if (code) 320 return fBadFontData; 321 for(k = 0; k < this->face->cvtSize; k++) 322 this->inst->cvt[k] = shortToF26Dot6(this->face->cvt[k]); 323 code = Instance_Init(this->inst); 324 if (code == TT_Err_Out_Of_Memory) 325 return fMemoryError; 326 if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement) 327 return fBadInstruction; 328 if (code) 329 return fBadFontData; 330 I.z = this->inst; 331 if (design_grid) 332 ww = hh = shortToF26Dot6(this->nUnitsPerEm); 333 else { 334 /* Round towards zero for a better view of mirrored characters : */ 335 ww = floatToF26Dot6(w); 336 hh = floatToF26Dot6(h); 337 } 338 code = TT_Set_Instance_CharSizes(I, ww, hh); 339 this->inst->metrics = this->exec->metrics; 340 if (code == TT_Err_Invalid_Engine) 341 return fPatented; 342 if (code == TT_Err_Out_Of_Memory) 343 return fMemoryError; 344 if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement) 345 return fBadInstruction; 346 if (code) 347 return fBadFontData; 348 return code; 349 } 350 351 private void ttfFont__StartGlyph(ttfFont *this) 352 { Context_Load( this->exec, this->inst ); 353 if ( this->inst->GS.instruct_control & 2 ) 354 this->exec->GS = Default_GraphicsState; 355 else 356 this->exec->GS = this->inst->GS; 357 this->tti->usage_top = 0; 358 } 359 360 private void ttfFont__StopGlyph(ttfFont *this) 361 { 362 Context_Save(this->exec, this->inst); 363 } 364 365 /*-------------------------------------------------------------------*/ 366 367 private void mount_zone( PGlyph_Zone source, 368 PGlyph_Zone target ) 369 { 370 Int np, nc; 371 372 np = source->n_points; 373 nc = source->n_contours; 374 375 target->org_x = source->org_x + np; 376 target->org_y = source->org_y + np; 377 target->cur_x = source->cur_x + np; 378 target->cur_y = source->cur_y + np; 379 target->touch = source->touch + np; 380 381 target->contours = source->contours + nc; 382 383 target->n_points = 0; 384 target->n_contours = 0; 385 } 386 387 private void Init_Glyph_Component( PSubglyph_Record element, 388 PSubglyph_Record original, 389 PExecution_Context exec ) 390 { 391 element->index = -1; 392 element->is_scaled = FALSE; 393 element->is_hinted = FALSE; 394 395 if (original) 396 mount_zone( &original->zone, &element->zone ); 397 else 398 element->zone = exec->pts; 399 400 element->zone.n_contours = 0; 401 element->zone.n_points = 0; 402 403 element->arg1 = 0; 404 element->arg2 = 0; 405 406 element->element_flag = 0; 407 element->preserve_pps = FALSE; 408 409 element->transform.xx = 1 << 16; 410 element->transform.xy = 0; 411 element->transform.yx = 0; 412 element->transform.yy = 1 << 16; 413 414 element->transform.ox = 0; 415 element->transform.oy = 0; 416 417 element->leftBearing = 0; 418 element->advanceWidth = 0; 419 } 420 421 private void cur_to_org( Int n, PGlyph_Zone zone ) 422 { 423 Int k; 424 425 for ( k = 0; k < n; k++ ) 426 zone->org_x[k] = zone->cur_x[k]; 427 428 for ( k = 0; k < n; k++ ) 429 zone->org_y[k] = zone->cur_y[k]; 430 } 431 432 private void org_to_cur( Int n, PGlyph_Zone zone ) 433 { 434 Int k; 435 436 for ( k = 0; k < n; k++ ) 437 zone->cur_x[k] = zone->org_x[k]; 438 439 for ( k = 0; k < n; k++ ) 440 zone->cur_y[k] = zone->org_y[k]; 441 } 442 443 444 /*-------------------------------------------------------------------*/ 445 446 void ttfOutliner__init(ttfOutliner *this, ttfFont *f, ttfReader *r, ttfExport *exp, 447 bool bOutline, bool bFirst, bool bVertical) 448 { 449 this->r = r; 450 this->bOutline = bOutline; 451 this->bFirst = bFirst; 452 this->pFont = f; 453 this->bVertical = bVertical; 454 this->exp = exp; 455 } 456 457 private void MoveGlyphOutline(TGlyph_Zone *pts, int nOffset, ttfGlyphOutline *out, FixMatrix *m) 458 { F26Dot6* x = pts->org_x + nOffset; 459 F26Dot6* y = pts->org_y + nOffset; 460 short count = out->pointCount; 461 F26Dot6Point p; 462 463 if (m->a == 65536 && m->b == 0 && 464 m->c == 0 && m->d == 65536 && 465 m->tx == 0 && m->ty == 0) 466 return; 467 for (; count != 0; --count) { 468 TransformF26Dot6PointFix(&p, *x, *y, m); 469 *x++ = p.x; 470 *y++ = p.y; 471 } 472 } 473 474 private FontError ttfOutliner__BuildGlyphOutlineAux(ttfOutliner *this, int glyphIndex, 475 FixMatrix *m_orig, ttfGlyphOutline* gOutline) 476 { ttfFont *pFont = this->pFont; 477 ttfReader *r = this->r; 478 ttfInterpreter *tti = pFont->tti; 479 short sideBearing; 480 FontError error = fNoError; 481 short arg1, arg2; 482 short count; 483 unsigned int nMtxPos, nMtxGlyph = glyphIndex, nLongMetrics, i; 484 unsigned short nAdvance; 485 unsigned int nNextGlyphPtr = 0; 486 unsigned int nPosBeg; 487 TExecution_Context *exec = pFont->exec; 488 TGlyph_Zone *pts = &exec->pts; 489 TSubglyph_Record subglyph; 490 ttfSubGlyphUsage *usage = tti->usage + tti->usage_top; 491 const byte *glyph = NULL; 492 int glyph_size; 493 494 if(this->bVertical && pFont->t_vhea.nPos && pFont->t_vmtx.nPos) { 495 nLongMetrics = pFont->nLongMetricsVert; 496 nMtxPos = pFont->t_vmtx.nPos; 497 } else { 498 nLongMetrics = pFont->nLongMetricsHorz; 499 nMtxPos = pFont->t_hmtx.nPos; 500 } 501 if (this->bVertical && (!pFont->t_vhea.nPos || pFont->t_vmtx.nPos) && nMtxGlyph < nLongMetrics) { 502 /* A bad font fix. */ 503 nMtxGlyph = nLongMetrics; 504 if(nMtxGlyph >= pFont->nNumGlyphs) 505 nMtxGlyph = pFont->nNumGlyphs - 1; 506 } 507 if (nMtxGlyph < nLongMetrics) { 508 r->Seek(r, nMtxPos + 4 * nMtxGlyph); 509 nAdvance = ttfReader__Short(r); 510 sideBearing = ttfReader__Short(r); 511 } else { 512 r->Seek(r, nMtxPos + 4 * (nLongMetrics - 1)); 513 nAdvance = ttfReader__Short(r); 514 r->Seek(r, nMtxPos + 4 * nLongMetrics + 2 * (nMtxGlyph - nLongMetrics)); 515 sideBearing = ttfReader__Short(r); 516 } 517 if (r->Error(r)) 518 goto errex; 519 gOutline->sideBearing = shortToF26Dot6(sideBearing); 520 gOutline->advance.x = shortToF26Dot6(nAdvance); 521 gOutline->advance.y = 0; 522 this->bFirst = FALSE; 523 524 525 if (!this->bOutline) 526 return fNoError; 527 if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size)) 528 return fGlyphNotFound; 529 if (r->Eof(r)) { 530 r->ReleaseGlyph(r, glyphIndex); 531 gOutline->xMinB = gOutline->yMinB = 0; 532 gOutline->xMaxB = gOutline->yMaxB = 0; 533 return fNoError; 534 } 535 if (r->Error(r)) 536 goto errex; 537 nPosBeg = r->Tell(r); 538 539 gOutline->contourCount = ttfReader__Short(r); 540 subglyph.bbox.xMin = ttfReader__Short(r); 541 subglyph.bbox.yMin = ttfReader__Short(r); 542 subglyph.bbox.xMax = ttfReader__Short(r); 543 subglyph.bbox.yMax = ttfReader__Short(r); 544 545 gOutline->xMinB = subglyph.bbox.xMin; 546 gOutline->yMinB = subglyph.bbox.yMin; 547 gOutline->xMaxB = subglyph.bbox.xMax; 548 gOutline->yMaxB = subglyph.bbox.yMax; 549 550 /* FreeType stuff beg */ 551 Init_Glyph_Component(&subglyph, NULL, pFont->exec); 552 subglyph.leftBearing = sideBearing; 553 subglyph.advanceWidth = nAdvance; 554 subglyph.pp1.x = subglyph.bbox.xMin - sideBearing; 555 subglyph.pp1.y = 0; 556 subglyph.pp2.x = subglyph.pp1.x + nAdvance; 557 subglyph.pp2.y = 0; 558 /* FreeType stuff end */ 559 560 if (gOutline->contourCount == 0) 561 gOutline->pointCount = 0; 562 else if (gOutline->contourCount == -1) { 563 unsigned short flags, index, bHaveInstructions = 0; 564 unsigned int nUsage = 0; 565 unsigned int nPos; 566 unsigned int n_ins; 567 568 gOutline->bCompound = TRUE; 569 if (tti->usage_top + pFont->nMaxComponents > tti->usage_size) 570 return fBadFontData; 571 gOutline->contourCount = gOutline->pointCount = 0; 572 do { 573 FixMatrix m; 574 ttfSubGlyphUsage *e; 575 576 if (nUsage >= pFont->nMaxComponents) { 577 error = fMemoryError; goto ex; 578 } 579 flags = ttfReader__UShort(r); 580 index = ttfReader__UShort(r); 581 bHaveInstructions |= (flags & WE_HAVE_INSTRUCTIONS); 582 if (flags & ARG_1_AND_2_ARE_WORDS) { 583 arg1 = ttfReader__Short(r); 584 arg2 = ttfReader__Short(r); 585 } else { 586 if (flags & ARGS_ARE_XY_VALUES) { 587 /* offsets are signed */ 588 arg1 = ttfReader__SignedByte(r); 589 arg2 = ttfReader__SignedByte(r); 590 } else { /* anchor points are unsigned */ 591 arg1 = ttfReader__Byte(r); 592 arg2 = ttfReader__Byte(r); 593 } 594 } 595 m.b = m.c = m.tx = m.ty = 0; 596 if (flags & WE_HAVE_A_SCALE) 597 m.a = m.d = (Fixed)ttfReader__Short(r) << 2; 598 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { 599 m.a = (Fixed)ttfReader__Short(r) << 2; 600 m.d = (Fixed)ttfReader__Short(r) << 2; 601 } else if (flags & WE_HAVE_A_TWO_BY_TWO) { 602 m.a = (Fixed)ttfReader__Short(r)<<2; 603 m.b = (Fixed)ttfReader__Short(r)<<2; 604 m.c = (Fixed)ttfReader__Short(r)<<2; 605 m.d = (Fixed)ttfReader__Short(r)<<2; 606 } else 607 m.a = m.d = 65536; 608 e = &usage[nUsage]; 609 e->m = m; 610 e->index = index; 611 e->arg1 = arg1; 612 e->arg2 = arg2; 613 e->flags = flags; 614 nUsage++; 615 } while (flags & MORE_COMPONENTS); 616 /* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */ 617 if (r->Error(r)) 618 goto errex; 619 nPos = r->Tell(r); 620 n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0); 621 nPos = r->Tell(r); 622 r->ReleaseGlyph(r, glyphIndex); 623 glyph = NULL; 624 for (i = 0; i < nUsage; i++) { 625 ttfGlyphOutline out; 626 ttfSubGlyphUsage *e = &usage[i]; 627 int j; 628 TT_Error code; 629 int nPointsStored = this->nPointsTotal, nContoursStored = this->nContoursTotal; 630 631 out.contourCount = 0; 632 out.pointCount = 0; 633 out.bCompound = FALSE; 634 pts->org_x += nPointsStored; 635 pts->org_y += nPointsStored; 636 pts->cur_x += nPointsStored; 637 pts->cur_y += nPointsStored; 638 pts->touch += nPointsStored; 639 pts->contours += nContoursStored; 640 tti->usage_top += nUsage; 641 code = ttfOutliner__BuildGlyphOutlineAux(this, e->index, m_orig, &out); 642 pts->org_x -= nPointsStored; 643 pts->org_y -= nPointsStored; 644 pts->cur_x -= nPointsStored; 645 pts->cur_y -= nPointsStored; 646 pts->touch -= nPointsStored; 647 tti->usage_top -= nUsage; 648 pts->contours -= nContoursStored; 649 if (code == fPatented) 650 error = code; 651 else if (code != fNoError) { 652 error = code; 653 goto ex; 654 } 655 if (flags & ARGS_ARE_XY_VALUES) { 656 e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10; 657 e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10; 658 } else { 659 e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10; 660 e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10; 661 } 662 MoveGlyphOutline(pts, nPointsStored, &out, &e->m); 663 for (j = nContoursStored; j < out.contourCount + nContoursStored; j++) 664 pts->contours[j] += nPointsStored; 665 gOutline->contourCount += out.contourCount; 666 gOutline->pointCount += out.pointCount; 667 if(e->flags & USE_MY_METRICS) { 668 gOutline->advance.x = out.advance.x; 669 gOutline->sideBearing = out.sideBearing; 670 } 671 } 672 if (!skip_instructions && n_ins && 673 !(pFont->inst->GS.instruct_control & 1)) { 674 TT_Error code; 675 676 r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size); 677 if (r->Error(r)) 678 goto errex; 679 if (nPos + n_ins > glyph_size) 680 goto errex; 681 code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins); 682 if (!code) { 683 int nPoints = gOutline->pointCount + 2; 684 int k; 685 F26Dot6 x; 686 687 exec->pts = subglyph.zone; 688 pts->n_points = nPoints; 689 pts->n_contours = gOutline->contourCount; 690 /* add phantom points : */ 691 pts->org_x[nPoints - 2] = Scale_X(&exec->metrics, subglyph.pp1.x); 692 pts->org_y[nPoints - 2] = Scale_Y(&exec->metrics, subglyph.pp1.y); 693 pts->org_x[nPoints - 1] = Scale_X(&exec->metrics, subglyph.pp2.x); 694 pts->org_y[nPoints - 1] = Scale_Y(&exec->metrics, subglyph.pp2.y); 695 pts->touch[nPoints - 1] = 0; 696 pts->touch[nPoints - 2] = 0; 697 /* if hinting, round the phantom points (not sure) : */ 698 x = pts->org_x[nPoints - 2]; 699 x = ((x + 32) & -64) - x; 700 if (x) 701 for (k = 0; k < nPoints; k++) 702 pts->org_x[k] += x; 703 pts->cur_x[nPoints - 1] = (pts->cur_x[nPoints - 1] + 32) & -64; 704 for (k = 0; k < nPoints; k++) 705 pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve; 706 org_to_cur(nPoints, pts); 707 exec->is_composite = TRUE; 708 if (pFont->patented) 709 code = TT_Err_Invalid_Engine; 710 else 711 code = Context_Run(exec, FALSE); 712 if (!code) 713 cur_to_org(nPoints, pts); 714 else if (code == TT_Err_Invalid_Engine) 715 error = fPatented; 716 else 717 error = fBadFontData; 718 } 719 Unset_CodeRange(exec); 720 Clear_CodeRange(exec, TT_CodeRange_Glyph); 721 } 722 } else if (gOutline->contourCount > 0) { 723 uint16 i; 724 int nPoints; 725 bool bInsOK; 726 byte *onCurve, *stop, flag; 727 short *endPoints; 728 unsigned int nPos; 729 unsigned int n_ins; 730 731 if (this->nContoursTotal + gOutline->contourCount > exec->n_contours) { 732 error = fBadFontData; goto ex; 733 } 734 endPoints = pts->contours; 735 for (i = 0; i < gOutline->contourCount; i++) 736 endPoints[i] = ttfReader__Short(r); 737 for (i = 1; i < gOutline->contourCount; i++) 738 if (endPoints[i - 1] >= endPoints[i]) { 739 error = fBadFontData; goto ex; 740 } 741 nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1; 742 if (this->nPointsTotal + nPoints + 2 > exec->n_points) { 743 error = fBadFontData; goto ex; 744 } 745 n_ins = ttfReader__Short(r); 746 nPos = r->Tell(r); 747 r->Seek(r, nPos + n_ins); 748 if (r->Error(r)) 749 goto errex; 750 bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins); 751 onCurve = pts->touch; 752 stop = onCurve + gOutline->pointCount; 753 754 while (onCurve < stop) { 755 *onCurve++ = flag = ttfReader__Byte(r); 756 if (flag & REPEAT_FLAGS) { 757 count = ttfReader__Byte(r); 758 for (--count; count >= 0; --count) 759 *onCurve++ = flag; 760 } 761 } 762 /* Lets do X */ 763 { short coord = (this->bVertical ? 0 : sideBearing - subglyph.bbox.xMin); 764 F26Dot6* x = pts->org_x; 765 onCurve = pts->touch; 766 while (onCurve < stop) { 767 if ((flag = *onCurve++) & XSHORT) { 768 if (flag & SHORT_X_IS_POS) 769 coord += ttfReader__Byte(r); 770 else 771 coord -= ttfReader__Byte(r); 772 } else if (!(flag & NEXT_X_IS_ZERO)) 773 coord += ttfReader__Short(r); 774 *x++ = Scale_X(&exec->metrics, coord); 775 } 776 } 777 /* Lets do Y */ 778 { short coord = 0; 779 F26Dot6* y = pts->org_y; 780 onCurve = pts->touch; 781 while (onCurve < stop) { 782 if((flag = *onCurve) & YSHORT) 783 if ( flag & SHORT_Y_IS_POS ) 784 coord += ttfReader__Byte(r); 785 else 786 coord -= ttfReader__Byte(r); 787 else if(!(flag & NEXT_Y_IS_ZERO)) 788 coord += ttfReader__Short(r); 789 *y++ = Scale_Y( &exec->metrics, coord ); 790 791 /* Filter off the extra bits */ 792 *onCurve++ = flag & ONCURVE; 793 } 794 } 795 MoveGlyphOutline(pts, 0, gOutline, m_orig); 796 this->nContoursTotal += gOutline->contourCount; 797 this->nPointsTotal += nPoints; 798 if (!skip_instructions && 799 !r->Error(r) && n_ins && bInsOK && !(pFont->inst->GS.instruct_control & 1)) { 800 TGlyph_Zone *pts = &exec->pts; 801 int k; 802 F26Dot6 x; 803 TT_Error code; 804 805 exec->is_composite = FALSE; 806 /* add phantom points : */ 807 pts->org_x[nPoints ] = Scale_X(&exec->metrics, subglyph.pp1.x); 808 pts->org_y[nPoints ] = Scale_Y(&exec->metrics, subglyph.pp1.y); 809 pts->org_x[nPoints + 1] = Scale_X(&exec->metrics, subglyph.pp2.x); 810 pts->org_y[nPoints + 1] = Scale_Y(&exec->metrics, subglyph.pp2.y); 811 pts->touch[nPoints ] = 0; 812 pts->touch[nPoints + 1] = 0; 813 pts->n_points = nPoints + 2; 814 pts->n_contours = gOutline->contourCount; 815 /* if hinting, round the phantom points (not sure) : */ 816 x = pts->org_x[nPoints]; 817 x = ((x + 32) & -64) - x; 818 if (x) 819 for (k = 0; k < nPoints + 2; k++) 820 pts->org_x[k] += x; 821 pts->cur_x[nPoints + 1] = (pts->cur_x[nPoints + 1] + 32) & -64; 822 org_to_cur(nPoints + 2, pts); 823 exec->is_composite = FALSE; 824 for (k = 0; k < nPoints + 2; k++) 825 pts->touch[k] &= TT_Flag_On_Curve; 826 if (pFont->patented) 827 code = TT_Err_Invalid_Engine; 828 else 829 code = Context_Run(exec, FALSE ); 830 if (!code) 831 cur_to_org(nPoints + 2, pts); 832 else if (code == TT_Err_Invalid_Engine) 833 error = fPatented; 834 else 835 error = fBadInstruction; 836 gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x; 837 gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x; 838 } 839 Unset_CodeRange(exec); 840 Clear_CodeRange(exec, TT_CodeRange_Glyph); 841 } else 842 error = fBadFontData; 843 goto ex; 844 errex:; 845 error = fBadFontData; 846 ex:; 847 r->ReleaseGlyph(r, glyphIndex); 848 return error; 849 } 850 851 private FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *this, int glyphIndex, 852 float orig_x, float orig_y, ttfGlyphOutline* gOutline) 853 { 854 FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0}; 855 856 /* Round towards zero like old character coordinate conversions do. */ 857 m_orig.tx = floatToF16Dot16(orig_x); 858 m_orig.ty = floatToF16Dot16(orig_y); 859 return ttfOutliner__BuildGlyphOutlineAux(this, glyphIndex, &m_orig, gOutline); 860 } 861 862 863 #define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */ 864 865 void ttfOutliner__DrawGlyphOutline(ttfOutliner *this) 866 { ttfGlyphOutline* out = &this->out; 867 FloatMatrix *m = &this->post_transform; 868 ttfFont *pFont = this->pFont; 869 ttfExport *exp = this->exp; 870 TExecution_Context *exec = pFont->exec; 871 TGlyph_Zone *pts = &exec->pts; 872 short* endP = pts->contours; 873 byte* onCurve = pts->touch; 874 F26Dot6* x = pts->org_x; 875 F26Dot6* y = pts->org_y; 876 F26Dot6 px, py; 877 short sp, ctr; 878 FloatPoint p0, p1, p2, p3; 879 880 # if AVECTOR_BUG 881 short xMinB = out->xMinB >> 6, xMaxB=out->xMaxB >> 6; 882 short yMinB = out->yMinB >> 6, yMaxB=out->yMaxB >> 6; 883 short expand=pFont->nUnitsPerEm*2; 884 F26Dot6 xMin, xMax, yMin, yMax; 885 886 xMinB -= expand; 887 yMinB -= expand; 888 xMaxB += expand; 889 yMaxB += expand; 890 xMin = Scale_X(&exec->metrics, xMinB); 891 xMax = Scale_X(&exec->metrics, xMaxB); 892 yMin = Scale_X(&exec->metrics, yMinB); 893 yMax = Scale_X(&exec->metrics, yMaxB); 894 # endif 895 896 TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m); 897 p1.x -= this->post_transform.tx; 898 p1.y -= this->post_transform.ty; 899 exp->SetWidth(exp, &p1); 900 sp = -1; 901 for (ctr = out->contourCount; ctr != 0; --ctr) { 902 short pt, pts = *endP - sp; 903 short ep = pts - 1; 904 905 if (pts < 3) { 906 x += pts; 907 y += pts; 908 onCurve += pts; 909 sp = *endP++; 910 continue; /* skip 1 and 2 point contours */ 911 } 912 913 if (exp->bPoints) { 914 for (pt = 0; pt <= ep; pt++) { 915 px = x[pt], py = y[pt]; 916 # if AVECTOR_BUG 917 if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) { 918 short prevIndex = pt == 0 ? ep : pt - 1; 919 short nextIndex = pt == ep ? 0 : pt + 1; 920 if (nextIndex > ep) 921 nextIndex = 0; 922 px=AVE(x[prevIndex], x[nextIndex]); 923 py=AVE(y[prevIndex], y[nextIndex]); 924 } 925 # endif 926 TransformF26Dot6PointFloat(&p0, px, py, m); 927 exp->Point(exp, &p0, onCurve[pt], !pt); 928 } 929 } 930 931 if (exp->bOutline) { 932 pt = 0; 933 if(onCurve[ep] & 1) { 934 px = x[ep]; 935 py = y[ep]; 936 } else if (onCurve[0] & 1) { 937 px = x[0]; 938 py = y[0]; 939 pt = 1; 940 } else { 941 px = AVE(x[0], x[ep]); 942 py = AVE(y[0], y[ep]); 943 } 944 this->ppx = px; this->ppy = py; 945 TransformF26Dot6PointFloat(&p0, px, py, m); 946 exp->MoveTo(exp, &p0); 947 948 for (; pt <= ep; pt++) { 949 short prevIndex = pt == 0 ? ep : pt - 1; 950 short nextIndex = pt == ep ? 0 : pt + 1; 951 if (onCurve[pt] & 1) { 952 if (onCurve[prevIndex] & 1) { 953 px = x[pt]; 954 py = y[pt]; 955 if (this->ppx != px || this->ppy != py) { 956 TransformF26Dot6PointFloat(&p1, px, py, m); 957 exp->LineTo(exp, &p1); 958 this->ppx = px; this->ppy = py; 959 p0 = p1; 960 } 961 } 962 } else { 963 F26Dot6 prevX, prevY, nextX, nextY; 964 965 px = x[pt]; 966 py = y[pt]; 967 # if AVECTOR_BUG 968 if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) { 969 px=AVE(x[prevIndex], x[nextIndex]); 970 py=AVE(y[prevIndex], y[nextIndex]); 971 } 972 # endif 973 if (onCurve[prevIndex] & 1) { 974 prevX = x[prevIndex]; 975 prevY = y[prevIndex]; 976 } else { 977 prevX = AVE(x[prevIndex], px); 978 prevY = AVE(y[prevIndex], py); 979 } 980 if (onCurve[nextIndex] & 1) { 981 nextX = x[nextIndex]; 982 nextY = y[nextIndex]; 983 } else { 984 nextX = AVE(px, x[nextIndex]); 985 nextY = AVE(py, y[nextIndex]); 986 } 987 if (this->ppx != nextX || this->ppy != nextY) { 988 double dx1, dy1, dx2, dy2, dx3, dy3; 989 const double prec = 1e-6; 990 991 TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m); 992 TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m); 993 TransformF26Dot6PointFloat(&p3, nextX, nextY, m); 994 dx1 = p1.x - p0.x, dy1 = p1.y - p0.y; 995 dx2 = p2.x - p0.x, dy2 = p2.y - p0.y; 996 dx3 = p3.x - p0.x, dy3 = p3.y - p0.y; 997 if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) || 998 fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3)) 999 exp->CurveTo(exp, &p1, &p2, &p3); 1000 else 1001 exp->LineTo(exp, &p3); 1002 this->ppx = nextX; this->ppy = nextY; 1003 p0 = p3; 1004 } 1005 } 1006 } 1007 exp->Close(exp); 1008 } 1009 x += pts; 1010 y += pts; 1011 onCurve += pts; 1012 sp = *endP++; 1013 } 1014 } 1015 1016 FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex, 1017 float orig_x, float orig_y, FloatMatrix *m1) 1018 { ttfFont *pFont = this->pFont; 1019 FontError error; 1020 1021 this->post_transform = *m1; 1022 this->out.contourCount = 0; 1023 this->out.pointCount = 0; 1024 this->out.bCompound = FALSE; 1025 this->nPointsTotal = 0; 1026 this->nContoursTotal = 0; 1027 this->out.advance.x = this->out.advance.y = 0; 1028 ttfFont__StartGlyph(pFont); 1029 error = ttfOutliner__BuildGlyphOutline(this, glyphIndex, orig_x, orig_y, &this->out); 1030 ttfFont__StopGlyph(pFont); 1031 if (pFont->nUnitsPerEm <= 0) 1032 pFont->nUnitsPerEm = 1024; 1033 if (pFont->design_grid) { 1034 this->post_transform.a /= pFont->nUnitsPerEm; 1035 this->post_transform.b /= pFont->nUnitsPerEm; 1036 this->post_transform.c /= pFont->nUnitsPerEm; 1037 this->post_transform.d /= pFont->nUnitsPerEm; 1038 } 1039 if (error != fNoError && error != fPatented) 1040 return error; 1041 return error; 1042 } 1043