TagStruct FontEngine_Freetype::get_tag_struct(int cont, int index, FT_Outline *ft_outline)
{
	TagStruct tags;

	int prev_index = get_index_of_prev_contour_point(cont, index, ft_outline);
	int next_index = get_index_of_next_contour_point(cont, index, ft_outline);

	tags.previous = FT_CURVE_TAG(ft_outline->tags[prev_index]);
	tags.next = FT_CURVE_TAG(ft_outline->tags[next_index]);
	tags.current = FT_CURVE_TAG(ft_outline->tags[index]);

	return tags;
}
Example #2
0
intermediate_point get_point(FT_Outline& outline, unsigned int contour, unsigned int point)
{
	unsigned int i = get_point_index(outline, contour, point);

	intermediate_point res;
	res.x   = outline.points[i].x;
	res.y   = outline.points[i].y;
	res.tag = FT_CURVE_TAG(outline.tags[i]); // we're only interested in the type tag

	return res;
}
Example #3
0
// Find the relative offset from start index to first point of type ON.
// This is neccesary because a contour may start with any type of point, but
// refonter assumes (for simplicity)  that the first point is type ON.
unsigned int get_contour_start_offset(FT_Outline& outline, unsigned int contour)
{
	// Determine start and end pos
	unsigned int start = get_contour_start_index(outline, contour);
	unsigned int stop = start + get_contour_num_points(outline, contour);

	// Look for first FT_CURVE_TAG_ON point
	unsigned int i = start;

	while (i<stop && FT_CURVE_TAG(outline.tags[i])!=FT_CURVE_TAG_ON)
		i++;

	// Return
	if (i<stop)
		return i-start;
	else
		return -1;
}
static ofTTFCharacter makeContoursForCharacter(FT_Face &face){

		//int num			= face->glyph->outline.n_points;
		int nContours	= face->glyph->outline.n_contours;
		int startPos	= 0;

		char * tags		= face->glyph->outline.tags;
		FT_Vector * vec = face->glyph->outline.points;

		ofTTFCharacter charOutlines;
		charOutlines.setUseShapeColor(false);

		for(int k = 0; k < nContours; k++){
			if( k > 0 ){
				startPos = face->glyph->outline.contours[k-1]+1;
			}
			int endPos = face->glyph->outline.contours[k]+1;

			if(printVectorInfo){
				ofLogNotice("ofTrueTypeFont") << "--NEW CONTOUR";
			}

			//vector <ofPoint> testOutline;
			ofPoint lastPoint;

			for(int j = startPos; j < endPos; j++){

				if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_ON ){
					lastPoint.set((float)vec[j].x, (float)-vec[j].y, 0);
					if(printVectorInfo){
						ofLogNotice("ofTrueTypeFont") << "flag[" << j << "] is set to 1 - regular point - " << lastPoint.x <<  lastPoint.y;
					}
					charOutlines.lineTo(lastPoint/64);

				}else{
					if(printVectorInfo){
						ofLogNotice("ofTrueTypeFont") << "flag[" << j << "] is set to 0 - control point";
					}

					if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_CUBIC ){
						if(printVectorInfo){
							ofLogNotice("ofTrueTypeFont") << "- bit 2 is set to 2 - CUBIC";
						}

						int prevPoint = j-1;
						if( j == 0){
							prevPoint = endPos-1;
						}

						int nextIndex = j+1;
						if( nextIndex >= endPos){
							nextIndex = startPos;
						}

						ofPoint nextPoint( (float)vec[nextIndex].x,  -(float)vec[nextIndex].y );

						//we need two control points to draw a cubic bezier
						bool lastPointCubic =  ( FT_CURVE_TAG(tags[prevPoint]) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG(tags[prevPoint]) == FT_CURVE_TAG_CUBIC);

						if( lastPointCubic ){
							ofPoint controlPoint1((float)vec[prevPoint].x,	(float)-vec[prevPoint].y);
							ofPoint controlPoint2((float)vec[j].x, (float)-vec[j].y);
							ofPoint nextPoint((float) vec[nextIndex].x,	-(float) vec[nextIndex].y);

							//cubic_bezier(testOutline, lastPoint.x, lastPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, nextPoint.x, nextPoint.y, 8);
							charOutlines.bezierTo(controlPoint1.x/64, controlPoint1.y/64, controlPoint2.x/64, controlPoint2.y/64, nextPoint.x/64, nextPoint.y/64);
						}

					}else{

						ofPoint conicPoint( (float)vec[j].x,  -(float)vec[j].y );

						if(printVectorInfo){
							ofLogNotice("ofTrueTypeFont") << "- bit 2 is set to 0 - conic- ";
							ofLogNotice("ofTrueTypeFont") << "--- conicPoint point is " << conicPoint.x << conicPoint.y;
						}

						//If the first point is connic and the last point is connic then we need to create a virutal point which acts as a wrap around
						if( j == startPos ){
							bool prevIsConnic = (  FT_CURVE_TAG( tags[endPos-1] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[endPos-1]) != FT_CURVE_TAG_CUBIC );

							if( prevIsConnic ){
								ofPoint lastConnic((float)vec[endPos - 1].x, (float)-vec[endPos - 1].y);
								lastPoint = (conicPoint + lastConnic) / 2;

								if(printVectorInfo){
									ofLogNotice("ofTrueTypeFont") << "NEED TO MIX WITH LAST";
									ofLogNotice("ofTrueTypeFont") << "last is " << lastPoint.x << " " << lastPoint.y;
								}
							}
						}

						//bool doubleConic = false;

						int nextIndex = j+1;
						if( nextIndex >= endPos){
							nextIndex = startPos;
						}

						ofPoint nextPoint( (float)vec[nextIndex].x,  -(float)vec[nextIndex].y );

						if(printVectorInfo){
							ofLogNotice("ofTrueTypeFont") << "--- last point is " << lastPoint.x << " " <<  lastPoint.y;
						}

						bool nextIsConnic = (  FT_CURVE_TAG( tags[nextIndex] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[nextIndex]) != FT_CURVE_TAG_CUBIC );

						//create a 'virtual on point' if we have two connic points
						if( nextIsConnic ){
							nextPoint = (conicPoint + nextPoint) / 2;
							if(printVectorInfo){
								ofLogNotice("ofTrueTypeFont") << "|_______ double connic!";
							}
						}
						if(printVectorInfo){
							ofLogNotice("ofTrueTypeFont") << "--- next point is " << nextPoint.x << " " << nextPoint.y;
						}

						//quad_bezier(testOutline, lastPoint.x, lastPoint.y, conicPoint.x, conicPoint.y, nextPoint.x, nextPoint.y, 8);
						charOutlines.quadBezierTo(lastPoint.x/64, lastPoint.y/64, conicPoint.x/64, conicPoint.y/64, nextPoint.x/64, nextPoint.y/64);

						if( nextIsConnic ){
							lastPoint = nextPoint;
						}
					}
				}

			//end for
			}
			charOutlines.close();
		}

	return charOutlines;
}
Example #5
0
  FT_Outline_Decompose( const FT_Outline*        outline,
                        const FT_Outline_Funcs*  func_interface,
                        void*                    user )
  {
#undef SCALED
#define SCALED( x )  ( ( (x) << shift ) - delta )

    FT_Vector   v_last;
    FT_Vector   v_control;
    FT_Vector   v_start;

    FT_Vector*  point;
    FT_Vector*  limit;
    char*       tags;

    FT_Error    error;

    FT_Int   n;         /* index of contour in outline     */
    FT_UInt  first;     /* index of first point in contour */
    FT_Int   tag;       /* current point's state           */

    FT_Int   shift;
    FT_Pos   delta;


    if ( !outline || !func_interface )
      return FT_Err_Invalid_Argument;

    shift = func_interface->shift;
    delta = func_interface->delta;
    first = 0;

    for ( n = 0; n < outline->n_contours; n++ )
    {
      FT_Int  last;  /* index of last point in contour */


      last = outline->contours[n];
      if ( last < 0 )
        goto Invalid_Outline;
      limit = outline->points + last;

      v_start = outline->points[first];
      v_last  = outline->points[last];

      v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
      v_last.x  = SCALED( v_last.x );  v_last.y  = SCALED( v_last.y );

      v_control = v_start;

      point = outline->points + first;
      tags  = outline->tags  + first;
      tag   = FT_CURVE_TAG( tags[0] );

      /* A contour cannot start with a cubic control point! */
      if ( tag == FT_CURVE_TAG_CUBIC )
        goto Invalid_Outline;

      /* check first point to determine origin */
      if ( tag == FT_CURVE_TAG_CONIC )
      {
        /* first point is conic control.  Yes, this happens. */
        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
        {
          /* start at last point if it is on the curve */
          v_start = v_last;
          limit--;
        }
        else
        {
          /* if both first and last points are conic,         */
          /* start at their middle and record its position    */
          /* for closure                                      */
          v_start.x = ( v_start.x + v_last.x ) / 2;
          v_start.y = ( v_start.y + v_last.y ) / 2;

          v_last = v_start;
        }
        point--;
        tags--;
      }

      error = func_interface->move_to( &v_start, user );
      if ( error )
        goto Exit;

      while ( point < limit )
      {
        point++;
        tags++;

        tag = FT_CURVE_TAG( tags[0] );
        switch ( tag )
        {
        case FT_CURVE_TAG_ON:  /* emit a single line_to */
          {
            FT_Vector  vec;


            vec.x = SCALED( point->x );
            vec.y = SCALED( point->y );

            error = func_interface->line_to( &vec, user );
            if ( error )
              goto Exit;
            continue;
          }

        case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
          v_control.x = SCALED( point->x );
          v_control.y = SCALED( point->y );

        Do_Conic:
          if ( point < limit )
          {
            FT_Vector  vec;
            FT_Vector  v_middle;


            point++;
            tags++;
            tag = FT_CURVE_TAG( tags[0] );

            vec.x = SCALED( point->x );
            vec.y = SCALED( point->y );

            if ( tag == FT_CURVE_TAG_ON )
            {
              error = func_interface->conic_to( &v_control, &vec, user );
              if ( error )
                goto Exit;
              continue;
            }

            if ( tag != FT_CURVE_TAG_CONIC )
              goto Invalid_Outline;

            v_middle.x = ( v_control.x + vec.x ) / 2;
            v_middle.y = ( v_control.y + vec.y ) / 2;

            error = func_interface->conic_to( &v_control, &v_middle, user );
            if ( error )
              goto Exit;

            v_control = vec;
            goto Do_Conic;
          }

          error = func_interface->conic_to( &v_control, &v_start, user );
          goto Close;

        default:  /* FT_CURVE_TAG_CUBIC */
          {
            FT_Vector  vec1, vec2;


            if ( point + 1 > limit                             ||
                 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
              goto Invalid_Outline;

            point += 2;
            tags  += 2;

            vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
            vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );

            if ( point <= limit )
            {
              FT_Vector  vec;


              vec.x = SCALED( point->x );
              vec.y = SCALED( point->y );

              error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
              if ( error )
                goto Exit;
              continue;
            }

            error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
            goto Close;
          }
        }
      }

      /* close the contour with a line segment */
      error = func_interface->line_to( &v_start, user );

    Close:
      if ( error )
        goto Exit;

      first = last + 1;
    }

    return 0;

  Exit:
    return error;

  Invalid_Outline:
    return FT_Err_Invalid_Outline;
  }
