Exemplo n.º 1
0
  FT_Glyph_Get_CBox( FT_Glyph  glyph,
                     FT_UInt   bbox_mode,
                     FT_BBox  *acbox )
  {
    const FT_Glyph_Class*  clazz;


    if ( !acbox )
      return;

    acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;

    if ( !glyph || !glyph->clazz )
      return;
    else
    {
      clazz = glyph->clazz;
      if ( !clazz->glyph_bbox )
        return;
      else
      {
        /* retrieve bbox in 26.6 coordinates */
        clazz->glyph_bbox( glyph, acbox );

        /* perform grid fitting if needed */
        if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
             bbox_mode == FT_GLYPH_BBOX_PIXELS  )
        {
          acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
          acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
          acbox->xMax = FT_PIX_CEIL( acbox->xMax );
          acbox->yMax = FT_PIX_CEIL( acbox->yMax );
        }

        /* convert to integer pixels if needed */
        if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
             bbox_mode == FT_GLYPH_BBOX_PIXELS   )
        {
          acbox->xMin >>= 6;
          acbox->yMin >>= 6;
          acbox->xMax >>= 6;
          acbox->yMax >>= 6;
        }
      }
    }
Exemplo n.º 2
0
/* convert a slot's glyph image into a bitmap */
static FT_Error
ft_raster1_render( FT_Renderer       render,
                   FT_GlyphSlot      slot,
                   FT_Render_Mode    mode,
                   const FT_Vector*  origin )
{
    FT_Error     error;
    FT_Outline*  outline;
    FT_BBox      cbox, cbox0;
    FT_UInt      width, height, pitch;
    FT_Bitmap*   bitmap;
    FT_Memory    memory;

    FT_Raster_Params  params;


    /* check glyph image format */
    if ( slot->format != render->glyph_format )
    {
        error = Raster_Err_Invalid_Argument;
        goto Exit;
    }

    /* check rendering mode */
#ifndef FT_CONFIG_OPTION_PIC
    if ( mode != FT_RENDER_MODE_MONO )
    {
        /* raster1 is only capable of producing monochrome bitmaps */
        if ( render->clazz == &ft_raster1_renderer_class )
            return Raster_Err_Cannot_Render_Glyph;
    }
    else
    {
        /* raster5 is only capable of producing 5-gray-levels bitmaps */
        if ( render->clazz == &ft_raster5_renderer_class )
            return Raster_Err_Cannot_Render_Glyph;
    }
#else /* FT_CONFIG_OPTION_PIC */
    /* When PIC is enabled, we cannot get to the class object      */
    /* so instead we check the final character in the class name   */
    /* ("raster5" or "raster1"). Yes this is a hack.               */
    /* The "correct" thing to do is have different render function */
    /* for each of the classes.                                    */
    if ( mode != FT_RENDER_MODE_MONO )
    {
        /* raster1 is only capable of producing monochrome bitmaps */
        if ( render->clazz->root.module_name[6] == '1' )
            return Raster_Err_Cannot_Render_Glyph;
    }
    else
    {
        /* raster5 is only capable of producing 5-gray-levels bitmaps */
        if ( render->clazz->root.module_name[6] == '5' )
            return Raster_Err_Cannot_Render_Glyph;
    }
#endif /* FT_CONFIG_OPTION_PIC */

    outline = &slot->outline;

    /* translate the outline to the new origin if needed */
    if ( origin )
        FT_Outline_Translate( outline, origin->x, origin->y );

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox( outline, &cbox0 );

    /* undocumented but confirmed: bbox values get rounded */
#if 1
    cbox.xMin = FT_PIX_ROUND( cbox0.xMin );
    cbox.yMin = FT_PIX_ROUND( cbox0.yMin );
    cbox.xMax = FT_PIX_ROUND( cbox0.xMax );
    cbox.yMax = FT_PIX_ROUND( cbox0.yMax );
#else
    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
    cbox.yMax = FT_PIX_CEIL( cbox.yMax );
#endif

    /* in the event either width or height round to 0, */
    /* try explicitly rounding up/down. In the case of */
    /* glyphs containing only one very narrow feature, */
    /* this give the drop-out compensation in the      */
    /* in the scan conversion code to do its stuff.    */
    width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    if ( width == 0 )
    {
        cbox.xMin = FT_PIX_FLOOR( cbox0.xMin );
        cbox.xMax = FT_PIX_CEIL( cbox0.xMax );

        width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    }
Exemplo n.º 3
0
  static FT_Pos
  af_hint_normal_stem( AF_GlyphHints  hints,
                       AF_Edge        edge,
                       AF_Edge        edge2,
                       FT_Pos         anchor,
                       AF_Dimension   dim )
  {
    FT_Pos  org_len, cur_len, org_center;
    FT_Pos  cur_pos1, cur_pos2;
    FT_Pos  d_off1, u_off1, d_off2, u_off2, delta;
    FT_Pos  offset;
    FT_Pos  threshold = 64;


    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
    {
      if ( ( edge->flags  & AF_EDGE_ROUND ) &&
           ( edge2->flags & AF_EDGE_ROUND ) )
      {
        if ( dim == AF_DIMENSION_VERT )
          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
        else
          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
      }
      else
      {
        if ( dim == AF_DIMENSION_VERT )
          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
        else
          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
      }
    }

    org_len    = edge2->opos - edge->opos;
    cur_len    = af_cjk_compute_stem_width( hints, dim, org_len,
                                            (AF_Edge_Flags)edge->flags,
                                            (AF_Edge_Flags)edge2->flags );

    org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
    cur_pos1   = org_center - cur_len / 2;
    cur_pos2   = cur_pos1 + cur_len;
    d_off1     = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
    d_off2     = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
    u_off1     = 64 - d_off1;
    u_off2     = 64 - d_off2;
    delta      = 0;


    if ( d_off1 == 0 || d_off2 == 0 )
      goto Exit;

    if ( cur_len <= threshold )
    {
      if ( d_off2 < cur_len )
      {
        if ( u_off1 <= d_off2 )
          delta =  u_off1;
        else
          delta = -d_off2;
      }

      goto Exit;
    }

    if ( threshold < 64 )
    {
      if ( d_off1 >= threshold || u_off1 >= threshold ||
           d_off2 >= threshold || u_off2 >= threshold )
        goto Exit;
    }

    offset = cur_len % 64;

    if ( offset < 32 )
    {
      if ( u_off1 <= offset || d_off2 <= offset )
        goto Exit;
    }
    else
      offset = 64 - threshold;

    d_off1 = threshold - u_off1;
    u_off1 = u_off1    - offset;
    u_off2 = threshold - d_off2;
    d_off2 = d_off2    - offset;

    if ( d_off1 <= u_off1 )
      u_off1 = -d_off1;

    if ( d_off2 <= u_off2 )
      u_off2 = -d_off2;

    if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
      delta = u_off1;
    else
      delta = u_off2;

  Exit:

#if 1
    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
    {
      if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
        delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
      else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
        delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
    }
#endif

    cur_pos1 += delta;

    if ( edge->opos < edge2->opos )
    {
      edge->pos  = cur_pos1;
      edge2->pos = cur_pos1 + cur_len;
    }
    else
    {
      edge->pos  = cur_pos1 + cur_len;
      edge2->pos = cur_pos1;
    }

    return delta;
  }
Exemplo n.º 4
0
  af_loader_load_glyph( AF_Loader  loader,
                        AF_Module  module,
                        FT_Face    face,
                        FT_UInt    glyph_index,
                        FT_Int32   load_flags )
  {
    FT_Error  error;

    FT_Size           size          = face->size;
    FT_Size_Internal  size_internal = size->internal;
    FT_GlyphSlot      slot          = face->glyph;
    FT_Slot_Internal  slot_internal = slot->internal;
    FT_GlyphLoader    gloader       = slot_internal->loader;

    AF_GlyphHints          hints         = loader->hints;
    AF_ScalerRec           scaler;
    AF_StyleMetrics        style_metrics;
    FT_UInt                style_options = AF_STYLE_NONE_DFLT;
    AF_StyleClass          style_class;
    AF_WritingSystemClass  writing_system_class;


    if ( !size )
      return FT_THROW( Invalid_Size_Handle );

    FT_ZERO( &scaler );

    if ( !size_internal->autohint_metrics.x_scale                          ||
         size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) )
    {
      /* switching between hinting modes usually means different scaling */
      /* values; this later on enforces recomputation of everything      */
      /* related to the current size                                     */

      size_internal->autohint_mode    = FT_LOAD_TARGET_MODE( load_flags );
      size_internal->autohint_metrics = size->metrics;

#ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS
      {
        FT_Size_Metrics*  size_metrics = &size_internal->autohint_metrics;


        /* set metrics to integer values and adjust scaling accordingly; */
        /* this is the same setup as with TrueType fonts, cf. function   */
        /* `tt_size_reset' in file `ttobjs.c'                            */
        size_metrics->ascender  = FT_PIX_ROUND(
                                    FT_MulFix( face->ascender,
                                               size_metrics->y_scale ) );
        size_metrics->descender = FT_PIX_ROUND(
                                    FT_MulFix( face->descender,
                                               size_metrics->y_scale ) );
        size_metrics->height    = FT_PIX_ROUND(
                                    FT_MulFix( face->height,
                                               size_metrics->y_scale ) );

        size_metrics->x_scale     = FT_DivFix( size_metrics->x_ppem << 6,
                                               face->units_per_EM );
        size_metrics->y_scale     = FT_DivFix( size_metrics->y_ppem << 6,
                                               face->units_per_EM );
        size_metrics->max_advance = FT_PIX_ROUND(
                                      FT_MulFix( face->max_advance_width,
                                                 size_metrics->x_scale ) );
      }
#endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */
    }

    /*
     * TODO: This code currently doesn't support fractional advance widths,
     * i.e., placing hinted glyphs at anything other than integer
     * x-positions.  This is only relevant for the warper code, which
     * scales and shifts glyphs to optimize blackness of stems (hinting on
     * the x-axis by nature places things on pixel integers, hinting on the
     * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis).  The delta
     * values of the scaler would need to be adjusted.
     */
    scaler.face    = face;
    scaler.x_scale = size_internal->autohint_metrics.x_scale;
    scaler.x_delta = 0;
    scaler.y_scale = size_internal->autohint_metrics.y_scale;
    scaler.y_delta = 0;

    scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
    scaler.flags       = 0;

    /* note that the fallback style can't be changed anymore */
    /* after the first call of `af_loader_load_glyph'        */
    error = af_loader_reset( loader, module, face );
    if ( error )
      goto Exit;

#ifdef FT_OPTION_AUTOFIT2
    /* XXX: undocumented hook to activate the latin2 writing system. */
    if ( load_flags & ( 1UL << 20 ) )
      style_options = AF_STYLE_LTN2_DFLT;
#endif

    /*
     * Glyphs (really code points) are assigned to scripts.  Script
     * analysis is done lazily: For each glyph that passes through here,
     * the corresponding script analyzer is called, but returns immediately
     * if it has been run already.
     */
    error = af_face_globals_get_metrics( loader->globals, glyph_index,
                                         style_options, &style_metrics );
    if ( error )
      goto Exit;

    style_class          = style_metrics->style_class;
    writing_system_class =
      af_writing_system_classes[style_class->writing_system];

    loader->metrics = style_metrics;

    if ( writing_system_class->style_metrics_scale )
      writing_system_class->style_metrics_scale( style_metrics, &scaler );
    else
      style_metrics->scaler = scaler;

    if ( writing_system_class->style_hints_init )
    {
      error = writing_system_class->style_hints_init( hints,
                                                      style_metrics );
      if ( error )
        goto Exit;
    }

    /*
     * Do the main work of `af_loader_load_glyph'.  Note that we never have
     * to deal with composite glyphs as those get loaded into
     * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function.
     * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies
     * FT_LOAD_NO_SCALE and as such the auto-hinter is never called.
     */
    load_flags |=  FT_LOAD_NO_SCALE         |
                   FT_LOAD_IGNORE_TRANSFORM |
                   FT_LOAD_LINEAR_DESIGN;
    load_flags &= ~FT_LOAD_RENDER;

    error = FT_Load_Glyph( face, glyph_index, load_flags );
    if ( error )
      goto Exit;

    /*
     * Apply stem darkening (emboldening) here before hints are applied to
     * the outline.  Glyphs are scaled down proportionally to the
     * emboldening so that curve points don't fall outside their
     * precomputed blue zones.
     *
     * Any emboldening done by the font driver (e.g., the CFF driver)
     * doesn't reach here because the autohinter loads the unprocessed
     * glyphs in font units for analysis (functions `af_*_metrics_init_*')
     * and then above to prepare it for the rasterizers by itself,
     * independently of the font driver.  So emboldening must be done here,
     * within the autohinter.
     *
     * All glyphs to be autohinted pass through here one by one.  The
     * standard widths can therefore change from one glyph to the next,
     * depending on what script a glyph is assigned to (each script has its
     * own set of standard widths and other metrics).  The darkening amount
     * must therefore be recomputed for each size and
     * `standard_{vertical,horizontal}_width' change.
     *
     * Ignore errors and carry on without emboldening.
     *
     */

    /* stem darkening only works well in `light' mode */
    if ( scaler.render_mode == FT_RENDER_MODE_LIGHT    &&
         ( !face->internal->no_stem_darkening        ||
           ( face->internal->no_stem_darkening < 0 &&
             !module->no_stem_darkening            ) ) )
      af_loader_embolden_glyph_in_slot( loader, face, style_metrics );

    loader->transformed = slot_internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;


      loader->trans_matrix = slot_internal->glyph_matrix;
      loader->trans_delta  = slot_internal->glyph_delta;

      inverse = loader->trans_matrix;
      if ( !FT_Matrix_Invert( &inverse ) )
        FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    switch ( slot->format )
    {
    case FT_GLYPH_FORMAT_OUTLINE:
      /* translate the loaded glyph when an internal transform is needed */
      if ( loader->transformed )
        FT_Outline_Translate( &slot->outline,
                              loader->trans_delta.x,
                              loader->trans_delta.y );

      /* compute original horizontal phantom points */
      /* (and ignore vertical ones)                 */
      loader->pp1.x = hints->x_delta;
      loader->pp1.y = hints->y_delta;
      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                 hints->x_scale ) + hints->x_delta;
      loader->pp2.y = hints->y_delta;

      /* be sure to check for spacing glyphs */
      if ( slot->outline.n_points == 0 )
        goto Hint_Metrics;

      /* now load the slot image into the auto-outline */
      /* and run the automatic hinting process         */
      if ( writing_system_class->style_hints_apply )
      {
        error = writing_system_class->style_hints_apply(
                  glyph_index,
                  hints,
                  &gloader->base.outline,
                  style_metrics );
        if ( error )
          goto Exit;
      }

      /* we now need to adjust the metrics according to the change in */
      /* width/positioning that occurred during the hinting process   */
      if ( scaler.render_mode != FT_RENDER_MODE_LIGHT )
      {
        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];


        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
        {
          AF_Edge  edge1 = axis->edges;         /* leftmost edge  */
          AF_Edge  edge2 = edge1 +
                           axis->num_edges - 1; /* rightmost edge */

          FT_Pos  old_rsb = loader->pp2.x - edge2->opos;
          /* loader->pp1.x is always zero at this point of time */
          FT_Pos  old_lsb = edge1->opos;     /* - loader->pp1.x */
          FT_Pos  new_lsb = edge1->pos;

          /* remember unhinted values to later account */
          /* for rounding errors                       */
          FT_Pos  pp1x_uh = new_lsb    - old_lsb;
          FT_Pos  pp2x_uh = edge2->pos + old_rsb;


          /* prefer too much space over too little space */
          /* for very small sizes                        */

          if ( old_lsb < 24 )
            pp1x_uh -= 8;

          if ( old_rsb < 24 )
            pp2x_uh += 8;

          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
            loader->pp1.x -= 64;

          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
            loader->pp2.x += 64;

          slot->lsb_delta = loader->pp1.x - pp1x_uh;
          slot->rsb_delta = loader->pp2.x - pp2x_uh;
        }
        else
        {
          FT_Pos  pp1x = loader->pp1.x;
          FT_Pos  pp2x = loader->pp2.x;


          loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
          loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );

          slot->lsb_delta = loader->pp1.x - pp1x;
          slot->rsb_delta = loader->pp2.x - pp2x;
        }
      }
      /* `light' mode uses integer advance widths */
      /* but sets `lsb_delta' and `rsb_delta'     */
      else
      {
        FT_Pos  pp1x = loader->pp1.x;
        FT_Pos  pp2x = loader->pp2.x;


        loader->pp1.x = FT_PIX_ROUND( pp1x );
        loader->pp2.x = FT_PIX_ROUND( pp2x );

        slot->lsb_delta = loader->pp1.x - pp1x;
        slot->rsb_delta = loader->pp2.x - pp2x;
      }

      break;

    default:
      /* we don't support other formats (yet?) */
      error = FT_THROW( Unimplemented_Feature );
    }

  Hint_Metrics:
    {
      FT_BBox    bbox;
      FT_Vector  vvector;


      vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
      vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
      vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale );
      vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale );

      /* transform the hinted outline if needed */
      if ( loader->transformed )
      {
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
        FT_Vector_Transform( &vvector, &loader->trans_matrix );
      }

      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );

      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width; ditto for     */
      /* digits if all have the same advance width                 */
      if ( scaler.render_mode != FT_RENDER_MODE_LIGHT                       &&
           ( FT_IS_FIXED_WIDTH( slot->face )                              ||
             ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
               style_metrics->digits_have_same_width                    ) ) )
      {
        slot->metrics.horiAdvance =
          FT_MulFix( slot->metrics.horiAdvance,
                     style_metrics->scaler.x_scale );

        /* Set delta values to 0.  Otherwise code that uses them is */
        /* going to ruin the fixed advance width.                   */
        slot->lsb_delta = 0;
        slot->rsb_delta = 0;
      }
      else
      {
        /* non-spacing glyphs must stay as-is */
        if ( slot->metrics.horiAdvance )
          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      }

      slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
                                             style_metrics->scaler.y_scale );

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
      slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );

      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

  Exit:
    return error;
  }
