Ejemplo n.º 1
0
  pfr_get_kerning( FT_Face     pfrface,     /* PFR_Face */
                   FT_UInt     left,
                   FT_UInt     right,
                   FT_Vector  *avector )
  {
    PFR_Face     face = (PFR_Face)pfrface;
    PFR_PhyFont  phys = &face->phy_font;


    pfr_face_get_kerning( pfrface, left, right, avector );

    /* convert from metrics to outline units when necessary */
    if ( phys->outline_resolution != phys->metrics_resolution )
    {
      if ( avector->x != 0 )
        avector->x = FT_MulDiv( avector->x, phys->outline_resolution,
                                            phys->metrics_resolution );

      if ( avector->y != 0 )
        avector->y = FT_MulDiv( avector->x, phys->outline_resolution,
                                            phys->metrics_resolution );
    }

    return PFR_Err_Ok;
  }
Ejemplo n.º 2
0
  static FT_Error
  pfr_get_kerning( PFR_Face    face,
                   FT_UInt     left,
                   FT_UInt     right,
                   FT_Vector  *avector )
  {
    FT_Error  error;

    error = pfr_face_get_kerning( face, left, right, avector );
    if ( !error )
    {
      PFR_PhyFont  phys = &face->phy_font;

      /* convert from metrics to outline units when necessary */
      if ( phys->outline_resolution != phys->metrics_resolution )
      {
        if ( avector->x != 0 )
          avector->x = FT_MulDiv( avector->x, phys->outline_resolution,
                                              phys->metrics_resolution );

        if ( avector->y != 0 )
          avector->y = FT_MulDiv( avector->x, phys->outline_resolution,
                                              phys->metrics_resolution );
      }
    }
    return error;
  }
Ejemplo n.º 3
0
  cff_size_select( FT_Size   size,
                   FT_ULong  strike_index )
  {
    CFF_Size           cffsize = (CFF_Size)size;
    PSH_Globals_Funcs  funcs;


    cffsize->strike_index = strike_index;

    FT_Select_Metrics( size->face, strike_index );

    funcs = cff_size_get_globals_funcs( cffsize );

    if ( funcs )
    {
      CFF_Face      face     = (CFF_Face)size->face;
      CFF_Font      font     = (CFF_Font)face->extra.data;
      CFF_Internal  internal = (CFF_Internal)size->internal;

      FT_ULong  top_upm  = font->top_font.font_dict.units_per_em;
      FT_UInt   i;


      funcs->set_scale( internal->topfont,
                        size->metrics.x_scale, size->metrics.y_scale,
                        0, 0 );

      for ( i = font->num_subfonts; i > 0; i-- )
      {
        CFF_SubFont  sub     = font->subfonts[i - 1];
        FT_ULong     sub_upm = sub->font_dict.units_per_em;
        FT_Pos       x_scale, y_scale;


        if ( top_upm != sub_upm )
        {
          x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
          y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
        }
        else
        {
          x_scale = size->metrics.x_scale;
          y_scale = size->metrics.y_scale;
        }

        funcs->set_scale( internal->subfonts[i - 1],
                          x_scale, y_scale, 0, 0 );
      }
    }

    return FT_Err_Ok;
  }
Ejemplo n.º 4
0
  /* the fill direction of given bbox extremum                       */
  static FT_Int
  ah_test_extremum( FT_Outline*  outline,
                    FT_Int       n )
  {
    FT_Vector  *prev, *cur, *next;
    FT_Pos      product;
    FT_Int      first, last, c;
    FT_Int      retval;


    /* we need to compute the `previous' and `next' point */
    /* for this extremum; we check whether the extremum   */
    /* is start or end of a contour and providing         */
    /* appropriate values if so                           */
    cur  = outline->points + n;
    prev = cur - 1;
    next = cur + 1;

    first = 0;
    for ( c = 0; c < outline->n_contours; c++ )
    {
      last = outline->contours[c];

      if ( n == first )
        prev = outline->points + last;

      if ( n == last )
        next = outline->points + first;

      first = last + 1;
    }

    /* compute the vectorial product -- since we know that the angle */
    /* is <= 180 degrees (otherwise it wouldn't be an extremum) we   */
    /* can determine the filling orientation if the product is       */
    /* either positive or negative                                   */
    product = FT_MulDiv( cur->x  - prev->x,  /* in.x  */
                         next->y - cur->y,   /* out.y */
                         0x40 )
              -
              FT_MulDiv( cur->y  - prev->y,  /* in.y  */
                         next->x - cur->x,   /* out.x */
                         0x40 );

    retval = 0;
    if ( product )
      retval = product > 0 ? 2 : 1;

    return retval;
  }
Ejemplo n.º 5
0
  static void
  BBox_Conic_Check( FT_Pos   y1,
                    FT_Pos   y2,
                    FT_Pos   y3,
                    FT_Pos*  min,
                    FT_Pos*  max )
  {
    if ( y1 <= y3 && y2 == y1 )     /* flat arc */
      goto Suite;

    if ( y1 < y3 )
    {
      if ( y2 >= y1 && y2 <= y3 )   /* ascending arc */
        goto Suite;
    }
    else
    {
      if ( y2 >= y3 && y2 <= y1 )   /* descending arc */
      {
        y2 = y1;
        y1 = y3;
        y3 = y2;
        goto Suite;
      }
    }

    y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );

  Suite:
    if ( y1 < *min ) *min = y1;
    if ( y3 > *max ) *max = y3;
  }
Ejemplo n.º 6
0
  static FT_Error
  _ft_face_scale_advances( FT_Face    face,
                           FT_Fixed*  advances,
                           FT_UInt    count,
                           FT_Int32   flags )
  {
    FT_Fixed  scale;
    FT_UInt   nn;


    if ( flags & FT_LOAD_NO_SCALE )
      return FT_Err_Ok;

    if ( face->size == NULL )
      return FT_THROW( Invalid_Size_Handle );

    if ( flags & FT_LOAD_VERTICAL_LAYOUT )
      scale = face->size->metrics.y_scale;
    else
      scale = face->size->metrics.x_scale;

    /* this must be the same scaling as to get linear{Hori,Vert}Advance */
    /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c)        */

    for ( nn = 0; nn < count; nn++ )
      advances[nn] = FT_MulDiv( advances[nn], scale, 64 );

    return FT_Err_Ok;
  }
Ejemplo n.º 7
0
Archivo: t1afm.c Proyecto: dmdware/vec
  T1_Get_Track_Kerning( FT_Face    face,
                        FT_Fixed   ptsize,
                        FT_Int     degree,
                        FT_Fixed*  kerning )
  {
    AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
    FT_Int        i;


    if ( !fi )
      return FT_THROW( Invalid_Argument );

    for ( i = 0; i < fi->NumTrackKern; i++ )
    {
      AFM_TrackKern  tk = fi->TrackKerns + i;


      if ( tk->degree != degree )
        continue;

      if ( ptsize < tk->min_ptsize )
        *kerning = tk->min_kern;
      else if ( ptsize > tk->max_ptsize )
        *kerning = tk->max_kern;
      else
      {
        *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
                              tk->max_kern - tk->min_kern,
                              tk->max_ptsize - tk->min_ptsize ) +
                   tk->min_kern;
      }
    }

    return FT_Err_Ok;
  }
Ejemplo n.º 8
0
  /* the fill direction of a given bbox extrema                      */
  static FT_Int
  ah_test_extrema( FT_Outline*  outline,
                   FT_Int       n )
  {
    FT_Vector  *prev, *cur, *next;
    FT_Pos      product;
    FT_Int      first, last, c;
    FT_Int      retval;


    /* we need to compute the `previous' and `next' point */
    /* for these extrema                                  */
    cur  = outline->points + n;
    prev = cur - 1;
    next = cur + 1;

    first = 0;
    for ( c = 0; c < outline->n_contours; c++ )
    {
      last  = outline->contours[c];

      if ( n == first )
        prev = outline->points + last;

      if ( n == last )
        next = outline->points + first;

      first = last + 1;
    }

    product = FT_MulDiv( cur->x  - prev->x,  /* in.x  */
                         next->y - cur->y,   /* out.y */
                         0x40 )
              -
              FT_MulDiv( cur->y  - prev->y,  /* in.y  */
                         next->x - cur->x,   /* out.x */
                         0x40 );

    retval = 0;
    if ( product )
      retval = product > 0 ? 2 : 1;

    return retval;
  }
Ejemplo n.º 9
0
static FT_Error
tt_size_request( FT_Size          size,
                 FT_Size_Request  req )
{
    TT_Size   ttsize = (TT_Size)size;
    FT_Error  error  = FT_Err_Ok;


#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS

    if ( FT_HAS_FIXED_SIZES( size->face ) )
    {
        TT_Face       ttface = (TT_Face)size->face;
        SFNT_Service  sfnt   = (SFNT_Service)ttface->sfnt;
        FT_ULong      strike_index;


        error = sfnt->set_sbit_strike( ttface, req, &strike_index );

        if ( error )
            ttsize->strike_index = 0xFFFFFFFFUL;
        else
            return tt_size_select( size, strike_index );
    }

#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

    FT_Request_Metrics( size->face, req );

    if ( FT_IS_SCALABLE( size->face ) )
    {
        error = tt_size_reset( ttsize );
        ttsize->root.metrics = ttsize->metrics;

#ifdef TT_USE_BYTECODE_INTERPRETER
        /* for the `MPS' bytecode instruction we need the point size */
        {
            FT_UInt  resolution = ttsize->metrics.x_ppem > ttsize->metrics.y_ppem
                                  ? req->horiResolution
                                  : req->vertResolution;


            /* if we don't have a resolution value, assume 72dpi */
            if ( req->type == FT_SIZE_REQUEST_TYPE_SCALES ||
                    !resolution                              )
                resolution = 72;

            ttsize->point_size = FT_MulDiv( ttsize->ttmetrics.ppem,
                                            64 * 72,
                                            resolution );
        }
#endif
    }

    return error;
}
Ejemplo n.º 10
0
  static void
  BBox_Conic_Check( FT_Pos   y1,
                    FT_Pos   y2,
                    FT_Pos   y3,
                    FT_Pos*  min,
                    FT_Pos*  max )
  {
    /* This function is only called when a control off-point is outside */
    /* the bbox that contains all on-points.  It finds a local extremum */
    /* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3).   */
    /* Or, offsetting from y2, we get                                   */

    y1 -= y2;
    y3 -= y2;
    y2 += FT_MulDiv( y1, y3, y1 + y3 );

    if ( y2 < *min )
      *min = y2;
    if ( y2 > *max )
      *max = y2;
  }
Ejemplo n.º 11
0
  pfr_slot_load( FT_GlyphSlot  pfrslot,         /* PFR_Slot */
                 FT_Size       pfrsize,         /* PFR_Size */
                 FT_UInt       gindex,
                 FT_Int32      load_flags )
  {
    PFR_Slot     slot    = (PFR_Slot)pfrslot;
    PFR_Size     size    = (PFR_Size)pfrsize;
    FT_Error     error;
    PFR_Face     face    = (PFR_Face)pfrslot->face;
    PFR_Char     gchar;
    FT_Outline*  outline = &pfrslot->outline;
    FT_ULong     gps_offset;


    if ( gindex > 0 )
      gindex--;

    /* check that the glyph index is correct */
    FT_ASSERT( gindex < face->phy_font.num_chars );

    /* try to load an embedded bitmap */
    if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
    {
      error = pfr_slot_load_bitmap( slot, size, gindex );
      if ( error == 0 )
        goto Exit;
    }

    if ( load_flags & FT_LOAD_SBITS_ONLY )
    {
      error = PFR_Err_Invalid_Argument;
      goto Exit;
    }

    gchar               = face->phy_font.chars + gindex;
    pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
    outline->n_points   = 0;
    outline->n_contours = 0;
    gps_offset          = face->header.gps_section_offset;

    /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
    error = pfr_glyph_load( &slot->glyph, face->root.stream,
                            gps_offset, gchar->gps_offset, gchar->gps_size );

    if ( !error )
    {
      FT_BBox            cbox;
      FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
      FT_Pos             advance;
      FT_Int             em_metrics, em_outline;
      FT_Bool            scaling;


      scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );

      /* copy outline data */
      *outline = slot->glyph.loader->base.outline;

      outline->flags &= ~FT_OUTLINE_OWNER;
      outline->flags |= FT_OUTLINE_REVERSE_FILL;

      if ( size && pfrsize->metrics.y_ppem < 24 )
        outline->flags |= FT_OUTLINE_HIGH_PRECISION;

      /* compute the advance vector */
      metrics->horiAdvance = 0;
      metrics->vertAdvance = 0;

      advance    = gchar->advance;
      em_metrics = face->phy_font.metrics_resolution;
      em_outline = face->phy_font.outline_resolution;

      if ( em_metrics != em_outline )
        advance = FT_MulDiv( advance, em_outline, em_metrics );

      if ( face->phy_font.flags & PFR_PHY_VERTICAL )
        metrics->vertAdvance = advance;
      else
        metrics->horiAdvance = advance;

      pfrslot->linearHoriAdvance = metrics->horiAdvance;
      pfrslot->linearVertAdvance = metrics->vertAdvance;

      /* make-up vertical metrics(?) */
      metrics->vertBearingX = 0;
      metrics->vertBearingY = 0;

      /* Apply the font matrix, if any.                 */
      /* TODO: Test existing fonts with unusual matrix  */
      /* whether we have to adjust Units per EM.        */
      {
        FT_Matrix font_matrix;


        font_matrix.xx = face->log_font.matrix[0] << 8;
        font_matrix.yx = face->log_font.matrix[1] << 8;
        font_matrix.xy = face->log_font.matrix[2] << 8;
        font_matrix.yy = face->log_font.matrix[3] << 8;

        FT_Outline_Transform( outline, &font_matrix );
      }

      /* scale when needed */
      if ( scaling )
      {
        FT_Int      n;
        FT_Fixed    x_scale = pfrsize->metrics.x_scale;
        FT_Fixed    y_scale = pfrsize->metrics.y_scale;
        FT_Vector*  vec     = outline->points;


        /* scale outline points */
        for ( n = 0; n < outline->n_points; n++, vec++ )
        {
          vec->x = FT_MulFix( vec->x, x_scale );
          vec->y = FT_MulFix( vec->y, y_scale );
        }

        /* scale the advance */
        metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
        metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
      }

      /* compute the rest of the metrics */
      FT_Outline_Get_CBox( outline, &cbox );

      metrics->width        = cbox.xMax - cbox.xMin;
      metrics->height       = cbox.yMax - cbox.yMin;
      metrics->horiBearingX = cbox.xMin;
      metrics->horiBearingY = cbox.yMax - metrics->height;
    }

  Exit:
    return error;
  }
