afloader.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  afloader.c                                                             */
00004 /*                                                                         */
00005 /*    Auto-fitter glyph loading routines (body).                           */
00006 /*                                                                         */
00007 /*  Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by                  */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include "afloader.h"
00020 #include "afhints.h"
00021 #include "afglobal.h"
00022 #include "aferrors.h"
00023 
00024 
00025   FT_LOCAL_DEF( FT_Error )
00026   af_loader_init( AF_Loader  loader,
00027                   FT_Memory  memory )
00028   {
00029     FT_ZERO( loader );
00030 
00031     af_glyph_hints_init( &loader->hints, memory );
00032 #ifdef AF_DEBUG
00033     _af_debug_hints = &loader->hints;
00034 #endif
00035     return FT_GlyphLoader_New( memory, &loader->gloader );
00036   }
00037 
00038 
00039   FT_LOCAL_DEF( FT_Error )
00040   af_loader_reset( AF_Loader  loader,
00041                    FT_Face    face )
00042   {
00043     FT_Error  error = AF_Err_Ok;
00044 
00045 
00046     loader->face    = face;
00047     loader->globals = (AF_FaceGlobals)face->autohint.data;
00048 
00049     FT_GlyphLoader_Rewind( loader->gloader );
00050 
00051     if ( loader->globals == NULL )
00052     {
00053       error = af_face_globals_new( face, &loader->globals );
00054       if ( !error )
00055       {
00056         face->autohint.data =
00057           (FT_Pointer)loader->globals;
00058         face->autohint.finalizer =
00059           (FT_Generic_Finalizer)af_face_globals_free;
00060       }
00061     }
00062 
00063     return error;
00064   }
00065 
00066 
00067   FT_LOCAL_DEF( void )
00068   af_loader_done( AF_Loader  loader )
00069   {
00070     af_glyph_hints_done( &loader->hints );
00071 
00072     loader->face    = NULL;
00073     loader->globals = NULL;
00074 
00075 #ifdef AF_DEBUG
00076     _af_debug_hints = NULL;
00077 #endif
00078     FT_GlyphLoader_Done( loader->gloader );
00079     loader->gloader = NULL;
00080   }
00081 
00082 
00083   static FT_Error
00084   af_loader_load_g( AF_Loader  loader,
00085                     AF_Scaler  scaler,
00086                     FT_UInt    glyph_index,
00087                     FT_Int32   load_flags,
00088                     FT_UInt    depth )
00089   {
00090     FT_Error          error;
00091     FT_Face           face     = loader->face;
00092     FT_GlyphLoader    gloader  = loader->gloader;
00093     AF_ScriptMetrics  metrics  = loader->metrics;
00094     AF_GlyphHints     hints    = &loader->hints;
00095     FT_GlyphSlot      slot     = face->glyph;
00096     FT_Slot_Internal  internal = slot->internal;
00097 
00098 
00099     error = FT_Load_Glyph( face, glyph_index, load_flags );
00100     if ( error )
00101       goto Exit;
00102 
00103     loader->transformed = internal->glyph_transformed;
00104     if ( loader->transformed )
00105     {
00106       FT_Matrix  inverse;
00107 
00108 
00109       loader->trans_matrix = internal->glyph_matrix;
00110       loader->trans_delta  = internal->glyph_delta;
00111 
00112       inverse = loader->trans_matrix;
00113       FT_Matrix_Invert( &inverse );
00114       FT_Vector_Transform( &loader->trans_delta, &inverse );
00115     }
00116 
00117     /* set linear metrics */
00118     slot->linearHoriAdvance = slot->metrics.horiAdvance;
00119     slot->linearVertAdvance = slot->metrics.vertAdvance;
00120 
00121     switch ( slot->format )
00122     {
00123     case FT_GLYPH_FORMAT_OUTLINE:
00124       /* translate the loaded glyph when an internal transform is needed */
00125       if ( loader->transformed )
00126         FT_Outline_Translate( &slot->outline,
00127                               loader->trans_delta.x,
00128                               loader->trans_delta.y );
00129 
00130       /* copy the outline points in the loader's current               */
00131       /* extra points which is used to keep original glyph coordinates */
00132       error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
00133                                            slot->outline.n_points + 4,
00134                                            slot->outline.n_contours );
00135       if ( error )
00136         goto Exit;
00137 
00138       FT_ARRAY_COPY( gloader->current.outline.points,
00139                      slot->outline.points,
00140                      slot->outline.n_points );
00141 
00142       FT_ARRAY_COPY( gloader->current.outline.contours,
00143                      slot->outline.contours,
00144                      slot->outline.n_contours );
00145 
00146       FT_ARRAY_COPY( gloader->current.outline.tags,
00147                      slot->outline.tags,
00148                      slot->outline.n_points );
00149 
00150       gloader->current.outline.n_points   = slot->outline.n_points;
00151       gloader->current.outline.n_contours = slot->outline.n_contours;
00152 
00153       /* compute original horizontal phantom points (and ignore */
00154       /* vertical ones)                                         */
00155       loader->pp1.x = hints->x_delta;
00156       loader->pp1.y = hints->y_delta;
00157       loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
00158                                  hints->x_scale ) + hints->x_delta;
00159       loader->pp2.y = hints->y_delta;
00160 
00161       /* be sure to check for spacing glyphs */
00162       if ( slot->outline.n_points == 0 )
00163         goto Hint_Metrics;
00164 
00165       /* now load the slot image into the auto-outline and run the */
00166       /* automatic hinting process                                 */
00167       if ( metrics->clazz->script_hints_apply )
00168         metrics->clazz->script_hints_apply( hints,
00169                                             &gloader->current.outline,
00170                                             metrics );
00171 
00172       /* we now need to hint the metrics according to the change in */
00173       /* width/positioning that occurred during the hinting process */
00174       if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
00175       {
00176         FT_Pos        old_rsb, old_lsb, new_lsb;
00177         FT_Pos        pp1x_uh, pp2x_uh;
00178         AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
00179         AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
00180         AF_Edge       edge2 = edge1 +
00181                               axis->num_edges - 1; /* rightmost edge */
00182 
00183 
00184         if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
00185         {
00186           old_rsb = loader->pp2.x - edge2->opos;
00187           old_lsb = edge1->opos;
00188           new_lsb = edge1->pos;
00189 
00190           /* remember unhinted values to later account */
00191           /* for rounding errors                       */
00192 
00193           pp1x_uh = new_lsb    - old_lsb;
00194           pp2x_uh = edge2->pos + old_rsb;
00195 
00196           /* prefer too much space over too little space */
00197           /* for very small sizes                        */
00198 
00199           if ( old_lsb < 24 )
00200             pp1x_uh -= 8;
00201 
00202           if ( old_rsb < 24 )
00203             pp2x_uh += 8;
00204 
00205           loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
00206           loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
00207 
00208           if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
00209             loader->pp1.x -= 64;
00210 
00211           if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
00212             loader->pp2.x += 64;
00213 
00214           slot->lsb_delta = loader->pp1.x - pp1x_uh;
00215           slot->rsb_delta = loader->pp2.x - pp2x_uh;
00216         }
00217         else
00218         {
00219           FT_Pos  pp1x = loader->pp1.x;
00220           FT_Pos  pp2x = loader->pp2.x;
00221 
00222 
00223           loader->pp1.x = FT_PIX_ROUND( pp1x );
00224           loader->pp2.x = FT_PIX_ROUND( pp2x );
00225 
00226           slot->lsb_delta = loader->pp1.x - pp1x;
00227           slot->rsb_delta = loader->pp2.x - pp2x;
00228         }
00229       }
00230       else
00231       {
00232         FT_Pos  pp1x = loader->pp1.x;
00233         FT_Pos  pp2x = loader->pp2.x;
00234 
00235 
00236         loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
00237         loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
00238 
00239         slot->lsb_delta = loader->pp1.x - pp1x;
00240         slot->rsb_delta = loader->pp2.x - pp2x;
00241       }
00242 
00243       /* good, we simply add the glyph to our loader's base */
00244       FT_GlyphLoader_Add( gloader );
00245       break;
00246 
00247     case FT_GLYPH_FORMAT_COMPOSITE:
00248       {
00249         FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
00250         FT_UInt      num_base_subgs, start_point;
00251         FT_SubGlyph  subglyph;
00252 
00253 
00254         start_point = gloader->base.outline.n_points;
00255 
00256         /* first of all, copy the subglyph descriptors in the glyph loader */
00257         error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
00258         if ( error )
00259           goto Exit;
00260 
00261         FT_ARRAY_COPY( gloader->current.subglyphs,
00262                        slot->subglyphs,
00263                        num_subglyphs );
00264 
00265         gloader->current.num_subglyphs = num_subglyphs;
00266         num_base_subgs                 = gloader->base.num_subglyphs;
00267 
00268         /* now, read each subglyph independently */
00269         for ( nn = 0; nn < num_subglyphs; nn++ )
00270         {
00271           FT_Vector  pp1, pp2;
00272           FT_Pos     x, y;
00273           FT_UInt    num_points, num_new_points, num_base_points;
00274 
00275 
00276           /* gloader.current.subglyphs can change during glyph loading due */
00277           /* to re-allocation -- we must recompute the current subglyph on */
00278           /* each iteration                                                */
00279           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
00280 
00281           pp1 = loader->pp1;
00282           pp2 = loader->pp2;
00283 
00284           num_base_points = gloader->base.outline.n_points;
00285 
00286           error = af_loader_load_g( loader, scaler, subglyph->index,
00287                                     load_flags, depth + 1 );
00288           if ( error )
00289             goto Exit;
00290 
00291           /* recompute subglyph pointer */
00292           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
00293 
00294           if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
00295           {
00296             pp1 = loader->pp1;
00297             pp2 = loader->pp2;
00298           }
00299           else
00300           {
00301             loader->pp1 = pp1;
00302             loader->pp2 = pp2;
00303           }
00304 
00305           num_points     = gloader->base.outline.n_points;
00306           num_new_points = num_points - num_base_points;
00307 
00308           /* now perform the transform required for this subglyph */
00309 
00310           if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
00311                                    FT_SUBGLYPH_FLAG_XY_SCALE |
00312                                    FT_SUBGLYPH_FLAG_2X2      ) )
00313           {
00314             FT_Vector*  cur   = gloader->base.outline.points +
00315                                 num_base_points;
00316             FT_Vector*  limit = cur + num_new_points;
00317 
00318 
00319             for ( ; cur < limit; cur++ )
00320               FT_Vector_Transform( cur, &subglyph->transform );
00321           }
00322 
00323           /* apply offset */
00324 
00325           if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
00326           {
00327             FT_Int      k = subglyph->arg1;
00328             FT_UInt     l = subglyph->arg2;
00329             FT_Vector*  p1;
00330             FT_Vector*  p2;
00331 
00332 
00333             if ( start_point + k >= num_base_points         ||
00334                                l >= (FT_UInt)num_new_points )
00335             {
00336               error = AF_Err_Invalid_Composite;
00337               goto Exit;
00338             }
00339 
00340             l += num_base_points;
00341 
00342             /* for now, only use the current point coordinates;    */
00343             /* we may consider another approach in the near future */
00344             p1 = gloader->base.outline.points + start_point + k;
00345             p2 = gloader->base.outline.points + start_point + l;
00346 
00347             x = p1->x - p2->x;
00348             y = p1->y - p2->y;
00349           }
00350           else
00351           {
00352             x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
00353             y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
00354 
00355             x = FT_PIX_ROUND( x );
00356             y = FT_PIX_ROUND( y );
00357           }
00358 
00359           {
00360             FT_Outline  dummy = gloader->base.outline;
00361 
00362 
00363             dummy.points  += num_base_points;
00364             dummy.n_points = (short)num_new_points;
00365 
00366             FT_Outline_Translate( &dummy, x, y );
00367           }
00368         }
00369       }
00370       break;
00371 
00372     default:
00373       /* we don't support other formats (yet?) */
00374       error = AF_Err_Unimplemented_Feature;
00375     }
00376 
00377   Hint_Metrics:
00378     if ( depth == 0 )
00379     {
00380       FT_BBox    bbox;
00381       FT_Vector  vvector;
00382 
00383 
00384       vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
00385       vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
00386       vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
00387       vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );
00388 
00389       /* transform the hinted outline if needed */
00390       if ( loader->transformed )
00391       {
00392         FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
00393         FT_Vector_Transform( &vvector, &loader->trans_matrix );
00394       }
00395 #if 1
00396       /* we must translate our final outline by -pp1.x and compute */
00397       /* the new metrics                                           */
00398       if ( loader->pp1.x )
00399         FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
00400 #endif
00401       FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
00402 
00403       bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
00404       bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
00405       bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
00406       bbox.yMax = FT_PIX_CEIL(  bbox.yMax );
00407 
00408       slot->metrics.width        = bbox.xMax - bbox.xMin;
00409       slot->metrics.height       = bbox.yMax - bbox.yMin;
00410       slot->metrics.horiBearingX = bbox.xMin;
00411       slot->metrics.horiBearingY = bbox.yMax;
00412 
00413       slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
00414       slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
00415 
00416       /* for mono-width fonts (like Andale, Courier, etc.) we need */
00417       /* to keep the original rounded advance width; ditto for     */
00418       /* digits if all have the same advance width                 */
00419 #if 0
00420       if ( !FT_IS_FIXED_WIDTH( slot->face ) )
00421         slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
00422       else
00423         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
00424                                                x_scale );
00425 #else
00426       if ( FT_IS_FIXED_WIDTH( slot->face )                              ||
00427            ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
00428              metrics->digits_have_same_width                          ) )
00429       {
00430         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
00431                                                metrics->scaler.x_scale );
00432 
00433         /* Set delta values to 0.  Otherwise code that uses them is */
00434         /* going to ruin the fixed advance width.                   */
00435         slot->lsb_delta = 0;
00436         slot->rsb_delta = 0;
00437       }
00438       else
00439       {
00440         /* non-spacing glyphs must stay as-is */
00441         if ( slot->metrics.horiAdvance )
00442           slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
00443       }
00444 #endif
00445 
00446       slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
00447                                               metrics->scaler.y_scale );
00448 
00449       slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
00450       slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
00451 
00452       /* now copy outline into glyph slot */
00453       FT_GlyphLoader_Rewind( internal->loader );
00454       error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
00455       if ( error )
00456         goto Exit;
00457 
00458       slot->outline = internal->loader->base.outline;
00459       slot->format  = FT_GLYPH_FORMAT_OUTLINE;
00460     }
00461 
00462 #ifdef DEBUG_HINTER
00463     af_debug_hinter = hinter;
00464 #endif
00465 
00466   Exit:
00467     return error;
00468   }
00469 
00470 
00471   FT_LOCAL_DEF( FT_Error )
00472   af_loader_load_glyph( AF_Loader  loader,
00473                         FT_Face    face,
00474                         FT_UInt    gindex,
00475                         FT_UInt32  load_flags )
00476   {
00477     FT_Error      error;
00478     FT_Size       size = face->size;
00479     AF_ScalerRec  scaler;
00480 
00481 
00482     if ( !size )
00483       return AF_Err_Invalid_Argument;
00484 
00485     FT_ZERO( &scaler );
00486 
00487     scaler.face    = face;
00488     scaler.x_scale = size->metrics.x_scale;
00489     scaler.x_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
00490     scaler.y_scale = size->metrics.y_scale;
00491     scaler.y_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
00492 
00493     scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
00494     scaler.flags       = 0;  /* XXX: fix this */
00495 
00496     error = af_loader_reset( loader, face );
00497     if ( !error )
00498     {
00499       AF_ScriptMetrics  metrics;
00500       FT_UInt           options = 0;
00501 
00502 
00503 #ifdef FT_OPTION_AUTOFIT2
00504       /* XXX: undocumented hook to activate the latin2 hinter */
00505       if ( load_flags & ( 1UL << 20 ) )
00506         options = 2;
00507 #endif
00508 
00509       error = af_face_globals_get_metrics( loader->globals, gindex,
00510                                            options, &metrics );
00511       if ( !error )
00512       {
00513         loader->metrics = metrics;
00514 
00515         if ( metrics->clazz->script_metrics_scale )
00516           metrics->clazz->script_metrics_scale( metrics, &scaler );
00517         else
00518           metrics->scaler = scaler;
00519 
00520         load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
00521         load_flags &= ~FT_LOAD_RENDER;
00522 
00523         if ( metrics->clazz->script_hints_init )
00524         {
00525           error = metrics->clazz->script_hints_init( &loader->hints,
00526                                                      metrics );
00527           if ( error )
00528             goto Exit;
00529         }
00530 
00531         error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 );
00532       }
00533     }
00534   Exit:
00535     return error;
00536   }
00537 
00538 
00539 /* END */

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