pshglob.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  pshglob.c                                                              */
00004 /*                                                                         */
00005 /*    PostScript hinter global hinting management (body).                  */
00006 /*    Inspired by the new auto-hinter module.                              */
00007 /*                                                                         */
00008 /*  Copyright 2001, 2002, 2003, 2004, 2006 by                              */
00009 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00010 /*                                                                         */
00011 /*  This file is part of the FreeType project, and may only be used        */
00012 /*  modified and distributed under the terms of the FreeType project       */
00013 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00014 /*  this file you indicate that you have read the license and              */
00015 /*  understand and accept it fully.                                        */
00016 /*                                                                         */
00017 /***************************************************************************/
00018 
00019 
00020 #include <ft2build.h>
00021 #include FT_FREETYPE_H
00022 #include FT_INTERNAL_OBJECTS_H
00023 #include "pshglob.h"
00024 
00025 #ifdef DEBUG_HINTER
00026   PSH_Globals  ps_debug_globals = 0;
00027 #endif
00028 
00029 
00030   /*************************************************************************/
00031   /*************************************************************************/
00032   /*****                                                               *****/
00033   /*****                       STANDARD WIDTHS                         *****/
00034   /*****                                                               *****/
00035   /*************************************************************************/
00036   /*************************************************************************/
00037 
00038 
00039   /* scale the widths/heights table */
00040   static void
00041   psh_globals_scale_widths( PSH_Globals  globals,
00042                             FT_UInt      direction )
00043   {
00044     PSH_Dimension  dim   = &globals->dimension[direction];
00045     PSH_Widths     stdw  = &dim->stdw;
00046     FT_UInt        count = stdw->count;
00047     PSH_Width      width = stdw->widths;
00048     PSH_Width      stand = width;               /* standard width/height */
00049     FT_Fixed       scale = dim->scale_mult;
00050 
00051 
00052     if ( count > 0 )
00053     {
00054       width->cur = FT_MulFix( width->org, scale );
00055       width->fit = FT_PIX_ROUND( width->cur );
00056 
00057       width++;
00058       count--;
00059 
00060       for ( ; count > 0; count--, width++ )
00061       {
00062         FT_Pos  w, dist;
00063 
00064 
00065         w    = FT_MulFix( width->org, scale );
00066         dist = w - stand->cur;
00067 
00068         if ( dist < 0 )
00069           dist = -dist;
00070 
00071         if ( dist < 128 )
00072           w = stand->cur;
00073 
00074         width->cur = w;
00075         width->fit = FT_PIX_ROUND( w );
00076       }
00077     }
00078   }
00079 
00080 
00081 #if 0
00082 
00083   /* org_width is is font units, result in device pixels, 26.6 format */
00084   FT_LOCAL_DEF( FT_Pos )
00085   psh_dimension_snap_width( PSH_Dimension  dimension,
00086                             FT_Int         org_width )
00087   {
00088     FT_UInt  n;
00089     FT_Pos   width     = FT_MulFix( org_width, dimension->scale_mult );
00090     FT_Pos   best      = 64 + 32 + 2;
00091     FT_Pos   reference = width;
00092 
00093 
00094     for ( n = 0; n < dimension->stdw.count; n++ )
00095     {
00096       FT_Pos  w;
00097       FT_Pos  dist;
00098 
00099 
00100       w = dimension->stdw.widths[n].cur;
00101       dist = width - w;
00102       if ( dist < 0 )
00103         dist = -dist;
00104       if ( dist < best )
00105       {
00106         best      = dist;
00107         reference = w;
00108       }
00109     }
00110 
00111     if ( width >= reference )
00112     {
00113       width -= 0x21;
00114       if ( width < reference )
00115         width = reference;
00116     }
00117     else
00118     {
00119       width += 0x21;
00120       if ( width > reference )
00121         width = reference;
00122     }
00123 
00124     return width;
00125   }
00126 
00127 #endif /* 0 */
00128 
00129 
00130   /*************************************************************************/
00131   /*************************************************************************/
00132   /*****                                                               *****/
00133   /*****                       BLUE ZONES                              *****/
00134   /*****                                                               *****/
00135   /*************************************************************************/
00136   /*************************************************************************/
00137 
00138   static void
00139   psh_blues_set_zones_0( PSH_Blues       target,
00140                          FT_Bool         is_others,
00141                          FT_UInt         read_count,
00142                          FT_Short*       read,
00143                          PSH_Blue_Table  top_table,
00144                          PSH_Blue_Table  bot_table )
00145   {
00146     FT_UInt  count_top = top_table->count;
00147     FT_UInt  count_bot = bot_table->count;
00148     FT_Bool  first     = 1;
00149 
00150     FT_UNUSED( target );
00151 
00152 
00153     for ( ; read_count > 1; read_count -= 2 )
00154     {
00155       FT_Int         reference, delta;
00156       FT_UInt        count;
00157       PSH_Blue_Zone  zones, zone;
00158       FT_Bool        top;
00159 
00160 
00161       /* read blue zone entry, and select target top/bottom zone */
00162       top = 0;
00163       if ( first || is_others )
00164       {
00165         reference = read[1];
00166         delta     = read[0] - reference;
00167 
00168         zones = bot_table->zones;
00169         count = count_bot;
00170         first = 0;
00171       }
00172       else
00173       {
00174         reference = read[0];
00175         delta     = read[1] - reference;
00176 
00177         zones = top_table->zones;
00178         count = count_top;
00179         top   = 1;
00180       }
00181 
00182       /* insert into sorted table */
00183       zone = zones;
00184       for ( ; count > 0; count--, zone++ )
00185       {
00186         if ( reference < zone->org_ref )
00187           break;
00188 
00189         if ( reference == zone->org_ref )
00190         {
00191           FT_Int  delta0 = zone->org_delta;
00192 
00193 
00194           /* we have two zones on the same reference position -- */
00195           /* only keep the largest one                           */
00196           if ( delta < 0 )
00197           {
00198             if ( delta < delta0 )
00199               zone->org_delta = delta;
00200           }
00201           else
00202           {
00203             if ( delta > delta0 )
00204               zone->org_delta = delta;
00205           }
00206           goto Skip;
00207         }
00208       }
00209 
00210       for ( ; count > 0; count-- )
00211         zone[count] = zone[count-1];
00212 
00213       zone->org_ref   = reference;
00214       zone->org_delta = delta;
00215 
00216       if ( top )
00217         count_top++;
00218       else
00219         count_bot++;
00220 
00221     Skip:
00222       read += 2;
00223     }
00224 
00225     top_table->count = count_top;
00226     bot_table->count = count_bot;
00227   }
00228 
00229 
00230   /* Re-read blue zones from the original fonts and store them into out */
00231   /* private structure.  This function re-orders, sanitizes and         */
00232   /* fuzz-expands the zones as well.                                    */
00233   static void
00234   psh_blues_set_zones( PSH_Blues  target,
00235                        FT_UInt    count,
00236                        FT_Short*  blues,
00237                        FT_UInt    count_others,
00238                        FT_Short*  other_blues,
00239                        FT_Int     fuzz,
00240                        FT_Int     family )
00241   {
00242     PSH_Blue_Table  top_table, bot_table;
00243     FT_Int          count_top, count_bot;
00244 
00245 
00246     if ( family )
00247     {
00248       top_table = &target->family_top;
00249       bot_table = &target->family_bottom;
00250     }
00251     else
00252     {
00253       top_table = &target->normal_top;
00254       bot_table = &target->normal_bottom;
00255     }
00256 
00257     /* read the input blue zones, and build two sorted tables  */
00258     /* (one for the top zones, the other for the bottom zones) */
00259     top_table->count = 0;
00260     bot_table->count = 0;
00261 
00262     /* first, the blues */
00263     psh_blues_set_zones_0( target, 0,
00264                            count, blues, top_table, bot_table );
00265     psh_blues_set_zones_0( target, 1,
00266                            count_others, other_blues, top_table, bot_table );
00267 
00268     count_top = top_table->count;
00269     count_bot = bot_table->count;
00270 
00271     /* sanitize top table */
00272     if ( count_top > 0 )
00273     {
00274       PSH_Blue_Zone  zone = top_table->zones;
00275 
00276 
00277       for ( count = count_top; count > 0; count--, zone++ )
00278       {
00279         FT_Int  delta;
00280 
00281 
00282         if ( count > 1 )
00283         {
00284           delta = zone[1].org_ref - zone[0].org_ref;
00285           if ( zone->org_delta > delta )
00286             zone->org_delta = delta;
00287         }
00288 
00289         zone->org_bottom = zone->org_ref;
00290         zone->org_top    = zone->org_delta + zone->org_ref;
00291       }
00292     }
00293 
00294     /* sanitize bottom table */
00295     if ( count_bot > 0 )
00296     {
00297       PSH_Blue_Zone  zone = bot_table->zones;
00298 
00299 
00300       for ( count = count_bot; count > 0; count--, zone++ )
00301       {
00302         FT_Int  delta;
00303 
00304 
00305         if ( count > 1 )
00306         {
00307           delta = zone[0].org_ref - zone[1].org_ref;
00308           if ( zone->org_delta < delta )
00309             zone->org_delta = delta;
00310         }
00311 
00312         zone->org_top    = zone->org_ref;
00313         zone->org_bottom = zone->org_delta + zone->org_ref;
00314       }
00315     }
00316 
00317     /* expand top and bottom tables with blue fuzz */
00318     {
00319       FT_Int         dim, top, bot, delta;
00320       PSH_Blue_Zone  zone;
00321 
00322 
00323       zone  = top_table->zones;
00324       count = count_top;
00325 
00326       for ( dim = 1; dim >= 0; dim-- )
00327       {
00328         if ( count > 0 )
00329         {
00330           /* expand the bottom of the lowest zone normally */
00331           zone->org_bottom -= fuzz;
00332 
00333           /* expand the top and bottom of intermediate zones;    */
00334           /* checking that the interval is smaller than the fuzz */
00335           top = zone->org_top;
00336 
00337           for ( count--; count > 0; count-- )
00338           {
00339             bot   = zone[1].org_bottom;
00340             delta = bot - top;
00341 
00342             if ( delta < 2 * fuzz )
00343               zone[0].org_top = zone[1].org_bottom = top + delta / 2;
00344             else
00345             {
00346               zone[0].org_top    = top + fuzz;
00347               zone[1].org_bottom = bot - fuzz;
00348             }
00349 
00350             zone++;
00351             top = zone->org_top;
00352           }
00353 
00354           /* expand the top of the highest zone normally */
00355           zone->org_top = top + fuzz;
00356         }
00357         zone  = bot_table->zones;
00358         count = count_bot;
00359       }
00360     }
00361   }
00362 
00363 
00364   /* reset the blues table when the device transform changes */
00365   static void
00366   psh_blues_scale_zones( PSH_Blues  blues,
00367                          FT_Fixed   scale,
00368                          FT_Pos     delta )
00369   {
00370     FT_UInt         count;
00371     FT_UInt         num;
00372     PSH_Blue_Table  table = 0;
00373 
00374     /*                                                        */
00375     /* Determine whether we need to suppress overshoots or    */
00376     /* not.  We simply need to compare the vertical scale     */
00377     /* parameter to the raw bluescale value.  Here is why:    */
00378     /*                                                        */
00379     /*   We need to suppress overshoots for all pointsizes.   */
00380     /*   At 300dpi that satisfies:                            */
00381     /*                                                        */
00382     /*      pointsize < 240*bluescale + 0.49                  */
00383     /*                                                        */
00384     /*   This corresponds to:                                 */
00385     /*                                                        */
00386     /*      pixelsize < 1000*bluescale + 49/24                */
00387     /*                                                        */
00388     /*      scale*EM_Size < 1000*bluescale + 49/24            */
00389     /*                                                        */
00390     /*   However, for normal Type 1 fonts, EM_Size is 1000!   */
00391     /*   We thus only check:                                  */
00392     /*                                                        */
00393     /*      scale < bluescale + 49/24000                      */
00394     /*                                                        */
00395     /*   which we shorten to                                  */
00396     /*                                                        */
00397     /*      "scale < bluescale"                               */
00398     /*                                                        */
00399     /* Note that `blue_scale' is stored 1000 times its real   */
00400     /* value, and that `scale' converts from font units to    */
00401     /* fractional pixels.                                     */
00402     /*                                                        */
00403 
00404     /* 1000 / 64 = 125 / 8 */
00405     if ( scale >= 0x20C49BAL )
00406       blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 );
00407     else
00408       blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 );
00409 
00410     /*                                                        */
00411     /*  The blue threshold is the font units distance under   */
00412     /*  which overshoots are suppressed due to the BlueShift  */
00413     /*  even if the scale is greater than BlueScale.          */
00414     /*                                                        */
00415     /*  It is the smallest distance such that                 */
00416     /*                                                        */
00417     /*    dist <= BlueShift && dist*scale <= 0.5 pixels       */
00418     /*                                                        */
00419     {
00420       FT_Int  threshold = blues->blue_shift;
00421 
00422 
00423       while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
00424         threshold--;
00425 
00426       blues->blue_threshold = threshold;
00427     }
00428 
00429     for ( num = 0; num < 4; num++ )
00430     {
00431       PSH_Blue_Zone  zone;
00432 
00433 
00434       switch ( num )
00435       {
00436       case 0:
00437         table = &blues->normal_top;
00438         break;
00439       case 1:
00440         table = &blues->normal_bottom;
00441         break;
00442       case 2:
00443         table = &blues->family_top;
00444         break;
00445       default:
00446         table = &blues->family_bottom;
00447         break;
00448       }
00449 
00450       zone  = table->zones;
00451       count = table->count;
00452       for ( ; count > 0; count--, zone++ )
00453       {
00454         zone->cur_top    = FT_MulFix( zone->org_top,    scale ) + delta;
00455         zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta;
00456         zone->cur_ref    = FT_MulFix( zone->org_ref,    scale ) + delta;
00457         zone->cur_delta  = FT_MulFix( zone->org_delta,  scale );
00458 
00459         /* round scaled reference position */
00460         zone->cur_ref = FT_PIX_ROUND( zone->cur_ref );
00461 
00462 #if 0
00463         if ( zone->cur_ref > zone->cur_top )
00464           zone->cur_ref -= 64;
00465         else if ( zone->cur_ref < zone->cur_bottom )
00466           zone->cur_ref += 64;
00467 #endif
00468       }
00469     }
00470 
00471     /* process the families now */
00472 
00473     for ( num = 0; num < 2; num++ )
00474     {
00475       PSH_Blue_Zone   zone1, zone2;
00476       FT_UInt         count1, count2;
00477       PSH_Blue_Table  normal, family;
00478 
00479 
00480       switch ( num )
00481       {
00482       case 0:
00483         normal = &blues->normal_top;
00484         family = &blues->family_top;
00485         break;
00486 
00487       default:
00488         normal = &blues->normal_bottom;
00489         family = &blues->family_bottom;
00490       }
00491 
00492       zone1  = normal->zones;
00493       count1 = normal->count;
00494 
00495       for ( ; count1 > 0; count1--, zone1++ )
00496       {
00497         /* try to find a family zone whose reference position is less */
00498         /* than 1 pixel far from the current zone                     */
00499         zone2  = family->zones;
00500         count2 = family->count;
00501 
00502         for ( ; count2 > 0; count2--, zone2++ )
00503         {
00504           FT_Pos  Delta;
00505 
00506 
00507           Delta = zone1->org_ref - zone2->org_ref;
00508           if ( Delta < 0 )
00509             Delta = -Delta;
00510 
00511           if ( FT_MulFix( Delta, scale ) < 64 )
00512           {
00513             zone1->cur_top    = zone2->cur_top;
00514             zone1->cur_bottom = zone2->cur_bottom;
00515             zone1->cur_ref    = zone2->cur_ref;
00516             zone1->cur_delta  = zone2->cur_delta;
00517             break;
00518           }
00519         }
00520       }
00521     }
00522   }
00523 
00524 
00525   FT_LOCAL_DEF( void )
00526   psh_blues_snap_stem( PSH_Blues      blues,
00527                        FT_Int         stem_top,
00528                        FT_Int         stem_bot,
00529                        PSH_Alignment  alignment )
00530   {
00531     PSH_Blue_Table  table;
00532     FT_UInt         count;
00533     FT_Pos          delta;
00534     PSH_Blue_Zone   zone;
00535     FT_Int          no_shoots;
00536 
00537 
00538     alignment->align = PSH_BLUE_ALIGN_NONE;
00539 
00540     no_shoots = blues->no_overshoots;
00541 
00542     /* look up stem top in top zones table */
00543     table = &blues->normal_top;
00544     count = table->count;
00545     zone  = table->zones;
00546 
00547     for ( ; count > 0; count--, zone++ )
00548     {
00549       delta = stem_top - zone->org_bottom;
00550       if ( delta < -blues->blue_fuzz )
00551         break;
00552 
00553       if ( stem_top <= zone->org_top + blues->blue_fuzz )
00554       {
00555         if ( no_shoots || delta <= blues->blue_threshold )
00556         {
00557           alignment->align    |= PSH_BLUE_ALIGN_TOP;
00558           alignment->align_top = zone->cur_ref;
00559         }
00560         break;
00561       }
00562     }
00563 
00564     /* look up stem bottom in bottom zones table */
00565     table = &blues->normal_bottom;
00566     count = table->count;
00567     zone  = table->zones + count-1;
00568 
00569     for ( ; count > 0; count--, zone-- )
00570     {
00571       delta = zone->org_top - stem_bot;
00572       if ( delta < -blues->blue_fuzz )
00573         break;
00574 
00575       if ( stem_bot >= zone->org_bottom - blues->blue_fuzz )
00576       {
00577         if ( no_shoots || delta < blues->blue_threshold )
00578         {
00579           alignment->align    |= PSH_BLUE_ALIGN_BOT;
00580           alignment->align_bot = zone->cur_ref;
00581         }
00582         break;
00583       }
00584     }
00585   }
00586 
00587 
00588   /*************************************************************************/
00589   /*************************************************************************/
00590   /*****                                                               *****/
00591   /*****                        GLOBAL HINTS                           *****/
00592   /*****                                                               *****/
00593   /*************************************************************************/
00594   /*************************************************************************/
00595 
00596   static void
00597   psh_globals_destroy( PSH_Globals  globals )
00598   {
00599     if ( globals )
00600     {
00601       FT_Memory  memory;
00602 
00603 
00604       memory = globals->memory;
00605       globals->dimension[0].stdw.count = 0;
00606       globals->dimension[1].stdw.count = 0;
00607 
00608       globals->blues.normal_top.count    = 0;
00609       globals->blues.normal_bottom.count = 0;
00610       globals->blues.family_top.count    = 0;
00611       globals->blues.family_bottom.count = 0;
00612 
00613       FT_FREE( globals );
00614 
00615 #ifdef DEBUG_HINTER
00616       ps_debug_globals = 0;
00617 #endif
00618     }
00619   }
00620 
00621 
00622   static FT_Error
00623   psh_globals_new( FT_Memory     memory,
00624                    T1_Private*   priv,
00625                    PSH_Globals  *aglobals )
00626   {
00627     PSH_Globals  globals;
00628     FT_Error     error;
00629 
00630 
00631     if ( !FT_NEW( globals ) )
00632     {
00633       FT_UInt    count;
00634       FT_Short*  read;
00635 
00636 
00637       globals->memory = memory;
00638 
00639       /* copy standard widths */
00640       {
00641         PSH_Dimension  dim   = &globals->dimension[1];
00642         PSH_Width      write = dim->stdw.widths;
00643 
00644 
00645         write->org = priv->standard_width[0];
00646         write++;
00647 
00648         read = priv->snap_widths;
00649         for ( count = priv->num_snap_widths; count > 0; count-- )
00650         {
00651           write->org = *read;
00652           write++;
00653           read++;
00654         }
00655 
00656         dim->stdw.count = priv->num_snap_widths + 1;
00657       }
00658 
00659       /* copy standard heights */
00660       {
00661         PSH_Dimension  dim = &globals->dimension[0];
00662         PSH_Width      write = dim->stdw.widths;
00663 
00664 
00665         write->org = priv->standard_height[0];
00666         write++;
00667         read = priv->snap_heights;
00668         for ( count = priv->num_snap_heights; count > 0; count-- )
00669         {
00670           write->org = *read;
00671           write++;
00672           read++;
00673         }
00674 
00675         dim->stdw.count = priv->num_snap_heights + 1;
00676       }
00677 
00678       /* copy blue zones */
00679       psh_blues_set_zones( &globals->blues, priv->num_blue_values,
00680                            priv->blue_values, priv->num_other_blues,
00681                            priv->other_blues, priv->blue_fuzz, 0 );
00682 
00683       psh_blues_set_zones( &globals->blues, priv->num_family_blues,
00684                            priv->family_blues, priv->num_family_other_blues,
00685                            priv->family_other_blues, priv->blue_fuzz, 1 );
00686 
00687       globals->blues.blue_scale = priv->blue_scale;
00688       globals->blues.blue_shift = priv->blue_shift;
00689       globals->blues.blue_fuzz  = priv->blue_fuzz;
00690 
00691       globals->dimension[0].scale_mult  = 0;
00692       globals->dimension[0].scale_delta = 0;
00693       globals->dimension[1].scale_mult  = 0;
00694       globals->dimension[1].scale_delta = 0;
00695 
00696 #ifdef DEBUG_HINTER
00697       ps_debug_globals = globals;
00698 #endif
00699     }
00700 
00701     *aglobals = globals;
00702     return error;
00703   }
00704 
00705 
00706   FT_LOCAL_DEF( FT_Error )
00707   psh_globals_set_scale( PSH_Globals  globals,
00708                          FT_Fixed     x_scale,
00709                          FT_Fixed     y_scale,
00710                          FT_Fixed     x_delta,
00711                          FT_Fixed     y_delta )
00712   {
00713     PSH_Dimension  dim = &globals->dimension[0];
00714 
00715 
00716     dim = &globals->dimension[0];
00717     if ( x_scale != dim->scale_mult  ||
00718          x_delta != dim->scale_delta )
00719     {
00720       dim->scale_mult  = x_scale;
00721       dim->scale_delta = x_delta;
00722 
00723       psh_globals_scale_widths( globals, 0 );
00724     }
00725 
00726     dim = &globals->dimension[1];
00727     if ( y_scale != dim->scale_mult  ||
00728          y_delta != dim->scale_delta )
00729     {
00730       dim->scale_mult  = y_scale;
00731       dim->scale_delta = y_delta;
00732 
00733       psh_globals_scale_widths( globals, 1 );
00734       psh_blues_scale_zones( &globals->blues, y_scale, y_delta );
00735     }
00736 
00737     return 0;
00738   }
00739 
00740 
00741   FT_LOCAL_DEF( void )
00742   psh_globals_funcs_init( PSH_Globals_FuncsRec*  funcs )
00743   {
00744     funcs->create    = psh_globals_new;
00745     funcs->set_scale = psh_globals_set_scale;
00746     funcs->destroy   = psh_globals_destroy;
00747   }
00748 
00749 
00750 /* END */

Generated on Tue Jul 5 14:13:50 2011 for ROOT_528-00b_version by  doxygen 1.5.1