Ejemplo n.º 12
0
LOCAL_DEF
FT_Error  TT_Reset_Size(TT_Size size)
{
	TT_Face face;
	FT_Error error = TT_Err_Ok;

	FT_Size_Metrics  *metrics;


	if(size->ttmetrics.valid)
	{
		return TT_Err_Ok;
	}

	face = (TT_Face)size->root.face;

	metrics = &size->root.metrics;

	if(metrics->x_ppem < 1 || metrics->y_ppem < 1)
	{
		return TT_Err_Invalid_PPem;
	}

	/* compute new transformation */
	if(metrics->x_ppem >= metrics->y_ppem)
	{
		size->ttmetrics.scale   = metrics->x_scale;
		size->ttmetrics.ppem    = metrics->x_ppem;
		size->ttmetrics.x_ratio = 0x10000L;
		size->ttmetrics.y_ratio = FT_MulDiv(metrics->y_ppem,
		                                    0x10000L,
		                                    metrics->x_ppem);
	}
	else
	{
		size->ttmetrics.scale   = metrics->y_scale;
		size->ttmetrics.ppem    = metrics->y_ppem;
		size->ttmetrics.x_ratio = FT_MulDiv(metrics->x_ppem,
		                                    0x10000L,
		                                    metrics->y_ppem);
		size->ttmetrics.y_ratio = 0x10000L;
	}

	/* Compute root ascender, descender, test height, and max_advance */
	metrics->ascender    = (FT_MulFix(face->root.ascender,
	                                  metrics->y_scale) + 32) & - 64;
	metrics->descender   = (FT_MulFix(face->root.descender,
	                                  metrics->y_scale) + 32) & - 64;
	metrics->height      = (FT_MulFix(face->root.height,
	                                  metrics->y_scale) + 32) & - 64;
	metrics->max_advance = (FT_MulFix(face->root.max_advance_width,
	                                  metrics->x_scale) + 32) & - 64;

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

	{
		TT_ExecContext exec;
		FT_UInt i, j;


		/* Scale the cvt values to the new ppem.          */
		/* We use by default the y ppem to scale the CVT. */
		for(i = 0; i < size->cvt_size; i++)
			size->cvt[i] = FT_MulFix(face->cvt[i], size->ttmetrics.scale);

		/* All twilight points are originally zero */
		for(j = 0; j < size->twilight.n_points; j++)
		{
			size->twilight.org[j].x = 0;
			size->twilight.org[j].y = 0;
			size->twilight.cur[j].x = 0;
			size->twilight.cur[j].y = 0;
		}

		/* clear storage area */
		for(i = 0; i < size->storage_size; i++)
			size->storage[i] = 0;

		size->GS = tt_default_graphics_state;

		/* get execution context and run prep program */
		if(size->debug)
		{
			exec = size->context;
		}
		else
		{
			exec = TT_New_Context(face);
		}

		/* debugging instances have their own context */

		if(!exec)
		{
			return TT_Err_Could_Not_Find_Context;
		}

		TT_Load_Context(exec, face, size);

		TT_Set_CodeRange(exec,
		                 tt_coderange_cvt,
		                 face->cvt_program,
		                 face->cvt_program_size);

		TT_Clear_CodeRange(exec, tt_coderange_glyph);

		exec->instruction_trap = FALSE;

		exec->top     = 0;
		exec->callTop = 0;

		if(face->cvt_program_size > 0)
		{
			error = TT_Goto_CodeRange(exec, tt_coderange_cvt, 0);

			if(error)
			{
				goto End;
			}

			if(!size->debug)
			{
				error = face->interpreter(exec);
			}
		}
		else
		{
			error = TT_Err_Ok;
		}

		size->GS = exec->GS;
		/* save default graphics state */

End:
		TT_Save_Context(exec, size);

		if(!size->debug)
		{
			TT_Done_Context(exec);
		}

		/* debugging instances keep their context */
	}

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

	if(!error)
	{
		size->ttmetrics.valid = TRUE;
	}

	return error;
}
Ejemplo n.º 13
0
  static void
  af_latin_metrics_scale_dim( AF_LatinMetrics  metrics,
                              AF_Scaler        scaler,
                              AF_Dimension     dim )
  {
    FT_Fixed      scale;
    FT_Pos        delta;
    AF_LatinAxis  axis;
    FT_UInt       nn;


    if ( dim == AF_DIMENSION_HORZ )
    {
      scale = scaler->x_scale;
      delta = scaler->x_delta;
    }
    else
    {
      scale = scaler->y_scale;
      delta = scaler->y_delta;
    }

    axis = &metrics->axis[dim];

    if ( axis->org_scale == scale && axis->org_delta == delta )
      return;

    axis->org_scale = scale;
    axis->org_delta = delta;

    /*
     * correct X and Y scale to optimize the alignment of the top of small
     * letters to the pixel grid
     */
    {
      AF_LatinAxis  Axis = &metrics->axis[AF_DIMENSION_VERT];
      AF_LatinBlue  blue = NULL;


      for ( nn = 0; nn < Axis->blue_count; nn++ )
      {
        if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
        {
          blue = &Axis->blues[nn];
          break;
        }
      }

      if ( blue )
      {
        FT_Pos  scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
        FT_Pos  fitted = ( scaled + 40 ) & ~63;


        if ( scaled != fitted )
        {
#if 0
          if ( dim == AF_DIMENSION_HORZ )
          {
            if ( fitted < scaled )
              scale -= scale / 50;  /* scale *= 0.98 */
          }
          else
#endif
          if ( dim == AF_DIMENSION_VERT )
          {
            scale = FT_MulDiv( scale, fitted, scaled );
          }
        }
      }
    }

    axis->scale = scale;
    axis->delta = delta;

    if ( dim == AF_DIMENSION_HORZ )
    {
      metrics->root.scaler.x_scale = scale;
      metrics->root.scaler.x_delta = delta;
    }
    else
    {
      metrics->root.scaler.y_scale = scale;
      metrics->root.scaler.y_delta = delta;
    }

    /* scale the standard widths */
    for ( nn = 0; nn < axis->width_count; nn++ )
    {
      AF_Width  width = axis->widths + nn;


      width->cur = FT_MulFix( width->org, scale );
      width->fit = width->cur;
    }

    /* an extra-light axis corresponds to a standard width that is */
    /* smaller than 0.75 pixels                                    */
    axis->extra_light =
      (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );

    if ( dim == AF_DIMENSION_VERT )
    {
      /* scale the blue zones */
      for ( nn = 0; nn < axis->blue_count; nn++ )
      {
        AF_LatinBlue  blue = &axis->blues[nn];
        FT_Pos        dist;


        blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
        blue->ref.fit   = blue->ref.cur;
        blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
        blue->shoot.fit = blue->shoot.cur;
        blue->flags    &= ~AF_LATIN_BLUE_ACTIVE;

        /* a blue zone is only active if it is less than 3/4 pixels tall */
        dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
        if ( dist <= 48 && dist >= -48 )
        {
          FT_Pos  delta1, delta2;


          delta1 = blue->shoot.org - blue->ref.org;
          delta2 = delta1;
          if ( delta1 < 0 )
            delta2 = -delta2;

          delta2 = FT_MulFix( delta2, scale );

          if ( delta2 < 32 )
            delta2 = 0;
          else if ( delta2 < 64 )
            delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
          else
            delta2 = FT_PIX_ROUND( delta2 );

          if ( delta1 < 0 )
            delta2 = -delta2;

          blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
          blue->shoot.fit = blue->ref.fit + delta2;

          blue->flags |= AF_LATIN_BLUE_ACTIVE;
        }
      }
    }
  }
Ejemplo n.º 14
0
  FT_Outline_Get_Orientation( FT_Outline*  outline )
  {
    FT_Pos      xmin       = 32768L;
    FT_Pos      xmin_ymin  = 32768L;
    FT_Pos      xmin_ymax  = -32768L;
    FT_Vector*  xmin_first = NULL;
    FT_Vector*  xmin_last  = NULL;

    short*      contour;

    FT_Vector*  first;
    FT_Vector*  last;
    FT_Vector*  prev;
    FT_Vector*  point;

    int             i;
    FT_Pos          ray_y[3];
    FT_Orientation  result[3];


    if ( !outline || outline->n_points <= 0 )
      return FT_ORIENTATION_TRUETYPE;

    /* We use the nonzero winding rule to find the orientation.       */
    /* Since glyph outlines behave much more `regular' than arbitrary */
    /* cubic or quadratic curves, this test deals with the polygon    */
    /* only which is spanned up by the control points.                */

    first = outline->points;
    for ( contour = outline->contours;
          contour < outline->contours + outline->n_contours;
          contour++, first = last + 1 )
    {
      FT_Pos  contour_xmin = 32768L;
      FT_Pos  contour_xmax = -32768L;
      FT_Pos  contour_ymin = 32768L;
      FT_Pos  contour_ymax = -32768L;


      last = outline->points + *contour;

      /* skip degenerate contours */
      if ( last < first + 2 )
        continue;

      for ( point = first; point <= last; ++point )
      {
        if ( point->x < contour_xmin )
          contour_xmin = point->x;

        if ( point->x > contour_xmax )
          contour_xmax = point->x;

        if ( point->y < contour_ymin )
          contour_ymin = point->y;

        if ( point->y > contour_ymax )
          contour_ymax = point->y;
      }

      if ( contour_xmin < xmin          &&
           contour_xmin != contour_xmax &&
           contour_ymin != contour_ymax )
      {
        xmin       = contour_xmin;
        xmin_ymin  = contour_ymin;
        xmin_ymax  = contour_ymax;
        xmin_first = first;
        xmin_last  = last;
      }
    }

    if ( xmin == 32768 )
      return FT_ORIENTATION_TRUETYPE;

    ray_y[0] = ( xmin_ymin * 3 + xmin_ymax     ) >> 2;
    ray_y[1] = ( xmin_ymin     + xmin_ymax     ) >> 1;
    ray_y[2] = ( xmin_ymin     + xmin_ymax * 3 ) >> 2;

    for ( i = 0; i < 3; i++ )
    {
      FT_Pos      left_x;
      FT_Pos      right_x;
      FT_Vector*  left1;
      FT_Vector*  left2;
      FT_Vector*  right1;
      FT_Vector*  right2;


    RedoRay:
      left_x  = 32768L;
      right_x = -32768L;

      left1 = left2 = right1 = right2 = NULL;

      prev = xmin_last;
      for ( point = xmin_first; point <= xmin_last; prev = point, ++point )
      {
        FT_Pos  tmp_x;


        if ( point->y == ray_y[i] || prev->y == ray_y[i] )
        {
          ray_y[i]++;
          goto RedoRay;
        }

        if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) ||
             ( point->y > ray_y[i] && prev->y > ray_y[i] ) )
          continue;

        tmp_x = FT_MulDiv( point->x - prev->x,
                           ray_y[i] - prev->y,
                           point->y - prev->y ) + prev->x;

        if ( tmp_x < left_x )
        {
          left_x = tmp_x;
          left1  = prev;
          left2  = point;
        }

        if ( tmp_x > right_x )
        {
          right_x = tmp_x;
          right1  = prev;
          right2  = point;
        }
      }

      if ( left1 && right1 )
      {
        if ( left1->y < left2->y && right1->y > right2->y )
          result[i] = FT_ORIENTATION_TRUETYPE;
        else if ( left1->y > left2->y && right1->y < right2->y )
          result[i] = FT_ORIENTATION_POSTSCRIPT;
        else
          result[i] = FT_ORIENTATION_NONE;
      }
    }

    if ( result[0] != FT_ORIENTATION_NONE                     &&
         ( result[0] == result[1] || result[0] == result[2] ) )
      return result[0];

    if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )
      return result[1];

    return FT_ORIENTATION_TRUETYPE;
  }
Ejemplo n.º 15
0
Archivo: psblues.c Proyecto: 93i/godot
  cf2_blues_init( CF2_Blues  blues,
                  CF2_Font   font )
  {
    /* pointer to parsed font object */
    PS_Decoder*  decoder = font->decoder;

    CF2_Fixed  zoneHeight;
    CF2_Fixed  maxZoneHeight = 0;
    CF2_Fixed  csUnitsPerPixel;

    size_t  numBlueValues;
    size_t  numOtherBlues;
    size_t  numFamilyBlues;
    size_t  numFamilyOtherBlues;

    FT_Pos*  blueValues;
    FT_Pos*  otherBlues;
    FT_Pos*  familyBlues;
    FT_Pos*  familyOtherBlues;

    size_t     i;
    CF2_Fixed  emBoxBottom, emBoxTop;

#if 0
    CF2_Int  unitsPerEm = font->unitsPerEm;


    if ( unitsPerEm == 0 )
      unitsPerEm = 1000;
#endif

    FT_ZERO( blues );
    blues->scale = font->innerTransform.d;

    cf2_getBlueMetrics( decoder,
                        &blues->blueScale,
                        &blues->blueShift,
                        &blues->blueFuzz );

    cf2_getBlueValues( decoder, &numBlueValues, &blueValues );
    cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues );
    cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues );
    cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues );

    /*
     * synthetic em box hint heuristic
     *
     * Apply this when ideographic dictionary (LanguageGroup 1) has no
     * real alignment zones.  Adobe tools generate dummy zones at -250 and
     * 1100 for a 1000 unit em.  Fonts with ICF-based alignment zones
     * should not enable the heuristic.  When the heuristic is enabled,
     * the font's blue zones are ignored.
     *
     */

    /* get em box from OS/2 typoAscender/Descender                      */
    /* TODO: FreeType does not parse these metrics.  Skip them for now. */
#if 0
    FCM_getHorizontalLineMetrics( &e,
                                  font->font,
                                  &ascender,
                                  &descender,
                                  &linegap );
    if ( ascender - descender == unitsPerEm )
    {
      emBoxBottom = cf2_intToFixed( descender );
      emBoxTop    = cf2_intToFixed( ascender );
    }
    else
