Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / base / ftoutln.c
blob2bae8573f40b2133a9ca85c0892614a92e5a0a34
1 /***************************************************************************/
2 /* */
3 /* ftoutln.c */
4 /* */
5 /* FreeType outline management (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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
29 #include FT_TRIGONOMETRY_H
32 /*************************************************************************/
33 /* */
34 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
35 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
36 /* messages during execution. */
37 /* */
38 #undef FT_COMPONENT
39 #define FT_COMPONENT trace_outline
42 static
43 const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
46 /* documentation is in ftoutln.h */
48 FT_EXPORT_DEF( FT_Error )
49 FT_Outline_Decompose( FT_Outline* outline,
50 const FT_Outline_Funcs* func_interface,
51 void* user )
53 #undef SCALED
54 #define SCALED( x ) ( ( (x) << shift ) - delta )
56 FT_Vector v_last;
57 FT_Vector v_control;
58 FT_Vector v_start;
60 FT_Vector* point;
61 FT_Vector* limit;
62 char* tags;
64 FT_Error error;
66 FT_Int n; /* index of contour in outline */
67 FT_UInt first; /* index of first point in contour */
68 FT_Int tag; /* current point's state */
70 FT_Int shift;
71 FT_Pos delta;
74 if ( !outline || !func_interface )
75 return FT_Err_Invalid_Argument;
77 shift = func_interface->shift;
78 delta = func_interface->delta;
79 first = 0;
81 for ( n = 0; n < outline->n_contours; n++ )
83 FT_Int last; /* index of last point in contour */
86 last = outline->contours[n];
87 if ( last < 0 )
88 goto Invalid_Outline;
89 limit = outline->points + last;
91 v_start = outline->points[first];
92 v_last = outline->points[last];
94 v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
95 v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
97 v_control = v_start;
99 point = outline->points + first;
100 tags = outline->tags + first;
101 tag = FT_CURVE_TAG( tags[0] );
103 /* A contour cannot start with a cubic control point! */
104 if ( tag == FT_CURVE_TAG_CUBIC )
105 goto Invalid_Outline;
107 /* check first point to determine origin */
108 if ( tag == FT_CURVE_TAG_CONIC )
110 /* first point is conic control. Yes, this happens. */
111 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
113 /* start at last point if it is on the curve */
114 v_start = v_last;
115 limit--;
117 else
119 /* if both first and last points are conic, */
120 /* start at their middle and record its position */
121 /* for closure */
122 v_start.x = ( v_start.x + v_last.x ) / 2;
123 v_start.y = ( v_start.y + v_last.y ) / 2;
125 v_last = v_start;
127 point--;
128 tags--;
131 error = func_interface->move_to( &v_start, user );
132 if ( error )
133 goto Exit;
135 while ( point < limit )
137 point++;
138 tags++;
140 tag = FT_CURVE_TAG( tags[0] );
141 switch ( tag )
143 case FT_CURVE_TAG_ON: /* emit a single line_to */
145 FT_Vector vec;
148 vec.x = SCALED( point->x );
149 vec.y = SCALED( point->y );
151 error = func_interface->line_to( &vec, user );
152 if ( error )
153 goto Exit;
154 continue;
157 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
158 v_control.x = SCALED( point->x );
159 v_control.y = SCALED( point->y );
161 Do_Conic:
162 if ( point < limit )
164 FT_Vector vec;
165 FT_Vector v_middle;
168 point++;
169 tags++;
170 tag = FT_CURVE_TAG( tags[0] );
172 vec.x = SCALED( point->x );
173 vec.y = SCALED( point->y );
175 if ( tag == FT_CURVE_TAG_ON )
177 error = func_interface->conic_to( &v_control, &vec, user );
178 if ( error )
179 goto Exit;
180 continue;
183 if ( tag != FT_CURVE_TAG_CONIC )
184 goto Invalid_Outline;
186 v_middle.x = ( v_control.x + vec.x ) / 2;
187 v_middle.y = ( v_control.y + vec.y ) / 2;
189 error = func_interface->conic_to( &v_control, &v_middle, user );
190 if ( error )
191 goto Exit;
193 v_control = vec;
194 goto Do_Conic;
197 error = func_interface->conic_to( &v_control, &v_start, user );
198 goto Close;
200 default: /* FT_CURVE_TAG_CUBIC */
202 FT_Vector vec1, vec2;
205 if ( point + 1 > limit ||
206 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
207 goto Invalid_Outline;
209 point += 2;
210 tags += 2;
212 vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
213 vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
215 if ( point <= limit )
217 FT_Vector vec;
220 vec.x = SCALED( point->x );
221 vec.y = SCALED( point->y );
223 error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
224 if ( error )
225 goto Exit;
226 continue;
229 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
230 goto Close;
235 /* close the contour with a line segment */
236 error = func_interface->line_to( &v_start, user );
238 Close:
239 if ( error )
240 goto Exit;
242 first = last + 1;
245 return 0;
247 Exit:
248 return error;
250 Invalid_Outline:
251 return FT_Err_Invalid_Outline;
255 FT_EXPORT_DEF( FT_Error )
256 FT_Outline_New_Internal( FT_Memory memory,
257 FT_UInt numPoints,
258 FT_Int numContours,
259 FT_Outline *anoutline )
261 FT_Error error;
264 if ( !anoutline || !memory )
265 return FT_Err_Invalid_Argument;
267 *anoutline = null_outline;
269 if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) ||
270 FT_NEW_ARRAY( anoutline->tags, numPoints ) ||
271 FT_NEW_ARRAY( anoutline->contours, numContours ) )
272 goto Fail;
274 anoutline->n_points = (FT_UShort)numPoints;
275 anoutline->n_contours = (FT_Short)numContours;
276 anoutline->flags |= FT_OUTLINE_OWNER;
278 return FT_Err_Ok;
280 Fail:
281 anoutline->flags |= FT_OUTLINE_OWNER;
282 FT_Outline_Done_Internal( memory, anoutline );
284 return error;
288 /* documentation is in ftoutln.h */
290 FT_EXPORT_DEF( FT_Error )
291 FT_Outline_New( FT_Library library,
292 FT_UInt numPoints,
293 FT_Int numContours,
294 FT_Outline *anoutline )
296 if ( !library )
297 return FT_Err_Invalid_Library_Handle;
299 return FT_Outline_New_Internal( library->memory, numPoints,
300 numContours, anoutline );
304 /* documentation is in ftoutln.h */
306 FT_EXPORT_DEF( FT_Error )
307 FT_Outline_Check( FT_Outline* outline )
309 if ( outline )
311 FT_Int n_points = outline->n_points;
312 FT_Int n_contours = outline->n_contours;
313 FT_Int end0, end;
314 FT_Int n;
317 /* empty glyph? */
318 if ( n_points == 0 && n_contours == 0 )
319 return 0;
321 /* check point and contour counts */
322 if ( n_points <= 0 || n_contours <= 0 )
323 goto Bad;
325 end0 = end = -1;
326 for ( n = 0; n < n_contours; n++ )
328 end = outline->contours[n];
330 /* note that we don't accept empty contours */
331 if ( end <= end0 || end >= n_points )
332 goto Bad;
334 end0 = end;
337 if ( end != n_points - 1 )
338 goto Bad;
340 /* XXX: check the tags array */
341 return 0;
344 Bad:
345 return FT_Err_Invalid_Argument;
349 /* documentation is in ftoutln.h */
351 FT_EXPORT_DEF( FT_Error )
352 FT_Outline_Copy( const FT_Outline* source,
353 FT_Outline *target )
355 FT_Int is_owner;
358 if ( !source || !target ||
359 source->n_points != target->n_points ||
360 source->n_contours != target->n_contours )
361 return FT_Err_Invalid_Argument;
363 if ( source == target )
364 return FT_Err_Ok;
366 FT_ARRAY_COPY( target->points, source->points, source->n_points );
368 FT_ARRAY_COPY( target->tags, source->tags, source->n_points );
370 FT_ARRAY_COPY( target->contours, source->contours, source->n_contours );
372 /* copy all flags, except the `FT_OUTLINE_OWNER' one */
373 is_owner = target->flags & FT_OUTLINE_OWNER;
374 target->flags = source->flags;
376 target->flags &= ~FT_OUTLINE_OWNER;
377 target->flags |= is_owner;
379 return FT_Err_Ok;
383 FT_EXPORT_DEF( FT_Error )
384 FT_Outline_Done_Internal( FT_Memory memory,
385 FT_Outline* outline )
387 if ( memory && outline )
389 if ( outline->flags & FT_OUTLINE_OWNER )
391 FT_FREE( outline->points );
392 FT_FREE( outline->tags );
393 FT_FREE( outline->contours );
395 *outline = null_outline;
397 return FT_Err_Ok;
399 else
400 return FT_Err_Invalid_Argument;
404 /* documentation is in ftoutln.h */
406 FT_EXPORT_DEF( FT_Error )
407 FT_Outline_Done( FT_Library library,
408 FT_Outline* outline )
410 /* check for valid `outline' in FT_Outline_Done_Internal() */
412 if ( !library )
413 return FT_Err_Invalid_Library_Handle;
415 return FT_Outline_Done_Internal( library->memory, outline );
419 /* documentation is in ftoutln.h */
421 FT_EXPORT_DEF( void )
422 FT_Outline_Get_CBox( const FT_Outline* outline,
423 FT_BBox *acbox )
425 FT_Pos xMin, yMin, xMax, yMax;
428 if ( outline && acbox )
430 if ( outline->n_points == 0 )
432 xMin = 0;
433 yMin = 0;
434 xMax = 0;
435 yMax = 0;
437 else
439 FT_Vector* vec = outline->points;
440 FT_Vector* limit = vec + outline->n_points;
443 xMin = xMax = vec->x;
444 yMin = yMax = vec->y;
445 vec++;
447 for ( ; vec < limit; vec++ )
449 FT_Pos x, y;
452 x = vec->x;
453 if ( x < xMin ) xMin = x;
454 if ( x > xMax ) xMax = x;
456 y = vec->y;
457 if ( y < yMin ) yMin = y;
458 if ( y > yMax ) yMax = y;
461 acbox->xMin = xMin;
462 acbox->xMax = xMax;
463 acbox->yMin = yMin;
464 acbox->yMax = yMax;
469 /* documentation is in ftoutln.h */
471 FT_EXPORT_DEF( void )
472 FT_Outline_Translate( const FT_Outline* outline,
473 FT_Pos xOffset,
474 FT_Pos yOffset )
476 FT_UShort n;
477 FT_Vector* vec;
480 if ( !outline )
481 return;
483 vec = outline->points;
485 for ( n = 0; n < outline->n_points; n++ )
487 vec->x += xOffset;
488 vec->y += yOffset;
489 vec++;
494 /* documentation is in ftoutln.h */
496 FT_EXPORT_DEF( void )
497 FT_Outline_Reverse( FT_Outline* outline )
499 FT_UShort n;
500 FT_Int first, last;
503 if ( !outline )
504 return;
506 first = 0;
508 for ( n = 0; n < outline->n_contours; n++ )
510 last = outline->contours[n];
512 /* reverse point table */
514 FT_Vector* p = outline->points + first;
515 FT_Vector* q = outline->points + last;
516 FT_Vector swap;
519 while ( p < q )
521 swap = *p;
522 *p = *q;
523 *q = swap;
524 p++;
525 q--;
529 /* reverse tags table */
531 char* p = outline->tags + first;
532 char* q = outline->tags + last;
533 char swap;
536 while ( p < q )
538 swap = *p;
539 *p = *q;
540 *q = swap;
541 p++;
542 q--;
546 first = last + 1;
549 outline->flags ^= FT_OUTLINE_REVERSE_FILL;
553 /* documentation is in ftoutln.h */
555 FT_EXPORT_DEF( FT_Error )
556 FT_Outline_Render( FT_Library library,
557 FT_Outline* outline,
558 FT_Raster_Params* params )
560 FT_Error error;
561 FT_Bool update = 0;
562 FT_Renderer renderer;
563 FT_ListNode node;
566 if ( !library )
567 return FT_Err_Invalid_Library_Handle;
569 if ( !outline || !params )
570 return FT_Err_Invalid_Argument;
572 renderer = library->cur_renderer;
573 node = library->renderers.head;
575 params->source = (void*)outline;
577 error = FT_Err_Cannot_Render_Glyph;
578 while ( renderer )
580 error = renderer->raster_render( renderer->raster, params );
581 if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
582 break;
584 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
585 /* is unsupported by the current renderer for this glyph image */
586 /* format */
588 /* now, look for another renderer that supports the same */
589 /* format */
590 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,
591 &node );
592 update = 1;
595 /* if we changed the current renderer for the glyph image format */
596 /* we need to select it as the next current one */
597 if ( !error && update && renderer )
598 FT_Set_Renderer( library, renderer, 0, 0 );
600 return error;
604 /* documentation is in ftoutln.h */
606 FT_EXPORT_DEF( FT_Error )
607 FT_Outline_Get_Bitmap( FT_Library library,
608 FT_Outline* outline,
609 const FT_Bitmap *abitmap )
611 FT_Raster_Params params;
614 if ( !abitmap )
615 return FT_Err_Invalid_Argument;
617 /* other checks are delayed to FT_Outline_Render() */
619 params.target = abitmap;
620 params.flags = 0;
622 if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
623 abitmap->pixel_mode == FT_PIXEL_MODE_LCD ||
624 abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
625 params.flags |= FT_RASTER_FLAG_AA;
627 return FT_Outline_Render( library, outline, &params );
631 /* documentation is in freetype.h */
633 FT_EXPORT_DEF( void )
634 FT_Vector_Transform( FT_Vector* vector,
635 const FT_Matrix* matrix )
637 FT_Pos xz, yz;
640 if ( !vector || !matrix )
641 return;
643 xz = FT_MulFix( vector->x, matrix->xx ) +
644 FT_MulFix( vector->y, matrix->xy );
646 yz = FT_MulFix( vector->x, matrix->yx ) +
647 FT_MulFix( vector->y, matrix->yy );
649 vector->x = xz;
650 vector->y = yz;
654 /* documentation is in ftoutln.h */
656 FT_EXPORT_DEF( void )
657 FT_Outline_Transform( const FT_Outline* outline,
658 const FT_Matrix* matrix )
660 FT_Vector* vec;
661 FT_Vector* limit;
664 if ( !outline || !matrix )
665 return;
667 vec = outline->points;
668 limit = vec + outline->n_points;
670 for ( ; vec < limit; vec++ )
671 FT_Vector_Transform( vec, matrix );
675 #if 0
677 #define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \
678 do { \
679 (first) = ( c > 0 ) ? (outline)->points + \
680 (outline)->contours[c - 1] + 1 \
681 : (outline)->points; \
682 (last) = (outline)->points + (outline)->contours[c]; \
683 } while ( 0 )
686 /* Is a point in some contour? */
687 /* */
688 /* We treat every point of the contour as if it */
689 /* it were ON. That is, we allow false positives, */
690 /* but disallow false negatives. (XXX really?) */
691 static FT_Bool
692 ft_contour_has( FT_Outline* outline,
693 FT_Short c,
694 FT_Vector* point )
696 FT_Vector* first;
697 FT_Vector* last;
698 FT_Vector* a;
699 FT_Vector* b;
700 FT_UInt n = 0;
703 FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
705 for ( a = first; a <= last; a++ )
707 FT_Pos x;
708 FT_Int intersect;
711 b = ( a == last ) ? first : a + 1;
713 intersect = ( a->y - point->y ) ^ ( b->y - point->y );
715 /* a and b are on the same side */
716 if ( intersect >= 0 )
718 if ( intersect == 0 && a->y == point->y )
720 if ( ( a->x <= point->x && b->x >= point->x ) ||
721 ( a->x >= point->x && b->x <= point->x ) )
722 return 1;
725 continue;
728 x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y );
730 if ( x < point->x )
731 n++;
732 else if ( x == point->x )
733 return 1;
736 return ( n % 2 );
740 static FT_Bool
741 ft_contour_enclosed( FT_Outline* outline,
742 FT_UShort c )
744 FT_Vector* first;
745 FT_Vector* last;
746 FT_Short i;
749 FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
751 for ( i = 0; i < outline->n_contours; i++ )
753 if ( i != c && ft_contour_has( outline, i, first ) )
755 FT_Vector* pt;
758 for ( pt = first + 1; pt <= last; pt++ )
759 if ( !ft_contour_has( outline, i, pt ) )
760 return 0;
762 return 1;
766 return 0;
770 /* This version differs from the public one in that each */
771 /* part (contour not enclosed in another contour) of the */
772 /* outline is checked for orientation. This is */
773 /* necessary for some buggy CJK fonts. */
774 static FT_Orientation
775 ft_outline_get_orientation( FT_Outline* outline )
777 FT_Short i;
778 FT_Vector* first;
779 FT_Vector* last;
780 FT_Orientation orient = FT_ORIENTATION_NONE;
783 first = outline->points;
784 for ( i = 0; i < outline->n_contours; i++, first = last + 1 )
786 FT_Vector* point;
787 FT_Vector* xmin_point;
788 FT_Pos xmin;
791 last = outline->points + outline->contours[i];
793 /* skip degenerate contours */
794 if ( last < first + 2 )
795 continue;
797 if ( ft_contour_enclosed( outline, i ) )
798 continue;
800 xmin = first->x;
801 xmin_point = first;
803 for ( point = first + 1; point <= last; point++ )
805 if ( point->x < xmin )
807 xmin = point->x;
808 xmin_point = point;
812 /* check the orientation of the contour */
814 FT_Vector* prev;
815 FT_Vector* next;
816 FT_Orientation o;
819 prev = ( xmin_point == first ) ? last : xmin_point - 1;
820 next = ( xmin_point == last ) ? first : xmin_point + 1;
822 if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
823 FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
824 o = FT_ORIENTATION_POSTSCRIPT;
825 else
826 o = FT_ORIENTATION_TRUETYPE;
828 if ( orient == FT_ORIENTATION_NONE )
829 orient = o;
830 else if ( orient != o )
831 return FT_ORIENTATION_NONE;
835 return orient;
838 #endif /* 0 */
841 /* documentation is in ftoutln.h */
843 FT_EXPORT_DEF( FT_Error )
844 FT_Outline_Embolden( FT_Outline* outline,
845 FT_Pos strength )
847 FT_Vector* points;
848 FT_Vector v_prev, v_first, v_next, v_cur;
849 FT_Angle rotate, angle_in, angle_out;
850 FT_Int c, n, first;
851 FT_Int orientation;
854 if ( !outline )
855 return FT_Err_Invalid_Argument;
857 strength /= 2;
858 if ( strength == 0 )
859 return FT_Err_Ok;
861 orientation = FT_Outline_Get_Orientation( outline );
862 if ( orientation == FT_ORIENTATION_NONE )
864 if ( outline->n_contours )
865 return FT_Err_Invalid_Argument;
866 else
867 return FT_Err_Ok;
870 if ( orientation == FT_ORIENTATION_TRUETYPE )
871 rotate = -FT_ANGLE_PI2;
872 else
873 rotate = FT_ANGLE_PI2;
875 points = outline->points;
877 first = 0;
878 for ( c = 0; c < outline->n_contours; c++ )
880 int last = outline->contours[c];
883 v_first = points[first];
884 v_prev = points[last];
885 v_cur = v_first;
887 for ( n = first; n <= last; n++ )
889 FT_Vector in, out;
890 FT_Angle angle_diff;
891 FT_Pos d;
892 FT_Fixed scale;
895 if ( n < last )
896 v_next = points[n + 1];
897 else
898 v_next = v_first;
900 /* compute the in and out vectors */
901 in.x = v_cur.x - v_prev.x;
902 in.y = v_cur.y - v_prev.y;
904 out.x = v_next.x - v_cur.x;
905 out.y = v_next.y - v_cur.y;
907 angle_in = FT_Atan2( in.x, in.y );
908 angle_out = FT_Atan2( out.x, out.y );
909 angle_diff = FT_Angle_Diff( angle_in, angle_out );
910 scale = FT_Cos( angle_diff / 2 );
912 if ( scale < 0x4000L && scale > -0x4000L )
913 in.x = in.y = 0;
914 else
916 d = FT_DivFix( strength, scale );
918 FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
921 outline->points[n].x = v_cur.x + strength + in.x;
922 outline->points[n].y = v_cur.y + strength + in.y;
924 v_prev = v_cur;
925 v_cur = v_next;
928 first = last + 1;
931 return FT_Err_Ok;
935 /* documentation is in ftoutln.h */
937 FT_EXPORT_DEF( FT_Orientation )
938 FT_Outline_Get_Orientation( FT_Outline* outline )
940 FT_Pos xmin = 32768L;
941 FT_Pos xmin_ymin = 32768L;
942 FT_Pos xmin_ymax = -32768L;
943 FT_Vector* xmin_first = NULL;
944 FT_Vector* xmin_last = NULL;
946 short* contour;
948 FT_Vector* first;
949 FT_Vector* last;
950 FT_Vector* prev;
951 FT_Vector* point;
953 int i;
954 FT_Pos ray_y[3];
955 FT_Orientation result[3];
958 if ( !outline || outline->n_points <= 0 )
959 return FT_ORIENTATION_TRUETYPE;
961 /* We use the nonzero winding rule to find the orientation. */
962 /* Since glyph outlines behave much more `regular' than arbitrary */
963 /* cubic or quadratic curves, this test deals with the polygon */
964 /* only which is spanned up by the control points. */
966 first = outline->points;
967 for ( contour = outline->contours;
968 contour < outline->contours + outline->n_contours;
969 contour++, first = last + 1 )
971 FT_Pos contour_xmin = 32768L;
972 FT_Pos contour_xmax = -32768L;
973 FT_Pos contour_ymin = 32768L;
974 FT_Pos contour_ymax = -32768L;
977 last = outline->points + *contour;
979 /* skip degenerate contours */
980 if ( last < first + 2 )
981 continue;
983 for ( point = first; point <= last; ++point )
985 if ( point->x < contour_xmin )
986 contour_xmin = point->x;
988 if ( point->x > contour_xmax )
989 contour_xmax = point->x;
991 if ( point->y < contour_ymin )
992 contour_ymin = point->y;
994 if ( point->y > contour_ymax )
995 contour_ymax = point->y;
998 if ( contour_xmin < xmin &&
999 contour_xmin != contour_xmax &&
1000 contour_ymin != contour_ymax )
1002 xmin = contour_xmin;
1003 xmin_ymin = contour_ymin;
1004 xmin_ymax = contour_ymax;
1005 xmin_first = first;
1006 xmin_last = last;
1010 if ( xmin == 32768 )
1011 return FT_ORIENTATION_TRUETYPE;
1013 ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2;
1014 ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1;
1015 ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2;
1017 for ( i = 0; i < 3; i++ )
1019 FT_Pos left_x;
1020 FT_Pos right_x;
1021 FT_Vector* left1;
1022 FT_Vector* left2;
1023 FT_Vector* right1;
1024 FT_Vector* right2;
1027 RedoRay:
1028 left_x = 32768L;
1029 right_x = -32768L;
1031 left1 = left2 = right1 = right2 = NULL;
1033 prev = xmin_last;
1034 for ( point = xmin_first; point <= xmin_last; prev = point, ++point )
1036 FT_Pos tmp_x;
1039 if ( point->y == ray_y[i] || prev->y == ray_y[i] )
1041 ray_y[i]++;
1042 goto RedoRay;
1045 if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) ||
1046 ( point->y > ray_y[i] && prev->y > ray_y[i] ) )
1047 continue;
1049 tmp_x = FT_MulDiv( point->x - prev->x,
1050 ray_y[i] - prev->y,
1051 point->y - prev->y ) + prev->x;
1053 if ( tmp_x < left_x )
1055 left_x = tmp_x;
1056 left1 = prev;
1057 left2 = point;
1060 if ( tmp_x > right_x )
1062 right_x = tmp_x;
1063 right1 = prev;
1064 right2 = point;
1068 if ( left1 && right1 )
1070 if ( left1->y < left2->y && right1->y > right2->y )
1071 result[i] = FT_ORIENTATION_TRUETYPE;
1072 else if ( left1->y > left2->y && right1->y < right2->y )
1073 result[i] = FT_ORIENTATION_POSTSCRIPT;
1074 else
1075 result[i] = FT_ORIENTATION_NONE;
1079 if ( result[0] != FT_ORIENTATION_NONE &&
1080 ( result[0] == result[1] || result[0] == result[2] ) )
1081 return result[0];
1083 if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )
1084 return result[1];
1086 return FT_ORIENTATION_TRUETYPE;
1090 /* END */