static ofTTFCharacter makeContoursForCharacter(FT_Face &face){

		//int num			= face->glyph->outline.n_points;
		int nContours	= face->glyph->outline.n_contours;
		int startPos	= 0;

		char * tags		= face->glyph->outline.tags;
		FT_Vector * vec = face->glyph->outline.points;

		ofTTFCharacter charOutlines;

		for(int k = 0; k < nContours; k++){
			if( k > 0 ){
				startPos = face->glyph->outline.contours[k-1]+1;
			}
			int endPos = face->glyph->outline.contours[k]+1;

			if( printVectorInfo )printf("--NEW CONTOUR\n\n");

			vector <ofPoint> testOutline;
			ofPoint lastPoint;

			for(int j = startPos; j < endPos; j++){

				if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_ON ){
					lastPoint.set((float)vec[j].x, (float)-vec[j].y, 0);
					if( printVectorInfo )printf("flag[%i] is set to 1 - regular point - %f %f \n", j, lastPoint.x, lastPoint.y);
					testOutline.push_back(lastPoint);

				}else{
					if( printVectorInfo )printf("flag[%i] is set to 0 - control point \n", j);

					if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_CUBIC ){
						if( printVectorInfo )printf("- bit 2 is set to 2 - CUBIC\n");

						int prevPoint = j-1;
						if( j == 0){
							prevPoint = endPos-1;
						}

						int nextIndex = j+1;
						if( nextIndex >= endPos){
							nextIndex = startPos;
						}

						ofPoint nextPoint( (float)vec[nextIndex].x,  -(float)vec[nextIndex].y );

						//we need two control points to draw a cubic bezier
						bool lastPointCubic =  ( FT_CURVE_TAG(tags[prevPoint]) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG(tags[prevPoint]) == FT_CURVE_TAG_CUBIC);

						if( lastPointCubic ){
							ofPoint controlPoint1((float)vec[prevPoint].x,	(float)-vec[prevPoint].y);
							ofPoint controlPoint2((float)vec[j].x, (float)-vec[j].y);
							ofPoint nextPoint((float) vec[nextIndex].x,	-(float) vec[nextIndex].y);

							cubic_bezier(testOutline, lastPoint.x, lastPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, nextPoint.x, nextPoint.y, 8);
						}

					}else{

						ofPoint conicPoint( (float)vec[j].x,  -(float)vec[j].y );

						if( printVectorInfo )printf("- bit 2 is set to 0 - conic- \n");
						if( printVectorInfo )printf("--- conicPoint point is %f %f \n", conicPoint.x, conicPoint.y);

						//If the first point is connic and the last point is connic then we need to create a virutal point which acts as a wrap around
						if( j == startPos ){
							bool prevIsConnic = (  FT_CURVE_TAG( tags[endPos-1] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[endPos-1]) != FT_CURVE_TAG_CUBIC );

							if( prevIsConnic ){
								ofPoint lastConnic((float)vec[endPos - 1].x, (float)-vec[endPos - 1].y);
								lastPoint = (conicPoint + lastConnic) / 2;

								if( printVectorInfo )	printf("NEED TO MIX WITH LAST\n");
								if( printVectorInfo )printf("last is %f %f \n", lastPoint.x, lastPoint.y);
							}
						}

						//bool doubleConic = false;

						int nextIndex = j+1;
						if( nextIndex >= endPos){
							nextIndex = startPos;
						}

						ofPoint nextPoint( (float)vec[nextIndex].x,  -(float)vec[nextIndex].y );

						if( printVectorInfo )printf("--- last point is %f %f \n", lastPoint.x, lastPoint.y);

						bool nextIsConnic = (  FT_CURVE_TAG( tags[nextIndex] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[nextIndex]) != FT_CURVE_TAG_CUBIC );

						//create a 'virtual on point' if we have two connic points
						if( nextIsConnic ){
							nextPoint = (conicPoint + nextPoint) / 2;
							if( printVectorInfo )printf("|_______ double connic!\n");
						}
						if( printVectorInfo )printf("--- next point is %f %f \n", nextPoint.x, nextPoint.y);

						quad_bezier(testOutline, lastPoint.x, lastPoint.y, conicPoint.x, conicPoint.y, nextPoint.x, nextPoint.y, 8);

						if( nextIsConnic ){
							lastPoint = nextPoint;
						}
					}
				}

			//end for
			}

			for(int g =0; g < (int)testOutline.size(); g++){
				testOutline[g] /= 64.0f;
			}

			charOutlines.contours.push_back(ofTTFContour());

			if( testOutline.size() ){
				charOutlines.contours.back().pts = ofSimplifyContour(testOutline, (float)TTF_SHAPE_SIMPLIFICATION_AMNT);
			}else{
				charOutlines.contours.back().pts = testOutline;
			}
		}

	return charOutlines;
}
Example #7
0
  ah_outline_load( AH_Outline  outline,
                   FT_Fixed    x_scale,
                   FT_Fixed    y_scale,
                   FT_Face     face )
  {
    FT_Memory    memory       = outline->memory;
    FT_Error     error        = AH_Err_Ok;
    FT_Outline*  source       = &face->glyph->outline;
    FT_Int       num_points   = source->n_points;
    FT_Int       num_contours = source->n_contours;
    AH_Point     points;


    /* check arguments */
    if ( !face                                          ||
         !face->size                                    ||
         face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )
      return AH_Err_Invalid_Argument;

    /* first of all, reallocate the contours array if necessary */
    if ( num_contours > outline->max_contours )
    {
      FT_Int  new_contours = ( num_contours + 3 ) & -4;


      if ( FT_RENEW_ARRAY( outline->contours,
                           outline->max_contours,
                           new_contours ) )
        goto Exit;

      outline->max_contours = new_contours;
    }

    /* then, reallocate the points, segments & edges arrays if needed -- */
    /* note that we reserved two additional point positions, used to     */
    /* hint metrics appropriately                                        */
    /*                                                                   */
    if ( num_points + 2 > outline->max_points )
    {
      FT_Int  news = ( num_points + 2 + 7 ) & -8;
      FT_Int  max  = outline->max_points;


      if ( FT_RENEW_ARRAY( outline->points,        max,     news     ) ||
           FT_RENEW_ARRAY( outline->horz_edges,    max * 2, news * 2 ) ||
           FT_RENEW_ARRAY( outline->horz_segments, max * 2, news * 2 ) )
        goto Exit;

      /* readjust some pointers */
      outline->vert_edges    = outline->horz_edges    + news;
      outline->vert_segments = outline->horz_segments + news;
      outline->max_points    = news;
    }

    outline->num_points   = num_points;
    outline->num_contours = num_contours;

    outline->num_hedges    = 0;
    outline->num_vedges    = 0;
    outline->num_hsegments = 0;
    outline->num_vsegments = 0;

    /* We can't rely on the value of `FT_Outline.flags' to know the fill  */
    /* direction used for a glyph, given that some fonts are broken (e.g. */
    /* the Arphic ones). We thus recompute it each time we need to.       */
    /*                                                                    */
    outline->vert_major_dir = AH_DIR_UP;
    outline->horz_major_dir = AH_DIR_LEFT;

    if ( ah_get_orientation( source ) > 1 )
    {
      outline->vert_major_dir = AH_DIR_DOWN;
      outline->horz_major_dir = AH_DIR_RIGHT;
    }

    outline->x_scale = x_scale;
    outline->y_scale = y_scale;

    points = outline->points;
    if ( outline->num_points == 0 )
      goto Exit;

    {
      /* do one thing at a time -- it is easier to understand, and */
      /* the code is clearer                                       */
      AH_Point  point;
      AH_Point  point_limit = points + outline->num_points;


      /* compute coordinates */
      {
        FT_Vector*  vec     = source->points;


        for ( point = points; point < point_limit; vec++, point++ )
        {
          point->fx = vec->x;
          point->fy = vec->y;
          point->ox = point->x = FT_MulFix( vec->x, x_scale );
          point->oy = point->y = FT_MulFix( vec->y, y_scale );

          point->flags = 0;
        }
      }

      /* compute Bezier flags */
      {
        char*  tag = source->tags;


        for ( point = points; point < point_limit; point++, tag++ )
        {
          switch ( FT_CURVE_TAG( *tag ) )
          {
          case FT_CURVE_TAG_CONIC:
            point->flags = AH_FLAG_CONIC; break;
          case FT_CURVE_TAG_CUBIC:
            point->flags = AH_FLAG_CUBIC; break;
          default:
            ;
          }
        }
      }

      /* compute `next' and `prev' */
      {
        FT_Int    contour_index;
        AH_Point  prev;
        AH_Point  first;
        AH_Point  end;


        contour_index = 0;

        first = points;
        end   = points + source->contours[0];
        prev  = end;

        for ( point = points; point < point_limit; point++ )
        {
          point->prev = prev;
          if ( point < end )
          {
            point->next = point + 1;
            prev        = point;
          }
          else
          {
            point->next = first;
            contour_index++;
            if ( point + 1 < point_limit )
            {
              end   = points + source->contours[contour_index];
              first = point + 1;
              prev  = end;
            }
          }
        }
      }

      /* set-up the contours array */
      {
        AH_Point*  contour       = outline->contours;
        AH_Point*  contour_limit = contour + outline->num_contours;
        short*     end           = source->contours;
        short      idx           = 0;


        for ( ; contour < contour_limit; contour++, end++ )
        {
          contour[0] = points + idx;
          idx        = (short)( end[0] + 1 );
        }
      }

      /* compute directions of in & out vectors */
      {
        for ( point = points; point < point_limit; point++ )
        {
          AH_Point   prev;
          AH_Point   next;
          FT_Vector  ivec, ovec;


          prev   = point->prev;
          ivec.x = point->fx - prev->fx;
          ivec.y = point->fy - prev->fy;

          point->in_dir = ah_compute_direction( ivec.x, ivec.y );

          next   = point->next;
          ovec.x = next->fx - point->fx;
          ovec.y = next->fy - point->fy;

          point->out_dir = ah_compute_direction( ovec.x, ovec.y );

#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
          if ( point->flags & (AH_FLAG_CONIC | AH_FLAG_CUBIC) )
          {
          Is_Weak_Point:
            point->flags |= AH_FLAG_WEAK_INTERPOLATION;
          }
          else if ( point->out_dir == point->in_dir )
          {
            AH_Angle  angle_in, angle_out, delta;


            if ( point->out_dir != AH_DIR_NONE )
              goto Is_Weak_Point;

            angle_in  = ah_angle( &ivec );
            angle_out = ah_angle( &ovec );
            delta     = angle_in - angle_out;

            if ( delta > AH_PI )
              delta = AH_2PI - delta;

            if ( delta < 0 )
              delta = -delta;

            if ( delta < 2 )
              goto Is_Weak_Point;
          }
          else if ( point->in_dir == -point->out_dir )
            goto Is_Weak_Point;
#endif
        }
      }
    }

  Exit:
    return error;
  }