Exemplo n.º 5
0
  static FT_Error
  af_loader_load_g( AF_Loader  loader,
                    AF_Scaler  scaler,
                    FT_UInt    glyph_index,
                    FT_Int32   load_flags,
                    FT_UInt    depth )
  {
    FT_Error          error;
    FT_Face           face     = loader->face;
    FT_GlyphLoader    gloader  = loader->gloader;
    AF_ScriptMetrics  metrics  = loader->metrics;
    AF_GlyphHints     hints    = &loader->hints;
    FT_GlyphSlot      slot     = face->glyph;
    FT_Slot_Internal  internal = slot->internal;
    FT_Int32          flags;


    flags = load_flags | FT_LOAD_LINEAR_DESIGN;
    error = FT_Load_Glyph( face, glyph_index, flags );
    if ( error )
      goto Exit;

    loader->transformed = internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;


      loader->trans_matrix = internal->glyph_matrix;
      loader->trans_delta  = internal->glyph_delta;

      inverse = loader->trans_matrix;
      FT_Matrix_Invert( &inverse );
      FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    switch ( slot->format )
    {
    case FT_GLYPH_FORMAT_OUTLINE:
      /* translate the loaded glyph when an internal transform is needed */
      if ( loader->transformed )
        FT_Outline_Translate( &slot->outline,
                              loader->trans_delta.x,
                              loader->trans_delta.y );

      /* copy the outline points in the loader's current                */
      /* extra points which are used to keep original glyph coordinates */
      error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
                                           slot->outline.n_points + 4,
                                           slot->outline.n_contours );
      if ( error )
        goto Exit;

      FT_ARRAY_COPY( gloader->current.outline.points,
                     slot->outline.points,
                     slot->outline.n_points );

      FT_ARRAY_COPY( gloader->current.outline.contours,
                     slot->outline.contours,
                     slot->outline.n_contours );

      FT_ARRAY_COPY( gloader->current.outline.tags,
                     slot->outline.tags,
                     slot->outline.n_points );

      gloader->current.outline.n_points   = slot->outline.n_points;
      gloader->current.outline.n_contours = slot->outline.n_contours;

      /* compute original horizontal phantom points (and ignore */
      /* vertical ones)                                         */
      loader->pp1.x = hints->x_delta;
      loader->pp1.y = hints->y_delta;
      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                 hints->x_scale ) + hints->x_delta;
      loader->pp2.y = hints->y_delta;

      /* be sure to check for spacing glyphs */
      if ( slot->outline.n_points == 0 )
        goto Hint_Metrics;

      /* now load the slot image into the auto-outline and run the */
      /* automatic hinting process                                 */
      if ( metrics->clazz->script_hints_apply )
        metrics->clazz->script_hints_apply( hints,
                                            &gloader->current.outline,
                                            metrics );

      /* we now need to adjust the metrics according to the change in */
      /* width/positioning that occurred during the hinting process   */
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
      {
        FT_Pos        old_rsb, old_lsb, new_lsb;
        FT_Pos        pp1x_uh, pp2x_uh;
        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
        AF_Edge       edge2 = edge1 +
                              axis->num_edges - 1; /* rightmost edge */


        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
        {
          old_rsb = loader->pp2.x - edge2->opos;
          old_lsb = edge1->opos;
          new_lsb = edge1->pos;

          /* remember unhinted values to later account */
          /* for rounding errors                       */

          pp1x_uh = new_lsb    - old_lsb;
          pp2x_uh = edge2->pos + old_rsb;

          /* prefer too much space over too little space */
          /* for very small sizes                        */

          if ( old_lsb < 24 )
            pp1x_uh -= 8;

          if ( old_rsb < 24 )
            pp2x_uh += 8;

          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
            loader->pp1.x -= 64;

          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
            loader->pp2.x += 64;

          slot->lsb_delta = loader->pp1.x - pp1x_uh;
          slot->rsb_delta = loader->pp2.x - pp2x_uh;
        }
        else
        {
          FT_Pos  pp1x = loader->pp1.x;
          FT_Pos  pp2x = loader->pp2.x;


          loader->pp1.x = FT_PIX_ROUND( pp1x );
          loader->pp2.x = FT_PIX_ROUND( pp2x );

          slot->lsb_delta = loader->pp1.x - pp1x;
          slot->rsb_delta = loader->pp2.x - pp2x;
        }
      }
      else
      {
        FT_Pos  pp1x = loader->pp1.x;
        FT_Pos  pp2x = loader->pp2.x;


        loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
        loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );

        slot->lsb_delta = loader->pp1.x - pp1x;
        slot->rsb_delta = loader->pp2.x - pp2x;
      }

      /* good, we simply add the glyph to our loader's base */
      FT_GlyphLoader_Add( gloader );
      break;

    case FT_GLYPH_FORMAT_COMPOSITE:
      {
        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
        FT_UInt      num_base_subgs, start_point;
        FT_SubGlyph  subglyph;


        start_point = gloader->base.outline.n_points;

        /* first of all, copy the subglyph descriptors in the glyph loader */
        error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
        if ( error )
          goto Exit;

        FT_ARRAY_COPY( gloader->current.subglyphs,
                       slot->subglyphs,
                       num_subglyphs );

        gloader->current.num_subglyphs = num_subglyphs;
        num_base_subgs                 = gloader->base.num_subglyphs;

        /* now read each subglyph independently */
        for ( nn = 0; nn < num_subglyphs; nn++ )
        {
          FT_Vector  pp1, pp2;
          FT_Pos     x, y;
          FT_UInt    num_points, num_new_points, num_base_points;


          /* gloader.current.subglyphs can change during glyph loading due */
          /* to re-allocation -- we must recompute the current subglyph on */
          /* each iteration                                                */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          pp1 = loader->pp1;
          pp2 = loader->pp2;

          num_base_points = gloader->base.outline.n_points;

          error = af_loader_load_g( loader, scaler, subglyph->index,
                                    load_flags, depth + 1 );
          if ( error )
            goto Exit;

          /* recompute subglyph pointer */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
          {
            pp1 = loader->pp1;
            pp2 = loader->pp2;
          }
          else
          {
            loader->pp1 = pp1;
            loader->pp2 = pp2;
          }

          num_points     = gloader->base.outline.n_points;
          num_new_points = num_points - num_base_points;

          /* now perform the transformation required for this subglyph */

          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
                                   FT_SUBGLYPH_FLAG_XY_SCALE |
                                   FT_SUBGLYPH_FLAG_2X2      ) )
          {
            FT_Vector*  cur   = gloader->base.outline.points +
                                num_base_points;
            FT_Vector*  limit = cur + num_new_points;


            for ( ; cur < limit; cur++ )
              FT_Vector_Transform( cur, &subglyph->transform );
          }

          /* apply offset */

          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
          {
            FT_Int      k = subglyph->arg1;
            FT_UInt     l = subglyph->arg2;
            FT_Vector*  p1;
            FT_Vector*  p2;


            if ( start_point + k >= num_base_points         ||
                               l >= (FT_UInt)num_new_points )
            {
              error = AF_Err_Invalid_Composite;
              goto Exit;
            }

            l += num_base_points;

            /* for now, only use the current point coordinates; */
            /* we eventually may consider another approach      */
            p1 = gloader->base.outline.points + start_point + k;
            p2 = gloader->base.outline.points + start_point + l;

            x = p1->x - p2->x;
            y = p1->y - p2->y;
          }
          else
          {
            x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
            y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;

            x = FT_PIX_ROUND( x );
            y = FT_PIX_ROUND( y );
          }

          {
            FT_Outline  dummy = gloader->base.outline;


            dummy.points  += num_base_points;
            dummy.n_points = (short)num_new_points;

            FT_Outline_Translate( &dummy, x, y );
          }
        }
      }
      break;

    default:
      /* we don't support other formats (yet?) */
      error = AF_Err_Unimplemented_Feature;
    }

  Hint_Metrics:
    if ( depth == 0 )
    {
      FT_BBox    bbox;
      FT_Vector  vvector;


      vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
      vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
      vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
      vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );

      /* transform the hinted outline if needed */
      if ( loader->transformed )
      {
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
        FT_Vector_Transform( &vvector, &loader->trans_matrix );
      }