#endif
    {
      emBoxBottom = CF2_ICF_Bottom;
      emBoxTop    = CF2_ICF_Top;
    }

    if ( cf2_getLanguageGroup( decoder ) == 1                   &&
         ( numBlueValues == 0                                 ||
           ( numBlueValues == 4                             &&
             cf2_blueToFixed( blueValues[0] ) < emBoxBottom &&
             cf2_blueToFixed( blueValues[1] ) < emBoxBottom &&
             cf2_blueToFixed( blueValues[2] ) > emBoxTop    &&
             cf2_blueToFixed( blueValues[3] ) > emBoxTop    ) ) )
    {
      /*
       * Construct hint edges suitable for synthetic ghost hints at top
       * and bottom of em box.  +-CF2_MIN_COUNTER allows for unhinted
       * features above or below the last hinted edge.  This also gives a
       * net 1 pixel boost to the height of ideographic glyphs.
       *
       * Note: Adjust synthetic hints outward by epsilon (0x.0001) to
       *       avoid interference.  E.g., some fonts have real hints at
       *       880 and -120.
       */

      blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON;
      blues->emBoxBottomEdge.dsCoord = cf2_fixedRound(
                                         FT_MulFix(
                                           blues->emBoxBottomEdge.csCoord,
                                           blues->scale ) ) -
                                       CF2_MIN_COUNTER;
      blues->emBoxBottomEdge.scale   = blues->scale;
      blues->emBoxBottomEdge.flags   = CF2_GhostBottom |
                                       CF2_Locked |
                                       CF2_Synthetic;

      blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON +
                                    2 * font->darkenY;
      blues->emBoxTopEdge.dsCoord = cf2_fixedRound(
                                      FT_MulFix(
                                        blues->emBoxTopEdge.csCoord,
                                        blues->scale ) ) +
                                    CF2_MIN_COUNTER;
      blues->emBoxTopEdge.scale   = blues->scale;
      blues->emBoxTopEdge.flags   = CF2_GhostTop |
                                    CF2_Locked |
                                    CF2_Synthetic;

      blues->doEmBoxHints = TRUE;    /* enable the heuristic */

      return;
    }

    /* copy `BlueValues' and `OtherBlues' to a combined array of top and */
    /* bottom zones                                                      */
    for ( i = 0; i < numBlueValues; i += 2 )
    {
      blues->zone[blues->count].csBottomEdge =
        cf2_blueToFixed( blueValues[i] );
      blues->zone[blues->count].csTopEdge =
        cf2_blueToFixed( blueValues[i + 1] );

      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
                              blues->zone[blues->count].csBottomEdge );

      if ( zoneHeight < 0 )
      {
        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
        continue;   /* reject this zone */
      }

      if ( zoneHeight > maxZoneHeight )
      {
        /* take maximum before darkening adjustment      */
        /* so overshoot suppression point doesn't change */
        maxZoneHeight = zoneHeight;
      }

      /* adjust both edges of top zone upward by twice darkening amount */
      if ( i != 0 )
      {
        blues->zone[blues->count].csTopEdge    += 2 * font->darkenY;
        blues->zone[blues->count].csBottomEdge += 2 * font->darkenY;
      }

      /* first `BlueValue' is bottom zone; others are top */
      if ( i == 0 )
      {
        blues->zone[blues->count].bottomZone =
          TRUE;
        blues->zone[blues->count].csFlatEdge =
          blues->zone[blues->count].csTopEdge;
      }
      else
      {
        blues->zone[blues->count].bottomZone =
          FALSE;
        blues->zone[blues->count].csFlatEdge =
          blues->zone[blues->count].csBottomEdge;
      }

      blues->count += 1;
    }

    for ( i = 0; i < numOtherBlues; i += 2 )
    {
      blues->zone[blues->count].csBottomEdge =
        cf2_blueToFixed( otherBlues[i] );
      blues->zone[blues->count].csTopEdge =
        cf2_blueToFixed( otherBlues[i + 1] );

      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
                              blues->zone[blues->count].csBottomEdge );

      if ( zoneHeight < 0 )
      {
        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
        continue;   /* reject this zone */
      }

      if ( zoneHeight > maxZoneHeight )
      {
        /* take maximum before darkening adjustment      */
        /* so overshoot suppression point doesn't change */
        maxZoneHeight = zoneHeight;
      }

      /* Note: bottom zones are not adjusted for darkening amount */

      /* all OtherBlues are bottom zone */
      blues->zone[blues->count].bottomZone =
        TRUE;
      blues->zone[blues->count].csFlatEdge =
        blues->zone[blues->count].csTopEdge;

      blues->count += 1;
    }

    /* Adjust for FamilyBlues */

    /* Search for the nearest flat edge in `FamilyBlues' or                */
    /* `FamilyOtherBlues'.  According to the Black Book, any matching edge */
    /* must be within one device pixel                                     */

    csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale );

    /* loop on all zones in this font */
    for ( i = 0; i < blues->count; i++ )
    {
      size_t     j;
      CF2_Fixed  minDiff;
      CF2_Fixed  flatFamilyEdge, diff;
      /* value for this font */
      CF2_Fixed  flatEdge = blues->zone[i].csFlatEdge;


      if ( blues->zone[i].bottomZone )
      {
        /* In a bottom zone, the top edge is the flat edge.             */
        /* Search `FamilyOtherBlues' for bottom zones; look for closest */
        /* Family edge that is within the one pixel threshold.          */

        minDiff = CF2_FIXED_MAX;

        for ( j = 0; j < numFamilyOtherBlues; j += 2 )
        {
          /* top edge */
          flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] );

          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );

          if ( diff < minDiff && diff < csUnitsPerPixel )
          {
            blues->zone[i].csFlatEdge = flatFamilyEdge;
            minDiff                   = diff;

            if ( diff == 0 )
              break;
          }
        }

        /* check the first member of FamilyBlues, which is a bottom zone */
        if ( numFamilyBlues >= 2 )
        {
          /* top edge */
          flatFamilyEdge = cf2_blueToFixed( familyBlues[1] );

          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );

          if ( diff < minDiff && diff < csUnitsPerPixel )
            blues->zone[i].csFlatEdge = flatFamilyEdge;
        }
      }
      else
      {
        /* In a top zone, the bottom edge is the flat edge.                */
        /* Search `FamilyBlues' for top zones; skip first zone, which is a */
        /* bottom zone; look for closest Family edge that is within the    */
        /* one pixel threshold                                             */

        minDiff = CF2_FIXED_MAX;

        for ( j = 2; j < numFamilyBlues; j += 2 )
        {
          /* bottom edge */
          flatFamilyEdge = cf2_blueToFixed( familyBlues[j] );

          /* adjust edges of top zone upward by twice darkening amount */
          flatFamilyEdge += 2 * font->darkenY;      /* bottom edge */

          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );

          if ( diff < minDiff && diff < csUnitsPerPixel )
          {
            blues->zone[i].csFlatEdge = flatFamilyEdge;
            minDiff                   = diff;

            if ( diff == 0 )
              break;
          }
        }
      }
    }

    /* TODO: enforce separation of zones, including BlueFuzz */

    /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */
    /* `bcsetup.c'.                                               */

    if ( maxZoneHeight > 0 )
    {
      if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ),
                                         maxZoneHeight ) )
      {
        /* clamp at maximum scale */
        blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ),
                                      maxZoneHeight );
      }

      /*
       * TODO: Revisit the bug fix for 613448.  The minimum scale
       *       requirement catches a number of library fonts.  For
       *       example, with default BlueScale (.039625) and 0.4 minimum,
       *       the test below catches any font with maxZoneHeight < 10.1.
       *       There are library fonts ranging from 2 to 10 that get
       *       caught, including e.g., Eurostile LT Std Medium with
       *       maxZoneHeight of 6.
       *
       */
#if 0
      if ( blueScale < .4 / maxZoneHeight )
      {
        tetraphilia_assert( 0 );
        /* clamp at minimum scale, per bug 0613448 fix */
        blueScale = .4 / maxZoneHeight;
      }
#endif

    }

    /*
     * Suppress overshoot and boost blue zones at small sizes.  Boost
     * amount varies linearly from 0.5 pixel near 0 to 0 pixel at
     * blueScale cutoff.
     * Note: This boost amount is different from the coretype heuristic.
     *
     */

    if ( blues->scale < blues->blueScale )
    {
      blues->suppressOvershoot = TRUE;

      /* Change rounding threshold for `dsFlatEdge'.                    */
      /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */
      /*       10ppem Arial                                             */

      blues->boost = cf2_doubleToFixed( .6 ) -
                       FT_MulDiv( cf2_doubleToFixed ( .6 ),
                                  blues->scale,
                                  blues->blueScale );
      if ( blues->boost > 0x7FFF )
      {
        /* boost must remain less than 0.5, or baseline could go negative */
        blues->boost = 0x7FFF;
      }
    }

    /* boost and darkening have similar effects; don't do both */
    if ( font->stemDarkened )
      blues->boost = 0;

    /* set device space alignment for each zone;    */
    /* apply boost amount before rounding flat edge */

    for ( i = 0; i < blues->count; i++ )
    {
      if ( blues->zone[i].bottomZone )
        blues->zone[i].dsFlatEdge = cf2_fixedRound(
                                      FT_MulFix(
                                        blues->zone[i].csFlatEdge,
                                        blues->scale ) -
                                      blues->boost );
      else
        blues->zone[i].dsFlatEdge = cf2_fixedRound(
                                      FT_MulFix(
                                        blues->zone[i].csFlatEdge,
                                        blues->scale ) +
                                      blues->boost );
    }
  }
Ejemplo n.º 16
0
  cff_face_init( FT_Stream      stream,
                 FT_Face        cffface,        /* CFF_Face */
                 FT_Int         face_index,
                 FT_Int         num_params,
                 FT_Parameter*  params )
  {
    CFF_Face            face        = (CFF_Face)cffface;
    FT_Error            error;
    SFNT_Service        sfnt;
    FT_Service_PsCMaps  psnames;
    PSHinter_Service    pshinter;
    FT_Bool             pure_cff    = 1;
    FT_Bool             sfnt_format = 0;
    FT_Library          library     = cffface->driver->root.library;


    sfnt = (SFNT_Service)FT_Get_Module_Interface(
             library, "sfnt" );
    if ( !sfnt )
    {
      FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" ));
      error = FT_THROW( Missing_Module );
      goto Exit;
    }

    FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );

    pshinter = (PSHinter_Service)FT_Get_Module_Interface(
                 library, "pshinter" );

    FT_TRACE2(( "CFF driver\n" ));

    /* create input stream from resource */
    if ( FT_STREAM_SEEK( 0 ) )
      goto Exit;

    /* check whether we have a valid OpenType file */
    error = sfnt->init_face( stream, face, face_index, num_params, params );
    if ( !error )
    {
      if ( face->format_tag != TTAG_OTTO )  /* `OTTO'; OpenType/CFF font */
      {
        FT_TRACE2(( "  not an OpenType/CFF font\n" ));
        error = FT_THROW( Unknown_File_Format );
        goto Exit;
      }

      /* if we are performing a simple font format check, exit immediately */
      if ( face_index < 0 )
        return FT_Err_Ok;

      sfnt_format = 1;

      /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
      /* font; in the latter case it doesn't have a `head' table         */
      error = face->goto_table( face, TTAG_head, stream, 0 );
      if ( !error )
      {
        pure_cff = 0;

        /* load font directory */
        error = sfnt->load_face( stream, face, face_index,
                                 num_params, params );
        if ( error )
          goto Exit;
      }
      else
      {
        /* load the `cmap' table explicitly */
        error = sfnt->load_cmap( face, stream );
        if ( error )
          goto Exit;
      }

      /* now load the CFF part of the file */
      error = face->goto_table( face, TTAG_CFF, stream, 0 );
      if ( error )
        goto Exit;
    }
    else
    {
      /* rewind to start of file; we are going to load a pure-CFF font */
      if ( FT_STREAM_SEEK( 0 ) )
        goto Exit;
      error = FT_Err_Ok;
    }

    /* now load and parse the CFF table in the file */
    {
      CFF_Font         cff = NULL;
      CFF_FontRecDict  dict;
      FT_Memory        memory = cffface->memory;
      FT_Int32         flags;
      FT_UInt          i;


      if ( FT_NEW( cff ) )
        goto Exit;

      face->extra.data = cff;
      error = cff_font_load( library, stream, face_index, cff, pure_cff );
      if ( error )
        goto Exit;

      cff->pshinter = pshinter;
      cff->psnames  = psnames;

      cffface->face_index = face_index;

      /* Complement the root flags with some interesting information. */
      /* Note that this is only necessary for pure CFF and CEF fonts; */
      /* SFNT based fonts use the `name' table instead.               */

      cffface->num_glyphs = cff->num_glyphs;

      dict = &cff->top_font.font_dict;

      /* we need the `PSNames' module for CFF and CEF formats */
      /* which aren't CID-keyed                               */
      if ( dict->cid_registry == 0xFFFFU && !psnames )
      {
        FT_ERROR(( "cff_face_init:"
                   " cannot open CFF & CEF fonts\n"
                   "              "
                   " without the `PSNames' module\n" ));
        error = FT_THROW( Missing_Module );
        goto Exit;
      }

#ifdef FT_DEBUG_LEVEL_TRACE
      {
        FT_UInt     idx;
        FT_String*  s;


        FT_TRACE4(( "SIDs\n" ));

        /* dump string index, including default strings for convenience */
        for ( idx = 0; idx < cff->num_strings + 390; idx++ )
        {
          s = cff_index_get_sid_string( cff, idx );
          if ( s )
            FT_TRACE4(("  %5d %s\n", idx, s ));
        }
      }
#endif /* FT_DEBUG_LEVEL_TRACE */

      if ( !dict->has_font_matrix )
        dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM;

      /* Normalize the font matrix so that `matrix->xx' is 1; the */
      /* scaling is done with `units_per_em' then (at this point, */
      /* it already contains the scaling factor, but without      */
      /* normalization of the matrix).                            */
      /*                                                          */
      /* Note that the offsets must be expressed in integer font  */
      /* units.                                                   */

      {
        FT_Matrix*  matrix = &dict->font_matrix;
        FT_Vector*  offset = &dict->font_offset;
        FT_ULong*   upm    = &dict->units_per_em;
        FT_Fixed    temp   = FT_ABS( matrix->yy );


        if ( temp != 0x10000L )
        {
          *upm = FT_DivFix( *upm, temp );

          matrix->xx = FT_DivFix( matrix->xx, temp );
          matrix->yx = FT_DivFix( matrix->yx, temp );
          matrix->xy = FT_DivFix( matrix->xy, temp );
          matrix->yy = FT_DivFix( matrix->yy, temp );
          offset->x  = FT_DivFix( offset->x,  temp );
          offset->y  = FT_DivFix( offset->y,  temp );
        }

        offset->x >>= 16;
        offset->y >>= 16;
      }

      for ( i = cff->num_subfonts; i > 0; i-- )
      {
        CFF_FontRecDict  sub = &cff->subfonts[i - 1]->font_dict;
        CFF_FontRecDict  top = &cff->top_font.font_dict;

        FT_Matrix*  matrix;
        FT_Vector*  offset;
        FT_ULong*   upm;
        FT_Fixed    temp;


        if ( sub->has_font_matrix )
        {
          FT_Long  scaling;


          /* if we have a top-level matrix, */
          /* concatenate the subfont matrix */

          if ( top->has_font_matrix )
          {
            if ( top->units_per_em > 1 && sub->units_per_em > 1 )
              scaling = FT_MIN( top->units_per_em, sub->units_per_em );
            else
              scaling = 1;

            FT_Matrix_Multiply_Scaled( &top->font_matrix,
                                       &sub->font_matrix,
                                       scaling );
            FT_Vector_Transform_Scaled( &sub->font_offset,
                                        &top->font_matrix,
                                        scaling );

            sub->units_per_em = FT_MulDiv( sub->units_per_em,
                                           top->units_per_em,
                                           scaling );
          }
        }
        else
        {
          sub->font_matrix = top->font_matrix;
          sub->font_offset = top->font_offset;

          sub->units_per_em = top->units_per_em;
        }

        matrix = &sub->font_matrix;
        offset = &sub->font_offset;
        upm    = &sub->units_per_em;
        temp   = FT_ABS( matrix->yy );

        if ( temp != 0x10000L )
        {
          *upm = FT_DivFix( *upm, temp );

          matrix->xx = FT_DivFix( matrix->xx, temp );
          matrix->yx = FT_DivFix( matrix->yx, temp );
          matrix->xy = FT_DivFix( matrix->xy, temp );
          matrix->yy = FT_DivFix( matrix->yy, temp );
          offset->x  = FT_DivFix( offset->x,  temp );
          offset->y  = FT_DivFix( offset->y,  temp );
        }

        offset->x >>= 16;
        offset->y >>= 16;
      }

      if ( pure_cff )
      {
        char*  style_name = NULL;


        /* set up num_faces */
        cffface->num_faces = cff->num_faces;

        /* compute number of glyphs */
        if ( dict->cid_registry != 0xFFFFU )
          cffface->num_glyphs = cff->charset.max_cid + 1;
        else
          cffface->num_glyphs = cff->charstrings_index.count;

        /* set global bbox, as well as EM size */
        cffface->bbox.xMin =   dict->font_bbox.xMin            >> 16;
        cffface->bbox.yMin =   dict->font_bbox.yMin            >> 16;
        /* no `U' suffix here to 0xFFFF! */
        cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16;
        cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16;

        cffface->units_per_EM = (FT_UShort)( dict->units_per_em );

        cffface->ascender  = (FT_Short)( cffface->bbox.yMax );
        cffface->descender = (FT_Short)( cffface->bbox.yMin );

        cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 );
        if ( cffface->height < cffface->ascender - cffface->descender )
          cffface->height = (FT_Short)( cffface->ascender - cffface->descender );

        cffface->underline_position  =
          (FT_Short)( dict->underline_position >> 16 );
        cffface->underline_thickness =
          (FT_Short)( dict->underline_thickness >> 16 );

        /* retrieve font family & style name */
        cffface->family_name = cff_index_get_name( cff, face_index );
        if ( cffface->family_name )
        {
          char*  full   = cff_index_get_sid_string( cff,
                                                    dict->full_name );
          char*  fullp  = full;
          char*  family = cffface->family_name;
          char*  family_name = NULL;


          remove_subset_prefix( cffface->family_name );

          if ( dict->family_name )
          {
            family_name = cff_index_get_sid_string( cff,
                                                    dict->family_name );
            if ( family_name )
              family = family_name;
          }

          /* We try to extract the style name from the full name.   */
          /* We need to ignore spaces and dashes during the search. */
          if ( full && family )
          {
            while ( *fullp )
            {
              /* skip common characters at the start of both strings */
              if ( *fullp == *family )
              {
                family++;
                fullp++;
                continue;
              }

              /* ignore spaces and dashes in full name during comparison */
              if ( *fullp == ' ' || *fullp == '-' )
              {
                fullp++;
                continue;
              }

              /* ignore spaces and dashes in family name during comparison */
              if ( *family == ' ' || *family == '-' )
              {
                family++;
                continue;
              }

              if ( !*family && *fullp )
              {
                /* The full name begins with the same characters as the  */
                /* family name, with spaces and dashes removed.  In this */
                /* case, the remaining string in `fullp' will be used as */
                /* the style name.                                       */
                style_name = cff_strcpy( memory, fullp );

                /* remove the style part from the family name (if present) */
                remove_style( cffface->family_name, style_name );
              }
              break;
            }
          }
        }
        else
        {
          char  *cid_font_name =
                   cff_index_get_sid_string( cff,
                                             dict->cid_font_name );


          /* do we have a `/FontName' for a CID-keyed font? */
          if ( cid_font_name )
            cffface->family_name = cff_strcpy( memory, cid_font_name );
        }

        if ( style_name )
          cffface->style_name = style_name;
        else
          /* assume "Regular" style if we don't know better */
          cffface->style_name = cff_strcpy( memory, (char *)"Regular" );

        /*******************************************************************/
        /*                                                                 */
        /* Compute face flags.                                             */
        /*                                                                 */
        flags = FT_FACE_FLAG_SCALABLE   | /* scalable outlines */
                FT_FACE_FLAG_HORIZONTAL | /* horizontal data   */
                FT_FACE_FLAG_HINTER;      /* has native hinter */

        if ( sfnt_format )
          flags |= FT_FACE_FLAG_SFNT;

        /* fixed width font? */
        if ( dict->is_fixed_pitch )
          flags |= FT_FACE_FLAG_FIXED_WIDTH;

  /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
#if 0
        /* kerning available? */
        if ( face->kern_pairs )
          flags |= FT_FACE_FLAG_KERNING;
#endif

        cffface->face_flags |= flags;

        /*******************************************************************/
        /*                                                                 */
        /* Compute style flags.                                            */
        /*                                                                 */
        flags = 0;

        if ( dict->italic_angle )
          flags |= FT_STYLE_FLAG_ITALIC;

        {
          char  *weight = cff_index_get_sid_string( cff,
                                                    dict->weight );


          if ( weight )
            if ( !ft_strcmp( weight, "Bold"  ) ||
                 !ft_strcmp( weight, "Black" ) )
              flags |= FT_STYLE_FLAG_BOLD;
        }

        /* double check */
        if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name )
          if ( !ft_strncmp( cffface->style_name, "Bold", 4 )  ||
               !ft_strncmp( cffface->style_name, "Black", 5 ) )
            flags |= FT_STYLE_FLAG_BOLD;

        cffface->style_flags = flags;
      }