Example #8
0
    bool decompose_ft_outline(const FT_Outline& outline,
                              bool flip_y,
                              const mapserver::trans_affine& mtx,
                              PathStorage& path)
    {
        FT_Vector   v_last;
        FT_Vector   v_control;
        FT_Vector   v_start;
        double x1, y1, x2, y2, x3, y3;

        FT_Vector*  point;
        FT_Vector*  limit;
        char*       tags;

        int   n;         // index of contour in outline
        int   first;     // index of first point in contour
        char  tag;       // current point's state

        first = 0;

        for(n = 0; n < outline.n_contours; n++)
        {
            int  last;  // index of last point in contour

            last  = outline.contours[n];
            limit = outline.points + last;

            v_start = outline.points[first];
            v_last  = outline.points[last];

            v_control = v_start;

            point = outline.points + first;
            tags  = outline.tags  + first;
            tag   = FT_CURVE_TAG(tags[0]);

            // A contour cannot start with a cubic control point!
            if(tag == FT_CURVE_TAG_CUBIC) return false;

            // check first point to determine origin
            if( tag == FT_CURVE_TAG_CONIC)
            {
                // first point is conic control.  Yes, this happens.
                if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
                {
                    // start at last point if it is on the curve
                    v_start = v_last;
                    limit--;
                }
                else
                {
                    // if both first and last points are conic,
                    // start at their middle and record its position
                    // for closure
                    v_start.x = (v_start.x + v_last.x) / 2;
                    v_start.y = (v_start.y + v_last.y) / 2;

                    v_last = v_start;
                }
                point--;
                tags--;
            }

            x1 = int26p6_to_dbl(v_start.x);
            y1 = int26p6_to_dbl(v_start.y);
            if(flip_y) y1 = -y1;
            mtx.transform(&x1, &y1);
            path.move_to(x1,y1);

            while(point < limit)
            {
                point++;
                tags++;

                tag = FT_CURVE_TAG(tags[0]);
                switch(tag)
                {
                    case FT_CURVE_TAG_ON:  // emit a single line_to
                    {
                        x1 = int26p6_to_dbl(point->x);
                        y1 = int26p6_to_dbl(point->y);
                        if(flip_y) y1 = -y1;
                        mtx.transform(&x1, &y1);
                        path.line_to(x1,y1);
                        //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y));
                        continue;
                    }

                    case FT_CURVE_TAG_CONIC:  // consume conic arcs
                    {
                        v_control.x = point->x;
                        v_control.y = point->y;

                    Do_Conic:
                        if(point < limit)
                        {
                            FT_Vector vec;
                            FT_Vector v_middle;

                            point++;
                            tags++;
                            tag = FT_CURVE_TAG(tags[0]);

                            vec.x = point->x;
                            vec.y = point->y;

                            if(tag == FT_CURVE_TAG_ON)
                            {
                                x1 = int26p6_to_dbl(v_control.x);
                                y1 = int26p6_to_dbl(v_control.y);
                                x2 = int26p6_to_dbl(vec.x);
                                y2 = int26p6_to_dbl(vec.y);
                                if(flip_y) { y1 = -y1; y2 = -y2; }
                                mtx.transform(&x1, &y1);
                                mtx.transform(&x2, &y2);
                                path.curve3(x1,y1,x2,y2);
                                continue;
                            }

                            if(tag != FT_CURVE_TAG_CONIC) return false;

                            v_middle.x = (v_control.x + vec.x) / 2;
                            v_middle.y = (v_control.y + vec.y) / 2;

                            x1 = int26p6_to_dbl(v_control.x);
                            y1 = int26p6_to_dbl(v_control.y);
                            x2 = int26p6_to_dbl(v_middle.x);
                            y2 = int26p6_to_dbl(v_middle.y);
                            if(flip_y) { y1 = -y1; y2 = -y2; }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            path.curve3(x1,y1,x2,y2);

                            //path.curve3(conv(v_control.x),
                            //            flip_y ? -conv(v_control.y) : conv(v_control.y),
                            //            conv(v_middle.x),
                            //            flip_y ? -conv(v_middle.y) : conv(v_middle.y));

                            v_control = vec;
                            goto Do_Conic;
                        }

                        x1 = int26p6_to_dbl(v_control.x);
                        y1 = int26p6_to_dbl(v_control.y);
                        x2 = int26p6_to_dbl(v_start.x);
                        y2 = int26p6_to_dbl(v_start.y);
                        if(flip_y) { y1 = -y1; y2 = -y2; }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        path.curve3(x1,y1,x2,y2);

                        //path.curve3(conv(v_control.x),
                        //            flip_y ? -conv(v_control.y) : conv(v_control.y),
                        //            conv(v_start.x),
                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
                        goto Close;
                    }

                    default:  // FT_CURVE_TAG_CUBIC
                    {
                        FT_Vector vec1, vec2;

                        if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
                        {
                            return false;
                        }

                        vec1.x = point[0].x;
                        vec1.y = point[0].y;
                        vec2.x = point[1].x;
                        vec2.y = point[1].y;

                        point += 2;
                        tags  += 2;

                        if(point <= limit)
                        {
                            FT_Vector vec;

                            vec.x = point->x;
                            vec.y = point->y;

                            x1 = int26p6_to_dbl(vec1.x);
                            y1 = int26p6_to_dbl(vec1.y);
                            x2 = int26p6_to_dbl(vec2.x);
                            y2 = int26p6_to_dbl(vec2.y);
                            x3 = int26p6_to_dbl(vec.x);
                            y3 = int26p6_to_dbl(vec.y);
                            if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            mtx.transform(&x3, &y3);
                            path.curve4(x1,y1,x2,y2,x3,y3);

                            //path.curve4(conv(vec1.x),
                            //            flip_y ? -conv(vec1.y) : conv(vec1.y),
                            //            conv(vec2.x),
                            //            flip_y ? -conv(vec2.y) : conv(vec2.y),
                            //            conv(vec.x),
                            //            flip_y ? -conv(vec.y) : conv(vec.y));
                            continue;
                        }

                        x1 = int26p6_to_dbl(vec1.x);
                        y1 = int26p6_to_dbl(vec1.y);
                        x2 = int26p6_to_dbl(vec2.x);
                        y2 = int26p6_to_dbl(vec2.y);
                        x3 = int26p6_to_dbl(v_start.x);
                        y3 = int26p6_to_dbl(v_start.y);
                        if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        mtx.transform(&x3, &y3);
                        path.curve4(x1,y1,x2,y2,x3,y3);

                        //path.curve4(conv(vec1.x),
                        //            flip_y ? -conv(vec1.y) : conv(vec1.y),
                        //            conv(vec2.x),
                        //            flip_y ? -conv(vec2.y) : conv(vec2.y),
                        //            conv(v_start.x),
                        //            flip_y ? -conv(v_start.y) : conv(v_start.y));
                        goto Close;
                    }
                }
            }

            path.close_polygon();

       Close:
            first = last + 1;
        }

        return true;
    }