#if 1
      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
#endif
      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width; ditto for     */
      /* digits if all have the same advance width                 */
#if 0
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               x_scale );
#else
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
           ( FT_IS_FIXED_WIDTH( slot->face )                              ||
             ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
               metrics->digits_have_same_width                          ) ) )
      {
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               metrics->scaler.x_scale );

        /* Set delta values to 0.  Otherwise code that uses them is */
        /* going to ruin the fixed advance width.                   */
        slot->lsb_delta = 0;
        slot->rsb_delta = 0;
      }
      else
      {
        /* non-spacing glyphs must stay as-is */
        if ( slot->metrics.horiAdvance )
          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      }
#endif

      slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
                                             metrics->scaler.y_scale );

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
      slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );

      /* now copy outline into glyph slot */
      FT_GlyphLoader_Rewind( internal->loader );
      error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
      if ( error )
        goto Exit;

      /* reassign all outline fields except flags to protect them */
      slot->outline.n_contours = internal->loader->base.outline.n_contours;
      slot->outline.n_points   = internal->loader->base.outline.n_points;
      slot->outline.points     = internal->loader->base.outline.points;
      slot->outline.tags       = internal->loader->base.outline.tags;
      slot->outline.contours   = internal->loader->base.outline.contours;

      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

  Exit:
    return error;
  }
