Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  afloader.c                                                             */
  4. /*                                                                         */
  5. /*    Auto-fitter glyph loading routines (body).                           */
  6. /*                                                                         */
  7. /*  Copyright 2003-2009, 2011-2013 by                                      */
  8. /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
  9. /*                                                                         */
  10. /*  This file is part of the FreeType project, and may only be used,       */
  11. /*  modified, and distributed under the terms of the FreeType project      */
  12. /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13. /*  this file you indicate that you have read the license and              */
  14. /*  understand and accept it fully.                                        */
  15. /*                                                                         */
  16. /***************************************************************************/
  17.  
  18.  
  19. #include "afglobal.h"
  20. #include "afloader.h"
  21. #include "afhints.h"
  22. #include "aferrors.h"
  23. #include "afmodule.h"
  24.  
  25.  
  26.   /* Initialize glyph loader. */
  27.  
  28.   FT_LOCAL_DEF( FT_Error )
  29.   af_loader_init( AF_Module  module )
  30.   {
  31.     AF_Loader  loader = module->loader;
  32.     FT_Memory  memory = module->root.library->memory;
  33.  
  34.  
  35.     FT_ZERO( loader );
  36.  
  37.     af_glyph_hints_init( &loader->hints, memory );
  38. #ifdef FT_DEBUG_AUTOFIT
  39.     _af_debug_hints = &loader->hints;
  40. #endif
  41.     return FT_GlyphLoader_New( memory, &loader->gloader );
  42.   }
  43.  
  44.  
  45.   /* Reset glyph loader and compute globals if necessary. */
  46.  
  47.   FT_LOCAL_DEF( FT_Error )
  48.   af_loader_reset( AF_Module  module,
  49.                    FT_Face    face )
  50.   {
  51.     FT_Error   error  = FT_Err_Ok;
  52.     AF_Loader  loader = module->loader;
  53.  
  54.  
  55.     loader->face    = face;
  56.     loader->globals = (AF_FaceGlobals)face->autohint.data;
  57.  
  58.     FT_GlyphLoader_Rewind( loader->gloader );
  59.  
  60.     if ( loader->globals == NULL )
  61.     {
  62.       error = af_face_globals_new( face, &loader->globals, module );
  63.       if ( !error )
  64.       {
  65.         face->autohint.data =
  66.           (FT_Pointer)loader->globals;
  67.         face->autohint.finalizer =
  68.           (FT_Generic_Finalizer)af_face_globals_free;
  69.       }
  70.     }
  71.  
  72.     return error;
  73.   }
  74.  
  75.  
  76.   /* Finalize glyph loader. */
  77.  
  78.   FT_LOCAL_DEF( void )
  79.   af_loader_done( AF_Module  module )
  80.   {
  81.     AF_Loader  loader = module->loader;
  82.  
  83.  
  84.     af_glyph_hints_done( &loader->hints );
  85.  
  86.     loader->face    = NULL;
  87.     loader->globals = NULL;
  88.  
  89. #ifdef FT_DEBUG_AUTOFIT
  90.     _af_debug_hints = NULL;
  91. #endif
  92.     FT_GlyphLoader_Done( loader->gloader );
  93.     loader->gloader = NULL;
  94.   }
  95.  
  96.  
  97.   /* Load a single glyph component.  This routine calls itself */
  98.   /* recursively, if necessary, and does the main work of      */
  99.   /* `af_loader_load_glyph.'                                   */
  100.  
  101.   static FT_Error
  102.   af_loader_load_g( AF_Loader  loader,
  103.                     AF_Scaler  scaler,
  104.                     FT_UInt    glyph_index,
  105.                     FT_Int32   load_flags,
  106.                     FT_UInt    depth )
  107.   {
  108.     FT_Error          error;
  109.     FT_Face           face     = loader->face;
  110.     FT_GlyphLoader    gloader  = loader->gloader;
  111.     AF_ScriptMetrics  metrics  = loader->metrics;
  112.     AF_GlyphHints     hints    = &loader->hints;
  113.     FT_GlyphSlot      slot     = face->glyph;
  114.     FT_Slot_Internal  internal = slot->internal;
  115.     FT_Int32          flags;
  116.  
  117.  
  118.     flags = load_flags | FT_LOAD_LINEAR_DESIGN;
  119.     error = FT_Load_Glyph( face, glyph_index, flags );
  120.     if ( error )
  121.       goto Exit;
  122.  
  123.     loader->transformed = internal->glyph_transformed;
  124.     if ( loader->transformed )
  125.     {
  126.       FT_Matrix  inverse;
  127.  
  128.  
  129.       loader->trans_matrix = internal->glyph_matrix;
  130.       loader->trans_delta  = internal->glyph_delta;
  131.  
  132.       inverse = loader->trans_matrix;
  133.       FT_Matrix_Invert( &inverse );
  134.       FT_Vector_Transform( &loader->trans_delta, &inverse );
  135.     }
  136.  
  137.     switch ( slot->format )
  138.     {
  139.     case FT_GLYPH_FORMAT_OUTLINE:
  140.       /* translate the loaded glyph when an internal transform is needed */
  141.       if ( loader->transformed )
  142.         FT_Outline_Translate( &slot->outline,
  143.                               loader->trans_delta.x,
  144.                               loader->trans_delta.y );
  145.  
  146.       /* copy the outline points in the loader's current                */
  147.       /* extra points which are used to keep original glyph coordinates */
  148.       error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
  149.                                            slot->outline.n_points + 4,
  150.                                            slot->outline.n_contours );
  151.       if ( error )
  152.         goto Exit;
  153.  
  154.       FT_ARRAY_COPY( gloader->current.outline.points,
  155.                      slot->outline.points,
  156.                      slot->outline.n_points );
  157.  
  158.       FT_ARRAY_COPY( gloader->current.outline.contours,
  159.                      slot->outline.contours,
  160.                      slot->outline.n_contours );
  161.  
  162.       FT_ARRAY_COPY( gloader->current.outline.tags,
  163.                      slot->outline.tags,
  164.                      slot->outline.n_points );
  165.  
  166.       gloader->current.outline.n_points   = slot->outline.n_points;
  167.       gloader->current.outline.n_contours = slot->outline.n_contours;
  168.  
  169.       /* compute original horizontal phantom points (and ignore */
  170.       /* vertical ones)                                         */
  171.       loader->pp1.x = hints->x_delta;
  172.       loader->pp1.y = hints->y_delta;
  173.       loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
  174.                                  hints->x_scale ) + hints->x_delta;
  175.       loader->pp2.y = hints->y_delta;
  176.  
  177.       /* be sure to check for spacing glyphs */
  178.       if ( slot->outline.n_points == 0 )
  179.         goto Hint_Metrics;
  180.  
  181.       /* now load the slot image into the auto-outline and run the */
  182.       /* automatic hinting process                                 */
  183.       if ( metrics->clazz->script_hints_apply )
  184.         metrics->clazz->script_hints_apply( hints,
  185.                                             &gloader->current.outline,
  186.                                             metrics );
  187.  
  188.       /* we now need to adjust the metrics according to the change in */
  189.       /* width/positioning that occurred during the hinting process   */
  190.       if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
  191.       {
  192.         FT_Pos        old_rsb, old_lsb, new_lsb;
  193.         FT_Pos        pp1x_uh, pp2x_uh;
  194.         AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
  195.         AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
  196.         AF_Edge       edge2 = edge1 +
  197.                               axis->num_edges - 1; /* rightmost edge */
  198.  
  199.  
  200.         if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
  201.         {
  202.           old_rsb = loader->pp2.x - edge2->opos;
  203.           old_lsb = edge1->opos;
  204.           new_lsb = edge1->pos;
  205.  
  206.           /* remember unhinted values to later account */
  207.           /* for rounding errors                       */
  208.  
  209.           pp1x_uh = new_lsb    - old_lsb;
  210.           pp2x_uh = edge2->pos + old_rsb;
  211.  
  212.           /* prefer too much space over too little space */
  213.           /* for very small sizes                        */
  214.  
  215.           if ( old_lsb < 24 )
  216.             pp1x_uh -= 8;
  217.  
  218.           if ( old_rsb < 24 )
  219.             pp2x_uh += 8;
  220.  
  221.           loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
  222.           loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
  223.  
  224.           if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
  225.             loader->pp1.x -= 64;
  226.  
  227.           if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
  228.             loader->pp2.x += 64;
  229.  
  230.           slot->lsb_delta = loader->pp1.x - pp1x_uh;
  231.           slot->rsb_delta = loader->pp2.x - pp2x_uh;
  232.         }
  233.         else
  234.         {
  235.           FT_Pos  pp1x = loader->pp1.x;
  236.           FT_Pos  pp2x = loader->pp2.x;
  237.  
  238.  
  239.           loader->pp1.x = FT_PIX_ROUND( pp1x );
  240.           loader->pp2.x = FT_PIX_ROUND( pp2x );
  241.  
  242.           slot->lsb_delta = loader->pp1.x - pp1x;
  243.           slot->rsb_delta = loader->pp2.x - pp2x;
  244.         }
  245.       }
  246.       else
  247.       {
  248.         FT_Pos  pp1x = loader->pp1.x;
  249.         FT_Pos  pp2x = loader->pp2.x;
  250.  
  251.  
  252.         loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
  253.         loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
  254.  
  255.         slot->lsb_delta = loader->pp1.x - pp1x;
  256.         slot->rsb_delta = loader->pp2.x - pp2x;
  257.       }
  258.  
  259.       /* good, we simply add the glyph to our loader's base */
  260.       FT_GlyphLoader_Add( gloader );
  261.       break;
  262.  
  263.     case FT_GLYPH_FORMAT_COMPOSITE:
  264.       {
  265.         FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
  266.         FT_UInt      num_base_subgs, start_point;
  267.         FT_SubGlyph  subglyph;
  268.  
  269.  
  270.         start_point = gloader->base.outline.n_points;
  271.  
  272.         /* first of all, copy the subglyph descriptors in the glyph loader */
  273.         error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
  274.         if ( error )
  275.           goto Exit;
  276.  
  277.         FT_ARRAY_COPY( gloader->current.subglyphs,
  278.                        slot->subglyphs,
  279.                        num_subglyphs );
  280.  
  281.         gloader->current.num_subglyphs = num_subglyphs;
  282.         num_base_subgs                 = gloader->base.num_subglyphs;
  283.  
  284.         /* now read each subglyph independently */
  285.         for ( nn = 0; nn < num_subglyphs; nn++ )
  286.         {
  287.           FT_Vector  pp1, pp2;
  288.           FT_Pos     x, y;
  289.           FT_UInt    num_points, num_new_points, num_base_points;
  290.  
  291.  
  292.           /* gloader.current.subglyphs can change during glyph loading due */
  293.           /* to re-allocation -- we must recompute the current subglyph on */
  294.           /* each iteration                                                */
  295.           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  296.  
  297.           pp1 = loader->pp1;
  298.           pp2 = loader->pp2;
  299.  
  300.           num_base_points = gloader->base.outline.n_points;
  301.  
  302.           error = af_loader_load_g( loader, scaler, subglyph->index,
  303.                                     load_flags, depth + 1 );
  304.           if ( error )
  305.             goto Exit;
  306.  
  307.           /* recompute subglyph pointer */
  308.           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  309.  
  310.           if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
  311.           {
  312.             pp1 = loader->pp1;
  313.             pp2 = loader->pp2;
  314.           }
  315.           else
  316.           {
  317.             loader->pp1 = pp1;
  318.             loader->pp2 = pp2;
  319.           }
  320.  
  321.           num_points     = gloader->base.outline.n_points;
  322.           num_new_points = num_points - num_base_points;
  323.  
  324.           /* now perform the transformation required for this subglyph */
  325.  
  326.           if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
  327.                                    FT_SUBGLYPH_FLAG_XY_SCALE |
  328.                                    FT_SUBGLYPH_FLAG_2X2      ) )
  329.           {
  330.             FT_Vector*  cur   = gloader->base.outline.points +
  331.                                 num_base_points;
  332.             FT_Vector*  limit = cur + num_new_points;
  333.  
  334.  
  335.             for ( ; cur < limit; cur++ )
  336.               FT_Vector_Transform( cur, &subglyph->transform );
  337.           }
  338.  
  339.           /* apply offset */
  340.  
  341.           if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
  342.           {
  343.             FT_Int      k = subglyph->arg1;
  344.             FT_UInt     l = subglyph->arg2;
  345.             FT_Vector*  p1;
  346.             FT_Vector*  p2;
  347.  
  348.  
  349.             if ( start_point + k >= num_base_points         ||
  350.                                l >= (FT_UInt)num_new_points )
  351.             {
  352.               error = FT_THROW( Invalid_Composite );
  353.               goto Exit;
  354.             }
  355.  
  356.             l += num_base_points;
  357.  
  358.             /* for now, only use the current point coordinates; */
  359.             /* we eventually may consider another approach      */
  360.             p1 = gloader->base.outline.points + start_point + k;
  361.             p2 = gloader->base.outline.points + start_point + l;
  362.  
  363.             x = p1->x - p2->x;
  364.             y = p1->y - p2->y;
  365.           }
  366.           else
  367.           {
  368.             x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
  369.             y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
  370.  
  371.             x = FT_PIX_ROUND( x );
  372.             y = FT_PIX_ROUND( y );
  373.           }
  374.  
  375.           {
  376.             FT_Outline  dummy = gloader->base.outline;
  377.  
  378.  
  379.             dummy.points  += num_base_points;
  380.             dummy.n_points = (short)num_new_points;
  381.  
  382.             FT_Outline_Translate( &dummy, x, y );
  383.           }
  384.         }
  385.       }
  386.       break;
  387.  
  388.     default:
  389.       /* we don't support other formats (yet?) */
  390.       error = FT_THROW( Unimplemented_Feature );
  391.     }
  392.  
  393.   Hint_Metrics:
  394.     if ( depth == 0 )
  395.     {
  396.       FT_BBox    bbox;
  397.       FT_Vector  vvector;
  398.  
  399.  
  400.       vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
  401.       vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
  402.       vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
  403.       vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );
  404.  
  405.       /* transform the hinted outline if needed */
  406.       if ( loader->transformed )
  407.       {
  408.         FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
  409.         FT_Vector_Transform( &vvector, &loader->trans_matrix );
  410.       }
  411. #if 1
  412.       /* we must translate our final outline by -pp1.x and compute */
  413.       /* the new metrics                                           */
  414.       if ( loader->pp1.x )
  415.         FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
  416. #endif
  417.       FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
  418.  
  419.       bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
  420.       bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
  421.       bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
  422.       bbox.yMax = FT_PIX_CEIL(  bbox.yMax );
  423.  
  424.       slot->metrics.width        = bbox.xMax - bbox.xMin;
  425.       slot->metrics.height       = bbox.yMax - bbox.yMin;
  426.       slot->metrics.horiBearingX = bbox.xMin;
  427.       slot->metrics.horiBearingY = bbox.yMax;
  428.  
  429.       slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
  430.       slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
  431.  
  432.       /* for mono-width fonts (like Andale, Courier, etc.) we need */
  433.       /* to keep the original rounded advance width; ditto for     */
  434.       /* digits if all have the same advance width                 */
  435. #if 0
  436.       if ( !FT_IS_FIXED_WIDTH( slot->face ) )
  437.         slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
  438.       else
  439.         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
  440.                                                x_scale );
  441. #else
  442.       if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
  443.            ( FT_IS_FIXED_WIDTH( slot->face )                              ||
  444.              ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
  445.                metrics->digits_have_same_width                          ) ) )
  446.       {
  447.         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
  448.                                                metrics->scaler.x_scale );
  449.  
  450.         /* Set delta values to 0.  Otherwise code that uses them is */
  451.         /* going to ruin the fixed advance width.                   */
  452.         slot->lsb_delta = 0;
  453.         slot->rsb_delta = 0;
  454.       }
  455.       else
  456.       {
  457.         /* non-spacing glyphs must stay as-is */
  458.         if ( slot->metrics.horiAdvance )
  459.           slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
  460.       }
  461. #endif
  462.  
  463.       slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
  464.                                              metrics->scaler.y_scale );
  465.  
  466.       slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
  467.       slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
  468.  
  469.       /* now copy outline into glyph slot */
  470.       FT_GlyphLoader_Rewind( internal->loader );
  471.       error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
  472.       if ( error )
  473.         goto Exit;
  474.  
  475.       /* reassign all outline fields except flags to protect them */
  476.       slot->outline.n_contours = internal->loader->base.outline.n_contours;
  477.       slot->outline.n_points   = internal->loader->base.outline.n_points;
  478.       slot->outline.points     = internal->loader->base.outline.points;
  479.       slot->outline.tags       = internal->loader->base.outline.tags;
  480.       slot->outline.contours   = internal->loader->base.outline.contours;
  481.  
  482.       slot->format  = FT_GLYPH_FORMAT_OUTLINE;
  483.     }
  484.  
  485.   Exit:
  486.     return error;
  487.   }
  488.  
  489.  
  490.   /* Load a glyph. */
  491.  
  492.   FT_LOCAL_DEF( FT_Error )
  493.   af_loader_load_glyph( AF_Module  module,
  494.                         FT_Face    face,
  495.                         FT_UInt    gindex,
  496.                         FT_Int32   load_flags )
  497.   {
  498.     FT_Error      error;
  499.     FT_Size       size   = face->size;
  500.     AF_Loader     loader = module->loader;
  501.     AF_ScalerRec  scaler;
  502.  
  503.  
  504.     if ( !size )
  505.       return FT_THROW( Invalid_Argument );
  506.  
  507.     FT_ZERO( &scaler );
  508.  
  509.     scaler.face    = face;
  510.     scaler.x_scale = size->metrics.x_scale;
  511.     scaler.x_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
  512.     scaler.y_scale = size->metrics.y_scale;
  513.     scaler.y_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
  514.  
  515.     scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
  516.     scaler.flags       = 0;  /* XXX: fix this */
  517.  
  518.     error = af_loader_reset( module, face );
  519.     if ( !error )
  520.     {
  521.       AF_ScriptMetrics  metrics;
  522.       FT_UInt           options = 0;
  523.  
  524.  
  525. #ifdef FT_OPTION_AUTOFIT2
  526.       /* XXX: undocumented hook to activate the latin2 hinter */
  527.       if ( load_flags & ( 1UL << 20 ) )
  528.         options = 2;
  529. #endif
  530.  
  531.       error = af_face_globals_get_metrics( loader->globals, gindex,
  532.                                            options, &metrics );
  533.       if ( !error )
  534.       {
  535.         loader->metrics = metrics;
  536.  
  537.         if ( metrics->clazz->script_metrics_scale )
  538.           metrics->clazz->script_metrics_scale( metrics, &scaler );
  539.         else
  540.           metrics->scaler = scaler;
  541.  
  542.         load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
  543.         load_flags &= ~FT_LOAD_RENDER;
  544.  
  545.         if ( metrics->clazz->script_hints_init )
  546.         {
  547.           error = metrics->clazz->script_hints_init( &loader->hints,
  548.                                                      metrics );
  549.           if ( error )
  550.             goto Exit;
  551.         }
  552.  
  553.         error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 );
  554.       }
  555.     }
  556.   Exit:
  557.     return error;
  558.   }
  559.  
  560.  
  561. /* END */
  562.