-/***************************************************************************/
-/* */
-/* ftoutln.c */
-/* */
-/* FreeType outline management (body). */
-/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
-/* David Turner, Robert Wilhelm, and Werner Lemberg. */
-/* */
-/* This file is part of the FreeType project, and may only be used, */
-/* modified, and distributed under the terms of the FreeType project */
-/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
-/* this file you indicate that you have read the license and */
-/* understand and accept it fully. */
-/* */
-/***************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* All functions are declared in freetype.h. */
- /* */
- /*************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_OUTLINE_H
-#include FT_INTERNAL_OBJECTS_H
-#include FT_TRIGONOMETRY_H
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_outline
-
-
- static
- const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Decompose( 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;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_New_Internal( FT_Memory memory,
- FT_UInt numPoints,
- FT_Int numContours,
- FT_Outline *anoutline )
- {
- FT_Error error;
-
-
- if ( !anoutline || !memory )
- return FT_Err_Invalid_Argument;
-
- *anoutline = null_outline;
-
- if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) ||
- FT_NEW_ARRAY( anoutline->tags, numPoints ) ||
- FT_NEW_ARRAY( anoutline->contours, numContours ) )
- goto Fail;
-
- anoutline->n_points = (FT_UShort)numPoints;
- anoutline->n_contours = (FT_Short)numContours;
- anoutline->flags |= FT_OUTLINE_OWNER;
-
- return FT_Err_Ok;
-
- Fail:
- anoutline->flags |= FT_OUTLINE_OWNER;
- FT_Outline_Done_Internal( memory, anoutline );
-
- return error;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_New( FT_Library library,
- FT_UInt numPoints,
- FT_Int numContours,
- FT_Outline *anoutline )
- {
- if ( !library )
- return FT_Err_Invalid_Library_Handle;
-
- return FT_Outline_New_Internal( library->memory, numPoints,
- numContours, anoutline );
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Check( FT_Outline* outline )
- {
- if ( outline )
- {
- FT_Int n_points = outline->n_points;
- FT_Int n_contours = outline->n_contours;
- FT_Int end0, end;
- FT_Int n;
-
-
- /* empty glyph? */
- if ( n_points == 0 && n_contours == 0 )
- return 0;
-
- /* check point and contour counts */
- if ( n_points <= 0 || n_contours <= 0 )
- goto Bad;
-
- end0 = end = -1;
- for ( n = 0; n < n_contours; n++ )
- {
- end = outline->contours[n];
-
- /* note that we don't accept empty contours */
- if ( end <= end0 || end >= n_points )
- goto Bad;
-
- end0 = end;
- }
-
- if ( end != n_points - 1 )
- goto Bad;
-
- /* XXX: check the tags array */
- return 0;
- }
-
- Bad:
- return FT_Err_Invalid_Argument;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Copy( const FT_Outline* source,
- FT_Outline *target )
- {
- FT_Int is_owner;
-
-
- if ( !source || !target ||
- source->n_points != target->n_points ||
- source->n_contours != target->n_contours )
- return FT_Err_Invalid_Argument;
-
- if ( source == target )
- return FT_Err_Ok;
-
- FT_ARRAY_COPY( target->points, source->points, source->n_points );
-
- FT_ARRAY_COPY( target->tags, source->tags, source->n_points );
-
- FT_ARRAY_COPY( target->contours, source->contours, source->n_contours );
-
- /* copy all flags, except the `FT_OUTLINE_OWNER' one */
- is_owner = target->flags & FT_OUTLINE_OWNER;
- target->flags = source->flags;
-
- target->flags &= ~FT_OUTLINE_OWNER;
- target->flags |= is_owner;
-
- return FT_Err_Ok;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Done_Internal( FT_Memory memory,
- FT_Outline* outline )
- {
- if ( memory && outline )
- {
- if ( outline->flags & FT_OUTLINE_OWNER )
- {
- FT_FREE( outline->points );
- FT_FREE( outline->tags );
- FT_FREE( outline->contours );
- }
- *outline = null_outline;
-
- return FT_Err_Ok;
- }
- else
- return FT_Err_Invalid_Argument;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Done( FT_Library library,
- FT_Outline* outline )
- {
- /* check for valid `outline' in FT_Outline_Done_Internal() */
-
- if ( !library )
- return FT_Err_Invalid_Library_Handle;
-
- return FT_Outline_Done_Internal( library->memory, outline );
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( void )
- FT_Outline_Get_CBox( const FT_Outline* outline,
- FT_BBox *acbox )
- {
- FT_Pos xMin, yMin, xMax, yMax;
-
-
- if ( outline && acbox )
- {
- if ( outline->n_points == 0 )
- {
- xMin = 0;
- yMin = 0;
- xMax = 0;
- yMax = 0;
- }
- else
- {
- FT_Vector* vec = outline->points;
- FT_Vector* limit = vec + outline->n_points;
-
-
- xMin = xMax = vec->x;
- yMin = yMax = vec->y;
- vec++;
-
- for ( ; vec < limit; vec++ )
- {
- FT_Pos x, y;
-
-
- x = vec->x;
- if ( x < xMin ) xMin = x;
- if ( x > xMax ) xMax = x;
-
- y = vec->y;
- if ( y < yMin ) yMin = y;
- if ( y > yMax ) yMax = y;
- }
- }
- acbox->xMin = xMin;
- acbox->xMax = xMax;
- acbox->yMin = yMin;
- acbox->yMax = yMax;
- }
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( void )
- FT_Outline_Translate( const FT_Outline* outline,
- FT_Pos xOffset,
- FT_Pos yOffset )
- {
- FT_UShort n;
- FT_Vector* vec = outline->points;
-
-
- if ( !outline )
- return;
-
- for ( n = 0; n < outline->n_points; n++ )
- {
- vec->x += xOffset;
- vec->y += yOffset;
- vec++;
- }
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( void )
- FT_Outline_Reverse( FT_Outline* outline )
- {
- FT_UShort n;
- FT_Int first, last;
-
-
- if ( !outline )
- return;
-
- first = 0;
-
- for ( n = 0; n < outline->n_contours; n++ )
- {
- last = outline->contours[n];
-
- /* reverse point table */
- {
- FT_Vector* p = outline->points + first;
- FT_Vector* q = outline->points + last;
- FT_Vector swap;
-
-
- while ( p < q )
- {
- swap = *p;
- *p = *q;
- *q = swap;
- p++;
- q--;
- }
- }
-
- /* reverse tags table */
- {
- char* p = outline->tags + first;
- char* q = outline->tags + last;
- char swap;
-
-
- while ( p < q )
- {
- swap = *p;
- *p = *q;
- *q = swap;
- p++;
- q--;
- }
- }
-
- first = last + 1;
- }
-
- outline->flags ^= FT_OUTLINE_REVERSE_FILL;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Render( FT_Library library,
- FT_Outline* outline,
- FT_Raster_Params* params )
- {
- FT_Error error;
- FT_Bool update = 0;
- FT_Renderer renderer;
- FT_ListNode node;
-
-
- if ( !library )
- return FT_Err_Invalid_Library_Handle;
-
- if ( !outline || !params )
- return FT_Err_Invalid_Argument;
-
- renderer = library->cur_renderer;
- node = library->renderers.head;
-
- params->source = (void*)outline;
-
- error = FT_Err_Cannot_Render_Glyph;
- while ( renderer )
- {
- error = renderer->raster_render( renderer->raster, params );
- if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
- break;
-
- /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
- /* is unsupported by the current renderer for this glyph image */
- /* format */
-
- /* now, look for another renderer that supports the same */
- /* format */
- renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,
- &node );
- update = 1;
- }
-
- /* if we changed the current renderer for the glyph image format */
- /* we need to select it as the next current one */
- if ( !error && update && renderer )
- FT_Set_Renderer( library, renderer, 0, 0 );
-
- return error;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Get_Bitmap( FT_Library library,
- FT_Outline* outline,
- const FT_Bitmap *abitmap )
- {
- FT_Raster_Params params;
-
-
- if ( !abitmap )
- return FT_Err_Invalid_Argument;
-
- /* other checks are delayed to FT_Outline_Render() */
-
- params.target = abitmap;
- params.flags = 0;
-
- if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
- abitmap->pixel_mode == FT_PIXEL_MODE_LCD ||
- abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
- params.flags |= FT_RASTER_FLAG_AA;
-
- return FT_Outline_Render( library, outline, ¶ms );
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( void )
- FT_Vector_Transform( FT_Vector* vector,
- const FT_Matrix* matrix )
- {
- FT_Pos xz, yz;
-
-
- if ( !vector || !matrix )
- return;
-
- xz = FT_MulFix( vector->x, matrix->xx ) +
- FT_MulFix( vector->y, matrix->xy );
-
- yz = FT_MulFix( vector->x, matrix->yx ) +
- FT_MulFix( vector->y, matrix->yy );
-
- vector->x = xz;
- vector->y = yz;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( void )
- FT_Outline_Transform( const FT_Outline* outline,
- const FT_Matrix* matrix )
- {
- FT_Vector* vec;
- FT_Vector* limit;
-
-
- if ( !outline || !matrix )
- return;
-
- vec = outline->points;
- limit = vec + outline->n_points;
-
- for ( ; vec < limit; vec++ )
- FT_Vector_Transform( vec, matrix );
- }
-
-
-#if 0
-
-#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \
- do { \
- (first) = ( c > 0 ) ? (outline)->points + \
- (outline)->contours[c - 1] + 1 \
- : (outline)->points; \
- (last) = (outline)->points + (outline)->contours[c]; \
- } while ( 0 )
-
-
- /* Is a point in some contour? */
- /* */
- /* We treat every point of the contour as if it */
- /* it were ON. That is, we allow false positives, */
- /* but disallow false negatives. (XXX really?) */
- static FT_Bool
- ft_contour_has( FT_Outline* outline,
- FT_Short c,
- FT_Vector* point )
- {
- FT_Vector* first;
- FT_Vector* last;
- FT_Vector* a;
- FT_Vector* b;
- FT_UInt n = 0;
-
-
- FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
-
- for ( a = first; a <= last; a++ )
- {
- FT_Pos x;
- FT_Int intersect;
-
-
- b = ( a == last ) ? first : a + 1;
-
- intersect = ( a->y - point->y ) ^ ( b->y - point->y );
-
- /* a and b are on the same side */
- if ( intersect >= 0 )
- {
- if ( intersect == 0 && a->y == point->y )
- {
- if ( ( a->x <= point->x && b->x >= point->x ) ||
- ( a->x >= point->x && b->x <= point->x ) )
- return 1;
- }
-
- continue;
- }
-
- x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y );
-
- if ( x < point->x )
- n++;
- else if ( x == point->x )
- return 1;
- }
-
- return ( n % 2 );
- }
-
-
- static FT_Bool
- ft_contour_enclosed( FT_Outline* outline,
- FT_UShort c )
- {
- FT_Vector* first;
- FT_Vector* last;
- FT_Short i;
-
-
- FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
-
- for ( i = 0; i < outline->n_contours; i++ )
- {
- if ( i != c && ft_contour_has( outline, i, first ) )
- {
- FT_Vector* pt;
-
-
- for ( pt = first + 1; pt <= last; pt++ )
- if ( !ft_contour_has( outline, i, pt ) )
- return 0;
-
- return 1;
- }
- }
-
- return 0;
- }
-
-
- /* This version differs from the public one in that each */
- /* part (contour not enclosed in another contour) of the */
- /* outline is checked for orientation. This is */
- /* necessary for some buggy CJK fonts. */
- static FT_Orientation
- ft_outline_get_orientation( FT_Outline* outline )
- {
- FT_Short i;
- FT_Vector* first;
- FT_Vector* last;
- FT_Orientation orient = FT_ORIENTATION_NONE;
-
-
- first = outline->points;
- for ( i = 0; i < outline->n_contours; i++, first = last + 1 )
- {
- FT_Vector* point;
- FT_Vector* xmin_point;
- FT_Pos xmin;
-
-
- last = outline->points + outline->contours[i];
-
- /* skip degenerate contours */
- if ( last < first + 2 )
- continue;
-
- if ( ft_contour_enclosed( outline, i ) )
- continue;
-
- xmin = first->x;
- xmin_point = first;
-
- for ( point = first + 1; point <= last; point++ )
- {
- if ( point->x < xmin )
- {
- xmin = point->x;
- xmin_point = point;
- }
- }
-
- /* check the orientation of the contour */
- {
- FT_Vector* prev;
- FT_Vector* next;
- FT_Orientation o;
-
-
- prev = ( xmin_point == first ) ? last : xmin_point - 1;
- next = ( xmin_point == last ) ? first : xmin_point + 1;
-
- if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
- FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
- o = FT_ORIENTATION_POSTSCRIPT;
- else
- o = FT_ORIENTATION_TRUETYPE;
-
- if ( orient == FT_ORIENTATION_NONE )
- orient = o;
- else if ( orient != o )
- return FT_ORIENTATION_NONE;
- }
- }
-
- return orient;
- }
-
-#endif /* 0 */
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Error )
- FT_Outline_Embolden( FT_Outline* outline,
- FT_Pos strength )
- {
- FT_Vector* points;
- FT_Vector v_prev, v_first, v_next, v_cur;
- FT_Angle rotate, angle_in, angle_out;
- FT_Int c, n, first;
- FT_Int orientation;
-
-
- if ( !outline )
- return FT_Err_Invalid_Argument;
-
- strength /= 2;
- if ( strength == 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;
- }
-
- if ( orientation == FT_ORIENTATION_TRUETYPE )
- rotate = -FT_ANGLE_PI2;
- else
- rotate = FT_ANGLE_PI2;
-
- points = outline->points;
-
- first = 0;
- for ( c = 0; c < outline->n_contours; c++ )
- {
- int last = outline->contours[c];
-
-
- v_first = points[first];
- v_prev = points[last];
- v_cur = v_first;
-
- for ( n = first; n <= last; n++ )
- {
- FT_Vector in, out;
- FT_Angle angle_diff;
- FT_Pos d;
- FT_Fixed scale;
-
-
- if ( n < last )
- v_next = points[n + 1];
- else
- v_next = v_first;
-
- /* compute the in and out vectors */
- in.x = v_cur.x - v_prev.x;
- in.y = v_cur.y - v_prev.y;
-
- out.x = v_next.x - v_cur.x;
- out.y = v_next.y - v_cur.y;
-
- angle_in = FT_Atan2( in.x, in.y );
- angle_out = FT_Atan2( out.x, out.y );
- angle_diff = FT_Angle_Diff( angle_in, angle_out );
- scale = FT_Cos( angle_diff / 2 );
-
- if ( scale < 0x4000L && scale > -0x4000L )
- in.x = in.y = 0;
- else
- {
- d = FT_DivFix( strength, scale );
-
- FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
- }
-
- outline->points[n].x = v_cur.x + strength + in.x;
- outline->points[n].y = v_cur.y + strength + in.y;
-
- v_prev = v_cur;
- v_cur = v_next;
- }
-
- first = last + 1;
- }
-
- return FT_Err_Ok;
- }
-
-
- /* documentation is in ftoutln.h */
-
- FT_EXPORT_DEF( FT_Orientation )
- 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;
- }
-
-
-/* END */
+/***************************************************************************/\r
+/* */\r
+/* ftoutln.c */\r
+/* */\r
+/* FreeType outline management (body). */\r
+/* */\r
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */\r
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */\r
+/* */\r
+/* This file is part of the FreeType project, and may only be used, */\r
+/* modified, and distributed under the terms of the FreeType project */\r
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */\r
+/* this file you indicate that you have read the license and */\r
+/* understand and accept it fully. */\r
+/* */\r
+/***************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* All functions are declared in freetype.h. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+#include <ft2build.h>\r
+#include FT_OUTLINE_H\r
+#include FT_INTERNAL_OBJECTS_H\r
+#include FT_TRIGONOMETRY_H\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */\r
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */\r
+ /* messages during execution. */\r
+ /* */\r
+#undef FT_COMPONENT\r
+#define FT_COMPONENT trace_outline\r
+\r
+\r
+ static\r
+ const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Decompose( FT_Outline* outline,\r
+ const FT_Outline_Funcs* func_interface,\r
+ void* user )\r
+ {\r
+#undef SCALED\r
+#define SCALED( x ) ( ( (x) << shift ) - delta )\r
+\r
+ FT_Vector v_last;\r
+ FT_Vector v_control;\r
+ FT_Vector v_start;\r
+\r
+ FT_Vector* point;\r
+ FT_Vector* limit;\r
+ char* tags;\r
+\r
+ FT_Error error;\r
+\r
+ FT_Int n; /* index of contour in outline */\r
+ FT_UInt first; /* index of first point in contour */\r
+ FT_Int tag; /* current point's state */\r
+\r
+ FT_Int shift;\r
+ FT_Pos delta;\r
+\r
+\r
+ if ( !outline || !func_interface )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ shift = func_interface->shift;\r
+ delta = func_interface->delta;\r
+ first = 0;\r
+\r
+ for ( n = 0; n < outline->n_contours; n++ )\r
+ {\r
+ FT_Int last; /* index of last point in contour */\r
+\r
+\r
+ last = outline->contours[n];\r
+ if ( last < 0 )\r
+ goto Invalid_Outline;\r
+ limit = outline->points + last;\r
+\r
+ v_start = outline->points[first];\r
+ v_last = outline->points[last];\r
+\r
+ v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );\r
+ v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );\r
+\r
+ v_control = v_start;\r
+\r
+ point = outline->points + first;\r
+ tags = outline->tags + first;\r
+ tag = FT_CURVE_TAG( tags[0] );\r
+\r
+ /* A contour cannot start with a cubic control point! */\r
+ if ( tag == FT_CURVE_TAG_CUBIC )\r
+ goto Invalid_Outline;\r
+\r
+ /* check first point to determine origin */\r
+ if ( tag == FT_CURVE_TAG_CONIC )\r
+ {\r
+ /* first point is conic control. Yes, this happens. */\r
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )\r
+ {\r
+ /* start at last point if it is on the curve */\r
+ v_start = v_last;\r
+ limit--;\r
+ }\r
+ else\r
+ {\r
+ /* if both first and last points are conic, */\r
+ /* start at their middle and record its position */\r
+ /* for closure */\r
+ v_start.x = ( v_start.x + v_last.x ) / 2;\r
+ v_start.y = ( v_start.y + v_last.y ) / 2;\r
+\r
+ v_last = v_start;\r
+ }\r
+ point--;\r
+ tags--;\r
+ }\r
+\r
+ error = func_interface->move_to( &v_start, user );\r
+ if ( error )\r
+ goto Exit;\r
+\r
+ while ( point < limit )\r
+ {\r
+ point++;\r
+ tags++;\r
+\r
+ tag = FT_CURVE_TAG( tags[0] );\r
+ switch ( tag )\r
+ {\r
+ case FT_CURVE_TAG_ON: /* emit a single line_to */\r
+ {\r
+ FT_Vector vec;\r
+\r
+\r
+ vec.x = SCALED( point->x );\r
+ vec.y = SCALED( point->y );\r
+\r
+ error = func_interface->line_to( &vec, user );\r
+ if ( error )\r
+ goto Exit;\r
+ continue;\r
+ }\r
+\r
+ case FT_CURVE_TAG_CONIC: /* consume conic arcs */\r
+ v_control.x = SCALED( point->x );\r
+ v_control.y = SCALED( point->y );\r
+\r
+ Do_Conic:\r
+ if ( point < limit )\r
+ {\r
+ FT_Vector vec;\r
+ FT_Vector v_middle;\r
+\r
+\r
+ point++;\r
+ tags++;\r
+ tag = FT_CURVE_TAG( tags[0] );\r
+\r
+ vec.x = SCALED( point->x );\r
+ vec.y = SCALED( point->y );\r
+\r
+ if ( tag == FT_CURVE_TAG_ON )\r
+ {\r
+ error = func_interface->conic_to( &v_control, &vec, user );\r
+ if ( error )\r
+ goto Exit;\r
+ continue;\r
+ }\r
+\r
+ if ( tag != FT_CURVE_TAG_CONIC )\r
+ goto Invalid_Outline;\r
+\r
+ v_middle.x = ( v_control.x + vec.x ) / 2;\r
+ v_middle.y = ( v_control.y + vec.y ) / 2;\r
+\r
+ error = func_interface->conic_to( &v_control, &v_middle, user );\r
+ if ( error )\r
+ goto Exit;\r
+\r
+ v_control = vec;\r
+ goto Do_Conic;\r
+ }\r
+\r
+ error = func_interface->conic_to( &v_control, &v_start, user );\r
+ goto Close;\r
+\r
+ default: /* FT_CURVE_TAG_CUBIC */\r
+ {\r
+ FT_Vector vec1, vec2;\r
+\r
+\r
+ if ( point + 1 > limit ||\r
+ FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )\r
+ goto Invalid_Outline;\r
+\r
+ point += 2;\r
+ tags += 2;\r
+\r
+ vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );\r
+ vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );\r
+\r
+ if ( point <= limit )\r
+ {\r
+ FT_Vector vec;\r
+\r
+\r
+ vec.x = SCALED( point->x );\r
+ vec.y = SCALED( point->y );\r
+\r
+ error = func_interface->cubic_to( &vec1, &vec2, &vec, user );\r
+ if ( error )\r
+ goto Exit;\r
+ continue;\r
+ }\r
+\r
+ error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );\r
+ goto Close;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* close the contour with a line segment */\r
+ error = func_interface->line_to( &v_start, user );\r
+\r
+ Close:\r
+ if ( error )\r
+ goto Exit;\r
+\r
+ first = last + 1;\r
+ }\r
+\r
+ return 0;\r
+\r
+ Exit:\r
+ return error;\r
+\r
+ Invalid_Outline:\r
+ return FT_Err_Invalid_Outline;\r
+ }\r
+\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_New_Internal( FT_Memory memory,\r
+ FT_UInt numPoints,\r
+ FT_Int numContours,\r
+ FT_Outline *anoutline )\r
+ {\r
+ FT_Error error;\r
+\r
+\r
+ if ( !anoutline || !memory )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ *anoutline = null_outline;\r
+\r
+ if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) ||\r
+ FT_NEW_ARRAY( anoutline->tags, numPoints ) ||\r
+ FT_NEW_ARRAY( anoutline->contours, numContours ) )\r
+ goto Fail;\r
+\r
+ anoutline->n_points = (FT_UShort)numPoints;\r
+ anoutline->n_contours = (FT_Short)numContours;\r
+ anoutline->flags |= FT_OUTLINE_OWNER;\r
+\r
+ return FT_Err_Ok;\r
+\r
+ Fail:\r
+ anoutline->flags |= FT_OUTLINE_OWNER;\r
+ FT_Outline_Done_Internal( memory, anoutline );\r
+\r
+ return error;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_New( FT_Library library,\r
+ FT_UInt numPoints,\r
+ FT_Int numContours,\r
+ FT_Outline *anoutline )\r
+ {\r
+ if ( !library )\r
+ return FT_Err_Invalid_Library_Handle;\r
+\r
+ return FT_Outline_New_Internal( library->memory, numPoints,\r
+ numContours, anoutline );\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Check( FT_Outline* outline )\r
+ {\r
+ if ( outline )\r
+ {\r
+ FT_Int n_points = outline->n_points;\r
+ FT_Int n_contours = outline->n_contours;\r
+ FT_Int end0, end;\r
+ FT_Int n;\r
+\r
+\r
+ /* empty glyph? */\r
+ if ( n_points == 0 && n_contours == 0 )\r
+ return 0;\r
+\r
+ /* check point and contour counts */\r
+ if ( n_points <= 0 || n_contours <= 0 )\r
+ goto Bad;\r
+\r
+ end0 = end = -1;\r
+ for ( n = 0; n < n_contours; n++ )\r
+ {\r
+ end = outline->contours[n];\r
+\r
+ /* note that we don't accept empty contours */\r
+ if ( end <= end0 || end >= n_points )\r
+ goto Bad;\r
+\r
+ end0 = end;\r
+ }\r
+\r
+ if ( end != n_points - 1 )\r
+ goto Bad;\r
+\r
+ /* XXX: check the tags array */\r
+ return 0;\r
+ }\r
+\r
+ Bad:\r
+ return FT_Err_Invalid_Argument;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Copy( const FT_Outline* source,\r
+ FT_Outline *target )\r
+ {\r
+ FT_Int is_owner;\r
+\r
+\r
+ if ( !source || !target ||\r
+ source->n_points != target->n_points ||\r
+ source->n_contours != target->n_contours )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ if ( source == target )\r
+ return FT_Err_Ok;\r
+\r
+ FT_ARRAY_COPY( target->points, source->points, source->n_points );\r
+\r
+ FT_ARRAY_COPY( target->tags, source->tags, source->n_points );\r
+\r
+ FT_ARRAY_COPY( target->contours, source->contours, source->n_contours );\r
+\r
+ /* copy all flags, except the `FT_OUTLINE_OWNER' one */\r
+ is_owner = target->flags & FT_OUTLINE_OWNER;\r
+ target->flags = source->flags;\r
+\r
+ target->flags &= ~FT_OUTLINE_OWNER;\r
+ target->flags |= is_owner;\r
+\r
+ return FT_Err_Ok;\r
+ }\r
+\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Done_Internal( FT_Memory memory,\r
+ FT_Outline* outline )\r
+ {\r
+ if ( memory && outline )\r
+ {\r
+ if ( outline->flags & FT_OUTLINE_OWNER )\r
+ {\r
+ FT_FREE( outline->points );\r
+ FT_FREE( outline->tags );\r
+ FT_FREE( outline->contours );\r
+ }\r
+ *outline = null_outline;\r
+\r
+ return FT_Err_Ok;\r
+ }\r
+ else\r
+ return FT_Err_Invalid_Argument;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Done( FT_Library library,\r
+ FT_Outline* outline )\r
+ {\r
+ /* check for valid `outline' in FT_Outline_Done_Internal() */\r
+\r
+ if ( !library )\r
+ return FT_Err_Invalid_Library_Handle;\r
+\r
+ return FT_Outline_Done_Internal( library->memory, outline );\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( void )\r
+ FT_Outline_Get_CBox( const FT_Outline* outline,\r
+ FT_BBox *acbox )\r
+ {\r
+ FT_Pos xMin, yMin, xMax, yMax;\r
+\r
+\r
+ if ( outline && acbox )\r
+ {\r
+ if ( outline->n_points == 0 )\r
+ {\r
+ xMin = 0;\r
+ yMin = 0;\r
+ xMax = 0;\r
+ yMax = 0;\r
+ }\r
+ else\r
+ {\r
+ FT_Vector* vec = outline->points;\r
+ FT_Vector* limit = vec + outline->n_points;\r
+\r
+\r
+ xMin = xMax = vec->x;\r
+ yMin = yMax = vec->y;\r
+ vec++;\r
+\r
+ for ( ; vec < limit; vec++ )\r
+ {\r
+ FT_Pos x, y;\r
+\r
+\r
+ x = vec->x;\r
+ if ( x < xMin ) xMin = x;\r
+ if ( x > xMax ) xMax = x;\r
+\r
+ y = vec->y;\r
+ if ( y < yMin ) yMin = y;\r
+ if ( y > yMax ) yMax = y;\r
+ }\r
+ }\r
+ acbox->xMin = xMin;\r
+ acbox->xMax = xMax;\r
+ acbox->yMin = yMin;\r
+ acbox->yMax = yMax;\r
+ }\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( void )\r
+ FT_Outline_Translate( const FT_Outline* outline,\r
+ FT_Pos xOffset,\r
+ FT_Pos yOffset )\r
+ {\r
+ FT_UShort n;\r
+ FT_Vector* vec = outline->points;\r
+\r
+\r
+ if ( !outline )\r
+ return;\r
+\r
+ for ( n = 0; n < outline->n_points; n++ )\r
+ {\r
+ vec->x += xOffset;\r
+ vec->y += yOffset;\r
+ vec++;\r
+ }\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( void )\r
+ FT_Outline_Reverse( FT_Outline* outline )\r
+ {\r
+ FT_UShort n;\r
+ FT_Int first, last;\r
+\r
+\r
+ if ( !outline )\r
+ return;\r
+\r
+ first = 0;\r
+\r
+ for ( n = 0; n < outline->n_contours; n++ )\r
+ {\r
+ last = outline->contours[n];\r
+\r
+ /* reverse point table */\r
+ {\r
+ FT_Vector* p = outline->points + first;\r
+ FT_Vector* q = outline->points + last;\r
+ FT_Vector swap;\r
+\r
+\r
+ while ( p < q )\r
+ {\r
+ swap = *p;\r
+ *p = *q;\r
+ *q = swap;\r
+ p++;\r
+ q--;\r
+ }\r
+ }\r
+\r
+ /* reverse tags table */\r
+ {\r
+ char* p = outline->tags + first;\r
+ char* q = outline->tags + last;\r
+ char swap;\r
+\r
+\r
+ while ( p < q )\r
+ {\r
+ swap = *p;\r
+ *p = *q;\r
+ *q = swap;\r
+ p++;\r
+ q--;\r
+ }\r
+ }\r
+\r
+ first = last + 1;\r
+ }\r
+\r
+ outline->flags ^= FT_OUTLINE_REVERSE_FILL;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Render( FT_Library library,\r
+ FT_Outline* outline,\r
+ FT_Raster_Params* params )\r
+ {\r
+ FT_Error error;\r
+ FT_Bool update = 0;\r
+ FT_Renderer renderer;\r
+ FT_ListNode node;\r
+\r
+\r
+ if ( !library )\r
+ return FT_Err_Invalid_Library_Handle;\r
+\r
+ if ( !outline || !params )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ renderer = library->cur_renderer;\r
+ node = library->renderers.head;\r
+\r
+ params->source = (void*)outline;\r
+\r
+ error = FT_Err_Cannot_Render_Glyph;\r
+ while ( renderer )\r
+ {\r
+ error = renderer->raster_render( renderer->raster, params );\r
+ if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )\r
+ break;\r
+\r
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */\r
+ /* is unsupported by the current renderer for this glyph image */\r
+ /* format */\r
+\r
+ /* now, look for another renderer that supports the same */\r
+ /* format */\r
+ renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,\r
+ &node );\r
+ update = 1;\r
+ }\r
+\r
+ /* if we changed the current renderer for the glyph image format */\r
+ /* we need to select it as the next current one */\r
+ if ( !error && update && renderer )\r
+ FT_Set_Renderer( library, renderer, 0, 0 );\r
+\r
+ return error;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Get_Bitmap( FT_Library library,\r
+ FT_Outline* outline,\r
+ const FT_Bitmap *abitmap )\r
+ {\r
+ FT_Raster_Params params;\r
+\r
+\r
+ if ( !abitmap )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ /* other checks are delayed to FT_Outline_Render() */\r
+\r
+ params.target = abitmap;\r
+ params.flags = 0;\r
+\r
+ if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||\r
+ abitmap->pixel_mode == FT_PIXEL_MODE_LCD ||\r
+ abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )\r
+ params.flags |= FT_RASTER_FLAG_AA;\r
+\r
+ return FT_Outline_Render( library, outline, ¶ms );\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( void )\r
+ FT_Vector_Transform( FT_Vector* vector,\r
+ const FT_Matrix* matrix )\r
+ {\r
+ FT_Pos xz, yz;\r
+\r
+\r
+ if ( !vector || !matrix )\r
+ return;\r
+\r
+ xz = FT_MulFix( vector->x, matrix->xx ) +\r
+ FT_MulFix( vector->y, matrix->xy );\r
+\r
+ yz = FT_MulFix( vector->x, matrix->yx ) +\r
+ FT_MulFix( vector->y, matrix->yy );\r
+\r
+ vector->x = xz;\r
+ vector->y = yz;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( void )\r
+ FT_Outline_Transform( const FT_Outline* outline,\r
+ const FT_Matrix* matrix )\r
+ {\r
+ FT_Vector* vec;\r
+ FT_Vector* limit;\r
+\r
+\r
+ if ( !outline || !matrix )\r
+ return;\r
+\r
+ vec = outline->points;\r
+ limit = vec + outline->n_points;\r
+\r
+ for ( ; vec < limit; vec++ )\r
+ FT_Vector_Transform( vec, matrix );\r
+ }\r
+\r
+\r
+#if 0\r
+\r
+#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \\r
+ do { \\r
+ (first) = ( c > 0 ) ? (outline)->points + \\r
+ (outline)->contours[c - 1] + 1 \\r
+ : (outline)->points; \\r
+ (last) = (outline)->points + (outline)->contours[c]; \\r
+ } while ( 0 )\r
+\r
+\r
+ /* Is a point in some contour? */\r
+ /* */\r
+ /* We treat every point of the contour as if it */\r
+ /* it were ON. That is, we allow false positives, */\r
+ /* but disallow false negatives. (XXX really?) */\r
+ static FT_Bool\r
+ ft_contour_has( FT_Outline* outline,\r
+ FT_Short c,\r
+ FT_Vector* point )\r
+ {\r
+ FT_Vector* first;\r
+ FT_Vector* last;\r
+ FT_Vector* a;\r
+ FT_Vector* b;\r
+ FT_UInt n = 0;\r
+\r
+\r
+ FT_OUTLINE_GET_CONTOUR( outline, c, first, last );\r
+\r
+ for ( a = first; a <= last; a++ )\r
+ {\r
+ FT_Pos x;\r
+ FT_Int intersect;\r
+\r
+\r
+ b = ( a == last ) ? first : a + 1;\r
+\r
+ intersect = ( a->y - point->y ) ^ ( b->y - point->y );\r
+\r
+ /* a and b are on the same side */\r
+ if ( intersect >= 0 )\r
+ {\r
+ if ( intersect == 0 && a->y == point->y )\r
+ {\r
+ if ( ( a->x <= point->x && b->x >= point->x ) ||\r
+ ( a->x >= point->x && b->x <= point->x ) )\r
+ return 1;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
+ x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y );\r
+\r
+ if ( x < point->x )\r
+ n++;\r
+ else if ( x == point->x )\r
+ return 1;\r
+ }\r
+\r
+ return ( n % 2 );\r
+ }\r
+\r
+\r
+ static FT_Bool\r
+ ft_contour_enclosed( FT_Outline* outline,\r
+ FT_UShort c )\r
+ {\r
+ FT_Vector* first;\r
+ FT_Vector* last;\r
+ FT_Short i;\r
+\r
+\r
+ FT_OUTLINE_GET_CONTOUR( outline, c, first, last );\r
+\r
+ for ( i = 0; i < outline->n_contours; i++ )\r
+ {\r
+ if ( i != c && ft_contour_has( outline, i, first ) )\r
+ {\r
+ FT_Vector* pt;\r
+\r
+\r
+ for ( pt = first + 1; pt <= last; pt++ )\r
+ if ( !ft_contour_has( outline, i, pt ) )\r
+ return 0;\r
+\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+ }\r
+\r
+\r
+ /* This version differs from the public one in that each */\r
+ /* part (contour not enclosed in another contour) of the */\r
+ /* outline is checked for orientation. This is */\r
+ /* necessary for some buggy CJK fonts. */\r
+ static FT_Orientation\r
+ ft_outline_get_orientation( FT_Outline* outline )\r
+ {\r
+ FT_Short i;\r
+ FT_Vector* first;\r
+ FT_Vector* last;\r
+ FT_Orientation orient = FT_ORIENTATION_NONE;\r
+\r
+\r
+ first = outline->points;\r
+ for ( i = 0; i < outline->n_contours; i++, first = last + 1 )\r
+ {\r
+ FT_Vector* point;\r
+ FT_Vector* xmin_point;\r
+ FT_Pos xmin;\r
+\r
+\r
+ last = outline->points + outline->contours[i];\r
+\r
+ /* skip degenerate contours */\r
+ if ( last < first + 2 )\r
+ continue;\r
+\r
+ if ( ft_contour_enclosed( outline, i ) )\r
+ continue;\r
+\r
+ xmin = first->x;\r
+ xmin_point = first;\r
+\r
+ for ( point = first + 1; point <= last; point++ )\r
+ {\r
+ if ( point->x < xmin )\r
+ {\r
+ xmin = point->x;\r
+ xmin_point = point;\r
+ }\r
+ }\r
+\r
+ /* check the orientation of the contour */\r
+ {\r
+ FT_Vector* prev;\r
+ FT_Vector* next;\r
+ FT_Orientation o;\r
+\r
+\r
+ prev = ( xmin_point == first ) ? last : xmin_point - 1;\r
+ next = ( xmin_point == last ) ? first : xmin_point + 1;\r
+\r
+ if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >\r
+ FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )\r
+ o = FT_ORIENTATION_POSTSCRIPT;\r
+ else\r
+ o = FT_ORIENTATION_TRUETYPE;\r
+\r
+ if ( orient == FT_ORIENTATION_NONE )\r
+ orient = o;\r
+ else if ( orient != o )\r
+ return FT_ORIENTATION_NONE;\r
+ }\r
+ }\r
+\r
+ return orient;\r
+ }\r
+\r
+#endif /* 0 */\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ FT_Outline_Embolden( FT_Outline* outline,\r
+ FT_Pos strength )\r
+ {\r
+ FT_Vector* points;\r
+ FT_Vector v_prev, v_first, v_next, v_cur;\r
+ FT_Angle rotate, angle_in, angle_out;\r
+ FT_Int c, n, first;\r
+ FT_Int orientation;\r
+\r
+\r
+ if ( !outline )\r
+ return FT_Err_Invalid_Argument;\r
+\r
+ strength /= 2;\r
+ if ( strength == 0 )\r
+ return FT_Err_Ok;\r
+\r
+ orientation = FT_Outline_Get_Orientation( outline );\r
+ if ( orientation == FT_ORIENTATION_NONE )\r
+ {\r
+ if ( outline->n_contours )\r
+ return FT_Err_Invalid_Argument;\r
+ else\r
+ return FT_Err_Ok;\r
+ }\r
+\r
+ if ( orientation == FT_ORIENTATION_TRUETYPE )\r
+ rotate = -FT_ANGLE_PI2;\r
+ else\r
+ rotate = FT_ANGLE_PI2;\r
+\r
+ points = outline->points;\r
+\r
+ first = 0;\r
+ for ( c = 0; c < outline->n_contours; c++ )\r
+ {\r
+ int last = outline->contours[c];\r
+\r
+\r
+ v_first = points[first];\r
+ v_prev = points[last];\r
+ v_cur = v_first;\r
+\r
+ for ( n = first; n <= last; n++ )\r
+ {\r
+ FT_Vector in, out;\r
+ FT_Angle angle_diff;\r
+ FT_Pos d;\r
+ FT_Fixed scale;\r
+\r
+\r
+ if ( n < last )\r
+ v_next = points[n + 1];\r
+ else\r
+ v_next = v_first;\r
+\r
+ /* compute the in and out vectors */\r
+ in.x = v_cur.x - v_prev.x;\r
+ in.y = v_cur.y - v_prev.y;\r
+\r
+ out.x = v_next.x - v_cur.x;\r
+ out.y = v_next.y - v_cur.y;\r
+\r
+ angle_in = FT_Atan2( in.x, in.y );\r
+ angle_out = FT_Atan2( out.x, out.y );\r
+ angle_diff = FT_Angle_Diff( angle_in, angle_out );\r
+ scale = FT_Cos( angle_diff / 2 );\r
+\r
+ if ( scale < 0x4000L && scale > -0x4000L )\r
+ in.x = in.y = 0;\r
+ else\r
+ {\r
+ d = FT_DivFix( strength, scale );\r
+\r
+ FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );\r
+ }\r
+\r
+ outline->points[n].x = v_cur.x + strength + in.x;\r
+ outline->points[n].y = v_cur.y + strength + in.y;\r
+\r
+ v_prev = v_cur;\r
+ v_cur = v_next;\r
+ }\r
+\r
+ first = last + 1;\r
+ }\r
+\r
+ return FT_Err_Ok;\r
+ }\r
+\r
+\r
+ /* documentation is in ftoutln.h */\r
+\r
+ FT_EXPORT_DEF( FT_Orientation )\r
+ FT_Outline_Get_Orientation( FT_Outline* outline )\r
+ {\r
+ FT_Pos xmin = 32768L;\r
+ FT_Pos xmin_ymin = 32768L;\r
+ FT_Pos xmin_ymax = -32768L;\r
+ FT_Vector* xmin_first = NULL;\r
+ FT_Vector* xmin_last = NULL;\r
+\r
+ short* contour;\r
+\r
+ FT_Vector* first;\r
+ FT_Vector* last;\r
+ FT_Vector* prev;\r
+ FT_Vector* point;\r
+\r
+ int i;\r
+ FT_Pos ray_y[3];\r
+ FT_Orientation result[3];\r
+\r
+\r
+ if ( !outline || outline->n_points <= 0 )\r
+ return FT_ORIENTATION_TRUETYPE;\r
+\r
+ /* We use the nonzero winding rule to find the orientation. */\r
+ /* Since glyph outlines behave much more `regular' than arbitrary */\r
+ /* cubic or quadratic curves, this test deals with the polygon */\r
+ /* only which is spanned up by the control points. */\r
+\r
+ first = outline->points;\r
+ for ( contour = outline->contours;\r
+ contour < outline->contours + outline->n_contours;\r
+ contour++, first = last + 1 )\r
+ {\r
+ FT_Pos contour_xmin = 32768L;\r
+ FT_Pos contour_xmax = -32768L;\r
+ FT_Pos contour_ymin = 32768L;\r
+ FT_Pos contour_ymax = -32768L;\r
+\r
+\r
+ last = outline->points + *contour;\r
+\r
+ /* skip degenerate contours */\r
+ if ( last < first + 2 )\r
+ continue;\r
+\r
+ for ( point = first; point <= last; ++point )\r
+ {\r
+ if ( point->x < contour_xmin )\r
+ contour_xmin = point->x;\r
+\r
+ if ( point->x > contour_xmax )\r
+ contour_xmax = point->x;\r
+\r
+ if ( point->y < contour_ymin )\r
+ contour_ymin = point->y;\r
+\r
+ if ( point->y > contour_ymax )\r
+ contour_ymax = point->y;\r
+ }\r
+\r
+ if ( contour_xmin < xmin &&\r
+ contour_xmin != contour_xmax &&\r
+ contour_ymin != contour_ymax )\r
+ {\r
+ xmin = contour_xmin;\r
+ xmin_ymin = contour_ymin;\r
+ xmin_ymax = contour_ymax;\r
+ xmin_first = first;\r
+ xmin_last = last;\r
+ }\r
+ }\r
+\r
+ if ( xmin == 32768 )\r
+ return FT_ORIENTATION_TRUETYPE;\r
+\r
+ ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2;\r
+ ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1;\r
+ ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2;\r
+\r
+ for ( i = 0; i < 3; i++ )\r
+ {\r
+ FT_Pos left_x;\r
+ FT_Pos right_x;\r
+ FT_Vector* left1;\r
+ FT_Vector* left2;\r
+ FT_Vector* right1;\r
+ FT_Vector* right2;\r
+\r
+\r
+ RedoRay:\r
+ left_x = 32768L;\r
+ right_x = -32768L;\r
+\r
+ left1 = left2 = right1 = right2 = NULL;\r
+\r
+ prev = xmin_last;\r
+ for ( point = xmin_first; point <= xmin_last; prev = point, ++point )\r
+ {\r
+ FT_Pos tmp_x;\r
+\r
+\r
+ if ( point->y == ray_y[i] || prev->y == ray_y[i] )\r
+ {\r
+ ray_y[i]++;\r
+ goto RedoRay;\r
+ }\r
+\r
+ if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) ||\r
+ ( point->y > ray_y[i] && prev->y > ray_y[i] ) )\r
+ continue;\r
+\r
+ tmp_x = FT_MulDiv( point->x - prev->x,\r
+ ray_y[i] - prev->y,\r
+ point->y - prev->y ) + prev->x;\r
+\r
+ if ( tmp_x < left_x )\r
+ {\r
+ left_x = tmp_x;\r
+ left1 = prev;\r
+ left2 = point;\r
+ }\r
+\r
+ if ( tmp_x > right_x )\r
+ {\r
+ right_x = tmp_x;\r
+ right1 = prev;\r
+ right2 = point;\r
+ }\r
+ }\r
+\r
+ if ( left1 && right1 )\r
+ {\r
+ if ( left1->y < left2->y && right1->y > right2->y )\r
+ result[i] = FT_ORIENTATION_TRUETYPE;\r
+ else if ( left1->y > left2->y && right1->y < right2->y )\r
+ result[i] = FT_ORIENTATION_POSTSCRIPT;\r
+ else\r
+ result[i] = FT_ORIENTATION_NONE;\r
+ }\r
+ }\r
+\r
+ if ( result[0] != FT_ORIENTATION_NONE &&\r
+ ( result[0] == result[1] || result[0] == result[2] ) )\r
+ return result[0];\r
+\r
+ if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )\r
+ return result[1];\r
+\r
+ return FT_ORIENTATION_TRUETYPE;\r
+ }\r
+\r
+\r
+/* END */\r