Exemplo n.º 6
0
  /* convert a slot's glyph image into a bitmap */
  static FT_Error
  ft_smooth_render_generic( FT_Renderer       render,
                            FT_GlyphSlot      slot,
                            FT_Render_Mode    mode,
                            const FT_Vector*  origin,
                            FT_Render_Mode    required_mode )
  {
    FT_Error     error;
    FT_Outline*  outline = NULL;
    FT_BBox      cbox;
    FT_UInt      width, height, height_org, width_org, pitch;
    FT_Bitmap*   bitmap;
    FT_Memory    memory;
    FT_Int       hmul = mode == FT_RENDER_MODE_LCD;
    FT_Int       vmul = mode == FT_RENDER_MODE_LCD_V;
    FT_Pos       x_shift, y_shift, x_left, y_top;

    FT_Raster_Params  params;


    /* check glyph image format */
    if ( slot->format != render->glyph_format )
    {
      error = Smooth_Err_Invalid_Argument;
      goto Exit;
    }

    /* check mode */
    if ( mode != required_mode )
      return Smooth_Err_Cannot_Render_Glyph;

    outline = &slot->outline;

    /* translate the outline to the new origin if needed */
    if ( origin )
      FT_Outline_Translate( outline, origin->x, origin->y );

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox( outline, &cbox );

    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
    cbox.yMax = FT_PIX_CEIL( cbox.yMax );

    width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
    bitmap = &slot->bitmap;
    memory = render->root.memory;

    width_org  = width;
    height_org = height;

    /* release old bitmap buffer */
    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    {
      FT_FREE( bitmap->buffer );
      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    }

    /* allocate new one */
    pitch = width;
    if ( hmul )
    {
      width = width * 3;
      pitch = FT_PAD_CEIL( width, 4 );
    }

    if ( vmul )
      height *= 3;

    x_shift = (FT_Int) cbox.xMin;
    y_shift = (FT_Int) cbox.yMin;
    x_left  = (FT_Int)( cbox.xMin >> 6 );
    y_top   = (FT_Int)( cbox.yMax >> 6 );

#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING

    if ( slot->library->lcd_filter_func )
    {
      FT_Int  extra = slot->library->lcd_extra;


      if ( hmul )
      {
        x_shift -= 64 * ( extra >> 1 );
        width   += 3 * extra;
        pitch    = FT_PAD_CEIL( width, 4 );
        x_left  -= extra >> 1;
      }

      if ( vmul )
      {
        y_shift -= 64 * ( extra >> 1 );
        height  += 3 * extra;
        y_top   += extra >> 1;
      }
    }
Exemplo n.º 7
0
  static FT_Error
  af_loader_load_g( AF_Loader  loader,
                    AF_Scaler  scaler,
                    FT_UInt    glyph_index,
                    FT_Int32   load_flags )
  {
    AF_Module  module = loader->globals->module;

    FT_Error          error;
    FT_Face           face     = loader->face;
    AF_StyleMetrics   metrics  = loader->metrics;
    AF_GlyphHints     hints    = loader->hints;
    FT_GlyphSlot      slot     = face->glyph;
    FT_Slot_Internal  internal = slot->internal;
    FT_GlyphLoader    gloader  = internal->loader;
    FT_Int32          flags;


    flags = load_flags | FT_LOAD_LINEAR_DESIGN;
    error = FT_Load_Glyph( face, glyph_index, flags );
    if ( error )
      goto Exit;

    /*
     * Apply stem darkening (emboldening) here before hints are applied to
     * the outline.  Glyphs are scaled down proportionally to the
     * emboldening so that curve points don't fall outside their precomputed
     * blue zones.
     *
     * Any emboldening done by the font driver (e.g., the CFF driver)
     * doesn't reach here because the autohinter loads the unprocessed
     * glyphs in font units for analysis (functions `af_*_metrics_init_*')
     * and then above to prepare it for the rasterizers by itself,
     * independently of the font driver.  So emboldening must be done here,
     * within the autohinter.
     *
     * All glyphs to be autohinted pass through here one by one.  The
     * standard widths can therefore change from one glyph to the next,
     * depending on what script a glyph is assigned to (each script has its
     * own set of standard widths and other metrics).  The darkening amount
     * must therefore be recomputed for each size and
     * `standard_{vertical,horizontal}_width' change.
     */
    if ( !module->no_stem_darkening )
    {
      AF_FaceGlobals         globals = loader->globals;
      AF_WritingSystemClass  writing_system_class;

      FT_Pos  stdVW = 0;
      FT_Pos  stdHW = 0;

      FT_Bool  size_changed = face->size->metrics.x_ppem
                                != globals->stem_darkening_for_ppem;

      FT_Fixed  em_size  = af_intToFixed( face->units_per_EM );
      FT_Fixed  em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size );

      FT_Matrix  scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };


      /* Skip stem darkening for broken fonts. */
      if ( !face->units_per_EM )
        goto After_Emboldening;

      /*
       * We depend on the writing system (script analyzers) to supply
       * standard widths for the script of the glyph we are looking at.  If
       * it can't deliver, stem darkening is effectively disabled.
       */
      writing_system_class =
        AF_WRITING_SYSTEM_CLASSES_GET[metrics->style_class->writing_system];

      if ( writing_system_class->style_metrics_getstdw )
        writing_system_class->style_metrics_getstdw( metrics,
                                                     &stdHW,
                                                     &stdVW );
      else
        goto After_Emboldening;


      if ( size_changed                                               ||
           ( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
      {
        FT_Fixed  darken_by_font_units_x, darken_x;


        darken_by_font_units_x =
          af_intToFixed( af_loader_compute_darkening( loader,
                                                      face,
                                                      stdVW ) );
        darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x,
                                         face->size->metrics.x_scale ),
                              em_ratio );

        globals->standard_vertical_width = stdVW;
        globals->stem_darkening_for_ppem = face->size->metrics.x_ppem;
        globals->darken_x                = af_fixedToInt( darken_x );
      }

      if ( size_changed                                                 ||
           ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
      {
        FT_Fixed  darken_by_font_units_y, darken_y;


        darken_by_font_units_y =
          af_intToFixed( af_loader_compute_darkening( loader,
                                                      face,
                                                      stdHW ) );
        darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y,
                                         face->size->metrics.y_scale ),
                              em_ratio );

        globals->standard_horizontal_width = stdHW;
        globals->stem_darkening_for_ppem   = face->size->metrics.x_ppem;
        globals->darken_y                  = af_fixedToInt( darken_y );

        /*
         * Scale outlines down on the Y-axis to keep them inside their blue
         * zones.  The stronger the emboldening, the stronger the
         * downscaling (plus heuristical padding to prevent outlines still
         * falling out their zones due to rounding).
         *
         * Reason: `FT_Outline_Embolden' works by shifting the rightmost
         * points of stems farther to the right, and topmost points farther
         * up.  This positions points on the Y-axis outside their
         * pre-computed blue zones and leads to distortion when applying the
         * hints in the code further below.  Code outside this emboldening
         * block doesn't know we are presenting it with modified outlines
         * the analyzer didn't see!
         *
         * An unfortunate side effect of downscaling is that the emboldening
         * effect is slightly decreased.  The loss becomes more pronounced
         * versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
         */
        globals->scale_down_factor =
          FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
                     em_size );
      }

      FT_Outline_EmboldenXY( &slot->outline,
                             globals->darken_x,
                             globals->darken_y );

      scale_down_matrix.yy = globals->scale_down_factor;
      FT_Outline_Transform( &slot->outline, &scale_down_matrix );
    }

  After_Emboldening:
    loader->transformed = internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;


      loader->trans_matrix = internal->glyph_matrix;
      loader->trans_delta  = internal->glyph_delta;

      inverse = loader->trans_matrix;
      if ( !FT_Matrix_Invert( &inverse ) )
        FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    switch ( slot->format )
    {
    case FT_GLYPH_FORMAT_OUTLINE:
      /* translate the loaded glyph when an internal transform is needed */
      if ( loader->transformed )
        FT_Outline_Translate( &slot->outline,
                              loader->trans_delta.x,
                              loader->trans_delta.y );

      /* compute original horizontal phantom points (and ignore */
      /* vertical ones)                                         */
      loader->pp1.x = hints->x_delta;
      loader->pp1.y = hints->y_delta;
      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                 hints->x_scale ) + hints->x_delta;
      loader->pp2.y = hints->y_delta;

      /* be sure to check for spacing glyphs */
      if ( slot->outline.n_points == 0 )
        goto Hint_Metrics;

      /* now load the slot image into the auto-outline and run the */
      /* automatic hinting process                                 */
      {
#ifdef FT_CONFIG_OPTION_PIC
        AF_FaceGlobals         globals = loader->globals;
#endif
        AF_StyleClass          style_class = metrics->style_class;
        AF_WritingSystemClass  writing_system_class =
          AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];


        if ( writing_system_class->style_hints_apply )
          writing_system_class->style_hints_apply( glyph_index,
                                                   hints,
                                                   &gloader->base.outline,
                                                   metrics );
      }

      /* we now need to adjust the metrics according to the change in */
      /* width/positioning that occurred during the hinting process   */
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
      {
        FT_Pos        old_rsb, old_lsb, new_lsb;
        FT_Pos        pp1x_uh, pp2x_uh;
        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
        AF_Edge       edge2 = edge1 +
                              axis->num_edges - 1; /* rightmost edge */


        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
        {
          old_rsb = loader->pp2.x - edge2->opos;
          old_lsb = edge1->opos;
          new_lsb = edge1->pos;

          /* remember unhinted values to later account */
          /* for rounding errors                       */

          pp1x_uh = new_lsb    - old_lsb;
          pp2x_uh = edge2->pos + old_rsb;

          /* prefer too much space over too little space */
          /* for very small sizes                        */

          if ( old_lsb < 24 )
            pp1x_uh -= 8;

          if ( old_rsb < 24 )
            pp2x_uh += 8;

          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
            loader->pp1.x -= 64;

          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
            loader->pp2.x += 64;

          slot->lsb_delta = loader->pp1.x - pp1x_uh;
          slot->rsb_delta = loader->pp2.x - pp2x_uh;
        }
        else
        {
          FT_Pos  pp1x = loader->pp1.x;
          FT_Pos  pp2x = loader->pp2.x;


          loader->pp1.x = FT_PIX_ROUND( pp1x );
          loader->pp2.x = FT_PIX_ROUND( pp2x );

          slot->lsb_delta = loader->pp1.x - pp1x;
          slot->rsb_delta = loader->pp2.x - pp2x;
        }
      }
      else
      {
        FT_Pos  pp1x = loader->pp1.x;
        FT_Pos  pp2x = loader->pp2.x;


        loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
        loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );

        slot->lsb_delta = loader->pp1.x - pp1x;
        slot->rsb_delta = loader->pp2.x - pp2x;
      }

      break;

    default:
      /* we don't support other formats (yet?) */
      error = FT_THROW( Unimplemented_Feature );
    }

  Hint_Metrics:
    {
      FT_BBox    bbox;
      FT_Vector  vvector;


      vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
      vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
      vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
      vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );

      /* transform the hinted outline if needed */
      if ( loader->transformed )
      {
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
        FT_Vector_Transform( &vvector, &loader->trans_matrix );
      }