#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
      /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
      /* has unset this flag because of the 3.0 `post' table.          */
      if ( dict->cid_registry == 0xFFFFU )
        cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
#endif

      if ( dict->cid_registry != 0xFFFFU && pure_cff )
        cffface->face_flags |= FT_FACE_FLAG_CID_KEYED;


      /*******************************************************************/
      /*                                                                 */
      /* Compute char maps.                                              */
      /*                                                                 */

      /* Try to synthesize a Unicode charmap if there is none available */
      /* already.  If an OpenType font contains a Unicode "cmap", we    */
      /* will use it, whatever be in the CFF part of the file.          */
      {
        FT_CharMapRec  cmaprec;
        FT_CharMap     cmap;
        FT_UInt        nn;
        CFF_Encoding   encoding = &cff->encoding;


        for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ )
        {
          cmap = cffface->charmaps[nn];

          /* Windows Unicode? */
          if ( cmap->platform_id == TT_PLATFORM_MICROSOFT &&
               cmap->encoding_id == TT_MS_ID_UNICODE_CS   )
            goto Skip_Unicode;

          /* Apple Unicode platform id? */
          if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE )
            goto Skip_Unicode; /* Apple Unicode */
        }

        /* since CID-keyed fonts don't contain glyph names, we can't */
        /* construct a cmap                                          */
        if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU )
          goto Exit;

#ifdef FT_MAX_CHARMAP_CACHEABLE
        if ( nn + 1 > FT_MAX_CHARMAP_CACHEABLE )
        {
          FT_ERROR(( "cff_face_init: no Unicode cmap is found, "
                     "and too many subtables (%d) to add synthesized cmap\n",
                     nn ));
          goto Exit;
        }
#endif

        /* we didn't find a Unicode charmap -- synthesize one */
        cmaprec.face        = cffface;
        cmaprec.platform_id = TT_PLATFORM_MICROSOFT;
        cmaprec.encoding_id = TT_MS_ID_UNICODE_CS;
        cmaprec.encoding    = FT_ENCODING_UNICODE;

        nn = (FT_UInt)cffface->num_charmaps;

        error = FT_CMap_New( &CFF_CMAP_UNICODE_CLASS_REC_GET, NULL,
                             &cmaprec, NULL );
        if ( error                                      &&
             FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) )
          goto Exit;
        error = FT_Err_Ok;

        /* if no Unicode charmap was previously selected, select this one */
        if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps )
          cffface->charmap = cffface->charmaps[nn];

      Skip_Unicode:
#ifdef FT_MAX_CHARMAP_CACHEABLE
        if ( nn > FT_MAX_CHARMAP_CACHEABLE )
        {
          FT_ERROR(( "cff_face_init: Unicode cmap is found, "
                     "but too many preceding subtables (%d) to access\n",
                     nn - 1 ));
          goto Exit;
        }
#endif
        if ( encoding->count > 0 )
        {
          FT_CMap_Class  clazz;


          cmaprec.face        = cffface;
          cmaprec.platform_id = TT_PLATFORM_ADOBE;  /* Adobe platform id */

          if ( encoding->offset == 0 )
          {
            cmaprec.encoding_id = TT_ADOBE_ID_STANDARD;
            cmaprec.encoding    = FT_ENCODING_ADOBE_STANDARD;
            clazz               = &CFF_CMAP_ENCODING_CLASS_REC_GET;
          }
          else if ( encoding->offset == 1 )
          {
            cmaprec.encoding_id = TT_ADOBE_ID_EXPERT;
            cmaprec.encoding    = FT_ENCODING_ADOBE_EXPERT;
            clazz               = &CFF_CMAP_ENCODING_CLASS_REC_GET;
          }
          else
          {
            cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM;
            cmaprec.encoding    = FT_ENCODING_ADOBE_CUSTOM;
            clazz               = &CFF_CMAP_ENCODING_CLASS_REC_GET;
          }

          error = FT_CMap_New( clazz, NULL, &cmaprec, NULL );
        }
      }
    }

  Exit:
    return error;
  }
Ejemplo n.º 17
0
Archivo: pfrobjs.c Proyecto: 8l/inferno
  pfr_slot_load( PFR_Slot  slot,
                 PFR_Size  size,
                 FT_UInt   gindex,
                 FT_Int32  load_flags )
  {
    FT_Error     error;
    PFR_Face     face    = (PFR_Face)slot->root.face;
    PFR_Char     gchar;
    FT_Outline*  outline = &slot->root.outline;
    FT_ULong     gps_offset;

    if (gindex > 0)
      gindex--;

    /* check that the glyph index is correct */
    FT_ASSERT( gindex < face->phy_font.num_chars );

    /* try to load an embedded bitmap */
    if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
    {
      error = pfr_slot_load_bitmap( slot, size, gindex );
      if ( error == 0 )
        goto Exit;
    }

    gchar               = face->phy_font.chars + gindex;
    slot->root.format   = FT_GLYPH_FORMAT_OUTLINE;
    outline->n_points   = 0;
    outline->n_contours = 0;
    gps_offset          = face->header.gps_section_offset;

    /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
    error = pfr_glyph_load( &slot->glyph, face->root.stream,
                            gps_offset, gchar->gps_offset, gchar->gps_size );

    if ( !error )
    {
      FT_BBox            cbox;
      FT_Glyph_Metrics*  metrics = &slot->root.metrics;
      FT_Pos             advance;
      FT_Int             em_metrics, em_outline;
      FT_Bool            scaling;


      scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );

      /* copy outline data */
      *outline = slot->glyph.loader->base.outline;

      outline->flags &= ~FT_OUTLINE_OWNER;
      outline->flags |= FT_OUTLINE_REVERSE_FILL;

      if ( size && size->root.metrics.y_ppem < 24 )
        outline->flags |= FT_OUTLINE_HIGH_PRECISION;

      /* compute the advance vector */
      metrics->horiAdvance = 0;
      metrics->vertAdvance = 0;

      advance    = gchar->advance;
      em_metrics = face->phy_font.metrics_resolution;
      em_outline = face->phy_font.outline_resolution;

      if ( em_metrics != em_outline )
        advance = FT_MulDiv( advance, em_outline, em_metrics );

      if ( face->phy_font.flags & PFR_PHY_VERTICAL )
        metrics->vertAdvance = advance;
      else
        metrics->horiAdvance = advance;

      slot->root.linearHoriAdvance = metrics->horiAdvance;
      slot->root.linearVertAdvance = metrics->vertAdvance;

      /* make-up vertical metrics(?) */
      metrics->vertBearingX = 0;
      metrics->vertBearingY = 0;

      /* scale when needed */
      if ( scaling )
      {
        FT_Int      n;
        FT_Fixed    x_scale = size->root.metrics.x_scale;
        FT_Fixed    y_scale = size->root.metrics.y_scale;
        FT_Vector*  vec     = outline->points;


        /* scale outline points */
        for ( n = 0; n < outline->n_points; n++, vec++ )
        {
          vec->x = FT_MulFix( vec->x, x_scale );
          vec->y = FT_MulFix( vec->y, y_scale );
        }

        /* scale the advance */
        metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
        metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
      }

      /* compute the rest of the metrics */
      FT_Outline_Get_CBox( outline, &cbox );

      metrics->width        = cbox.xMax - cbox.xMin;
      metrics->height       = cbox.yMax - cbox.yMin;
      metrics->horiBearingX = cbox.xMin;
      metrics->horiBearingY = cbox.yMax - metrics->height;
    }

  Exit:
    return error;
  }