Example #9
0
  static FT_Error
  ah_hinter_compute_blues( AH_Hinter*  hinter )
  {
    AH_Blue       blue;
    AH_Globals*   globals = &hinter->globals->design;
    FT_Pos        flats [MAX_TEST_CHARACTERS];
    FT_Pos        rounds[MAX_TEST_CHARACTERS];
    FT_Int        num_flats;
    FT_Int        num_rounds;

    FT_Face       face;
    FT_GlyphSlot  glyph;
    FT_Error      error;
    FT_CharMap    charmap;


    face  = hinter->face;
    glyph = face->glyph;

    /* save current charmap */
    charmap = face->charmap;

    /* do we have a Unicode charmap in there? */
    error = FT_Select_Charmap( face, ft_encoding_unicode );
    if ( error )
      goto Exit;

    /* we compute the blues simply by loading each character from the */
    /* 'blue_chars[blues]' string, then compute its top-most and      */
    /* bottom-most points                                             */

    AH_LOG(( "blue zones computation\n" ));
    AH_LOG(( "------------------------------------------------\n" ));

    for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
    {
      const char*  p     = blue_chars[blue];
      const char*  limit = p + MAX_TEST_CHARACTERS;
      FT_Pos       *blue_ref, *blue_shoot;


      AH_LOG(( "blue %3d: ", blue ));

      num_flats  = 0;
      num_rounds = 0;

      for ( ; p < limit; p++ )
      {
        FT_UInt     glyph_index;
        FT_Vector*  extremum;
        FT_Vector*  points;
        FT_Vector*  point_limit;
        FT_Vector*  point;
        FT_Bool     round;


        /* exit if we reach the end of the string */
        if ( !*p )
          break;

        AH_LOG(( "`%c'", *p ));

        /* load the character in the face -- skip unknown or empty ones */
        glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
        if ( glyph_index == 0 )
          continue;

        error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
        if ( error || glyph->outline.n_points <= 0 )
          continue;

        /* now compute min or max point indices and coordinates */
        points      = glyph->outline.points;
        point_limit = points + glyph->outline.n_points;
        point       = points;
        extremum    = point;
        point++;

        if ( AH_IS_TOP_BLUE( blue ) )
        {
          for ( ; point < point_limit; point++ )
            if ( point->y > extremum->y )
              extremum = point;
        }
        else
        {
          for ( ; point < point_limit; point++ )
            if ( point->y < extremum->y )
              extremum = point;
        }

        AH_LOG(( "%5d", (int)extremum->y ));

        /* now, check whether the point belongs to a straight or round  */
        /* segment; we first need to find in which contour the extremum */
        /* lies, then see its previous and next points                  */
        {
          FT_Int  idx = (FT_Int)( extremum - points );
          FT_Int  n;
          FT_Int  first, last, prev, next, end;
          FT_Pos  dist;


          last  = -1;
          first = 0;

          for ( n = 0; n < glyph->outline.n_contours; n++ )
          {
            end = glyph->outline.contours[n];
            if ( end >= idx )
            {
              last = end;
              break;
            }
            first = end + 1;
          }

          /* XXX: should never happen! */
          if ( last < 0 )
            continue;

          /* now look for the previous and next points that are not on the */
          /* same Y coordinate.  Threshold the `closeness'...              */

          prev = idx;
          next = prev;

          do
          {
            if ( prev > first )
              prev--;
            else
              prev = last;

            dist = points[prev].y - extremum->y;
            if ( dist < -5 || dist > 5 )
              break;

          } while ( prev != idx );

          do
          {
            if ( next < last )
              next++;
            else
              next = first;

            dist = points[next].y - extremum->y;
            if ( dist < -5 || dist > 5 )
              break;

          } while ( next != idx );

          /* now, set the `round' flag depending on the segment's kind */
          round = FT_BOOL(
            FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_Curve_Tag_On ||
            FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_Curve_Tag_On );

          AH_LOG(( "%c ", round ? 'r' : 'f' ));
        }

        if ( round )
          rounds[num_rounds++] = extremum->y;
        else
          flats[num_flats++] = extremum->y;
      }

      AH_LOG(( "\n" ));

      /* we have computed the contents of the `rounds' and `flats' tables, */
      /* now determine the reference and overshoot position of the blue;   */
      /* we simply take the median value after a simple short              */
      sort_values( num_rounds, rounds );
      sort_values( num_flats,  flats  );

      blue_ref   = globals->blue_refs + blue;
      blue_shoot = globals->blue_shoots + blue;
      if ( num_flats == 0 && num_rounds == 0 )
      {
        *blue_ref   = -10000;
        *blue_shoot = -10000;
      }
      else if ( num_flats == 0 )
      {
        *blue_ref   =
        *blue_shoot = rounds[num_rounds / 2];
      }
      else if ( num_rounds == 0 )
      {
        *blue_ref   =
        *blue_shoot = flats[num_flats / 2];
      }
      else
      {
        *blue_ref   = flats[num_flats / 2];
        *blue_shoot = rounds[num_rounds / 2];
      }

      /* there are sometimes problems: if the overshoot position of top     */
      /* zones is under its reference position, or the opposite for bottom  */
      /* zones.  We must thus check everything there and correct the errors */
      if ( *blue_shoot != *blue_ref )
      {
        FT_Pos   ref      = *blue_ref;
        FT_Pos   shoot    = *blue_shoot;
        FT_Bool  over_ref = FT_BOOL( shoot > ref );


        if ( AH_IS_TOP_BLUE( blue ) ^ over_ref )
          *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
      }

      AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
    }

    /* reset original face charmap */
    FT_Set_Charmap( face, charmap );
    error = 0;

  Exit:
    return error;
  }
