Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenaflatin2.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* aflatin.c */ 00004 /* */ 00005 /* Auto-fitter hinting routines for latin script (body). */ 00006 /* */ 00007 /* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 00019 #include FT_ADVANCES_H 00020 00021 #include "aflatin.h" 00022 #include "aflatin2.h" 00023 #include "aferrors.h" 00024 00025 00026 #ifdef AF_USE_WARPER 00027 #include "afwarp.h" 00028 #endif 00029 00030 FT_LOCAL_DEF( FT_Error ) 00031 af_latin2_hints_compute_segments( AF_GlyphHints hints, 00032 AF_Dimension dim ); 00033 00034 FT_LOCAL_DEF( void ) 00035 af_latin2_hints_link_segments( AF_GlyphHints hints, 00036 AF_Dimension dim ); 00037 00038 /*************************************************************************/ 00039 /*************************************************************************/ 00040 /***** *****/ 00041 /***** L A T I N G L O B A L M E T R I C S *****/ 00042 /***** *****/ 00043 /*************************************************************************/ 00044 /*************************************************************************/ 00045 00046 FT_LOCAL_DEF( void ) 00047 af_latin2_metrics_init_widths( AF_LatinMetrics metrics, 00048 FT_Face face, 00049 FT_ULong charcode ) 00050 { 00051 /* scan the array of segments in each direction */ 00052 AF_GlyphHintsRec hints[1]; 00053 00054 00055 af_glyph_hints_init( hints, face->memory ); 00056 00057 metrics->axis[AF_DIMENSION_HORZ].width_count = 0; 00058 metrics->axis[AF_DIMENSION_VERT].width_count = 0; 00059 00060 { 00061 FT_Error error; 00062 FT_UInt glyph_index; 00063 int dim; 00064 AF_LatinMetricsRec dummy[1]; 00065 AF_Scaler scaler = &dummy->root.scaler; 00066 00067 00068 glyph_index = FT_Get_Char_Index( face, charcode ); 00069 if ( glyph_index == 0 ) 00070 goto Exit; 00071 00072 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); 00073 if ( error || face->glyph->outline.n_points <= 0 ) 00074 goto Exit; 00075 00076 FT_ZERO( dummy ); 00077 00078 dummy->units_per_em = metrics->units_per_em; 00079 scaler->x_scale = scaler->y_scale = 0x10000L; 00080 scaler->x_delta = scaler->y_delta = 0; 00081 scaler->face = face; 00082 scaler->render_mode = FT_RENDER_MODE_NORMAL; 00083 scaler->flags = 0; 00084 00085 af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); 00086 00087 error = af_glyph_hints_reload( hints, &face->glyph->outline ); 00088 if ( error ) 00089 goto Exit; 00090 00091 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 00092 { 00093 AF_LatinAxis axis = &metrics->axis[dim]; 00094 AF_AxisHints axhints = &hints->axis[dim]; 00095 AF_Segment seg, limit, link; 00096 FT_UInt num_widths = 0; 00097 00098 00099 error = af_latin2_hints_compute_segments( hints, 00100 (AF_Dimension)dim ); 00101 if ( error ) 00102 goto Exit; 00103 00104 af_latin2_hints_link_segments( hints, 00105 (AF_Dimension)dim ); 00106 00107 seg = axhints->segments; 00108 limit = seg + axhints->num_segments; 00109 00110 for ( ; seg < limit; seg++ ) 00111 { 00112 link = seg->link; 00113 00114 /* we only consider stem segments there! */ 00115 if ( link && link->link == seg && link > seg ) 00116 { 00117 FT_Pos dist; 00118 00119 00120 dist = seg->pos - link->pos; 00121 if ( dist < 0 ) 00122 dist = -dist; 00123 00124 if ( num_widths < AF_LATIN_MAX_WIDTHS ) 00125 axis->widths[ num_widths++ ].org = dist; 00126 } 00127 } 00128 00129 af_sort_widths( num_widths, axis->widths ); 00130 axis->width_count = num_widths; 00131 } 00132 00133 Exit: 00134 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 00135 { 00136 AF_LatinAxis axis = &metrics->axis[dim]; 00137 FT_Pos stdw; 00138 00139 00140 stdw = ( axis->width_count > 0 ) 00141 ? axis->widths[0].org 00142 : AF_LATIN_CONSTANT( metrics, 50 ); 00143 00144 /* let's try 20% of the smallest width */ 00145 axis->edge_distance_threshold = stdw / 5; 00146 axis->standard_width = stdw; 00147 axis->extra_light = 0; 00148 } 00149 } 00150 00151 af_glyph_hints_done( hints ); 00152 } 00153 00154 00155 00156 #define AF_LATIN_MAX_TEST_CHARACTERS 12 00157 00158 00159 static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES][AF_LATIN_MAX_TEST_CHARACTERS+1] = 00160 { 00161 "THEZOCQS", 00162 "HEZLOCUS", 00163 "fijkdbh", 00164 "xzroesc", 00165 "xzroesc", 00166 "pqgjy" 00167 }; 00168 00169 00170 static void 00171 af_latin2_metrics_init_blues( AF_LatinMetrics metrics, 00172 FT_Face face ) 00173 { 00174 FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; 00175 FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; 00176 FT_Int num_flats; 00177 FT_Int num_rounds; 00178 FT_Int bb; 00179 AF_LatinBlue blue; 00180 FT_Error error; 00181 AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; 00182 FT_GlyphSlot glyph = face->glyph; 00183 00184 00185 /* we compute the blues simply by loading each character from the */ 00186 /* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */ 00187 /* bottom-most points (depending on `AF_IS_TOP_BLUE') */ 00188 00189 AF_LOG(( "blue zones computation\n" )); 00190 AF_LOG(( "------------------------------------------------\n" )); 00191 00192 for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) 00193 { 00194 const char* p = af_latin2_blue_chars[bb]; 00195 const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS; 00196 FT_Pos* blue_ref; 00197 FT_Pos* blue_shoot; 00198 00199 00200 AF_LOG(( "blue %3d: ", bb )); 00201 00202 num_flats = 0; 00203 num_rounds = 0; 00204 00205 for ( ; p < limit && *p; p++ ) 00206 { 00207 FT_UInt glyph_index; 00208 FT_Int best_point, best_y, best_first, best_last; 00209 FT_Vector* points; 00210 FT_Bool round; 00211 00212 00213 AF_LOG(( "'%c'", *p )); 00214 00215 /* load the character in the face -- skip unknown or empty ones */ 00216 glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); 00217 if ( glyph_index == 0 ) 00218 continue; 00219 00220 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); 00221 if ( error || glyph->outline.n_points <= 0 ) 00222 continue; 00223 00224 /* now compute min or max point indices and coordinates */ 00225 points = glyph->outline.points; 00226 best_point = -1; 00227 best_y = 0; /* make compiler happy */ 00228 best_first = 0; /* ditto */ 00229 best_last = 0; /* ditto */ 00230 00231 { 00232 FT_Int nn; 00233 FT_Int first = 0; 00234 FT_Int last = -1; 00235 00236 00237 for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ ) 00238 { 00239 FT_Int old_best_point = best_point; 00240 FT_Int pp; 00241 00242 00243 last = glyph->outline.contours[nn]; 00244 00245 /* Avoid single-point contours since they are never rasterized. */ 00246 /* In some fonts, they correspond to mark attachment points */ 00247 /* which are way outside of the glyph's real outline. */ 00248 if ( last == first ) 00249 continue; 00250 00251 if ( AF_LATIN_IS_TOP_BLUE( bb ) ) 00252 { 00253 for ( pp = first; pp <= last; pp++ ) 00254 if ( best_point < 0 || points[pp].y > best_y ) 00255 { 00256 best_point = pp; 00257 best_y = points[pp].y; 00258 } 00259 } 00260 else 00261 { 00262 for ( pp = first; pp <= last; pp++ ) 00263 if ( best_point < 0 || points[pp].y < best_y ) 00264 { 00265 best_point = pp; 00266 best_y = points[pp].y; 00267 } 00268 } 00269 00270 if ( best_point != old_best_point ) 00271 { 00272 best_first = first; 00273 best_last = last; 00274 } 00275 } 00276 AF_LOG(( "%5d", best_y )); 00277 } 00278 00279 /* now check whether the point belongs to a straight or round */ 00280 /* segment; we first need to find in which contour the extremum */ 00281 /* lies, then inspect its previous and next points */ 00282 { 00283 FT_Int start, end, prev, next; 00284 FT_Pos dist; 00285 00286 00287 /* now look for the previous and next points that are not on the */ 00288 /* same Y coordinate. Threshold the `closeness'... */ 00289 start = end = best_point; 00290 00291 do 00292 { 00293 prev = start-1; 00294 if ( prev < best_first ) 00295 prev = best_last; 00296 00297 dist = points[prev].y - best_y; 00298 if ( dist < -5 || dist > 5 ) 00299 break; 00300 00301 start = prev; 00302 00303 } while ( start != best_point ); 00304 00305 do 00306 { 00307 next = end+1; 00308 if ( next > best_last ) 00309 next = best_first; 00310 00311 dist = points[next].y - best_y; 00312 if ( dist < -5 || dist > 5 ) 00313 break; 00314 00315 end = next; 00316 00317 } while ( end != best_point ); 00318 00319 /* now, set the `round' flag depending on the segment's kind */ 00320 round = FT_BOOL( 00321 FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON || 00322 FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON ); 00323 00324 AF_LOG(( "%c ", round ? 'r' : 'f' )); 00325 } 00326 00327 if ( round ) 00328 rounds[num_rounds++] = best_y; 00329 else 00330 flats[num_flats++] = best_y; 00331 } 00332 00333 AF_LOG(( "\n" )); 00334 00335 if ( num_flats == 0 && num_rounds == 0 ) 00336 { 00337 /* 00338 * we couldn't find a single glyph to compute this blue zone, 00339 * we will simply ignore it then 00340 */ 00341 AF_LOG(( "empty\n" )); 00342 continue; 00343 } 00344 00345 /* we have computed the contents of the `rounds' and `flats' tables, */ 00346 /* now determine the reference and overshoot position of the blue -- */ 00347 /* we simply take the median value after a simple sort */ 00348 af_sort_pos( num_rounds, rounds ); 00349 af_sort_pos( num_flats, flats ); 00350 00351 blue = & axis->blues[axis->blue_count]; 00352 blue_ref = & blue->ref.org; 00353 blue_shoot = & blue->shoot.org; 00354 00355 axis->blue_count++; 00356 00357 if ( num_flats == 0 ) 00358 { 00359 *blue_ref = 00360 *blue_shoot = rounds[num_rounds / 2]; 00361 } 00362 else if ( num_rounds == 0 ) 00363 { 00364 *blue_ref = 00365 *blue_shoot = flats[num_flats / 2]; 00366 } 00367 else 00368 { 00369 *blue_ref = flats[num_flats / 2]; 00370 *blue_shoot = rounds[num_rounds / 2]; 00371 } 00372 00373 /* there are sometimes problems: if the overshoot position of top */ 00374 /* zones is under its reference position, or the opposite for bottom */ 00375 /* zones. We must thus check everything there and correct the errors */ 00376 if ( *blue_shoot != *blue_ref ) 00377 { 00378 FT_Pos ref = *blue_ref; 00379 FT_Pos shoot = *blue_shoot; 00380 FT_Bool over_ref = FT_BOOL( shoot > ref ); 00381 00382 00383 if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) 00384 *blue_shoot = *blue_ref = ( shoot + ref ) / 2; 00385 } 00386 00387 blue->flags = 0; 00388 if ( AF_LATIN_IS_TOP_BLUE( bb ) ) 00389 blue->flags |= AF_LATIN_BLUE_TOP; 00390 00391 /* 00392 * The following flags is used later to adjust the y and x scales 00393 * in order to optimize the pixel grid alignment of the top of small 00394 * letters. 00395 */ 00396 if ( bb == AF_LATIN_BLUE_SMALL_TOP ) 00397 blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; 00398 00399 AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); 00400 } 00401 00402 return; 00403 } 00404 00405 00406 FT_LOCAL_DEF( void ) 00407 af_latin2_metrics_check_digits( AF_LatinMetrics metrics, 00408 FT_Face face ) 00409 { 00410 FT_UInt i; 00411 FT_Bool started = 0, same_width = 1; 00412 FT_Fixed advance, old_advance = 0; 00413 00414 00415 /* check whether all ASCII digits have the same advance width; */ 00416 /* digit `0' is 0x30 in all supported charmaps */ 00417 for ( i = 0x30; i <= 0x39; i++ ) 00418 { 00419 FT_UInt glyph_index; 00420 00421 00422 glyph_index = FT_Get_Char_Index( face, i ); 00423 if ( glyph_index == 0 ) 00424 continue; 00425 00426 if ( FT_Get_Advance( face, glyph_index, 00427 FT_LOAD_NO_SCALE | 00428 FT_LOAD_NO_HINTING | 00429 FT_LOAD_IGNORE_TRANSFORM, 00430 &advance ) ) 00431 continue; 00432 00433 if ( started ) 00434 { 00435 if ( advance != old_advance ) 00436 { 00437 same_width = 0; 00438 break; 00439 } 00440 } 00441 else 00442 { 00443 old_advance = advance; 00444 started = 1; 00445 } 00446 } 00447 00448 metrics->root.digits_have_same_width = same_width; 00449 } 00450 00451 00452 FT_LOCAL_DEF( FT_Error ) 00453 af_latin2_metrics_init( AF_LatinMetrics metrics, 00454 FT_Face face ) 00455 { 00456 FT_Error error = AF_Err_Ok; 00457 FT_CharMap oldmap = face->charmap; 00458 FT_UInt ee; 00459 00460 static const FT_Encoding latin_encodings[] = 00461 { 00462 FT_ENCODING_UNICODE, 00463 FT_ENCODING_APPLE_ROMAN, 00464 FT_ENCODING_ADOBE_STANDARD, 00465 FT_ENCODING_ADOBE_LATIN_1, 00466 FT_ENCODING_NONE /* end of list */ 00467 }; 00468 00469 00470 metrics->units_per_em = face->units_per_EM; 00471 00472 /* do we have a latin charmap in there? */ 00473 for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ ) 00474 { 00475 error = FT_Select_Charmap( face, latin_encodings[ee] ); 00476 if ( !error ) 00477 break; 00478 } 00479 00480 if ( !error ) 00481 { 00482 /* For now, compute the standard width and height from the `o'. */ 00483 af_latin2_metrics_init_widths( metrics, face, 'o' ); 00484 af_latin2_metrics_init_blues( metrics, face ); 00485 af_latin2_metrics_check_digits( metrics, face ); 00486 } 00487 00488 FT_Set_Charmap( face, oldmap ); 00489 return AF_Err_Ok; 00490 } 00491 00492 00493 static void 00494 af_latin2_metrics_scale_dim( AF_LatinMetrics metrics, 00495 AF_Scaler scaler, 00496 AF_Dimension dim ) 00497 { 00498 FT_Fixed scale; 00499 FT_Pos delta; 00500 AF_LatinAxis axis; 00501 FT_UInt nn; 00502 00503 00504 if ( dim == AF_DIMENSION_HORZ ) 00505 { 00506 scale = scaler->x_scale; 00507 delta = scaler->x_delta; 00508 } 00509 else 00510 { 00511 scale = scaler->y_scale; 00512 delta = scaler->y_delta; 00513 } 00514 00515 axis = &metrics->axis[dim]; 00516 00517 if ( axis->org_scale == scale && axis->org_delta == delta ) 00518 return; 00519 00520 axis->org_scale = scale; 00521 axis->org_delta = delta; 00522 00523 /* 00524 * correct Y scale to optimize the alignment of the top of small 00525 * letters to the pixel grid 00526 */ 00527 if ( dim == AF_DIMENSION_VERT ) 00528 { 00529 AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT]; 00530 AF_LatinBlue blue = NULL; 00531 00532 00533 for ( nn = 0; nn < vaxis->blue_count; nn++ ) 00534 { 00535 if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) 00536 { 00537 blue = &vaxis->blues[nn]; 00538 break; 00539 } 00540 } 00541 00542 if ( blue ) 00543 { 00544 FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); 00545 FT_Pos fitted = ( scaled + 40 ) & ~63; 00546 00547 #if 1 00548 if ( scaled != fitted ) 00549 { 00550 scale = FT_MulDiv( scale, fitted, scaled ); 00551 AF_LOG(( "== scaled x-top = %.2g fitted = %.2g, scaling = %.4g\n", scaled/64.0, fitted/64.0, (fitted*1.0)/scaled )); 00552 } 00553 #endif 00554 } 00555 } 00556 00557 axis->scale = scale; 00558 axis->delta = delta; 00559 00560 if ( dim == AF_DIMENSION_HORZ ) 00561 { 00562 metrics->root.scaler.x_scale = scale; 00563 metrics->root.scaler.x_delta = delta; 00564 } 00565 else 00566 { 00567 metrics->root.scaler.y_scale = scale; 00568 metrics->root.scaler.y_delta = delta; 00569 } 00570 00571 /* scale the standard widths */ 00572 for ( nn = 0; nn < axis->width_count; nn++ ) 00573 { 00574 AF_Width width = axis->widths + nn; 00575 00576 00577 width->cur = FT_MulFix( width->org, scale ); 00578 width->fit = width->cur; 00579 } 00580 00581 /* an extra-light axis corresponds to a standard width that is */ 00582 /* smaller than 0.75 pixels */ 00583 axis->extra_light = 00584 (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); 00585 00586 if ( dim == AF_DIMENSION_VERT ) 00587 { 00588 /* scale the blue zones */ 00589 for ( nn = 0; nn < axis->blue_count; nn++ ) 00590 { 00591 AF_LatinBlue blue = &axis->blues[nn]; 00592 FT_Pos dist; 00593 00594 00595 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; 00596 blue->ref.fit = blue->ref.cur; 00597 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; 00598 blue->shoot.fit = blue->shoot.cur; 00599 blue->flags &= ~AF_LATIN_BLUE_ACTIVE; 00600 00601 /* a blue zone is only active if it is less than 3/4 pixels tall */ 00602 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); 00603 if ( dist <= 48 && dist >= -48 ) 00604 { 00605 FT_Pos delta1, delta2; 00606 00607 delta1 = blue->shoot.org - blue->ref.org; 00608 delta2 = delta1; 00609 if ( delta1 < 0 ) 00610 delta2 = -delta2; 00611 00612 delta2 = FT_MulFix( delta2, scale ); 00613 00614 if ( delta2 < 32 ) 00615 delta2 = 0; 00616 else if ( delta2 < 64 ) 00617 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); 00618 else 00619 delta2 = FT_PIX_ROUND( delta2 ); 00620 00621 if ( delta1 < 0 ) 00622 delta2 = -delta2; 00623 00624 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); 00625 blue->shoot.fit = blue->ref.fit + delta2; 00626 00627 AF_LOG(( ">> activating blue zone %d: ref.cur=%.2g ref.fit=%.2g shoot.cur=%.2g shoot.fit=%.2g\n", 00628 nn, blue->ref.cur/64.0, blue->ref.fit/64.0, 00629 blue->shoot.cur/64.0, blue->shoot.fit/64.0 )); 00630 00631 blue->flags |= AF_LATIN_BLUE_ACTIVE; 00632 } 00633 } 00634 } 00635 } 00636 00637 00638 FT_LOCAL_DEF( void ) 00639 af_latin2_metrics_scale( AF_LatinMetrics metrics, 00640 AF_Scaler scaler ) 00641 { 00642 metrics->root.scaler.render_mode = scaler->render_mode; 00643 metrics->root.scaler.face = scaler->face; 00644 00645 af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); 00646 af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); 00647 } 00648 00649 00650 /*************************************************************************/ 00651 /*************************************************************************/ 00652 /***** *****/ 00653 /***** L A T I N G L Y P H A N A L Y S I S *****/ 00654 /***** *****/ 00655 /*************************************************************************/ 00656 /*************************************************************************/ 00657 00658 #define SORT_SEGMENTS 00659 00660 FT_LOCAL_DEF( FT_Error ) 00661 af_latin2_hints_compute_segments( AF_GlyphHints hints, 00662 AF_Dimension dim ) 00663 { 00664 AF_AxisHints axis = &hints->axis[dim]; 00665 FT_Memory memory = hints->memory; 00666 FT_Error error = AF_Err_Ok; 00667 AF_Segment segment = NULL; 00668 AF_SegmentRec seg0; 00669 AF_Point* contour = hints->contours; 00670 AF_Point* contour_limit = contour + hints->num_contours; 00671 AF_Direction major_dir, segment_dir; 00672 00673 00674 FT_ZERO( &seg0 ); 00675 seg0.score = 32000; 00676 seg0.flags = AF_EDGE_NORMAL; 00677 00678 major_dir = (AF_Direction)FT_ABS( axis->major_dir ); 00679 segment_dir = major_dir; 00680 00681 axis->num_segments = 0; 00682 00683 /* set up (u,v) in each point */ 00684 if ( dim == AF_DIMENSION_HORZ ) 00685 { 00686 AF_Point point = hints->points; 00687 AF_Point limit = point + hints->num_points; 00688 00689 00690 for ( ; point < limit; point++ ) 00691 { 00692 point->u = point->fx; 00693 point->v = point->fy; 00694 } 00695 } 00696 else 00697 { 00698 AF_Point point = hints->points; 00699 AF_Point limit = point + hints->num_points; 00700 00701 00702 for ( ; point < limit; point++ ) 00703 { 00704 point->u = point->fy; 00705 point->v = point->fx; 00706 } 00707 } 00708 00709 /* do each contour separately */ 00710 for ( ; contour < contour_limit; contour++ ) 00711 { 00712 AF_Point point = contour[0]; 00713 AF_Point start = point; 00714 AF_Point last = point->prev; 00715 00716 00717 if ( point == last ) /* skip singletons -- just in case */ 00718 continue; 00719 00720 /* already on an edge ?, backtrack to find its start */ 00721 if ( FT_ABS( point->in_dir ) == major_dir ) 00722 { 00723 point = point->prev; 00724 00725 while ( point->in_dir == start->in_dir ) 00726 point = point->prev; 00727 } 00728 else /* otherwise, find first segment start, if any */ 00729 { 00730 while ( FT_ABS( point->out_dir ) != major_dir ) 00731 { 00732 point = point->next; 00733 00734 if ( point == start ) 00735 goto NextContour; 00736 } 00737 } 00738 00739 start = point; 00740 00741 for (;;) 00742 { 00743 AF_Point first; 00744 FT_Pos min_u, min_v, max_u, max_v; 00745 00746 /* we're at the start of a new segment */ 00747 FT_ASSERT( FT_ABS( point->out_dir ) == major_dir && 00748 point->in_dir != point->out_dir ); 00749 first = point; 00750 00751 min_u = max_u = point->u; 00752 min_v = max_v = point->v; 00753 00754 point = point->next; 00755 00756 while ( point->out_dir == first->out_dir ) 00757 { 00758 point = point->next; 00759 00760 if ( point->u < min_u ) 00761 min_u = point->u; 00762 00763 if ( point->u > max_u ) 00764 max_u = point->u; 00765 } 00766 00767 if ( point->v < min_v ) 00768 min_v = point->v; 00769 00770 if ( point->v > max_v ) 00771 max_v = point->v; 00772 00773 /* record new segment */ 00774 error = af_axis_hints_new_segment( axis, memory, &segment ); 00775 if ( error ) 00776 goto Exit; 00777 00778 segment[0] = seg0; 00779 segment->dir = first->out_dir; 00780 segment->first = first; 00781 segment->last = point; 00782 segment->contour = contour; 00783 segment->pos = (FT_Short)(( min_u + max_u ) >> 1); 00784 segment->min_coord = (FT_Short) min_v; 00785 segment->max_coord = (FT_Short) max_v; 00786 segment->height = (FT_Short)(max_v - min_v); 00787 00788 /* a segment is round if it doesn't have successive */ 00789 /* on-curve points. */ 00790 { 00791 AF_Point pt = first; 00792 AF_Point last = point; 00793 AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); 00794 AF_Flags f1; 00795 00796 00797 segment->flags &= ~AF_EDGE_ROUND; 00798 00799 for ( ; pt != last; f0 = f1 ) 00800 { 00801 pt = pt->next; 00802 f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); 00803 00804 if ( !f0 && !f1 ) 00805 break; 00806 00807 if ( pt == last ) 00808 segment->flags |= AF_EDGE_ROUND; 00809 } 00810 } 00811 00812 /* this can happen in the case of a degenerate contour 00813 * e.g. a 2-point vertical contour 00814 */ 00815 if ( point == start ) 00816 break; 00817 00818 /* jump to the start of the next segment, if any */ 00819 while ( FT_ABS(point->out_dir) != major_dir ) 00820 { 00821 point = point->next; 00822 00823 if ( point == start ) 00824 goto NextContour; 00825 } 00826 } 00827 00828 NextContour: 00829 ; 00830 } /* contours */ 00831 00832 /* now slightly increase the height of segments when this makes */ 00833 /* sense -- this is used to better detect and ignore serifs */ 00834 { 00835 AF_Segment segments = axis->segments; 00836 AF_Segment segments_end = segments + axis->num_segments; 00837 00838 00839 for ( segment = segments; segment < segments_end; segment++ ) 00840 { 00841 AF_Point first = segment->first; 00842 AF_Point last = segment->last; 00843 AF_Point p; 00844 FT_Pos first_v = first->v; 00845 FT_Pos last_v = last->v; 00846 00847 00848 if ( first == last ) 00849 continue; 00850 00851 if ( first_v < last_v ) 00852 { 00853 p = first->prev; 00854 if ( p->v < first_v ) 00855 segment->height = (FT_Short)( segment->height + 00856 ( ( first_v - p->v ) >> 1 ) ); 00857 00858 p = last->next; 00859 if ( p->v > last_v ) 00860 segment->height = (FT_Short)( segment->height + 00861 ( ( p->v - last_v ) >> 1 ) ); 00862 } 00863 else 00864 { 00865 p = first->prev; 00866 if ( p->v > first_v ) 00867 segment->height = (FT_Short)( segment->height + 00868 ( ( p->v - first_v ) >> 1 ) ); 00869 00870 p = last->next; 00871 if ( p->v < last_v ) 00872 segment->height = (FT_Short)( segment->height + 00873 ( ( last_v - p->v ) >> 1 ) ); 00874 } 00875 } 00876 } 00877 00878 #ifdef AF_SORT_SEGMENTS 00879 /* place all segments with a negative direction to the start 00880 * of the array, used to speed up segment linking later... 00881 */ 00882 { 00883 AF_Segment segments = axis->segments; 00884 FT_UInt count = axis->num_segments; 00885 FT_UInt ii, jj; 00886 00887 for (ii = 0; ii < count; ii++) 00888 { 00889 if ( segments[ii].dir > 0 ) 00890 { 00891 for (jj = ii+1; jj < count; jj++) 00892 { 00893 if ( segments[jj].dir < 0 ) 00894 { 00895 AF_SegmentRec tmp; 00896 00897 tmp = segments[ii]; 00898 segments[ii] = segments[jj]; 00899 segments[jj] = tmp; 00900 00901 break; 00902 } 00903 } 00904 00905 if ( jj == count ) 00906 break; 00907 } 00908 } 00909 axis->mid_segments = ii; 00910 } 00911 #endif 00912 00913 Exit: 00914 return error; 00915 } 00916 00917 00918 FT_LOCAL_DEF( void ) 00919 af_latin2_hints_link_segments( AF_GlyphHints hints, 00920 AF_Dimension dim ) 00921 { 00922 AF_AxisHints axis = &hints->axis[dim]; 00923 AF_Segment segments = axis->segments; 00924 AF_Segment segment_limit = segments + axis->num_segments; 00925 #ifdef AF_SORT_SEGMENTS 00926 AF_Segment segment_mid = segments + axis->mid_segments; 00927 #endif 00928 FT_Pos len_threshold, len_score; 00929 AF_Segment seg1, seg2; 00930 00931 00932 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); 00933 if ( len_threshold == 0 ) 00934 len_threshold = 1; 00935 00936 len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); 00937 00938 #ifdef AF_SORT_SEGMENTS 00939 for ( seg1 = segments; seg1 < segment_mid; seg1++ ) 00940 { 00941 if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) 00942 continue; 00943 00944 for ( seg2 = segment_mid; seg2 < segment_limit; seg2++ ) 00945 #else 00946 /* now compare each segment to the others */ 00947 for ( seg1 = segments; seg1 < segment_limit; seg1++ ) 00948 { 00949 /* the fake segments are introduced to hint the metrics -- */ 00950 /* we must never link them to anything */ 00951 if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) 00952 continue; 00953 00954 for ( seg2 = segments; seg2 < segment_limit; seg2++ ) 00955 if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos ) 00956 #endif 00957 { 00958 FT_Pos pos1 = seg1->pos; 00959 FT_Pos pos2 = seg2->pos; 00960 FT_Pos dist = pos2 - pos1; 00961 00962 00963 if ( dist < 0 ) 00964 continue; 00965 00966 { 00967 FT_Pos min = seg1->min_coord; 00968 FT_Pos max = seg1->max_coord; 00969 FT_Pos len, score; 00970 00971 00972 if ( min < seg2->min_coord ) 00973 min = seg2->min_coord; 00974 00975 if ( max > seg2->max_coord ) 00976 max = seg2->max_coord; 00977 00978 len = max - min; 00979 if ( len >= len_threshold ) 00980 { 00981 score = dist + len_score / len; 00982 if ( score < seg1->score ) 00983 { 00984 seg1->score = score; 00985 seg1->link = seg2; 00986 } 00987 00988 if ( score < seg2->score ) 00989 { 00990 seg2->score = score; 00991 seg2->link = seg1; 00992 } 00993 } 00994 } 00995 } 00996 } 00997 #if 0 00998 } 00999 #endif 01000 01001 /* now, compute the `serif' segments */ 01002 for ( seg1 = segments; seg1 < segment_limit; seg1++ ) 01003 { 01004 seg2 = seg1->link; 01005 01006 if ( seg2 ) 01007 { 01008 if ( seg2->link != seg1 ) 01009 { 01010 seg1->link = 0; 01011 seg1->serif = seg2->link; 01012 } 01013 } 01014 } 01015 } 01016 01017 01018 FT_LOCAL_DEF( FT_Error ) 01019 af_latin2_hints_compute_edges( AF_GlyphHints hints, 01020 AF_Dimension dim ) 01021 { 01022 AF_AxisHints axis = &hints->axis[dim]; 01023 FT_Error error = AF_Err_Ok; 01024 FT_Memory memory = hints->memory; 01025 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; 01026 01027 AF_Segment segments = axis->segments; 01028 AF_Segment segment_limit = segments + axis->num_segments; 01029 AF_Segment seg; 01030 01031 AF_Direction up_dir; 01032 FT_Fixed scale; 01033 FT_Pos edge_distance_threshold; 01034 FT_Pos segment_length_threshold; 01035 01036 01037 axis->num_edges = 0; 01038 01039 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale 01040 : hints->y_scale; 01041 01042 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP 01043 : AF_DIR_RIGHT; 01044 01045 /* 01046 * We want to ignore very small (mostly serif) segments, we do that 01047 * by ignoring those that whose length is less than a given fraction 01048 * of the standard width. If there is no standard width, we ignore 01049 * those that are less than a given size in pixels 01050 * 01051 * also, unlink serif segments that are linked to segments farther 01052 * than 50% of the standard width 01053 */ 01054 if ( dim == AF_DIMENSION_HORZ ) 01055 { 01056 if ( laxis->width_count > 0 ) 01057 segment_length_threshold = (laxis->standard_width * 10 ) >> 4; 01058 else 01059 segment_length_threshold = FT_DivFix( 64, hints->y_scale ); 01060 } 01061 else 01062 segment_length_threshold = 0; 01063 01064 /*********************************************************************/ 01065 /* */ 01066 /* We will begin by generating a sorted table of edges for the */ 01067 /* current direction. To do so, we simply scan each segment and try */ 01068 /* to find an edge in our table that corresponds to its position. */ 01069 /* */ 01070 /* If no edge is found, we create and insert a new edge in the */ 01071 /* sorted table. Otherwise, we simply add the segment to the edge's */ 01072 /* list which will be processed in the second step to compute the */ 01073 /* edge's properties. */ 01074 /* */ 01075 /* Note that the edges table is sorted along the segment/edge */ 01076 /* position. */ 01077 /* */ 01078 /*********************************************************************/ 01079 01080 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, 01081 scale ); 01082 if ( edge_distance_threshold > 64 / 4 ) 01083 edge_distance_threshold = 64 / 4; 01084 01085 edge_distance_threshold = FT_DivFix( edge_distance_threshold, 01086 scale ); 01087 01088 for ( seg = segments; seg < segment_limit; seg++ ) 01089 { 01090 AF_Edge found = 0; 01091 FT_Int ee; 01092 01093 01094 if ( seg->height < segment_length_threshold ) 01095 continue; 01096 01097 /* A special case for serif edges: If they are smaller than */ 01098 /* 1.5 pixels we ignore them. */ 01099 if ( seg->serif ) 01100 { 01101 FT_Pos dist = seg->serif->pos - seg->pos; 01102 01103 if (dist < 0) 01104 dist = -dist; 01105 01106 if (dist >= laxis->standard_width >> 1) 01107 { 01108 /* unlink this serif, it is too distant from its reference stem */ 01109 seg->serif = NULL; 01110 } 01111 else if ( 2*seg->height < 3 * segment_length_threshold ) 01112 continue; 01113 } 01114 01115 /* look for an edge corresponding to the segment */ 01116 for ( ee = 0; ee < axis->num_edges; ee++ ) 01117 { 01118 AF_Edge edge = axis->edges + ee; 01119 FT_Pos dist; 01120 01121 01122 dist = seg->pos - edge->fpos; 01123 if ( dist < 0 ) 01124 dist = -dist; 01125 01126 if ( dist < edge_distance_threshold && edge->dir == seg->dir ) 01127 { 01128 found = edge; 01129 break; 01130 } 01131 } 01132 01133 if ( !found ) 01134 { 01135 AF_Edge edge; 01136 01137 01138 /* insert a new edge in the list and */ 01139 /* sort according to the position */ 01140 error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, memory, &edge ); 01141 if ( error ) 01142 goto Exit; 01143 01144 /* add the segment to the new edge's list */ 01145 FT_ZERO( edge ); 01146 01147 edge->first = seg; 01148 edge->last = seg; 01149 edge->fpos = seg->pos; 01150 edge->dir = seg->dir; 01151 edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); 01152 seg->edge_next = seg; 01153 } 01154 else 01155 { 01156 /* if an edge was found, simply add the segment to the edge's */ 01157 /* list */ 01158 seg->edge_next = found->first; 01159 found->last->edge_next = seg; 01160 found->last = seg; 01161 } 01162 } 01163 01164 01165 /*********************************************************************/ 01166 /* */ 01167 /* Good, we will now compute each edge's properties according to */ 01168 /* segments found on its position. Basically, these are: */ 01169 /* */ 01170 /* - edge's main direction */ 01171 /* - stem edge, serif edge or both (which defaults to stem then) */ 01172 /* - rounded edge, straight or both (which defaults to straight) */ 01173 /* - link for edge */ 01174 /* */ 01175 /*********************************************************************/ 01176 01177 /* first of all, set the `edge' field in each segment -- this is */ 01178 /* required in order to compute edge links */ 01179 01180 /* 01181 * Note that removing this loop and setting the `edge' field of each 01182 * segment directly in the code above slows down execution speed for 01183 * some reasons on platforms like the Sun. 01184 */ 01185 { 01186 AF_Edge edges = axis->edges; 01187 AF_Edge edge_limit = edges + axis->num_edges; 01188 AF_Edge edge; 01189 01190 01191 for ( edge = edges; edge < edge_limit; edge++ ) 01192 { 01193 seg = edge->first; 01194 if ( seg ) 01195 do 01196 { 01197 seg->edge = edge; 01198 seg = seg->edge_next; 01199 01200 } while ( seg != edge->first ); 01201 } 01202 01203 /* now, compute each edge properties */ 01204 for ( edge = edges; edge < edge_limit; edge++ ) 01205 { 01206 FT_Int is_round = 0; /* does it contain round segments? */ 01207 FT_Int is_straight = 0; /* does it contain straight segments? */ 01208 FT_Pos ups = 0; /* number of upwards segments */ 01209 FT_Pos downs = 0; /* number of downwards segments */ 01210 01211 01212 seg = edge->first; 01213 01214 do 01215 { 01216 FT_Bool is_serif; 01217 01218 01219 /* check for roundness of segment */ 01220 if ( seg->flags & AF_EDGE_ROUND ) 01221 is_round++; 01222 else 01223 is_straight++; 01224 01225 /* check for segment direction */ 01226 if ( seg->dir == up_dir ) 01227 ups += seg->max_coord-seg->min_coord; 01228 else 01229 downs += seg->max_coord-seg->min_coord; 01230 01231 /* check for links -- if seg->serif is set, then seg->link must */ 01232 /* be ignored */ 01233 is_serif = (FT_Bool)( seg->serif && 01234 seg->serif->edge && 01235 seg->serif->edge != edge ); 01236 01237 if ( ( seg->link && seg->link->edge != NULL ) || is_serif ) 01238 { 01239 AF_Edge edge2; 01240 AF_Segment seg2; 01241 01242 01243 edge2 = edge->link; 01244 seg2 = seg->link; 01245 01246 if ( is_serif ) 01247 { 01248 seg2 = seg->serif; 01249 edge2 = edge->serif; 01250 } 01251 01252 if ( edge2 ) 01253 { 01254 FT_Pos edge_delta; 01255 FT_Pos seg_delta; 01256 01257 01258 edge_delta = edge->fpos - edge2->fpos; 01259 if ( edge_delta < 0 ) 01260 edge_delta = -edge_delta; 01261 01262 seg_delta = seg->pos - seg2->pos; 01263 if ( seg_delta < 0 ) 01264 seg_delta = -seg_delta; 01265 01266 if ( seg_delta < edge_delta ) 01267 edge2 = seg2->edge; 01268 } 01269 else 01270 edge2 = seg2->edge; 01271 01272 if ( is_serif ) 01273 { 01274 edge->serif = edge2; 01275 edge2->flags |= AF_EDGE_SERIF; 01276 } 01277 else 01278 edge->link = edge2; 01279 } 01280 01281 seg = seg->edge_next; 01282 01283 } while ( seg != edge->first ); 01284 01285 /* set the round/straight flags */ 01286 edge->flags = AF_EDGE_NORMAL; 01287 01288 if ( is_round > 0 && is_round >= is_straight ) 01289 edge->flags |= AF_EDGE_ROUND; 01290 01291 #if 0 01292 /* set the edge's main direction */ 01293 edge->dir = AF_DIR_NONE; 01294 01295 if ( ups > downs ) 01296 edge->dir = (FT_Char)up_dir; 01297 01298 else if ( ups < downs ) 01299 edge->dir = (FT_Char)-up_dir; 01300 01301 else if ( ups == downs ) 01302 edge->dir = 0; /* both up and down! */ 01303 #endif 01304 01305 /* gets rid of serifs if link is set */ 01306 /* XXX: This gets rid of many unpleasant artefacts! */ 01307 /* Example: the `c' in cour.pfa at size 13 */ 01308 01309 if ( edge->serif && edge->link ) 01310 edge->serif = 0; 01311 } 01312 } 01313 01314 Exit: 01315 return error; 01316 } 01317 01318 01319 FT_LOCAL_DEF( FT_Error ) 01320 af_latin2_hints_detect_features( AF_GlyphHints hints, 01321 AF_Dimension dim ) 01322 { 01323 FT_Error error; 01324 01325 01326 error = af_latin2_hints_compute_segments( hints, dim ); 01327 if ( !error ) 01328 { 01329 af_latin2_hints_link_segments( hints, dim ); 01330 01331 error = af_latin2_hints_compute_edges( hints, dim ); 01332 } 01333 return error; 01334 } 01335 01336 01337 FT_LOCAL_DEF( void ) 01338 af_latin2_hints_compute_blue_edges( AF_GlyphHints hints, 01339 AF_LatinMetrics metrics ) 01340 { 01341 AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ]; 01342 AF_Edge edge = axis->edges; 01343 AF_Edge edge_limit = edge + axis->num_edges; 01344 AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ]; 01345 FT_Fixed scale = latin->scale; 01346 FT_Pos best_dist0; /* initial threshold */ 01347 01348 01349 /* compute the initial threshold as a fraction of the EM size */ 01350 best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); 01351 01352 if ( best_dist0 > 64 / 2 ) 01353 best_dist0 = 64 / 2; 01354 01355 /* compute which blue zones are active, i.e. have their scaled */ 01356 /* size < 3/4 pixels */ 01357 01358 /* for each horizontal edge search the blue zone which is closest */ 01359 for ( ; edge < edge_limit; edge++ ) 01360 { 01361 FT_Int bb; 01362 AF_Width best_blue = NULL; 01363 FT_Pos best_dist = best_dist0; 01364 01365 for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) 01366 { 01367 AF_LatinBlue blue = latin->blues + bb; 01368 FT_Bool is_top_blue, is_major_dir; 01369 01370 01371 /* skip inactive blue zones (i.e., those that are too small) */ 01372 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) 01373 continue; 01374 01375 /* if it is a top zone, check for right edges -- if it is a bottom */ 01376 /* zone, check for left edges */ 01377 /* */ 01378 /* of course, that's for TrueType */ 01379 is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); 01380 is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); 01381 01382 /* if it is a top zone, the edge must be against the major */ 01383 /* direction; if it is a bottom zone, it must be in the major */ 01384 /* direction */ 01385 if ( is_top_blue ^ is_major_dir ) 01386 { 01387 FT_Pos dist; 01388 AF_Width compare; 01389 01390 01391 /* if it's a rounded edge, compare it to the overshoot position */ 01392 /* if it's a flat edge, compare it to the reference position */ 01393 if ( edge->flags & AF_EDGE_ROUND ) 01394 compare = &blue->shoot; 01395 else 01396 compare = &blue->ref; 01397 01398 dist = edge->fpos - compare->org; 01399 if (dist < 0) 01400 dist = -dist; 01401 01402 dist = FT_MulFix( dist, scale ); 01403 if ( dist < best_dist ) 01404 { 01405 best_dist = dist; 01406 best_blue = compare; 01407 } 01408 01409 #if 0 01410 /* now, compare it to the overshoot position if the edge is */ 01411 /* rounded, and if the edge is over the reference position of a */ 01412 /* top zone, or under the reference position of a bottom zone */ 01413 if ( edge->flags & AF_EDGE_ROUND && dist != 0 ) 01414 { 01415 FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); 01416 01417 01418 if ( is_top_blue ^ is_under_ref ) 01419 { 01420 blue = latin->blues + bb; 01421 dist = edge->fpos - blue->shoot.org; 01422 if ( dist < 0 ) 01423 dist = -dist; 01424 01425 dist = FT_MulFix( dist, scale ); 01426 if ( dist < best_dist ) 01427 { 01428 best_dist = dist; 01429 best_blue = & blue->shoot; 01430 } 01431 } 01432 } 01433 #endif 01434 } 01435 } 01436 01437 if ( best_blue ) 01438 edge->blue_edge = best_blue; 01439 } 01440 } 01441 01442 01443 static FT_Error 01444 af_latin2_hints_init( AF_GlyphHints hints, 01445 AF_LatinMetrics metrics ) 01446 { 01447 FT_Render_Mode mode; 01448 FT_UInt32 scaler_flags, other_flags; 01449 FT_Face face = metrics->root.scaler.face; 01450 01451 01452 af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics ); 01453 01454 /* 01455 * correct x_scale and y_scale if needed, since they may have 01456 * been modified `af_latin2_metrics_scale_dim' above 01457 */ 01458 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; 01459 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; 01460 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; 01461 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; 01462 01463 /* compute flags depending on render mode, etc. */ 01464 mode = metrics->root.scaler.render_mode; 01465 01466 #if 0 /* #ifdef AF_USE_WARPER */ 01467 if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) 01468 { 01469 metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; 01470 } 01471 #endif 01472 01473 scaler_flags = hints->scaler_flags; 01474 other_flags = 0; 01475 01476 /* 01477 * We snap the width of vertical stems for the monochrome and 01478 * horizontal LCD rendering targets only. 01479 */ 01480 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) 01481 other_flags |= AF_LATIN_HINTS_HORZ_SNAP; 01482 01483 /* 01484 * We snap the width of horizontal stems for the monochrome and 01485 * vertical LCD rendering targets only. 01486 */ 01487 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) 01488 other_flags |= AF_LATIN_HINTS_VERT_SNAP; 01489 01490 /* 01491 * We adjust stems to full pixels only if we don't use the `light' mode. 01492 */ 01493 if ( mode != FT_RENDER_MODE_LIGHT ) 01494 other_flags |= AF_LATIN_HINTS_STEM_ADJUST; 01495 01496 if ( mode == FT_RENDER_MODE_MONO ) 01497 other_flags |= AF_LATIN_HINTS_MONO; 01498 01499 /* 01500 * In `light' hinting mode we disable horizontal hinting completely. 01501 * We also do it if the face is italic. 01502 */ 01503 if ( mode == FT_RENDER_MODE_LIGHT || 01504 (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 ) 01505 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; 01506 01507 hints->scaler_flags = scaler_flags; 01508 hints->other_flags = other_flags; 01509 01510 return 0; 01511 } 01512 01513 01514 /*************************************************************************/ 01515 /*************************************************************************/ 01516 /***** *****/ 01517 /***** L A T I N G L Y P H G R I D - F I T T I N G *****/ 01518 /***** *****/ 01519 /*************************************************************************/ 01520 /*************************************************************************/ 01521 01522 /* snap a given width in scaled coordinates to one of the */ 01523 /* current standard widths */ 01524 01525 static FT_Pos 01526 af_latin2_snap_width( AF_Width widths, 01527 FT_Int count, 01528 FT_Pos width ) 01529 { 01530 int n; 01531 FT_Pos best = 64 + 32 + 2; 01532 FT_Pos reference = width; 01533 FT_Pos scaled; 01534 01535 01536 for ( n = 0; n < count; n++ ) 01537 { 01538 FT_Pos w; 01539 FT_Pos dist; 01540 01541 01542 w = widths[n].cur; 01543 dist = width - w; 01544 if ( dist < 0 ) 01545 dist = -dist; 01546 if ( dist < best ) 01547 { 01548 best = dist; 01549 reference = w; 01550 } 01551 } 01552 01553 scaled = FT_PIX_ROUND( reference ); 01554 01555 if ( width >= reference ) 01556 { 01557 if ( width < scaled + 48 ) 01558 width = reference; 01559 } 01560 else 01561 { 01562 if ( width > scaled - 48 ) 01563 width = reference; 01564 } 01565 01566 return width; 01567 } 01568 01569 01570 /* compute the snapped width of a given stem */ 01571 01572 static FT_Pos 01573 af_latin2_compute_stem_width( AF_GlyphHints hints, 01574 AF_Dimension dim, 01575 FT_Pos width, 01576 AF_Edge_Flags base_flags, 01577 AF_Edge_Flags stem_flags ) 01578 { 01579 AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; 01580 AF_LatinAxis axis = & metrics->axis[dim]; 01581 FT_Pos dist = width; 01582 FT_Int sign = 0; 01583 FT_Int vertical = ( dim == AF_DIMENSION_VERT ); 01584 01585 01586 FT_UNUSED(base_flags); 01587 01588 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || 01589 axis->extra_light ) 01590 return width; 01591 01592 if ( dist < 0 ) 01593 { 01594 dist = -width; 01595 sign = 1; 01596 } 01597 01598 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || 01599 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) 01600 { 01601 /* smooth hinting process: very lightly quantize the stem width */ 01602 01603 /* leave the widths of serifs alone */ 01604 01605 if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) 01606 goto Done_Width; 01607 01608 #if 0 01609 else if ( ( base_flags & AF_EDGE_ROUND ) ) 01610 { 01611 if ( dist < 80 ) 01612 dist = 64; 01613 } 01614 else if ( dist < 56 ) 01615 dist = 56; 01616 #endif 01617 if ( axis->width_count > 0 ) 01618 { 01619 FT_Pos delta; 01620 01621 01622 /* compare to standard width */ 01623 if ( axis->width_count > 0 ) 01624 { 01625 delta = dist - axis->widths[0].cur; 01626 01627 if ( delta < 0 ) 01628 delta = -delta; 01629 01630 if ( delta < 40 ) 01631 { 01632 dist = axis->widths[0].cur; 01633 if ( dist < 48 ) 01634 dist = 48; 01635 01636 goto Done_Width; 01637 } 01638 } 01639 01640 if ( dist < 3 * 64 ) 01641 { 01642 delta = dist & 63; 01643 dist &= -64; 01644 01645 if ( delta < 10 ) 01646 dist += delta; 01647 01648 else if ( delta < 32 ) 01649 dist += 10; 01650 01651 else if ( delta < 54 ) 01652 dist += 54; 01653 01654 else 01655 dist += delta; 01656 } 01657 else 01658 dist = ( dist + 32 ) & ~63; 01659 } 01660 } 01661 else 01662 { 01663 /* strong hinting process: snap the stem width to integer pixels */ 01664 FT_Pos org_dist = dist; 01665 01666 01667 dist = af_latin2_snap_width( axis->widths, axis->width_count, dist ); 01668 01669 if ( vertical ) 01670 { 01671 /* in the case of vertical hinting, always round */ 01672 /* the stem heights to integer pixels */ 01673 01674 if ( dist >= 64 ) 01675 dist = ( dist + 16 ) & ~63; 01676 else 01677 dist = 64; 01678 } 01679 else 01680 { 01681 if ( AF_LATIN_HINTS_DO_MONO( hints ) ) 01682 { 01683 /* monochrome horizontal hinting: snap widths to integer pixels */ 01684 /* with a different threshold */ 01685 01686 if ( dist < 64 ) 01687 dist = 64; 01688 else 01689 dist = ( dist + 32 ) & ~63; 01690 } 01691 else 01692 { 01693 /* for horizontal anti-aliased hinting, we adopt a more subtle */ 01694 /* approach: we strengthen small stems, round stems whose size */ 01695 /* is between 1 and 2 pixels to an integer, otherwise nothing */ 01696 01697 if ( dist < 48 ) 01698 dist = ( dist + 64 ) >> 1; 01699 01700 else if ( dist < 128 ) 01701 { 01702 /* We only round to an integer width if the corresponding */ 01703 /* distortion is less than 1/4 pixel. Otherwise this */ 01704 /* makes everything worse since the diagonals, which are */ 01705 /* not hinted, appear a lot bolder or thinner than the */ 01706 /* vertical stems. */ 01707 01708 FT_Int delta; 01709 01710 01711 dist = ( dist + 22 ) & ~63; 01712 delta = dist - org_dist; 01713 if ( delta < 0 ) 01714 delta = -delta; 01715 01716 if (delta >= 16) 01717 { 01718 dist = org_dist; 01719 if ( dist < 48 ) 01720 dist = ( dist + 64 ) >> 1; 01721 } 01722 } 01723 else 01724 /* round otherwise to prevent color fringes in LCD mode */ 01725 dist = ( dist + 32 ) & ~63; 01726 } 01727 } 01728 } 01729 01730 Done_Width: 01731 if ( sign ) 01732 dist = -dist; 01733 01734 return dist; 01735 } 01736 01737 01738 /* align one stem edge relative to the previous stem edge */ 01739 01740 static void 01741 af_latin2_align_linked_edge( AF_GlyphHints hints, 01742 AF_Dimension dim, 01743 AF_Edge base_edge, 01744 AF_Edge stem_edge ) 01745 { 01746 FT_Pos dist = stem_edge->opos - base_edge->opos; 01747 01748 FT_Pos fitted_width = af_latin2_compute_stem_width( 01749 hints, dim, dist, 01750 (AF_Edge_Flags)base_edge->flags, 01751 (AF_Edge_Flags)stem_edge->flags ); 01752 01753 01754 stem_edge->pos = base_edge->pos + fitted_width; 01755 01756 AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), " 01757 "dist was %.2f, now %.2f\n", 01758 stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0, 01759 stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 )); 01760 } 01761 01762 01763 static void 01764 af_latin2_align_serif_edge( AF_GlyphHints hints, 01765 AF_Edge base, 01766 AF_Edge serif ) 01767 { 01768 FT_UNUSED( hints ); 01769 01770 serif->pos = base->pos + (serif->opos - base->opos); 01771 } 01772 01773 01774 /*************************************************************************/ 01775 /*************************************************************************/ 01776 /*************************************************************************/ 01777 /**** ****/ 01778 /**** E D G E H I N T I N G ****/ 01779 /**** ****/ 01780 /*************************************************************************/ 01781 /*************************************************************************/ 01782 /*************************************************************************/ 01783 01784 01785 FT_LOCAL_DEF( void ) 01786 af_latin2_hint_edges( AF_GlyphHints hints, 01787 AF_Dimension dim ) 01788 { 01789 AF_AxisHints axis = &hints->axis[dim]; 01790 AF_Edge edges = axis->edges; 01791 AF_Edge edge_limit = edges + axis->num_edges; 01792 AF_Edge edge; 01793 AF_Edge anchor = 0; 01794 FT_Int has_serifs = 0; 01795 FT_Pos anchor_drift = 0; 01796 01797 01798 01799 AF_LOG(( "==== hinting %s edges =====\n", dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); 01800 01801 /* we begin by aligning all stems relative to the blue zone */ 01802 /* if needed -- that's only for horizontal edges */ 01803 01804 if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) 01805 { 01806 for ( edge = edges; edge < edge_limit; edge++ ) 01807 { 01808 AF_Width blue; 01809 AF_Edge edge1, edge2; 01810 01811 01812 if ( edge->flags & AF_EDGE_DONE ) 01813 continue; 01814 01815 blue = edge->blue_edge; 01816 edge1 = NULL; 01817 edge2 = edge->link; 01818 01819 if ( blue ) 01820 { 01821 edge1 = edge; 01822 } 01823 else if ( edge2 && edge2->blue_edge ) 01824 { 01825 blue = edge2->blue_edge; 01826 edge1 = edge2; 01827 edge2 = edge; 01828 } 01829 01830 if ( !edge1 ) 01831 continue; 01832 01833 AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), " 01834 "was (%.2f)\n", 01835 edge1-edges, edge1->opos / 64.0, blue->fit / 64.0, 01836 edge1->pos / 64.0 )); 01837 01838 edge1->pos = blue->fit; 01839 edge1->flags |= AF_EDGE_DONE; 01840 01841 if ( edge2 && !edge2->blue_edge ) 01842 { 01843 af_latin2_align_linked_edge( hints, dim, edge1, edge2 ); 01844 edge2->flags |= AF_EDGE_DONE; 01845 } 01846 01847 if ( !anchor ) 01848 { 01849 anchor = edge; 01850 01851 anchor_drift = (anchor->pos - anchor->opos); 01852 if (edge2) 01853 anchor_drift = (anchor_drift + (edge2->pos - edge2->opos)) >> 1; 01854 } 01855 } 01856 } 01857 01858 /* now we will align all stem edges, trying to maintain the */ 01859 /* relative order of stems in the glyph */ 01860 for ( edge = edges; edge < edge_limit; edge++ ) 01861 { 01862 AF_Edge edge2; 01863 01864 01865 if ( edge->flags & AF_EDGE_DONE ) 01866 continue; 01867 01868 /* skip all non-stem edges */ 01869 edge2 = edge->link; 01870 if ( !edge2 ) 01871 { 01872 has_serifs++; 01873 continue; 01874 } 01875 01876 /* now align the stem */ 01877 01878 /* this should not happen, but it's better to be safe */ 01879 if ( edge2->blue_edge ) 01880 { 01881 AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges )); 01882 01883 af_latin2_align_linked_edge( hints, dim, edge2, edge ); 01884 edge->flags |= AF_EDGE_DONE; 01885 continue; 01886 } 01887 01888 if ( !anchor ) 01889 { 01890 FT_Pos org_len, org_center, cur_len; 01891 FT_Pos cur_pos1, error1, error2, u_off, d_off; 01892 01893 01894 org_len = edge2->opos - edge->opos; 01895 cur_len = af_latin2_compute_stem_width( 01896 hints, dim, org_len, 01897 (AF_Edge_Flags)edge->flags, 01898 (AF_Edge_Flags)edge2->flags ); 01899 if ( cur_len <= 64 ) 01900 u_off = d_off = 32; 01901 else 01902 { 01903 u_off = 38; 01904 d_off = 26; 01905 } 01906 01907 if ( cur_len < 96 ) 01908 { 01909 org_center = edge->opos + ( org_len >> 1 ); 01910 01911 cur_pos1 = FT_PIX_ROUND( org_center ); 01912 01913 error1 = org_center - ( cur_pos1 - u_off ); 01914 if ( error1 < 0 ) 01915 error1 = -error1; 01916 01917 error2 = org_center - ( cur_pos1 + d_off ); 01918 if ( error2 < 0 ) 01919 error2 = -error2; 01920 01921 if ( error1 < error2 ) 01922 cur_pos1 -= u_off; 01923 else 01924 cur_pos1 += d_off; 01925 01926 edge->pos = cur_pos1 - cur_len / 2; 01927 edge2->pos = edge->pos + cur_len; 01928 } 01929 else 01930 edge->pos = FT_PIX_ROUND( edge->opos ); 01931 01932 AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) " 01933 "snapped to (%.2f) (%.2f)\n", 01934 edge-edges, edge->opos / 64.0, 01935 edge2-edges, edge2->opos / 64.0, 01936 edge->pos / 64.0, edge2->pos / 64.0 )); 01937 anchor = edge; 01938 01939 edge->flags |= AF_EDGE_DONE; 01940 01941 af_latin2_align_linked_edge( hints, dim, edge, edge2 ); 01942 01943 edge2->flags |= AF_EDGE_DONE; 01944 01945 anchor_drift = ( (anchor->pos - anchor->opos) + 01946 (edge2->pos - edge2->opos)) >> 1; 01947 01948 AF_LOG(( "DRIFT: %.2f\n", anchor_drift/64.0 )); 01949 } 01950 else 01951 { 01952 FT_Pos org_pos, org_len, org_center, cur_center, cur_len; 01953 FT_Pos org_left, org_right; 01954 01955 01956 org_pos = edge->opos + anchor_drift; 01957 org_len = edge2->opos - edge->opos; 01958 org_center = org_pos + ( org_len >> 1 ); 01959 01960 cur_len = af_latin2_compute_stem_width( 01961 hints, dim, org_len, 01962 (AF_Edge_Flags)edge->flags, 01963 (AF_Edge_Flags)edge2->flags ); 01964 01965 org_left = org_pos + ((org_len - cur_len) >> 1); 01966 org_right = org_pos + ((org_len + cur_len) >> 1); 01967 01968 AF_LOG(( "ALIGN: left=%.2f right=%.2f ", org_left/64.0, org_right/64.0 )); 01969 cur_center = org_center; 01970 01971 if ( edge2->flags & AF_EDGE_DONE ) 01972 { 01973 AF_LOG(( "\n" )); 01974 edge->pos = edge2->pos - cur_len; 01975 } 01976 else 01977 { 01978 /* we want to compare several displacement, and choose 01979 * the one that increases fitness while minimizing 01980 * distortion as well 01981 */ 01982 FT_Pos displacements[6], scores[6], org, fit, delta; 01983 FT_UInt count = 0; 01984 01985 /* note: don't even try to fit tiny stems */ 01986 if ( cur_len < 32 ) 01987 { 01988 AF_LOG(( "tiny stem\n" )); 01989 goto AlignStem; 01990 } 01991 01992 /* if the span is within a single pixel, don't touch it */ 01993 if ( FT_PIX_FLOOR(org_left) == FT_PIX_CEIL(org_right) ) 01994 { 01995 AF_LOG(( "single pixel stem\n" )); 01996 goto AlignStem; 01997 } 01998 01999 if (cur_len <= 96) 02000 { 02001 /* we want to avoid the absolute worst case which is 02002 * when the left and right edges of the span each represent 02003 * about 50% of the gray. we'd better want to change this 02004 * to 25/75%, since this is much more pleasant to the eye with 02005 * very acceptable distortion 02006 */ 02007 FT_Pos frac_left = (org_left) & 63; 02008 FT_Pos frac_right = (org_right) & 63; 02009 02010 if ( frac_left >= 22 && frac_left <= 42 && 02011 frac_right >= 22 && frac_right <= 42 ) 02012 { 02013 org = frac_left; 02014 fit = (org <= 32) ? 16 : 48; 02015 delta = FT_ABS(fit - org); 02016 displacements[count] = fit - org; 02017 scores[count++] = delta; 02018 AF_LOG(( "dispA=%.2f (%d) ", (fit - org)/64.0, delta )); 02019 02020 org = frac_right; 02021 fit = (org <= 32) ? 16 : 48; 02022 delta = FT_ABS(fit - org); 02023 displacements[count] = fit - org; 02024 scores[count++] = delta; 02025 AF_LOG(( "dispB=%.2f (%d) ", (fit - org)/64.0, delta )); 02026 } 02027 } 02028 02029 /* snapping the left edge to the grid */ 02030 org = org_left; 02031 fit = FT_PIX_ROUND(org); 02032 delta = FT_ABS(fit - org); 02033 displacements[count] = fit - org; 02034 scores[count++] = delta; 02035 AF_LOG(( "dispC=%.2f (%d) ", (fit - org)/64.0, delta )); 02036 02037 /* snapping the right edge to the grid */ 02038 org = org_right; 02039 fit = FT_PIX_ROUND(org); 02040 delta = FT_ABS(fit - org); 02041 displacements[count] = fit - org; 02042 scores[count++] = delta; 02043 AF_LOG(( "dispD=%.2f (%d) ", (fit - org)/64.0, delta )); 02044 02045 /* now find the best displacement */ 02046 { 02047 FT_Pos best_score = scores[0]; 02048 FT_Pos best_disp = displacements[0]; 02049 FT_UInt nn; 02050 02051 for (nn = 1; nn < count; nn++) 02052 { 02053 if (scores[nn] < best_score) 02054 { 02055 best_score = scores[nn]; 02056 best_disp = displacements[nn]; 02057 } 02058 } 02059 02060 cur_center = org_center + best_disp; 02061 } 02062 AF_LOG(( "\n" )); 02063 } 02064 02065 AlignStem: 02066 edge->pos = cur_center - (cur_len >> 1); 02067 edge2->pos = edge->pos + cur_len; 02068 02069 AF_LOG(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f) " 02070 "snapped to (%.2f) and (%.2f), org_len = %.2f cur_len=%.2f\n", 02071 edge-edges, edge->opos / 64.0, 02072 edge2-edges, edge2->opos / 64.0, 02073 edge->pos / 64.0, edge2->pos / 64.0, 02074 org_len / 64.0, cur_len / 64.0 )); 02075 02076 edge->flags |= AF_EDGE_DONE; 02077 edge2->flags |= AF_EDGE_DONE; 02078 02079 if ( edge > edges && edge->pos < edge[-1].pos ) 02080 { 02081 AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n", 02082 edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); 02083 edge->pos = edge[-1].pos; 02084 } 02085 } 02086 } 02087 02088 /* make sure that lowercase m's maintain their symmetry */ 02089 02090 /* In general, lowercase m's have six vertical edges if they are sans */ 02091 /* serif, or twelve if they are with serifs. This implementation is */ 02092 /* based on that assumption, and seems to work very well with most */ 02093 /* faces. However, if for a certain face this assumption is not */ 02094 /* true, the m is just rendered like before. In addition, any stem */ 02095 /* correction will only be applied to symmetrical glyphs (even if the */ 02096 /* glyph is not an m), so the potential for unwanted distortion is */ 02097 /* relatively low. */ 02098 02099 /* We don't handle horizontal edges since we can't easily assure that */ 02100 /* the third (lowest) stem aligns with the base line; it might end up */ 02101 /* one pixel higher or lower. */ 02102 02103 #if 0 02104 { 02105 FT_Int n_edges = edge_limit - edges; 02106 02107 02108 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) 02109 { 02110 AF_Edge edge1, edge2, edge3; 02111 FT_Pos dist1, dist2, span, delta; 02112 02113 02114 if ( n_edges == 6 ) 02115 { 02116 edge1 = edges; 02117 edge2 = edges + 2; 02118 edge3 = edges + 4; 02119 } 02120 else 02121 { 02122 edge1 = edges + 1; 02123 edge2 = edges + 5; 02124 edge3 = edges + 9; 02125 } 02126 02127 dist1 = edge2->opos - edge1->opos; 02128 dist2 = edge3->opos - edge2->opos; 02129 02130 span = dist1 - dist2; 02131 if ( span < 0 ) 02132 span = -span; 02133 02134 if ( span < 8 ) 02135 { 02136 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); 02137 edge3->pos -= delta; 02138 if ( edge3->link ) 02139 edge3->link->pos -= delta; 02140 02141 /* move the serifs along with the stem */ 02142 if ( n_edges == 12 ) 02143 { 02144 ( edges + 8 )->pos -= delta; 02145 ( edges + 11 )->pos -= delta; 02146 } 02147 02148 edge3->flags |= AF_EDGE_DONE; 02149 if ( edge3->link ) 02150 edge3->link->flags |= AF_EDGE_DONE; 02151 } 02152 } 02153 } 02154 #endif 02155 02156 if ( has_serifs || !anchor ) 02157 { 02158 /* 02159 * now hint the remaining edges (serifs and single) in order 02160 * to complete our processing 02161 */ 02162 for ( edge = edges; edge < edge_limit; edge++ ) 02163 { 02164 FT_Pos delta; 02165 02166 02167 if ( edge->flags & AF_EDGE_DONE ) 02168 continue; 02169 02170 delta = 1000; 02171 02172 if ( edge->serif ) 02173 { 02174 delta = edge->serif->opos - edge->opos; 02175 if ( delta < 0 ) 02176 delta = -delta; 02177 } 02178 02179 if ( delta < 64 + 16 ) 02180 { 02181 af_latin2_align_serif_edge( hints, edge->serif, edge ); 02182 AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) " 02183 "aligned to (%.2f)\n", 02184 edge-edges, edge->opos / 64.0, 02185 edge->serif - edges, edge->serif->opos / 64.0, 02186 edge->pos / 64.0 )); 02187 } 02188 else if ( !anchor ) 02189 { 02190 AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n", 02191 edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); 02192 edge->pos = FT_PIX_ROUND( edge->opos ); 02193 anchor = edge; 02194 } 02195 else 02196 { 02197 AF_Edge before, after; 02198 02199 02200 for ( before = edge - 1; before >= edges; before-- ) 02201 if ( before->flags & AF_EDGE_DONE ) 02202 break; 02203 02204 for ( after = edge + 1; after < edge_limit; after++ ) 02205 if ( after->flags & AF_EDGE_DONE ) 02206 break; 02207 02208 if ( before >= edges && before < edge && 02209 after < edge_limit && after > edge ) 02210 { 02211 if ( after->opos == before->opos ) 02212 edge->pos = before->pos; 02213 else 02214 edge->pos = before->pos + 02215 FT_MulDiv( edge->opos - before->opos, 02216 after->pos - before->pos, 02217 after->opos - before->opos ); 02218 AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) from %d (opos=%.2f)\n", 02219 edge-edges, edge->opos / 64.0, edge->pos / 64.0, before - edges, before->opos / 64.0 )); 02220 } 02221 else 02222 { 02223 edge->pos = anchor->pos + (( edge->opos - anchor->opos + 16) & ~31); 02224 02225 AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n", 02226 edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); 02227 } 02228 } 02229 02230 edge->flags |= AF_EDGE_DONE; 02231 02232 if ( edge > edges && edge->pos < edge[-1].pos ) 02233 edge->pos = edge[-1].pos; 02234 02235 if ( edge + 1 < edge_limit && 02236 edge[1].flags & AF_EDGE_DONE && 02237 edge->pos > edge[1].pos ) 02238 edge->pos = edge[1].pos; 02239 } 02240 } 02241 } 02242 02243 02244 static FT_Error 02245 af_latin2_hints_apply( AF_GlyphHints hints, 02246 FT_Outline* outline, 02247 AF_LatinMetrics metrics ) 02248 { 02249 FT_Error error; 02250 int dim; 02251 02252 02253 error = af_glyph_hints_reload( hints, outline ); 02254 if ( error ) 02255 goto Exit; 02256 02257 /* analyze glyph outline */ 02258 #ifdef AF_USE_WARPER 02259 if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT || 02260 AF_HINTS_DO_HORIZONTAL( hints ) ) 02261 #else 02262 if ( AF_HINTS_DO_HORIZONTAL( hints ) ) 02263 #endif 02264 { 02265 error = af_latin2_hints_detect_features( hints, AF_DIMENSION_HORZ ); 02266 if ( error ) 02267 goto Exit; 02268 } 02269 02270 if ( AF_HINTS_DO_VERTICAL( hints ) ) 02271 { 02272 error = af_latin2_hints_detect_features( hints, AF_DIMENSION_VERT ); 02273 if ( error ) 02274 goto Exit; 02275 02276 af_latin2_hints_compute_blue_edges( hints, metrics ); 02277 } 02278 02279 /* grid-fit the outline */ 02280 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) 02281 { 02282 #ifdef AF_USE_WARPER 02283 if ( ( dim == AF_DIMENSION_HORZ && 02284 metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) ) 02285 { 02286 AF_WarperRec warper; 02287 FT_Fixed scale; 02288 FT_Pos delta; 02289 02290 02291 af_warper_compute( &warper, hints, dim, &scale, &delta ); 02292 af_glyph_hints_scale_dim( hints, dim, scale, delta ); 02293 continue; 02294 } 02295 #endif 02296 02297 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || 02298 ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) 02299 { 02300 af_latin2_hint_edges( hints, (AF_Dimension)dim ); 02301 af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); 02302 af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); 02303 af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); 02304 } 02305 } 02306 af_glyph_hints_save( hints, outline ); 02307 02308 Exit: 02309 return error; 02310 } 02311 02312 02313 /*************************************************************************/ 02314 /*************************************************************************/ 02315 /***** *****/ 02316 /***** L A T I N S C R I P T C L A S S *****/ 02317 /***** *****/ 02318 /*************************************************************************/ 02319 /*************************************************************************/ 02320 02321 02322 static const AF_Script_UniRangeRec af_latin2_uniranges[] = 02323 { 02324 AF_UNIRANGE_REC( 32UL, 127UL ), /* XXX: TODO: Add new Unicode ranges here! */ 02325 AF_UNIRANGE_REC( 160UL, 255UL ), 02326 AF_UNIRANGE_REC( 0UL, 0UL ) 02327 }; 02328 02329 02330 AF_DEFINE_SCRIPT_CLASS(af_latin2_script_class, 02331 AF_SCRIPT_LATIN2, 02332 af_latin2_uniranges, 02333 02334 sizeof( AF_LatinMetricsRec ), 02335 02336 (AF_Script_InitMetricsFunc) af_latin2_metrics_init, 02337 (AF_Script_ScaleMetricsFunc)af_latin2_metrics_scale, 02338 (AF_Script_DoneMetricsFunc) NULL, 02339 02340 (AF_Script_InitHintsFunc) af_latin2_hints_init, 02341 (AF_Script_ApplyHintsFunc) af_latin2_hints_apply 02342 ) 02343 02344 02345 /* END */ Generated on Sat May 26 2012 04:32:29 for ReactOS by
1.7.6.1
|