#if 1
      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
#endif
      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width; ditto for     */
      /* digits if all have the same advance width                 */
#if 0
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               x_scale );
#else
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
           ( FT_IS_FIXED_WIDTH( slot->face )                              ||
             ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
               metrics->digits_have_same_width                          ) ) )
      {
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               metrics->scaler.x_scale );

        /* Set delta values to 0.  Otherwise code that uses them is */
        /* going to ruin the fixed advance width.                   */
        slot->lsb_delta = 0;
        slot->rsb_delta = 0;
      }
      else
      {
        /* non-spacing glyphs must stay as-is */
        if ( slot->metrics.horiAdvance )
          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      }
#endif

      slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
                                             metrics->scaler.y_scale );

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
      slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );

#if 0
      /* reassign all outline fields except flags to protect them */
      slot->outline.n_contours = internal->loader->base.outline.n_contours;
      slot->outline.n_points   = internal->loader->base.outline.n_points;
      slot->outline.points     = internal->loader->base.outline.points;
      slot->outline.tags       = internal->loader->base.outline.tags;
      slot->outline.contours   = internal->loader->base.outline.contours;
#endif

      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

  Exit:
    return error;
  }
Exemplo n.º 8
0
  /* convert a slot's glyph image into a bitmap */
  static FT_Error
  ft_smooth_render_generic( FT_Renderer       render,
                            FT_GlyphSlot      slot,
                            FT_Render_Mode    mode,
                            const FT_Vector*  origin,
                            FT_Render_Mode    required_mode,
                            FT_Int            hmul,
                            FT_Int            vmul )
  {
    FT_Error     error;
    FT_Outline*  outline = NULL;
    FT_BBox      cbox;
    FT_UInt      width, height, pitch;
    FT_Bitmap*   bitmap;
    FT_Memory    memory;

    FT_Raster_Params  params;


    /* check glyph image format */
    if ( slot->format != render->glyph_format )
    {
      error = Smooth_Err_Invalid_Argument;
      goto Exit;
    }

    /* check mode */
    if ( mode != required_mode )
      return Smooth_Err_Cannot_Render_Glyph;

    outline = &slot->outline;

    /* translate the outline to the new origin if needed */
    if ( origin )
      FT_Outline_Translate( outline, origin->x, origin->y );

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox( outline, &cbox );

    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
    cbox.yMax = FT_PIX_CEIL( cbox.yMax );

    width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
    bitmap = &slot->bitmap;
    memory = render->root.memory;

    /* release old bitmap buffer */
    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    {
      FT_FREE( bitmap->buffer );
      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    }

    /* allocate new one, depends on pixel format */
    pitch = width;
    if ( hmul )
    {
      width = width * hmul;
      pitch = FT_PAD_CEIL( width, 4 );
    }

    if ( vmul )
      height *= vmul;

    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
    bitmap->num_grays  = 256;
    bitmap->width      = width;
    bitmap->rows       = height;
    bitmap->pitch      = pitch;

    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
      goto Exit;

    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;

    /* translate outline to render it into the bitmap */
    FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );

    /* set up parameters */
    params.target = bitmap;
    params.source = outline;
    params.flags  = FT_RASTER_FLAG_AA;

    /* implode outline if needed */
    {
      FT_Int      n;
      FT_Vector*  vec;


      if ( hmul )
        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
          vec->x *= hmul;

      if ( vmul )
        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
          vec->y *= vmul;
    }

    /* render outline into the bitmap */
    error = render->raster_render( render->raster, &params );

    /* deflate outline if needed */
    {
      FT_Int      n;
      FT_Vector*  vec;


      if ( hmul )
        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
          vec->x /= hmul;

      if ( vmul )
        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
          vec->y /= vmul;
    }

    FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );

    if ( error )
      goto Exit;

    slot->format      = FT_GLYPH_FORMAT_BITMAP;
    slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
    slot->bitmap_top  = (FT_Int)( cbox.yMax >> 6 );

  Exit:
    if ( outline && origin )
      FT_Outline_Translate( outline, -origin->x, -origin->y );

    return error;
  }