Example #10
0
  static void
  af_latin_metrics_init_blues( AF_LatinMetrics  metrics,
                               FT_Face          face )
  {
    FT_Pos        flats [AF_LATIN_MAX_TEST_CHARACTERS];
    FT_Pos        rounds[AF_LATIN_MAX_TEST_CHARACTERS];
    FT_Int        num_flats;
    FT_Int        num_rounds;
    FT_Int        bb;
    AF_LatinBlue  blue;
    FT_Error      error;
    AF_LatinAxis  axis  = &metrics->axis[AF_DIMENSION_VERT];
    FT_GlyphSlot  glyph = face->glyph;


    /* we compute the blues simply by loading each character from the    */
    /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
    /* bottom-most points (depending on `AF_IS_TOP_BLUE')                */

    AF_LOG(( "blue zones computation\n" ));
    AF_LOG(( "------------------------------------------------\n" ));

    for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
    {
      const char*  p     = af_latin_blue_chars[bb];
      const char*  limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
      FT_Pos*      blue_ref;
      FT_Pos*      blue_shoot;


      AF_LOG(( "blue %3d: ", bb ));

      num_flats  = 0;
      num_rounds = 0;

      for ( ; p < limit && *p; p++ )
      {
        FT_UInt     glyph_index;
        FT_Int      best_point, best_y, best_first, best_last;
        FT_Vector*  points;
        FT_Bool     round = 0;


        AF_LOG(( "'%c'", *p ));

        /* load the character in the face -- skip unknown or empty ones */
        glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
        if ( glyph_index == 0 )
          continue;

        error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
        if ( error || glyph->outline.n_points <= 0 )
          continue;

        /* now compute min or max point indices and coordinates */
        points      = glyph->outline.points;
        best_point  = -1;
        best_y      = 0;  /* make compiler happy */
        best_first  = 0;  /* ditto */
        best_last   = 0;  /* ditto */

        {
          FT_Int  nn;
          FT_Int  first = 0;
          FT_Int  last  = -1;


          for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
          {
            FT_Int  old_best_point = best_point;
            FT_Int  pp;


            last = glyph->outline.contours[nn];

            /* Avoid single-point contours since they are never rasterized. */
            /* In some fonts, they correspond to mark attachment points     */
            /* which are way outside of the glyph's real outline.           */
            if ( last <= first )
                continue;

            if ( AF_LATIN_IS_TOP_BLUE( bb ) )
            {
              for ( pp = first; pp <= last; pp++ )
                if ( best_point < 0 || points[pp].y > best_y )
                {
                  best_point = pp;
                  best_y     = points[pp].y;
                }
            }
            else
            {
              for ( pp = first; pp <= last; pp++ )
                if ( best_point < 0 || points[pp].y < best_y )
                {
                  best_point = pp;
                  best_y     = points[pp].y;
                }
            }

            if ( best_point != old_best_point )
            {
              best_first = first;
              best_last  = last;
            }
          }
          AF_LOG(( "%5d", best_y ));
        }

        /* now check whether the point belongs to a straight or round   */
        /* segment; we first need to find in which contour the extremum */
        /* lies, then inspect its previous and next points              */
        if ( best_point >= 0 )
        {
          FT_Int  prev, next;
          FT_Pos  dist;


          /* now look for the previous and next points that are not on the */
          /* same Y coordinate.  Threshold the `closeness'...              */
          prev = best_point;
          next = prev;

          do
          {
            if ( prev > best_first )
              prev--;
            else
              prev = best_last;

            dist = points[prev].y - best_y;
            if ( dist < -5 || dist > 5 )
              break;

          } while ( prev != best_point );

          do
          {
            if ( next < best_last )
              next++;
            else
              next = best_first;

            dist = points[next].y - best_y;
            if ( dist < -5 || dist > 5 )
              break;

          } while ( next != best_point );

          /* now, set the `round' flag depending on the segment's kind */
          round = FT_BOOL(
            FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
            FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );

          AF_LOG(( "%c ", round ? 'r' : 'f' ));
        }

        if ( round )
          rounds[num_rounds++] = best_y;
        else
          flats[num_flats++]   = best_y;
      }

      AF_LOG(( "\n" ));

      if ( num_flats == 0 && num_rounds == 0 )
      {
        /*
         *  we couldn't find a single glyph to compute this blue zone,
         *  we will simply ignore it then
         */
        AF_LOG(( "empty!\n" ));
        continue;
      }

      /* we have computed the contents of the `rounds' and `flats' tables, */
      /* now determine the reference and overshoot position of the blue -- */
      /* we simply take the median value after a simple sort               */
      af_sort_pos( num_rounds, rounds );
      af_sort_pos( num_flats,  flats );

      blue       = & axis->blues[axis->blue_count];
      blue_ref   = & blue->ref.org;
      blue_shoot = & blue->shoot.org;

      axis->blue_count++;

      if ( num_flats == 0 )
      {
        *blue_ref   =
        *blue_shoot = rounds[num_rounds / 2];
      }
      else if ( num_rounds == 0 )
      {
        *blue_ref   =
        *blue_shoot = flats[num_flats / 2];
      }
      else
      {
        *blue_ref   = flats[num_flats / 2];
        *blue_shoot = rounds[num_rounds / 2];
      }

      /* there are sometimes problems: if the overshoot position of top     */
      /* zones is under its reference position, or the opposite for bottom  */
      /* zones.  We must thus check everything there and correct the errors */
      if ( *blue_shoot != *blue_ref )
      {
        FT_Pos   ref      = *blue_ref;
        FT_Pos   shoot    = *blue_shoot;
        FT_Bool  over_ref = FT_BOOL( shoot > ref );


        if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
          *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
      }

      blue->flags = 0;
      if ( AF_LATIN_IS_TOP_BLUE( bb ) )
        blue->flags |= AF_LATIN_BLUE_TOP;

      /*
       * The following flags is used later to adjust the y and x scales
       * in order to optimize the pixel grid alignment of the top of small
       * letters.
       */
      if ( bb == AF_LATIN_BLUE_SMALL_TOP )
        blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;

      AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
    }

    return;
  }