Ejemplo n.º 18
0
  /* Compute a stem darkening amount in character space. */
  static void
  cf2_computeDarkening( CF2_Fixed   emRatio,
                        CF2_Fixed   ppem,
                        CF2_Fixed   stemWidth,
                        CF2_Fixed*  darkenAmount,
                        CF2_Fixed   boldenAmount,
                        FT_Bool     stemDarkened,
                        FT_Int*     darkenParams )
  {
    /*
     * Total darkening amount is computed in 1000 unit character space
     * using the modified 5 part curve as Adobe's Avalon rasterizer.
     * The darkening amount is smaller for thicker stems.
     * It becomes zero when the stem is thicker than 2.333 pixels.
     *
     * By default, we use
     *
     *   darkenAmount = 0.4 pixels   if scaledStem <= 0.5 pixels,
     *   darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
     *   darkenAmount = 0 pixel      if scaledStem >= 2.333 pixels,
     *
     * and piecewise linear in-between:
     *
     *
     *   darkening
     *       ^
     *       |
     *       |      (x1,y1)
     *       |--------+
     *       |         \
     *       |          \
     *       |           \          (x3,y3)
     *       |            +----------+
     *       |        (x2,y2)         \
     *       |                         \
     *       |                          \
     *       |                           +-----------------
     *       |                         (x4,y4)
     *       +--------------------------------------------->   stem
     *                                                       thickness
     *
     *
     * This corresponds to the following values for the
     * `darkening-parameters' property:
     *
     *   (x1, y1) = (500, 400)
     *   (x2, y2) = (1000, 275)
     *   (x3, y3) = (1667, 275)
     *   (x4, y4) = (2333, 0)
     *
     */

    /* Internal calculations are done in units per thousand for */
    /* convenience. The x axis is scaled stem width in          */
    /* thousandths of a pixel. That is, 1000 is 1 pixel.        */
    /* The y axis is darkening amount in thousandths of a pixel.*/
    /* In the code, below, dividing by ppem and                 */
    /* adjusting for emRatio converts darkenAmount to character */
    /* space (font units).                                      */
    CF2_Fixed  stemWidthPer1000, scaledStem;
    FT_Int     logBase2;


    *darkenAmount = 0;

    if ( boldenAmount == 0 && !stemDarkened )
      return;

    /* protect against range problems and divide by zero */
    if ( emRatio < cf2_floatToFixed( .01 ) )
      return;

    if ( stemDarkened )
    {
      FT_Int  x1 = darkenParams[0];
      FT_Int  y1 = darkenParams[1];
      FT_Int  x2 = darkenParams[2];
      FT_Int  y2 = darkenParams[3];
      FT_Int  x3 = darkenParams[4];
      FT_Int  y3 = darkenParams[5];
      FT_Int  x4 = darkenParams[6];
      FT_Int  y4 = darkenParams[7];


      /* convert from true character space to 1000 unit character space; */
      /* add synthetic emboldening effect                                */

      /* `stemWidthPer1000' will not overflow for a legitimate font      */

      stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio );

      /* `scaledStem' can easily overflow, so we must clamp its maximum  */
      /* value; the test doesn't need to be precise, but must be         */
      /* conservative.  The clamp value (default 2333) where             */
      /* `darkenAmount' is zero is well below the overflow value of      */
      /* 32767.                                                          */
      /*                                                                 */
      /* FT_MSB computes the integer part of the base 2 logarithm.  The  */
      /* number of bits for the product is 1 or 2 more than the sum of   */
      /* logarithms; remembering that the 16 lowest bits of the fraction */
      /* are dropped this is correct to within a factor of almost 4.     */
      /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and   */
      /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */
      /* 0xFFFF.FE00 is also 23+23.                                      */

      logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) +
                   FT_MSB( (FT_UInt32)ppem );

      if ( logBase2 >= 46 )
        /* possible overflow */
        scaledStem = cf2_intToFixed( x4 );
      else
        scaledStem = FT_MulFix( stemWidthPer1000, ppem );

      /* now apply the darkening parameters */

      if ( scaledStem < cf2_intToFixed( x1 ) )
        *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem );

      else if ( scaledStem < cf2_intToFixed( x2 ) )
      {
        FT_Int  xdelta = x2 - x1;
        FT_Int  ydelta = y2 - y1;
        FT_Int  x      = stemWidthPer1000 -
                           FT_DivFix( cf2_intToFixed( x1 ), ppem );


        if ( !xdelta )
          goto Try_x3;

        *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
                          FT_DivFix( cf2_intToFixed( y1 ), ppem );
      }

      else if ( scaledStem < cf2_intToFixed( x3 ) )
      {
      Try_x3:
        {
          FT_Int  xdelta = x3 - x2;
          FT_Int  ydelta = y3 - y2;
          FT_Int  x      = stemWidthPer1000 -
                             FT_DivFix( cf2_intToFixed( x2 ), ppem );


          if ( !xdelta )
            goto Try_x4;

          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
                            FT_DivFix( cf2_intToFixed( y2 ), ppem );
        }
      }

      else if ( scaledStem < cf2_intToFixed( x4 ) )
      {
      Try_x4:
        {
          FT_Int  xdelta = x4 - x3;
          FT_Int  ydelta = y4 - y3;
          FT_Int  x      = stemWidthPer1000 -
                             FT_DivFix( cf2_intToFixed( x3 ), ppem );


          if ( !xdelta )
            goto Use_y4;

          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
                            FT_DivFix( cf2_intToFixed( y3 ), ppem );
        }
      }

      else
      {
      Use_y4:
        *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem );
      }

      /* use half the amount on each side and convert back to true */
      /* character space                                           */
      *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio );
    }

    /* add synthetic emboldening effect in character space */
    *darkenAmount += boldenAmount / 2;
  }
Ejemplo n.º 19
0
  static void
  af_cjk_hint_edges( AF_GlyphHints  hints,
                     AF_Dimension   dim )
  {
    AF_AxisHints  axis       = &hints->axis[dim];
    AF_Edge       edges      = axis->edges;
    AF_Edge       edge_limit = edges + axis->num_edges;
    FT_Int        n_edges;
    AF_Edge       edge;
    AF_Edge       anchor   = 0;
    FT_Pos        delta    = 0;
    FT_Int        skipped  = 0;


    /* now we align all stem edges. */
    for ( edge = edges; edge < edge_limit; edge++ )
    {
      AF_Edge  edge2;


      if ( edge->flags & AF_EDGE_DONE )
        continue;

      /* skip all non-stem edges */
      edge2 = edge->link;
      if ( !edge2 )
      {
        skipped++;
        continue;
      }

      /* now align the stem */

      if ( edge2 < edge )
      {
        af_cjk_align_linked_edge( hints, dim, edge2, edge );
        edge->flags |= AF_EDGE_DONE;
        continue;
      }

      if ( dim != AF_DIMENSION_VERT && !anchor )
      {

#if 0
        if ( fixedpitch )
        {
          AF_Edge     left  = edge;
          AF_Edge     right = edge_limit - 1;
          AF_EdgeRec  left1, left2, right1, right2;
          FT_Pos      target, center1, center2;
          FT_Pos      delta1, delta2, d1, d2;


          while ( right > left && !right->link )
            right--;

          left1  = *left;
          left2  = *left->link;
          right1 = *right->link;
          right2 = *right;

          delta  = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
          target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;

          delta1  = delta;
          delta1 += af_hint_normal_stem( hints, left, left->link,
                                         delta1, 0 );

          if ( left->link != right )
            af_hint_normal_stem( hints, right->link, right, delta1, 0 );

          center1 = left->pos + ( right->pos - left->pos ) / 2;

          if ( center1 >= target )
            delta2 = delta - 32;
          else
            delta2 = delta + 32;

          delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );

          if ( delta1 != delta2 )
          {
            if ( left->link != right )
              af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );

            center2 = left1.pos + ( right2.pos - left1.pos ) / 2;

            d1 = center1 - target;
            d2 = center2 - target;

            if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
            {
              left->pos       = left1.pos;
              left->link->pos = left2.pos;

              if ( left->link != right )
              {
                right->link->pos = right1.pos;
                right->pos       = right2.pos;
              }

              delta1 = delta2;
            }
          }

          delta               = delta1;
          right->link->flags |= AF_EDGE_DONE;
          right->flags       |= AF_EDGE_DONE;
        }
        else

#endif /* 0 */

          delta = af_hint_normal_stem( hints, edge, edge2, 0,
                                       AF_DIMENSION_HORZ );
      }
      else
        af_hint_normal_stem( hints, edge, edge2, delta, dim );

#if 0
      FT_PRINTF( "stem (%d,%d) adjusted (%.1f,%.1f)\n",
               edge - edges, edge2 - edges,
               ( edge->pos - edge->opos ) / 64.0,
               ( edge2->pos - edge2->opos ) / 64.0 );
#endif

      anchor = edge;
      edge->flags  |= AF_EDGE_DONE;
      edge2->flags |= AF_EDGE_DONE;
    }

    /* make sure that lowercase m's maintain their symmetry */

    /* In general, lowercase m's have six vertical edges if they are sans */
    /* serif, or twelve if they are with serifs.  This implementation is  */
    /* based on that assumption, and seems to work very well with most    */
    /* faces.  However, if for a certain face this assumption is not      */
    /* true, the m is just rendered like before.  In addition, any stem   */
    /* correction will only be applied to symmetrical glyphs (even if the */
    /* glyph is not an m), so the potential for unwanted distortion is    */
    /* relatively low.                                                    */

    /* We don't handle horizontal edges since we can't easily assure that */
    /* the third (lowest) stem aligns with the base line; it might end up */
    /* one pixel higher or lower.                                         */

    n_edges = edge_limit - edges;
    if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
    {
      AF_Edge  edge1, edge2, edge3;
      FT_Pos   dist1, dist2, span;


      if ( n_edges == 6 )
      {
        edge1 = edges;
        edge2 = edges + 2;
        edge3 = edges + 4;
      }
      else
      {
        edge1 = edges + 1;
        edge2 = edges + 5;
        edge3 = edges + 9;
      }

      dist1 = edge2->opos - edge1->opos;
      dist2 = edge3->opos - edge2->opos;

      span = dist1 - dist2;
      if ( span < 0 )
        span = -span;

      if ( edge1->link == edge1 + 1 &&
           edge2->link == edge2 + 1 &&
           edge3->link == edge3 + 1 && span < 8 )
      {
        delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
        edge3->pos -= delta;
        if ( edge3->link )
          edge3->link->pos -= delta;

        /* move the serifs along with the stem */
        if ( n_edges == 12 )
        {
          ( edges + 8 )->pos -= delta;
          ( edges + 11 )->pos -= delta;
        }

        edge3->flags |= AF_EDGE_DONE;
        if ( edge3->link )
          edge3->link->flags |= AF_EDGE_DONE;
      }
    }

    if ( !skipped )
      return;

    /*
     *  now hint the remaining edges (serifs and single) in order
     *  to complete our processing
     */
    for ( edge = edges; edge < edge_limit; edge++ )
    {
      if ( edge->flags & AF_EDGE_DONE )
        continue;

      if ( edge->serif )
      {
        af_cjk_align_serif_edge( hints, edge->serif, edge );
        edge->flags |= AF_EDGE_DONE;
        skipped--;
      }
    }

    if ( !skipped )
      return;

    for ( edge = edges; edge < edge_limit; edge++ )
    {
      AF_Edge  before, after;


      if ( edge->flags & AF_EDGE_DONE )
        continue;

      before = after = edge;

      while ( --before >= edges )
        if ( before->flags & AF_EDGE_DONE )
          break;

      while ( ++after < edge_limit )
        if ( after->flags & AF_EDGE_DONE )
          break;

      if ( before >= edges || after < edge_limit )
      {
        if ( before < edges )
          af_cjk_align_serif_edge( hints, after, edge );
        else if ( after >= edge_limit )
          af_cjk_align_serif_edge( hints, before, edge );
        else
        {
          if ( after->fpos == before->fpos )
            edge->pos = before->pos;
          else
            edge->pos = before->pos +
                        FT_MulDiv( edge->fpos - before->fpos,
                                   after->pos - before->pos,
                                   after->fpos - before->fpos );
        }
      }
    }
  }
Ejemplo n.º 20
0
  af_loader_compute_darkening( AF_Loader  loader,
                               FT_Face    face,
                               FT_Pos     standard_width )
  {
    AF_Module  module = loader->globals->module;

    FT_UShort  units_per_EM;
    FT_Fixed   ppem, em_ratio;
    FT_Fixed   stem_width, stem_width_per_1000, scaled_stem, darken_amount;
    FT_Int     log_base_2;
    FT_Int     x1, y1, x2, y2, x3, y3, x4, y4;


    ppem         = FT_MAX( af_intToFixed( 4 ),
                           af_intToFixed( face->size->metrics.x_ppem ) );
    units_per_EM = face->units_per_EM;

    em_ratio = FT_DivFix( af_intToFixed( 1000 ),
                          af_intToFixed ( units_per_EM ) );
    if ( em_ratio < af_floatToFixed( .01 ) )
    {
      /* If something goes wrong, don't embolden. */
      return 0;
    }

    x1 = module->darken_params[0];
    y1 = module->darken_params[1];
    x2 = module->darken_params[2];
    y2 = module->darken_params[3];
    x3 = module->darken_params[4];
    y3 = module->darken_params[5];
    x4 = module->darken_params[6];
    y4 = module->darken_params[7];

    if ( standard_width <= 0 )
    {
      stem_width          = af_intToFixed( 75 ); /* taken from cf2font.c */
      stem_width_per_1000 = stem_width;
    }
    else
    {
      stem_width          = af_intToFixed( standard_width );
      stem_width_per_1000 = FT_MulFix( stem_width, em_ratio );
    }

    log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) +
                 FT_MSB( (FT_UInt32)ppem );

    if ( log_base_2 >= 46 )
    {
      /* possible overflow */
      scaled_stem = af_intToFixed( x4 );
    }
    else
      scaled_stem = FT_MulFix( stem_width_per_1000, ppem );

    /* now apply the darkening parameters */
    if ( scaled_stem < af_intToFixed( x1 ) )
      darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem );

    else if ( scaled_stem < af_intToFixed( x2 ) )
    {
      FT_Int  xdelta = x2 - x1;
      FT_Int  ydelta = y2 - y1;
      FT_Int  x      = stem_width_per_1000 -
                       FT_DivFix( af_intToFixed( x1 ), ppem );


      if ( !xdelta )
        goto Try_x3;

      darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
                      FT_DivFix( af_intToFixed( y1 ), ppem );
    }

    else if ( scaled_stem < af_intToFixed( x3 ) )
    {
    Try_x3:
      {
        FT_Int  xdelta = x3 - x2;
        FT_Int  ydelta = y3 - y2;
        FT_Int  x      = stem_width_per_1000 -
                         FT_DivFix( af_intToFixed( x2 ), ppem );


        if ( !xdelta )
          goto Try_x4;

        darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
                        FT_DivFix( af_intToFixed( y2 ), ppem );
      }
    }

    else if ( scaled_stem < af_intToFixed( x4 ) )
    {
    Try_x4:
      {
        FT_Int  xdelta = x4 - x3;
        FT_Int  ydelta = y4 - y3;
        FT_Int  x      = stem_width_per_1000 -
                         FT_DivFix( af_intToFixed( x3 ), ppem );


        if ( !xdelta )
          goto Use_y4;

        darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
                        FT_DivFix( af_intToFixed( y3 ), ppem );
      }
    }

    else
    {
    Use_y4:
      darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem );
    }

    /* Convert darken_amount from per 1000 em to true character space. */
    return af_fixedToInt( FT_DivFix( darken_amount, em_ratio ) );
  }
Ejemplo n.º 21
0
  tt_size_reset( TT_Size  size )
  {
    TT_Face           face;
    FT_Error          error = TT_Err_Ok;
    FT_Size_Metrics*  metrics;


    size->ttmetrics.valid = FALSE;

    face = (TT_Face)size->root.face;

    metrics = &size->metrics;

    /* copy the result from base layer */
    *metrics = size->root.metrics;

    if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 )
      return TT_Err_Invalid_PPem;

    /* This bit flag, if set, indicates that the ppems must be       */
    /* rounded to integers.  Nearly all TrueType fonts have this bit */
    /* set, as hinting won't work really well otherwise.             */
    /*                                                               */
    if ( face->header.Flags & 8 )
    {
      metrics->x_scale = FT_DivFix( metrics->x_ppem << 6,
                                    face->root.units_per_EM );
      metrics->y_scale = FT_DivFix( metrics->y_ppem << 6,
                                    face->root.units_per_EM );

      metrics->ascender =
        FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) );
      metrics->descender =
        FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) );
      metrics->height =
        FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) );
      metrics->max_advance =
        FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width,
                                 metrics->x_scale ) );
    }

    /* compute new transformation */
    if ( metrics->x_ppem >= metrics->y_ppem )
    {
      size->ttmetrics.scale   = metrics->x_scale;
      size->ttmetrics.ppem    = metrics->x_ppem;
      size->ttmetrics.x_ratio = 0x10000L;
      size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem,
                                           0x10000L,
                                           metrics->x_ppem );
    }
    else
    {
      size->ttmetrics.scale   = metrics->y_scale;
      size->ttmetrics.ppem    = metrics->y_ppem;
      size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem,
                                           0x10000L,
                                           metrics->y_ppem );
      size->ttmetrics.y_ratio = 0x10000L;
    }