Exemplo n.º 9
0
  static FT_Error
  af_loader_load_g( AF_Loader  loader,
                    AF_Scaler  scaler,
                    FT_UInt    glyph_index,
                    FT_Int32   load_flags )
  {
    FT_Error          error;
    FT_Face           face     = loader->face;
    AF_StyleMetrics   metrics  = loader->metrics;
    AF_GlyphHints     hints    = loader->hints;
    FT_GlyphSlot      slot     = face->glyph;
    FT_Slot_Internal  internal = slot->internal;
    FT_GlyphLoader    gloader  = internal->loader;
    FT_Int32          flags;


    flags = load_flags | FT_LOAD_LINEAR_DESIGN;
    error = FT_Load_Glyph( face, glyph_index, flags );
    if ( error )
      goto Exit;

    loader->transformed = internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;


      loader->trans_matrix = internal->glyph_matrix;
      loader->trans_delta  = internal->glyph_delta;

      inverse = loader->trans_matrix;
      if ( !FT_Matrix_Invert( &inverse ) )
        FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    switch ( slot->format )
    {
    case FT_GLYPH_FORMAT_OUTLINE:
      /* translate the loaded glyph when an internal transform is needed */
      if ( loader->transformed )
        FT_Outline_Translate( &slot->outline,
                              loader->trans_delta.x,
                              loader->trans_delta.y );

      /* compute original horizontal phantom points (and ignore */
      /* vertical ones)                                         */
      loader->pp1.x = hints->x_delta;
      loader->pp1.y = hints->y_delta;
      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                 hints->x_scale ) + hints->x_delta;
      loader->pp2.y = hints->y_delta;

      /* be sure to check for spacing glyphs */
      if ( slot->outline.n_points == 0 )
        goto Hint_Metrics;

      /* now load the slot image into the auto-outline and run the */
      /* automatic hinting process                                 */
      {
#ifdef FT_CONFIG_OPTION_PIC
        AF_FaceGlobals         globals = loader->globals;
#endif
        AF_StyleClass          style_class = metrics->style_class;
        AF_WritingSystemClass  writing_system_class =
          AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];


        if ( writing_system_class->style_hints_apply )
          writing_system_class->style_hints_apply( hints,
                                                   &gloader->base.outline,
                                                   metrics );
      }

      /* we now need to adjust the metrics according to the change in */
      /* width/positioning that occurred during the hinting process   */
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
      {
        FT_Pos        old_rsb, old_lsb, new_lsb;
        FT_Pos        pp1x_uh, pp2x_uh;
        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
        AF_Edge       edge2 = edge1 +
                              axis->num_edges - 1; /* rightmost edge */


        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
        {
          old_rsb = loader->pp2.x - edge2->opos;
          old_lsb = edge1->opos;
          new_lsb = edge1->pos;

          /* remember unhinted values to later account */
          /* for rounding errors                       */

          pp1x_uh = new_lsb    - old_lsb;
          pp2x_uh = edge2->pos + old_rsb;

          /* prefer too much space over too little space */
          /* for very small sizes                        */

          if ( old_lsb < 24 )
            pp1x_uh -= 8;

          if ( old_rsb < 24 )
            pp2x_uh += 8;

          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
            loader->pp1.x -= 64;

          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
            loader->pp2.x += 64;

          slot->lsb_delta = loader->pp1.x - pp1x_uh;
          slot->rsb_delta = loader->pp2.x - pp2x_uh;
        }
        else
        {
          FT_Pos  pp1x = loader->pp1.x;
          FT_Pos  pp2x = loader->pp2.x;


          loader->pp1.x = FT_PIX_ROUND( pp1x );
          loader->pp2.x = FT_PIX_ROUND( pp2x );

          slot->lsb_delta = loader->pp1.x - pp1x;
          slot->rsb_delta = loader->pp2.x - pp2x;
        }
      }
      else
      {
        FT_Pos  pp1x = loader->pp1.x;
        FT_Pos  pp2x = loader->pp2.x;


        loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
        loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );

        slot->lsb_delta = loader->pp1.x - pp1x;
        slot->rsb_delta = loader->pp2.x - pp2x;
      }

      break;

    default:
      /* we don't support other formats (yet?) */
      error = FT_THROW( Unimplemented_Feature );
    }

  Hint_Metrics:
    {
      FT_BBox    bbox;
      FT_Vector  vvector;


      vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
      vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
      vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
      vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );

      /* transform the hinted outline if needed */
      if ( loader->transformed )
      {
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
        FT_Vector_Transform( &vvector, &loader->trans_matrix );
      }