Example #11
0
af_glyph_hints_reload( AF_GlyphHints     hints,
                       FT_Outline*       outline )
{
    FT_Error     error        = FT_Err_Ok;
    AF_Point     points;
    FT_UInt      old_max, new_max;
    AF_Scaler    scaler  = &hints->metrics->scaler;
    FT_Fixed     x_scale = hints->x_scale;
    FT_Fixed     y_scale = hints->y_scale;
    FT_Pos       x_delta = hints->x_delta;
    FT_Pos       y_delta = hints->y_delta;
    FT_Memory    memory  = hints->memory;

    hints->scaler_flags  = scaler->flags;
    hints->num_points    = 0;
    hints->num_contours  = 0;

    hints->axis[0].num_segments = 0;
    hints->axis[0].num_edges    = 0;
    hints->axis[1].num_segments = 0;
    hints->axis[1].num_edges    = 0;

    /* first of all, reallocate the contours array when necessary
     */
    new_max = (FT_UInt) outline->n_contours;
    old_max = hints->max_contours;
    if ( new_max > old_max )
    {
        new_max = (new_max + 3) & ~3;

        if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
            goto Exit;

        hints->max_contours = new_max;
    }

    /* then, reallocate the points, segments & edges arrays if needed --
     * note that we reserved two additional point positions, used to
     * hint metrics appropriately
     */
    new_max = (FT_UInt)( outline->n_points + 2 );
    old_max = hints->max_points;
    if ( new_max > old_max )
    {
        FT_Byte*    items;
        FT_ULong    off1, off2, off3;

        /* we store in a single buffer the following arrays:
         *
         *  - an array of   N  AF_PointRec   items
         *  - an array of 2*N  AF_SegmentRec items
         *  - an array of 2*N  AF_EdgeRec    items
         *
         */

        new_max = ( new_max + 2 + 7 ) & ~7;

#define OFF_PAD2(x,y)   (((x)+(y)-1) & ~((y)-1))
#define OFF_PADX(x,y)   ((((x)+(y)-1)/(y))*(y))
#define OFF_PAD(x,y)    ( ((y) & ((y)-1)) ? OFF_PADX(x,y) : OFF_PAD2(x,y) )

#undef  OFF_INCREMENT
#define OFF_INCREMENT( _off, _type, _count )   \
     ( OFF_PAD( _off, sizeof(_type) ) + (_count)*sizeof(_type))

        off1 = OFF_INCREMENT( 0, AF_PointRec, new_max );
        off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max*2 );
        off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 );

        FT_FREE( hints->points );

        if ( FT_ALLOC( items, off3 ) )
        {
            hints->max_points       = 0;
            hints->axis[0].segments = NULL;
            hints->axis[0].edges    = NULL;
            hints->axis[1].segments = NULL;
            hints->axis[1].edges    = NULL;
            goto Exit;
        }

        /* readjust some pointers
         */
        hints->max_points       = new_max;
        hints->points           = (AF_Point) items;

        hints->axis[0].segments = (AF_Segment)( items + off1 );
        hints->axis[1].segments = hints->axis[0].segments + new_max;

        hints->axis[0].edges    = (AF_Edge)   ( items + off2 );
        hints->axis[1].edges    = hints->axis[0].edges + new_max;
    }

    hints->num_points   = outline->n_points;
    hints->num_contours = outline->n_contours;


    /* We can't rely on the value of `FT_Outline.flags' to know the fill  */
    /* direction used for a glyph, given that some fonts are broken (e.g. */
    /* the Arphic ones).  We thus recompute it each time we need to.      */
    /*                                                                    */
    hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP;
    hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT;

    if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
    {
        hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN;
        hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT;
    }

    hints->x_scale = x_scale;
    hints->y_scale = y_scale;
    hints->x_delta = x_delta;
    hints->y_delta = y_delta;

    points = hints->points;
    if ( hints->num_points == 0 )
        goto Exit;

    {
        AF_Point  point;
        AF_Point  point_limit = points + hints->num_points;


        /* compute coordinates & bezier flags */
        {
            FT_Vector*  vec = outline->points;
            char*       tag = outline->tags;


            for ( point = points; point < point_limit; point++, vec++, tag++ )
            {
                point->fx = vec->x;
                point->fy = vec->y;
                point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
                point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;

                switch ( FT_CURVE_TAG( *tag ) )
                {
                case FT_CURVE_TAG_CONIC:
                    point->flags = AF_FLAG_CONIC;
                    break;
                case FT_CURVE_TAG_CUBIC:
                    point->flags = AF_FLAG_CUBIC;
                    break;
                default:
                    point->flags = 0;
                    ;
                }
            }
        }

        /* compute `next' and `prev' */
        {
            FT_Int    contour_index;
            AF_Point  prev;
            AF_Point  first;
            AF_Point  end;


            contour_index = 0;

            first = points;
            end   = points + outline->contours[0];
            prev  = end;

            for ( point = points; point < point_limit; point++ )
            {
                point->prev = prev;
                if ( point < end )
                {
                    point->next = point + 1;
                    prev        = point;
                }
                else
                {
                    point->next = first;
                    contour_index++;
                    if ( point + 1 < point_limit )
                    {
                        end   = points + outline->contours[contour_index];
                        first = point + 1;
                        prev  = end;
                    }
                }
            }
        }

        /* set-up the contours array */
        {
            AF_Point*  contour       = hints->contours;
            AF_Point*  contour_limit = contour + hints->num_contours;
            short*     end           = outline->contours;
            short      idx           = 0;


            for ( ; contour < contour_limit; contour++, end++ )
            {
                contour[0] = points + idx;
                idx        = (short)( end[0] + 1 );
            }
        }

        /* compute directions of in & out vectors */
        {
            for ( point = points; point < point_limit; point++ )
            {
                AF_Point   prev;
                AF_Point   next;
                FT_Pos     in_x, in_y, out_x, out_y;


                prev   = point->prev;
                in_x   = point->fx - prev->fx;
                in_y   = point->fy - prev->fy;

                point->in_dir = af_direction_compute( in_x, in_y );

                next   = point->next;
                out_x  = next->fx - point->fx;
                out_y  = next->fy - point->fy;

                point->out_dir = af_direction_compute( out_x, out_y );

                if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
                {
Is_Weak_Point:
                    point->flags |= AF_FLAG_WEAK_INTERPOLATION;
                }
                else if ( point->out_dir == point->in_dir )
                {
                    AF_Angle  angle_in, angle_out, delta;


                    if ( point->out_dir != AF_DIR_NONE )
                        goto Is_Weak_Point;

                    angle_in  = af_angle_atan( in_x, in_y );
                    angle_out = af_angle_atan( out_x, out_y );
                    delta     = af_angle_diff( angle_in, angle_out );

                    if ( delta < 2 && delta > -2 )
                        goto Is_Weak_Point;
                }
                else if ( point->in_dir == -point->out_dir )
                    goto Is_Weak_Point;
            }
        }
    }

    /* compute inflection points
     */
    af_glyph_hints_compute_inflections( hints );