#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

    {
      FT_UInt  i;


      /* Scale the cvt values to the new ppem.          */
      /* We use by default the y ppem to scale the CVT. */
      for ( i = 0; i < size->cvt_size; i++ )
        size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );

      /* All twilight points are originally zero */
      for ( i = 0; i < (FT_UInt)size->twilight.n_points; i++ )
      {
        size->twilight.org[i].x = 0;
        size->twilight.org[i].y = 0;
        size->twilight.cur[i].x = 0;
        size->twilight.cur[i].y = 0;
      }

      /* clear storage area */
      for ( i = 0; i < (FT_UInt)size->storage_size; i++ )
        size->storage[i] = 0;

      size->GS = tt_default_graphics_state;

      error = tt_size_run_prep( size );
    }

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    if ( !error )
      size->ttmetrics.valid = TRUE;

    return error;
  }
Ejemplo n.º 22
0
  FT_Outline_EmboldenXY( FT_Outline*  outline,
                         FT_Pos       xstrength,
                         FT_Pos       ystrength )
  {
    FT_Vector*  points;
    FT_Int      c, first, last;
    FT_Int      orientation;


    if ( !outline )
      return FT_THROW( Invalid_Outline );

    xstrength /= 2;
    ystrength /= 2;
    if ( xstrength == 0 && ystrength == 0 )
      return FT_Err_Ok;

    orientation = FT_Outline_Get_Orientation( outline );
    if ( orientation == FT_ORIENTATION_NONE )
    {
      if ( outline->n_contours )
        return FT_THROW( Invalid_Argument );
      else
        return FT_Err_Ok;
    }

    points = outline->points;

    first = 0;
    for ( c = 0; c < outline->n_contours; c++ )
    {
      FT_Vector  in, out, anchor, shift;
      FT_Fixed   l_in, l_out, l_anchor = 0, l, q, d;
      FT_Int     i, j, k;


      l_in = 0;
      last = outline->contours[c];

      /* pacify compiler */
      in.x = in.y = anchor.x = anchor.y = 0;

      /* Counter j cycles though the points; counter i advances only  */
      /* when points are moved; anchor k marks the first moved point. */
      for ( i = last, j = first, k = -1;
            j != i && i != k;
            j = j < last ? j + 1 : first )
      {
        if ( j != k )
        {
          out.x = points[j].x - points[i].x;
          out.y = points[j].y - points[i].y;
          l_out = (FT_Fixed)FT_Vector_NormLen( &out );

          if ( l_out == 0 )
            continue;
        }
        else
        {
          out   = anchor;
          l_out = l_anchor;
        }

        if ( l_in != 0 )
        {
          if ( k < 0 )
          {
            k        = i;
            anchor   = in;
            l_anchor = l_in;
          }

          d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );

          /* shift only if turn is less than ~160 degrees */
          if ( d > -0xF000L )
          {
            d = d + 0x10000L;

            /* shift components along lateral bisector in proper orientation */
            shift.x = in.y + out.y;
            shift.y = in.x + out.x;

            if ( orientation == FT_ORIENTATION_TRUETYPE )
              shift.x = -shift.x;
            else
              shift.y = -shift.y;

            /* restrict shift magnitude to better handle collapsing segments */
            q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x );
            if ( orientation == FT_ORIENTATION_TRUETYPE )
              q = -q;

            l = FT_MIN( l_in, l_out );

            /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
            if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) )
              shift.x = FT_MulDiv( shift.x, xstrength, d );
            else
              shift.x = FT_MulDiv( shift.x, l, q );


            if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) )
              shift.y = FT_MulDiv( shift.y, ystrength, d );
            else
              shift.y = FT_MulDiv( shift.y, l, q );
          }
          else
            shift.x = shift.y = 0;

          for ( ;
                i != j;
                i = i < last ? i + 1 : first )
          {
            points[i].x += xstrength + shift.x;
            points[i].y += ystrength + shift.y;
          }
        }
        else
          i = j;

        in   = out;
        l_in = l_out;
      }

      first = last + 1;
    }

    return FT_Err_Ok;
  }
Ejemplo n.º 23
0
  FT_Outline_EmboldenXY( FT_Outline*  outline,
                         FT_Pos       xstrength,
                         FT_Pos       ystrength )
  {
    FT_Vector*  points;
    FT_Vector   v_prev, v_first, v_next, v_cur;
    FT_Int      c, n, first;
    FT_Int      orientation;


    if ( !outline )
      return FT_Err_Invalid_Argument;

    xstrength /= 2;
    ystrength /= 2;
    if ( xstrength == 0 && ystrength == 0 )
      return FT_Err_Ok;

    orientation = FT_Outline_Get_Orientation( outline );
    if ( orientation == FT_ORIENTATION_NONE )
    {
      if ( outline->n_contours )
        return FT_Err_Invalid_Argument;
      else
        return FT_Err_Ok;
    }

    points = outline->points;

    first = 0;
    for ( c = 0; c < outline->n_contours; c++ )
    {
      FT_Vector  in, out, shift;
      FT_Fixed   l_in, l_out, l, q, d;
      int        last = outline->contours[c];


      v_first = points[first];
      v_prev  = points[last];
      v_cur   = v_first;

      /* compute the incoming vector and its length */
      in.x = v_cur.x - v_prev.x;
      in.y = v_cur.y - v_prev.y;
      l_in = FT_Vector_Length( &in );

      for ( n = first; n <= last; n++ )
      {
        if ( n < last )
          v_next = points[n + 1];
        else
          v_next = v_first;

        /* compute the outgoing vector and its length */
        out.x = v_next.x - v_cur.x;
        out.y = v_next.y - v_cur.y;
        l_out = FT_Vector_Length( &out );

        d = l_in * l_out + in.x * out.x + in.y * out.y;

        /* shift only if turn is less then ~160 degrees */
        if ( 16 * d > l_in * l_out )
        {
          /* shift components are aligned along bisector        */
          /* and directed according to the outline orientation. */
          shift.x = l_out * in.y + l_in * out.y;
          shift.y = l_out * in.x + l_in * out.x;

          if ( orientation == FT_ORIENTATION_TRUETYPE )
            shift.x = -shift.x;
          else
            shift.y = -shift.y;

          /* threshold strength to better handle collapsing segments */
          l = FT_MIN( l_in, l_out );
          q = out.x * in.y - out.y * in.x;
          if ( orientation == FT_ORIENTATION_TRUETYPE )
            q = -q;

          if ( FT_MulDiv( xstrength, q, l ) < d )
            shift.x = FT_MulDiv( shift.x, xstrength, d );
          else
            shift.x = FT_MulDiv( shift.x, l, q );

          
          if ( FT_MulDiv( ystrength, q, l ) < d )
            shift.y = FT_MulDiv( shift.y, ystrength, d );
          else
            shift.y = FT_MulDiv( shift.y, l, q );
        }
        else
          shift.x = shift.y = 0;

        outline->points[n].x = v_cur.x + xstrength + shift.x;
        outline->points[n].y = v_cur.y + ystrength + shift.y;

        in    = out;
        l_in  = l_out;
        v_cur = v_next;
      }

      first = last + 1;
    }

    return FT_Err_Ok;
  }
Ejemplo n.º 24
0
  cff_size_request( FT_Size          size,
                    FT_Size_Request  req )
  {
    CFF_Size           cffsize = (CFF_Size)size;
    PSH_Globals_Funcs  funcs;


#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS

    if ( FT_HAS_FIXED_SIZES( size->face ) )
    {
      CFF_Face      cffface = (CFF_Face)size->face;
      SFNT_Service  sfnt    = (SFNT_Service)cffface->sfnt;
      FT_ULong      strike_index;


      if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) )
        cffsize->strike_index = 0xFFFFFFFFUL;
      else
        return cff_size_select( size, strike_index );
    }

#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

    FT_Request_Metrics( size->face, req );

    funcs = cff_size_get_globals_funcs( cffsize );

    if ( funcs )
    {
      CFF_Face      cffface  = (CFF_Face)size->face;
      CFF_Font      font     = (CFF_Font)cffface->extra.data;
      CFF_Internal  internal = (CFF_Internal)size->internal;

      FT_ULong  top_upm  = font->top_font.font_dict.units_per_em;
      FT_UInt   i;


      funcs->set_scale( internal->topfont,
                        size->metrics.x_scale, size->metrics.y_scale,
                        0, 0 );

      for ( i = font->num_subfonts; i > 0; i-- )
      {
        CFF_SubFont  sub     = font->subfonts[i - 1];
        FT_ULong     sub_upm = sub->font_dict.units_per_em;
        FT_Pos       x_scale, y_scale;


        if ( top_upm != sub_upm )
        {
          x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
          y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
        }
        else
        {
          x_scale = size->metrics.x_scale;
          y_scale = size->metrics.y_scale;
        }

        funcs->set_scale( internal->subfonts[i - 1],
                          x_scale, y_scale, 0, 0 );
      }
    }

    return FT_Err_Ok;
  }
Ejemplo n.º 25
0
Archivo: cffgload.c Proyecto: 93i/godot
  cff_slot_load( CFF_GlyphSlot  glyph,
                 CFF_Size       size,
                 FT_UInt        glyph_index,
                 FT_Int32       load_flags )
  {
    FT_Error     error;
    CFF_Decoder  decoder;
    PS_Decoder   psdecoder;
    TT_Face      face = (TT_Face)glyph->root.face;
    FT_Bool      hinting, scaled, force_scaling;
    CFF_Font     cff  = (CFF_Font)face->extra.data;

    PSAux_Service            psaux         = (PSAux_Service)face->psaux;
    const CFF_Decoder_Funcs  decoder_funcs = psaux->cff_decoder_funcs;

    FT_Matrix    font_matrix;
    FT_Vector    font_offset;


    force_scaling = FALSE;

    /* in a CID-keyed font, consider `glyph_index' as a CID and map */
    /* it immediately to the real glyph_index -- if it isn't a      */
    /* subsetted font, glyph_indices and CIDs are identical, though */
    if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
         cff->charset.cids                               )
    {
      /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
      if ( glyph_index != 0 )
      {
        glyph_index = cff_charset_cid_to_gindex( &cff->charset,
                                                 glyph_index );
        if ( glyph_index == 0 )
          return FT_THROW( Invalid_Argument );
      }
    }
    else if ( glyph_index >= cff->num_glyphs )
      return FT_THROW( Invalid_Argument );

    if ( load_flags & FT_LOAD_NO_RECURSE )
      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;

    glyph->x_scale = 0x10000L;
    glyph->y_scale = 0x10000L;
    if ( size )
    {
      glyph->x_scale = size->root.metrics.x_scale;
      glyph->y_scale = size->root.metrics.y_scale;
    }

#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS

    /* try to load embedded bitmap if any              */
    /*                                                 */
    /* XXX: The convention should be emphasized in     */
    /*      the documents because it can be confusing. */
    if ( size )
    {
      CFF_Face      cff_face = (CFF_Face)size->root.face;
      SFNT_Service  sfnt     = (SFNT_Service)cff_face->sfnt;
      FT_Stream     stream   = cff_face->root.stream;


      if ( size->strike_index != 0xFFFFFFFFUL      &&
           sfnt->load_eblc                         &&
           ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
      {
        TT_SBit_MetricsRec  metrics;


        error = sfnt->load_sbit_image( face,
                                       size->strike_index,
                                       glyph_index,
                                       (FT_UInt)load_flags,
                                       stream,
                                       &glyph->root.bitmap,
                                       &metrics );

        if ( !error )
        {
          FT_Bool    has_vertical_info;
          FT_UShort  advance;
          FT_Short   dummy;


          glyph->root.outline.n_points   = 0;
          glyph->root.outline.n_contours = 0;

          glyph->root.metrics.width  = (FT_Pos)metrics.width  << 6;
          glyph->root.metrics.height = (FT_Pos)metrics.height << 6;

          glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
          glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
          glyph->root.metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;

          glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
          glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
          glyph->root.metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;

          glyph->root.format = FT_GLYPH_FORMAT_BITMAP;

          if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
          {
            glyph->root.bitmap_left = metrics.vertBearingX;
            glyph->root.bitmap_top  = metrics.vertBearingY;
          }
          else
          {
            glyph->root.bitmap_left = metrics.horiBearingX;
            glyph->root.bitmap_top  = metrics.horiBearingY;
          }

          /* compute linear advance widths */

          (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
                                                           glyph_index,
                                                           &dummy,
                                                           &advance );
          glyph->root.linearHoriAdvance = advance;

          has_vertical_info = FT_BOOL(
                                face->vertical_info                   &&
                                face->vertical.number_Of_VMetrics > 0 );

          /* get the vertical metrics from the vmtx table if we have one */
          if ( has_vertical_info )
          {
            (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
                                                             glyph_index,
                                                             &dummy,
                                                             &advance );
            glyph->root.linearVertAdvance = advance;
          }
          else
          {
            /* make up vertical ones */
            if ( face->os2.version != 0xFFFFU )
              glyph->root.linearVertAdvance = (FT_Pos)
                ( face->os2.sTypoAscender - face->os2.sTypoDescender );
            else
              glyph->root.linearVertAdvance = (FT_Pos)
                ( face->horizontal.Ascender - face->horizontal.Descender );
          }

          return error;
        }
      }
    }

#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

    /* return immediately if we only want the embedded bitmaps */
    if ( load_flags & FT_LOAD_SBITS_ONLY )
      return FT_THROW( Invalid_Argument );

    /* if we have a CID subfont, use its matrix (which has already */
    /* been multiplied with the root matrix)                       */

    /* this scaling is only relevant if the PS hinter isn't active */
    if ( cff->num_subfonts )
    {
      FT_Long  top_upm, sub_upm;
      FT_Byte  fd_index = cff_fd_select_get( &cff->fd_select,
                                             glyph_index );


      if ( fd_index >= cff->num_subfonts )
        fd_index = (FT_Byte)( cff->num_subfonts - 1 );

      top_upm = (FT_Long)cff->top_font.font_dict.units_per_em;
      sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em;


      font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix;
      font_offset = cff->subfonts[fd_index]->font_dict.font_offset;

      if ( top_upm != sub_upm )
      {
        glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm );
        glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm );

        force_scaling = TRUE;
      }
    }
    else
    {
      font_matrix = cff->top_font.font_dict.font_matrix;
      font_offset = cff->top_font.font_dict.font_offset;
    }

    glyph->root.outline.n_points   = 0;
    glyph->root.outline.n_contours = 0;

    /* top-level code ensures that FT_LOAD_NO_HINTING is set */
    /* if FT_LOAD_NO_SCALE is active                         */
    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
    scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );

    glyph->hint        = hinting;
    glyph->scaled      = scaled;
    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;  /* by default */

    {
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
      PS_Driver  driver = (PS_Driver)FT_FACE_DRIVER( face );
#endif


      FT_Byte*  charstring;
      FT_ULong  charstring_len;


      decoder_funcs->init( &decoder, face, size, glyph, hinting,
                           FT_LOAD_TARGET_MODE( load_flags ),
                           cff_get_glyph_data,
                           cff_free_glyph_data );

      /* this is for pure CFFs */
      if ( load_flags & FT_LOAD_ADVANCE_ONLY )
        decoder.width_only = TRUE;

      decoder.builder.no_recurse =
        (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE );

      /* now load the unscaled outline */
      error = cff_get_glyph_data( face, glyph_index,
                                  &charstring, &charstring_len );
      if ( error )
        goto Glyph_Build_Finished;

      error = decoder_funcs->prepare( &decoder, size, glyph_index );
      if ( error )
        goto Glyph_Build_Finished;

#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
      /* choose which CFF renderer to use */
      if ( driver->hinting_engine == FT_HINTING_FREETYPE )
        error = decoder_funcs->parse_charstrings_old( &decoder,
                                                      charstring,
                                                      charstring_len,
                                                      0 );
      else
#endif
      {
        psaux->ps_decoder_init( &psdecoder, &decoder, FALSE );

        error = decoder_funcs->parse_charstrings( &psdecoder,
                                                  charstring,
                                                  charstring_len );

        /* Adobe's engine uses 16.16 numbers everywhere;              */
        /* as a consequence, glyphs larger than 2000ppem get rejected */
        if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
        {
          /* this time, we retry unhinted and scale up the glyph later on */
          /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
          /* 0x400 for both `x_scale' and `y_scale' in this case)         */
          hinting       = FALSE;
          force_scaling = TRUE;
          glyph->hint   = hinting;

          error = decoder_funcs->parse_charstrings( &psdecoder,
                                                    charstring,
                                                    charstring_len );
        }
      }

      cff_free_glyph_data( face, &charstring, charstring_len );

      if ( error )
        goto Glyph_Build_Finished;

#ifdef FT_CONFIG_OPTION_INCREMENTAL
      /* Control data and length may not be available for incremental */
      /* fonts.                                                       */
      if ( face->root.internal->incremental_interface )
      {
        glyph->root.control_data = NULL;
        glyph->root.control_len = 0;
      }
      else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */

      /* We set control_data and control_len if charstrings is loaded. */
      /* See how charstring loads at cff_index_access_element() in     */
      /* cffload.c.                                                    */
      {
        CFF_Index  csindex = &cff->charstrings_index;


        if ( csindex->offsets )
        {
          glyph->root.control_data = csindex->bytes +
                                     csindex->offsets[glyph_index] - 1;
          glyph->root.control_len  = (FT_Long)charstring_len;
        }
      }

  Glyph_Build_Finished:
      /* save new glyph tables, if no error */
      if ( !error )
        decoder.builder.funcs.done( &decoder.builder );
      /* XXX: anything to do for broken glyph entry? */
    }