#if 1
      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
#endif
      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width; ditto for     */
      /* digits if all have the same advance width                 */
#if 0
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               x_scale );
#else
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
           ( FT_IS_FIXED_WIDTH( slot->face )                              ||
             ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
               metrics->digits_have_same_width                          ) ) )
      {
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               metrics->scaler.x_scale );

        /* Set delta values to 0.  Otherwise code that uses them is */
        /* going to ruin the fixed advance width.                   */
        slot->lsb_delta = 0;
        slot->rsb_delta = 0;
      }
      else
      {
        /* non-spacing glyphs must stay as-is */
        if ( slot->metrics.horiAdvance )
          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      }
#endif

      slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
                                             metrics->scaler.y_scale );

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
      slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );

#if 0
      /* reassign all outline fields except flags to protect them */
      slot->outline.n_contours = internal->loader->base.outline.n_contours;
      slot->outline.n_points   = internal->loader->base.outline.n_points;
      slot->outline.points     = internal->loader->base.outline.points;
      slot->outline.tags       = internal->loader->base.outline.tags;
      slot->outline.contours   = internal->loader->base.outline.contours;
#endif

      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

  Exit:
    return error;
  }
Exemplo n.º 10
0
  static FT_Error
  af_loader_load_g( AF_Loader  loader,
                    AF_Scaler  scaler,
                    FT_UInt    glyph_index,
                    FT_Int32   load_flags,
                    FT_UInt    depth )
  {
    FT_Error          error    = 0;
    FT_Face           face     = loader->face;
    FT_GlyphLoader    gloader  = loader->gloader;
    AF_ScriptMetrics  metrics  = loader->metrics;
    AF_GlyphHints     hints    = &loader->hints;
    FT_GlyphSlot      slot     = face->glyph;
    FT_Slot_Internal  internal = slot->internal;

    error = FT_Load_Glyph( face, glyph_index, load_flags );
    if ( error )
      goto Exit;

    loader->transformed = internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;

      loader->trans_matrix = internal->glyph_matrix;
      loader->trans_delta  = internal->glyph_delta;

      inverse = loader->trans_matrix;
      FT_Matrix_Invert( &inverse );
      FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    /* set linear metrics */
    slot->linearHoriAdvance = slot->metrics.horiAdvance;
    slot->linearVertAdvance = slot->metrics.vertAdvance;

    switch ( slot->format )
    {
      case FT_GLYPH_FORMAT_OUTLINE:
       /* translate the loaded glyph when an internal transform
        * is needed
        */
        if ( loader->transformed )
          FT_Outline_Translate( &slot->outline,
                                loader->trans_delta.x,
                                loader->trans_delta.y );

        /* copy the outline points in the loader's current               */
        /* extra points which is used to keep original glyph coordinates */
        error = FT_GlyphLoader_CheckPoints( gloader,
                                            slot->outline.n_points + 4,
                                            slot->outline.n_contours );
        if ( error )
          goto Exit;

        FT_ARRAY_COPY( gloader->current.outline.points,
                       slot->outline.points,
                       slot->outline.n_points );

        FT_ARRAY_COPY( gloader->current.extra_points,
                       slot->outline.points,
                       slot->outline.n_points );

        FT_ARRAY_COPY( gloader->current.outline.contours,
                       slot->outline.contours,
                       slot->outline.n_contours );

        FT_ARRAY_COPY( gloader->current.outline.tags,
                       slot->outline.tags,
                       slot->outline.n_points );

        gloader->current.outline.n_points   = slot->outline.n_points;
        gloader->current.outline.n_contours = slot->outline.n_contours;

        /* compute original horizontal phantom points (and ignore */
        /* vertical ones)                                         */
        loader->pp1.x = hints->x_delta;
        loader->pp1.y = hints->y_delta;
        loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                   hints->x_scale ) + hints->x_delta;
        loader->pp2.y = hints->y_delta;

        /* be sure to check for spacing glyphs */
        if ( slot->outline.n_points == 0 )
          goto Hint_Metrics;

        /* now load the slot image into the auto-outline and run the */
        /* automatic hinting process                                 */
        metrics->clazz->script_hints_apply( hints,
                                            &gloader->current.outline,
                                            metrics );

        /* we now need to hint the metrics according to the change in */
        /* width/positioning that occured during the hinting process  */
        {
          FT_Pos        old_advance, old_rsb, old_lsb, new_lsb;
          FT_Pos        pp1x_uh, pp2x_uh;
          AF_AxisHints  axis  = &hints->axis[ AF_DIMENSION_HORZ ];
          AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
          AF_Edge       edge2 = edge1 +
                                axis->num_edges - 1; /* rightmost edge */


          if ( edge2 > edge1 )
          {
            old_advance = loader->pp2.x;
            old_rsb     = old_advance - edge2->opos;
            old_lsb     = edge1->opos;
            new_lsb     = edge1->pos;

            /* remember unhinted values to later account */
            /* for rounding errors                       */

            pp1x_uh = new_lsb    - old_lsb;
            pp2x_uh = edge2->pos + old_rsb;

            /* prefer too much space over too little space */
            /* for very small sizes                        */

            if ( old_lsb < 24 )
              pp1x_uh -= 5;

            if ( old_rsb < 24 )
              pp2x_uh += 5;

            loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
            loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

            slot->lsb_delta = loader->pp1.x - pp1x_uh;
            slot->rsb_delta = loader->pp2.x - pp2x_uh;

#if 0
            /* try to fix certain bad advance computations */
            if ( loader->pp2.x + loader->pp1.x == edge2->pos && old_rsb > 4 )
              loader->pp2.x += 64;
#endif
          }
          else
          {
            loader->pp1.x = FT_PIX_ROUND( loader->pp1.x );
            loader->pp2.x = FT_PIX_ROUND( loader->pp2.x );
          }
        }

        /* good, we simply add the glyph to our loader's base */
        FT_GlyphLoader_Add( gloader );
        break;

    case FT_GLYPH_FORMAT_COMPOSITE:
      {
        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
        FT_UInt      num_base_subgs, start_point;
        FT_SubGlyph  subglyph;


        start_point = gloader->base.outline.n_points;

        /* first of all, copy the subglyph descriptors in the glyph loader */
        error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
        if ( error )
          goto Exit;

        FT_ARRAY_COPY( gloader->current.subglyphs,
                       slot->subglyphs,
                       num_subglyphs );

        gloader->current.num_subglyphs = num_subglyphs;
        num_base_subgs = gloader->base.num_subglyphs;

        /* now, read each subglyph independently */
        for ( nn = 0; nn < num_subglyphs; nn++ )
        {
          FT_Vector  pp1, pp2;
          FT_Pos     x, y;
          FT_UInt    num_points, num_new_points, num_base_points;


          /* gloader.current.subglyphs can change during glyph loading due */
          /* to re-allocation -- we must recompute the current subglyph on */
          /* each iteration                                                */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          pp1 = loader->pp1;
          pp2 = loader->pp2;

          num_base_points = gloader->base.outline.n_points;

          error = af_loader_load_g( loader, scaler, subglyph->index,
                                    load_flags, depth + 1 );
          if ( error )
            goto Exit;

          /* recompute subglyph pointer */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
          {
            pp1 = loader->pp1;
            pp2 = loader->pp2;
          }
          else
          {
            loader->pp1 = pp1;
            loader->pp2 = pp2;
          }

          num_points     = gloader->base.outline.n_points;
          num_new_points = num_points - num_base_points;

          /* now perform the transform required for this subglyph */

          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
                                   FT_SUBGLYPH_FLAG_XY_SCALE |
                                   FT_SUBGLYPH_FLAG_2X2      ) )
          {
            FT_Vector*  cur   = gloader->base.outline.points +
                                num_base_points;
            FT_Vector*  org   = gloader->base.extra_points +
                                num_base_points;
            FT_Vector*  limit = cur + num_new_points;


            for ( ; cur < limit; cur++, org++ )
            {
              FT_Vector_Transform( cur, &subglyph->transform );
              FT_Vector_Transform( org, &subglyph->transform );
            }
          }

          /* apply offset */

          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
          {
            FT_Int      k = subglyph->arg1;
            FT_UInt     l = subglyph->arg2;
            FT_Vector*  p1;
            FT_Vector*  p2;


            if ( start_point + k >= num_base_points         ||
                               l >= (FT_UInt)num_new_points )
            {
              error = FT_Err_Invalid_Composite;
              goto Exit;
            }

            l += num_base_points;

            /* for now, only use the current point coordinates;    */
            /* we may consider another approach in the near future */
            p1 = gloader->base.outline.points + start_point + k;
            p2 = gloader->base.outline.points + start_point + l;

            x = p1->x - p2->x;
            y = p1->y - p2->y;
          }
          else
          {
            x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
            y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;

            x = FT_PIX_ROUND(x);
            y = FT_PIX_ROUND(y);
          }

          {
            FT_Outline  dummy = gloader->base.outline;


            dummy.points  += num_base_points;
            dummy.n_points = (short)num_new_points;

            FT_Outline_Translate( &dummy, x, y );
          }
        }
      }
      break;

    default:
      /* we don't support other formats (yet?) */
      error = FT_Err_Unimplemented_Feature;
    }

  Hint_Metrics:
    if ( depth == 0 )
    {
      FT_BBox  bbox;


      /* transform the hinted outline if needed */
      if ( loader->transformed )
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );

      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );

      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin  = FT_PIX_FLOOR(  bbox.xMin );
      bbox.yMin  = FT_PIX_FLOOR(  bbox.yMin );
      bbox.xMax  = FT_PIX_CEIL( bbox.xMax );
      bbox.yMax  = FT_PIX_CEIL( bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width                */
#if 0
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               x_scale );
#else
      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width                */
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               metrics->scaler.x_scale );
#endif

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );

      /* now copy outline into glyph slot */
      FT_GlyphLoader_Rewind( internal->loader );
      error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
      if ( error )
        goto Exit;

      slot->outline = internal->loader->base.outline;
      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

