00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "aftypes.h"
00026 #include "aflatin.h"
00027
00028
00029 #ifdef AF_CONFIG_OPTION_CJK
00030
00031 #include "afcjk.h"
00032 #include "aferrors.h"
00033
00034
00035 #ifdef AF_USE_WARPER
00036 #include "afwarp.h"
00037 #endif
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 FT_LOCAL_DEF( FT_Error )
00049 af_cjk_metrics_init( AF_LatinMetrics metrics,
00050 FT_Face face )
00051 {
00052 FT_CharMap oldmap = face->charmap;
00053
00054
00055 metrics->units_per_em = face->units_per_EM;
00056
00057
00058
00059 if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
00060 face->charmap = NULL;
00061 else
00062 {
00063
00064 af_latin_metrics_init_widths( metrics, face, 0x7530 );
00065 af_latin_metrics_check_digits( metrics, face );
00066 }
00067
00068 FT_Set_Charmap( face, oldmap );
00069
00070 return AF_Err_Ok;
00071 }
00072
00073
00074 static void
00075 af_cjk_metrics_scale_dim( AF_LatinMetrics metrics,
00076 AF_Scaler scaler,
00077 AF_Dimension dim )
00078 {
00079 AF_LatinAxis axis;
00080
00081
00082 axis = &metrics->axis[dim];
00083
00084 if ( dim == AF_DIMENSION_HORZ )
00085 {
00086 axis->scale = scaler->x_scale;
00087 axis->delta = scaler->x_delta;
00088 }
00089 else
00090 {
00091 axis->scale = scaler->y_scale;
00092 axis->delta = scaler->y_delta;
00093 }
00094 }
00095
00096
00097 FT_LOCAL_DEF( void )
00098 af_cjk_metrics_scale( AF_LatinMetrics metrics,
00099 AF_Scaler scaler )
00100 {
00101 metrics->root.scaler = *scaler;
00102
00103 af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
00104 af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 static FT_Error
00117 af_cjk_hints_compute_segments( AF_GlyphHints hints,
00118 AF_Dimension dim )
00119 {
00120 AF_AxisHints axis = &hints->axis[dim];
00121 AF_Segment segments = axis->segments;
00122 AF_Segment segment_limit = segments + axis->num_segments;
00123 FT_Error error;
00124 AF_Segment seg;
00125
00126
00127 error = af_latin_hints_compute_segments( hints, dim );
00128 if ( error )
00129 return error;
00130
00131
00132
00133 for ( seg = segments; seg < segment_limit; seg++ )
00134 {
00135 AF_Point pt = seg->first;
00136 AF_Point last = seg->last;
00137 AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
00138 AF_Flags f1;
00139
00140
00141 seg->flags &= ~AF_EDGE_ROUND;
00142
00143 for ( ; pt != last; f0 = f1 )
00144 {
00145 pt = pt->next;
00146 f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
00147
00148 if ( !f0 && !f1 )
00149 break;
00150
00151 if ( pt == last )
00152 seg->flags |= AF_EDGE_ROUND;
00153 }
00154 }
00155
00156 return AF_Err_Ok;
00157 }
00158
00159
00160 static void
00161 af_cjk_hints_link_segments( AF_GlyphHints hints,
00162 AF_Dimension dim )
00163 {
00164 AF_AxisHints axis = &hints->axis[dim];
00165 AF_Segment segments = axis->segments;
00166 AF_Segment segment_limit = segments + axis->num_segments;
00167 AF_Direction major_dir = axis->major_dir;
00168 AF_Segment seg1, seg2;
00169 FT_Pos len_threshold;
00170 FT_Pos dist_threshold;
00171
00172
00173 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
00174
00175 dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
00176 : hints->y_scale;
00177 dist_threshold = FT_DivFix( 64 * 3, dist_threshold );
00178
00179
00180 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00181 {
00182
00183 if ( seg1->first == seg1->last )
00184 continue;
00185
00186 if ( seg1->dir != major_dir )
00187 continue;
00188
00189 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
00190 if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
00191 {
00192 FT_Pos dist = seg2->pos - seg1->pos;
00193
00194
00195 if ( dist < 0 )
00196 continue;
00197
00198 {
00199 FT_Pos min = seg1->min_coord;
00200 FT_Pos max = seg1->max_coord;
00201 FT_Pos len;
00202
00203
00204 if ( min < seg2->min_coord )
00205 min = seg2->min_coord;
00206
00207 if ( max > seg2->max_coord )
00208 max = seg2->max_coord;
00209
00210 len = max - min;
00211 if ( len >= len_threshold )
00212 {
00213 if ( dist * 8 < seg1->score * 9 &&
00214 ( dist * 8 < seg1->score * 7 || seg1->len < len ) )
00215 {
00216 seg1->score = dist;
00217 seg1->len = len;
00218 seg1->link = seg2;
00219 }
00220
00221 if ( dist * 8 < seg2->score * 9 &&
00222 ( dist * 8 < seg2->score * 7 || seg2->len < len ) )
00223 {
00224 seg2->score = dist;
00225 seg2->len = len;
00226 seg2->link = seg1;
00227 }
00228 }
00229 }
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 {
00243 AF_Segment link1, link2;
00244
00245
00246 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00247 {
00248 link1 = seg1->link;
00249 if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos )
00250 continue;
00251
00252 if ( seg1->score >= dist_threshold )
00253 continue;
00254
00255 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
00256 {
00257 if ( seg2->pos > seg1->pos || seg1 == seg2 )
00258 continue;
00259
00260 link2 = seg2->link;
00261 if ( !link2 || link2->link != seg2 || link2->pos < link1->pos )
00262 continue;
00263
00264 if ( seg1->pos == seg2->pos && link1->pos == link2->pos )
00265 continue;
00266
00267 if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score )
00268 continue;
00269
00270
00271
00272 if ( seg1->len >= seg2->len * 3 )
00273 {
00274 AF_Segment seg;
00275
00276
00277 for ( seg = segments; seg < segment_limit; seg++ )
00278 {
00279 AF_Segment link = seg->link;
00280
00281
00282 if ( link == seg2 )
00283 {
00284 seg->link = 0;
00285 seg->serif = link1;
00286 }
00287 else if ( link == link2 )
00288 {
00289 seg->link = 0;
00290 seg->serif = seg1;
00291 }
00292 }
00293 }
00294 else
00295 {
00296 seg1->link = link1->link = 0;
00297
00298 break;
00299 }
00300 }
00301 }
00302 }
00303
00304 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00305 {
00306 seg2 = seg1->link;
00307
00308 if ( seg2 )
00309 {
00310 seg2->num_linked++;
00311 if ( seg2->link != seg1 )
00312 {
00313 seg1->link = 0;
00314
00315 if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 )
00316 seg1->serif = seg2->link;
00317 else
00318 seg2->num_linked--;
00319 }
00320 }
00321 }
00322 }
00323
00324
00325 static FT_Error
00326 af_cjk_hints_compute_edges( AF_GlyphHints hints,
00327 AF_Dimension dim )
00328 {
00329 AF_AxisHints axis = &hints->axis[dim];
00330 FT_Error error = AF_Err_Ok;
00331 FT_Memory memory = hints->memory;
00332 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
00333
00334 AF_Segment segments = axis->segments;
00335 AF_Segment segment_limit = segments + axis->num_segments;
00336 AF_Segment seg;
00337
00338 FT_Fixed scale;
00339 FT_Pos edge_distance_threshold;
00340
00341
00342 axis->num_edges = 0;
00343
00344 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
00345 : hints->y_scale;
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
00364 scale );
00365 if ( edge_distance_threshold > 64 / 4 )
00366 edge_distance_threshold = FT_DivFix( 64 / 4, scale );
00367 else
00368 edge_distance_threshold = laxis->edge_distance_threshold;
00369
00370 for ( seg = segments; seg < segment_limit; seg++ )
00371 {
00372 AF_Edge found = 0;
00373 FT_Pos best = 0xFFFFU;
00374 FT_Int ee;
00375
00376
00377
00378 for ( ee = 0; ee < axis->num_edges; ee++ )
00379 {
00380 AF_Edge edge = axis->edges + ee;
00381 FT_Pos dist;
00382
00383
00384 if ( edge->dir != seg->dir )
00385 continue;
00386
00387 dist = seg->pos - edge->fpos;
00388 if ( dist < 0 )
00389 dist = -dist;
00390
00391 if ( dist < edge_distance_threshold && dist < best )
00392 {
00393 AF_Segment link = seg->link;
00394
00395
00396
00397
00398 if ( link )
00399 {
00400 AF_Segment seg1 = edge->first;
00401 AF_Segment link1;
00402 FT_Pos dist2 = 0;
00403
00404
00405 do
00406 {
00407 link1 = seg1->link;
00408 if ( link1 )
00409 {
00410 dist2 = AF_SEGMENT_DIST( link, link1 );
00411 if ( dist2 >= edge_distance_threshold )
00412 break;
00413 }
00414
00415 } while ( ( seg1 = seg1->edge_next ) != edge->first );
00416
00417 if ( dist2 >= edge_distance_threshold )
00418 continue;
00419 }
00420
00421 best = dist;
00422 found = edge;
00423 }
00424 }
00425
00426 if ( !found )
00427 {
00428 AF_Edge edge;
00429
00430
00431
00432
00433 error = af_axis_hints_new_edge( axis, seg->pos,
00434 (AF_Direction)seg->dir,
00435 memory, &edge );
00436 if ( error )
00437 goto Exit;
00438
00439
00440 FT_ZERO( edge );
00441
00442 edge->first = seg;
00443 edge->last = seg;
00444 edge->fpos = seg->pos;
00445 edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
00446 seg->edge_next = seg;
00447 edge->dir = seg->dir;
00448 }
00449 else
00450 {
00451
00452
00453 seg->edge_next = found->first;
00454 found->last->edge_next = seg;
00455 found->last = seg;
00456 }
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 {
00479 AF_Edge edges = axis->edges;
00480 AF_Edge edge_limit = edges + axis->num_edges;
00481 AF_Edge edge;
00482
00483
00484 for ( edge = edges; edge < edge_limit; edge++ )
00485 {
00486 seg = edge->first;
00487 if ( seg )
00488 do
00489 {
00490 seg->edge = edge;
00491 seg = seg->edge_next;
00492
00493 } while ( seg != edge->first );
00494 }
00495
00496
00497 for ( edge = edges; edge < edge_limit; edge++ )
00498 {
00499 FT_Int is_round = 0;
00500 FT_Int is_straight = 0;
00501
00502
00503 seg = edge->first;
00504
00505 do
00506 {
00507 FT_Bool is_serif;
00508
00509
00510
00511 if ( seg->flags & AF_EDGE_ROUND )
00512 is_round++;
00513 else
00514 is_straight++;
00515
00516
00517
00518 is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
00519
00520 if ( seg->link || is_serif )
00521 {
00522 AF_Edge edge2;
00523 AF_Segment seg2;
00524
00525
00526 edge2 = edge->link;
00527 seg2 = seg->link;
00528
00529 if ( is_serif )
00530 {
00531 seg2 = seg->serif;
00532 edge2 = edge->serif;
00533 }
00534
00535 if ( edge2 )
00536 {
00537 FT_Pos edge_delta;
00538 FT_Pos seg_delta;
00539
00540
00541 edge_delta = edge->fpos - edge2->fpos;
00542 if ( edge_delta < 0 )
00543 edge_delta = -edge_delta;
00544
00545 seg_delta = AF_SEGMENT_DIST( seg, seg2 );
00546
00547 if ( seg_delta < edge_delta )
00548 edge2 = seg2->edge;
00549 }
00550 else
00551 edge2 = seg2->edge;
00552
00553 if ( is_serif )
00554 {
00555 edge->serif = edge2;
00556 edge2->flags |= AF_EDGE_SERIF;
00557 }
00558 else
00559 edge->link = edge2;
00560 }
00561
00562 seg = seg->edge_next;
00563
00564 } while ( seg != edge->first );
00565
00566
00567 edge->flags = AF_EDGE_NORMAL;
00568
00569 if ( is_round > 0 && is_round >= is_straight )
00570 edge->flags |= AF_EDGE_ROUND;
00571
00572
00573
00574
00575
00576 if ( edge->serif && edge->link )
00577 edge->serif = 0;
00578 }
00579 }
00580
00581 Exit:
00582 return error;
00583 }
00584
00585
00586 static FT_Error
00587 af_cjk_hints_detect_features( AF_GlyphHints hints,
00588 AF_Dimension dim )
00589 {
00590 FT_Error error;
00591
00592
00593 error = af_cjk_hints_compute_segments( hints, dim );
00594 if ( !error )
00595 {
00596 af_cjk_hints_link_segments( hints, dim );
00597
00598 error = af_cjk_hints_compute_edges( hints, dim );
00599 }
00600 return error;
00601 }
00602
00603
00604 FT_LOCAL_DEF( FT_Error )
00605 af_cjk_hints_init( AF_GlyphHints hints,
00606 AF_LatinMetrics metrics )
00607 {
00608 FT_Render_Mode mode;
00609 FT_UInt32 scaler_flags, other_flags;
00610
00611
00612 af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
00613
00614
00615
00616
00617
00618 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
00619 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
00620 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
00621 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
00622
00623
00624 mode = metrics->root.scaler.render_mode;
00625
00626 #ifdef AF_USE_WARPER
00627 if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
00628 metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
00629 #endif
00630
00631 scaler_flags = hints->scaler_flags;
00632 other_flags = 0;
00633
00634
00635
00636
00637
00638 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
00639 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
00640
00641
00642
00643
00644
00645 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
00646 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
00647
00648
00649
00650
00651 if ( mode != FT_RENDER_MODE_LIGHT )
00652 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
00653
00654 if ( mode == FT_RENDER_MODE_MONO )
00655 other_flags |= AF_LATIN_HINTS_MONO;
00656
00657 scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
00658
00659 hints->scaler_flags = scaler_flags;
00660 hints->other_flags = other_flags;
00661
00662 return 0;
00663 }
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 static FT_Pos
00678 af_cjk_snap_width( AF_Width widths,
00679 FT_Int count,
00680 FT_Pos width )
00681 {
00682 int n;
00683 FT_Pos best = 64 + 32 + 2;
00684 FT_Pos reference = width;
00685 FT_Pos scaled;
00686
00687
00688 for ( n = 0; n < count; n++ )
00689 {
00690 FT_Pos w;
00691 FT_Pos dist;
00692
00693
00694 w = widths[n].cur;
00695 dist = width - w;
00696 if ( dist < 0 )
00697 dist = -dist;
00698 if ( dist < best )
00699 {
00700 best = dist;
00701 reference = w;
00702 }
00703 }
00704
00705 scaled = FT_PIX_ROUND( reference );
00706
00707 if ( width >= reference )
00708 {
00709 if ( width < scaled + 48 )
00710 width = reference;
00711 }
00712 else
00713 {
00714 if ( width > scaled - 48 )
00715 width = reference;
00716 }
00717
00718 return width;
00719 }
00720
00721
00722
00723
00724 static FT_Pos
00725 af_cjk_compute_stem_width( AF_GlyphHints hints,
00726 AF_Dimension dim,
00727 FT_Pos width,
00728 AF_Edge_Flags base_flags,
00729 AF_Edge_Flags stem_flags )
00730 {
00731 AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
00732 AF_LatinAxis axis = & metrics->axis[dim];
00733 FT_Pos dist = width;
00734 FT_Int sign = 0;
00735 FT_Int vertical = ( dim == AF_DIMENSION_VERT );
00736
00737 FT_UNUSED( base_flags );
00738 FT_UNUSED( stem_flags );
00739
00740
00741 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
00742 return width;
00743
00744 if ( dist < 0 )
00745 {
00746 dist = -width;
00747 sign = 1;
00748 }
00749
00750 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
00751 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
00752 {
00753
00754
00755 if ( axis->width_count > 0 )
00756 {
00757 if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
00758 {
00759 dist = axis->widths[0].cur;
00760 if ( dist < 48 )
00761 dist = 48;
00762
00763 goto Done_Width;
00764 }
00765 }
00766
00767 if ( dist < 54 )
00768 dist += ( 54 - dist ) / 2 ;
00769 else if ( dist < 3 * 64 )
00770 {
00771 FT_Pos delta;
00772
00773
00774 delta = dist & 63;
00775 dist &= -64;
00776
00777 if ( delta < 10 )
00778 dist += delta;
00779 else if ( delta < 22 )
00780 dist += 10;
00781 else if ( delta < 42 )
00782 dist += delta;
00783 else if ( delta < 54 )
00784 dist += 54;
00785 else
00786 dist += delta;
00787 }
00788 }
00789 else
00790 {
00791
00792
00793 dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
00794
00795 if ( vertical )
00796 {
00797
00798
00799
00800 if ( dist >= 64 )
00801 dist = ( dist + 16 ) & ~63;
00802 else
00803 dist = 64;
00804 }
00805 else
00806 {
00807 if ( AF_LATIN_HINTS_DO_MONO( hints ) )
00808 {
00809
00810
00811
00812 if ( dist < 64 )
00813 dist = 64;
00814 else
00815 dist = ( dist + 32 ) & ~63;
00816 }
00817 else
00818 {
00819
00820
00821
00822
00823 if ( dist < 48 )
00824 dist = ( dist + 64 ) >> 1;
00825
00826 else if ( dist < 128 )
00827 dist = ( dist + 22 ) & ~63;
00828 else
00829
00830 dist = ( dist + 32 ) & ~63;
00831 }
00832 }
00833 }
00834
00835 Done_Width:
00836 if ( sign )
00837 dist = -dist;
00838
00839 return dist;
00840 }
00841
00842
00843
00844
00845 static void
00846 af_cjk_align_linked_edge( AF_GlyphHints hints,
00847 AF_Dimension dim,
00848 AF_Edge base_edge,
00849 AF_Edge stem_edge )
00850 {
00851 FT_Pos dist = stem_edge->opos - base_edge->opos;
00852
00853 FT_Pos fitted_width = af_cjk_compute_stem_width(
00854 hints, dim, dist,
00855 (AF_Edge_Flags)base_edge->flags,
00856 (AF_Edge_Flags)stem_edge->flags );
00857
00858
00859 stem_edge->pos = base_edge->pos + fitted_width;
00860 }
00861
00862
00863 static void
00864 af_cjk_align_serif_edge( AF_GlyphHints hints,
00865 AF_Edge base,
00866 AF_Edge serif )
00867 {
00868 FT_UNUSED( hints );
00869
00870 serif->pos = base->pos + ( serif->opos - base->opos );
00871 }
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 #define AF_LIGHT_MODE_MAX_HORZ_GAP 9
00886 #define AF_LIGHT_MODE_MAX_VERT_GAP 15
00887 #define AF_LIGHT_MODE_MAX_DELTA_ABS 14
00888
00889
00890 static FT_Pos
00891 af_hint_normal_stem( AF_GlyphHints hints,
00892 AF_Edge edge,
00893 AF_Edge edge2,
00894 FT_Pos anchor,
00895 AF_Dimension dim )
00896 {
00897 FT_Pos org_len, cur_len, org_center;
00898 FT_Pos cur_pos1, cur_pos2;
00899 FT_Pos d_off1, u_off1, d_off2, u_off2, delta;
00900 FT_Pos offset;
00901 FT_Pos threshold = 64;
00902
00903
00904 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
00905 {
00906 if ( ( edge->flags & AF_EDGE_ROUND ) &&
00907 ( edge2->flags & AF_EDGE_ROUND ) )
00908 {
00909 if ( dim == AF_DIMENSION_VERT )
00910 threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
00911 else
00912 threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
00913 }
00914 else
00915 {
00916 if ( dim == AF_DIMENSION_VERT )
00917 threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
00918 else
00919 threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
00920 }
00921 }
00922
00923 org_len = edge2->opos - edge->opos;
00924 cur_len = af_cjk_compute_stem_width( hints, dim, org_len,
00925 (AF_Edge_Flags)edge->flags,
00926 (AF_Edge_Flags)edge2->flags );
00927
00928 org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
00929 cur_pos1 = org_center - cur_len / 2;
00930 cur_pos2 = cur_pos1 + cur_len;
00931 d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
00932 d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
00933 u_off1 = 64 - d_off1;
00934 u_off2 = 64 - d_off2;
00935 delta = 0;
00936
00937
00938 if ( d_off1 == 0 || d_off2 == 0 )
00939 goto Exit;
00940
00941 if ( cur_len <= threshold )
00942 {
00943 if ( d_off2 < cur_len )
00944 {
00945 if ( u_off1 <= d_off2 )
00946 delta = u_off1;
00947 else
00948 delta = -d_off2;
00949 }
00950
00951 goto Exit;
00952 }
00953
00954 if ( threshold < 64 )
00955 {
00956 if ( d_off1 >= threshold || u_off1 >= threshold ||
00957 d_off2 >= threshold || u_off2 >= threshold )
00958 goto Exit;
00959 }
00960
00961 offset = cur_len % 64;
00962
00963 if ( offset < 32 )
00964 {
00965 if ( u_off1 <= offset || d_off2 <= offset )
00966 goto Exit;
00967 }
00968 else
00969 offset = 64 - threshold;
00970
00971 d_off1 = threshold - u_off1;
00972 u_off1 = u_off1 - offset;
00973 u_off2 = threshold - d_off2;
00974 d_off2 = d_off2 - offset;
00975
00976 if ( d_off1 <= u_off1 )
00977 u_off1 = -d_off1;
00978
00979 if ( d_off2 <= u_off2 )
00980 u_off2 = -d_off2;
00981
00982 if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
00983 delta = u_off1;
00984 else
00985 delta = u_off2;
00986
00987 Exit:
00988
00989 #if 1
00990 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
00991 {
00992 if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
00993 delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
00994 else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
00995 delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
00996 }
00997 #endif
00998
00999 cur_pos1 += delta;
01000
01001 if ( edge->opos < edge2->opos )
01002 {
01003 edge->pos = cur_pos1;
01004 edge2->pos = cur_pos1 + cur_len;
01005 }
01006 else
01007 {
01008 edge->pos = cur_pos1 + cur_len;
01009 edge2->pos = cur_pos1;
01010 }
01011
01012 return delta;
01013 }
01014
01015
01016 static void
01017 af_cjk_hint_edges( AF_GlyphHints hints,
01018 AF_Dimension dim )
01019 {
01020 AF_AxisHints axis = &hints->axis[dim];
01021 AF_Edge edges = axis->edges;
01022 AF_Edge edge_limit = edges + axis->num_edges;
01023 FT_PtrDist n_edges;
01024 AF_Edge edge;
01025 AF_Edge anchor = 0;
01026 FT_Pos delta = 0;
01027 FT_Int skipped = 0;
01028
01029
01030
01031 for ( edge = edges; edge < edge_limit; edge++ )
01032 {
01033 AF_Edge edge2;
01034
01035
01036 if ( edge->flags & AF_EDGE_DONE )
01037 continue;
01038
01039
01040 edge2 = edge->link;
01041 if ( !edge2 )
01042 {
01043 skipped++;
01044 continue;
01045 }
01046
01047
01048
01049 if ( edge2 < edge )
01050 {
01051 af_cjk_align_linked_edge( hints, dim, edge2, edge );
01052 edge->flags |= AF_EDGE_DONE;
01053 continue;
01054 }
01055
01056 if ( dim != AF_DIMENSION_VERT && !anchor )
01057 {
01058
01059 #if 0
01060 if ( fixedpitch )
01061 {
01062 AF_Edge left = edge;
01063 AF_Edge right = edge_limit - 1;
01064 AF_EdgeRec left1, left2, right1, right2;
01065 FT_Pos target, center1, center2;
01066 FT_Pos delta1, delta2, d1, d2;
01067
01068
01069 while ( right > left && !right->link )
01070 right--;
01071
01072 left1 = *left;
01073 left2 = *left->link;
01074 right1 = *right->link;
01075 right2 = *right;
01076
01077 delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
01078 target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;
01079
01080 delta1 = delta;
01081 delta1 += af_hint_normal_stem( hints, left, left->link,
01082 delta1, 0 );
01083
01084 if ( left->link != right )
01085 af_hint_normal_stem( hints, right->link, right, delta1, 0 );
01086
01087 center1 = left->pos + ( right->pos - left->pos ) / 2;
01088
01089 if ( center1 >= target )
01090 delta2 = delta - 32;
01091 else
01092 delta2 = delta + 32;
01093
01094 delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );
01095
01096 if ( delta1 != delta2 )
01097 {
01098 if ( left->link != right )
01099 af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );
01100
01101 center2 = left1.pos + ( right2.pos - left1.pos ) / 2;
01102
01103 d1 = center1 - target;
01104 d2 = center2 - target;
01105
01106 if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
01107 {
01108 left->pos = left1.pos;
01109 left->link->pos = left2.pos;
01110
01111 if ( left->link != right )
01112 {
01113 right->link->pos = right1.pos;
01114 right->pos = right2.pos;
01115 }
01116
01117 delta1 = delta2;
01118 }
01119 }
01120
01121 delta = delta1;
01122 right->link->flags |= AF_EDGE_DONE;
01123 right->flags |= AF_EDGE_DONE;
01124 }
01125 else
01126
01127 #endif
01128
01129 delta = af_hint_normal_stem( hints, edge, edge2, 0,
01130 AF_DIMENSION_HORZ );
01131 }
01132 else
01133 af_hint_normal_stem( hints, edge, edge2, delta, dim );
01134
01135 #if 0
01136 printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n",
01137 edge - edges, edge2 - edges,
01138 ( edge->pos - edge->opos ) / 64.0,
01139 ( edge2->pos - edge2->opos ) / 64.0 );
01140 #endif
01141
01142 anchor = edge;
01143 edge->flags |= AF_EDGE_DONE;
01144 edge2->flags |= AF_EDGE_DONE;
01145 }
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162 n_edges = edge_limit - edges;
01163 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
01164 {
01165 AF_Edge edge1, edge2, edge3;
01166 FT_Pos dist1, dist2, span;
01167
01168
01169 if ( n_edges == 6 )
01170 {
01171 edge1 = edges;
01172 edge2 = edges + 2;
01173 edge3 = edges + 4;
01174 }
01175 else
01176 {
01177 edge1 = edges + 1;
01178 edge2 = edges + 5;
01179 edge3 = edges + 9;
01180 }
01181
01182 dist1 = edge2->opos - edge1->opos;
01183 dist2 = edge3->opos - edge2->opos;
01184
01185 span = dist1 - dist2;
01186 if ( span < 0 )
01187 span = -span;
01188
01189 if ( edge1->link == edge1 + 1 &&
01190 edge2->link == edge2 + 1 &&
01191 edge3->link == edge3 + 1 && span < 8 )
01192 {
01193 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
01194 edge3->pos -= delta;
01195 if ( edge3->link )
01196 edge3->link->pos -= delta;
01197
01198
01199 if ( n_edges == 12 )
01200 {
01201 ( edges + 8 )->pos -= delta;
01202 ( edges + 11 )->pos -= delta;
01203 }
01204
01205 edge3->flags |= AF_EDGE_DONE;
01206 if ( edge3->link )
01207 edge3->link->flags |= AF_EDGE_DONE;
01208 }
01209 }
01210
01211 if ( !skipped )
01212 return;
01213
01214
01215
01216
01217
01218 for ( edge = edges; edge < edge_limit; edge++ )
01219 {
01220 if ( edge->flags & AF_EDGE_DONE )
01221 continue;
01222
01223 if ( edge->serif )
01224 {
01225 af_cjk_align_serif_edge( hints, edge->serif, edge );
01226 edge->flags |= AF_EDGE_DONE;
01227 skipped--;
01228 }
01229 }
01230
01231 if ( !skipped )
01232 return;
01233
01234 for ( edge = edges; edge < edge_limit; edge++ )
01235 {
01236 AF_Edge before, after;
01237
01238
01239 if ( edge->flags & AF_EDGE_DONE )
01240 continue;
01241
01242 before = after = edge;
01243
01244 while ( --before >= edges )
01245 if ( before->flags & AF_EDGE_DONE )
01246 break;
01247
01248 while ( ++after < edge_limit )
01249 if ( after->flags & AF_EDGE_DONE )
01250 break;
01251
01252 if ( before >= edges || after < edge_limit )
01253 {
01254 if ( before < edges )
01255 af_cjk_align_serif_edge( hints, after, edge );
01256 else if ( after >= edge_limit )
01257 af_cjk_align_serif_edge( hints, before, edge );
01258 else
01259 {
01260 if ( after->fpos == before->fpos )
01261 edge->pos = before->pos;
01262 else
01263 edge->pos = before->pos +
01264 FT_MulDiv( edge->fpos - before->fpos,
01265 after->pos - before->pos,
01266 after->fpos - before->fpos );
01267 }
01268 }
01269 }
01270 }
01271
01272
01273 static void
01274 af_cjk_align_edge_points( AF_GlyphHints hints,
01275 AF_Dimension dim )
01276 {
01277 AF_AxisHints axis = & hints->axis[dim];
01278 AF_Edge edges = axis->edges;
01279 AF_Edge edge_limit = edges + axis->num_edges;
01280 AF_Edge edge;
01281 FT_Bool snapping;
01282
01283
01284 snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ &&
01285 AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ||
01286 ( dim == AF_DIMENSION_VERT &&
01287 AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) );
01288
01289 for ( edge = edges; edge < edge_limit; edge++ )
01290 {
01291
01292
01293 AF_Segment seg = edge->first;
01294
01295
01296 if ( snapping )
01297 {
01298 do
01299 {
01300 AF_Point point = seg->first;
01301
01302
01303 for (;;)
01304 {
01305 if ( dim == AF_DIMENSION_HORZ )
01306 {
01307 point->x = edge->pos;
01308 point->flags |= AF_FLAG_TOUCH_X;
01309 }
01310 else
01311 {
01312 point->y = edge->pos;
01313 point->flags |= AF_FLAG_TOUCH_Y;
01314 }
01315
01316 if ( point == seg->last )
01317 break;
01318
01319 point = point->next;
01320 }
01321
01322 seg = seg->edge_next;
01323
01324 } while ( seg != edge->first );
01325 }
01326 else
01327 {
01328 FT_Pos delta = edge->pos - edge->opos;
01329
01330
01331 do
01332 {
01333 AF_Point point = seg->first;
01334
01335
01336 for (;;)
01337 {
01338 if ( dim == AF_DIMENSION_HORZ )
01339 {
01340 point->x += delta;
01341 point->flags |= AF_FLAG_TOUCH_X;
01342 }
01343 else
01344 {
01345 point->y += delta;
01346 point->flags |= AF_FLAG_TOUCH_Y;
01347 }
01348
01349 if ( point == seg->last )
01350 break;
01351
01352 point = point->next;
01353 }
01354
01355 seg = seg->edge_next;
01356
01357 } while ( seg != edge->first );
01358 }
01359 }
01360 }
01361
01362
01363 FT_LOCAL_DEF( FT_Error )
01364 af_cjk_hints_apply( AF_GlyphHints hints,
01365 FT_Outline* outline,
01366 AF_LatinMetrics metrics )
01367 {
01368 FT_Error error;
01369 int dim;
01370
01371 FT_UNUSED( metrics );
01372
01373
01374 error = af_glyph_hints_reload( hints, outline, 0 );
01375 if ( error )
01376 goto Exit;
01377
01378
01379 if ( AF_HINTS_DO_HORIZONTAL( hints ) )
01380 {
01381 error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ );
01382 if ( error )
01383 goto Exit;
01384 }
01385
01386 if ( AF_HINTS_DO_VERTICAL( hints ) )
01387 {
01388 error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT );
01389 if ( error )
01390 goto Exit;
01391 }
01392
01393
01394 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
01395 {
01396 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
01397 ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
01398 {
01399
01400 #ifdef AF_USE_WARPER
01401 if ( dim == AF_DIMENSION_HORZ &&
01402 metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL )
01403 {
01404 AF_WarperRec warper;
01405 FT_Fixed scale;
01406 FT_Pos delta;
01407
01408
01409 af_warper_compute( &warper, hints, dim, &scale, &delta );
01410 af_glyph_hints_scale_dim( hints, dim, scale, delta );
01411 continue;
01412 }
01413 #endif
01414
01415 af_cjk_hint_edges( hints, (AF_Dimension)dim );
01416 af_cjk_align_edge_points( hints, (AF_Dimension)dim );
01417 af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
01418 af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
01419 }
01420 }
01421
01422 #if 0
01423 af_glyph_hints_dump_points( hints );
01424 af_glyph_hints_dump_segments( hints );
01425 af_glyph_hints_dump_edges( hints );
01426 #endif
01427
01428 af_glyph_hints_save( hints, outline );
01429
01430 Exit:
01431 return error;
01432 }
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444 static const AF_Script_UniRangeRec af_cjk_uniranges[] =
01445 {
01446 #if 0
01447 AF_UNIRANGE_REC( 0x0100UL, 0xFFFFUL ),
01448 #endif
01449 AF_UNIRANGE_REC( 0x2E80UL, 0x2EFFUL ),
01450 AF_UNIRANGE_REC( 0x2F00UL, 0x2FDFUL ),
01451 AF_UNIRANGE_REC( 0x3000UL, 0x303FUL ),
01452 AF_UNIRANGE_REC( 0x3040UL, 0x309FUL ),
01453 AF_UNIRANGE_REC( 0x30A0UL, 0x30FFUL ),
01454 AF_UNIRANGE_REC( 0x3100UL, 0x312FUL ),
01455 AF_UNIRANGE_REC( 0x3130UL, 0x318FUL ),
01456 AF_UNIRANGE_REC( 0x31A0UL, 0x31BFUL ),
01457 AF_UNIRANGE_REC( 0x31C0UL, 0x31EFUL ),
01458 AF_UNIRANGE_REC( 0x31F0UL, 0x31FFUL ),
01459 AF_UNIRANGE_REC( 0x3200UL, 0x32FFUL ),
01460 AF_UNIRANGE_REC( 0x3300UL, 0x33FFUL ),
01461 AF_UNIRANGE_REC( 0x3400UL, 0x4DBFUL ),
01462 AF_UNIRANGE_REC( 0x4DC0UL, 0x4DFFUL ),
01463 AF_UNIRANGE_REC( 0x4E00UL, 0x9FFFUL ),
01464 AF_UNIRANGE_REC( 0xF900UL, 0xFAFFUL ),
01465 AF_UNIRANGE_REC( 0xFE30UL, 0xFE4FUL ),
01466 AF_UNIRANGE_REC( 0xFF00UL, 0xFFEFUL ),
01467 AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ),
01468 AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ),
01469 AF_UNIRANGE_REC( 0UL, 0UL )
01470 };
01471
01472
01473 AF_DEFINE_SCRIPT_CLASS(af_cjk_script_class,
01474 AF_SCRIPT_CJK,
01475 af_cjk_uniranges,
01476
01477 sizeof( AF_LatinMetricsRec ),
01478
01479 (AF_Script_InitMetricsFunc) af_cjk_metrics_init,
01480 (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale,
01481 (AF_Script_DoneMetricsFunc) NULL,
01482
01483 (AF_Script_InitHintsFunc) af_cjk_hints_init,
01484 (AF_Script_ApplyHintsFunc) af_cjk_hints_apply
01485 )
01486
01487 #else
01488
01489 static const AF_Script_UniRangeRec af_cjk_uniranges[] =
01490 {
01491 AF_UNIRANGE_REC( 0UL, 0UL )
01492 };
01493
01494
01495 AF_DEFINE_SCRIPT_CLASS(af_cjk_script_class,
01496 AF_SCRIPT_CJK,
01497 af_cjk_uniranges,
01498
01499 sizeof( AF_LatinMetricsRec ),
01500
01501 (AF_Script_InitMetricsFunc) NULL,
01502 (AF_Script_ScaleMetricsFunc)NULL,
01503 (AF_Script_DoneMetricsFunc) NULL,
01504
01505 (AF_Script_InitHintsFunc) NULL,
01506 (AF_Script_ApplyHintsFunc) NULL
01507 )
01508
01509 #endif
01510
01511
01512