]> git.saurik.com Git - wxWidgets.git/blame - src/freetype/base/ftoutln.c
wxDC::SetFont can now handle invalid font and doesn't assert anymore (other ports...
[wxWidgets.git] / src / freetype / base / ftoutln.c
CommitLineData
cabec872
RR
1/***************************************************************************/
2/* */
3/* ftoutln.c */
4/* */
5/* FreeType outline management (body). */
6/* */
7/* Copyright 1996-2000 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/***************************************************************************/
17
18
19 /*************************************************************************/
20 /* */
21 /* All functions are declared in freetype.h. */
22 /* */
23 /*************************************************************************/
24
25
26#include <freetype/ftoutln.h>
27#include <freetype/internal/ftobjs.h>
28
29
30 /*************************************************************************/
31 /* */
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
34 /* messages during execution. */
35 /* */
36#undef FT_COMPONENT
37#define FT_COMPONENT trace_outline
38
39
40 static
41 const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
42
43
44 /*************************************************************************/
45 /* */
46 /* <Function> */
47 /* FT_Outline_Decompose */
48 /* */
49 /* <Description> */
50 /* Walks over an outline's structure to decompose it into individual */
51 /* segments and Bezier arcs. This function is also able to emit */
52 /* `move to' and `close to' operations to indicate the start and end */
53 /* of new contours in the outline. */
54 /* */
55 /* <Input> */
56 /* outline :: A pointer to the source target. */
57 /* */
58 /* interface :: A table of `emitters', i.e,. function pointers called */
59 /* during decomposition to indicate path operations. */
60 /* */
61 /* user :: A typeless pointer which is passed to each emitter */
62 /* during the decomposition. It can be used to store */
63 /* the state during the decomposition. */
64 /* */
65 /* <Return> */
66 /* FreeType error code. 0 means sucess. */
67 /* */
68 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Decompose(
69 FT_Outline* outline,
70 FT_Outline_Funcs* interface,
71 void* user )
72 {
73#undef SCALED
74#define SCALED( x ) ( ( (x) << shift ) - delta )
75
76 FT_Vector v_last;
77 FT_Vector v_control;
78 FT_Vector v_start;
79
80 FT_Vector* point;
81 FT_Vector* limit;
82 char* tags;
83
84 FT_Error error;
85
86 FT_Int n; /* index of contour in outline */
87 FT_UInt first; /* index of first point in contour */
88 char tag; /* current point's state */
89
90 FT_Int shift;
91 FT_Pos delta;
92
93
94 if ( !outline || !interface )
95 return FT_Err_Invalid_Argument;
96
97 shift = interface->shift;
98 delta = interface->delta;
99 first = 0;
100
101 for ( n = 0; n < outline->n_contours; n++ )
102 {
103 FT_Int last; /* index of last point in contour */
104
105
106 last = outline->contours[n];
107 limit = outline->points + last;
108
109 v_start = outline->points[first];
110 v_last = outline->points[last];
111
112 v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
113 v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
114
115 v_control = v_start;
116
117 point = outline->points + first;
118 tags = outline->tags + first;
119 tag = FT_CURVE_TAG( tags[0] );
120
121 /* A contour cannot start with a cubic control point! */
122 if ( tag == FT_Curve_Tag_Cubic )
123 goto Invalid_Outline;
124
125 /* check first point to determine origin */
126 if ( tag == FT_Curve_Tag_Conic )
127 {
128 /* first point is conic control. Yes, this happens. */
129 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
130 {
131 /* start at last point if it is on the curve */
132 v_start = v_last;
133 limit--;
134 }
135 else
136 {
137 /* if both first and last points are conic, */
138 /* start at their middle and record its position */
139 /* for closure */
140 v_start.x = ( v_start.x + v_last.x ) / 2;
141 v_start.y = ( v_start.y + v_last.y ) / 2;
142
143 v_last = v_start;
144 }
145 point--;
146 tags--;
147 }
148
149 error = interface->move_to( &v_start, user );
150 if ( error )
151 goto Exit;
152
153 while ( point < limit )
154 {
155 point++;
156 tags++;
157
158 tag = FT_CURVE_TAG( tags[0] );
159 switch ( tag )
160 {
161 case FT_Curve_Tag_On: /* emit a single line_to */
162 {
163 FT_Vector vec;
164
165
166 vec.x = SCALED( point->x );
167 vec.y = SCALED( point->y );
168
169 error = interface->line_to( &vec, user );
170 if ( error )
171 goto Exit;
172 continue;
173 }
174
175 case FT_Curve_Tag_Conic: /* consume conic arcs */
176 v_control.x = SCALED( point->x );
177 v_control.y = SCALED( point->y );
178
179 Do_Conic:
180 if ( point < limit )
181 {
182 FT_Vector vec;
183 FT_Vector v_middle;
184
185
186 point++;
187 tags++;
188 tag = FT_CURVE_TAG( tags[0] );
189
190 vec.x = SCALED( point->x );
191 vec.y = SCALED( point->y );
192
193 if ( tag == FT_Curve_Tag_On )
194 {
195 error = interface->conic_to( &v_control, &vec, user );
196 if ( error )
197 goto Exit;
198 continue;
199 }
200
201 if ( tag != FT_Curve_Tag_Conic )
202 goto Invalid_Outline;
203
204 v_middle.x = ( v_control.x + vec.x ) / 2;
205 v_middle.y = ( v_control.y + vec.y ) / 2;
206
207 error = interface->conic_to( &v_control, &v_middle, user );
208 if ( error )
209 goto Exit;
210
211 v_control = vec;
212 goto Do_Conic;
213 }
214
215 error = interface->conic_to( &v_control, &v_start, user );
216 goto Close;
217
218 default: /* FT_Curve_Tag_Cubic */
219 {
220 FT_Vector vec1, vec2;
221
222
223 if ( point + 1 > limit ||
224 FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
225 goto Invalid_Outline;
226
227 point += 2;
228 tags += 2;
229
230 vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
231 vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
232
233 if ( point <= limit )
234 {
235 FT_Vector vec;
236
237
238 vec.x = SCALED( point->x );
239 vec.y = SCALED( point->y );
240
241 error = interface->cubic_to( &vec1, &vec2, &vec, user );
242 if ( error )
243 goto Exit;
244 continue;
245 }
246
247 error = interface->cubic_to( &vec1, &vec2, &v_start, user );
248 goto Close;
249 }
250 }
251 }
252
253 /* close the contour with a line segment */
254 error = interface->line_to( &v_start, user );
255
256 Close:
257 if ( error )
258 goto Exit;
259
260 first = last + 1;
261 }
262
263 return 0;
264
265 Exit:
266 return error;
267
268 Invalid_Outline:
269 return FT_Err_Invalid_Outline;
270 }
271
272
273 FT_EXPORT_FUNC( FT_Error ) FT_Outline_New_Internal(
274 FT_Memory memory,
275 FT_UInt numPoints,
276 FT_Int numContours,
277 FT_Outline* outline )
278 {
279 FT_Error error;
280
281
282 if ( !outline || !memory )
283 return FT_Err_Invalid_Argument;
284
285 *outline = null_outline;
286
287 if ( ALLOC_ARRAY( outline->points, numPoints * 2L, FT_Pos ) ||
288 ALLOC_ARRAY( outline->tags, numPoints, FT_Byte ) ||
289 ALLOC_ARRAY( outline->contours, numContours, FT_UShort ) )
290 goto Fail;
291
292 outline->n_points = (FT_UShort)numPoints;
293 outline->n_contours = (FT_Short)numContours;
294 outline->flags |= ft_outline_owner;
295
296 return FT_Err_Ok;
297
298 Fail:
299 outline->flags |= ft_outline_owner;
300 FT_Outline_Done_Internal( memory, outline );
301
302 return error;
303 }
304
305
306 /*************************************************************************/
307 /* */
308 /* <Function> */
309 /* FT_Outline_New */
310 /* */
311 /* <Description> */
312 /* Creates a new outline of a given size. */
313 /* */
314 /* <Input> */
315 /* library :: A handle to the library object from where the */
316 /* outline is allocated. Note however that the new */
317 /* outline will NOT necessarily be FREED, when */
318 /* destroying the library, by FT_Done_FreeType(). */
319 /* */
320 /* numPoints :: The maximal number of points within the outline. */
321 /* */
322 /* numContours :: The maximal number of contours within the outline. */
323 /* */
324 /* <Output> */
325 /* outline :: A handle to the new outline. NULL in case of */
326 /* error. */
327 /* */
328 /* <Return> */
329 /* FreeType error code. 0 means success. */
330 /* */
331 /* <MT-Note> */
332 /* No. */
333 /* */
334 /* <Note> */
335 /* The reason why this function takes a `library' parameter is simply */
336 /* to use the library's memory allocator. */
337 /* */
338 FT_EXPORT_FUNC( FT_Error ) FT_Outline_New( FT_Library library,
339 FT_UInt numPoints,
340 FT_Int numContours,
341 FT_Outline* outline )
342 {
343 if ( !library )
344 return FT_Err_Invalid_Library_Handle;
345
346 return FT_Outline_New_Internal( library->memory, numPoints,
347 numContours, outline );
348 }
349
350
351 /*************************************************************************/
352 /* */
353 /* <Function> */
354 /* FT_Outline_Copy */
355 /* */
356 /* <Description> */
357 /* Copies an outline into another one. Both objects must have the */
358 /* same sizes (number of points & number of contours) when this */
359 /* function is called. */
360 /* */
361 /* <Input> */
362 /* source :: A handle to the source outline. */
363 /* */
364 /* <Output> */
365 /* target :: A handle to the target outline. */
366 /* */
367 /* <Return> */
368 /* FreeType error code. 0 means success. */
369 /* */
370 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Copy( FT_Outline* source,
371 FT_Outline* target )
372 {
373 FT_Int is_owner;
374
375
376 if ( !source || !target ||
377 source->n_points != target->n_points ||
378 source->n_contours != target->n_contours )
379 return FT_Err_Invalid_Argument;
380
381 MEM_Copy( target->points, source->points,
382 source->n_points * sizeof ( FT_Vector ) );
383
384 MEM_Copy( target->tags, source->tags,
385 source->n_points * sizeof ( FT_Byte ) );
386
387 MEM_Copy( target->contours, source->contours,
388 source->n_contours * sizeof ( FT_Short ) );
389
390 /* copy all flags, except the `ft_outline_owner' one */
391 is_owner = target->flags & ft_outline_owner;
392 target->flags = source->flags;
393
394 target->flags &= ~ft_outline_owner;
395 target->flags |= is_owner;
396
397 return FT_Err_Ok;
398 }
399
400
401 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Done_Internal( FT_Memory memory,
402 FT_Outline* outline )
403 {
404 if ( outline )
405 {
406 if ( outline->flags & ft_outline_owner )
407 {
408 FREE( outline->points );
409 FREE( outline->tags );
410 FREE( outline->contours );
411 }
412 *outline = null_outline;
413
414 return FT_Err_Ok;
415 }
416 else
417 return FT_Err_Invalid_Argument;
418 }
419
420
421 /*************************************************************************/
422 /* */
423 /* <Function> */
424 /* FT_Outline_Done */
425 /* */
426 /* <Description> */
427 /* Destroys an outline created with FT_Outline_New(). */
428 /* */
429 /* <Input> */
430 /* library :: A handle of the library object used to allocate the */
431 /* outline. */
432 /* */
433 /* outline :: A pointer to the outline object to be discarded. */
434 /* */
435 /* <Return> */
436 /* FreeType error code. 0 means success. */
437 /* */
438 /* <MT-Note> */
439 /* No. */
440 /* */
441 /* <Note> */
442 /* If the outline's `owner' field is not set, only the outline */
443 /* descriptor will be released. */
444 /* */
445 /* The reason why this function takes an `outline' parameter is */
446 /* simply to use FT_Free(). */
447 /* */
448 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Done( FT_Library library,
449 FT_Outline* outline )
450 {
451 /* check for valid `outline' in FT_Outline_Done_Internal() */
452
453 if ( !library )
454 return FT_Err_Invalid_Library_Handle;
455
456 return FT_Outline_Done_Internal( library->memory, outline );
457 }
458
459
460 /*************************************************************************/
461 /* */
462 /* <Function> */
463 /* FT_Outline_Get_CBox */
464 /* */
465 /* <Description> */
466 /* Returns an outline's `control box'. The control box encloses all */
467 /* the outline's points, including Bezier control points. Though it */
468 /* coincides with the exact bounding box for most glyphs, it can be */
469 /* slightly larger in some situations (like when rotating an outline */
470 /* which contains Bezier outside arcs). */
471 /* */
472 /* Computing the control box is very fast, while getting the bounding */
473 /* box can take much more time as it needs to walk over all segments */
474 /* and arcs in the outline. To get the latter, you can use the */
475 /* `ftbbox' component which is dedicated to this single task. */
476 /* */
477 /* <Input> */
478 /* outline :: A pointer to the source outline descriptor. */
479 /* */
480 /* <Output> */
481 /* cbox :: The outline's control box. */
482 /* */
483 /* <MT-Note> */
484 /* Yes. */
485 /* */
486 FT_EXPORT_FUNC( void ) FT_Outline_Get_CBox( FT_Outline* outline,
487 FT_BBox* cbox )
488 {
489 FT_Pos xMin, yMin, xMax, yMax;
490
491
492 if ( outline && cbox )
493 {
494 if ( outline->n_points == 0 )
495 {
496 xMin = 0;
497 yMin = 0;
498 xMax = 0;
499 yMax = 0;
500 }
501 else
502 {
503 FT_Vector* vec = outline->points;
504 FT_Vector* limit = vec + outline->n_points;
505
506
507 xMin = xMax = vec->x;
508 yMin = yMax = vec->y;
509 vec++;
510
511 for ( ; vec < limit; vec++ )
512 {
513 FT_Pos x, y;
514
515
516 x = vec->x;
517 if ( x < xMin ) xMin = x;
518 if ( x > xMax ) xMax = x;
519
520 y = vec->y;
521 if ( y < yMin ) yMin = y;
522 if ( y > yMax ) yMax = y;
523 }
524 }
525 cbox->xMin = xMin;
526 cbox->xMax = xMax;
527 cbox->yMin = yMin;
528 cbox->yMax = yMax;
529 }
530 }
531
532
533 /*************************************************************************/
534 /* */
535 /* <Function> */
536 /* FT_Outline_Translate */
537 /* */
538 /* <Description> */
539 /* Applies a simple translation to the points of an outline. */
540 /* */
541 /* <Input> */
542 /* outline :: A pointer to the target outline descriptor. */
543 /* */
544 /* xOffset :: The horizontal offset. */
545 /* */
546 /* yOffset :: The vertical offset. */
547 /* */
548 /* <MT-Note> */
549 /* Yes. */
550 /* */
551 FT_EXPORT_FUNC( void ) FT_Outline_Translate( FT_Outline* outline,
552 FT_Pos xOffset,
553 FT_Pos yOffset )
554 {
555 FT_UShort n;
556 FT_Vector* vec = outline->points;
557
558
559 for ( n = 0; n < outline->n_points; n++ )
560 {
561 vec->x += xOffset;
562 vec->y += yOffset;
563 vec++;
564 }
565 }
566
567
568 /*************************************************************************/
569 /* */
570 /* <Function> */
571 /* FT_Outline_Reverse */
572 /* */
573 /* <Description> */
574 /* Reverses the drawing direction of an outline. This is used to */
575 /* ensure consistent fill conventions for mirrored glyphs. */
576 /* */
577 /* <Input> */
578 /* outline :: A pointer to the target outline descriptor. */
579 /* */
580 /* <Note> */
581 /* This functions toggles the bit flag `ft_outline_reverse_fill' in */
582 /* the outline's `flags' field. */
583 /* */
584 FT_EXPORT_FUNC( void ) FT_Outline_Reverse( FT_Outline* outline )
585 {
586 FT_UShort n;
587 FT_Int first, last;
588
589
590 first = 0;
591
592 for ( n = 0; n < outline->n_contours; n++ )
593 {
594 last = outline->contours[n];
595
596 /* reverse point table */
597 {
598 FT_Vector* p = outline->points + first;
599 FT_Vector* q = outline->points + last;
600 FT_Vector swap;
601
602
603 while ( p < q )
604 {
605 swap = *p;
606 *p = *q;
607 *q = swap;
608 p++;
609 q--;
610 }
611 }
612
613 /* reverse tags table */
614 {
615 char* p = outline->tags + first;
616 char* q = outline->tags + last;
617 char swap;
618
619
620 while ( p < q )
621 {
622 swap = *p;
623 *p = *q;
624 *q = swap;
625 p++;
626 q--;
627 }
628 }
629
630 first = last + 1;
631 }
632
633 outline->flags ^= ft_outline_reverse_fill;
634 }
635
636
637 /*************************************************************************/
638 /* */
639 /* <Function> */
640 /* FT_Outline_Render */
641 /* */
642 /* <Description> */
643 /* Renders an outline within a bitmap using the current scan-convert. */
644 /* This functions uses an FT_Raster_Params structure as an argument, */
645 /* allowing advanced features like direct composition, translucency, */
646 /* etc. */
647 /* */
648 /* <Input> */
649 /* library :: A handle to a FreeType library object. */
650 /* */
651 /* outline :: A pointer to the source outline descriptor. */
652 /* */
653 /* params :: A pointer to a FT_Raster_Params structure used to */
654 /* describe the rendering operation. */
655 /* */
656 /* <Return> */
657 /* FreeType error code. 0 means success. */
658 /* */
659 /* <MT-Note> */
660 /* YES. Rendering is synchronized, so that concurrent calls to the */
661 /* scan-line converter will be serialized. */
662 /* */
663 /* <Note> */
664 /* You should know what you are doing and how FT_Raster_Params works */
665 /* to use this function. */
666 /* */
667 /* The field `params.source' will be set to `outline' before the scan */
668 /* converter is called, which means that the value you give to it is */
669 /* actually ignored. */
670 /* */
671 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Render( FT_Library library,
672 FT_Outline* outline,
673 FT_Raster_Params* params )
674 {
675 FT_Error error;
676 FT_Bool update = 0;
677 FT_Renderer renderer;
678 FT_ListNode node;
679
680
681 if ( !library )
682 return FT_Err_Invalid_Library_Handle;
683
684 if ( !params )
685 return FT_Err_Invalid_Argument;
686
687 renderer = library->cur_renderer;
688 node = library->renderers.head;
689
690 params->source = (void*)outline;
691
692 error = FT_Err_Cannot_Render_Glyph;
693 while ( renderer )
694 {
695 error = renderer->raster_render( renderer->raster, params );
696 if ( !error || error != FT_Err_Cannot_Render_Glyph )
697 break;
698
699 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
700 /* is unsupported by the current renderer for this glyph image */
701 /* format */
702
703 /* now, look for another renderer that supports the same */
704 /* format */
705 renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline,
706 &node );
707 update = 1;
708 }
709
710 /* if we changed the current renderer for the glyph image format */
711 /* we need to select it as the next current one */
712 if ( !error && update && renderer )
713 FT_Set_Renderer( library, renderer, 0, 0 );
714
715 return error;
716 }
717
718
719 /*************************************************************************/
720 /* */
721 /* <Function> */
722 /* FT_Outline_Get_Bitmap */
723 /* */
724 /* <Description> */
725 /* Renders an outline within a bitmap. The outline's image is simply */
726 /* OR-ed to the target bitmap. */
727 /* */
728 /* <Input> */
729 /* library :: A handle to a FreeType library object. */
730 /* */
731 /* outline :: A pointer to the source outline descriptor. */
732 /* */
733 /* map :: A pointer to the target bitmap descriptor. */
734 /* */
735 /* <Return> */
736 /* FreeType error code. 0 means success. */
737 /* */
738 /* <MT-Note> */
739 /* YES. Rendering is synchronized, so that concurrent calls to the */
740 /* scan-line converter will be serialized. */
741 /* */
742 /* <Note> */
743 /* This function does NOT CREATE the bitmap, it only renders an */
744 /* outline image within the one you pass to it! */
745 /* */
746 /* It will use the raster correponding to the default glyph format. */
747 /* */
748 FT_EXPORT_FUNC( FT_Error ) FT_Outline_Get_Bitmap( FT_Library library,
749 FT_Outline* outline,
750 FT_Bitmap* bitmap )
751 {
752 FT_Raster_Params params;
753
754
755 if ( !bitmap )
756 return FT_Err_Invalid_Argument;
757
758 /* other checks are delayed to FT_Outline_Render() */
759
760 params.target = bitmap;
761 params.flags = 0;
762
763 if ( bitmap->pixel_mode == ft_pixel_mode_grays )
764 params.flags |= ft_raster_flag_aa;
765
766 return FT_Outline_Render( library, outline, &params );
767 }
768
769
770 /*************************************************************************/
771 /* */
772 /* <Function> */
773 /* FT_Vector_Transform */
774 /* */
775 /* <Description> */
776 /* Transforms a single vector through a 2x2 matrix. */
777 /* */
778 /* <InOut> */
779 /* vector :: The target vector to transform. */
780 /* */
781 /* <Input> */
782 /* matrix :: A pointer to the source 2x2 matrix. */
783 /* */
784 /* <MT-Note> */
785 /* Yes. */
786 /* */
787 /* <Note> */
788 /* The result is undefined if either `vector' or `matrix' is invalid. */
789 /* */
790 FT_EXPORT_FUNC( void ) FT_Vector_Transform( FT_Vector* vector,
791 FT_Matrix* matrix )
792 {
793 FT_Pos xz, yz;
794
795
796 if ( !vector || !matrix )
797 return;
798
799 xz = FT_MulFix( vector->x, matrix->xx ) +
800 FT_MulFix( vector->y, matrix->xy );
801
802 yz = FT_MulFix( vector->x, matrix->yx ) +
803 FT_MulFix( vector->y, matrix->yy );
804
805 vector->x = xz;
806 vector->y = yz;
807 }
808
809
810 /*************************************************************************/
811 /* */
812 /* <Function> */
813 /* FT_Outline_Transform */
814 /* */
815 /* <Description> */
816 /* Applies a simple 2x2 matrix to all of an outline's points. Useful */
817 /* for applying rotations, slanting, flipping, etc. */
818 /* */
819 /* <Input> */
820 /* outline :: A pointer to the target outline descriptor. */
821 /* */
822 /* matrix :: A pointer to the transformation matrix. */
823 /* */
824 /* <MT-Note> */
825 /* Yes. */
826 /* */
827 /* <Note> */
828 /* You can use FT_Outline_Translate() if you need to translate the */
829 /* outline's points. */
830 /* */
831 FT_EXPORT_FUNC( void ) FT_Outline_Transform( FT_Outline* outline,
832 FT_Matrix* matrix )
833 {
834 FT_Vector* vec = outline->points;
835 FT_Vector* limit = vec + outline->n_points;
836
837
838 for ( ; vec < limit; vec++ )
839 FT_Vector_Transform( vec, matrix );
840 }
841
842/* END */