ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

afcjk.c
Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  afcjk.c                                                                */
00004 /*                                                                         */
00005 /*    Auto-fitter hinting routines for CJK script (body).                  */
00006 /*                                                                         */
00007 /*  Copyright 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    *  The algorithm is based on akito's autohint patch, available here:
00020    *
00021    *  http://www.kde.gr.jp/~akito/patch/freetype2/
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   /*****              C J K   G L O B A L   M E T R I C S              *****/
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     /* TODO are there blues? */
00058 
00059     if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
00060       face->charmap = NULL;
00061     else
00062     {
00063       /* latin's version would suffice */
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   /*****              C J K   G L Y P H   A N A L Y S I S              *****/
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     /* a segment is round if it doesn't have successive */
00132     /* on-curve points.                                 */
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     /* now compare each segment to the others */
00180     for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00181     {
00182       /* the fake segments are for metrics hinting only */
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      *  now compute the `serif' segments
00235      *
00236      *  In Hanzi, some strokes are wider on one or both of the ends.
00237      *  We either identify the stems on the ends as serifs or remove
00238      *  the linkage, depending on the length of the stems.
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           /* seg2 < seg1 < link1 < link2 */
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     /* We begin by generating a sorted table of edges for the current    */
00350     /* direction.  To do so, we simply scan each segment and try to find */
00351     /* an edge in our table that corresponds to its position.            */
00352     /*                                                                   */
00353     /* If no edge is found, we create and insert a new edge in the       */
00354     /* sorted table.  Otherwise, we simply add the segment to the edge's */
00355     /* list which is then processed in the second step to compute the    */
00356     /* edge's properties.                                                */
00357     /*                                                                   */
00358     /* Note that the edges table is sorted along the segment/edge        */
00359     /* position.                                                         */
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       /* look for an edge corresponding to the segment */
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           /* check whether all linked segments of the candidate edge */
00397           /* can make a single edge.                                 */
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         /* insert a new edge in the list and */
00432         /* sort according to the position    */
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         /* add the segment to the new edge's list */
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         /* if an edge was found, simply add the segment to the edge's */
00452         /* list                                                       */
00453         seg->edge_next         = found->first;
00454         found->last->edge_next = seg;
00455         found->last            = seg;
00456       }
00457     }
00458 
00459     /*********************************************************************/
00460     /*                                                                   */
00461     /* Good, we now compute each edge's properties according to segments */
00462     /* found on its position.  Basically, these are as follows.          */
00463     /*                                                                   */
00464     /*  - edge's main direction                                          */
00465     /*  - stem edge, serif edge or both (which defaults to stem then)    */
00466     /*  - rounded edge, straight or both (which defaults to straight)    */
00467     /*  - link for edge                                                  */
00468     /*                                                                   */
00469     /*********************************************************************/
00470 
00471     /* first of all, set the `edge' field in each segment -- this is     */
00472     /* required in order to compute edge links                           */
00473     /*                                                                   */
00474     /* Note that removing this loop and setting the `edge' field of each */
00475     /* segment directly in the code above slows down execution speed for */
00476     /* some reasons on platforms like the Sun.                           */
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       /* now compute each edge properties */
00497       for ( edge = edges; edge < edge_limit; edge++ )
00498       {
00499         FT_Int  is_round    = 0;  /* does it contain round segments?    */
00500         FT_Int  is_straight = 0;  /* does it contain straight segments? */
00501 
00502 
00503         seg = edge->first;
00504 
00505         do
00506         {
00507           FT_Bool  is_serif;
00508 
00509 
00510           /* check for roundness of segment */
00511           if ( seg->flags & AF_EDGE_ROUND )
00512             is_round++;
00513           else
00514             is_straight++;
00515 
00516           /* check for links -- if seg->serif is set, then seg->link must */
00517           /* be ignored                                                   */
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         /* set the round/straight flags */
00567         edge->flags = AF_EDGE_NORMAL;
00568 
00569         if ( is_round > 0 && is_round >= is_straight )
00570           edge->flags |= AF_EDGE_ROUND;
00571 
00572         /* get rid of serifs if link is set                 */
00573         /* XXX: This gets rid of many unpleasant artefacts! */
00574         /*      Example: the `c' in cour.pfa at size 13     */
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      *  correct x_scale and y_scale when needed, since they may have
00616      *  been modified af_cjk_scale_dim above
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     /* compute flags depending on render mode, etc. */
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      *  We snap the width of vertical stems for the monochrome and
00636      *  horizontal LCD rendering targets only.
00637      */
00638     if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
00639       other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
00640 
00641     /*
00642      *  We snap the width of horizontal stems for the monochrome and
00643      *  vertical LCD rendering targets only.
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      *  We adjust stems to full pixels only if we don't use the `light' mode.
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   /*****          C J K   G L Y P H   G R I D - F I T T I N G          *****/
00670   /*****                                                               *****/
00671   /*************************************************************************/
00672   /*************************************************************************/
00673 
00674   /* snap a given width in scaled coordinates to one of the */
00675   /* current standard widths                                */
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   /* compute the snapped width of a given stem */
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       /* smooth hinting process: very lightly quantize the stem width */
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       /* strong hinting process: snap the stem width to integer pixels */
00792 
00793       dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
00794 
00795       if ( vertical )
00796       {
00797         /* in the case of vertical hinting, always round */
00798         /* the stem heights to integer pixels            */
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           /* monochrome horizontal hinting: snap widths to integer pixels */
00810           /* with a different threshold                                   */
00811 
00812           if ( dist < 64 )
00813             dist = 64;
00814           else
00815             dist = ( dist + 32 ) & ~63;
00816         }
00817         else
00818         {
00819           /* for horizontal anti-aliased hinting, we adopt a more subtle */
00820           /* approach: we strengthen small stems, round stems whose size */
00821           /* is between 1 and 2 pixels to an integer, otherwise nothing  */
00822 
00823           if ( dist < 48 )
00824             dist = ( dist + 64 ) >> 1;
00825 
00826           else if ( dist < 128 )
00827             dist = ( dist + 22 ) & ~63;
00828           else
00829             /* round otherwise to prevent color fringes in LCD mode */
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   /* align one stem edge relative to the previous stem edge */
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   /****                    E D G E   H I N T I N G                      ****/
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     /* now we align all stem edges. */
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       /* skip all non-stem edges */
01040       edge2 = edge->link;
01041       if ( !edge2 )
01042       {
01043         skipped++;
01044         continue;
01045       }
01046 
01047       /* now align the stem */
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 /* 0 */
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     /* make sure that lowercase m's maintain their symmetry */
01148 
01149     /* In general, lowercase m's have six vertical edges if they are sans */
01150     /* serif, or twelve if they are with serifs.  This implementation is  */
01151     /* based on that assumption, and seems to work very well with most    */
01152     /* faces.  However, if for a certain face this assumption is not      */
01153     /* true, the m is just rendered like before.  In addition, any stem   */
01154     /* correction will only be applied to symmetrical glyphs (even if the */
01155     /* glyph is not an m), so the potential for unwanted distortion is    */
01156     /* relatively low.                                                    */
01157 
01158     /* We don't handle horizontal edges since we can't easily assure that */
01159     /* the third (lowest) stem aligns with the base line; it might end up */
01160     /* one pixel higher or lower.                                         */
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         /* move the serifs along with the stem */
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      *  now hint the remaining edges (serifs and single) in order
01216      *  to complete our processing
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       /* move the points of each segment     */
01292       /* in each edge to the edge's position */
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 );
01375     if ( error )
01376       goto Exit;
01377 
01378     /* analyze glyph outline */
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     /* grid-fit the outline */
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 /* AF_USE_WARPER */
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   /*****                C J K   S C R I P T   C L A S S                *****/
01439   /*****                                                               *****/
01440   /*************************************************************************/
01441   /*************************************************************************/
01442 
01443 
01444   static const AF_Script_UniRangeRec  af_cjk_uniranges[] =
01445   {
01446 #if 0
01447     AF_UNIRANGE_REC(  0x0100UL,  0xFFFFUL ),  /* why this? */
01448 #endif
01449     AF_UNIRANGE_REC(  0x2E80UL,  0x2EFFUL ),  /* CJK Radicals Supplement                 */
01450     AF_UNIRANGE_REC(  0x2F00UL,  0x2FDFUL ),  /* Kangxi Radicals                         */
01451     AF_UNIRANGE_REC(  0x3000UL,  0x303FUL ),  /* CJK Symbols and Punctuation             */
01452     AF_UNIRANGE_REC(  0x3040UL,  0x309FUL ),  /* Hiragana                                */
01453     AF_UNIRANGE_REC(  0x30A0UL,  0x30FFUL ),  /* Katakana                                */
01454     AF_UNIRANGE_REC(  0x3100UL,  0x312FUL ),  /* Bopomofo                                */
01455     AF_UNIRANGE_REC(  0x3130UL,  0x318FUL ),  /* Hangul Compatibility Jamo               */
01456     AF_UNIRANGE_REC(  0x31A0UL,  0x31BFUL ),  /* Bopomofo Extended                       */
01457     AF_UNIRANGE_REC(  0x31C0UL,  0x31EFUL ),  /* CJK Strokes                             */
01458     AF_UNIRANGE_REC(  0x31F0UL,  0x31FFUL ),  /* Katakana Phonetic Extensions            */
01459     AF_UNIRANGE_REC(  0x3200UL,  0x32FFUL ),  /* Enclosed CJK Letters and Months         */
01460     AF_UNIRANGE_REC(  0x3300UL,  0x33FFUL ),  /* CJK Compatibility                       */
01461     AF_UNIRANGE_REC(  0x3400UL,  0x4DBFUL ),  /* CJK Unified Ideographs Extension A      */
01462     AF_UNIRANGE_REC(  0x4DC0UL,  0x4DFFUL ),  /* Yijing Hexagram Symbols                 */
01463     AF_UNIRANGE_REC(  0x4E00UL,  0x9FFFUL ),  /* CJK Unified Ideographs                  */
01464     AF_UNIRANGE_REC(  0xF900UL,  0xFAFFUL ),  /* CJK Compatibility Ideographs            */
01465     AF_UNIRANGE_REC(  0xFE30UL,  0xFE4FUL ),  /* CJK Compatibility Forms                 */
01466     AF_UNIRANGE_REC(  0xFF00UL,  0xFFEFUL ),  /* Halfwidth and Fullwidth Forms           */
01467     AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ),  /* CJK Unified Ideographs Extension B      */
01468     AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ),  /* CJK Compatibility Ideographs Supplement */
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 /* !AF_CONFIG_OPTION_CJK */
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 /* !AF_CONFIG_OPTION_CJK */
01510 
01511 
01512 /* END */

Generated on Sun May 27 2012 04:33:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.