1 /***************************************************************************/
5 /* FreeType outline management (body). */
7 /* Copyright 1996-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
19 /*************************************************************************/
21 /* All functions are declared in freetype.h. */
23 /*************************************************************************/
28 #include FT_INTERNAL_OBJECTS_H
31 /*************************************************************************/
33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
35 /* messages during execution. */
38 #define FT_COMPONENT trace_outline
42 const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
45 /* documentation is in ftoutln.h */
47 FT_EXPORT_DEF( FT_Error )
48 FT_Outline_Decompose( FT_Outline* outline,
49 const FT_Outline_Funcs* interface,
53 #define SCALED( x ) ( ( (x) << shift ) - delta )
65 FT_Int n; /* index of contour in outline */
66 FT_UInt first; /* index of first point in contour */
67 FT_Int tag; /* current point's state */
73 if ( !outline || !interface )
74 return FT_Err_Invalid_Argument;
76 shift = interface->shift;
77 delta = interface->delta;
80 for ( n = 0; n < outline->n_contours; n++ )
82 FT_Int last; /* index of last point in contour */
85 last = outline->contours[n];
86 limit = outline->points + last;
88 v_start = outline->points[first];
89 v_last = outline->points[last];
91 v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
92 v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
96 point = outline->points + first;
97 tags = outline->tags + first;
98 tag = FT_CURVE_TAG( tags[0] );
100 /* A contour cannot start with a cubic control point! */
101 if ( tag == FT_Curve_Tag_Cubic )
102 goto Invalid_Outline;
104 /* check first point to determine origin */
105 if ( tag == FT_Curve_Tag_Conic )
107 /* first point is conic control. Yes, this happens. */
108 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
110 /* start at last point if it is on the curve */
116 /* if both first and last points are conic, */
117 /* start at their middle and record its position */
119 v_start.x = ( v_start.x + v_last.x ) / 2;
120 v_start.y = ( v_start.y + v_last.y ) / 2;
128 error = interface->move_to( &v_start, user );
132 while ( point < limit )
137 tag = FT_CURVE_TAG( tags[0] );
140 case FT_Curve_Tag_On: /* emit a single line_to */
145 vec.x = SCALED( point->x );
146 vec.y = SCALED( point->y );
148 error = interface->line_to( &vec, user );
154 case FT_Curve_Tag_Conic: /* consume conic arcs */
155 v_control.x = SCALED( point->x );
156 v_control.y = SCALED( point->y );
167 tag = FT_CURVE_TAG( tags[0] );
169 vec.x = SCALED( point->x );
170 vec.y = SCALED( point->y );
172 if ( tag == FT_Curve_Tag_On )
174 error = interface->conic_to( &v_control, &vec, user );
180 if ( tag != FT_Curve_Tag_Conic )
181 goto Invalid_Outline;
183 v_middle.x = ( v_control.x + vec.x ) / 2;
184 v_middle.y = ( v_control.y + vec.y ) / 2;
186 error = interface->conic_to( &v_control, &v_middle, user );
194 error = interface->conic_to( &v_control, &v_start, user );
197 default: /* FT_Curve_Tag_Cubic */
199 FT_Vector vec1, vec2;
202 if ( point + 1 > limit ||
203 FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
204 goto Invalid_Outline;
209 vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
210 vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
212 if ( point <= limit )
217 vec.x = SCALED( point->x );
218 vec.y = SCALED( point->y );
220 error = interface->cubic_to( &vec1, &vec2, &vec, user );
226 error = interface->cubic_to( &vec1, &vec2, &v_start, user );
232 /* close the contour with a line segment */
233 error = interface->line_to( &v_start, user );
248 return FT_Err_Invalid_Outline;
252 FT_EXPORT_DEF( FT_Error )
253 FT_Outline_New_Internal( FT_Memory memory,
256 FT_Outline *anoutline )
261 if ( !anoutline || !memory )
262 return FT_Err_Invalid_Argument;
264 *anoutline = null_outline;
266 if ( ALLOC_ARRAY( anoutline->points, numPoints * 2L, FT_Pos ) ||
267 ALLOC_ARRAY( anoutline->tags, numPoints, FT_Byte ) ||
268 ALLOC_ARRAY( anoutline->contours, numContours, FT_UShort ) )
271 anoutline->n_points = (FT_UShort)numPoints;
272 anoutline->n_contours = (FT_Short)numContours;
273 anoutline->flags |= ft_outline_owner;
278 anoutline->flags |= ft_outline_owner;
279 FT_Outline_Done_Internal( memory, anoutline );
285 /* documentation is in ftoutln.h */
287 FT_EXPORT_DEF( FT_Error )
288 FT_Outline_New( FT_Library library,
291 FT_Outline *anoutline )
294 return FT_Err_Invalid_Library_Handle;
296 return FT_Outline_New_Internal( library->memory, numPoints,
297 numContours, anoutline );
301 /* documentation is in ftoutln.h */
303 FT_EXPORT_DEF( FT_Error )
304 FT_Outline_Copy( FT_Outline* source,
310 if ( !source || !target ||
311 source->n_points != target->n_points ||
312 source->n_contours != target->n_contours )
313 return FT_Err_Invalid_Argument;
315 MEM_Copy( target->points, source->points,
316 source->n_points * sizeof ( FT_Vector ) );
318 MEM_Copy( target->tags, source->tags,
319 source->n_points * sizeof ( FT_Byte ) );
321 MEM_Copy( target->contours, source->contours,
322 source->n_contours * sizeof ( FT_Short ) );
324 /* copy all flags, except the `ft_outline_owner' one */
325 is_owner = target->flags & ft_outline_owner;
326 target->flags = source->flags;
328 target->flags &= ~ft_outline_owner;
329 target->flags |= is_owner;
335 FT_EXPORT_DEF( FT_Error )
336 FT_Outline_Done_Internal( FT_Memory memory,
337 FT_Outline* outline )
341 if ( outline->flags & ft_outline_owner )
343 FREE( outline->points );
344 FREE( outline->tags );
345 FREE( outline->contours );
347 *outline = null_outline;
352 return FT_Err_Invalid_Argument;
356 /* documentation is in ftoutln.h */
358 FT_EXPORT_DEF( FT_Error )
359 FT_Outline_Done( FT_Library library,
360 FT_Outline* outline )
362 /* check for valid `outline' in FT_Outline_Done_Internal() */
365 return FT_Err_Invalid_Library_Handle;
367 return FT_Outline_Done_Internal( library->memory, outline );
371 /* documentation is in ftoutln.h */
373 FT_EXPORT_DEF( void )
374 FT_Outline_Get_CBox( FT_Outline* outline,
377 FT_Pos xMin, yMin, xMax, yMax;
380 if ( outline && acbox )
382 if ( outline->n_points == 0 )
391 FT_Vector* vec = outline->points;
392 FT_Vector* limit = vec + outline->n_points;
395 xMin = xMax = vec->x;
396 yMin = yMax = vec->y;
399 for ( ; vec < limit; vec++ )
405 if ( x < xMin ) xMin = x;
406 if ( x > xMax ) xMax = x;
409 if ( y < yMin ) yMin = y;
410 if ( y > yMax ) yMax = y;
421 /* documentation is in ftoutln.h */
423 FT_EXPORT_DEF( void )
424 FT_Outline_Translate( FT_Outline* outline,
429 FT_Vector* vec = outline->points;
432 for ( n = 0; n < outline->n_points; n++ )
441 /* documentation is in ftoutln.h */
443 FT_EXPORT_DEF( void )
444 FT_Outline_Reverse( FT_Outline* outline )
452 for ( n = 0; n < outline->n_contours; n++ )
454 last = outline->contours[n];
456 /* reverse point table */
458 FT_Vector* p = outline->points + first;
459 FT_Vector* q = outline->points + last;
473 /* reverse tags table */
475 char* p = outline->tags + first;
476 char* q = outline->tags + last;
493 outline->flags ^= ft_outline_reverse_fill;
497 /* documentation is in ftoutln.h */
499 FT_EXPORT_DEF( FT_Error )
500 FT_Outline_Render( FT_Library library,
502 FT_Raster_Params* params )
506 FT_Renderer renderer;
511 return FT_Err_Invalid_Library_Handle;
514 return FT_Err_Invalid_Argument;
516 renderer = library->cur_renderer;
517 node = library->renderers.head;
519 params->source = (void*)outline;
521 error = FT_Err_Cannot_Render_Glyph;
524 error = renderer->raster_render( renderer->raster, params );
525 if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
528 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
529 /* is unsupported by the current renderer for this glyph image */
532 /* now, look for another renderer that supports the same */
534 renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline,
539 /* if we changed the current renderer for the glyph image format */
540 /* we need to select it as the next current one */
541 if ( !error && update && renderer )
542 FT_Set_Renderer( library, renderer, 0, 0 );
548 /* documentation is in ftoutln.h */
550 FT_EXPORT_DEF( FT_Error )
551 FT_Outline_Get_Bitmap( FT_Library library,
555 FT_Raster_Params params;
559 return FT_Err_Invalid_Argument;
561 /* other checks are delayed to FT_Outline_Render() */
563 params.target = abitmap;
566 if ( abitmap->pixel_mode == ft_pixel_mode_grays )
567 params.flags |= ft_raster_flag_aa;
569 return FT_Outline_Render( library, outline, ¶ms );
573 /* documentation is in ftoutln.h */
575 FT_EXPORT_DEF( void )
576 FT_Vector_Transform( FT_Vector* vector,
582 if ( !vector || !matrix )
585 xz = FT_MulFix( vector->x, matrix->xx ) +
586 FT_MulFix( vector->y, matrix->xy );
588 yz = FT_MulFix( vector->x, matrix->yx ) +
589 FT_MulFix( vector->y, matrix->yy );
596 /* documentation is in ftoutln.h */
598 FT_EXPORT_DEF( void )
599 FT_Outline_Transform( FT_Outline* outline,
602 FT_Vector* vec = outline->points;
603 FT_Vector* limit = vec + outline->n_points;
606 for ( ; vec < limit; vec++ )
607 FT_Vector_Transform( vec, matrix );