Exit:
    return error;
}
Example #12
0
bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy)
{
	FT_Vector   v_last;
	FT_Vector   v_control;
	FT_Vector   v_start;
	FT_Vector*  point;
	FT_Vector*  limit;
	char*       tags;
	int   n;         // index of contour in outline
	char  tag;       // current point's state
	int   first = 0; // index of first point in contour
	for(n = 0; n < outline.n_contours; n++) {
		int  last = outline.contours[n];
		limit = outline.points + last;
		v_start = outline.points[first];
		v_last  = outline.points[last];
		v_control = v_start;
		point = outline.points + first;
		tags  = outline.tags  + first;
		tag   = FT_CURVE_TAG(tags[0]);
		if(tag == FT_CURVE_TAG_CUBIC) return false;
		if(tag == FT_CURVE_TAG_CONIC) {
			if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
				// start at last point if it is on the curve
				v_start = v_last;
				limit--;
			}
			else {
				// if both first and last points are conic,
				// start at their middle and record its position
				// for closure
				v_start.x = (v_start.x + v_last.x) / 2;
				v_start.y = (v_start.y + v_last.y) / 2;
				v_last = v_start;
			}
			point--;
			tags--;
		}
		path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
		while(point < limit) {
			point++;
			tags++;

			tag = FT_CURVE_TAG(tags[0]);
			switch(tag) {
			case FT_CURVE_TAG_ON:
				path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy);
				continue;
			case FT_CURVE_TAG_CONIC:
				v_control.x = point->x;
				v_control.y = point->y;
			Do_Conic:
				if(point < limit) {
					FT_Vector vec;
					FT_Vector v_middle;
					point++;
					tags++;
					tag = FT_CURVE_TAG(tags[0]);
					vec.x = point->x;
					vec.y = point->y;
					if(tag == FT_CURVE_TAG_ON) {
						path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
						               ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
						continue;
					}
					if(tag != FT_CURVE_TAG_CONIC) return false;
					v_middle.x = (v_control.x + vec.x) / 2;
					v_middle.y = (v_control.y + vec.y) / 2;
					path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
					               ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy);
					v_control = vec;
					goto Do_Conic;
				}
				path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
				               ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
				goto Close;

			default:
				FT_Vector vec1, vec2;
				if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
				    return false;
				vec1.x = point[0].x; 
				vec1.y = point[0].y;
				vec2.x = point[1].x; 
				vec2.y = point[1].y;
				point += 2;
				tags  += 2;
				if(point <= limit) {
					FT_Vector vec;
					vec.x = point->x;
					vec.y = point->y;
					path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
					           ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
					           ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
					continue;
				}
				path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
				           ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
				           ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
				goto Close;
			}
		}
	Close:
		path.Close();
		first = last + 1; 
    }
	return true;
}
Example #13
0
FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n)
{
    FTPoint prev, cur(contour[(n - 1) % n]), next(contour[0]);
    FTPoint a, b = next - cur;
    double olddir, dir = atan2((next - cur).Y(), (next - cur).X());
    double angle = 0.0;

    // See http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
    // for a full description of FreeType tags.
    for(unsigned int i = 0; i < n; i++)
    {
        prev = cur;
        cur = next;
        next = FTPoint(contour[(i + 1) % n]);
        olddir = dir;
        dir = atan2((next - cur).Y(), (next - cur).X());

        // Compute our path's new direction.
        double t = dir - olddir;
        if(t < -M_PI) t += 2 * M_PI;
        if(t > M_PI) t -= 2 * M_PI;
        angle += t;

        // Only process point tags we know.
        if(n < 2 || FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_On)
        {
            AddPoint(cur);
        }
        else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Conic)
        {
            FTPoint prev2 = prev, next2 = next;

            // Previous point is either the real previous point (an "on"
            // point), or the midpoint between the current one and the
            // previous "conic off" point.
            if(FT_CURVE_TAG(tags[(i - 1 + n) % n]) == FT_Curve_Tag_Conic)
            {
                prev2 = (cur + prev) * 0.5;
                AddPoint(prev2);
            }

            // Next point is either the real next point or the midpoint.
            if(FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Conic)
            {
                next2 = (cur + next) * 0.5;
            }

            evaluateQuadraticCurve(prev2, cur, next2);
        }
        else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Cubic
                 && FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Cubic)
        {
            evaluateCubicCurve(prev, cur, next,
                               FTPoint(contour[(i + 2) % n]));
        }
    }

    // If final angle is positive (+2PI), it's an anti-clockwise contour,
    // otherwise (-2PI) it's clockwise.
    clockwise = (angle < 0.0);
}