00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <ft2build.h>
00020 #include FT_INTERNAL_OBJECTS_H
00021 #include FT_INTERNAL_DEBUG_H
00022 #include FT_INTERNAL_CALC_H
00023 #include "pshalgo.h"
00024
00025 #include "pshnterr.h"
00026
00027
00028 #undef FT_COMPONENT
00029 #define FT_COMPONENT trace_pshalgo2
00030
00031
00032 #ifdef DEBUG_HINTER
00033 PSH_Hint_Table ps_debug_hint_table = 0;
00034 PSH_HintFunc ps_debug_hint_func = 0;
00035 PSH_Glyph ps_debug_glyph = 0;
00036 #endif
00037
00038
00039 #define COMPUTE_INFLEXS
00040
00041 #define STRONGER
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 static FT_Int
00055 psh_hint_overlap( PSH_Hint hint1,
00056 PSH_Hint hint2 )
00057 {
00058 return hint1->org_pos + hint1->org_len >= hint2->org_pos &&
00059 hint2->org_pos + hint2->org_len >= hint1->org_pos;
00060 }
00061
00062
00063
00064 static void
00065 psh_hint_table_done( PSH_Hint_Table table,
00066 FT_Memory memory )
00067 {
00068 FT_FREE( table->zones );
00069 table->num_zones = 0;
00070 table->zone = 0;
00071
00072 FT_FREE( table->sort );
00073 FT_FREE( table->hints );
00074 table->num_hints = 0;
00075 table->max_hints = 0;
00076 table->sort_global = 0;
00077 }
00078
00079
00080
00081 static void
00082 psh_hint_table_deactivate( PSH_Hint_Table table )
00083 {
00084 FT_UInt count = table->max_hints;
00085 PSH_Hint hint = table->hints;
00086
00087
00088 for ( ; count > 0; count--, hint++ )
00089 {
00090 psh_hint_deactivate( hint );
00091 hint->order = -1;
00092 }
00093 }
00094
00095
00096
00097 static void
00098 psh_hint_table_record( PSH_Hint_Table table,
00099 FT_UInt idx )
00100 {
00101 PSH_Hint hint = table->hints + idx;
00102
00103
00104 if ( idx >= table->max_hints )
00105 {
00106 FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx ));
00107 return;
00108 }
00109
00110
00111 if ( psh_hint_is_active( hint ) )
00112 return;
00113
00114 psh_hint_activate( hint );
00115
00116
00117
00118 {
00119 PSH_Hint* sorted = table->sort_global;
00120 FT_UInt count = table->num_hints;
00121 PSH_Hint hint2;
00122
00123
00124 hint->parent = 0;
00125 for ( ; count > 0; count--, sorted++ )
00126 {
00127 hint2 = sorted[0];
00128
00129 if ( psh_hint_overlap( hint, hint2 ) )
00130 {
00131 hint->parent = hint2;
00132 break;
00133 }
00134 }
00135 }
00136
00137 if ( table->num_hints < table->max_hints )
00138 table->sort_global[table->num_hints++] = hint;
00139 else
00140 FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" ));
00141 }
00142
00143
00144 static void
00145 psh_hint_table_record_mask( PSH_Hint_Table table,
00146 PS_Mask hint_mask )
00147 {
00148 FT_Int mask = 0, val = 0;
00149 FT_Byte* cursor = hint_mask->bytes;
00150 FT_UInt idx, limit;
00151
00152
00153 limit = hint_mask->num_bits;
00154
00155 for ( idx = 0; idx < limit; idx++ )
00156 {
00157 if ( mask == 0 )
00158 {
00159 val = *cursor++;
00160 mask = 0x80;
00161 }
00162
00163 if ( val & mask )
00164 psh_hint_table_record( table, idx );
00165
00166 mask >>= 1;
00167 }
00168 }
00169
00170
00171
00172 static FT_Error
00173 psh_hint_table_init( PSH_Hint_Table table,
00174 PS_Hint_Table hints,
00175 PS_Mask_Table hint_masks,
00176 PS_Mask_Table counter_masks,
00177 FT_Memory memory )
00178 {
00179 FT_UInt count;
00180 FT_Error error;
00181
00182 FT_UNUSED( counter_masks );
00183
00184
00185 count = hints->num_hints;
00186
00187
00188 if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
00189 FT_NEW_ARRAY( table->hints, count ) ||
00190 FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
00191 goto Exit;
00192
00193 table->max_hints = count;
00194 table->sort_global = table->sort + count;
00195 table->num_hints = 0;
00196 table->num_zones = 0;
00197 table->zone = 0;
00198
00199
00200 {
00201 PSH_Hint write = table->hints;
00202 PS_Hint read = hints->hints;
00203
00204
00205 for ( ; count > 0; count--, write++, read++ )
00206 {
00207 write->org_pos = read->pos;
00208 write->org_len = read->len;
00209 write->flags = read->flags;
00210 }
00211 }
00212
00213
00214
00215 if ( hint_masks )
00216 {
00217 PS_Mask mask = hint_masks->masks;
00218
00219
00220 count = hint_masks->num_masks;
00221 table->hint_masks = hint_masks;
00222
00223 for ( ; count > 0; count--, mask++ )
00224 psh_hint_table_record_mask( table, mask );
00225 }
00226
00227
00228 if ( table->num_hints != table->max_hints )
00229 {
00230 FT_UInt idx;
00231
00232
00233 FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" ));
00234
00235 count = table->max_hints;
00236 for ( idx = 0; idx < count; idx++ )
00237 psh_hint_table_record( table, idx );
00238 }
00239
00240 Exit:
00241 return error;
00242 }
00243
00244
00245 static void
00246 psh_hint_table_activate_mask( PSH_Hint_Table table,
00247 PS_Mask hint_mask )
00248 {
00249 FT_Int mask = 0, val = 0;
00250 FT_Byte* cursor = hint_mask->bytes;
00251 FT_UInt idx, limit, count;
00252
00253
00254 limit = hint_mask->num_bits;
00255 count = 0;
00256
00257 psh_hint_table_deactivate( table );
00258
00259 for ( idx = 0; idx < limit; idx++ )
00260 {
00261 if ( mask == 0 )
00262 {
00263 val = *cursor++;
00264 mask = 0x80;
00265 }
00266
00267 if ( val & mask )
00268 {
00269 PSH_Hint hint = &table->hints[idx];
00270
00271
00272 if ( !psh_hint_is_active( hint ) )
00273 {
00274 FT_UInt count2;
00275
00276 #if 0
00277 PSH_Hint* sort = table->sort;
00278 PSH_Hint hint2;
00279
00280
00281 for ( count2 = count; count2 > 0; count2--, sort++ )
00282 {
00283 hint2 = sort[0];
00284 if ( psh_hint_overlap( hint, hint2 ) )
00285 FT_TRACE0(( "psh_hint_table_activate_mask:"
00286 " found overlapping hints\n" ))
00287 }
00288 #else
00289 count2 = 0;
00290 #endif
00291
00292 if ( count2 == 0 )
00293 {
00294 psh_hint_activate( hint );
00295 if ( count < table->max_hints )
00296 table->sort[count++] = hint;
00297 else
00298 FT_TRACE0(( "psh_hint_tableactivate_mask:"
00299 " too many active hints\n" ));
00300 }
00301 }
00302 }
00303
00304 mask >>= 1;
00305 }
00306 table->num_hints = count;
00307
00308
00309
00310 {
00311 FT_Int i1, i2;
00312 PSH_Hint hint1, hint2;
00313 PSH_Hint* sort = table->sort;
00314
00315
00316
00317
00318 for ( i1 = 1; i1 < (FT_Int)count; i1++ )
00319 {
00320 hint1 = sort[i1];
00321 for ( i2 = i1 - 1; i2 >= 0; i2-- )
00322 {
00323 hint2 = sort[i2];
00324
00325 if ( hint2->org_pos < hint1->org_pos )
00326 break;
00327
00328 sort[i2 + 1] = hint2;
00329 sort[i2] = hint1;
00330 }
00331 }
00332 }
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 #if 1
00345 static FT_Pos
00346 psh_dimension_quantize_len( PSH_Dimension dim,
00347 FT_Pos len,
00348 FT_Bool do_snapping )
00349 {
00350 if ( len <= 64 )
00351 len = 64;
00352 else
00353 {
00354 FT_Pos delta = len - dim->stdw.widths[0].cur;
00355
00356
00357 if ( delta < 0 )
00358 delta = -delta;
00359
00360 if ( delta < 40 )
00361 {
00362 len = dim->stdw.widths[0].cur;
00363 if ( len < 48 )
00364 len = 48;
00365 }
00366
00367 if ( len < 3 * 64 )
00368 {
00369 delta = ( len & 63 );
00370 len &= -64;
00371
00372 if ( delta < 10 )
00373 len += delta;
00374
00375 else if ( delta < 32 )
00376 len += 10;
00377
00378 else if ( delta < 54 )
00379 len += 54;
00380
00381 else
00382 len += delta;
00383 }
00384 else
00385 len = FT_PIX_ROUND( len );
00386 }
00387
00388 if ( do_snapping )
00389 len = FT_PIX_ROUND( len );
00390
00391 return len;
00392 }
00393 #endif
00394
00395
00396 #ifdef DEBUG_HINTER
00397
00398 static void
00399 ps_simple_scale( PSH_Hint_Table table,
00400 FT_Fixed scale,
00401 FT_Fixed delta,
00402 FT_Int dimension )
00403 {
00404 PSH_Hint hint;
00405 FT_UInt count;
00406
00407
00408 for ( count = 0; count < table->max_hints; count++ )
00409 {
00410 hint = table->hints + count;
00411
00412 hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
00413 hint->cur_len = FT_MulFix( hint->org_len, scale );
00414
00415 if ( ps_debug_hint_func )
00416 ps_debug_hint_func( hint, dimension );
00417 }
00418 }
00419
00420 #endif
00421
00422
00423 static FT_Fixed
00424 psh_hint_snap_stem_side_delta( FT_Fixed pos,
00425 FT_Fixed len )
00426 {
00427 FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos;
00428 FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len;
00429
00430
00431 if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) )
00432 return delta1;
00433 else
00434 return delta2;
00435 }
00436
00437
00438 static void
00439 psh_hint_align( PSH_Hint hint,
00440 PSH_Globals globals,
00441 FT_Int dimension,
00442 PSH_Glyph glyph )
00443 {
00444 PSH_Dimension dim = &globals->dimension[dimension];
00445 FT_Fixed scale = dim->scale_mult;
00446 FT_Fixed delta = dim->scale_delta;
00447
00448
00449 if ( !psh_hint_is_fitted( hint ) )
00450 {
00451 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
00452 FT_Pos len = FT_MulFix( hint->org_len, scale );
00453
00454 FT_Int do_snapping;
00455 FT_Pos fit_len;
00456 PSH_AlignmentRec align;
00457
00458
00459
00460 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
00461 ( dimension == 1 && !glyph->do_vert_hints ) )
00462 {
00463 hint->cur_pos = pos;
00464 hint->cur_len = len;
00465
00466 psh_hint_set_fitted( hint );
00467 return;
00468 }
00469
00470
00471
00472
00473 do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
00474 ( dimension == 1 && glyph->do_vert_snapping );
00475
00476 hint->cur_len = fit_len = len;
00477
00478
00479 align.align = PSH_BLUE_ALIGN_NONE;
00480 align.align_bot = align.align_top = 0;
00481
00482 if ( dimension == 1 )
00483 psh_blues_snap_stem( &globals->blues,
00484 hint->org_pos + hint->org_len,
00485 hint->org_pos,
00486 &align );
00487
00488 switch ( align.align )
00489 {
00490 case PSH_BLUE_ALIGN_TOP:
00491
00492 hint->cur_pos = align.align_top - fit_len;
00493 break;
00494
00495 case PSH_BLUE_ALIGN_BOT:
00496
00497 hint->cur_pos = align.align_bot;
00498 break;
00499
00500 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
00501
00502 hint->cur_pos = align.align_bot;
00503 hint->cur_len = align.align_top - align.align_bot;
00504 break;
00505
00506 default:
00507 {
00508 PSH_Hint parent = hint->parent;
00509
00510
00511 if ( parent )
00512 {
00513 FT_Pos par_org_center, par_cur_center;
00514 FT_Pos cur_org_center, cur_delta;
00515
00516
00517
00518 if ( !psh_hint_is_fitted( parent ) )
00519 psh_hint_align( parent, globals, dimension, glyph );
00520
00521
00522
00523
00524 par_org_center = parent->org_pos + ( parent->org_len >> 1 );
00525 par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
00526 cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
00527
00528 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
00529 pos = par_cur_center + cur_delta - ( len >> 1 );
00530 }
00531
00532 hint->cur_pos = pos;
00533 hint->cur_len = fit_len;
00534
00535
00536
00537
00538
00539 if ( glyph->do_stem_adjust )
00540 {
00541 if ( len <= 64 )
00542 {
00543
00544
00545
00546 if ( len >= 32 )
00547 {
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) );
00560 len = 64;
00561 }
00562 else if ( len > 0 )
00563 {
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 FT_Pos left_nearest = FT_PIX_ROUND( pos );
00579 FT_Pos right_nearest = FT_PIX_ROUND( pos + len );
00580 FT_Pos left_disp = left_nearest - pos;
00581 FT_Pos right_disp = right_nearest - ( pos + len );
00582
00583
00584 if ( left_disp < 0 )
00585 left_disp = -left_disp;
00586 if ( right_disp < 0 )
00587 right_disp = -right_disp;
00588 if ( left_disp <= right_disp )
00589 pos = left_nearest;
00590 else
00591 pos = right_nearest;
00592 }
00593 else
00594 {
00595
00596 pos = FT_PIX_ROUND( pos );
00597 }
00598 }
00599 else
00600 {
00601 len = psh_dimension_quantize_len( dim, len, 0 );
00602 }
00603 }
00604
00605
00606
00607 hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len );
00608 hint->cur_len = len;
00609 }
00610 }
00611
00612 if ( do_snapping )
00613 {
00614 pos = hint->cur_pos;
00615 len = hint->cur_len;
00616
00617 if ( len < 64 )
00618 len = 64;
00619 else
00620 len = FT_PIX_ROUND( len );
00621
00622 switch ( align.align )
00623 {
00624 case PSH_BLUE_ALIGN_TOP:
00625 hint->cur_pos = align.align_top - len;
00626 hint->cur_len = len;
00627 break;
00628
00629 case PSH_BLUE_ALIGN_BOT:
00630 hint->cur_len = len;
00631 break;
00632
00633 case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
00634
00635 break;
00636
00637
00638 default:
00639 hint->cur_len = len;
00640 if ( len & 64 )
00641 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32;
00642 else
00643 pos = FT_PIX_ROUND( pos + ( len >> 1 ) );
00644
00645 hint->cur_pos = pos - ( len >> 1 );
00646 hint->cur_len = len;
00647 }
00648 }
00649
00650 psh_hint_set_fitted( hint );
00651
00652 #ifdef DEBUG_HINTER
00653 if ( ps_debug_hint_func )
00654 ps_debug_hint_func( hint, dimension );
00655 #endif
00656 }
00657 }
00658
00659
00660 #if 0
00661
00662
00663
00664
00665
00666 static void
00667 psh_hint_align_light( PSH_Hint hint,
00668 PSH_Globals globals,
00669 FT_Int dimension,
00670 PSH_Glyph glyph )
00671 {
00672 PSH_Dimension dim = &globals->dimension[dimension];
00673 FT_Fixed scale = dim->scale_mult;
00674 FT_Fixed delta = dim->scale_delta;
00675
00676
00677 if ( !psh_hint_is_fitted( hint ) )
00678 {
00679 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
00680 FT_Pos len = FT_MulFix( hint->org_len, scale );
00681
00682 FT_Pos fit_len;
00683
00684 PSH_AlignmentRec align;
00685
00686
00687
00688 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
00689 ( dimension == 1 && !glyph->do_vert_hints ) )
00690 {
00691 hint->cur_pos = pos;
00692 hint->cur_len = len;
00693
00694 psh_hint_set_fitted( hint );
00695 return;
00696 }
00697
00698 fit_len = len;
00699
00700 hint->cur_len = fit_len;
00701
00702
00703 align.align = PSH_BLUE_ALIGN_NONE;
00704 align.align_bot = align.align_top = 0;
00705
00706 if ( dimension == 1 )
00707 psh_blues_snap_stem( &globals->blues,
00708 hint->org_pos + hint->org_len,
00709 hint->org_pos,
00710 &align );
00711
00712 switch ( align.align )
00713 {
00714 case PSH_BLUE_ALIGN_TOP:
00715
00716 hint->cur_pos = align.align_top - fit_len;
00717 break;
00718
00719 case PSH_BLUE_ALIGN_BOT:
00720
00721 hint->cur_pos = align.align_bot;
00722 break;
00723
00724 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
00725
00726 hint->cur_pos = align.align_bot;
00727 hint->cur_len = align.align_top - align.align_bot;
00728 break;
00729
00730 default:
00731 {
00732 PSH_Hint parent = hint->parent;
00733
00734
00735 if ( parent )
00736 {
00737 FT_Pos par_org_center, par_cur_center;
00738 FT_Pos cur_org_center, cur_delta;
00739
00740
00741
00742 if ( !psh_hint_is_fitted( parent ) )
00743 psh_hint_align_light( parent, globals, dimension, glyph );
00744
00745 par_org_center = parent->org_pos + ( parent->org_len / 2 );
00746 par_cur_center = parent->cur_pos + ( parent->cur_len / 2 );
00747 cur_org_center = hint->org_pos + ( hint->org_len / 2 );
00748
00749 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
00750 pos = par_cur_center + cur_delta - ( len >> 1 );
00751 }
00752
00753
00754
00755
00756
00757
00758
00759 if ( len <= 64 )
00760 {
00761 if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
00762 pos += psh_hint_snap_stem_side_delta ( pos, len );
00763 }
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788 else
00789 {
00790 FT_Fixed frac_len = len & 63;
00791 FT_Fixed center = pos + ( len >> 1 );
00792 FT_Fixed delta_a, delta_b;
00793
00794
00795 if ( ( len / 64 ) & 1 )
00796 {
00797 delta_a = FT_PIX_FLOOR( center ) + 32 - center;
00798 delta_b = FT_PIX_ROUND( center ) - center;
00799 }
00800 else
00801 {
00802 delta_a = FT_PIX_ROUND( center ) - center;
00803 delta_b = FT_PIX_FLOOR( center ) + 32 - center;
00804 }
00805
00806
00807
00808
00809
00810
00811 if ( frac_len < 32 )
00812 {
00813 pos += psh_hint_snap_stem_side_delta ( pos, len );
00814 }
00815 else if ( frac_len < 48 )
00816 {
00817 FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos,
00818 len );
00819
00820 if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) )
00821 pos += side_delta;
00822 else
00823 pos += delta_b;
00824 }
00825 else
00826 {
00827 pos += delta_b;
00828 }
00829 }
00830
00831 hint->cur_pos = pos;
00832 }
00833 }
00834
00835 psh_hint_set_fitted( hint );
00836
00837 #ifdef DEBUG_HINTER
00838 if ( ps_debug_hint_func )
00839 ps_debug_hint_func( hint, dimension );
00840 #endif
00841 }
00842 }
00843
00844 #endif
00845
00846
00847 static void
00848 psh_hint_table_align_hints( PSH_Hint_Table table,
00849 PSH_Globals globals,
00850 FT_Int dimension,
00851 PSH_Glyph glyph )
00852 {
00853 PSH_Hint hint;
00854 FT_UInt count;
00855
00856 #ifdef DEBUG_HINTER
00857
00858 PSH_Dimension dim = &globals->dimension[dimension];
00859 FT_Fixed scale = dim->scale_mult;
00860 FT_Fixed delta = dim->scale_delta;
00861
00862
00863 if ( ps_debug_no_vert_hints && dimension == 0 )
00864 {
00865 ps_simple_scale( table, scale, delta, dimension );
00866 return;
00867 }
00868
00869 if ( ps_debug_no_horz_hints && dimension == 1 )
00870 {
00871 ps_simple_scale( table, scale, delta, dimension );
00872 return;
00873 }
00874
00875 #endif
00876
00877 hint = table->hints;
00878 count = table->max_hints;
00879
00880 for ( ; count > 0; count--, hint++ )
00881 psh_hint_align( hint, globals, dimension, glyph );
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893 #define PSH_ZONE_MIN -3200000L
00894 #define PSH_ZONE_MAX +3200000L
00895
00896 #define xxDEBUG_ZONES
00897
00898
00899 #ifdef DEBUG_ZONES
00900
00901 #include FT_CONFIG_STANDARD_LIBRARY_H
00902
00903 static void
00904 psh_print_zone( PSH_Zone zone )
00905 {
00906 printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
00907 zone->scale / 65536.0,
00908 zone->delta / 64.0,
00909 zone->min,
00910 zone->max );
00911 }
00912
00913 #else
00914
00915 #define psh_print_zone( x ) do { } while ( 0 )
00916
00917 #endif
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 #if 1
00929
00930 #define psh_corner_is_flat ft_corner_is_flat
00931 #define psh_corner_orientation ft_corner_orientation
00932
00933 #else
00934
00935 FT_LOCAL_DEF( FT_Int )
00936 psh_corner_is_flat( FT_Pos x_in,
00937 FT_Pos y_in,
00938 FT_Pos x_out,
00939 FT_Pos y_out )
00940 {
00941 FT_Pos ax = x_in;
00942 FT_Pos ay = y_in;
00943
00944 FT_Pos d_in, d_out, d_corner;
00945
00946
00947 if ( ax < 0 )
00948 ax = -ax;
00949 if ( ay < 0 )
00950 ay = -ay;
00951 d_in = ax + ay;
00952
00953 ax = x_out;
00954 if ( ax < 0 )
00955 ax = -ax;
00956 ay = y_out;
00957 if ( ay < 0 )
00958 ay = -ay;
00959 d_out = ax + ay;
00960
00961 ax = x_out + x_in;
00962 if ( ax < 0 )
00963 ax = -ax;
00964 ay = y_out + y_in;
00965 if ( ay < 0 )
00966 ay = -ay;
00967 d_corner = ax + ay;
00968
00969 return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
00970 }
00971
00972 static FT_Int
00973 psh_corner_orientation( FT_Pos in_x,
00974 FT_Pos in_y,
00975 FT_Pos out_x,
00976 FT_Pos out_y )
00977 {
00978 FT_Int result;
00979
00980
00981
00982 if ( in_y == 0 )
00983 {
00984 if ( in_x >= 0 )
00985 result = out_y;
00986 else
00987 result = -out_y;
00988 }
00989 else if ( in_x == 0 )
00990 {
00991 if ( in_y >= 0 )
00992 result = -out_x;
00993 else
00994 result = out_x;
00995 }
00996 else if ( out_y == 0 )
00997 {
00998 if ( out_x >= 0 )
00999 result = in_y;
01000 else
01001 result = -in_y;
01002 }
01003 else if ( out_x == 0 )
01004 {
01005 if ( out_y >= 0 )
01006 result = -in_x;
01007 else
01008 result = in_x;
01009 }
01010 else
01011 {
01012 long long delta = (long long)in_x * out_y - (long long)in_y * out_x;
01013
01014 if ( delta == 0 )
01015 result = 0;
01016 else
01017 result = 1 - 2 * ( delta < 0 );
01018 }
01019
01020 return result;
01021 }
01022
01023 #endif
01024
01025
01026 #ifdef COMPUTE_INFLEXS
01027
01028
01029 static void
01030 psh_glyph_compute_inflections( PSH_Glyph glyph )
01031 {
01032 FT_UInt n;
01033
01034
01035 for ( n = 0; n < glyph->num_contours; n++ )
01036 {
01037 PSH_Point first, start, end, before, after;
01038 FT_Pos in_x, in_y, out_x, out_y;
01039 FT_Int orient_prev, orient_cur;
01040 FT_Int finished = 0;
01041
01042
01043
01044 if ( glyph->contours[n].count < 4 )
01045 continue;
01046
01047
01048 first = glyph->contours[n].start;
01049
01050 start = end = first;
01051 do
01052 {
01053 end = end->next;
01054 if ( end == first )
01055 goto Skip;
01056
01057 in_x = end->org_u - start->org_u;
01058 in_y = end->org_v - start->org_v;
01059
01060 } while ( in_x == 0 && in_y == 0 );
01061
01062
01063 before = start;
01064 do
01065 {
01066 do
01067 {
01068 start = before;
01069 before = before->prev;
01070 if ( before == first )
01071 goto Skip;
01072
01073 out_x = start->org_u - before->org_u;
01074 out_y = start->org_v - before->org_v;
01075
01076 } while ( out_x == 0 && out_y == 0 );
01077
01078 orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
01079
01080 } while ( orient_prev == 0 );
01081
01082 first = start;
01083 in_x = out_x;
01084 in_y = out_y;
01085
01086
01087 do
01088 {
01089
01090 after = end;
01091 do
01092 {
01093 do
01094 {
01095 end = after;
01096 after = after->next;
01097 if ( after == first )
01098 finished = 1;
01099
01100 out_x = after->org_u - end->org_u;
01101 out_y = after->org_v - end->org_v;
01102
01103 } while ( out_x == 0 && out_y == 0 );
01104
01105 orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
01106
01107 } while ( orient_cur == 0 );
01108
01109 if ( ( orient_cur ^ orient_prev ) < 0 )
01110 {
01111 do
01112 {
01113 psh_point_set_inflex( start );
01114 start = start->next;
01115 }
01116 while ( start != end );
01117
01118 psh_point_set_inflex( start );
01119 }
01120
01121 start = end;
01122 end = after;
01123 orient_prev = orient_cur;
01124 in_x = out_x;
01125 in_y = out_y;
01126
01127 } while ( !finished );
01128
01129 Skip:
01130 ;
01131 }
01132 }
01133
01134 #endif
01135
01136
01137 static void
01138 psh_glyph_done( PSH_Glyph glyph )
01139 {
01140 FT_Memory memory = glyph->memory;
01141
01142
01143 psh_hint_table_done( &glyph->hint_tables[1], memory );
01144 psh_hint_table_done( &glyph->hint_tables[0], memory );
01145
01146 FT_FREE( glyph->points );
01147 FT_FREE( glyph->contours );
01148
01149 glyph->num_points = 0;
01150 glyph->num_contours = 0;
01151
01152 glyph->memory = 0;
01153 }
01154
01155
01156 static int
01157 psh_compute_dir( FT_Pos dx,
01158 FT_Pos dy )
01159 {
01160 FT_Pos ax, ay;
01161 int result = PSH_DIR_NONE;
01162
01163
01164 ax = ( dx >= 0 ) ? dx : -dx;
01165 ay = ( dy >= 0 ) ? dy : -dy;
01166
01167 if ( ay * 12 < ax )
01168 {
01169
01170 result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT;
01171 }
01172 else if ( ax * 12 < ay )
01173 {
01174
01175 result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN;
01176 }
01177
01178 return result;
01179 }
01180
01181
01182
01183 static void
01184 psh_glyph_load_points( PSH_Glyph glyph,
01185 FT_Int dimension )
01186 {
01187 FT_Vector* vec = glyph->outline->points;
01188 PSH_Point point = glyph->points;
01189 FT_UInt count = glyph->num_points;
01190
01191
01192 for ( ; count > 0; count--, point++, vec++ )
01193 {
01194 point->flags2 = 0;
01195 point->hint = NULL;
01196 if ( dimension == 0 )
01197 {
01198 point->org_u = vec->x;
01199 point->org_v = vec->y;
01200 }
01201 else
01202 {
01203 point->org_u = vec->y;
01204 point->org_v = vec->x;
01205 }
01206
01207 #ifdef DEBUG_HINTER
01208 point->org_x = vec->x;
01209 point->org_y = vec->y;
01210 #endif
01211
01212 }
01213 }
01214
01215
01216
01217 static void
01218 psh_glyph_save_points( PSH_Glyph glyph,
01219 FT_Int dimension )
01220 {
01221 FT_UInt n;
01222 PSH_Point point = glyph->points;
01223 FT_Vector* vec = glyph->outline->points;
01224 char* tags = glyph->outline->tags;
01225
01226
01227 for ( n = 0; n < glyph->num_points; n++ )
01228 {
01229 if ( dimension == 0 )
01230 vec[n].x = point->cur_u;
01231 else
01232 vec[n].y = point->cur_u;
01233
01234 if ( psh_point_is_strong( point ) )
01235 tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
01236
01237 #ifdef DEBUG_HINTER
01238
01239 if ( dimension == 0 )
01240 {
01241 point->cur_x = point->cur_u;
01242 point->flags_x = point->flags2 | point->flags;
01243 }
01244 else
01245 {
01246 point->cur_y = point->cur_u;
01247 point->flags_y = point->flags2 | point->flags;
01248 }
01249
01250 #endif
01251
01252 point++;
01253 }
01254 }
01255
01256
01257 static FT_Error
01258 psh_glyph_init( PSH_Glyph glyph,
01259 FT_Outline* outline,
01260 PS_Hints ps_hints,
01261 PSH_Globals globals )
01262 {
01263 FT_Error error;
01264 FT_Memory memory;
01265
01266
01267
01268 FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
01269
01270 memory = glyph->memory = globals->memory;
01271
01272
01273 if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
01274 FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
01275 goto Exit;
01276
01277 glyph->num_points = outline->n_points;
01278 glyph->num_contours = outline->n_contours;
01279
01280 {
01281 FT_UInt first = 0, next, n;
01282 PSH_Point points = glyph->points;
01283 PSH_Contour contour = glyph->contours;
01284
01285
01286 for ( n = 0; n < glyph->num_contours; n++ )
01287 {
01288 FT_Int count;
01289 PSH_Point point;
01290
01291
01292 next = outline->contours[n] + 1;
01293 count = next - first;
01294
01295 contour->start = points + first;
01296 contour->count = (FT_UInt)count;
01297
01298 if ( count > 0 )
01299 {
01300 point = points + first;
01301
01302 point->prev = points + next - 1;
01303 point->contour = contour;
01304
01305 for ( ; count > 1; count-- )
01306 {
01307 point[0].next = point + 1;
01308 point[1].prev = point;
01309 point++;
01310 point->contour = contour;
01311 }
01312 point->next = points + first;
01313 }
01314
01315 contour++;
01316 first = next;
01317 }
01318 }
01319
01320 {
01321 PSH_Point points = glyph->points;
01322 PSH_Point point = points;
01323 FT_Vector* vec = outline->points;
01324 FT_UInt n;
01325
01326
01327 for ( n = 0; n < glyph->num_points; n++, point++ )
01328 {
01329 FT_Int n_prev = (FT_Int)( point->prev - points );
01330 FT_Int n_next = (FT_Int)( point->next - points );
01331 FT_Pos dxi, dyi, dxo, dyo;
01332
01333
01334 if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
01335 point->flags = PSH_POINT_OFF;
01336
01337 dxi = vec[n].x - vec[n_prev].x;
01338 dyi = vec[n].y - vec[n_prev].y;
01339
01340 point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi );
01341
01342 dxo = vec[n_next].x - vec[n].x;
01343 dyo = vec[n_next].y - vec[n].y;
01344
01345 point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo );
01346
01347
01348 if ( point->flags & PSH_POINT_OFF )
01349 point->flags |= PSH_POINT_SMOOTH;
01350
01351 else if ( point->dir_in == point->dir_out )
01352 {
01353 if ( point->dir_out != PSH_DIR_NONE ||
01354 psh_corner_is_flat( dxi, dyi, dxo, dyo ) )
01355 point->flags |= PSH_POINT_SMOOTH;
01356 }
01357 }
01358 }
01359
01360 glyph->outline = outline;
01361 glyph->globals = globals;
01362
01363 #ifdef COMPUTE_INFLEXS
01364 psh_glyph_load_points( glyph, 0 );
01365 psh_glyph_compute_inflections( glyph );
01366 #endif
01367
01368
01369 error = psh_hint_table_init( &glyph->hint_tables [0],
01370 &ps_hints->dimension[0].hints,
01371 &ps_hints->dimension[0].masks,
01372 &ps_hints->dimension[0].counters,
01373 memory );
01374 if ( error )
01375 goto Exit;
01376
01377 error = psh_hint_table_init( &glyph->hint_tables [1],
01378 &ps_hints->dimension[1].hints,
01379 &ps_hints->dimension[1].masks,
01380 &ps_hints->dimension[1].counters,
01381 memory );
01382 if ( error )
01383 goto Exit;
01384
01385 Exit:
01386 return error;
01387 }
01388
01389
01390
01391 static void
01392 psh_glyph_compute_extrema( PSH_Glyph glyph )
01393 {
01394 FT_UInt n;
01395
01396
01397
01398 for ( n = 0; n < glyph->num_contours; n++ )
01399 {
01400 PSH_Point first = glyph->contours[n].start;
01401 PSH_Point point, before, after;
01402
01403
01404 if ( glyph->contours[n].count == 0 )
01405 continue;
01406
01407 point = first;
01408 before = point;
01409 after = point;
01410
01411 do
01412 {
01413 before = before->prev;
01414 if ( before == first )
01415 goto Skip;
01416
01417 } while ( before->org_u == point->org_u );
01418
01419 first = point = before->next;
01420
01421 for (;;)
01422 {
01423 after = point;
01424 do
01425 {
01426 after = after->next;
01427 if ( after == first )
01428 goto Next;
01429
01430 } while ( after->org_u == point->org_u );
01431
01432 if ( before->org_u < point->org_u )
01433 {
01434 if ( after->org_u < point->org_u )
01435 {
01436
01437 goto Extremum;
01438 }
01439 }
01440 else
01441 {
01442 if ( after->org_u > point->org_u )
01443 {
01444
01445 Extremum:
01446 do
01447 {
01448 psh_point_set_extremum( point );
01449 point = point->next;
01450
01451 } while ( point != after );
01452 }
01453 }
01454
01455 before = after->prev;
01456 point = after;
01457
01458 }
01459
01460 Next:
01461 ;
01462 }
01463
01464
01465
01466 for ( n = 0; n < glyph->num_points; n++ )
01467 {
01468 PSH_Point point, before, after;
01469
01470
01471 point = &glyph->points[n];
01472 before = point;
01473 after = point;
01474
01475 if ( psh_point_is_extremum( point ) )
01476 {
01477 do
01478 {
01479 before = before->prev;
01480 if ( before == point )
01481 goto Skip;
01482
01483 } while ( before->org_v == point->org_v );
01484
01485 do
01486 {
01487 after = after->next;
01488 if ( after == point )
01489 goto Skip;
01490
01491 } while ( after->org_v == point->org_v );
01492 }
01493
01494 if ( before->org_v < point->org_v &&
01495 after->org_v > point->org_v )
01496 {
01497 psh_point_set_positive( point );
01498 }
01499 else if ( before->org_v > point->org_v &&
01500 after->org_v < point->org_v )
01501 {
01502 psh_point_set_negative( point );
01503 }
01504
01505 Skip:
01506 ;
01507 }
01508 }
01509
01510
01511
01512
01513
01514
01515 static void
01516 psh_hint_table_find_strong_points( PSH_Hint_Table table,
01517 PSH_Point point,
01518 FT_UInt count,
01519 FT_Int threshold,
01520 FT_Int major_dir )
01521 {
01522 PSH_Hint* sort = table->sort;
01523 FT_UInt num_hints = table->num_hints;
01524
01525
01526 for ( ; count > 0; count--, point++ )
01527 {
01528 FT_Int point_dir = 0;
01529 FT_Pos org_u = point->org_u;
01530
01531
01532 if ( psh_point_is_strong( point ) )
01533 continue;
01534
01535 if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) )
01536 point_dir = point->dir_in;
01537
01538 else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) )
01539 point_dir = point->dir_out;
01540
01541 if ( point_dir )
01542 {
01543 if ( point_dir == major_dir )
01544 {
01545 FT_UInt nn;
01546
01547
01548 for ( nn = 0; nn < num_hints; nn++ )
01549 {
01550 PSH_Hint hint = sort[nn];
01551 FT_Pos d = org_u - hint->org_pos;
01552
01553
01554 if ( d < threshold && -d < threshold )
01555 {
01556 psh_point_set_strong( point );
01557 point->flags2 |= PSH_POINT_EDGE_MIN;
01558 point->hint = hint;
01559 break;
01560 }
01561 }
01562 }
01563 else if ( point_dir == -major_dir )
01564 {
01565 FT_UInt nn;
01566
01567
01568 for ( nn = 0; nn < num_hints; nn++ )
01569 {
01570 PSH_Hint hint = sort[nn];
01571 FT_Pos d = org_u - hint->org_pos - hint->org_len;
01572
01573
01574 if ( d < threshold && -d < threshold )
01575 {
01576 psh_point_set_strong( point );
01577 point->flags2 |= PSH_POINT_EDGE_MAX;
01578 point->hint = hint;
01579 break;
01580 }
01581 }
01582 }
01583 }
01584
01585 #if 1
01586 else if ( psh_point_is_extremum( point ) )
01587 {
01588
01589 FT_UInt nn, min_flag, max_flag;
01590
01591
01592 if ( major_dir == PSH_DIR_HORIZONTAL )
01593 {
01594 min_flag = PSH_POINT_POSITIVE;
01595 max_flag = PSH_POINT_NEGATIVE;
01596 }
01597 else
01598 {
01599 min_flag = PSH_POINT_NEGATIVE;
01600 max_flag = PSH_POINT_POSITIVE;
01601 }
01602
01603 if ( point->flags2 & min_flag )
01604 {
01605 for ( nn = 0; nn < num_hints; nn++ )
01606 {
01607 PSH_Hint hint = sort[nn];
01608 FT_Pos d = org_u - hint->org_pos;
01609
01610
01611 if ( d < threshold && -d < threshold )
01612 {
01613 point->flags2 |= PSH_POINT_EDGE_MIN;
01614 point->hint = hint;
01615 psh_point_set_strong( point );
01616 break;
01617 }
01618 }
01619 }
01620 else if ( point->flags2 & max_flag )
01621 {
01622 for ( nn = 0; nn < num_hints; nn++ )
01623 {
01624 PSH_Hint hint = sort[nn];
01625 FT_Pos d = org_u - hint->org_pos - hint->org_len;
01626
01627
01628 if ( d < threshold && -d < threshold )
01629 {
01630 point->flags2 |= PSH_POINT_EDGE_MAX;
01631 point->hint = hint;
01632 psh_point_set_strong( point );
01633 break;
01634 }
01635 }
01636 }
01637
01638 if ( point->hint == NULL )
01639 {
01640 for ( nn = 0; nn < num_hints; nn++ )
01641 {
01642 PSH_Hint hint = sort[nn];
01643
01644
01645 if ( org_u >= hint->org_pos &&
01646 org_u <= hint->org_pos + hint->org_len )
01647 {
01648 point->hint = hint;
01649 break;
01650 }
01651 }
01652 }
01653 }
01654
01655 #endif
01656 }
01657 }
01658
01659
01660
01661 #define PSH_STRONG_THRESHOLD 32
01662
01663
01664 #define PSH_STRONG_THRESHOLD_MAXIMUM 30
01665
01666
01667
01668 static void
01669 psh_glyph_find_strong_points( PSH_Glyph glyph,
01670 FT_Int dimension )
01671 {
01672
01673
01674
01675 PSH_Hint_Table table = &glyph->hint_tables[dimension];
01676 PS_Mask mask = table->hint_masks->masks;
01677 FT_UInt num_masks = table->hint_masks->num_masks;
01678 FT_UInt first = 0;
01679 FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL
01680 : PSH_DIR_HORIZONTAL;
01681 PSH_Dimension dim = &glyph->globals->dimension[dimension];
01682 FT_Fixed scale = dim->scale_mult;
01683 FT_Int threshold;
01684
01685
01686 threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale );
01687 if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM )
01688 threshold = PSH_STRONG_THRESHOLD_MAXIMUM;
01689
01690
01691 if ( num_masks > 1 && glyph->num_points > 0 )
01692 {
01693 first = mask->end_point;
01694 mask++;
01695 for ( ; num_masks > 1; num_masks--, mask++ )
01696 {
01697 FT_UInt next;
01698 FT_Int count;
01699
01700
01701 next = mask->end_point;
01702 count = next - first;
01703 if ( count > 0 )
01704 {
01705 PSH_Point point = glyph->points + first;
01706
01707
01708 psh_hint_table_activate_mask( table, mask );
01709
01710 psh_hint_table_find_strong_points( table, point, count,
01711 threshold, major_dir );
01712 }
01713 first = next;
01714 }
01715 }
01716
01717
01718 if ( num_masks == 1 )
01719 {
01720 FT_UInt count = glyph->num_points;
01721 PSH_Point point = glyph->points;
01722
01723
01724 psh_hint_table_activate_mask( table, table->hint_masks->masks );
01725
01726 psh_hint_table_find_strong_points( table, point, count,
01727 threshold, major_dir );
01728 }
01729
01730
01731
01732 {
01733 FT_UInt count = glyph->num_points;
01734 PSH_Point point = glyph->points;
01735
01736
01737 for ( ; count > 0; count--, point++ )
01738 if ( point->hint && !psh_point_is_strong( point ) )
01739 psh_point_set_strong( point );
01740 }
01741 }
01742
01743
01744
01745
01746 static void
01747 psh_glyph_find_blue_points( PSH_Blues blues,
01748 PSH_Glyph glyph )
01749 {
01750 PSH_Blue_Table table;
01751 PSH_Blue_Zone zone;
01752 FT_UInt glyph_count = glyph->num_points;
01753 FT_UInt blue_count;
01754 PSH_Point point = glyph->points;
01755
01756
01757 for ( ; glyph_count > 0; glyph_count--, point++ )
01758 {
01759 FT_Pos y;
01760
01761
01762
01763 if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) &&
01764 !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) )
01765 continue;
01766
01767
01768 if ( psh_point_is_strong( point ) )
01769 continue;
01770
01771 y = point->org_u;
01772
01773
01774 table = &blues->normal_top;
01775 blue_count = table->count;
01776 zone = table->zones;
01777
01778 for ( ; blue_count > 0; blue_count--, zone++ )
01779 {
01780 FT_Pos delta = y - zone->org_bottom;
01781
01782
01783 if ( delta < -blues->blue_fuzz )
01784 break;
01785
01786 if ( y <= zone->org_top + blues->blue_fuzz )
01787 if ( blues->no_overshoots || delta <= blues->blue_threshold )
01788 {
01789 point->cur_u = zone->cur_bottom;
01790 psh_point_set_strong( point );
01791 psh_point_set_fitted( point );
01792 }
01793 }
01794
01795
01796 table = &blues->normal_bottom;
01797 blue_count = table->count;
01798 zone = table->zones + blue_count - 1;
01799
01800 for ( ; blue_count > 0; blue_count--, zone-- )
01801 {
01802 FT_Pos delta = zone->org_top - y;
01803
01804
01805 if ( delta < -blues->blue_fuzz )
01806 break;
01807
01808 if ( y >= zone->org_bottom - blues->blue_fuzz )
01809 if ( blues->no_overshoots || delta < blues->blue_threshold )
01810 {
01811 point->cur_u = zone->cur_top;
01812 psh_point_set_strong( point );
01813 psh_point_set_fitted( point );
01814 }
01815 }
01816 }
01817 }
01818
01819
01820
01821 static void
01822 psh_glyph_interpolate_strong_points( PSH_Glyph glyph,
01823 FT_Int dimension )
01824 {
01825 PSH_Dimension dim = &glyph->globals->dimension[dimension];
01826 FT_Fixed scale = dim->scale_mult;
01827
01828 FT_UInt count = glyph->num_points;
01829 PSH_Point point = glyph->points;
01830
01831
01832 for ( ; count > 0; count--, point++ )
01833 {
01834 PSH_Hint hint = point->hint;
01835
01836
01837 if ( hint )
01838 {
01839 FT_Pos delta;
01840
01841
01842 if ( psh_point_is_edge_min( point ) )
01843 point->cur_u = hint->cur_pos;
01844
01845 else if ( psh_point_is_edge_max( point ) )
01846 point->cur_u = hint->cur_pos + hint->cur_len;
01847
01848 else
01849 {
01850 delta = point->org_u - hint->org_pos;
01851
01852 if ( delta <= 0 )
01853 point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
01854
01855 else if ( delta >= hint->org_len )
01856 point->cur_u = hint->cur_pos + hint->cur_len +
01857 FT_MulFix( delta - hint->org_len, scale );
01858
01859 else if ( hint->org_len > 0 )
01860 point->cur_u = hint->cur_pos +
01861 FT_MulDiv( delta, hint->cur_len,
01862 hint->org_len );
01863 else
01864 point->cur_u = hint->cur_pos;
01865 }
01866 psh_point_set_fitted( point );
01867 }
01868 }
01869 }
01870
01871
01872 #define PSH_MAX_STRONG_INTERNAL 16
01873
01874 static void
01875 psh_glyph_interpolate_normal_points( PSH_Glyph glyph,
01876 FT_Int dimension )
01877 {
01878
01879 #if 1
01880
01881
01882 PSH_Dimension dim = &glyph->globals->dimension[dimension];
01883 FT_Fixed scale = dim->scale_mult;
01884 FT_Memory memory = glyph->memory;
01885
01886 PSH_Point* strongs = NULL;
01887 PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL];
01888 FT_UInt num_strongs = 0;
01889
01890 PSH_Point points = glyph->points;
01891 PSH_Point points_end = points + glyph->num_points;
01892 PSH_Point point;
01893
01894
01895
01896 for ( point = points; point < points_end; point++ )
01897 {
01898 if ( psh_point_is_strong( point ) )
01899 num_strongs++;
01900 }
01901
01902 if ( num_strongs == 0 )
01903 return;
01904
01905
01906
01907 if ( num_strongs <= PSH_MAX_STRONG_INTERNAL )
01908 strongs = strongs_0;
01909 else
01910 {
01911 FT_Error error;
01912
01913
01914 if ( FT_NEW_ARRAY( strongs, num_strongs ) )
01915 return;
01916 }
01917
01918 num_strongs = 0;
01919 for ( point = points; point < points_end; point++ )
01920 {
01921 PSH_Point* insert;
01922
01923
01924 if ( !psh_point_is_strong( point ) )
01925 continue;
01926
01927 for ( insert = strongs + num_strongs; insert > strongs; insert-- )
01928 {
01929 if ( insert[-1]->org_u <= point->org_u )
01930 break;
01931
01932 insert[0] = insert[-1];
01933 }
01934 insert[0] = point;
01935 num_strongs++;
01936 }
01937
01938
01939 for ( point = points; point < points_end; point++ )
01940 {
01941 if ( psh_point_is_strong( point ) )
01942 continue;
01943
01944
01945 if ( psh_point_is_smooth( point ) )
01946 {
01947 if ( point->dir_in == PSH_DIR_NONE ||
01948 point->dir_in != point->dir_out )
01949 continue;
01950
01951 if ( !psh_point_is_extremum( point ) &&
01952 !psh_point_is_inflex( point ) )
01953 continue;
01954
01955 point->flags &= ~PSH_POINT_SMOOTH;
01956 }
01957
01958
01959 {
01960 PSH_Point before, after;
01961 FT_UInt nn;
01962
01963
01964 for ( nn = 0; nn < num_strongs; nn++ )
01965 if ( strongs[nn]->org_u > point->org_u )
01966 break;
01967
01968 if ( nn == 0 )
01969 {
01970 after = strongs[0];
01971
01972 point->cur_u = after->cur_u +
01973 FT_MulFix( point->org_u - after->org_u,
01974 scale );
01975 }
01976 else
01977 {
01978 before = strongs[nn - 1];
01979
01980 for ( nn = num_strongs; nn > 0; nn-- )
01981 if ( strongs[nn - 1]->org_u < point->org_u )
01982 break;
01983
01984 if ( nn == num_strongs )
01985 {
01986 before = strongs[nn - 1];
01987
01988 point->cur_u = before->cur_u +
01989 FT_MulFix( point->org_u - before->org_u,
01990 scale );
01991 }
01992 else
01993 {
01994 FT_Pos u;
01995
01996
01997 after = strongs[nn];
01998
01999
02000 u = point->org_u;
02001
02002 if ( u == before->org_u )
02003 point->cur_u = before->cur_u;
02004
02005 else if ( u == after->org_u )
02006 point->cur_u = after->cur_u;
02007
02008 else
02009 point->cur_u = before->cur_u +
02010 FT_MulDiv( u - before->org_u,
02011 after->cur_u - before->cur_u,
02012 after->org_u - before->org_u );
02013 }
02014 }
02015 psh_point_set_fitted( point );
02016 }
02017 }
02018
02019 if ( strongs != strongs_0 )
02020 FT_FREE( strongs );
02021
02022 #endif
02023
02024 }
02025
02026
02027
02028 static void
02029 psh_glyph_interpolate_other_points( PSH_Glyph glyph,
02030 FT_Int dimension )
02031 {
02032 PSH_Dimension dim = &glyph->globals->dimension[dimension];
02033 FT_Fixed scale = dim->scale_mult;
02034 FT_Fixed delta = dim->scale_delta;
02035 PSH_Contour contour = glyph->contours;
02036 FT_UInt num_contours = glyph->num_contours;
02037
02038
02039 for ( ; num_contours > 0; num_contours--, contour++ )
02040 {
02041 PSH_Point start = contour->start;
02042 PSH_Point first, next, point;
02043 FT_UInt fit_count;
02044
02045
02046
02047 next = start + contour->count;
02048 fit_count = 0;
02049 first = 0;
02050
02051 for ( point = start; point < next; point++ )
02052 if ( psh_point_is_fitted( point ) )
02053 {
02054 if ( !first )
02055 first = point;
02056
02057 fit_count++;
02058 }
02059
02060
02061
02062 if ( fit_count < 2 )
02063 {
02064 if ( fit_count == 1 )
02065 delta = first->cur_u - FT_MulFix( first->org_u, scale );
02066
02067 for ( point = start; point < next; point++ )
02068 if ( point != first )
02069 point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
02070
02071 goto Next_Contour;
02072 }
02073
02074
02075
02076 start = first;
02077 do
02078 {
02079 point = first;
02080
02081
02082 for (;;)
02083 {
02084 next = first->next;
02085 if ( next == start )
02086 goto Next_Contour;
02087
02088 if ( !psh_point_is_fitted( next ) )
02089 break;
02090
02091 first = next;
02092 }
02093
02094
02095 for (;;)
02096 {
02097 next = next->next;
02098 if ( psh_point_is_fitted( next ) )
02099 break;
02100 }
02101
02102
02103 {
02104 FT_Pos org_a, org_ab, cur_a, cur_ab;
02105 FT_Pos org_c, org_ac, cur_c;
02106 FT_Fixed scale_ab;
02107
02108
02109 if ( first->org_u <= next->org_u )
02110 {
02111 org_a = first->org_u;
02112 cur_a = first->cur_u;
02113 org_ab = next->org_u - org_a;
02114 cur_ab = next->cur_u - cur_a;
02115 }
02116 else
02117 {
02118 org_a = next->org_u;
02119 cur_a = next->cur_u;
02120 org_ab = first->org_u - org_a;
02121 cur_ab = first->cur_u - cur_a;
02122 }
02123
02124 scale_ab = 0x10000L;
02125 if ( org_ab > 0 )
02126 scale_ab = FT_DivFix( cur_ab, org_ab );
02127
02128 point = first->next;
02129 do
02130 {
02131 org_c = point->org_u;
02132 org_ac = org_c - org_a;
02133
02134 if ( org_ac <= 0 )
02135 {
02136
02137 cur_c = cur_a + FT_MulFix( org_ac, scale );
02138 }
02139 else if ( org_ac >= org_ab )
02140 {
02141
02142 cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
02143 }
02144 else
02145 {
02146
02147 cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
02148 }
02149
02150 point->cur_u = cur_c;
02151
02152 point = point->next;
02153
02154 } while ( point != next );
02155 }
02156
02157
02158 first = next;
02159
02160 } while ( first != start );
02161
02162 Next_Contour:
02163 ;
02164 }
02165 }
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176 FT_Error
02177 ps_hints_apply( PS_Hints ps_hints,
02178 FT_Outline* outline,
02179 PSH_Globals globals,
02180 FT_Render_Mode hint_mode )
02181 {
02182 PSH_GlyphRec glyphrec;
02183 PSH_Glyph glyph = &glyphrec;
02184 FT_Error error;
02185 #ifdef DEBUG_HINTER
02186 FT_Memory memory;
02187 #endif
02188 FT_Int dimension;
02189
02190
02191
02192 if ( outline->n_points == 0 || outline->n_contours == 0 )
02193 return PSH_Err_Ok;
02194
02195 #ifdef DEBUG_HINTER
02196
02197 memory = globals->memory;
02198
02199 if ( ps_debug_glyph )
02200 {
02201 psh_glyph_done( ps_debug_glyph );
02202 FT_FREE( ps_debug_glyph );
02203 }
02204
02205 if ( FT_NEW( glyph ) )
02206 return error;
02207
02208 ps_debug_glyph = glyph;
02209
02210 #endif
02211
02212 error = psh_glyph_init( glyph, outline, ps_hints, globals );
02213 if ( error )
02214 goto Exit;
02215
02216
02217
02218
02219 {
02220 PSH_Dimension dim_x = &glyph->globals->dimension[0];
02221 PSH_Dimension dim_y = &glyph->globals->dimension[1];
02222
02223 FT_Fixed x_scale = dim_x->scale_mult;
02224 FT_Fixed y_scale = dim_y->scale_mult;
02225
02226 FT_Fixed old_x_scale = x_scale;
02227 FT_Fixed old_y_scale = y_scale;
02228
02229 FT_Fixed scaled;
02230 FT_Fixed fitted;
02231
02232 FT_Bool rescale = FALSE;
02233
02234
02235 scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale );
02236 fitted = FT_PIX_ROUND( scaled );
02237
02238 if ( fitted != 0 && scaled != fitted )
02239 {
02240 rescale = TRUE;
02241
02242 y_scale = FT_MulDiv( y_scale, fitted, scaled );
02243
02244 if ( fitted < scaled )
02245 x_scale -= x_scale / 50;
02246
02247 psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 );
02248 }
02249
02250 glyph->do_horz_hints = 1;
02251 glyph->do_vert_hints = 1;
02252
02253 glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
02254 hint_mode == FT_RENDER_MODE_LCD );
02255
02256 glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
02257 hint_mode == FT_RENDER_MODE_LCD_V );
02258
02259 glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
02260
02261 for ( dimension = 0; dimension < 2; dimension++ )
02262 {
02263
02264 psh_glyph_load_points( glyph, dimension );
02265
02266
02267 psh_glyph_compute_extrema( glyph );
02268
02269
02270 psh_hint_table_align_hints( &glyph->hint_tables[dimension],
02271 glyph->globals,
02272 dimension,
02273 glyph );
02274
02275
02276 psh_glyph_find_strong_points( glyph, dimension );
02277 if ( dimension == 1 )
02278 psh_glyph_find_blue_points( &globals->blues, glyph );
02279 psh_glyph_interpolate_strong_points( glyph, dimension );
02280 psh_glyph_interpolate_normal_points( glyph, dimension );
02281 psh_glyph_interpolate_other_points( glyph, dimension );
02282
02283
02284 psh_glyph_save_points( glyph, dimension );
02285
02286 if ( rescale )
02287 psh_globals_set_scale( glyph->globals,
02288 old_x_scale, old_y_scale, 0, 0 );
02289 }
02290 }
02291
02292 Exit:
02293
02294 #ifndef DEBUG_HINTER
02295 psh_glyph_done( glyph );
02296 #endif
02297
02298 return error;
02299 }
02300
02301
02302