#ifdef FT_CONFIG_OPTION_INCREMENTAL

    /* Incremental fonts can optionally override the metrics. */
    if ( !error                                                               &&
         face->root.internal->incremental_interface                           &&
         face->root.internal->incremental_interface->funcs->get_glyph_metrics )
    {
      FT_Incremental_MetricsRec  metrics;


      metrics.bearing_x = decoder.builder.left_bearing.x;
      metrics.bearing_y = 0;
      metrics.advance   = decoder.builder.advance.x;
      metrics.advance_v = decoder.builder.advance.y;

      error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
                face->root.internal->incremental_interface->object,
                glyph_index, FALSE, &metrics );

      decoder.builder.left_bearing.x = metrics.bearing_x;
      decoder.builder.advance.x      = metrics.advance;
      decoder.builder.advance.y      = metrics.advance_v;
    }

#endif /* FT_CONFIG_OPTION_INCREMENTAL */

    if ( !error )
    {
      /* Now, set the metrics -- this is rather simple, as   */
      /* the left side bearing is the xMin, and the top side */
      /* bearing the yMax.                                   */

      /* For composite glyphs, return only left side bearing and */
      /* advance width.                                          */
      if ( load_flags & FT_LOAD_NO_RECURSE )
      {
        FT_Slot_Internal  internal = glyph->root.internal;


        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
        glyph->root.metrics.horiAdvance  = decoder.glyph_width;
        internal->glyph_matrix           = font_matrix;
        internal->glyph_delta            = font_offset;
        internal->glyph_transformed      = 1;
      }
      else
      {
        FT_BBox            cbox;
        FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
        FT_Bool            has_vertical_info;


        if ( face->horizontal.number_Of_HMetrics )
        {
          FT_Short   horiBearingX = 0;
          FT_UShort  horiAdvance  = 0;


          ( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
                                                     glyph_index,
                                                     &horiBearingX,
                                                     &horiAdvance );
          metrics->horiAdvance          = horiAdvance;
          metrics->horiBearingX         = horiBearingX;
          glyph->root.linearHoriAdvance = horiAdvance;
        }
        else
        {
          /* copy the _unscaled_ advance width */
          metrics->horiAdvance          = decoder.glyph_width;
          glyph->root.linearHoriAdvance = decoder.glyph_width;
        }

        glyph->root.internal->glyph_transformed = 0;

        has_vertical_info = FT_BOOL( face->vertical_info                   &&
                                     face->vertical.number_Of_VMetrics > 0 );

        /* get the vertical metrics from the vmtx table if we have one */
        if ( has_vertical_info )
        {
          FT_Short   vertBearingY = 0;
          FT_UShort  vertAdvance  = 0;


          ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
                                                     glyph_index,
                                                     &vertBearingY,
                                                     &vertAdvance );
          metrics->vertBearingY = vertBearingY;
          metrics->vertAdvance  = vertAdvance;
        }
        else
        {
          /* make up vertical ones */
          if ( face->os2.version != 0xFFFFU )
            metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender -
                                             face->os2.sTypoDescender );
          else
            metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender -
                                             face->horizontal.Descender );
        }

        glyph->root.linearVertAdvance = metrics->vertAdvance;

        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;

        glyph->root.outline.flags = 0;
        if ( size && size->root.metrics.y_ppem < 24 )
          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;

        glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;

        /* apply the font matrix, if any */
        if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
             font_matrix.xy != 0        || font_matrix.yx != 0        )
        {
          FT_Outline_Transform( &glyph->root.outline, &font_matrix );

          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
                                            font_matrix.xx );
          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
                                            font_matrix.yy );
        }

        if ( font_offset.x || font_offset.y )
        {
          FT_Outline_Translate( &glyph->root.outline,
                                font_offset.x,
                                font_offset.y );

          metrics->horiAdvance += font_offset.x;
          metrics->vertAdvance += font_offset.y;
        }

        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
        {
          /* scale the outline and the metrics */
          FT_Int       n;
          FT_Outline*  cur     = &glyph->root.outline;
          FT_Vector*   vec     = cur->points;
          FT_Fixed     x_scale = glyph->x_scale;
          FT_Fixed     y_scale = glyph->y_scale;


          /* First of all, scale the points */
          if ( !hinting || !decoder.builder.hints_funcs )
            for ( n = cur->n_points; n > 0; n--, vec++ )
            {
              vec->x = FT_MulFix( vec->x, x_scale );
              vec->y = FT_MulFix( vec->y, y_scale );
            }

          /* Then scale the metrics */
          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
        }

        /* compute the other metrics */
        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );

        metrics->width  = cbox.xMax - cbox.xMin;
        metrics->height = cbox.yMax - cbox.yMin;

        metrics->horiBearingX = cbox.xMin;
        metrics->horiBearingY = cbox.yMax;

        if ( has_vertical_info )
          metrics->vertBearingX = metrics->horiBearingX -
                                    metrics->horiAdvance / 2;
        else
        {
          if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
            ft_synthesize_vertical_metrics( metrics,
                                            metrics->vertAdvance );
        }
      }
    }

    return error;
  }
Ejemplo n.º 26
0
static void scantags(FT_GlyphEngine *ge, struct TagItem *tags)
{
    Tag   otagtag;
    ULONG otagdata;
    const struct TagItem *tstate;
    struct TagItem *tag;
    int temp, temp2;

    tstate = tags;
    while ((tag = NextTagItem(&tstate)))
    {
	otagtag  = tag->ti_Tag;
	otagdata = tag->ti_Data;

	switch (otagtag)
	{
	    /* OT_Spec1 = the filename of the ft file */
	case OT_Spec1_FontFile:
	    D(bug("SetInfo: Tag=OT_Spec1 ft file=%ls\n",otagdata));
	    /*			if(OpenFace(ge,(char *)otagdata)) return; */
	    strcpy(ge->base_filename,(char *)otagdata);
	    /* clear all other names */
	    ge->afm_filename[0] = '\0';
            switch_family(ge);
	    break;

	case OT_Spec2_DefCodePage:	/* direct = use default */
	    D(bug("SetInfo: Tag=OT_Spec2 Default Code Page\n"));
	    set_default_codepage(ge);
	    break;

	case OT_Spec2_CodePage:
	    D(bug("SetInfo: Tag=OT_Spec2 Custom Code Page\n"));
	    CopyMem((char *)otagdata,ge->codepage,sizeof(ge->codepage));
	    break;

	case OT_Spec3_AFMFile:
	    strcpy(ge->afm_filename,(char *)otagdata);
	    break;

	    /* OT_Spec4 = metric source */
	case OT_Spec4_Metric:
	    D(bug("SetInfo: Tag=OT_Spec4 Metric Source=%lx\n",otagdata));
	    temp=(ULONG)otagdata;
	    if(ge->metric_source!=temp)
	    {
		ge->metric_source = temp;
		ge->instance_changed=TRUE;
	    }
	    break;

	    /* OT_Spec5 = custom metrics */
	case OT_Spec5_BBox:
	    D(bug("SetInfo: Tag=OT_Spec5 Custom Metrics=%lx\n",otagdata));
	    temp=(ULONG)otagdata;
	    if(ge->metric_custom!=temp)
	    {
		ge->metric_custom = temp;
		ge->instance_changed=TRUE;
	    }
	    break;

	case OT_Spec6_FaceNum:
	    D(bug("SetInfo: Tag=OT_Spec6_FaceNum\n"));
	    ge->face_num = otagdata;
	    break;

	case OT_Spec7_BMSize:
	    break;

	case OT_Spec9_Hinter:
	    break;

	case OT_SymbolSet: /* index to charmap encodings */
	    D(bug("SetInfo: Tag=OT_SymbolSet cmap=%lx\n",otagdata));
	    ge->requested_cmap = (ULONG)otagdata;
	    ge->cmap_index=NO_CMAP_SET;
	    break;

	    /* some programs specify point and DPI with every glyph
	     * request, so check if they really changed before setting
	     * instance_changed. (Note: OpenFace ALWAYS sets it.) */
	case OT_PointHeight:
	    D(bug("SetInfo: Tag=OT_PointHeight size=%lx\n",otagdata));
	    temp = ((ULONG)otagdata) >> 16;
	    if(ge->point_size != temp)
	    {
		ge->point_size = temp;
		ge->instance_changed=TRUE;
	    }
	    break;

	case OT_DeviceDPI:
	    temp = ((ULONG)otagdata) >> 16;
	    temp2 = ((ULONG)otagdata) & 0xffff;
	    D(bug("SetInfo: Tag=OT_DeviceDPI xres=%ld yres=%ld\n",temp,temp2));
	    if((temp!=ge->xres) || (temp2!=ge->yres))
	    {
		ge->xres = temp;
		ge->yres = temp2;
		ge->instance_changed=TRUE;
	    }
	    break;

	case OT_RotateSin:	/* by spec set SIN then COS */
	    D(bug("SetInfo: Tag=OT_RotateSin sin=%lx\n",otagdata));
	    ge->hold_sin = ((ULONG)otagdata);
	    break;

	case OT_RotateCos:	/* process both SIN and COS */
	    D(bug("SetInfo: Tag=OT_RotateCos cos=%lx\n",otagdata));
	    ge->hold_cos = ((ULONG)otagdata);
	    /* sin=0.0 cos=1.0 is no rotation */
	    if(ge->hold_sin==0 && ge->hold_cos==0x10000)
		ge->do_rotate=0;
	    else
	    {
		/* argh! counter clockwise rotation
		 * swapped .xy and .yx to match bullet.
		 * hmmm, shear is clockwise...arrggghhh! */
		ge->do_rotate=1;
		ge->rotate_matrix.xx = ge->hold_cos;
		ge->rotate_matrix.xy = -ge->hold_sin;
		ge->rotate_matrix.yx = ge->hold_sin;
		ge->rotate_matrix.yy = ge->hold_cos;
	    }
	    set_transform(ge);
	    break;

	case OT_ShearSin:	/* by spec set SIN then COS */
	    D(bug("SetInfo: Tag=OT_ShearSin sin=%lx\n",otagdata));
	    ge->hold_sin = ((ULONG)otagdata);
	    break;

	case OT_ShearCos:
	    D(bug("SetInfo: Tag=OT_ShearCos cos=%lx\n",otagdata));
	    ge->hold_cos = ((ULONG)otagdata);
	    /* sin=0.0 cos=1.0 is no shear */
	    if(ge->hold_sin==0 && ge->hold_cos==0x10000)
	    {
		ge->do_shear=0;
		//					ge->italic_sig=0;
	    }
	    else
	    {
		ge->do_shear=1;
		//					ge->italic_sig=1;
		if(ge->hold_cos)
		    temp=FT_MulDiv(ge->hold_sin,
				   0x10000,ge->hold_cos);
		else	temp=0;
		ge->shear_matrix.xx = 1<<16;
		ge->shear_matrix.xy = temp;
		ge->shear_matrix.yx = 0;
		ge->shear_matrix.yy = 1<<16;
	    }
	    set_transform(ge);
	    break;

#if 0
	case OT_EmboldenX:
	    D(bug("SetInfo: Tag=OT_EmboldenX data=%lx\n",otagdata));
	    ge->do_embold=0;
	    ge->bold_sig=0;
	    ge->embold_x = (ULONG)otagdata;
	    if(ge->embold_x || ge->embold_y)
	    {
		ge->do_embold=1;
		ge->bold_sig=2;
	    }
	    break;

	case OT_EmboldenY:
	    D(bug("SetInfo: Tag=OT_EmboldenY data=%lx\n",otagdata));
	    ge->do_embold=0;
	    ge->bold_sig=0;
	    ge->embold_y = (ULONG)otagdata;
	    if(ge->embold_x || ge->embold_y)
	    {
		ge->do_embold=1;
		ge->bold_sig=2;
	    }
	    break;
#endif
#if 0
	    Diskfont Bold signature
	    <Set: Tag=8000000E  Data=E75
	    <Set: Tag=8000000F  Data=99E
		
	    Diskfont Italic signature
	    <Set: Tag=8000000A  Data=4690
	    <Set: Tag=8000000B  Data=F615
#endif

	case OT_GlyphCode:
	    D(bug("SetInfo: Tag=OT_GlyphCode data=%lx\n",otagdata));
	    ge->request_char = (ULONG)otagdata;
	    break;

	case OT_GlyphCode2:
	    D(bug("SetInfo: Tag=OT_GlyphCode2 data=%lx\n",otagdata));
	    ge->request_char2 = (ULONG)otagdata;
	    break;

	case OT_OTagList: /* a tag of tags? */
	    D(bug("SetInfo: Tag=OT_OTagList data=%lx\n",otagdata));
	    if (otagdata)
		scantags(ge, (struct TagItem *)otagdata);
	    break;

	default:
	    D(bug("Ignored Set: Tag=%lx  Data=%lx\n",(LONG)otagtag, otagdata));
	    break;
	}
    }
}
Ejemplo n.º 27
0
  cff_face_init( FT_Stream      stream,
                 FT_Face        cffface,        /* CFF_Face */
                 FT_Int         face_index,
                 FT_Int         num_params,
                 FT_Parameter*  params )
  {
    CFF_Face            face = (CFF_Face)cffface;
    FT_Error            error;
    SFNT_Service        sfnt;
    FT_Service_PsCMaps  psnames;
    PSHinter_Service    pshinter;
    FT_Bool             pure_cff    = 1;
    FT_Bool             sfnt_format = 0;


#if 0
    FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt,     SFNT );
    FT_FACE_FIND_GLOBAL_SERVICE( face, psnames,  POSTSCRIPT_NAMES );
    FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER );

    if ( !sfnt )
      goto Bad_Format;