#ifdef DEBUG_HINTER
    af_debug_hinter = hinter;
#endif

  Exit:
    return error;
  }
Exemplo n.º 11
0
  /* convert a slot's glyph image into a bitmap */
  static FT_Error
  ft_smooth_render_generic( FT_Renderer       render,
                            FT_GlyphSlot      slot,
                            FT_Render_Mode    mode,
                            const FT_Vector*  origin,
                            FT_Render_Mode    required_mode )
  {
    FT_Error     error;
    FT_Outline*  outline = NULL;
    FT_BBox      cbox;
    FT_Pos       width, height, pitch;
#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    FT_Pos       height_org, width_org;
#endif
    FT_Bitmap*   bitmap  = &slot->bitmap;
    FT_Memory    memory  = render->root.memory;
    FT_Int       hmul    = mode == FT_RENDER_MODE_LCD;
    FT_Int       vmul    = mode == FT_RENDER_MODE_LCD_V;
    FT_Pos       x_shift = 0;
    FT_Pos       y_shift = 0;
    FT_Pos       x_left, y_top;

    FT_Raster_Params  params;

    FT_Bool  have_translated_origin = FALSE;
    FT_Bool  have_outline_shifted   = FALSE;
    FT_Bool  have_buffer            = FALSE;


    /* check glyph image format */
    if ( slot->format != render->glyph_format )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    /* check mode */
    if ( mode != required_mode )
    {
      error = FT_THROW( Cannot_Render_Glyph );
      goto Exit;
    }

    outline = &slot->outline;

    /* translate the outline to the new origin if needed */
    if ( origin )
    {
      FT_Outline_Translate( outline, origin->x, origin->y );
      have_translated_origin = TRUE;
    }

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox( outline, &cbox );

    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
    cbox.yMax = FT_PIX_CEIL( cbox.yMax );

    if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin )
    {
      FT_ERROR(( "ft_smooth_render_generic: glyph too large:"
                 " xMin = %d, xMax = %d\n",
                 cbox.xMin >> 6, cbox.xMax >> 6 ));
      error = FT_THROW( Raster_Overflow );
      goto Exit;
    }
Exemplo n.º 12
0
  /* convert a slot's glyph image into a bitmap */
  static FT_Error
  ft_raster1_render( FT_Renderer       render,
                     FT_GlyphSlot      slot,
                     FT_Render_Mode    mode,
                     const FT_Vector*  origin )
  {
    FT_Error     error;
    FT_Outline*  outline;
    FT_BBox      cbox, cbox0;
    FT_UInt      width, height, pitch;
    FT_Bitmap*   bitmap;
    FT_Memory    memory;

    FT_Raster_Params  params;


    /* check glyph image format */
    if ( slot->format != render->glyph_format )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    /* check rendering mode */
    if ( mode != FT_RENDER_MODE_MONO )
    {
      /* raster1 is only capable of producing monochrome bitmaps */
      return FT_THROW( Cannot_Render_Glyph );
    }

    outline = &slot->outline;

    /* translate the outline to the new origin if needed */
    if ( origin )
      FT_Outline_Translate( outline, origin->x, origin->y );

    /* compute the control box, and grid fit it */
    FT_Outline_Get_CBox( outline, &cbox0 );

    /* undocumented but confirmed: bbox values get rounded */
#if 1
    cbox.xMin = FT_PIX_ROUND( cbox0.xMin );
    cbox.yMin = FT_PIX_ROUND( cbox0.yMin );
    cbox.xMax = FT_PIX_ROUND( cbox0.xMax );
    cbox.yMax = FT_PIX_ROUND( cbox0.yMax );
#else
    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
    cbox.yMax = FT_PIX_CEIL( cbox.yMax );
#endif

    /* If either `width' or `height' round to 0, try    */
    /* explicitly rounding up/down.  In the case of     */
    /* glyphs containing only one very narrow feature,  */
    /* this gives the drop-out compensation in the scan */
    /* conversion code a chance to do its stuff.        */
    width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    if ( width == 0 )
    {
      cbox.xMin = FT_PIX_FLOOR( cbox0.xMin );
      cbox.xMax = FT_PIX_CEIL( cbox0.xMax );

      width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
    }