1 /***************************************************************************/
2 /* */
3 /* ftoutln.c */
4 /* */
5 /* FreeType outline management (body). */
6 /* */
7 /* Copyright 1996-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
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. */
15 /* */
16 /***************************************************************************/
19 /*************************************************************************/
20 /* */
21 /* All functions are declared in freetype.h. */
22 /* */
23 /*************************************************************************/
26 #include <ft2build.h>
27 #include FT_OUTLINE_H
28 #include FT_INTERNAL_OBJECTS_H
31 /*************************************************************************/
32 /* */
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. */
36 /* */
37 #undef FT_COMPONENT
38 #define FT_COMPONENT trace_outline
41 static
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,
50 void* user )
51 {
52 #undef SCALED
53 #define SCALED( x ) ( ( (x) << shift ) - delta )
55 FT_Vector v_last;
56 FT_Vector v_control;
57 FT_Vector v_start;
59 FT_Vector* point;
60 FT_Vector* limit;
61 char* tags;
63 FT_Error error;
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 */
69 FT_Int shift;
70 FT_Pos delta;
73 if ( !outline || !interface )
74 return FT_Err_Invalid_Argument;
76 shift = interface->shift;
77 delta = interface->delta;
78 first = 0;
80 for ( n = 0; n < outline->n_contours; n++ )
81 {
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 );
94 v_control = v_start;
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 )
106 {
107 /* first point is conic control. Yes, this happens. */
108 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
109 {
110 /* start at last point if it is on the curve */
111 v_start = v_last;
112 limit--;
113 }
114 else
115 {
116 /* if both first and last points are conic, */
117 /* start at their middle and record its position */
118 /* for closure */
119 v_start.x = ( v_start.x + v_last.x ) / 2;
120 v_start.y = ( v_start.y + v_last.y ) / 2;
122 v_last = v_start;
123 }
124 point--;
125 tags--;
126 }
128 error = interface->move_to( &v_start, user );
129 if ( error )
130 goto Exit;
132 while ( point < limit )
133 {
134 point++;
135 tags++;
137 tag = FT_CURVE_TAG( tags[0] );
138 switch ( tag )
139 {
140 case FT_Curve_Tag_On: /* emit a single line_to */
141 {
142 FT_Vector vec;
145 vec.x = SCALED( point->x );
146 vec.y = SCALED( point->y );
148 error = interface->line_to( &vec, user );
149 if ( error )
150 goto Exit;
151 continue;
152 }
154 case FT_Curve_Tag_Conic: /* consume conic arcs */
155 v_control.x = SCALED( point->x );
156 v_control.y = SCALED( point->y );
158 Do_Conic:
159 if ( point < limit )
160 {
161 FT_Vector vec;
162 FT_Vector v_middle;
165 point++;
166 tags++;
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 )
173 {
174 error = interface->conic_to( &v_control, &vec, user );
175 if ( error )
176 goto Exit;
177 continue;
178 }
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 );
187 if ( error )
188 goto Exit;
190 v_control = vec;
191 goto Do_Conic;
192 }
194 error = interface->conic_to( &v_control, &v_start, user );
195 goto Close;
197 default: /* FT_Curve_Tag_Cubic */
198 {
199 FT_Vector vec1, vec2;
202 if ( point + 1 > limit ||
203 FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
204 goto Invalid_Outline;
206 point += 2;
207 tags += 2;
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 )
213 {
214 FT_Vector vec;
217 vec.x = SCALED( point->x );
218 vec.y = SCALED( point->y );
220 error = interface->cubic_to( &vec1, &vec2, &vec, user );
221 if ( error )
222 goto Exit;
223 continue;
224 }
226 error = interface->cubic_to( &vec1, &vec2, &v_start, user );
227 goto Close;
228 }
229 }
230 }
232 /* close the contour with a line segment */
233 error = interface->line_to( &v_start, user );
235 Close:
236 if ( error )
237 goto Exit;
239 first = last + 1;
240 }
242 return 0;
244 Exit:
245 return error;
247 Invalid_Outline:
248 return FT_Err_Invalid_Outline;
249 }
252 FT_EXPORT_DEF( FT_Error )
253 FT_Outline_New_Internal( FT_Memory memory,
254 FT_UInt numPoints,
255 FT_Int numContours,
256 FT_Outline *anoutline )
257 {
258 FT_Error error;
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 ) )
269 goto Fail;
271 anoutline->n_points = (FT_UShort)numPoints;
272 anoutline->n_contours = (FT_Short)numContours;
273 anoutline->flags |= ft_outline_owner;
275 return FT_Err_Ok;
277 Fail:
278 anoutline->flags |= ft_outline_owner;
279 FT_Outline_Done_Internal( memory, anoutline );
281 return error;
282 }
285 /* documentation is in ftoutln.h */
287 FT_EXPORT_DEF( FT_Error )
288 FT_Outline_New( FT_Library library,
289 FT_UInt numPoints,
290 FT_Int numContours,
291 FT_Outline *anoutline )
292 {
293 if ( !library )
294 return FT_Err_Invalid_Library_Handle;
296 return FT_Outline_New_Internal( library->memory, numPoints,
297 numContours, anoutline );
298 }
301 /* documentation is in ftoutln.h */
303 FT_EXPORT_DEF( FT_Error )
304 FT_Outline_Copy( FT_Outline* source,
305 FT_Outline *target )
306 {
307 FT_Int is_owner;
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;
331 return FT_Err_Ok;
332 }
335 FT_EXPORT_DEF( FT_Error )
336 FT_Outline_Done_Internal( FT_Memory memory,
337 FT_Outline* outline )
338 {
339 if ( outline )
340 {
341 if ( outline->flags & ft_outline_owner )
342 {
343 FREE( outline->points );
344 FREE( outline->tags );
345 FREE( outline->contours );
346 }
347 *outline = null_outline;
349 return FT_Err_Ok;
350 }
351 else
352 return FT_Err_Invalid_Argument;
353 }
356 /* documentation is in ftoutln.h */
358 FT_EXPORT_DEF( FT_Error )
359 FT_Outline_Done( FT_Library library,
360 FT_Outline* outline )
361 {
362 /* check for valid `outline' in FT_Outline_Done_Internal() */
364 if ( !library )
365 return FT_Err_Invalid_Library_Handle;
367 return FT_Outline_Done_Internal( library->memory, outline );
368 }
371 /* documentation is in ftoutln.h */
373 FT_EXPORT_DEF( void )
374 FT_Outline_Get_CBox( FT_Outline* outline,
375 FT_BBox *acbox )
376 {
377 FT_Pos xMin, yMin, xMax, yMax;
380 if ( outline && acbox )
381 {
382 if ( outline->n_points == 0 )
383 {
384 xMin = 0;
385 yMin = 0;
386 xMax = 0;
387 yMax = 0;
388 }
389 else
390 {
391 FT_Vector* vec = outline->points;
392 FT_Vector* limit = vec + outline->n_points;
395 xMin = xMax = vec->x;
396 yMin = yMax = vec->y;
397 vec++;
399 for ( ; vec < limit; vec++ )
400 {
401 FT_Pos x, y;
404 x = vec->x;
405 if ( x < xMin ) xMin = x;
406 if ( x > xMax ) xMax = x;
408 y = vec->y;
409 if ( y < yMin ) yMin = y;
410 if ( y > yMax ) yMax = y;
411 }
412 }
413 acbox->xMin = xMin;
414 acbox->xMax = xMax;
415 acbox->yMin = yMin;
416 acbox->yMax = yMax;
417 }
418 }
421 /* documentation is in ftoutln.h */
423 FT_EXPORT_DEF( void )
424 FT_Outline_Translate( FT_Outline* outline,
425 FT_Pos xOffset,
426 FT_Pos yOffset )
427 {
428 FT_UShort n;
429 FT_Vector* vec = outline->points;
432 for ( n = 0; n < outline->n_points; n++ )
433 {
434 vec->x += xOffset;
435 vec->y += yOffset;
436 vec++;
437 }
438 }
441 /* documentation is in ftoutln.h */
443 FT_EXPORT_DEF( void )
444 FT_Outline_Reverse( FT_Outline* outline )
445 {
446 FT_UShort n;
447 FT_Int first, last;
450 first = 0;
452 for ( n = 0; n < outline->n_contours; n++ )
453 {
454 last = outline->contours[n];
456 /* reverse point table */
457 {
458 FT_Vector* p = outline->points + first;
459 FT_Vector* q = outline->points + last;
460 FT_Vector swap;
463 while ( p < q )
464 {
465 swap = *p;
466 *p = *q;
467 *q = swap;
468 p++;
469 q--;
470 }
471 }
473 /* reverse tags table */
474 {
475 char* p = outline->tags + first;
476 char* q = outline->tags + last;
477 char swap;
480 while ( p < q )
481 {
482 swap = *p;
483 *p = *q;
484 *q = swap;
485 p++;
486 q--;
487 }
488 }
490 first = last + 1;
491 }
493 outline->flags ^= ft_outline_reverse_fill;
494 }
497 /* documentation is in ftoutln.h */
499 FT_EXPORT_DEF( FT_Error )
500 FT_Outline_Render( FT_Library library,
501 FT_Outline* outline,
502 FT_Raster_Params* params )
503 {
504 FT_Error error;
505 FT_Bool update = 0;
506 FT_Renderer renderer;
507 FT_ListNode node;
510 if ( !library )
511 return FT_Err_Invalid_Library_Handle;
513 if ( !params )
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;
522 while ( renderer )
523 {
524 error = renderer->raster_render( renderer->raster, params );
525 if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
526 break;
528 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
529 /* is unsupported by the current renderer for this glyph image */
530 /* format */
532 /* now, look for another renderer that supports the same */
533 /* format */
534 renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline,
535 &node );
536 update = 1;
537 }
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 );
544 return error;
545 }
548 /* documentation is in ftoutln.h */
550 FT_EXPORT_DEF( FT_Error )
551 FT_Outline_Get_Bitmap( FT_Library library,
552 FT_Outline* outline,
553 FT_Bitmap *abitmap )
554 {
555 FT_Raster_Params params;
558 if ( !abitmap )
559 return FT_Err_Invalid_Argument;
561 /* other checks are delayed to FT_Outline_Render() */
563 params.target = abitmap;
564 params.flags = 0;
566 if ( abitmap->pixel_mode == ft_pixel_mode_grays )
567 params.flags |= ft_raster_flag_aa;
569 return FT_Outline_Render( library, outline, ¶ms );
570 }
573 /* documentation is in ftoutln.h */
575 FT_EXPORT_DEF( void )
576 FT_Vector_Transform( FT_Vector* vector,
577 FT_Matrix* matrix )
578 {
579 FT_Pos xz, yz;
582 if ( !vector || !matrix )
583 return;
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 );
591 vector->x = xz;
592 vector->y = yz;
593 }
596 /* documentation is in ftoutln.h */
598 FT_EXPORT_DEF( void )
599 FT_Outline_Transform( FT_Outline* outline,
600 FT_Matrix* matrix )
601 {
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 );
608 }
611 /* END */