#else
    sfnt = (SFNT_Service)FT_Get_Module_Interface(
             cffface->driver->root.library, "sfnt" );
    if ( !sfnt )
      goto Bad_Format;

    FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );

    pshinter = (PSHinter_Service)FT_Get_Module_Interface(
                 cffface->driver->root.library, "pshinter" );
#endif

    /* create input stream from resource */
    if ( FT_STREAM_SEEK( 0 ) )
      goto Exit;

    /* check whether we have a valid OpenType file */
    error = sfnt->init_face( stream, face, face_index, num_params, params );
    if ( !error )
    {
      if ( face->format_tag != 0x4F54544FL )  /* `OTTO'; OpenType/CFF font */
      {
        FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
        goto Bad_Format;
      }

      /* if we are performing a simple font format check, exit immediately */
      if ( face_index < 0 )
        return CFF_Err_Ok;

      /* UNDOCUMENTED!  A CFF in an SFNT can have only a single font. */
      if ( face_index > 0 )
      {
        FT_ERROR(( "cff_face_init: invalid face index\n" ));
        error = CFF_Err_Invalid_Argument;
        goto Exit;
      }

      sfnt_format = 1;

      /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
      /* font; in the latter case it doesn't have a `head' table         */
      error = face->goto_table( face, TTAG_head, stream, 0 );
      if ( !error )
      {
        pure_cff = 0;

        /* load font directory */
        error = sfnt->load_face( stream, face,
                                 face_index, num_params, params );
        if ( error )
          goto Exit;
      }
      else
      {
        /* load the `cmap' table explicitly */
        error = sfnt->load_cmap( face, stream );
        if ( error )
          goto Exit;

        /* XXX: we don't load the GPOS table, as OpenType Layout     */
        /* support will be added later to a layout library on top of */
        /* FreeType 2                                                */
      }

      /* now load the CFF part of the file */
      error = face->goto_table( face, TTAG_CFF, stream, 0 );
      if ( error )
        goto Exit;
    }
    else
    {
      /* rewind to start of file; we are going to load a pure-CFF font */
      if ( FT_STREAM_SEEK( 0 ) )
        goto Exit;
      error = CFF_Err_Ok;
    }

    /* now load and parse the CFF table in the file */
    {
      CFF_Font         cff;
      CFF_FontRecDict  dict;
      FT_Memory        memory = cffface->memory;
      FT_Int32         flags;
      FT_UInt          i;


      if ( FT_NEW( cff ) )
        goto Exit;

      face->extra.data = cff;
      error = cff_font_load( stream, face_index, cff );
      if ( error )
        goto Exit;

      cff->pshinter = pshinter;
      cff->psnames  = (void*)psnames;

      /* Complement the root flags with some interesting information. */
      /* Note that this is only necessary for pure CFF and CEF fonts; */
      /* SFNT based fonts use the `name' table instead.               */

      cffface->num_glyphs = cff->num_glyphs;

      dict = &cff->top_font.font_dict;

      /* we need the `PSNames' module for CFF and CEF formats */
      /* which aren't CID-keyed                               */
      if ( dict->cid_registry == 0xFFFFU && !psnames )
      {
        FT_ERROR(( "cff_face_init:" ));
        FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
        FT_ERROR(( "              " ));
        FT_ERROR(( " without the `PSNames' module\n" ));
        goto Bad_Format;
      }

      if ( pure_cff )
      {
        char*  style_name = NULL;


        /* set up num_faces */
        cffface->num_faces = cff->num_faces;

        /* compute number of glyphs */
        if ( dict->cid_registry != 0xFFFFU )
          cffface->num_glyphs = cff->charset.max_cid;
        else
          cffface->num_glyphs = cff->charstrings_index.count;

        /* set global bbox, as well as EM size */
        cffface->bbox.xMin =   dict->font_bbox.xMin             >> 16;
        cffface->bbox.yMin =   dict->font_bbox.yMin             >> 16;
        cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16;
        cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16;

        if ( !dict->units_per_em )
          dict->units_per_em = 1000;

        cffface->units_per_EM = dict->units_per_em;

        cffface->ascender  = (FT_Short)( cffface->bbox.yMax );
        cffface->descender = (FT_Short)( cffface->bbox.yMin );

        cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 );
        if ( cffface->height < cffface->ascender - cffface->descender )
          cffface->height = (FT_Short)( cffface->ascender - cffface->descender );

        cffface->underline_position  =
          (FT_Short)( dict->underline_position >> 16 );
        cffface->underline_thickness =
          (FT_Short)( dict->underline_thickness >> 16 );

        /* retrieve font family & style name */
        cffface->family_name = cff_index_get_name( &cff->name_index,
                                                   face_index );

        if ( cffface->family_name )
        {
          char*  full   = cff_index_get_sid_string( &cff->string_index,
                                                    dict->full_name,
                                                    psnames );
          char*  fullp  = full;
          char*  family = cffface->family_name;
          char*  family_name = 0;


          if ( dict->family_name )
          {
            family_name = cff_index_get_sid_string( &cff->string_index,
                                                    dict->family_name,
                                                    psnames);
            if ( family_name )
              family = family_name;
          }

          /* We try to extract the style name from the full name.   */
          /* We need to ignore spaces and dashes during the search. */
          if ( full && family )
          {
            while ( *fullp )
            {
              /* skip common characters at the start of both strings */
              if ( *fullp == *family )
              {
                family++;
                fullp++;
                continue;
              }

              /* ignore spaces and dashes in full name during comparison */
              if ( *fullp == ' ' || *fullp == '-' )
              {
                fullp++;
                continue;
              }

              /* ignore spaces and dashes in family name during comparison */
              if ( *family == ' ' || *family == '-' )
              {
                family++;
                continue;
              }

              if ( !*family && *fullp )
              {
                /* The full name begins with the same characters as the  */
                /* family name, with spaces and dashes removed.  In this */
                /* case, the remaining string in `fullp' will be used as */
                /* the style name.                                       */
                style_name = cff_strcpy( memory, fullp );
              }
              break;
            }

            if ( family_name )
              FT_FREE( family_name );
            FT_FREE( full );
          }
        }
        else
        {
          char  *cid_font_name =
                   cff_index_get_sid_string( &cff->string_index,
                                             dict->cid_font_name,
                                             psnames );


          /* do we have a `/FontName' for a CID-keyed font? */
          if ( cid_font_name )
            cffface->family_name = cid_font_name;
        }

        if ( style_name )
          cffface->style_name = style_name;
        else
          /* assume "Regular" style if we don't know better */
          cffface->style_name = cff_strcpy( memory, (char *)"Regular" );

        /*******************************************************************/
        /*                                                                 */
        /* Compute face flags.                                             */
        /*                                                                 */
        flags = FT_FACE_FLAG_SCALABLE   |       /* scalable outlines */
                FT_FACE_FLAG_HORIZONTAL |       /* horizontal data   */
                FT_FACE_FLAG_HINTER;            /* has native hinter */

        if ( sfnt_format )
          flags |= FT_FACE_FLAG_SFNT;

        /* fixed width font? */
        if ( dict->is_fixed_pitch )
          flags |= FT_FACE_FLAG_FIXED_WIDTH;

  /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
#if 0
        /* kerning available? */
        if ( face->kern_pairs )
          flags |= FT_FACE_FLAG_KERNING;
#endif

        cffface->face_flags = flags;

        /*******************************************************************/
        /*                                                                 */
        /* Compute style flags.                                            */
        /*                                                                 */
        flags = 0;

        if ( dict->italic_angle )
          flags |= FT_STYLE_FLAG_ITALIC;

        {
          char  *weight = cff_index_get_sid_string( &cff->string_index,
                                                    dict->weight,
                                                    psnames );


          if ( weight )
            if ( !ft_strcmp( weight, "Bold"  ) ||
                 !ft_strcmp( weight, "Black" ) )
              flags |= FT_STYLE_FLAG_BOLD;
          FT_FREE( weight );
        }

        /* double check */
        if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name )
          if ( !ft_strncmp( cffface->style_name, "Bold", 4 )  ||
               !ft_strncmp( cffface->style_name, "Black", 5 ) )
            flags |= FT_STYLE_FLAG_BOLD;

        cffface->style_flags = flags;
      }
      else
      {
        if ( !dict->units_per_em )
          dict->units_per_em = face->root.units_per_EM;
      }

      /* Normalize the font matrix so that `matrix->xx' is 1; the */
      /* scaling is done with `units_per_em' then (at this point, */
      /* it already contains the scaling factor, but without      */
      /* normalization of the matrix).                            */
      /*                                                          */
      /* Note that the offsets must be expressed in integer font  */
      /* units.                                                   */

      {
        FT_Matrix*  matrix = &dict->font_matrix;
        FT_Vector*  offset = &dict->font_offset;
        FT_ULong*   upm    = &dict->units_per_em;
        FT_Fixed    temp   = FT_ABS( matrix->yy );


        if ( temp != 0x10000L )
        {
          *upm = FT_DivFix( *upm, temp );

          matrix->xx = FT_DivFix( matrix->xx, temp );
          matrix->yx = FT_DivFix( matrix->yx, temp );
          matrix->xy = FT_DivFix( matrix->xy, temp );
          matrix->yy = FT_DivFix( matrix->yy, temp );
          offset->x  = FT_DivFix( offset->x,  temp );
          offset->y  = FT_DivFix( offset->y,  temp );
        }

        offset->x >>= 16;
        offset->y >>= 16;
      }

      for ( i = cff->num_subfonts; i > 0; i-- )
      {
        CFF_FontRecDict  sub = &cff->subfonts[i - 1]->font_dict;
        CFF_FontRecDict  top = &cff->top_font.font_dict;

        FT_Matrix*  matrix;
        FT_Vector*  offset;
        FT_ULong*   upm;
        FT_Fixed    temp;


        if ( sub->units_per_em )
        {
          FT_Int  scaling;


          if ( top->units_per_em > 1 && sub->units_per_em > 1 )
            scaling = FT_MIN( top->units_per_em, sub->units_per_em );
          else
            scaling = 1;

          FT_Matrix_Multiply_Scaled( &top->font_matrix,
                                     &sub->font_matrix,
                                     scaling );
          FT_Vector_Transform_Scaled( &sub->font_offset,
                                      &top->font_matrix,
                                      scaling );

          sub->units_per_em = FT_MulDiv( sub->units_per_em,
                                         top->units_per_em,
                                         scaling );
        }
        else
        {
          sub->font_matrix = top->font_matrix;
          sub->font_offset = top->font_offset;

          sub->units_per_em = top->units_per_em;
        }

        matrix = &sub->font_matrix;
        offset = &sub->font_offset;
        upm    = &sub->units_per_em;
        temp   = FT_ABS( matrix->yy );

        if ( temp != 0x10000L )
        {
          *upm = FT_DivFix( *upm, temp );

          /* if *upm is larger than 100*1000 we divide by 1000 --     */
          /* this can happen if e.g. there is no top-font FontMatrix  */
          /* and the subfont FontMatrix already contains the complete */
          /* scaling for the subfont (see section 5.11 of the PLRM)   */

          /* 100 is a heuristic value */

          if ( *upm > 100L * 1000L )
            *upm = ( *upm + 500 ) / 1000;

          matrix->xx = FT_DivFix( matrix->xx, temp );
          matrix->yx = FT_DivFix( matrix->yx, temp );
          matrix->xy = FT_DivFix( matrix->xy, temp );
          matrix->yy = FT_DivFix( matrix->yy, temp );
          offset->x  = FT_DivFix( offset->x,  temp );
          offset->y  = FT_DivFix( offset->y,  temp );
        }

        offset->x >>= 16;
        offset->y >>= 16;
      }

#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
      /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
      /* has unset this flag because of the 3.0 `post' table.          */
      if ( dict->cid_registry == 0xFFFFU )
        cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
#endif

      if ( dict->cid_registry != 0xFFFFU )
        cffface->face_flags |= FT_FACE_FLAG_CID_KEYED;


      /*******************************************************************/
      /*                                                                 */
      /* Compute char maps.                                              */
      /*                                                                 */

      /* Try to synthetize a Unicode charmap if there is none available */
      /* already.  If an OpenType font contains a Unicode "cmap", we    */
      /* will use it, whatever be in the CFF part of the file.          */
      {
        FT_CharMapRec  cmaprec;
        FT_CharMap     cmap;
        FT_UInt        nn;
        CFF_Encoding   encoding = &cff->encoding;


        for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ )
        {
          cmap = cffface->charmaps[nn];

          /* Windows Unicode (3,1)? */
          if ( cmap->platform_id == 3 && cmap->encoding_id == 1 )
            goto Skip_Unicode;

          /* Deprecated Unicode platform id? */
          if ( cmap->platform_id == 0 )
            goto Skip_Unicode; /* Standard Unicode (deprecated) */
        }

        /* since CID-keyed fonts don't contain glyph names, we can't */
        /* construct a cmap                                          */
        if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU )
          goto Exit;

        /* we didn't find a Unicode charmap -- synthesize one */
        cmaprec.face        = cffface;
        cmaprec.platform_id = 3;
        cmaprec.encoding_id = 1;
        cmaprec.encoding    = FT_ENCODING_UNICODE;

        nn = (FT_UInt)cffface->num_charmaps;

        FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL );

        /* if no Unicode charmap was previously selected, select this one */
        if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps )
          cffface->charmap = cffface->charmaps[nn];

      Skip_Unicode:
        if ( encoding->count > 0 )
        {
          FT_CMap_Class  clazz;


          cmaprec.face        = cffface;
          cmaprec.platform_id = 7;  /* Adobe platform id */

          if ( encoding->offset == 0 )
          {
            cmaprec.encoding_id = TT_ADOBE_ID_STANDARD;
            cmaprec.encoding    = FT_ENCODING_ADOBE_STANDARD;
            clazz               = &cff_cmap_encoding_class_rec;
          }
          else if ( encoding->offset == 1 )
          {
            cmaprec.encoding_id = TT_ADOBE_ID_EXPERT;
            cmaprec.encoding    = FT_ENCODING_ADOBE_EXPERT;
            clazz               = &cff_cmap_encoding_class_rec;
          }
          else
          {
            cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM;
            cmaprec.encoding    = FT_ENCODING_ADOBE_CUSTOM;
            clazz               = &cff_cmap_encoding_class_rec;
          }

          FT_CMap_New( clazz, NULL, &cmaprec, NULL );
        }
      }
    }