| 1 | /***************************************************************************/ |
| 2 | /* */ |
| 3 | /* ttgload.c */ |
| 4 | /* */ |
| 5 | /* TrueType Glyph Loader (body). */ |
| 6 | /* */ |
| 7 | /* Copyright 1996-2000 by */ |
| 8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
| 9 | /* */ |
| 10 | /* This file is part of the FreeType project, and may only be used, */ |
| 11 | /* modified, and distributed under the terms of the FreeType project */ |
| 12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
| 13 | /* this file you indicate that you have read the license and */ |
| 14 | /* understand and accept it fully. */ |
| 15 | /* */ |
| 16 | /***************************************************************************/ |
| 17 | |
| 18 | |
| 19 | #include <freetype/internal/ftdebug.h> |
| 20 | #include <freetype/internal/ftcalc.h> |
| 21 | #include <freetype/internal/ftstream.h> |
| 22 | #include <freetype/internal/sfnt.h> |
| 23 | #include <freetype/tttags.h> |
| 24 | #include <freetype/ftoutln.h> |
| 25 | |
| 26 | |
| 27 | #ifdef FT_FLAT_COMPILE |
| 28 | |
| 29 | #include "ttgload.h" |
| 30 | |
| 31 | #else |
| 32 | |
| 33 | #include <truetype/ttgload.h> |
| 34 | |
| 35 | #endif |
| 36 | |
| 37 | |
| 38 | /*************************************************************************/ |
| 39 | /* */ |
| 40 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
| 41 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
| 42 | /* messages during execution. */ |
| 43 | /* */ |
| 44 | #undef FT_COMPONENT |
| 45 | #define FT_COMPONENT trace_ttgload |
| 46 | |
| 47 | |
| 48 | /*************************************************************************/ |
| 49 | /* */ |
| 50 | /* Composite font flags. */ |
| 51 | /* */ |
| 52 | #define ARGS_ARE_WORDS 0x001 |
| 53 | #define ARGS_ARE_XY_VALUES 0x002 |
| 54 | #define ROUND_XY_TO_GRID 0x004 |
| 55 | #define WE_HAVE_A_SCALE 0x008 |
| 56 | /* reserved 0x010 */ |
| 57 | #define MORE_COMPONENTS 0x020 |
| 58 | #define WE_HAVE_AN_XY_SCALE 0x040 |
| 59 | #define WE_HAVE_A_2X2 0x080 |
| 60 | #define WE_HAVE_INSTR 0x100 |
| 61 | #define USE_MY_METRICS 0x200 |
| 62 | |
| 63 | |
| 64 | |
| 65 | /*************************************************************************/ |
| 66 | /* */ |
| 67 | /* <Function> */ |
| 68 | /* TT_Get_Metrics */ |
| 69 | /* */ |
| 70 | /* <Description> */ |
| 71 | /* Returns the horizontal or vertical metrics in font units for a */ |
| 72 | /* given glyph. The metrics are the left side bearing (resp. top */ |
| 73 | /* side bearing) and advance width (resp. advance height). */ |
| 74 | /* */ |
| 75 | /* <Input> */ |
| 76 | /* header :: A pointer to either the horizontal or vertical metrics */ |
| 77 | /* structure. */ |
| 78 | /* */ |
| 79 | /* index :: The glyph index. */ |
| 80 | /* */ |
| 81 | /* <Output> */ |
| 82 | /* bearing :: The bearing, either left side or top side. */ |
| 83 | /* */ |
| 84 | /* advance :: The advance width resp. advance height. */ |
| 85 | /* */ |
| 86 | /* <Note> */ |
| 87 | /* This function will much probably move to another component in the */ |
| 88 | /* near future, but I haven't decided which yet. */ |
| 89 | /* */ |
| 90 | LOCAL_FUNC |
| 91 | void TT_Get_Metrics( TT_HoriHeader* header, |
| 92 | FT_UInt index, |
| 93 | FT_Short* bearing, |
| 94 | FT_UShort* advance ) |
| 95 | { |
| 96 | TT_LongMetrics* longs_m; |
| 97 | FT_UShort k = header->number_Of_HMetrics; |
| 98 | |
| 99 | |
| 100 | if ( index < k ) |
| 101 | { |
| 102 | longs_m = (TT_LongMetrics*)header->long_metrics + index; |
| 103 | *bearing = longs_m->bearing; |
| 104 | *advance = longs_m->advance; |
| 105 | } |
| 106 | else |
| 107 | { |
| 108 | *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k]; |
| 109 | *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | |
| 114 | /*************************************************************************/ |
| 115 | /* */ |
| 116 | /* Returns the horizontal metrics in font units for a given glyph. If */ |
| 117 | /* `check' is true, take care of monospaced fonts by returning the */ |
| 118 | /* advance width maximum. */ |
| 119 | /* */ |
| 120 | static |
| 121 | void Get_HMetrics( TT_Face face, |
| 122 | FT_UInt index, |
| 123 | FT_Bool check, |
| 124 | FT_Short* lsb, |
| 125 | FT_UShort* aw ) |
| 126 | { |
| 127 | TT_Get_Metrics( &face->horizontal, index, lsb, aw ); |
| 128 | |
| 129 | if ( check && face->postscript.isFixedPitch ) |
| 130 | *aw = face->horizontal.advance_Width_Max; |
| 131 | } |
| 132 | |
| 133 | |
| 134 | /*************************************************************************/ |
| 135 | /* */ |
| 136 | /* Returns the advance width table for a given pixel size if it is */ |
| 137 | /* found in the font's `hdmx' table (if any). */ |
| 138 | /* */ |
| 139 | static |
| 140 | FT_Byte* Get_Advance_Widths( TT_Face face, |
| 141 | FT_UShort ppem ) |
| 142 | { |
| 143 | FT_UShort n; |
| 144 | |
| 145 | for ( n = 0; n < face->hdmx.num_records; n++ ) |
| 146 | if ( face->hdmx.records[n].ppem == ppem ) |
| 147 | return face->hdmx.records[n].widths; |
| 148 | |
| 149 | return NULL; |
| 150 | } |
| 151 | |
| 152 | |
| 153 | #define cur_to_org( n, zone ) \ |
| 154 | MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( FT_Vector ) ) |
| 155 | |
| 156 | #define org_to_cur( n, zone ) \ |
| 157 | MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( FT_Vector ) ) |
| 158 | |
| 159 | |
| 160 | /*************************************************************************/ |
| 161 | /* */ |
| 162 | /* Translates an array of coordinates. */ |
| 163 | /* */ |
| 164 | static |
| 165 | void translate_array( FT_UInt n, |
| 166 | FT_Vector* coords, |
| 167 | FT_Pos delta_x, |
| 168 | FT_Pos delta_y ) |
| 169 | { |
| 170 | FT_UInt k; |
| 171 | |
| 172 | |
| 173 | if ( delta_x ) |
| 174 | for ( k = 0; k < n; k++ ) |
| 175 | coords[k].x += delta_x; |
| 176 | |
| 177 | if ( delta_y ) |
| 178 | for ( k = 0; k < n; k++ ) |
| 179 | coords[k].y += delta_y; |
| 180 | } |
| 181 | |
| 182 | |
| 183 | static |
| 184 | void tt_prepare_zone( TT_GlyphZone* zone, |
| 185 | FT_GlyphLoad* load, |
| 186 | FT_UInt start_point, |
| 187 | FT_UInt start_contour ) |
| 188 | { |
| 189 | zone->n_points = load->outline.n_points - start_point; |
| 190 | zone->n_contours = load->outline.n_contours - start_contour; |
| 191 | zone->org = load->extra_points + start_point; |
| 192 | zone->cur = load->outline.points + start_point; |
| 193 | zone->tags = (FT_Byte*)load->outline.tags + start_point; |
| 194 | zone->contours = (FT_UShort*)load->outline.contours + start_contour; |
| 195 | } |
| 196 | |
| 197 | |
| 198 | #undef IS_HINTED |
| 199 | #define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) |
| 200 | |
| 201 | |
| 202 | /*************************************************************************/ |
| 203 | /* */ |
| 204 | /* The following functions are used by default with TrueType fonts. */ |
| 205 | /* However, they can be replaced by alternatives if we need to support */ |
| 206 | /* TrueType-compressed formats (like MicroType) in the future. */ |
| 207 | /* */ |
| 208 | /*************************************************************************/ |
| 209 | |
| 210 | static |
| 211 | FT_Error TT_Access_Glyph_Frame( TT_Loader* loader, |
| 212 | FT_UInt glyph_index, |
| 213 | FT_ULong offset, |
| 214 | FT_UInt byte_count ) |
| 215 | { |
| 216 | FT_Error error; |
| 217 | FT_Stream stream = loader->stream; |
| 218 | |
| 219 | |
| 220 | /* the following line sets the `error' variable through macros! */ |
| 221 | (void)( FILE_Seek( offset ) || ACCESS_Frame( byte_count ) ); |
| 222 | |
| 223 | FT_TRACE5(( "Glyph %ld\n", glyph_index )); |
| 224 | return error; |
| 225 | } |
| 226 | |
| 227 | |
| 228 | static |
| 229 | void TT_Forget_Glyph_Frame( TT_Loader* loader ) |
| 230 | { |
| 231 | FT_Stream stream = loader->stream; |
| 232 | |
| 233 | |
| 234 | FORGET_Frame(); |
| 235 | } |
| 236 | |
| 237 | |
| 238 | static |
| 239 | FT_Error TT_Load_Glyph_Header( TT_Loader* loader ) |
| 240 | { |
| 241 | FT_Stream stream = loader->stream; |
| 242 | |
| 243 | |
| 244 | loader->n_contours = GET_Short(); |
| 245 | |
| 246 | loader->bbox.xMin = GET_Short(); |
| 247 | loader->bbox.yMin = GET_Short(); |
| 248 | loader->bbox.xMax = GET_Short(); |
| 249 | loader->bbox.yMax = GET_Short(); |
| 250 | |
| 251 | FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); |
| 252 | FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, |
| 253 | loader->bbox.xMax )); |
| 254 | FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, |
| 255 | loader->bbox.yMax )); |
| 256 | |
| 257 | return FT_Err_Ok; |
| 258 | } |
| 259 | |
| 260 | |
| 261 | static |
| 262 | FT_Error TT_Load_Simple_Glyph( TT_Loader* load ) |
| 263 | { |
| 264 | FT_Error error; |
| 265 | FT_Stream stream = load->stream; |
| 266 | FT_GlyphLoader* gloader = load->gloader; |
| 267 | FT_Int n_contours = load->n_contours; |
| 268 | FT_Outline* outline; |
| 269 | TT_Face face = (TT_Face)load->face; |
| 270 | TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph; |
| 271 | FT_UShort n_ins; |
| 272 | FT_Int n, n_points; |
| 273 | |
| 274 | |
| 275 | /* reading the contours endpoints & number of points */ |
| 276 | { |
| 277 | short* cur = gloader->current.outline.contours; |
| 278 | short* limit = cur + n_contours; |
| 279 | |
| 280 | |
| 281 | for ( ; cur < limit; cur++ ) |
| 282 | cur[0] = GET_UShort(); |
| 283 | |
| 284 | n_points = 0; |
| 285 | if ( n_contours > 0 ) |
| 286 | n_points = cur[-1] + 1; |
| 287 | |
| 288 | error = FT_GlyphLoader_Check_Points( gloader, n_points + 2, 0 ); |
| 289 | if ( error ) |
| 290 | goto Fail; |
| 291 | |
| 292 | outline = &gloader->current.outline; |
| 293 | } |
| 294 | |
| 295 | /* reading the bytecode instructions */ |
| 296 | slot->control_len = 0; |
| 297 | slot->control_data = 0; |
| 298 | |
| 299 | n_ins = GET_UShort(); |
| 300 | |
| 301 | FT_TRACE5(( " Instructions size: %d\n", n_ins )); |
| 302 | |
| 303 | if ( n_ins > face->max_profile.maxSizeOfInstructions ) |
| 304 | { |
| 305 | FT_TRACE0(( "ERROR: Too many instructions!\n" )); |
| 306 | error = TT_Err_Too_Many_Ins; |
| 307 | goto Fail; |
| 308 | } |
| 309 | |
| 310 | if ( stream->cursor + n_ins > stream->limit ) |
| 311 | { |
| 312 | FT_TRACE0(( "ERROR: Instruction count mismatch!\n" )); |
| 313 | error = TT_Err_Too_Many_Ins; |
| 314 | goto Fail; |
| 315 | } |
| 316 | |
| 317 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 318 | |
| 319 | if ( ( load->load_flags & |
| 320 | ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 && |
| 321 | load->instructions ) |
| 322 | { |
| 323 | slot->control_len = n_ins; |
| 324 | slot->control_data = load->instructions; |
| 325 | |
| 326 | MEM_Copy( load->instructions, stream->cursor, n_ins ); |
| 327 | } |
| 328 | |
| 329 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 330 | |
| 331 | stream->cursor += n_ins; |
| 332 | |
| 333 | /* reading the point tags */ |
| 334 | |
| 335 | { |
| 336 | FT_Byte* flag = (FT_Byte*)outline->tags; |
| 337 | FT_Byte* limit = flag + n_points; |
| 338 | FT_Byte c, count; |
| 339 | |
| 340 | |
| 341 | for ( ; flag < limit; flag++ ) |
| 342 | { |
| 343 | *flag = c = GET_Byte(); |
| 344 | if ( c & 8 ) |
| 345 | { |
| 346 | for ( count = GET_Byte(); count > 0; count-- ) |
| 347 | *++flag = c; |
| 348 | } |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | /* reading the X coordinates */ |
| 353 | |
| 354 | { |
| 355 | FT_Vector* vec = outline->points; |
| 356 | FT_Vector* limit = vec + n_points; |
| 357 | FT_Byte* flag = (FT_Byte*)outline->tags; |
| 358 | FT_Pos x = 0; |
| 359 | |
| 360 | |
| 361 | for ( ; vec < limit; vec++, flag++ ) |
| 362 | { |
| 363 | FT_Pos y = 0; |
| 364 | |
| 365 | |
| 366 | if ( *flag & 2 ) |
| 367 | { |
| 368 | y = GET_Byte(); |
| 369 | if ( ( *flag & 16 ) == 0 ) |
| 370 | y = -y; |
| 371 | } |
| 372 | else if ( ( *flag & 16 ) == 0 ) |
| 373 | y = GET_Short(); |
| 374 | |
| 375 | x += y; |
| 376 | vec->x = x; |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /* reading the Y coordinates */ |
| 381 | |
| 382 | { |
| 383 | FT_Vector* vec = gloader->current.outline.points; |
| 384 | FT_Vector* limit = vec + n_points; |
| 385 | FT_Byte* flag = (FT_Byte*)outline->tags; |
| 386 | FT_Pos x = 0; |
| 387 | |
| 388 | |
| 389 | for ( ; vec < limit; vec++, flag++ ) |
| 390 | { |
| 391 | FT_Pos y = 0; |
| 392 | |
| 393 | |
| 394 | if ( *flag & 4 ) |
| 395 | { |
| 396 | y = GET_Byte(); |
| 397 | if ( ( *flag & 32 ) == 0 ) |
| 398 | y = -y; |
| 399 | } |
| 400 | else if ( ( *flag & 32 ) == 0 ) |
| 401 | y = GET_Short(); |
| 402 | |
| 403 | x += y; |
| 404 | vec->y = x; |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | /* clear the touch tags */ |
| 409 | for ( n = 0; n < n_points; n++ ) |
| 410 | outline->tags[n] &= FT_Curve_Tag_On; |
| 411 | |
| 412 | outline->n_points = n_points; |
| 413 | outline->n_contours = n_contours; |
| 414 | |
| 415 | Fail: |
| 416 | return error; |
| 417 | } |
| 418 | |
| 419 | |
| 420 | static |
| 421 | FT_Error TT_Load_Composite_Glyph( TT_Loader* loader ) |
| 422 | { |
| 423 | FT_Error error; |
| 424 | FT_Stream stream = loader->stream; |
| 425 | FT_GlyphLoader* gloader = loader->gloader; |
| 426 | FT_SubGlyph* subglyph; |
| 427 | FT_UInt num_subglyphs; |
| 428 | |
| 429 | |
| 430 | num_subglyphs = 0; |
| 431 | |
| 432 | do |
| 433 | { |
| 434 | FT_Fixed xx, xy, yy, yx; |
| 435 | |
| 436 | |
| 437 | /* check that we can load a new subglyph */ |
| 438 | error = FT_GlyphLoader_Check_Subglyphs( gloader, num_subglyphs + 1 ); |
| 439 | if ( error ) |
| 440 | goto Fail; |
| 441 | |
| 442 | subglyph = gloader->current.subglyphs + num_subglyphs; |
| 443 | |
| 444 | subglyph->arg1 = subglyph->arg2 = 0; |
| 445 | |
| 446 | subglyph->flags = GET_UShort(); |
| 447 | subglyph->index = GET_UShort(); |
| 448 | |
| 449 | /* read arguments */ |
| 450 | if ( subglyph->flags & ARGS_ARE_WORDS ) |
| 451 | { |
| 452 | subglyph->arg1 = GET_Short(); |
| 453 | subglyph->arg2 = GET_Short(); |
| 454 | } |
| 455 | else |
| 456 | { |
| 457 | subglyph->arg1 = GET_Char(); |
| 458 | subglyph->arg2 = GET_Char(); |
| 459 | } |
| 460 | |
| 461 | /* read transform */ |
| 462 | xx = yy = 0x10000L; |
| 463 | xy = yx = 0; |
| 464 | |
| 465 | if ( subglyph->flags & WE_HAVE_A_SCALE ) |
| 466 | { |
| 467 | xx = (FT_Fixed)GET_Short() << 2; |
| 468 | yy = xx; |
| 469 | } |
| 470 | else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) |
| 471 | { |
| 472 | xx = (FT_Fixed)GET_Short() << 2; |
| 473 | yy = (FT_Fixed)GET_Short() << 2; |
| 474 | } |
| 475 | else if ( subglyph->flags & WE_HAVE_A_2X2 ) |
| 476 | { |
| 477 | xx = (FT_Fixed)GET_Short() << 2; |
| 478 | xy = (FT_Fixed)GET_Short() << 2; |
| 479 | yx = (FT_Fixed)GET_Short() << 2; |
| 480 | yy = (FT_Fixed)GET_Short() << 2; |
| 481 | } |
| 482 | |
| 483 | subglyph->transform.xx = xx; |
| 484 | subglyph->transform.xy = xy; |
| 485 | subglyph->transform.yx = yx; |
| 486 | subglyph->transform.yy = yy; |
| 487 | |
| 488 | num_subglyphs++; |
| 489 | |
| 490 | } while ( subglyph->flags & MORE_COMPONENTS ); |
| 491 | |
| 492 | gloader->current.num_subglyphs = num_subglyphs; |
| 493 | |
| 494 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 495 | { |
| 496 | /* we must undo the ACCESS_Frame in order to point to the */ |
| 497 | /* composite instructions, if we find some. */ |
| 498 | /* we will process them later... */ |
| 499 | /* */ |
| 500 | loader->ins_pos = FILE_Pos() + stream->cursor - stream->limit; |
| 501 | } |
| 502 | #endif |
| 503 | |
| 504 | Fail: |
| 505 | return error; |
| 506 | } |
| 507 | |
| 508 | |
| 509 | LOCAL_FUNC |
| 510 | void TT_Init_Glyph_Loading( TT_Face face ) |
| 511 | { |
| 512 | face->access_glyph_frame = TT_Access_Glyph_Frame; |
| 513 | face->read_glyph_header = TT_Load_Glyph_Header; |
| 514 | face->read_simple_glyph = TT_Load_Simple_Glyph; |
| 515 | face->read_composite_glyph = TT_Load_Composite_Glyph; |
| 516 | face->forget_glyph_frame = TT_Forget_Glyph_Frame; |
| 517 | } |
| 518 | |
| 519 | |
| 520 | /*************************************************************************/ |
| 521 | /* */ |
| 522 | /* <Function> */ |
| 523 | /* TT_Process_Simple_Glyph */ |
| 524 | /* */ |
| 525 | /* <Description> */ |
| 526 | /* Once a simple glyph has been loaded, it needs to be processed. */ |
| 527 | /* Usually, this means scaling and hinting through bytecode */ |
| 528 | /* interpretation. */ |
| 529 | /* */ |
| 530 | static |
| 531 | FT_Error TT_Process_Simple_Glyph( TT_Loader* load, |
| 532 | FT_Bool debug ) |
| 533 | { |
| 534 | FT_GlyphLoader* gloader = load->gloader; |
| 535 | FT_Outline* outline = &gloader->current.outline; |
| 536 | FT_UInt n_points = outline->n_points; |
| 537 | FT_UInt n_ins; |
| 538 | TT_GlyphZone* zone = &load->zone; |
| 539 | FT_Error error = FT_Err_Ok; |
| 540 | |
| 541 | |
| 542 | n_ins = load->glyph->control_len; |
| 543 | |
| 544 | /* add shadow points */ |
| 545 | |
| 546 | /* Now add the two shadow points at n and n + 1. */ |
| 547 | /* We need the left side bearing and advance width. */ |
| 548 | |
| 549 | { |
| 550 | FT_Vector* pp1; |
| 551 | FT_Vector* pp2; |
| 552 | |
| 553 | |
| 554 | /* pp1 = xMin - lsb */ |
| 555 | pp1 = outline->points + n_points; |
| 556 | pp1->x = load->bbox.xMin - load->left_bearing; |
| 557 | pp1->y = 0; |
| 558 | |
| 559 | /* pp2 = pp1 + aw */ |
| 560 | pp2 = pp1 + 1; |
| 561 | pp2->x = pp1->x + load->advance; |
| 562 | pp2->y = 0; |
| 563 | |
| 564 | outline->tags[n_points ] = 0; |
| 565 | outline->tags[n_points + 1] = 0; |
| 566 | } |
| 567 | |
| 568 | /* Note that we return two more points that are not */ |
| 569 | /* part of the glyph outline. */ |
| 570 | |
| 571 | n_points += 2; |
| 572 | |
| 573 | /* set up zone for hinting */ |
| 574 | tt_prepare_zone( zone, &gloader->current, 0, 0 ); |
| 575 | |
| 576 | /* eventually scale the glyph */ |
| 577 | if ( !( load->load_flags & FT_LOAD_NO_SCALE ) ) |
| 578 | { |
| 579 | FT_Vector* vec = zone->cur; |
| 580 | FT_Vector* limit = vec + n_points; |
| 581 | FT_Fixed x_scale = load->size->metrics.x_scale; |
| 582 | FT_Fixed y_scale = load->size->metrics.y_scale; |
| 583 | |
| 584 | |
| 585 | /* first scale the glyph points */ |
| 586 | for ( ; vec < limit; vec++ ) |
| 587 | { |
| 588 | vec->x = FT_MulFix( vec->x, x_scale ); |
| 589 | vec->y = FT_MulFix( vec->y, y_scale ); |
| 590 | } |
| 591 | } |
| 592 | |
| 593 | cur_to_org( n_points, zone ); |
| 594 | |
| 595 | /* eventually hint the glyph */ |
| 596 | if ( IS_HINTED( load->load_flags ) ) |
| 597 | { |
| 598 | FT_Pos x = zone->org[n_points-2].x; |
| 599 | |
| 600 | |
| 601 | x = ( ( x + 32 ) & -64 ) - x; |
| 602 | translate_array( n_points, zone->org, x, 0 ); |
| 603 | |
| 604 | org_to_cur( n_points, zone ); |
| 605 | |
| 606 | zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64; |
| 607 | |
| 608 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 609 | |
| 610 | /* now consider hinting */ |
| 611 | if ( n_ins > 0 ) |
| 612 | { |
| 613 | error = TT_Set_CodeRange( load->exec, tt_coderange_glyph, |
| 614 | load->exec->glyphIns, n_ins ); |
| 615 | if ( error ) |
| 616 | goto Exit; |
| 617 | |
| 618 | load->exec->is_composite = FALSE; |
| 619 | load->exec->pedantic_hinting = (FT_Bool)( load->load_flags & |
| 620 | FT_LOAD_PEDANTIC ); |
| 621 | load->exec->pts = *zone; |
| 622 | load->exec->pts.n_points += 2; |
| 623 | |
| 624 | error = TT_Run_Context( load->exec, debug ); |
| 625 | if ( error && load->exec->pedantic_hinting ) |
| 626 | goto Exit; |
| 627 | |
| 628 | error = FT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */ |
| 629 | } |
| 630 | |
| 631 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 632 | |
| 633 | } |
| 634 | |
| 635 | /* save glyph phantom points */ |
| 636 | if ( !load->preserve_pps ) |
| 637 | { |
| 638 | load->pp1 = zone->cur[n_points - 2]; |
| 639 | load->pp2 = zone->cur[n_points - 1]; |
| 640 | } |
| 641 | |
| 642 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 643 | Exit: |
| 644 | #endif |
| 645 | return error; |
| 646 | } |
| 647 | |
| 648 | |
| 649 | /*************************************************************************/ |
| 650 | /* */ |
| 651 | /* <Function> */ |
| 652 | /* load_truetype_glyph */ |
| 653 | /* */ |
| 654 | /* <Description> */ |
| 655 | /* Loads a given truetype glyph. Handles composites and uses a */ |
| 656 | /* TT_Loader object. */ |
| 657 | /* */ |
| 658 | static |
| 659 | FT_Error load_truetype_glyph( TT_Loader* loader, |
| 660 | FT_UInt glyph_index ) |
| 661 | { |
| 662 | FT_Stream stream = loader->stream; |
| 663 | FT_Error error; |
| 664 | TT_Face face = (TT_Face)loader->face; |
| 665 | FT_ULong offset; |
| 666 | FT_Int contours_count; |
| 667 | FT_UInt index, num_points, num_contours, count; |
| 668 | FT_Fixed x_scale, y_scale; |
| 669 | FT_ULong ins_offset; |
| 670 | FT_GlyphLoader* gloader = loader->gloader; |
| 671 | FT_Bool opened_frame = 0; |
| 672 | |
| 673 | |
| 674 | /* check glyph index */ |
| 675 | index = glyph_index; |
| 676 | if ( index >= (FT_UInt)face->root.num_glyphs ) |
| 677 | { |
| 678 | error = TT_Err_Invalid_Glyph_Index; |
| 679 | goto Exit; |
| 680 | } |
| 681 | |
| 682 | loader->glyph_index = glyph_index; |
| 683 | num_contours = 0; |
| 684 | num_points = 0; |
| 685 | ins_offset = 0; |
| 686 | |
| 687 | x_scale = 0x10000L; |
| 688 | y_scale = 0x10000L; |
| 689 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) |
| 690 | { |
| 691 | x_scale = loader->size->metrics.x_scale; |
| 692 | y_scale = loader->size->metrics.y_scale; |
| 693 | } |
| 694 | |
| 695 | /* get horizontal metrics */ |
| 696 | { |
| 697 | FT_Short left_bearing; |
| 698 | FT_UShort advance_width; |
| 699 | |
| 700 | |
| 701 | Get_HMetrics( face, index, |
| 702 | (FT_Bool)!(loader->load_flags & |
| 703 | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), |
| 704 | &left_bearing, |
| 705 | &advance_width ); |
| 706 | |
| 707 | loader->left_bearing = left_bearing; |
| 708 | loader->advance = advance_width; |
| 709 | } |
| 710 | |
| 711 | offset = face->glyph_locations[index]; |
| 712 | count = 0; |
| 713 | |
| 714 | if ( index < (FT_UInt)face->num_locations - 1 ) |
| 715 | count = face->glyph_locations[index + 1] - offset; |
| 716 | |
| 717 | if ( count == 0 ) |
| 718 | { |
| 719 | /* as described by Frederic Loyer, these are spaces, and */ |
| 720 | /* not the unknown glyph. */ |
| 721 | loader->bbox.xMin = 0; |
| 722 | loader->bbox.xMax = 0; |
| 723 | loader->bbox.yMin = 0; |
| 724 | loader->bbox.yMax = 0; |
| 725 | |
| 726 | loader->pp1.x = 0; |
| 727 | loader->pp2.x = loader->advance; |
| 728 | |
| 729 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) |
| 730 | loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); |
| 731 | |
| 732 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 733 | |
| 734 | if ( loader->exec ) |
| 735 | loader->exec->glyphSize = 0; |
| 736 | |
| 737 | #endif |
| 738 | |
| 739 | error = FT_Err_Ok; |
| 740 | goto Exit; |
| 741 | } |
| 742 | |
| 743 | offset = loader->glyf_offset + offset; |
| 744 | |
| 745 | /* access glyph frame */ |
| 746 | error = face->access_glyph_frame( loader, glyph_index, offset, count ); |
| 747 | if ( error ) |
| 748 | goto Exit; |
| 749 | |
| 750 | opened_frame = 1; |
| 751 | |
| 752 | /* read first glyph header */ |
| 753 | error = face->read_glyph_header( loader ); |
| 754 | if ( error ) |
| 755 | goto Fail; |
| 756 | |
| 757 | contours_count = loader->n_contours; |
| 758 | |
| 759 | count -= 10; |
| 760 | |
| 761 | loader->pp1.x = loader->bbox.xMin - loader->left_bearing; |
| 762 | loader->pp1.y = 0; |
| 763 | loader->pp2.x = loader->pp1.x + loader->advance; |
| 764 | loader->pp2.y = 0; |
| 765 | |
| 766 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) |
| 767 | { |
| 768 | loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); |
| 769 | loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); |
| 770 | } |
| 771 | |
| 772 | /***********************************************************************/ |
| 773 | /***********************************************************************/ |
| 774 | /***********************************************************************/ |
| 775 | |
| 776 | /* if it is a simple glyph, load it */ |
| 777 | |
| 778 | if ( contours_count >= 0 ) |
| 779 | { |
| 780 | /* check that we can add the contours to the glyph */ |
| 781 | error = FT_GlyphLoader_Check_Points( gloader, 0, contours_count ); |
| 782 | if ( error ) |
| 783 | goto Fail; |
| 784 | |
| 785 | error = face->read_simple_glyph( loader ); |
| 786 | if ( error ) |
| 787 | goto Fail; |
| 788 | |
| 789 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 790 | |
| 791 | { |
| 792 | TT_Size size = (TT_Size)loader->size; |
| 793 | |
| 794 | |
| 795 | error = TT_Process_Simple_Glyph( loader, |
| 796 | (FT_Bool)( size && size->debug ) ); |
| 797 | } |
| 798 | |
| 799 | #else |
| 800 | |
| 801 | error = TT_Process_Simple_Glyph( loader, 0 ); |
| 802 | |
| 803 | #endif |
| 804 | |
| 805 | if ( error ) |
| 806 | goto Fail; |
| 807 | |
| 808 | FT_GlyphLoader_Add( gloader ); |
| 809 | |
| 810 | /* Note: We could have put the simple loader source there */ |
| 811 | /* but the code is fat enough already :-) */ |
| 812 | } |
| 813 | |
| 814 | /***********************************************************************/ |
| 815 | /***********************************************************************/ |
| 816 | /***********************************************************************/ |
| 817 | |
| 818 | /* otherwise, load a composite! */ |
| 819 | else |
| 820 | { |
| 821 | TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph; |
| 822 | FT_UInt start_point, start_contour; |
| 823 | FT_ULong ins_pos; /* position of composite instructions, if any */ |
| 824 | |
| 825 | |
| 826 | /* for each subglyph, read composite header */ |
| 827 | start_point = gloader->base.outline.n_points; |
| 828 | start_contour = gloader->base.outline.n_contours; |
| 829 | |
| 830 | error = face->read_composite_glyph( loader ); |
| 831 | if ( error ) |
| 832 | goto Fail; |
| 833 | |
| 834 | ins_pos = loader->ins_pos; |
| 835 | face->forget_glyph_frame( loader ); |
| 836 | opened_frame = 0; |
| 837 | |
| 838 | /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ |
| 839 | /* `as is' in the glyph slot (the client application will be */ |
| 840 | /* responsible for interpreting this data)... */ |
| 841 | /* */ |
| 842 | if ( loader->load_flags & FT_LOAD_NO_RECURSE ) |
| 843 | { |
| 844 | /* set up remaining glyph fields */ |
| 845 | FT_GlyphLoader_Add( gloader ); |
| 846 | |
| 847 | glyph->num_subglyphs = gloader->base.num_subglyphs; |
| 848 | glyph->format = ft_glyph_format_composite; |
| 849 | glyph->subglyphs = gloader->base.subglyphs; |
| 850 | |
| 851 | goto Exit; |
| 852 | } |
| 853 | |
| 854 | /*********************************************************************/ |
| 855 | /*********************************************************************/ |
| 856 | /*********************************************************************/ |
| 857 | |
| 858 | /* Now, read each subglyph independently. */ |
| 859 | { |
| 860 | FT_Int n, num_base_points, num_new_points; |
| 861 | FT_SubGlyph* subglyph = 0; |
| 862 | |
| 863 | FT_UInt num_subglyphs = gloader->current.num_subglyphs; |
| 864 | FT_UInt num_base_subgs = gloader->base.num_subglyphs; |
| 865 | |
| 866 | |
| 867 | FT_GlyphLoader_Add( gloader ); |
| 868 | |
| 869 | for ( n = 0; n < (FT_Int)num_subglyphs; n++ ) |
| 870 | { |
| 871 | FT_Vector pp1, pp2; |
| 872 | FT_Pos x, y; |
| 873 | |
| 874 | |
| 875 | /* Each time we call load_truetype_glyph in this loop, the */ |
| 876 | /* value of `gloader.base.subglyphs' can change due to table */ |
| 877 | /* reallocations. We thus need to recompute the subglyph */ |
| 878 | /* pointer on each iteration. */ |
| 879 | subglyph = gloader->base.subglyphs + num_base_subgs + n; |
| 880 | |
| 881 | pp1 = loader->pp1; |
| 882 | pp2 = loader->pp2; |
| 883 | |
| 884 | num_base_points = gloader->base.outline.n_points; |
| 885 | |
| 886 | error = load_truetype_glyph( loader, subglyph->index ); |
| 887 | if ( error ) |
| 888 | goto Fail; |
| 889 | |
| 890 | subglyph = gloader->base.subglyphs + num_base_subgs + n; |
| 891 | |
| 892 | if ( subglyph->flags & USE_MY_METRICS ) |
| 893 | { |
| 894 | pp1 = loader->pp1; |
| 895 | pp2 = loader->pp2; |
| 896 | } |
| 897 | else |
| 898 | { |
| 899 | loader->pp1 = pp1; |
| 900 | loader->pp2 = pp2; |
| 901 | } |
| 902 | |
| 903 | num_points = gloader->base.outline.n_points; |
| 904 | |
| 905 | num_new_points = num_points - num_base_points; |
| 906 | |
| 907 | /* now perform the transform required for this subglyph */ |
| 908 | |
| 909 | if ( subglyph->flags & ( WE_HAVE_A_SCALE | |
| 910 | WE_HAVE_AN_XY_SCALE | |
| 911 | WE_HAVE_A_2X2 ) ) |
| 912 | { |
| 913 | FT_Vector* cur = gloader->base.outline.points + |
| 914 | num_base_points; |
| 915 | FT_Vector* org = gloader->base.extra_points + |
| 916 | num_base_points; |
| 917 | FT_Vector* limit = cur + num_new_points; |
| 918 | |
| 919 | |
| 920 | for ( ; cur < limit; cur++, org++ ) |
| 921 | { |
| 922 | FT_Vector_Transform( cur, &subglyph->transform ); |
| 923 | FT_Vector_Transform( org, &subglyph->transform ); |
| 924 | } |
| 925 | } |
| 926 | |
| 927 | /* apply offset */ |
| 928 | |
| 929 | if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) |
| 930 | { |
| 931 | FT_UInt k = subglyph->arg1; |
| 932 | FT_UInt l = subglyph->arg2; |
| 933 | FT_Vector* p1; |
| 934 | FT_Vector* p2; |
| 935 | |
| 936 | |
| 937 | if ( start_point + k >= (FT_UInt)num_base_points || |
| 938 | l >= (FT_UInt)num_new_points ) |
| 939 | { |
| 940 | error = TT_Err_Invalid_Composite; |
| 941 | goto Fail; |
| 942 | } |
| 943 | |
| 944 | l += num_base_points; |
| 945 | |
| 946 | p1 = gloader->base.outline.points + start_point + k; |
| 947 | p2 = gloader->base.outline.points + start_point + l; |
| 948 | |
| 949 | x = p1->x - p2->x; |
| 950 | y = p1->y - p2->y; |
| 951 | } |
| 952 | else |
| 953 | { |
| 954 | x = subglyph->arg1; |
| 955 | y = subglyph->arg2; |
| 956 | |
| 957 | if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) |
| 958 | { |
| 959 | x = FT_MulFix( x, x_scale ); |
| 960 | y = FT_MulFix( y, y_scale ); |
| 961 | |
| 962 | if ( subglyph->flags & ROUND_XY_TO_GRID ) |
| 963 | { |
| 964 | x = ( x + 32 ) & -64; |
| 965 | y = ( y + 32 ) & -64; |
| 966 | } |
| 967 | } |
| 968 | } |
| 969 | |
| 970 | translate_array( num_new_points, loader->zone.cur, x, y ); |
| 971 | cur_to_org( num_new_points, &loader->zone ); |
| 972 | } |
| 973 | |
| 974 | /*******************************************************************/ |
| 975 | /*******************************************************************/ |
| 976 | /*******************************************************************/ |
| 977 | |
| 978 | /* we have finished loading all sub-glyphs; now, look for */ |
| 979 | /* instructions for this composite! */ |
| 980 | |
| 981 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 982 | |
| 983 | if ( num_subglyphs > 0 && |
| 984 | loader->exec && |
| 985 | ins_pos > 0 && |
| 986 | subglyph->flags & WE_HAVE_INSTR ) |
| 987 | { |
| 988 | FT_UShort n_ins; |
| 989 | TT_ExecContext exec = loader->exec; |
| 990 | TT_GlyphZone* pts; |
| 991 | FT_Vector* pp1; |
| 992 | |
| 993 | |
| 994 | /* read size of instructions */ |
| 995 | if ( FILE_Seek( ins_pos ) || |
| 996 | READ_UShort( n_ins ) ) |
| 997 | goto Fail; |
| 998 | FT_TRACE5(( " Instructions size = %d\n", n_ins )); |
| 999 | |
| 1000 | /* in some fonts? */ |
| 1001 | if ( n_ins == 0xFFFF ) |
| 1002 | n_ins = 0; |
| 1003 | |
| 1004 | /* check it */ |
| 1005 | if ( n_ins > face->max_profile.maxSizeOfInstructions ) |
| 1006 | { |
| 1007 | FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n", |
| 1008 | n_ins, subglyph->index )); |
| 1009 | return TT_Err_Too_Many_Ins; |
| 1010 | } |
| 1011 | |
| 1012 | /* read the instructions */ |
| 1013 | if ( FILE_Read( exec->glyphIns, n_ins ) ) |
| 1014 | goto Fail; |
| 1015 | |
| 1016 | glyph->control_data = exec->glyphIns; |
| 1017 | glyph->control_len = n_ins; |
| 1018 | |
| 1019 | error = TT_Set_CodeRange( exec, |
| 1020 | tt_coderange_glyph, |
| 1021 | exec->glyphIns, |
| 1022 | n_ins ); |
| 1023 | if ( error ) |
| 1024 | goto Fail; |
| 1025 | |
| 1026 | /* prepare the execution context */ |
| 1027 | tt_prepare_zone( &exec->pts, &gloader->base, |
| 1028 | start_point, start_contour ); |
| 1029 | pts = &exec->pts; |
| 1030 | |
| 1031 | pts->n_points = num_points + 2; |
| 1032 | pts->n_contours = gloader->base.outline.n_contours; |
| 1033 | |
| 1034 | /* add phantom points */ |
| 1035 | pp1 = pts->cur + num_points; |
| 1036 | pp1[0] = loader->pp1; |
| 1037 | pp1[1] = loader->pp2; |
| 1038 | |
| 1039 | pts->tags[num_points ] = 0; |
| 1040 | pts->tags[num_points + 1] = 0; |
| 1041 | |
| 1042 | /* if hinting, round the phantom points */ |
| 1043 | if ( IS_HINTED( loader->load_flags ) ) |
| 1044 | { |
| 1045 | pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 ); |
| 1046 | pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 ); |
| 1047 | } |
| 1048 | |
| 1049 | { |
| 1050 | FT_UInt k; |
| 1051 | |
| 1052 | |
| 1053 | for ( k = 0; k < num_points; k++ ) |
| 1054 | pts->tags[k] &= FT_Curve_Tag_On; |
| 1055 | } |
| 1056 | |
| 1057 | cur_to_org( num_points + 2, pts ); |
| 1058 | |
| 1059 | /* now consider hinting */ |
| 1060 | if ( IS_HINTED( loader->load_flags ) && n_ins > 0 ) |
| 1061 | { |
| 1062 | exec->is_composite = TRUE; |
| 1063 | exec->pedantic_hinting = |
| 1064 | (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC ); |
| 1065 | |
| 1066 | error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug ); |
| 1067 | if ( error && exec->pedantic_hinting ) |
| 1068 | goto Fail; |
| 1069 | } |
| 1070 | |
| 1071 | /* save glyph origin and advance points */ |
| 1072 | loader->pp1 = pp1[0]; |
| 1073 | loader->pp2 = pp1[1]; |
| 1074 | } |
| 1075 | |
| 1076 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 1077 | |
| 1078 | } |
| 1079 | /* end of composite loading */ |
| 1080 | } |
| 1081 | |
| 1082 | /***********************************************************************/ |
| 1083 | /***********************************************************************/ |
| 1084 | /***********************************************************************/ |
| 1085 | |
| 1086 | Fail: |
| 1087 | if ( opened_frame ) |
| 1088 | face->forget_glyph_frame( loader ); |
| 1089 | |
| 1090 | Exit: |
| 1091 | return error; |
| 1092 | } |
| 1093 | |
| 1094 | |
| 1095 | static |
| 1096 | void compute_glyph_metrics( TT_Loader* loader, |
| 1097 | FT_UInt glyph_index ) |
| 1098 | { |
| 1099 | FT_BBox bbox; |
| 1100 | TT_Face face = (TT_Face)loader->face; |
| 1101 | FT_Fixed x_scale, y_scale; |
| 1102 | TT_GlyphSlot glyph = loader->glyph; |
| 1103 | TT_Size size = (TT_Size)loader->size; |
| 1104 | |
| 1105 | |
| 1106 | x_scale = 0x10000L; |
| 1107 | y_scale = 0x10000L; |
| 1108 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) |
| 1109 | { |
| 1110 | x_scale = size->root.metrics.x_scale; |
| 1111 | y_scale = size->root.metrics.y_scale; |
| 1112 | } |
| 1113 | |
| 1114 | if ( glyph->format != ft_glyph_format_composite ) |
| 1115 | { |
| 1116 | glyph->outline.flags &= ~ft_outline_single_pass; |
| 1117 | |
| 1118 | /* copy outline to our glyph slot */ |
| 1119 | FT_GlyphLoader_Copy_Points( glyph->loader, loader->gloader ); |
| 1120 | glyph->outline = glyph->loader->base.outline; |
| 1121 | |
| 1122 | /* translate array so that (0,0) is the glyph's origin */ |
| 1123 | FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 ); |
| 1124 | |
| 1125 | FT_Outline_Get_CBox( &glyph->outline, &bbox ); |
| 1126 | |
| 1127 | if ( IS_HINTED( loader->load_flags ) ) |
| 1128 | { |
| 1129 | /* grid-fit the bounding box */ |
| 1130 | bbox.xMin &= -64; |
| 1131 | bbox.yMin &= -64; |
| 1132 | bbox.xMax = ( bbox.xMax + 63 ) & -64; |
| 1133 | bbox.yMax = ( bbox.yMax + 63 ) & -64; |
| 1134 | } |
| 1135 | } |
| 1136 | else |
| 1137 | bbox = loader->bbox; |
| 1138 | |
| 1139 | /* get the device-independent horizontal advance. It is scaled later */ |
| 1140 | /* by the base layer. */ |
| 1141 | { |
| 1142 | FT_Pos advance = loader->advance; |
| 1143 | |
| 1144 | |
| 1145 | /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ |
| 1146 | /* correctly support DynaLab fonts, which have an incorrect */ |
| 1147 | /* `advance_Width_Max' field! It is used, to my knowledge, */ |
| 1148 | /* exclusively in the X-TrueType font server. */ |
| 1149 | /* */ |
| 1150 | if ( face->postscript.isFixedPitch && |
| 1151 | ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) |
| 1152 | advance = face->horizontal.advance_Width_Max; |
| 1153 | |
| 1154 | /* we need to return the advance in font units in linearHoriAdvance, */ |
| 1155 | /* it will be scaled later by the base layer. */ |
| 1156 | glyph->linearHoriAdvance = advance; |
| 1157 | } |
| 1158 | |
| 1159 | glyph->metrics.horiBearingX = bbox.xMin; |
| 1160 | glyph->metrics.horiBearingY = bbox.yMax; |
| 1161 | glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; |
| 1162 | |
| 1163 | /* Now take care of vertical metrics. In the case where there is */ |
| 1164 | /* no vertical information within the font (relatively common), make */ |
| 1165 | /* up some metrics by `hand'... */ |
| 1166 | |
| 1167 | { |
| 1168 | FT_Short top_bearing; /* vertical top side bearing (EM units) */ |
| 1169 | FT_UShort advance_height; /* vertical advance height (EM units) */ |
| 1170 | |
| 1171 | FT_Pos left; /* scaled vertical left side bearing */ |
| 1172 | FT_Pos Top; /* scaled original vertical top side bearing */ |
| 1173 | FT_Pos top; /* scaled vertical top side bearing */ |
| 1174 | FT_Pos advance; /* scaled vertical advance height */ |
| 1175 | |
| 1176 | |
| 1177 | /* Get the unscaled `tsb' and `ah' */ |
| 1178 | if ( face->vertical_info && |
| 1179 | face->vertical.number_Of_VMetrics > 0 ) |
| 1180 | { |
| 1181 | /* Don't assume that both the vertical header and vertical */ |
| 1182 | /* metrics are present in the same font :-) */ |
| 1183 | |
| 1184 | TT_Get_Metrics( (TT_HoriHeader*)&face->vertical, |
| 1185 | glyph_index, |
| 1186 | &top_bearing, |
| 1187 | &advance_height ); |
| 1188 | } |
| 1189 | else |
| 1190 | { |
| 1191 | /* Make up the distances from the horizontal header. */ |
| 1192 | |
| 1193 | /* NOTE: The OS/2 values are the only `portable' ones, */ |
| 1194 | /* which is why we use them, if there is an OS/2 */ |
| 1195 | /* table in the font. Otherwise, we use the */ |
| 1196 | /* values defined in the horizontal header. */ |
| 1197 | /* */ |
| 1198 | /* NOTE2: The sTypoDescender is negative, which is why */ |
| 1199 | /* we compute the baseline-to-baseline distance */ |
| 1200 | /* here with: */ |
| 1201 | /* ascender - descender + linegap */ |
| 1202 | /* */ |
| 1203 | if ( face->os2.version != 0xFFFF ) |
| 1204 | { |
| 1205 | top_bearing = face->os2.sTypoLineGap / 2; |
| 1206 | advance_height = (FT_UShort)( face->os2.sTypoAscender - |
| 1207 | face->os2.sTypoDescender + |
| 1208 | face->os2.sTypoLineGap ); |
| 1209 | } |
| 1210 | else |
| 1211 | { |
| 1212 | top_bearing = face->horizontal.Line_Gap / 2; |
| 1213 | advance_height = (FT_UShort)( face->horizontal.Ascender + |
| 1214 | face->horizontal.Descender + |
| 1215 | face->horizontal.Line_Gap ); |
| 1216 | } |
| 1217 | } |
| 1218 | |
| 1219 | /* We must adjust the top_bearing value from the bounding box given */ |
| 1220 | /* in the glyph header to te bounding box calculated with */ |
| 1221 | /* FT_Get_Outline_CBox(). */ |
| 1222 | |
| 1223 | /* scale the metrics */ |
| 1224 | if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) |
| 1225 | { |
| 1226 | Top = FT_MulFix( top_bearing, y_scale ); |
| 1227 | top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale ) |
| 1228 | - bbox.yMax; |
| 1229 | advance = FT_MulFix( advance_height, y_scale ); |
| 1230 | } |
| 1231 | else |
| 1232 | { |
| 1233 | Top = top_bearing; |
| 1234 | top = top_bearing + loader->bbox.yMax - bbox.yMax; |
| 1235 | advance = advance_height; |
| 1236 | } |
| 1237 | |
| 1238 | /* set the advance height in design units. It is scaled later by */ |
| 1239 | /* the base layer. */ |
| 1240 | glyph->linearVertAdvance = advance_height; |
| 1241 | |
| 1242 | /* XXX: for now, we have no better algorithm for the lsb, but it */ |
| 1243 | /* should work fine. */ |
| 1244 | /* */ |
| 1245 | left = ( bbox.xMin - bbox.xMax ) / 2; |
| 1246 | |
| 1247 | /* grid-fit them if necessary */ |
| 1248 | if ( IS_HINTED( loader->load_flags ) ) |
| 1249 | { |
| 1250 | left &= -64; |
| 1251 | top = ( top + 63 ) & -64; |
| 1252 | advance = ( advance + 32 ) & -64; |
| 1253 | } |
| 1254 | |
| 1255 | glyph->metrics.vertBearingX = left; |
| 1256 | glyph->metrics.vertBearingY = top; |
| 1257 | glyph->metrics.vertAdvance = advance; |
| 1258 | } |
| 1259 | |
| 1260 | /* adjust advance width to the value contained in the hdmx table */ |
| 1261 | if ( !face->postscript.isFixedPitch && size && |
| 1262 | IS_HINTED( loader->load_flags ) ) |
| 1263 | { |
| 1264 | FT_Byte* widths = Get_Advance_Widths( face, |
| 1265 | size->root.metrics.x_ppem ); |
| 1266 | |
| 1267 | |
| 1268 | if ( widths ) |
| 1269 | glyph->metrics.horiAdvance = widths[glyph_index] << 6; |
| 1270 | } |
| 1271 | |
| 1272 | /* set glyph dimensions */ |
| 1273 | glyph->metrics.width = bbox.xMax - bbox.xMin; |
| 1274 | glyph->metrics.height = bbox.yMax - bbox.yMin; |
| 1275 | } |
| 1276 | |
| 1277 | |
| 1278 | /*************************************************************************/ |
| 1279 | /* */ |
| 1280 | /* <Function> */ |
| 1281 | /* TT_Load_Glyph */ |
| 1282 | /* */ |
| 1283 | /* <Description> */ |
| 1284 | /* A function used to load a single glyph within a given glyph slot, */ |
| 1285 | /* for a given size. */ |
| 1286 | /* */ |
| 1287 | /* <Input> */ |
| 1288 | /* glyph :: A handle to a target slot object where the glyph */ |
| 1289 | /* will be loaded. */ |
| 1290 | /* */ |
| 1291 | /* size :: A handle to the source face size at which the glyph */ |
| 1292 | /* must be scaled/loaded. */ |
| 1293 | /* */ |
| 1294 | /* glyph_index :: The index of the glyph in the font file. */ |
| 1295 | /* */ |
| 1296 | /* load_flags :: A flag indicating what to load for this glyph. The */ |
| 1297 | /* FT_LOAD_XXX constants can be used to control the */ |
| 1298 | /* glyph loading process (e.g., whether the outline */ |
| 1299 | /* should be scaled, whether to load bitmaps or not, */ |
| 1300 | /* whether to hint the outline, etc). */ |
| 1301 | /* */ |
| 1302 | /* <Return> */ |
| 1303 | /* FreeType error code. 0 means success. */ |
| 1304 | /* */ |
| 1305 | LOCAL_FUNC |
| 1306 | FT_Error TT_Load_Glyph( TT_Size size, |
| 1307 | TT_GlyphSlot glyph, |
| 1308 | FT_UShort glyph_index, |
| 1309 | FT_UInt load_flags ) |
| 1310 | { |
| 1311 | SFNT_Interface* sfnt; |
| 1312 | TT_Face face; |
| 1313 | FT_Stream stream; |
| 1314 | FT_Memory memory; |
| 1315 | FT_Error error; |
| 1316 | TT_Loader loader; |
| 1317 | |
| 1318 | |
| 1319 | face = (TT_Face)glyph->face; |
| 1320 | sfnt = (SFNT_Interface*)face->sfnt; |
| 1321 | stream = face->root.stream; |
| 1322 | memory = face->root.memory; |
| 1323 | error = 0; |
| 1324 | |
| 1325 | if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) || |
| 1326 | ( load_flags & FT_LOAD_NO_RECURSE ) ) |
| 1327 | { |
| 1328 | size = NULL; |
| 1329 | load_flags |= FT_LOAD_NO_SCALE | |
| 1330 | FT_LOAD_NO_HINTING | |
| 1331 | FT_LOAD_NO_BITMAP; |
| 1332 | } |
| 1333 | |
| 1334 | glyph->num_subglyphs = 0; |
| 1335 | |
| 1336 | #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
| 1337 | |
| 1338 | /* try to load embedded bitmap if any */ |
| 1339 | if ( size && |
| 1340 | ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && |
| 1341 | sfnt->load_sbits ) |
| 1342 | { |
| 1343 | TT_SBit_Metrics metrics; |
| 1344 | |
| 1345 | |
| 1346 | error = sfnt->load_sbit_image( face, |
| 1347 | size->root.metrics.x_ppem, |
| 1348 | size->root.metrics.y_ppem, |
| 1349 | glyph_index, |
| 1350 | load_flags, |
| 1351 | stream, |
| 1352 | &glyph->bitmap, |
| 1353 | &metrics ); |
| 1354 | if ( !error ) |
| 1355 | { |
| 1356 | glyph->outline.n_points = 0; |
| 1357 | glyph->outline.n_contours = 0; |
| 1358 | |
| 1359 | glyph->metrics.width = (FT_Pos)metrics.width << 6; |
| 1360 | glyph->metrics.height = (FT_Pos)metrics.height << 6; |
| 1361 | |
| 1362 | glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; |
| 1363 | glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; |
| 1364 | glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; |
| 1365 | |
| 1366 | glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; |
| 1367 | glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; |
| 1368 | glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; |
| 1369 | |
| 1370 | glyph->format = ft_glyph_format_bitmap; |
| 1371 | if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) |
| 1372 | { |
| 1373 | glyph->bitmap_left = metrics.vertBearingX; |
| 1374 | glyph->bitmap_top = metrics.vertBearingY; |
| 1375 | } |
| 1376 | else |
| 1377 | { |
| 1378 | glyph->bitmap_left = metrics.horiBearingX; |
| 1379 | glyph->bitmap_top = metrics.horiBearingY; |
| 1380 | } |
| 1381 | return error; |
| 1382 | } |
| 1383 | } |
| 1384 | |
| 1385 | #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ |
| 1386 | |
| 1387 | /* seek to the beginning of the glyph table. For Type 42 fonts */ |
| 1388 | /* the table might be accessed from a Postscript stream or something */ |
| 1389 | /* else... */ |
| 1390 | |
| 1391 | error = face->goto_table( face, TTAG_glyf, stream, 0 ); |
| 1392 | if ( error ) |
| 1393 | { |
| 1394 | FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" )); |
| 1395 | goto Exit; |
| 1396 | } |
| 1397 | |
| 1398 | MEM_Set( &loader, 0, sizeof ( loader ) ); |
| 1399 | |
| 1400 | /* update the glyph zone bounds */ |
| 1401 | { |
| 1402 | FT_GlyphLoader* gloader = FT_FACE_DRIVER(face)->glyph_loader; |
| 1403 | |
| 1404 | |
| 1405 | loader.gloader = gloader; |
| 1406 | |
| 1407 | FT_GlyphLoader_Rewind( gloader ); |
| 1408 | |
| 1409 | tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 ); |
| 1410 | tt_prepare_zone( &loader.base, &gloader->base, 0, 0 ); |
| 1411 | } |
| 1412 | |
| 1413 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 1414 | |
| 1415 | if ( size ) |
| 1416 | { |
| 1417 | /* query new execution context */ |
| 1418 | loader.exec = size->debug ? size->context : TT_New_Context( face ); |
| 1419 | if ( !loader.exec ) |
| 1420 | return TT_Err_Could_Not_Find_Context; |
| 1421 | |
| 1422 | TT_Load_Context( loader.exec, face, size ); |
| 1423 | loader.instructions = loader.exec->glyphIns; |
| 1424 | |
| 1425 | /* load default graphics state - if needed */ |
| 1426 | if ( size->GS.instruct_control & 2 ) |
| 1427 | loader.exec->GS = tt_default_graphics_state; |
| 1428 | } |
| 1429 | |
| 1430 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 1431 | |
| 1432 | /* clear all outline flags, except the `owner' one */ |
| 1433 | glyph->outline.flags = 0; |
| 1434 | |
| 1435 | if ( size && size->root.metrics.y_ppem < 24 ) |
| 1436 | glyph->outline.flags |= ft_outline_high_precision; |
| 1437 | |
| 1438 | /* let's initialize the rest of our loader now */ |
| 1439 | |
| 1440 | loader.load_flags = load_flags; |
| 1441 | |
| 1442 | loader.face = (FT_Face)face; |
| 1443 | loader.size = (FT_Size)size; |
| 1444 | loader.glyph = (FT_GlyphSlot)glyph; |
| 1445 | loader.stream = stream; |
| 1446 | |
| 1447 | loader.glyf_offset = FILE_Pos(); |
| 1448 | |
| 1449 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 1450 | |
| 1451 | /* if the cvt program has disabled hinting, the argument */ |
| 1452 | /* is ignored. */ |
| 1453 | if ( size && ( size->GS.instruct_control & 1 ) ) |
| 1454 | loader.load_flags |= FT_LOAD_NO_HINTING; |
| 1455 | |
| 1456 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 1457 | |
| 1458 | /* Main loading loop */ |
| 1459 | glyph->format = ft_glyph_format_outline; |
| 1460 | glyph->num_subglyphs = 0; |
| 1461 | error = load_truetype_glyph( &loader, glyph_index ); |
| 1462 | if ( !error ) |
| 1463 | compute_glyph_metrics( &loader, glyph_index ); |
| 1464 | |
| 1465 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER |
| 1466 | |
| 1467 | if ( !size || !size->debug ) |
| 1468 | TT_Done_Context( loader.exec ); |
| 1469 | |
| 1470 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ |
| 1471 | |
| 1472 | Exit: |
| 1473 | return error; |
| 1474 | } |
| 1475 | |
| 1476 | |
| 1477 | /* END */ |