Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenttsbit.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ttsbit.c */ 00004 /* */ 00005 /* TrueType and OpenType embedded bitmap support (body). */ 00006 /* */ 00007 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ 00008 /* 2010 by */ 00009 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00010 /* */ 00011 /* This file is part of the FreeType project, and may only be used, */ 00012 /* modified, and distributed under the terms of the FreeType project */ 00013 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00014 /* this file you indicate that you have read the license and */ 00015 /* understand and accept it fully. */ 00016 /* */ 00017 /***************************************************************************/ 00018 00019 #include <ft2build.h> 00020 #include FT_INTERNAL_DEBUG_H 00021 #include FT_INTERNAL_STREAM_H 00022 #include FT_TRUETYPE_TAGS_H 00023 00024 /* 00025 * Alas, the memory-optimized sbit loader can't be used when implementing 00026 * the `old internals' hack 00027 */ 00028 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS 00029 00030 #include "ttsbit0.c" 00031 00032 #else /* FT_CONFIG_OPTION_OLD_INTERNALS */ 00033 00034 #include <ft2build.h> 00035 #include FT_INTERNAL_DEBUG_H 00036 #include FT_INTERNAL_STREAM_H 00037 #include FT_TRUETYPE_TAGS_H 00038 #include "ttsbit.h" 00039 00040 #include "sferrors.h" 00041 00042 00043 /*************************************************************************/ 00044 /* */ 00045 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00046 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00047 /* messages during execution. */ 00048 /* */ 00049 #undef FT_COMPONENT 00050 #define FT_COMPONENT trace_ttsbit 00051 00052 00053 /*************************************************************************/ 00054 /* */ 00055 /* <Function> */ 00056 /* blit_sbit */ 00057 /* */ 00058 /* <Description> */ 00059 /* Blits a bitmap from an input stream into a given target. Supports */ 00060 /* x and y offsets as well as byte padded lines. */ 00061 /* */ 00062 /* <Input> */ 00063 /* target :: The target bitmap/pixmap. */ 00064 /* */ 00065 /* source :: The input packed bitmap data. */ 00066 /* */ 00067 /* line_bits :: The number of bits per line. */ 00068 /* */ 00069 /* byte_padded :: A flag which is true if lines are byte-padded. */ 00070 /* */ 00071 /* x_offset :: The horizontal offset. */ 00072 /* */ 00073 /* y_offset :: The vertical offset. */ 00074 /* */ 00075 /* <Note> */ 00076 /* IMPORTANT: The x and y offsets are relative to the top corner of */ 00077 /* the target bitmap (unlike the normal TrueType */ 00078 /* convention). A positive y offset indicates a downwards */ 00079 /* direction! */ 00080 /* */ 00081 static void 00082 blit_sbit( FT_Bitmap* target, 00083 FT_Byte* source, 00084 FT_Int line_bits, 00085 FT_Bool byte_padded, 00086 FT_Int x_offset, 00087 FT_Int y_offset, 00088 FT_Int source_height ) 00089 { 00090 FT_Byte* line_buff; 00091 FT_Int line_incr; 00092 FT_Int height; 00093 00094 FT_UShort acc; 00095 FT_UInt loaded; 00096 00097 00098 /* first of all, compute starting write position */ 00099 line_incr = target->pitch; 00100 line_buff = target->buffer; 00101 00102 if ( line_incr < 0 ) 00103 line_buff -= line_incr * ( target->rows - 1 ); 00104 00105 line_buff += ( x_offset >> 3 ) + y_offset * line_incr; 00106 00107 /***********************************************************************/ 00108 /* */ 00109 /* We use the extra-classic `accumulator' trick to extract the bits */ 00110 /* from the source byte stream. */ 00111 /* */ 00112 /* Namely, the variable `acc' is a 16-bit accumulator containing the */ 00113 /* last `loaded' bits from the input stream. The bits are shifted to */ 00114 /* the upmost position in `acc'. */ 00115 /* */ 00116 /***********************************************************************/ 00117 00118 acc = 0; /* clear accumulator */ 00119 loaded = 0; /* no bits were loaded */ 00120 00121 for ( height = source_height; height > 0; height-- ) 00122 { 00123 FT_Byte* cur = line_buff; /* current write cursor */ 00124 FT_Int count = line_bits; /* # of bits to extract per line */ 00125 FT_Byte shift = (FT_Byte)( x_offset & 7 ); /* current write shift */ 00126 FT_Byte space = (FT_Byte)( 8 - shift ); 00127 00128 00129 /* first of all, read individual source bytes */ 00130 if ( count >= 8 ) 00131 { 00132 count -= 8; 00133 { 00134 do 00135 { 00136 FT_Byte val; 00137 00138 00139 /* ensure that there are at least 8 bits in the accumulator */ 00140 if ( loaded < 8 ) 00141 { 00142 acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded )); 00143 loaded += 8; 00144 } 00145 00146 /* now write one byte */ 00147 val = (FT_Byte)( acc >> 8 ); 00148 if ( shift ) 00149 { 00150 cur[0] |= (FT_Byte)( val >> shift ); 00151 cur[1] |= (FT_Byte)( val << space ); 00152 } 00153 else 00154 cur[0] |= val; 00155 00156 cur++; 00157 acc <<= 8; /* remove bits from accumulator */ 00158 loaded -= 8; 00159 count -= 8; 00160 00161 } while ( count >= 0 ); 00162 } 00163 00164 /* restore `count' to correct value */ 00165 count += 8; 00166 } 00167 00168 /* now write remaining bits (count < 8) */ 00169 if ( count > 0 ) 00170 { 00171 FT_Byte val; 00172 00173 00174 /* ensure that there are at least `count' bits in the accumulator */ 00175 if ( (FT_Int)loaded < count ) 00176 { 00177 acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded )); 00178 loaded += 8; 00179 } 00180 00181 /* now write remaining bits */ 00182 val = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) ); 00183 cur[0] |= (FT_Byte)( val >> shift ); 00184 00185 if ( count > space ) 00186 cur[1] |= (FT_Byte)( val << space ); 00187 00188 acc <<= count; 00189 loaded -= count; 00190 } 00191 00192 /* now, skip to next line */ 00193 if ( byte_padded ) 00194 { 00195 acc = 0; 00196 loaded = 0; /* clear accumulator on byte-padded lines */ 00197 } 00198 00199 line_buff += line_incr; 00200 } 00201 } 00202 00203 00204 static const FT_Frame_Field sbit_metrics_fields[] = 00205 { 00206 #undef FT_STRUCTURE 00207 #define FT_STRUCTURE TT_SBit_MetricsRec 00208 00209 FT_FRAME_START( 8 ), 00210 FT_FRAME_BYTE( height ), 00211 FT_FRAME_BYTE( width ), 00212 00213 FT_FRAME_CHAR( horiBearingX ), 00214 FT_FRAME_CHAR( horiBearingY ), 00215 FT_FRAME_BYTE( horiAdvance ), 00216 00217 FT_FRAME_CHAR( vertBearingX ), 00218 FT_FRAME_CHAR( vertBearingY ), 00219 FT_FRAME_BYTE( vertAdvance ), 00220 FT_FRAME_END 00221 }; 00222 00223 00224 /*************************************************************************/ 00225 /* */ 00226 /* <Function> */ 00227 /* Load_SBit_Const_Metrics */ 00228 /* */ 00229 /* <Description> */ 00230 /* Loads the metrics for `EBLC' index tables format 2 and 5. */ 00231 /* */ 00232 /* <Input> */ 00233 /* range :: The target range. */ 00234 /* */ 00235 /* stream :: The input stream. */ 00236 /* */ 00237 /* <Return> */ 00238 /* FreeType error code. 0 means success. */ 00239 /* */ 00240 static FT_Error 00241 Load_SBit_Const_Metrics( TT_SBit_Range range, 00242 FT_Stream stream ) 00243 { 00244 FT_Error error; 00245 00246 00247 if ( FT_READ_ULONG( range->image_size ) ) 00248 return error; 00249 00250 return FT_STREAM_READ_FIELDS( sbit_metrics_fields, &range->metrics ); 00251 } 00252 00253 00254 /*************************************************************************/ 00255 /* */ 00256 /* <Function> */ 00257 /* Load_SBit_Range_Codes */ 00258 /* */ 00259 /* <Description> */ 00260 /* Loads the range codes for `EBLC' index tables format 4 and 5. */ 00261 /* */ 00262 /* <Input> */ 00263 /* range :: The target range. */ 00264 /* */ 00265 /* stream :: The input stream. */ 00266 /* */ 00267 /* load_offsets :: A flag whether to load the glyph offset table. */ 00268 /* */ 00269 /* <Return> */ 00270 /* FreeType error code. 0 means success. */ 00271 /* */ 00272 static FT_Error 00273 Load_SBit_Range_Codes( TT_SBit_Range range, 00274 FT_Stream stream, 00275 FT_Bool load_offsets ) 00276 { 00277 FT_Error error; 00278 FT_ULong count, n, size; 00279 FT_Memory memory = stream->memory; 00280 00281 00282 if ( FT_READ_ULONG( count ) ) 00283 goto Exit; 00284 00285 range->num_glyphs = count; 00286 00287 /* Allocate glyph offsets table if needed */ 00288 if ( load_offsets ) 00289 { 00290 if ( FT_NEW_ARRAY( range->glyph_offsets, count ) ) 00291 goto Exit; 00292 00293 size = count * 4L; 00294 } 00295 else 00296 size = count * 2L; 00297 00298 /* Allocate glyph codes table and access frame */ 00299 if ( FT_NEW_ARRAY ( range->glyph_codes, count ) || 00300 FT_FRAME_ENTER( size ) ) 00301 goto Exit; 00302 00303 for ( n = 0; n < count; n++ ) 00304 { 00305 range->glyph_codes[n] = FT_GET_USHORT(); 00306 00307 if ( load_offsets ) 00308 range->glyph_offsets[n] = (FT_ULong)range->image_offset + 00309 FT_GET_USHORT(); 00310 } 00311 00312 FT_FRAME_EXIT(); 00313 00314 Exit: 00315 return error; 00316 } 00317 00318 00319 /*************************************************************************/ 00320 /* */ 00321 /* <Function> */ 00322 /* Load_SBit_Range */ 00323 /* */ 00324 /* <Description> */ 00325 /* Loads a given `EBLC' index/range table. */ 00326 /* */ 00327 /* <Input> */ 00328 /* range :: The target range. */ 00329 /* */ 00330 /* stream :: The input stream. */ 00331 /* */ 00332 /* <Return> */ 00333 /* FreeType error code. 0 means success. */ 00334 /* */ 00335 static FT_Error 00336 Load_SBit_Range( TT_SBit_Range range, 00337 FT_Stream stream ) 00338 { 00339 FT_Error error; 00340 FT_Memory memory = stream->memory; 00341 00342 00343 switch( range->index_format ) 00344 { 00345 case 1: /* variable metrics with 4-byte offsets */ 00346 case 3: /* variable metrics with 2-byte offsets */ 00347 { 00348 FT_ULong num_glyphs, n; 00349 FT_Int size_elem; 00350 FT_Bool large = FT_BOOL( range->index_format == 1 ); 00351 00352 00353 00354 if ( range->last_glyph < range->first_glyph ) 00355 { 00356 error = SFNT_Err_Invalid_File_Format; 00357 goto Exit; 00358 } 00359 00360 num_glyphs = range->last_glyph - range->first_glyph + 1L; 00361 range->num_glyphs = num_glyphs; 00362 num_glyphs++; /* XXX: BEWARE - see spec */ 00363 00364 size_elem = large ? 4 : 2; 00365 00366 if ( FT_NEW_ARRAY( range->glyph_offsets, num_glyphs ) || 00367 FT_FRAME_ENTER( num_glyphs * size_elem ) ) 00368 goto Exit; 00369 00370 for ( n = 0; n < num_glyphs; n++ ) 00371 range->glyph_offsets[n] = (FT_ULong)( range->image_offset + 00372 ( large ? FT_GET_ULONG() 00373 : FT_GET_USHORT() ) ); 00374 FT_FRAME_EXIT(); 00375 } 00376 break; 00377 00378 case 2: /* all glyphs have identical metrics */ 00379 error = Load_SBit_Const_Metrics( range, stream ); 00380 break; 00381 00382 case 4: 00383 error = Load_SBit_Range_Codes( range, stream, 1 ); 00384 break; 00385 00386 case 5: 00387 error = Load_SBit_Const_Metrics( range, stream ); 00388 if ( !error ) 00389 error = Load_SBit_Range_Codes( range, stream, 0 ); 00390 break; 00391 00392 default: 00393 error = SFNT_Err_Invalid_File_Format; 00394 } 00395 00396 Exit: 00397 return error; 00398 } 00399 00400 00401 /*************************************************************************/ 00402 /* */ 00403 /* <Function> */ 00404 /* tt_face_load_eblc */ 00405 /* */ 00406 /* <Description> */ 00407 /* Loads the table of embedded bitmap sizes for this face. */ 00408 /* */ 00409 /* <Input> */ 00410 /* face :: The target face object. */ 00411 /* */ 00412 /* stream :: The input stream. */ 00413 /* */ 00414 /* <Return> */ 00415 /* FreeType error code. 0 means success. */ 00416 /* */ 00417 FT_LOCAL_DEF( FT_Error ) 00418 tt_face_load_eblc( TT_Face face, 00419 FT_Stream stream ) 00420 { 00421 FT_Error error = SFNT_Err_Ok; 00422 FT_Memory memory = stream->memory; 00423 FT_Fixed version; 00424 FT_ULong num_strikes; 00425 FT_ULong table_base; 00426 00427 static const FT_Frame_Field sbit_line_metrics_fields[] = 00428 { 00429 #undef FT_STRUCTURE 00430 #define FT_STRUCTURE TT_SBit_LineMetricsRec 00431 00432 /* no FT_FRAME_START */ 00433 FT_FRAME_CHAR( ascender ), 00434 FT_FRAME_CHAR( descender ), 00435 FT_FRAME_BYTE( max_width ), 00436 00437 FT_FRAME_CHAR( caret_slope_numerator ), 00438 FT_FRAME_CHAR( caret_slope_denominator ), 00439 FT_FRAME_CHAR( caret_offset ), 00440 00441 FT_FRAME_CHAR( min_origin_SB ), 00442 FT_FRAME_CHAR( min_advance_SB ), 00443 FT_FRAME_CHAR( max_before_BL ), 00444 FT_FRAME_CHAR( min_after_BL ), 00445 FT_FRAME_CHAR( pads[0] ), 00446 FT_FRAME_CHAR( pads[1] ), 00447 FT_FRAME_END 00448 }; 00449 00450 static const FT_Frame_Field strike_start_fields[] = 00451 { 00452 #undef FT_STRUCTURE 00453 #define FT_STRUCTURE TT_SBit_StrikeRec 00454 00455 /* no FT_FRAME_START */ 00456 FT_FRAME_ULONG( ranges_offset ), 00457 FT_FRAME_SKIP_LONG, 00458 FT_FRAME_ULONG( num_ranges ), 00459 FT_FRAME_ULONG( color_ref ), 00460 FT_FRAME_END 00461 }; 00462 00463 static const FT_Frame_Field strike_end_fields[] = 00464 { 00465 /* no FT_FRAME_START */ 00466 FT_FRAME_USHORT( start_glyph ), 00467 FT_FRAME_USHORT( end_glyph ), 00468 FT_FRAME_BYTE ( x_ppem ), 00469 FT_FRAME_BYTE ( y_ppem ), 00470 FT_FRAME_BYTE ( bit_depth ), 00471 FT_FRAME_CHAR ( flags ), 00472 FT_FRAME_END 00473 }; 00474 00475 00476 face->num_sbit_strikes = 0; 00477 00478 /* this table is optional */ 00479 error = face->goto_table( face, TTAG_EBLC, stream, 0 ); 00480 if ( error ) 00481 error = face->goto_table( face, TTAG_bloc, stream, 0 ); 00482 if ( error ) 00483 goto Exit; 00484 00485 table_base = FT_STREAM_POS(); 00486 if ( FT_FRAME_ENTER( 8L ) ) 00487 goto Exit; 00488 00489 version = FT_GET_LONG(); 00490 num_strikes = FT_GET_ULONG(); 00491 00492 FT_FRAME_EXIT(); 00493 00494 /* check version number and strike count */ 00495 if ( version != 0x00020000L || 00496 num_strikes >= 0x10000L ) 00497 { 00498 FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version\n" )); 00499 error = SFNT_Err_Invalid_File_Format; 00500 00501 goto Exit; 00502 } 00503 00504 /* allocate the strikes table */ 00505 if ( FT_NEW_ARRAY( face->sbit_strikes, num_strikes ) ) 00506 goto Exit; 00507 00508 face->num_sbit_strikes = num_strikes; 00509 00510 /* now read each strike table separately */ 00511 { 00512 TT_SBit_Strike strike = face->sbit_strikes; 00513 FT_ULong count = num_strikes; 00514 00515 00516 if ( FT_FRAME_ENTER( 48L * num_strikes ) ) 00517 goto Exit; 00518 00519 while ( count > 0 ) 00520 { 00521 if ( FT_STREAM_READ_FIELDS( strike_start_fields, strike ) || 00522 FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->hori ) || 00523 FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->vert ) || 00524 FT_STREAM_READ_FIELDS( strike_end_fields, strike ) ) 00525 break; 00526 00527 count--; 00528 strike++; 00529 } 00530 00531 FT_FRAME_EXIT(); 00532 } 00533 00534 /* allocate the index ranges for each strike table */ 00535 { 00536 TT_SBit_Strike strike = face->sbit_strikes; 00537 FT_ULong count = num_strikes; 00538 00539 00540 while ( count > 0 ) 00541 { 00542 TT_SBit_Range range; 00543 FT_ULong count2 = strike->num_ranges; 00544 00545 00546 /* read each range */ 00547 if ( FT_STREAM_SEEK( table_base + strike->ranges_offset ) || 00548 FT_FRAME_ENTER( strike->num_ranges * 8L ) ) 00549 goto Exit; 00550 00551 if ( FT_NEW_ARRAY( strike->sbit_ranges, strike->num_ranges ) ) 00552 goto Exit; 00553 00554 range = strike->sbit_ranges; 00555 while ( count2 > 0 ) 00556 { 00557 range->first_glyph = FT_GET_USHORT(); 00558 range->last_glyph = FT_GET_USHORT(); 00559 range->table_offset = table_base + strike->ranges_offset + 00560 FT_GET_ULONG(); 00561 count2--; 00562 range++; 00563 } 00564 00565 FT_FRAME_EXIT(); 00566 00567 /* Now, read each index table */ 00568 count2 = strike->num_ranges; 00569 range = strike->sbit_ranges; 00570 while ( count2 > 0 ) 00571 { 00572 /* Read the header */ 00573 if ( FT_STREAM_SEEK( range->table_offset ) || 00574 FT_FRAME_ENTER( 8L ) ) 00575 goto Exit; 00576 00577 range->index_format = FT_GET_USHORT(); 00578 range->image_format = FT_GET_USHORT(); 00579 range->image_offset = FT_GET_ULONG(); 00580 00581 FT_FRAME_EXIT(); 00582 00583 error = Load_SBit_Range( range, stream ); 00584 if ( error ) 00585 goto Exit; 00586 00587 count2--; 00588 range++; 00589 } 00590 00591 count--; 00592 strike++; 00593 } 00594 } 00595 00596 Exit: 00597 return error; 00598 } 00599 00600 00601 /*************************************************************************/ 00602 /* */ 00603 /* <Function> */ 00604 /* tt_face_free_eblc */ 00605 /* */ 00606 /* <Description> */ 00607 /* Releases the embedded bitmap tables. */ 00608 /* */ 00609 /* <Input> */ 00610 /* face :: The target face object. */ 00611 /* */ 00612 FT_LOCAL_DEF( void ) 00613 tt_face_free_eblc( TT_Face face ) 00614 { 00615 FT_Memory memory = face->root.memory; 00616 TT_SBit_Strike strike = face->sbit_strikes; 00617 TT_SBit_Strike strike_limit = strike + face->num_sbit_strikes; 00618 00619 00620 if ( strike ) 00621 { 00622 for ( ; strike < strike_limit; strike++ ) 00623 { 00624 TT_SBit_Range range = strike->sbit_ranges; 00625 TT_SBit_Range range_limit = range + strike->num_ranges; 00626 00627 00628 if ( range ) 00629 { 00630 for ( ; range < range_limit; range++ ) 00631 { 00632 /* release the glyph offsets and codes tables */ 00633 /* where appropriate */ 00634 FT_FREE( range->glyph_offsets ); 00635 FT_FREE( range->glyph_codes ); 00636 } 00637 } 00638 FT_FREE( strike->sbit_ranges ); 00639 strike->num_ranges = 0; 00640 } 00641 FT_FREE( face->sbit_strikes ); 00642 } 00643 face->num_sbit_strikes = 0; 00644 } 00645 00646 00647 FT_LOCAL_DEF( FT_Error ) 00648 tt_face_set_sbit_strike( TT_Face face, 00649 FT_Size_Request req, 00650 FT_ULong* astrike_index ) 00651 { 00652 return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); 00653 } 00654 00655 00656 FT_LOCAL_DEF( FT_Error ) 00657 tt_face_load_strike_metrics( TT_Face face, 00658 FT_ULong strike_index, 00659 FT_Size_Metrics* metrics ) 00660 { 00661 TT_SBit_Strike strike; 00662 00663 00664 if ( strike_index >= face->num_sbit_strikes ) 00665 return SFNT_Err_Invalid_Argument; 00666 00667 strike = face->sbit_strikes + strike_index; 00668 00669 metrics->x_ppem = strike->x_ppem; 00670 metrics->y_ppem = strike->y_ppem; 00671 00672 metrics->ascender = strike->hori.ascender << 6; 00673 metrics->descender = strike->hori.descender << 6; 00674 00675 /* XXX: Is this correct? */ 00676 metrics->max_advance = ( strike->hori.min_origin_SB + 00677 strike->hori.max_width + 00678 strike->hori.min_advance_SB ) << 6; 00679 00680 metrics->height = metrics->ascender - metrics->descender; 00681 00682 return SFNT_Err_Ok; 00683 } 00684 00685 00686 /*************************************************************************/ 00687 /* */ 00688 /* <Function> */ 00689 /* find_sbit_range */ 00690 /* */ 00691 /* <Description> */ 00692 /* Scans a given strike's ranges and return, for a given glyph */ 00693 /* index, the corresponding sbit range, and `EBDT' offset. */ 00694 /* */ 00695 /* <Input> */ 00696 /* glyph_index :: The glyph index. */ 00697 /* */ 00698 /* strike :: The source/current sbit strike. */ 00699 /* */ 00700 /* <Output> */ 00701 /* arange :: The sbit range containing the glyph index. */ 00702 /* */ 00703 /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ 00704 /* */ 00705 /* <Return> */ 00706 /* FreeType error code. 0 means the glyph index was found. */ 00707 /* */ 00708 static FT_Error 00709 find_sbit_range( FT_UInt glyph_index, 00710 TT_SBit_Strike strike, 00711 TT_SBit_Range *arange, 00712 FT_ULong *aglyph_offset ) 00713 { 00714 TT_SBit_RangeRec *range, *range_limit; 00715 00716 00717 /* check whether the glyph index is within this strike's */ 00718 /* glyph range */ 00719 if ( glyph_index < (FT_UInt)strike->start_glyph || 00720 glyph_index > (FT_UInt)strike->end_glyph ) 00721 goto Fail; 00722 00723 /* scan all ranges in strike */ 00724 range = strike->sbit_ranges; 00725 range_limit = range + strike->num_ranges; 00726 if ( !range ) 00727 goto Fail; 00728 00729 for ( ; range < range_limit; range++ ) 00730 { 00731 if ( glyph_index >= (FT_UInt)range->first_glyph && 00732 glyph_index <= (FT_UInt)range->last_glyph ) 00733 { 00734 FT_UShort delta = (FT_UShort)( glyph_index - range->first_glyph ); 00735 00736 00737 switch ( range->index_format ) 00738 { 00739 case 1: 00740 case 3: 00741 *aglyph_offset = range->glyph_offsets[delta]; 00742 break; 00743 00744 case 2: 00745 *aglyph_offset = range->image_offset + 00746 range->image_size * delta; 00747 break; 00748 00749 case 4: 00750 case 5: 00751 { 00752 FT_ULong n; 00753 00754 00755 for ( n = 0; n < range->num_glyphs; n++ ) 00756 { 00757 if ( (FT_UInt)range->glyph_codes[n] == glyph_index ) 00758 { 00759 if ( range->index_format == 4 ) 00760 *aglyph_offset = range->glyph_offsets[n]; 00761 else 00762 *aglyph_offset = range->image_offset + 00763 n * range->image_size; 00764 goto Found; 00765 } 00766 } 00767 } 00768 00769 /* fall-through */ 00770 default: 00771 goto Fail; 00772 } 00773 00774 Found: 00775 /* return successfully! */ 00776 *arange = range; 00777 return SFNT_Err_Ok; 00778 } 00779 } 00780 00781 Fail: 00782 *arange = 0; 00783 *aglyph_offset = 0; 00784 00785 return SFNT_Err_Invalid_Argument; 00786 } 00787 00788 00789 /*************************************************************************/ 00790 /* */ 00791 /* <Function> */ 00792 /* tt_find_sbit_image */ 00793 /* */ 00794 /* <Description> */ 00795 /* Checks whether an embedded bitmap (an `sbit') exists for a given */ 00796 /* glyph, at a given strike. */ 00797 /* */ 00798 /* <Input> */ 00799 /* face :: The target face object. */ 00800 /* */ 00801 /* glyph_index :: The glyph index. */ 00802 /* */ 00803 /* strike_index :: The current strike index. */ 00804 /* */ 00805 /* <Output> */ 00806 /* arange :: The SBit range containing the glyph index. */ 00807 /* */ 00808 /* astrike :: The SBit strike containing the glyph index. */ 00809 /* */ 00810 /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ 00811 /* */ 00812 /* <Return> */ 00813 /* FreeType error code. 0 means success. Returns */ 00814 /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */ 00815 /* glyph. */ 00816 /* */ 00817 FT_LOCAL( FT_Error ) 00818 tt_find_sbit_image( TT_Face face, 00819 FT_UInt glyph_index, 00820 FT_ULong strike_index, 00821 TT_SBit_Range *arange, 00822 TT_SBit_Strike *astrike, 00823 FT_ULong *aglyph_offset ) 00824 { 00825 FT_Error error; 00826 TT_SBit_Strike strike; 00827 00828 00829 if ( !face->sbit_strikes || 00830 ( face->num_sbit_strikes <= strike_index ) ) 00831 goto Fail; 00832 00833 strike = &face->sbit_strikes[strike_index]; 00834 00835 error = find_sbit_range( glyph_index, strike, 00836 arange, aglyph_offset ); 00837 if ( error ) 00838 goto Fail; 00839 00840 *astrike = strike; 00841 00842 return SFNT_Err_Ok; 00843 00844 Fail: 00845 /* no embedded bitmap for this glyph in face */ 00846 *arange = 0; 00847 *astrike = 0; 00848 *aglyph_offset = 0; 00849 00850 return SFNT_Err_Invalid_Argument; 00851 } 00852 00853 00854 /*************************************************************************/ 00855 /* */ 00856 /* <Function> */ 00857 /* tt_load_sbit_metrics */ 00858 /* */ 00859 /* <Description> */ 00860 /* Gets the big metrics for a given SBit. */ 00861 /* */ 00862 /* <Input> */ 00863 /* stream :: The input stream. */ 00864 /* */ 00865 /* range :: The SBit range containing the glyph. */ 00866 /* */ 00867 /* <Output> */ 00868 /* big_metrics :: A big SBit metrics structure for the glyph. */ 00869 /* */ 00870 /* <Return> */ 00871 /* FreeType error code. 0 means success. */ 00872 /* */ 00873 /* <Note> */ 00874 /* The stream cursor must be positioned at the glyph's offset within */ 00875 /* the `EBDT' table before the call. */ 00876 /* */ 00877 /* If the image format uses variable metrics, the stream cursor is */ 00878 /* positioned just after the metrics header in the `EBDT' table on */ 00879 /* function exit. */ 00880 /* */ 00881 FT_LOCAL( FT_Error ) 00882 tt_load_sbit_metrics( FT_Stream stream, 00883 TT_SBit_Range range, 00884 TT_SBit_Metrics metrics ) 00885 { 00886 FT_Error error = SFNT_Err_Ok; 00887 00888 00889 switch ( range->image_format ) 00890 { 00891 case 1: 00892 case 2: 00893 case 8: 00894 /* variable small metrics */ 00895 { 00896 TT_SBit_SmallMetricsRec smetrics; 00897 00898 static const FT_Frame_Field sbit_small_metrics_fields[] = 00899 { 00900 #undef FT_STRUCTURE 00901 #define FT_STRUCTURE TT_SBit_SmallMetricsRec 00902 00903 FT_FRAME_START( 5 ), 00904 FT_FRAME_BYTE( height ), 00905 FT_FRAME_BYTE( width ), 00906 FT_FRAME_CHAR( bearingX ), 00907 FT_FRAME_CHAR( bearingY ), 00908 FT_FRAME_BYTE( advance ), 00909 FT_FRAME_END 00910 }; 00911 00912 00913 /* read small metrics */ 00914 if ( FT_STREAM_READ_FIELDS( sbit_small_metrics_fields, &smetrics ) ) 00915 goto Exit; 00916 00917 /* convert it to a big metrics */ 00918 metrics->height = smetrics.height; 00919 metrics->width = smetrics.width; 00920 metrics->horiBearingX = smetrics.bearingX; 00921 metrics->horiBearingY = smetrics.bearingY; 00922 metrics->horiAdvance = smetrics.advance; 00923 00924 /* these metrics are made up at a higher level when */ 00925 /* needed. */ 00926 metrics->vertBearingX = 0; 00927 metrics->vertBearingY = 0; 00928 metrics->vertAdvance = 0; 00929 } 00930 break; 00931 00932 case 6: 00933 case 7: 00934 case 9: 00935 /* variable big metrics */ 00936 if ( FT_STREAM_READ_FIELDS( sbit_metrics_fields, metrics ) ) 00937 goto Exit; 00938 break; 00939 00940 case 5: 00941 default: /* constant metrics */ 00942 if ( range->index_format == 2 || range->index_format == 5 ) 00943 *metrics = range->metrics; 00944 else 00945 return SFNT_Err_Invalid_File_Format; 00946 } 00947 00948 Exit: 00949 return error; 00950 } 00951 00952 00953 /*************************************************************************/ 00954 /* */ 00955 /* <Function> */ 00956 /* crop_bitmap */ 00957 /* */ 00958 /* <Description> */ 00959 /* Crops a bitmap to its tightest bounding box, and adjusts its */ 00960 /* metrics. */ 00961 /* */ 00962 /* <InOut> */ 00963 /* map :: The bitmap. */ 00964 /* */ 00965 /* metrics :: The corresponding metrics structure. */ 00966 /* */ 00967 static void 00968 crop_bitmap( FT_Bitmap* map, 00969 TT_SBit_Metrics metrics ) 00970 { 00971 /***********************************************************************/ 00972 /* */ 00973 /* In this situation, some bounding boxes of embedded bitmaps are too */ 00974 /* large. We need to crop it to a reasonable size. */ 00975 /* */ 00976 /* --------- */ 00977 /* | | ----- */ 00978 /* | *** | |***| */ 00979 /* | * | | * | */ 00980 /* | * | ------> | * | */ 00981 /* | * | | * | */ 00982 /* | * | | * | */ 00983 /* | *** | |***| */ 00984 /* --------- ----- */ 00985 /* */ 00986 /***********************************************************************/ 00987 00988 FT_Int rows, count; 00989 FT_Long line_len; 00990 FT_Byte* line; 00991 00992 00993 /***********************************************************************/ 00994 /* */ 00995 /* first of all, check the top-most lines of the bitmap, and remove */ 00996 /* them if they're empty. */ 00997 /* */ 00998 { 00999 line = (FT_Byte*)map->buffer; 01000 rows = map->rows; 01001 line_len = map->pitch; 01002 01003 01004 for ( count = 0; count < rows; count++ ) 01005 { 01006 FT_Byte* cur = line; 01007 FT_Byte* limit = line + line_len; 01008 01009 01010 for ( ; cur < limit; cur++ ) 01011 if ( cur[0] ) 01012 goto Found_Top; 01013 01014 /* the current line was empty - skip to next one */ 01015 line = limit; 01016 } 01017 01018 Found_Top: 01019 /* check that we have at least one filled line */ 01020 if ( count >= rows ) 01021 goto Empty_Bitmap; 01022 01023 /* now, crop the empty upper lines */ 01024 if ( count > 0 ) 01025 { 01026 line = (FT_Byte*)map->buffer; 01027 01028 FT_MEM_MOVE( line, line + count * line_len, 01029 ( rows - count ) * line_len ); 01030 01031 metrics->height = (FT_Byte)( metrics->height - count ); 01032 metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count ); 01033 metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count ); 01034 01035 map->rows -= count; 01036 rows -= count; 01037 } 01038 } 01039 01040 /***********************************************************************/ 01041 /* */ 01042 /* second, crop the lower lines */ 01043 /* */ 01044 { 01045 line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len; 01046 01047 for ( count = 0; count < rows; count++ ) 01048 { 01049 FT_Byte* cur = line; 01050 FT_Byte* limit = line + line_len; 01051 01052 01053 for ( ; cur < limit; cur++ ) 01054 if ( cur[0] ) 01055 goto Found_Bottom; 01056 01057 /* the current line was empty - skip to previous one */ 01058 line -= line_len; 01059 } 01060 01061 Found_Bottom: 01062 if ( count > 0 ) 01063 { 01064 metrics->height = (FT_Byte)( metrics->height - count ); 01065 rows -= count; 01066 map->rows -= count; 01067 } 01068 } 01069 01070 /***********************************************************************/ 01071 /* */ 01072 /* third, get rid of the space on the left side of the glyph */ 01073 /* */ 01074 do 01075 { 01076 FT_Byte* limit; 01077 01078 01079 line = (FT_Byte*)map->buffer; 01080 limit = line + rows * line_len; 01081 01082 for ( ; line < limit; line += line_len ) 01083 if ( line[0] & 0x80 ) 01084 goto Found_Left; 01085 01086 /* shift the whole glyph one pixel to the left */ 01087 line = (FT_Byte*)map->buffer; 01088 limit = line + rows * line_len; 01089 01090 for ( ; line < limit; line += line_len ) 01091 { 01092 FT_Int n, width = map->width; 01093 FT_Byte old; 01094 FT_Byte* cur = line; 01095 01096 01097 old = (FT_Byte)(cur[0] << 1); 01098 for ( n = 8; n < width; n += 8 ) 01099 { 01100 FT_Byte val; 01101 01102 01103 val = cur[1]; 01104 cur[0] = (FT_Byte)( old | ( val >> 7 ) ); 01105 old = (FT_Byte)( val << 1 ); 01106 cur++; 01107 } 01108 cur[0] = old; 01109 } 01110 01111 map->width--; 01112 metrics->horiBearingX++; 01113 metrics->vertBearingX++; 01114 metrics->width--; 01115 01116 } while ( map->width > 0 ); 01117 01118 Found_Left: 01119 01120 /***********************************************************************/ 01121 /* */ 01122 /* finally, crop the bitmap width to get rid of the space on the right */ 01123 /* side of the glyph. */ 01124 /* */ 01125 do 01126 { 01127 FT_Int right = map->width - 1; 01128 FT_Byte* limit; 01129 FT_Byte mask; 01130 01131 01132 line = (FT_Byte*)map->buffer + ( right >> 3 ); 01133 limit = line + rows * line_len; 01134 mask = (FT_Byte)( 0x80 >> ( right & 7 ) ); 01135 01136 for ( ; line < limit; line += line_len ) 01137 if ( line[0] & mask ) 01138 goto Found_Right; 01139 01140 /* crop the whole glyph to the right */ 01141 map->width--; 01142 metrics->width--; 01143 01144 } while ( map->width > 0 ); 01145 01146 Found_Right: 01147 /* all right, the bitmap was cropped */ 01148 return; 01149 01150 Empty_Bitmap: 01151 map->width = 0; 01152 map->rows = 0; 01153 map->pitch = 0; 01154 map->pixel_mode = FT_PIXEL_MODE_MONO; 01155 } 01156 01157 01158 static FT_Error 01159 Load_SBit_Single( FT_Bitmap* map, 01160 FT_Int x_offset, 01161 FT_Int y_offset, 01162 FT_Int pix_bits, 01163 FT_UShort image_format, 01164 TT_SBit_Metrics metrics, 01165 FT_Stream stream ) 01166 { 01167 FT_Error error; 01168 01169 01170 /* check that the source bitmap fits into the target pixmap */ 01171 if ( x_offset < 0 || x_offset + metrics->width > map->width || 01172 y_offset < 0 || y_offset + metrics->height > map->rows ) 01173 { 01174 error = SFNT_Err_Invalid_Argument; 01175 01176 goto Exit; 01177 } 01178 01179 { 01180 FT_Int glyph_width = metrics->width; 01181 FT_Int glyph_height = metrics->height; 01182 FT_Int glyph_size; 01183 FT_Int line_bits = pix_bits * glyph_width; 01184 FT_Bool pad_bytes = 0; 01185 01186 01187 /* compute size of glyph image */ 01188 switch ( image_format ) 01189 { 01190 case 1: /* byte-padded formats */ 01191 case 6: 01192 { 01193 FT_Int line_length; 01194 01195 01196 switch ( pix_bits ) 01197 { 01198 case 1: 01199 line_length = ( glyph_width + 7 ) >> 3; 01200 break; 01201 case 2: 01202 line_length = ( glyph_width + 3 ) >> 2; 01203 break; 01204 case 4: 01205 line_length = ( glyph_width + 1 ) >> 1; 01206 break; 01207 default: 01208 line_length = glyph_width; 01209 } 01210 01211 glyph_size = glyph_height * line_length; 01212 pad_bytes = 1; 01213 } 01214 break; 01215 01216 case 2: 01217 case 5: 01218 case 7: 01219 line_bits = glyph_width * pix_bits; 01220 glyph_size = ( glyph_height * line_bits + 7 ) >> 3; 01221 break; 01222 01223 default: /* invalid format */ 01224 return SFNT_Err_Invalid_File_Format; 01225 } 01226 01227 /* Now read data and draw glyph into target pixmap */ 01228 if ( FT_FRAME_ENTER( glyph_size ) ) 01229 goto Exit; 01230 01231 /* don't forget to multiply `x_offset' by `map->pix_bits' as */ 01232 /* the sbit blitter doesn't make a difference between pixmap */ 01233 /* depths. */ 01234 blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes, 01235 x_offset * pix_bits, y_offset, metrics->height ); 01236 01237 FT_FRAME_EXIT(); 01238 } 01239 01240 Exit: 01241 return error; 01242 } 01243 01244 01245 static FT_Error 01246 Load_SBit_Image( TT_SBit_Strike strike, 01247 TT_SBit_Range range, 01248 FT_ULong ebdt_pos, 01249 FT_ULong glyph_offset, 01250 FT_GlyphSlot slot, 01251 FT_Int x_offset, 01252 FT_Int y_offset, 01253 FT_Stream stream, 01254 TT_SBit_Metrics metrics, 01255 FT_Int depth ) 01256 { 01257 FT_Memory memory = stream->memory; 01258 FT_Bitmap* map = &slot->bitmap; 01259 FT_Error error; 01260 01261 01262 /* place stream at beginning of glyph data and read metrics */ 01263 if ( FT_STREAM_SEEK( ebdt_pos + glyph_offset ) ) 01264 goto Exit; 01265 01266 error = tt_load_sbit_metrics( stream, range, metrics ); 01267 if ( error ) 01268 goto Exit; 01269 01270 /* This function is recursive. At the top-level call, we */ 01271 /* compute the dimensions of the higher-level glyph to */ 01272 /* allocate the final pixmap buffer. */ 01273 if ( depth == 0 ) 01274 { 01275 FT_Long size; 01276 01277 01278 map->width = metrics->width; 01279 map->rows = metrics->height; 01280 01281 switch ( strike->bit_depth ) 01282 { 01283 case 1: 01284 map->pixel_mode = FT_PIXEL_MODE_MONO; 01285 map->pitch = ( map->width + 7 ) >> 3; 01286 break; 01287 01288 case 2: 01289 map->pixel_mode = FT_PIXEL_MODE_GRAY2; 01290 map->pitch = ( map->width + 3 ) >> 2; 01291 break; 01292 01293 case 4: 01294 map->pixel_mode = FT_PIXEL_MODE_GRAY4; 01295 map->pitch = ( map->width + 1 ) >> 1; 01296 break; 01297 01298 case 8: 01299 map->pixel_mode = FT_PIXEL_MODE_GRAY; 01300 map->pitch = map->width; 01301 break; 01302 01303 default: 01304 return SFNT_Err_Invalid_File_Format; 01305 } 01306 01307 size = map->rows * map->pitch; 01308 01309 /* check that there is no empty image */ 01310 if ( size == 0 ) 01311 goto Exit; /* exit successfully! */ 01312 01313 error = ft_glyphslot_alloc_bitmap( slot, size ); 01314 if (error) 01315 goto Exit; 01316 } 01317 01318 switch ( range->image_format ) 01319 { 01320 case 1: /* single sbit image - load it */ 01321 case 2: 01322 case 5: 01323 case 6: 01324 case 7: 01325 return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth, 01326 range->image_format, metrics, stream ); 01327 01328 case 8: /* compound format */ 01329 if ( FT_STREAM_SKIP( 1L ) ) 01330 { 01331 error = SFNT_Err_Invalid_Stream_Skip; 01332 goto Exit; 01333 } 01334 /* fallthrough */ 01335 01336 case 9: 01337 break; 01338 01339 default: /* invalid image format */ 01340 return SFNT_Err_Invalid_File_Format; 01341 } 01342 01343 /* All right, we have a compound format. First of all, read */ 01344 /* the array of elements. */ 01345 { 01346 TT_SBit_Component components; 01347 TT_SBit_Component comp; 01348 FT_UShort num_components, count; 01349 01350 01351 if ( FT_READ_USHORT( num_components ) || 01352 FT_NEW_ARRAY( components, num_components ) ) 01353 goto Exit; 01354 01355 count = num_components; 01356 01357 if ( FT_FRAME_ENTER( 4L * num_components ) ) 01358 goto Fail_Memory; 01359 01360 for ( comp = components; count > 0; count--, comp++ ) 01361 { 01362 comp->glyph_code = FT_GET_USHORT(); 01363 comp->x_offset = FT_GET_CHAR(); 01364 comp->y_offset = FT_GET_CHAR(); 01365 } 01366 01367 FT_FRAME_EXIT(); 01368 01369 /* Now recursively load each element glyph */ 01370 count = num_components; 01371 comp = components; 01372 for ( ; count > 0; count--, comp++ ) 01373 { 01374 TT_SBit_Range elem_range; 01375 TT_SBit_MetricsRec elem_metrics; 01376 FT_ULong elem_offset; 01377 01378 01379 /* find the range for this element */ 01380 error = find_sbit_range( comp->glyph_code, 01381 strike, 01382 &elem_range, 01383 &elem_offset ); 01384 if ( error ) 01385 goto Fail_Memory; 01386 01387 /* now load the element, recursively */ 01388 error = Load_SBit_Image( strike, 01389 elem_range, 01390 ebdt_pos, 01391 elem_offset, 01392 slot, 01393 x_offset + comp->x_offset, 01394 y_offset + comp->y_offset, 01395 stream, 01396 &elem_metrics, 01397 depth + 1 ); 01398 if ( error ) 01399 goto Fail_Memory; 01400 } 01401 01402 Fail_Memory: 01403 FT_FREE( components ); 01404 } 01405 01406 Exit: 01407 return error; 01408 } 01409 01410 01411 /*************************************************************************/ 01412 /* */ 01413 /* <Function> */ 01414 /* tt_face_load_sbit_image */ 01415 /* */ 01416 /* <Description> */ 01417 /* Loads a given glyph sbit image from the font resource. This also */ 01418 /* returns its metrics. */ 01419 /* */ 01420 /* <Input> */ 01421 /* face :: The target face object. */ 01422 /* */ 01423 /* strike_index :: The current strike index. */ 01424 /* */ 01425 /* glyph_index :: The current glyph index. */ 01426 /* */ 01427 /* load_flags :: The glyph load flags (the code checks for the flag */ 01428 /* FT_LOAD_CROP_BITMAP). */ 01429 /* */ 01430 /* stream :: The input stream. */ 01431 /* */ 01432 /* <Output> */ 01433 /* map :: The target pixmap. */ 01434 /* */ 01435 /* metrics :: A big sbit metrics structure for the glyph image. */ 01436 /* */ 01437 /* <Return> */ 01438 /* FreeType error code. 0 means success. Returns an error if no */ 01439 /* glyph sbit exists for the index. */ 01440 /* */ 01441 /* <Note> */ 01442 /* The `map.buffer' field is always freed before the glyph is loaded. */ 01443 /* */ 01444 FT_LOCAL_DEF( FT_Error ) 01445 tt_face_load_sbit_image( TT_Face face, 01446 FT_ULong strike_index, 01447 FT_UInt glyph_index, 01448 FT_UInt load_flags, 01449 FT_Stream stream, 01450 FT_Bitmap *map, 01451 TT_SBit_MetricsRec *metrics ) 01452 { 01453 FT_Error error; 01454 FT_ULong ebdt_pos, glyph_offset; 01455 01456 TT_SBit_Strike strike; 01457 TT_SBit_Range range; 01458 01459 01460 /* Check whether there is a glyph sbit for the current index */ 01461 error = tt_find_sbit_image( face, glyph_index, strike_index, 01462 &range, &strike, &glyph_offset ); 01463 if ( error ) 01464 goto Exit; 01465 01466 /* now, find the location of the `EBDT' table in */ 01467 /* the font file */ 01468 error = face->goto_table( face, TTAG_EBDT, stream, 0 ); 01469 if ( error ) 01470 error = face->goto_table( face, TTAG_bdat, stream, 0 ); 01471 if ( error ) 01472 goto Exit; 01473 01474 ebdt_pos = FT_STREAM_POS(); 01475 01476 error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset, 01477 face->root.glyph, 0, 0, stream, metrics, 0 ); 01478 if ( error ) 01479 goto Exit; 01480 01481 /* setup vertical metrics if needed */ 01482 if ( strike->flags & 1 ) 01483 { 01484 /* in case of a horizontal strike only */ 01485 FT_Int advance; 01486 01487 01488 advance = strike->hori.ascender - strike->hori.descender; 01489 01490 /* some heuristic values */ 01491 01492 metrics->vertBearingX = (FT_Char)(-metrics->width / 2 ); 01493 metrics->vertBearingY = (FT_Char)( ( advance - metrics->height ) / 2 ); 01494 metrics->vertAdvance = (FT_Char)( advance * 12 / 10 ); 01495 } 01496 01497 /* Crop the bitmap now, unless specified otherwise */ 01498 if ( load_flags & FT_LOAD_CROP_BITMAP ) 01499 crop_bitmap( map, metrics ); 01500 01501 Exit: 01502 return error; 01503 } 01504 01505 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ 01506 01507 01508 /* END */ Generated on Sun May 27 2012 04:34:02 for ReactOS by
1.7.6.1
|