Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ftstroke.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* ftstroke.c */
4 /* */
5 /* FreeType path stroker (body). */
6 /* */
7 /* Copyright 2002-2006, 2008-2011, 2013 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 #include <ft2build.h>
20 #include FT_STROKER_H
21 #include FT_TRIGONOMETRY_H
22 #include FT_OUTLINE_H
23 #include FT_INTERNAL_MEMORY_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_OBJECTS_H
26 
27 
28  /* documentation is in ftstroke.h */
29 
32  {
34 
35 
38  }
39 
40 
41  /* documentation is in ftstroke.h */
42 
45  {
47 
48 
51  }
52 
53 
54  /*************************************************************************/
55  /*************************************************************************/
56  /***** *****/
57  /***** BEZIER COMPUTATIONS *****/
58  /***** *****/
59  /*************************************************************************/
60  /*************************************************************************/
61 
62 #define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 )
63 #define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 8 )
64 
65 #define FT_EPSILON 2
66 
67 #define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON )
68 
69 
70  static FT_Pos
71  ft_pos_abs( FT_Pos x )
72  {
73  return x >= 0 ? x : -x;
74  }
75 
76 
77  static void
78  ft_conic_split( FT_Vector* base )
79  {
80  FT_Pos a, b;
81 
82 
83  base[4].x = base[2].x;
84  b = base[1].x;
85  a = base[3].x = ( base[2].x + b ) / 2;
86  b = base[1].x = ( base[0].x + b ) / 2;
87  base[2].x = ( a + b ) / 2;
88 
89  base[4].y = base[2].y;
90  b = base[1].y;
91  a = base[3].y = ( base[2].y + b ) / 2;
92  b = base[1].y = ( base[0].y + b ) / 2;
93  base[2].y = ( a + b ) / 2;
94  }
95 
96 
97  static FT_Bool
98  ft_conic_is_small_enough( FT_Vector* base,
99  FT_Angle *angle_in,
100  FT_Angle *angle_out )
101  {
102  FT_Vector d1, d2;
103  FT_Angle theta;
104  FT_Int close1, close2;
105 
106 
107  d1.x = base[1].x - base[2].x;
108  d1.y = base[1].y - base[2].y;
109  d2.x = base[0].x - base[1].x;
110  d2.y = base[0].y - base[1].y;
111 
112  close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
113  close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
114 
115  if ( close1 )
116  {
117  if ( close2 )
118  {
119  /* basically a point; */
120  /* do nothing to retain original direction */
121  }
122  else
123  {
124  *angle_in =
125  *angle_out = FT_Atan2( d2.x, d2.y );
126  }
127  }
128  else /* !close1 */
129  {
130  if ( close2 )
131  {
132  *angle_in =
133  *angle_out = FT_Atan2( d1.x, d1.y );
134  }
135  else
136  {
137  *angle_in = FT_Atan2( d1.x, d1.y );
138  *angle_out = FT_Atan2( d2.x, d2.y );
139  }
140  }
141 
142  theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
143 
144  return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
145  }
146 
147 
148  static void
149  ft_cubic_split( FT_Vector* base )
150  {
151  FT_Pos a, b, c, d;
152 
153 
154  base[6].x = base[3].x;
155  c = base[1].x;
156  d = base[2].x;
157  base[1].x = a = ( base[0].x + c ) / 2;
158  base[5].x = b = ( base[3].x + d ) / 2;
159  c = ( c + d ) / 2;
160  base[2].x = a = ( a + c ) / 2;
161  base[4].x = b = ( b + c ) / 2;
162  base[3].x = ( a + b ) / 2;
163 
164  base[6].y = base[3].y;
165  c = base[1].y;
166  d = base[2].y;
167  base[1].y = a = ( base[0].y + c ) / 2;
168  base[5].y = b = ( base[3].y + d ) / 2;
169  c = ( c + d ) / 2;
170  base[2].y = a = ( a + c ) / 2;
171  base[4].y = b = ( b + c ) / 2;
172  base[3].y = ( a + b ) / 2;
173  }
174 
175 
176  /* Return the average of `angle1' and `angle2'. */
177  /* This gives correct result even if `angle1' and `angle2' */
178  /* have opposite signs. */
179  static FT_Angle
180  ft_angle_mean( FT_Angle angle1,
181  FT_Angle angle2 )
182  {
183  return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2;
184  }
185 
186 
187  static FT_Bool
188  ft_cubic_is_small_enough( FT_Vector* base,
189  FT_Angle *angle_in,
190  FT_Angle *angle_mid,
191  FT_Angle *angle_out )
192  {
193  FT_Vector d1, d2, d3;
194  FT_Angle theta1, theta2;
195  FT_Int close1, close2, close3;
196 
197 
198  d1.x = base[2].x - base[3].x;
199  d1.y = base[2].y - base[3].y;
200  d2.x = base[1].x - base[2].x;
201  d2.y = base[1].y - base[2].y;
202  d3.x = base[0].x - base[1].x;
203  d3.y = base[0].y - base[1].y;
204 
205  close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
206  close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
207  close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y );
208 
209  if ( close1 )
210  {
211  if ( close2 )
212  {
213  if ( close3 )
214  {
215  /* basically a point; */
216  /* do nothing to retain original direction */
217  }
218  else /* !close3 */
219  {
220  *angle_in =
221  *angle_mid =
222  *angle_out = FT_Atan2( d3.x, d3.y );
223  }
224  }
225  else /* !close2 */
226  {
227  if ( close3 )
228  {
229  *angle_in =
230  *angle_mid =
231  *angle_out = FT_Atan2( d2.x, d2.y );
232  }
233  else /* !close3 */
234  {
235  *angle_in =
236  *angle_mid = FT_Atan2( d2.x, d2.y );
237  *angle_out = FT_Atan2( d3.x, d3.y );
238  }
239  }
240  }
241  else /* !close1 */
242  {
243  if ( close2 )
244  {
245  if ( close3 )
246  {
247  *angle_in =
248  *angle_mid =
249  *angle_out = FT_Atan2( d1.x, d1.y );
250  }
251  else /* !close3 */
252  {
253  *angle_in = FT_Atan2( d1.x, d1.y );
254  *angle_out = FT_Atan2( d3.x, d3.y );
255  *angle_mid = ft_angle_mean( *angle_in, *angle_out );
256  }
257  }
258  else /* !close2 */
259  {
260  if ( close3 )
261  {
262  *angle_in = FT_Atan2( d1.x, d1.y );
263  *angle_mid =
264  *angle_out = FT_Atan2( d2.x, d2.y );
265  }
266  else /* !close3 */
267  {
268  *angle_in = FT_Atan2( d1.x, d1.y );
269  *angle_mid = FT_Atan2( d2.x, d2.y );
270  *angle_out = FT_Atan2( d3.x, d3.y );
271  }
272  }
273  }
274 
275  theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) );
276  theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
277 
278  return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
279  theta2 < FT_SMALL_CUBIC_THRESHOLD );
280  }
281 
282 
283  /*************************************************************************/
284  /*************************************************************************/
285  /***** *****/
286  /***** STROKE BORDERS *****/
287  /***** *****/
288  /*************************************************************************/
289  /*************************************************************************/
290 
291  typedef enum FT_StrokeTags_
292  {
293  FT_STROKE_TAG_ON = 1, /* on-curve point */
294  FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */
295  FT_STROKE_TAG_BEGIN = 4, /* sub-path start */
296  FT_STROKE_TAG_END = 8 /* sub-path end */
297 
298  } FT_StrokeTags;
299 
300 #define FT_STROKE_TAG_BEGIN_END ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END )
301 
302  typedef struct FT_StrokeBorderRec_
303  {
304  FT_UInt num_points;
305  FT_UInt max_points;
306  FT_Vector* points;
307  FT_Byte* tags;
308  FT_Bool movable; /* TRUE for ends of lineto borders */
309  FT_Int start; /* index of current sub-path start point */
310  FT_Memory memory;
311  FT_Bool valid;
312 
314 
315 
316  static FT_Error
317  ft_stroke_border_grow( FT_StrokeBorder border,
318  FT_UInt new_points )
319  {
320  FT_UInt old_max = border->max_points;
321  FT_UInt new_max = border->num_points + new_points;
323 
324 
325  if ( new_max > old_max )
326  {
327  FT_UInt cur_max = old_max;
328  FT_Memory memory = border->memory;
329 
330 
331  while ( cur_max < new_max )
332  cur_max += ( cur_max >> 1 ) + 16;
333 
334  if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
335  FT_RENEW_ARRAY( border->tags, old_max, cur_max ) )
336  goto Exit;
337 
338  border->max_points = cur_max;
339  }
340 
341  Exit:
342  return error;
343  }
344 
345 
346  static void
347  ft_stroke_border_close( FT_StrokeBorder border,
348  FT_Bool reverse )
349  {
350  FT_UInt start = border->start;
351  FT_UInt count = border->num_points;
352 
353 
354  FT_ASSERT( border->start >= 0 );
355 
356  /* don't record empty paths! */
357  if ( count <= start + 1U )
358  border->num_points = start;
359  else
360  {
361  /* copy the last point to the start of this sub-path, since */
362  /* it contains the `adjusted' starting coordinates */
363  border->num_points = --count;
364  border->points[start] = border->points[count];
365 
366  if ( reverse )
367  {
368  /* reverse the points */
369  {
370  FT_Vector* vec1 = border->points + start + 1;
371  FT_Vector* vec2 = border->points + count - 1;
372 
373 
374  for ( ; vec1 < vec2; vec1++, vec2-- )
375  {
376  FT_Vector tmp;
377 
378 
379  tmp = *vec1;
380  *vec1 = *vec2;
381  *vec2 = tmp;
382  }
383  }
384 
385  /* then the tags */
386  {
387  FT_Byte* tag1 = border->tags + start + 1;
388  FT_Byte* tag2 = border->tags + count - 1;
389 
390 
391  for ( ; tag1 < tag2; tag1++, tag2-- )
392  {
393  FT_Byte tmp;
394 
395 
396  tmp = *tag1;
397  *tag1 = *tag2;
398  *tag2 = tmp;
399  }
400  }
401  }
402 
403  border->tags[start ] |= FT_STROKE_TAG_BEGIN;
404  border->tags[count - 1] |= FT_STROKE_TAG_END;
405  }
406 
407  border->start = -1;
408  border->movable = FALSE;
409  }
410 
411 
412  static FT_Error
413  ft_stroke_border_lineto( FT_StrokeBorder border,
414  FT_Vector* to,
415  FT_Bool movable )
416  {
418 
419 
420  FT_ASSERT( border->start >= 0 );
421 
422  if ( border->movable )
423  {
424  /* move last point */
425  border->points[border->num_points - 1] = *to;
426  }
427  else
428  {
429  /* don't add zero-length lineto */
430  if ( border->num_points > 0 &&
431  FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) &&
432  FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) )
433  return error;
434 
435  /* add one point */
436  error = ft_stroke_border_grow( border, 1 );
437  if ( !error )
438  {
439  FT_Vector* vec = border->points + border->num_points;
440  FT_Byte* tag = border->tags + border->num_points;
441 
442 
443  vec[0] = *to;
444  tag[0] = FT_STROKE_TAG_ON;
445 
446  border->num_points += 1;
447  }
448  }
449  border->movable = movable;
450  return error;
451  }
452 
453 
454  static FT_Error
455  ft_stroke_border_conicto( FT_StrokeBorder border,
456  FT_Vector* control,
457  FT_Vector* to )
458  {
459  FT_Error error;
460 
461 
462  FT_ASSERT( border->start >= 0 );
463 
464  error = ft_stroke_border_grow( border, 2 );
465  if ( !error )
466  {
467  FT_Vector* vec = border->points + border->num_points;
468  FT_Byte* tag = border->tags + border->num_points;
469 
470 
471  vec[0] = *control;
472  vec[1] = *to;
473 
474  tag[0] = 0;
475  tag[1] = FT_STROKE_TAG_ON;
476 
477  border->num_points += 2;
478  }
479 
480  border->movable = FALSE;
481 
482  return error;
483  }
484 
485 
486  static FT_Error
487  ft_stroke_border_cubicto( FT_StrokeBorder border,
488  FT_Vector* control1,
489  FT_Vector* control2,
490  FT_Vector* to )
491  {
492  FT_Error error;
493 
494 
495  FT_ASSERT( border->start >= 0 );
496 
497  error = ft_stroke_border_grow( border, 3 );
498  if ( !error )
499  {
500  FT_Vector* vec = border->points + border->num_points;
501  FT_Byte* tag = border->tags + border->num_points;
502 
503 
504  vec[0] = *control1;
505  vec[1] = *control2;
506  vec[2] = *to;
507 
508  tag[0] = FT_STROKE_TAG_CUBIC;
509  tag[1] = FT_STROKE_TAG_CUBIC;
510  tag[2] = FT_STROKE_TAG_ON;
511 
512  border->num_points += 3;
513  }
514 
515  border->movable = FALSE;
516 
517  return error;
518  }
519 
520 
521 #define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 )
522 
523 
524  static FT_Error
525  ft_stroke_border_arcto( FT_StrokeBorder border,
526  FT_Vector* center,
527  FT_Fixed radius,
528  FT_Angle angle_start,
529  FT_Angle angle_diff )
530  {
531  FT_Angle total, angle, step, rotate, next, theta;
532  FT_Vector a, b, a2, b2;
535 
536 
537  /* compute start point */
538  FT_Vector_From_Polar( &a, radius, angle_start );
539  a.x += center->x;
540  a.y += center->y;
541 
542  total = angle_diff;
543  angle = angle_start;
544  rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
545 
546  while ( total != 0 )
547  {
548  step = total;
549  if ( step > FT_ARC_CUBIC_ANGLE )
550  step = FT_ARC_CUBIC_ANGLE;
551 
552  else if ( step < -FT_ARC_CUBIC_ANGLE )
553  step = -FT_ARC_CUBIC_ANGLE;
554 
555  next = angle + step;
556  theta = step;
557  if ( theta < 0 )
558  theta = -theta;
559 
560  theta >>= 1;
561 
562  /* compute end point */
563  FT_Vector_From_Polar( &b, radius, next );
564  b.x += center->x;
565  b.y += center->y;
566 
567  /* compute first and second control points */
568  length = FT_MulDiv( radius, FT_Sin( theta ) * 4,
569  ( 0x10000L + FT_Cos( theta ) ) * 3 );
570 
571  FT_Vector_From_Polar( &a2, length, angle + rotate );
572  a2.x += a.x;
573  a2.y += a.y;
574 
575  FT_Vector_From_Polar( &b2, length, next - rotate );
576  b2.x += b.x;
577  b2.y += b.y;
578 
579  /* add cubic arc */
580  error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
581  if ( error )
582  break;
583 
584  /* process the rest of the arc ?? */
585  a = b;
586  total -= step;
587  angle = next;
588  }
589 
590  return error;
591  }
592 
593 
594  static FT_Error
595  ft_stroke_border_moveto( FT_StrokeBorder border,
596  FT_Vector* to )
597  {
598  /* close current open path if any ? */
599  if ( border->start >= 0 )
600  ft_stroke_border_close( border, FALSE );
601 
602  border->start = border->num_points;
603  border->movable = FALSE;
604 
605  return ft_stroke_border_lineto( border, to, FALSE );
606  }
607 
608 
609  static void
610  ft_stroke_border_init( FT_StrokeBorder border,
611  FT_Memory memory )
612  {
613  border->memory = memory;
614  border->points = NULL;
615  border->tags = NULL;
616 
617  border->num_points = 0;
618  border->max_points = 0;
619  border->start = -1;
620  border->valid = FALSE;
621  }
622 
623 
624  static void
625  ft_stroke_border_reset( FT_StrokeBorder border )
626  {
627  border->num_points = 0;
628  border->start = -1;
629  border->valid = FALSE;
630  }
631 
632 
633  static void
634  ft_stroke_border_done( FT_StrokeBorder border )
635  {
636  FT_Memory memory = border->memory;
637 
638 
639  FT_FREE( border->points );
640  FT_FREE( border->tags );
641 
642  border->num_points = 0;
643  border->max_points = 0;
644  border->start = -1;
645  border->valid = FALSE;
646  }
647 
648 
649  static FT_Error
650  ft_stroke_border_get_counts( FT_StrokeBorder border,
651  FT_UInt *anum_points,
652  FT_UInt *anum_contours )
653  {
655  FT_UInt num_points = 0;
656  FT_UInt num_contours = 0;
657 
658  FT_UInt count = border->num_points;
659  FT_Vector* point = border->points;
660  FT_Byte* tags = border->tags;
661  FT_Int in_contour = 0;
662 
663 
664  for ( ; count > 0; count--, num_points++, point++, tags++ )
665  {
666  if ( tags[0] & FT_STROKE_TAG_BEGIN )
667  {
668  if ( in_contour != 0 )
669  goto Fail;
670 
671  in_contour = 1;
672  }
673  else if ( in_contour == 0 )
674  goto Fail;
675 
676  if ( tags[0] & FT_STROKE_TAG_END )
677  {
678  in_contour = 0;
679  num_contours++;
680  }
681  }
682 
683  if ( in_contour != 0 )
684  goto Fail;
685 
686  border->valid = TRUE;
687 
688  Exit:
689  *anum_points = num_points;
690  *anum_contours = num_contours;
691  return error;
692 
693  Fail:
694  num_points = 0;
695  num_contours = 0;
696  goto Exit;
697  }
698 
699 
700  static void
701  ft_stroke_border_export( FT_StrokeBorder border,
702  FT_Outline* outline )
703  {
704  /* copy point locations */
705  FT_ARRAY_COPY( outline->points + outline->n_points,
706  border->points,
707  border->num_points );
708 
709  /* copy tags */
710  {
711  FT_UInt count = border->num_points;
712  FT_Byte* read = border->tags;
713  FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points;
714 
715 
716  for ( ; count > 0; count--, read++, write++ )
717  {
718  if ( *read & FT_STROKE_TAG_ON )
719  *write = FT_CURVE_TAG_ON;
720  else if ( *read & FT_STROKE_TAG_CUBIC )
721  *write = FT_CURVE_TAG_CUBIC;
722  else
723  *write = FT_CURVE_TAG_CONIC;
724  }
725  }
726 
727  /* copy contours */
728  {
729  FT_UInt count = border->num_points;
730  FT_Byte* tags = border->tags;
731  FT_Short* write = outline->contours + outline->n_contours;
732  FT_Short idx = (FT_Short)outline->n_points;
733 
734 
735  for ( ; count > 0; count--, tags++, idx++ )
736  {
737  if ( *tags & FT_STROKE_TAG_END )
738  {
739  *write++ = idx;
740  outline->n_contours++;
741  }
742  }
743  }
744 
745  outline->n_points = (short)( outline->n_points + border->num_points );
746 
747  FT_ASSERT( FT_Outline_Check( outline ) == 0 );
748  }
749 
750 
751  /*************************************************************************/
752  /*************************************************************************/
753  /***** *****/
754  /***** STROKER *****/
755  /***** *****/
756  /*************************************************************************/
757  /*************************************************************************/
758 
759 #define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI )
760 
761  typedef struct FT_StrokerRec_
762  {
763  FT_Angle angle_in; /* direction into curr join */
764  FT_Angle angle_out; /* direction out of join */
765  FT_Vector center; /* current position */
766  FT_Fixed line_length; /* length of last lineto */
767  FT_Bool first_point; /* is this the start? */
768  FT_Bool subpath_open; /* is the subpath open? */
769  FT_Angle subpath_angle; /* subpath start direction */
770  FT_Vector subpath_start; /* subpath start position */
771  FT_Fixed subpath_line_length; /* subpath start lineto len */
772  FT_Bool handle_wide_strokes; /* use wide strokes logic? */
773 
774  FT_Stroker_LineCap line_cap;
775  FT_Stroker_LineJoin line_join;
776  FT_Stroker_LineJoin line_join_saved;
777  FT_Fixed miter_limit;
778  FT_Fixed radius;
779 
780  FT_StrokeBorderRec borders[2];
782 
783  } FT_StrokerRec;
784 
785 
786  /* documentation is in ftstroke.h */
787 
790  FT_Stroker *astroker )
791  {
792  FT_Error error; /* assigned in FT_NEW */
793  FT_Memory memory;
794  FT_Stroker stroker = NULL;
795 
796 
797  if ( !library )
798  return FT_THROW( Invalid_Argument );
799 
800  memory = library->memory;
801 
802  if ( !FT_NEW( stroker ) )
803  {
804  stroker->library = library;
805 
806  ft_stroke_border_init( &stroker->borders[0], memory );
807  ft_stroke_border_init( &stroker->borders[1], memory );
808  }
809 
810  *astroker = stroker;
811 
812  return error;
813  }
814 
815 
816  /* documentation is in ftstroke.h */
817 
818  FT_EXPORT_DEF( void )
820  FT_Fixed radius,
821  FT_Stroker_LineCap line_cap,
822  FT_Stroker_LineJoin line_join,
823  FT_Fixed miter_limit )
824  {
825  stroker->radius = radius;
826  stroker->line_cap = line_cap;
827  stroker->line_join = line_join;
828  stroker->miter_limit = miter_limit;
829 
830  /* ensure miter limit has sensible value */
831  if ( stroker->miter_limit < 0x10000 )
832  stroker->miter_limit = 0x10000;
833 
834  /* save line join style: */
835  /* line join style can be temporarily changed when stroking curves */
836  stroker->line_join_saved = line_join;
837 
838  FT_Stroker_Rewind( stroker );
839  }
840 
841 
842  /* documentation is in ftstroke.h */
843 
844  FT_EXPORT_DEF( void )
846  {
847  if ( stroker )
848  {
849  ft_stroke_border_reset( &stroker->borders[0] );
850  ft_stroke_border_reset( &stroker->borders[1] );
851  }
852  }
853 
854 
855  /* documentation is in ftstroke.h */
856 
857  FT_EXPORT_DEF( void )
859  {
860  if ( stroker )
861  {
862  FT_Memory memory = stroker->library->memory;
863 
864 
865  ft_stroke_border_done( &stroker->borders[0] );
866  ft_stroke_border_done( &stroker->borders[1] );
867 
868  stroker->library = NULL;
869  FT_FREE( stroker );
870  }
871  }
872 
873 
874  /* create a circular arc at a corner or cap */
875  static FT_Error
876  ft_stroker_arcto( FT_Stroker stroker,
877  FT_Int side )
878  {
879  FT_Angle total, rotate;
880  FT_Fixed radius = stroker->radius;
882  FT_StrokeBorder border = stroker->borders + side;
883 
884 
885  rotate = FT_SIDE_TO_ROTATE( side );
886 
887  total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
888  if ( total == FT_ANGLE_PI )
889  total = -rotate * 2;
890 
891  error = ft_stroke_border_arcto( border,
892  &stroker->center,
893  radius,
894  stroker->angle_in + rotate,
895  total );
896  border->movable = FALSE;
897  return error;
898  }
899 
900 
901  /* add a cap at the end of an opened path */
902  static FT_Error
903  ft_stroker_cap( FT_Stroker stroker,
904  FT_Angle angle,
905  FT_Int side )
906  {
908 
909 
910  if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
911  {
912  /* add a round cap */
913  stroker->angle_in = angle;
914  stroker->angle_out = angle + FT_ANGLE_PI;
915 
916  error = ft_stroker_arcto( stroker, side );
917  }
918  else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
919  {
920  /* add a square cap */
921  FT_Vector delta, delta2;
923  FT_Fixed radius = stroker->radius;
924  FT_StrokeBorder border = stroker->borders + side;
925 
926 
927  FT_Vector_From_Polar( &delta2, radius, angle + rotate );
928  FT_Vector_From_Polar( &delta, radius, angle );
929 
930  delta.x += stroker->center.x + delta2.x;
931  delta.y += stroker->center.y + delta2.y;
932 
933  error = ft_stroke_border_lineto( border, &delta, FALSE );
934  if ( error )
935  goto Exit;
936 
937  FT_Vector_From_Polar( &delta2, radius, angle - rotate );
938  FT_Vector_From_Polar( &delta, radius, angle );
939 
940  delta.x += delta2.x + stroker->center.x;
941  delta.y += delta2.y + stroker->center.y;
942 
943  error = ft_stroke_border_lineto( border, &delta, FALSE );
944  }
945  else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT )
946  {
947  /* add a butt ending */
948  FT_Vector delta;
950  FT_Fixed radius = stroker->radius;
951  FT_StrokeBorder border = stroker->borders + side;
952 
953 
954  FT_Vector_From_Polar( &delta, radius, angle + rotate );
955 
956  delta.x += stroker->center.x;
957  delta.y += stroker->center.y;
958 
959  error = ft_stroke_border_lineto( border, &delta, FALSE );
960  if ( error )
961  goto Exit;
962 
963  FT_Vector_From_Polar( &delta, radius, angle - rotate );
964 
965  delta.x += stroker->center.x;
966  delta.y += stroker->center.y;
967 
968  error = ft_stroke_border_lineto( border, &delta, FALSE );
969  }
970 
971  Exit:
972  return error;
973  }
974 
975 
976  /* process an inside corner, i.e. compute intersection */
977  static FT_Error
978  ft_stroker_inside( FT_Stroker stroker,
979  FT_Int side,
980  FT_Fixed line_length )
981  {
982  FT_StrokeBorder border = stroker->borders + side;
983  FT_Angle phi, theta, rotate;
984  FT_Fixed length, thcos;
985  FT_Vector delta;
987  FT_Bool intersect; /* use intersection of lines? */
988 
989 
990  rotate = FT_SIDE_TO_ROTATE( side );
991 
992  theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2;
993 
994  /* Only intersect borders if between two lineto's and both */
995  /* lines are long enough (line_length is zero for curves). */
996  if ( !border->movable || line_length == 0 )
997  intersect = FALSE;
998  else
999  {
1000  /* compute minimum required length of lines */
1001  FT_Fixed min_length = ft_pos_abs( FT_MulFix( stroker->radius,
1002  FT_Tan( theta ) ) );
1003 
1004 
1005  intersect = FT_BOOL( stroker->line_length >= min_length &&
1006  line_length >= min_length );
1007  }
1008 
1009  if ( !intersect )
1010  {
1011  FT_Vector_From_Polar( &delta, stroker->radius,
1012  stroker->angle_out + rotate );
1013  delta.x += stroker->center.x;
1014  delta.y += stroker->center.y;
1015 
1016  border->movable = FALSE;
1017  }
1018  else
1019  {
1020  /* compute median angle */
1021  phi = stroker->angle_in + theta;
1022 
1023  thcos = FT_Cos( theta );
1024 
1025  length = FT_DivFix( stroker->radius, thcos );
1026 
1027  FT_Vector_From_Polar( &delta, length, phi + rotate );
1028  delta.x += stroker->center.x;
1029  delta.y += stroker->center.y;
1030  }
1031 
1032  error = ft_stroke_border_lineto( border, &delta, FALSE );
1033 
1034  return error;
1035  }
1036 
1037 
1038  /* process an outside corner, i.e. compute bevel/miter/round */
1039  static FT_Error
1040  ft_stroker_outside( FT_Stroker stroker,
1041  FT_Int side,
1042  FT_Fixed line_length )
1043  {
1044  FT_StrokeBorder border = stroker->borders + side;
1045  FT_Error error;
1046  FT_Angle rotate;
1047 
1048 
1049  if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
1050  error = ft_stroker_arcto( stroker, side );
1051  else
1052  {
1053  /* this is a mitered (pointed) or beveled (truncated) corner */
1054  FT_Fixed sigma = 0, radius = stroker->radius;
1055  FT_Angle theta = 0, phi = 0;
1056  FT_Fixed thcos = 0;
1057  FT_Bool bevel, fixed_bevel;
1058 
1059 
1060  rotate = FT_SIDE_TO_ROTATE( side );
1061 
1062  bevel =
1063  FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL );
1064 
1065  fixed_bevel =
1066  FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE );
1067 
1068  if ( !bevel )
1069  {
1070  theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
1071 
1072  if ( theta == FT_ANGLE_PI )
1073  {
1074  theta = rotate;
1075  phi = stroker->angle_in;
1076  }
1077  else
1078  {
1079  theta /= 2;
1080  phi = stroker->angle_in + theta + rotate;
1081  }
1082 
1083  thcos = FT_Cos( theta );
1084  sigma = FT_MulFix( stroker->miter_limit, thcos );
1085 
1086  /* is miter limit exceeded? */
1087  if ( sigma < 0x10000L )
1088  {
1089  /* don't create variable bevels for very small deviations; */
1090  /* FT_Sin(x) = 0 for x <= 57 */
1091  if ( fixed_bevel || ft_pos_abs( theta ) > 57 )
1092  bevel = TRUE;
1093  }
1094  }
1095 
1096  if ( bevel ) /* this is a bevel (broken angle) */
1097  {
1098  if ( fixed_bevel )
1099  {
1100  /* the outer corners are simply joined together */
1101  FT_Vector delta;
1102 
1103 
1104  /* add bevel */
1105  FT_Vector_From_Polar( &delta,
1106  radius,
1107  stroker->angle_out + rotate );
1108  delta.x += stroker->center.x;
1109  delta.y += stroker->center.y;
1110 
1111  border->movable = FALSE;
1112  error = ft_stroke_border_lineto( border, &delta, FALSE );
1113  }
1114  else /* variable bevel */
1115  {
1116  /* the miter is truncated */
1117  FT_Vector middle, delta;
1118  FT_Fixed length;
1119 
1120 
1121  /* compute middle point */
1122  FT_Vector_From_Polar( &middle,
1123  FT_MulFix( radius, stroker->miter_limit ),
1124  phi );
1125  middle.x += stroker->center.x;
1126  middle.y += stroker->center.y;
1127 
1128  /* compute first angle point */
1129  length = FT_MulDiv( radius, 0x10000L - sigma,
1130  ft_pos_abs( FT_Sin( theta ) ) );
1131 
1132  FT_Vector_From_Polar( &delta, length, phi + rotate );
1133  delta.x += middle.x;
1134  delta.y += middle.y;
1135 
1136  error = ft_stroke_border_lineto( border, &delta, FALSE );
1137  if ( error )
1138  goto Exit;
1139 
1140  /* compute second angle point */
1141  FT_Vector_From_Polar( &delta, length, phi - rotate );
1142  delta.x += middle.x;
1143  delta.y += middle.y;
1144 
1145  error = ft_stroke_border_lineto( border, &delta, FALSE );
1146  if ( error )
1147  goto Exit;
1148 
1149  /* finally, add an end point; only needed if not lineto */
1150  /* (line_length is zero for curves) */
1151  if ( line_length == 0 )
1152  {
1153  FT_Vector_From_Polar( &delta,
1154  radius,
1155  stroker->angle_out + rotate );
1156 
1157  delta.x += stroker->center.x;
1158  delta.y += stroker->center.y;
1159 
1160  error = ft_stroke_border_lineto( border, &delta, FALSE );
1161  }
1162  }
1163  }
1164  else /* this is a miter (intersection) */
1165  {
1166  FT_Fixed length;
1167  FT_Vector delta;
1168 
1169 
1170  length = FT_DivFix( stroker->radius, thcos );
1171 
1172  FT_Vector_From_Polar( &delta, length, phi );
1173  delta.x += stroker->center.x;
1174  delta.y += stroker->center.y;
1175 
1176  error = ft_stroke_border_lineto( border, &delta, FALSE );
1177  if ( error )
1178  goto Exit;
1179 
1180  /* now add an end point; only needed if not lineto */
1181  /* (line_length is zero for curves) */
1182  if ( line_length == 0 )
1183  {
1184  FT_Vector_From_Polar( &delta,
1185  stroker->radius,
1186  stroker->angle_out + rotate );
1187  delta.x += stroker->center.x;
1188  delta.y += stroker->center.y;
1189 
1190  error = ft_stroke_border_lineto( border, &delta, FALSE );
1191  }
1192  }
1193  }
1194 
1195  Exit:
1196  return error;
1197  }
1198 
1199 
1200  static FT_Error
1201  ft_stroker_process_corner( FT_Stroker stroker,
1202  FT_Fixed line_length )
1203  {
1205  FT_Angle turn;
1206  FT_Int inside_side;
1207 
1208 
1209  turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
1210 
1211  /* no specific corner processing is required if the turn is 0 */
1212  if ( turn == 0 )
1213  goto Exit;
1214 
1215  /* when we turn to the right, the inside side is 0 */
1216  inside_side = 0;
1217 
1218  /* otherwise, the inside side is 1 */
1219  if ( turn < 0 )
1220  inside_side = 1;
1221 
1222  /* process the inside side */
1223  error = ft_stroker_inside( stroker, inside_side, line_length );
1224  if ( error )
1225  goto Exit;
1226 
1227  /* process the outside side */
1228  error = ft_stroker_outside( stroker, 1 - inside_side, line_length );
1229 
1230  Exit:
1231  return error;
1232  }
1233 
1234 
1235  /* add two points to the left and right borders corresponding to the */
1236  /* start of the subpath */
1237  static FT_Error
1238  ft_stroker_subpath_start( FT_Stroker stroker,
1239  FT_Angle start_angle,
1240  FT_Fixed line_length )
1241  {
1242  FT_Vector delta;
1243  FT_Vector point;
1244  FT_Error error;
1246 
1247 
1248  FT_Vector_From_Polar( &delta, stroker->radius,
1249  start_angle + FT_ANGLE_PI2 );
1250 
1251  point.x = stroker->center.x + delta.x;
1252  point.y = stroker->center.y + delta.y;
1253 
1254  border = stroker->borders;
1255  error = ft_stroke_border_moveto( border, &point );
1256  if ( error )
1257  goto Exit;
1258 
1259  point.x = stroker->center.x - delta.x;
1260  point.y = stroker->center.y - delta.y;
1261 
1262  border++;
1263  error = ft_stroke_border_moveto( border, &point );
1264 
1265  /* save angle, position, and line length for last join */
1266  /* (line_length is zero for curves) */
1267  stroker->subpath_angle = start_angle;
1268  stroker->first_point = FALSE;
1269  stroker->subpath_line_length = line_length;
1270 
1271  Exit:
1272  return error;
1273  }
1274 
1275 
1276  /* documentation is in ftstroke.h */
1277 
1280  FT_Vector* to )
1281  {
1284  FT_Vector delta;
1285  FT_Angle angle;
1286  FT_Int side;
1287  FT_Fixed line_length;
1288 
1289 
1290  delta.x = to->x - stroker->center.x;
1291  delta.y = to->y - stroker->center.y;
1292 
1293  /* a zero-length lineto is a no-op; avoid creating a spurious corner */
1294  if ( delta.x == 0 && delta.y == 0 )
1295  goto Exit;
1296 
1297  /* compute length of line */
1298  line_length = FT_Vector_Length( &delta );
1299 
1300  angle = FT_Atan2( delta.x, delta.y );
1301  FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
1302 
1303  /* process corner if necessary */
1304  if ( stroker->first_point )
1305  {
1306  /* This is the first segment of a subpath. We need to */
1307  /* add a point to each border at their respective starting */
1308  /* point locations. */
1309  error = ft_stroker_subpath_start( stroker, angle, line_length );
1310  if ( error )
1311  goto Exit;
1312  }
1313  else
1314  {
1315  /* process the current corner */
1316  stroker->angle_out = angle;
1317  error = ft_stroker_process_corner( stroker, line_length );
1318  if ( error )
1319  goto Exit;
1320  }
1321 
1322  /* now add a line segment to both the `inside' and `outside' paths */
1323  for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
1324  {
1325  FT_Vector point;
1326 
1327 
1328  point.x = to->x + delta.x;
1329  point.y = to->y + delta.y;
1330 
1331  /* the ends of lineto borders are movable */
1332  error = ft_stroke_border_lineto( border, &point, TRUE );
1333  if ( error )
1334  goto Exit;
1335 
1336  delta.x = -delta.x;
1337  delta.y = -delta.y;
1338  }
1339 
1340  stroker->angle_in = angle;
1341  stroker->center = *to;
1342  stroker->line_length = line_length;
1343 
1344  Exit:
1345  return error;
1346  }
1347 
1348 
1349  /* documentation is in ftstroke.h */
1350 
1353  FT_Vector* control,
1354  FT_Vector* to )
1355  {
1357  FT_Vector bez_stack[34];
1358  FT_Vector* arc;
1359  FT_Vector* limit = bez_stack + 30;
1360  FT_Bool first_arc = TRUE;
1361 
1362 
1363  /* if all control points are coincident, this is a no-op; */
1364  /* avoid creating a spurious corner */
1365  if ( FT_IS_SMALL( stroker->center.x - control->x ) &&
1366  FT_IS_SMALL( stroker->center.y - control->y ) &&
1367  FT_IS_SMALL( control->x - to->x ) &&
1368  FT_IS_SMALL( control->y - to->y ) )
1369  {
1370  stroker->center = *to;
1371  goto Exit;
1372  }
1373 
1374  arc = bez_stack;
1375  arc[0] = *to;
1376  arc[1] = *control;
1377  arc[2] = stroker->center;
1378 
1379  while ( arc >= bez_stack )
1380  {
1381  FT_Angle angle_in, angle_out;
1382 
1383 
1384  /* initialize with current direction */
1385  angle_in = angle_out = stroker->angle_in;
1386 
1387  if ( arc < limit &&
1388  !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
1389  {
1390  if ( stroker->first_point )
1391  stroker->angle_in = angle_in;
1392 
1393  ft_conic_split( arc );
1394  arc += 2;
1395  continue;
1396  }
1397 
1398  if ( first_arc )
1399  {
1400  first_arc = FALSE;
1401 
1402  /* process corner if necessary */
1403  if ( stroker->first_point )
1404  error = ft_stroker_subpath_start( stroker, angle_in, 0 );
1405  else
1406  {
1407  stroker->angle_out = angle_in;
1408  error = ft_stroker_process_corner( stroker, 0 );
1409  }
1410  }
1411  else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
1413  {
1414  /* if the deviation from one arc to the next is too great, */
1415  /* add a round corner */
1416  stroker->center = arc[2];
1417  stroker->angle_out = angle_in;
1418  stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
1419 
1420  error = ft_stroker_process_corner( stroker, 0 );
1421 
1422  /* reinstate line join style */
1423  stroker->line_join = stroker->line_join_saved;
1424  }
1425 
1426  if ( error )
1427  goto Exit;
1428 
1429  /* the arc's angle is small enough; we can add it directly to each */
1430  /* border */
1431  {
1432  FT_Vector ctrl, end;
1433  FT_Angle theta, phi, rotate, alpha0 = 0;
1434  FT_Fixed length;
1436  FT_Int side;
1437 
1438 
1439  theta = FT_Angle_Diff( angle_in, angle_out ) / 2;
1440  phi = angle_in + theta;
1441  length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
1442 
1443  /* compute direction of original arc */
1444  if ( stroker->handle_wide_strokes )
1445  alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y );
1446 
1447  for ( border = stroker->borders, side = 0;
1448  side <= 1;
1449  side++, border++ )
1450  {
1451  rotate = FT_SIDE_TO_ROTATE( side );
1452 
1453  /* compute control point */
1454  FT_Vector_From_Polar( &ctrl, length, phi + rotate );
1455  ctrl.x += arc[1].x;
1456  ctrl.y += arc[1].y;
1457 
1458  /* compute end point */
1459  FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
1460  end.x += arc[0].x;
1461  end.y += arc[0].y;
1462 
1463  if ( stroker->handle_wide_strokes )
1464  {
1465  FT_Vector start;
1466  FT_Angle alpha1;
1467 
1468 
1469  /* determine whether the border radius is greater than the */
1470  /* radius of curvature of the original arc */
1471  start = border->points[border->num_points - 1];
1472 
1473  alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
1474 
1475  /* is the direction of the border arc opposite to */
1476  /* that of the original arc? */
1477  if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
1478  FT_ANGLE_PI / 2 )
1479  {
1480  FT_Angle beta, gamma;
1481  FT_Vector bvec, delta;
1482  FT_Fixed blen, sinA, sinB, alen;
1483 
1484 
1485  /* use the sine rule to find the intersection point */
1486  beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y );
1487  gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
1488 
1489  bvec.x = end.x - start.x;
1490  bvec.y = end.y - start.y;
1491 
1492  blen = FT_Vector_Length( &bvec );
1493 
1494  sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
1495  sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
1496 
1497  alen = FT_MulDiv( blen, sinA, sinB );
1498 
1499  FT_Vector_From_Polar( &delta, alen, beta );
1500  delta.x += start.x;
1501  delta.y += start.y;
1502 
1503  /* circumnavigate the negative sector backwards */
1504  border->movable = FALSE;
1505  error = ft_stroke_border_lineto( border, &delta, FALSE );
1506  if ( error )
1507  goto Exit;
1508  error = ft_stroke_border_lineto( border, &end, FALSE );
1509  if ( error )
1510  goto Exit;
1511  error = ft_stroke_border_conicto( border, &ctrl, &start );
1512  if ( error )
1513  goto Exit;
1514  /* and then move to the endpoint */
1515  error = ft_stroke_border_lineto( border, &end, FALSE );
1516  if ( error )
1517  goto Exit;
1518 
1519  continue;
1520  }
1521 
1522  /* else fall through */
1523  }
1524 
1525  /* simply add an arc */
1526  error = ft_stroke_border_conicto( border, &ctrl, &end );
1527  if ( error )
1528  goto Exit;
1529  }
1530  }
1531 
1532  arc -= 2;
1533 
1534  stroker->angle_in = angle_out;
1535  }
1536 
1537  stroker->center = *to;
1538 
1539  Exit:
1540  return error;
1541  }
1542 
1543 
1544  /* documentation is in ftstroke.h */
1545 
1548  FT_Vector* control1,
1549  FT_Vector* control2,
1550  FT_Vector* to )
1551  {
1553  FT_Vector bez_stack[37];
1554  FT_Vector* arc;
1555  FT_Vector* limit = bez_stack + 32;
1556  FT_Bool first_arc = TRUE;
1557 
1558 
1559  /* if all control points are coincident, this is a no-op; */
1560  /* avoid creating a spurious corner */
1561  if ( FT_IS_SMALL( stroker->center.x - control1->x ) &&
1562  FT_IS_SMALL( stroker->center.y - control1->y ) &&
1563  FT_IS_SMALL( control1->x - control2->x ) &&
1564  FT_IS_SMALL( control1->y - control2->y ) &&
1565  FT_IS_SMALL( control2->x - to->x ) &&
1566  FT_IS_SMALL( control2->y - to->y ) )
1567  {
1568  stroker->center = *to;
1569  goto Exit;
1570  }
1571 
1572  arc = bez_stack;
1573  arc[0] = *to;
1574  arc[1] = *control2;
1575  arc[2] = *control1;
1576  arc[3] = stroker->center;
1577 
1578  while ( arc >= bez_stack )
1579  {
1580  FT_Angle angle_in, angle_mid, angle_out;
1581 
1582 
1583  /* initialize with current direction */
1584  angle_in = angle_out = angle_mid = stroker->angle_in;
1585 
1586  if ( arc < limit &&
1587  !ft_cubic_is_small_enough( arc, &angle_in,
1588  &angle_mid, &angle_out ) )
1589  {
1590  if ( stroker->first_point )
1591  stroker->angle_in = angle_in;
1592 
1593  ft_cubic_split( arc );
1594  arc += 3;
1595  continue;
1596  }
1597 
1598  if ( first_arc )
1599  {
1600  first_arc = FALSE;
1601 
1602  /* process corner if necessary */
1603  if ( stroker->first_point )
1604  error = ft_stroker_subpath_start( stroker, angle_in, 0 );
1605  else
1606  {
1607  stroker->angle_out = angle_in;
1608  error = ft_stroker_process_corner( stroker, 0 );
1609  }
1610  }
1611  else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
1613  {
1614  /* if the deviation from one arc to the next is too great, */
1615  /* add a round corner */
1616  stroker->center = arc[3];
1617  stroker->angle_out = angle_in;
1618  stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
1619 
1620  error = ft_stroker_process_corner( stroker, 0 );
1621 
1622  /* reinstate line join style */
1623  stroker->line_join = stroker->line_join_saved;
1624  }
1625 
1626  if ( error )
1627  goto Exit;
1628 
1629  /* the arc's angle is small enough; we can add it directly to each */
1630  /* border */
1631  {
1632  FT_Vector ctrl1, ctrl2, end;
1633  FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0;
1634  FT_Fixed length1, length2;
1636  FT_Int side;
1637 
1638 
1639  theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2;
1640  theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2;
1641  phi1 = ft_angle_mean( angle_in, angle_mid );
1642  phi2 = ft_angle_mean( angle_mid, angle_out );
1643  length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
1644  length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) );
1645 
1646  /* compute direction of original arc */
1647  if ( stroker->handle_wide_strokes )
1648  alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y );
1649 
1650  for ( border = stroker->borders, side = 0;
1651  side <= 1;
1652  side++, border++ )
1653  {
1654  rotate = FT_SIDE_TO_ROTATE( side );
1655 
1656  /* compute control points */
1657  FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
1658  ctrl1.x += arc[2].x;
1659  ctrl1.y += arc[2].y;
1660 
1661  FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
1662  ctrl2.x += arc[1].x;
1663  ctrl2.y += arc[1].y;
1664 
1665  /* compute end point */
1666  FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
1667  end.x += arc[0].x;
1668  end.y += arc[0].y;
1669 
1670  if ( stroker->handle_wide_strokes )
1671  {
1672  FT_Vector start;
1673  FT_Angle alpha1;
1674 
1675 
1676  /* determine whether the border radius is greater than the */
1677  /* radius of curvature of the original arc */
1678  start = border->points[border->num_points - 1];
1679 
1680  alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
1681 
1682  /* is the direction of the border arc opposite to */
1683  /* that of the original arc? */
1684  if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
1685  FT_ANGLE_PI / 2 )
1686  {
1687  FT_Angle beta, gamma;
1688  FT_Vector bvec, delta;
1689  FT_Fixed blen, sinA, sinB, alen;
1690 
1691 
1692  /* use the sine rule to find the intersection point */
1693  beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y );
1694  gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
1695 
1696  bvec.x = end.x - start.x;
1697  bvec.y = end.y - start.y;
1698 
1699  blen = FT_Vector_Length( &bvec );
1700 
1701  sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
1702  sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
1703 
1704  alen = FT_MulDiv( blen, sinA, sinB );
1705 
1706  FT_Vector_From_Polar( &delta, alen, beta );
1707  delta.x += start.x;
1708  delta.y += start.y;
1709 
1710  /* circumnavigate the negative sector backwards */
1711  border->movable = FALSE;
1712  error = ft_stroke_border_lineto( border, &delta, FALSE );
1713  if ( error )
1714  goto Exit;
1715  error = ft_stroke_border_lineto( border, &end, FALSE );
1716  if ( error )
1717  goto Exit;
1718  error = ft_stroke_border_cubicto( border,
1719  &ctrl2,
1720  &ctrl1,
1721  &start );
1722  if ( error )
1723  goto Exit;
1724  /* and then move to the endpoint */
1725  error = ft_stroke_border_lineto( border, &end, FALSE );
1726  if ( error )
1727  goto Exit;
1728 
1729  continue;
1730  }
1731 
1732  /* else fall through */
1733  }
1734 
1735  /* simply add an arc */
1736  error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end );
1737  if ( error )
1738  goto Exit;
1739  }
1740  }
1741 
1742  arc -= 3;
1743 
1744  stroker->angle_in = angle_out;
1745  }
1746 
1747  stroker->center = *to;
1748 
1749  Exit:
1750  return error;
1751  }
1752 
1753 
1754  /* documentation is in ftstroke.h */
1755 
1758  FT_Vector* to,
1759  FT_Bool open )
1760  {
1761  /* We cannot process the first point, because there is not enough */
1762  /* information regarding its corner/cap. The latter will be processed */
1763  /* in the `FT_Stroker_EndSubPath' routine. */
1764  /* */
1765  stroker->first_point = TRUE;
1766  stroker->center = *to;
1767  stroker->subpath_open = open;
1768 
1769  /* Determine if we need to check whether the border radius is greater */
1770  /* than the radius of curvature of a curve, to handle this case */
1771  /* specially. This is only required if bevel joins or butt caps may */
1772  /* be created, because round & miter joins and round & square caps */
1773  /* cover the negative sector created with wide strokes. */
1774  stroker->handle_wide_strokes =
1775  FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND ||
1776  ( stroker->subpath_open &&
1777  stroker->line_cap == FT_STROKER_LINECAP_BUTT ) );
1778 
1779  /* record the subpath start point for each border */
1780  stroker->subpath_start = *to;
1781 
1782  stroker->angle_in = 0;
1783 
1784  return FT_Err_Ok;
1785  }
1786 
1787 
1788  static FT_Error
1789  ft_stroker_add_reverse_left( FT_Stroker stroker,
1790  FT_Bool open )
1791  {
1792  FT_StrokeBorder right = stroker->borders + 0;
1793  FT_StrokeBorder left = stroker->borders + 1;
1794  FT_Int new_points;
1796 
1797 
1798  FT_ASSERT( left->start >= 0 );
1799 
1800  new_points = left->num_points - left->start;
1801  if ( new_points > 0 )
1802  {
1803  error = ft_stroke_border_grow( right, (FT_UInt)new_points );
1804  if ( error )
1805  goto Exit;
1806 
1807  {
1808  FT_Vector* dst_point = right->points + right->num_points;
1809  FT_Byte* dst_tag = right->tags + right->num_points;
1810  FT_Vector* src_point = left->points + left->num_points - 1;
1811  FT_Byte* src_tag = left->tags + left->num_points - 1;
1812 
1813 
1814  while ( src_point >= left->points + left->start )
1815  {
1816  *dst_point = *src_point;
1817  *dst_tag = *src_tag;
1818 
1819  if ( open )
1820  dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END;
1821  else
1822  {
1823  FT_Byte ttag =
1824  (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
1825 
1826 
1827  /* switch begin/end tags if necessary */
1828  if ( ttag == FT_STROKE_TAG_BEGIN ||
1829  ttag == FT_STROKE_TAG_END )
1830  dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END;
1831  }
1832 
1833  src_point--;
1834  src_tag--;
1835  dst_point++;
1836  dst_tag++;
1837  }
1838  }
1839 
1840  left->num_points = left->start;
1841  right->num_points += new_points;
1842 
1843  right->movable = FALSE;
1844  left->movable = FALSE;
1845  }
1846 
1847  Exit:
1848  return error;
1849  }
1850 
1851 
1852  /* documentation is in ftstroke.h */
1853 
1854  /* there's a lot of magic in this function! */
1857  {
1859 
1860 
1861  if ( stroker->subpath_open )
1862  {
1863  FT_StrokeBorder right = stroker->borders;
1864 
1865 
1866  /* All right, this is an opened path, we need to add a cap between */
1867  /* right & left, add the reverse of left, then add a final cap */
1868  /* between left & right. */
1869  error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
1870  if ( error )
1871  goto Exit;
1872 
1873  /* add reversed points from `left' to `right' */
1874  error = ft_stroker_add_reverse_left( stroker, TRUE );
1875  if ( error )
1876  goto Exit;
1877 
1878  /* now add the final cap */
1879  stroker->center = stroker->subpath_start;
1880  error = ft_stroker_cap( stroker,
1881  stroker->subpath_angle + FT_ANGLE_PI, 0 );
1882  if ( error )
1883  goto Exit;
1884 
1885  /* Now end the right subpath accordingly. The left one is */
1886  /* rewind and doesn't need further processing. */
1887  ft_stroke_border_close( right, FALSE );
1888  }
1889  else
1890  {
1891  FT_Angle turn;
1892  FT_Int inside_side;
1893 
1894 
1895  /* close the path if needed */
1896  if ( stroker->center.x != stroker->subpath_start.x ||
1897  stroker->center.y != stroker->subpath_start.y )
1898  {
1899  error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
1900  if ( error )
1901  goto Exit;
1902  }
1903 
1904  /* process the corner */
1905  stroker->angle_out = stroker->subpath_angle;
1906  turn = FT_Angle_Diff( stroker->angle_in,
1907  stroker->angle_out );
1908 
1909  /* no specific corner processing is required if the turn is 0 */
1910  if ( turn != 0 )
1911  {
1912  /* when we turn to the right, the inside side is 0 */
1913  inside_side = 0;
1914 
1915  /* otherwise, the inside side is 1 */
1916  if ( turn < 0 )
1917  inside_side = 1;
1918 
1919  error = ft_stroker_inside( stroker,
1920  inside_side,
1921  stroker->subpath_line_length );
1922  if ( error )
1923  goto Exit;
1924 
1925  /* process the outside side */
1926  error = ft_stroker_outside( stroker,
1927  1 - inside_side,
1928  stroker->subpath_line_length );
1929  if ( error )
1930  goto Exit;
1931  }
1932 
1933  /* then end our two subpaths */
1934  ft_stroke_border_close( stroker->borders + 0, FALSE );
1935  ft_stroke_border_close( stroker->borders + 1, TRUE );
1936  }
1937 
1938  Exit:
1939  return error;
1940  }
1941 
1942 
1943  /* documentation is in ftstroke.h */
1944 
1948  FT_UInt *anum_points,
1949  FT_UInt *anum_contours )
1950  {
1951  FT_UInt num_points = 0, num_contours = 0;
1952  FT_Error error;
1953 
1954 
1955  if ( !stroker || border > 1 )
1956  {
1957  error = FT_THROW( Invalid_Argument );
1958  goto Exit;
1959  }
1960 
1961  error = ft_stroke_border_get_counts( stroker->borders + border,
1962  &num_points, &num_contours );
1963  Exit:
1964  if ( anum_points )
1965  *anum_points = num_points;
1966 
1967  if ( anum_contours )
1968  *anum_contours = num_contours;
1969 
1970  return error;
1971  }
1972 
1973 
1974  /* documentation is in ftstroke.h */
1975 
1978  FT_UInt *anum_points,
1979  FT_UInt *anum_contours )
1980  {
1981  FT_UInt count1, count2, num_points = 0;
1982  FT_UInt count3, count4, num_contours = 0;
1983  FT_Error error;
1984 
1985 
1986  error = ft_stroke_border_get_counts( stroker->borders + 0,
1987  &count1, &count2 );
1988  if ( error )
1989  goto Exit;
1990 
1991  error = ft_stroke_border_get_counts( stroker->borders + 1,
1992  &count3, &count4 );
1993  if ( error )
1994  goto Exit;
1995 
1996  num_points = count1 + count3;
1997  num_contours = count2 + count4;
1998 
1999  Exit:
2000  *anum_points = num_points;
2001  *anum_contours = num_contours;
2002  return error;
2003  }
2004 
2005 
2006  /* documentation is in ftstroke.h */
2007 
2008  FT_EXPORT_DEF( void )
2011  FT_Outline* outline )
2012  {
2013  if ( border == FT_STROKER_BORDER_LEFT ||
2015  {
2016  FT_StrokeBorder sborder = & stroker->borders[border];
2017 
2018 
2019  if ( sborder->valid )
2020  ft_stroke_border_export( sborder, outline );
2021  }
2022  }
2023 
2024 
2025  /* documentation is in ftstroke.h */
2026 
2027  FT_EXPORT_DEF( void )
2029  FT_Outline* outline )
2030  {
2031  FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline );
2032  FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline );
2033  }
2034 
2035 
2036  /* documentation is in ftstroke.h */
2037 
2038  /*
2039  * The following is very similar to FT_Outline_Decompose, except
2040  * that we do support opened paths, and do not scale the outline.
2041  */
2044  FT_Outline* outline,
2045  FT_Bool opened )
2046  {
2047  FT_Vector v_last;
2048  FT_Vector v_control;
2049  FT_Vector v_start;
2050 
2051  FT_Vector* point;
2052  FT_Vector* limit;
2053  char* tags;
2054 
2055  FT_Error error;
2056 
2057  FT_Int n; /* index of contour in outline */
2058  FT_UInt first; /* index of first point in contour */
2059  FT_Int tag; /* current point's state */
2060 
2061 
2062  if ( !outline || !stroker )
2063  return FT_THROW( Invalid_Argument );
2064 
2065  FT_Stroker_Rewind( stroker );
2066 
2067  first = 0;
2068 
2069  for ( n = 0; n < outline->n_contours; n++ )
2070  {
2071  FT_UInt last; /* index of last point in contour */
2072 
2073 
2074  last = outline->contours[n];
2075  limit = outline->points + last;
2076 
2077  /* skip empty points; we don't stroke these */
2078  if ( last <= first )
2079  {
2080  first = last + 1;
2081  continue;
2082  }
2083 
2084  v_start = outline->points[first];
2085  v_last = outline->points[last];
2086 
2087  v_control = v_start;
2088 
2089  point = outline->points + first;
2090  tags = outline->tags + first;
2091  tag = FT_CURVE_TAG( tags[0] );
2092 
2093  /* A contour cannot start with a cubic control point! */
2094  if ( tag == FT_CURVE_TAG_CUBIC )
2095  goto Invalid_Outline;
2096 
2097  /* check first point to determine origin */
2098  if ( tag == FT_CURVE_TAG_CONIC )
2099  {
2100  /* First point is conic control. Yes, this happens. */
2101  if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
2102  {
2103  /* start at last point if it is on the curve */
2104  v_start = v_last;
2105  limit--;
2106  }
2107  else
2108  {
2109  /* if both first and last points are conic, */
2110  /* start at their middle */
2111  v_start.x = ( v_start.x + v_last.x ) / 2;
2112  v_start.y = ( v_start.y + v_last.y ) / 2;
2113  }
2114  point--;
2115  tags--;
2116  }
2117 
2118  error = FT_Stroker_BeginSubPath( stroker, &v_start, opened );
2119  if ( error )
2120  goto Exit;
2121 
2122  while ( point < limit )
2123  {
2124  point++;
2125  tags++;
2126 
2127  tag = FT_CURVE_TAG( tags[0] );
2128  switch ( tag )
2129  {
2130  case FT_CURVE_TAG_ON: /* emit a single line_to */
2131  {
2132  FT_Vector vec;
2133 
2134 
2135  vec.x = point->x;
2136  vec.y = point->y;
2137 
2138  error = FT_Stroker_LineTo( stroker, &vec );
2139  if ( error )
2140  goto Exit;
2141  continue;
2142  }
2143 
2144  case FT_CURVE_TAG_CONIC: /* consume conic arcs */
2145  v_control.x = point->x;
2146  v_control.y = point->y;
2147 
2148  Do_Conic:
2149  if ( point < limit )
2150  {
2151  FT_Vector vec;
2152  FT_Vector v_middle;
2153 
2154 
2155  point++;
2156  tags++;
2157  tag = FT_CURVE_TAG( tags[0] );
2158 
2159  vec = point[0];
2160 
2161  if ( tag == FT_CURVE_TAG_ON )
2162  {
2163  error = FT_Stroker_ConicTo( stroker, &v_control, &vec );
2164  if ( error )
2165  goto Exit;
2166  continue;
2167  }
2168 
2169  if ( tag != FT_CURVE_TAG_CONIC )
2170  goto Invalid_Outline;
2171 
2172  v_middle.x = ( v_control.x + vec.x ) / 2;
2173  v_middle.y = ( v_control.y + vec.y ) / 2;
2174 
2175  error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle );
2176  if ( error )
2177  goto Exit;
2178 
2179  v_control = vec;
2180  goto Do_Conic;
2181  }
2182 
2183  error = FT_Stroker_ConicTo( stroker, &v_control, &v_start );
2184  goto Close;
2185 
2186  default: /* FT_CURVE_TAG_CUBIC */
2187  {
2188  FT_Vector vec1, vec2;
2189 
2190 
2191  if ( point + 1 > limit ||
2192  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
2193  goto Invalid_Outline;
2194 
2195  point += 2;
2196  tags += 2;
2197 
2198  vec1 = point[-2];
2199  vec2 = point[-1];
2200 
2201  if ( point <= limit )
2202  {
2203  FT_Vector vec;
2204 
2205 
2206  vec = point[0];
2207 
2208  error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec );
2209  if ( error )
2210  goto Exit;
2211  continue;
2212  }
2213 
2214  error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start );
2215  goto Close;
2216  }
2217  }
2218  }
2219 
2220  Close:
2221  if ( error )
2222  goto Exit;
2223 
2224  /* don't try to end the path if no segments have been generated */
2225  if ( !stroker->first_point )
2226  {
2227  error = FT_Stroker_EndSubPath( stroker );
2228  if ( error )
2229  goto Exit;
2230  }
2231 
2232  first = last + 1;
2233  }
2234 
2235  return FT_Err_Ok;
2236 
2237  Exit:
2238  return error;
2239 
2240  Invalid_Outline:
2241  return FT_THROW( Invalid_Outline );
2242  }
2243 
2244 
2245  /* declare an extern to access `ft_outline_glyph_class' globally */
2246  /* allocated in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */
2247  /* macro to access it when FT_CONFIG_OPTION_PIC is defined */
2248 #ifndef FT_CONFIG_OPTION_PIC
2250 #endif
2251 #include "basepic.h"
2252 
2253 
2254  /* documentation is in ftstroke.h */
2255 
2258  FT_Stroker stroker,
2259  FT_Bool destroy )
2260  {
2261  FT_Error error = FT_ERR( Invalid_Argument );
2262  FT_Glyph glyph = NULL;
2263  FT_Library library = stroker->library;
2264 
2265  FT_UNUSED( library );
2266 
2267 
2268  if ( pglyph == NULL )
2269  goto Exit;
2270 
2271  glyph = *pglyph;
2272  if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
2273  goto Exit;
2274 
2275  {
2276  FT_Glyph copy;
2277 
2278 
2279  error = FT_Glyph_Copy( glyph, &copy );
2280  if ( error )
2281  goto Exit;
2282 
2283  glyph = copy;
2284  }
2285 
2286  {
2287  FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
2288  FT_Outline* outline = &oglyph->outline;
2289  FT_UInt num_points, num_contours;
2290 
2291 
2292  error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
2293  if ( error )
2294  goto Fail;
2295 
2296  (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours );
2297 
2298  FT_Outline_Done( glyph->library, outline );
2299 
2300  error = FT_Outline_New( glyph->library,
2301  num_points, num_contours, outline );
2302  if ( error )
2303  goto Fail;
2304 
2305  outline->n_points = 0;
2306  outline->n_contours = 0;
2307 
2308  FT_Stroker_Export( stroker, outline );
2309  }
2310 
2311  if ( destroy )
2312  FT_Done_Glyph( *pglyph );
2313 
2314  *pglyph = glyph;
2315  goto Exit;
2316 
2317  Fail:
2318  FT_Done_Glyph( glyph );
2319  glyph = NULL;
2320 
2321  if ( !destroy )
2322  *pglyph = NULL;
2323 
2324  Exit:
2325  return error;
2326  }
2327 
2328 
2329  /* documentation is in ftstroke.h */
2330 
2333  FT_Stroker stroker,
2334  FT_Bool inside,
2335  FT_Bool destroy )
2336  {
2337  FT_Error error = FT_ERR( Invalid_Argument );
2338  FT_Glyph glyph = NULL;
2339  FT_Library library = stroker->library;
2340 
2341  FT_UNUSED( library );
2342 
2343 
2344  if ( pglyph == NULL )
2345  goto Exit;
2346 
2347  glyph = *pglyph;
2348  if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
2349  goto Exit;
2350 
2351  {
2352  FT_Glyph copy;
2353 
2354 
2355  error = FT_Glyph_Copy( glyph, &copy );
2356  if ( error )
2357  goto Exit;
2358 
2359  glyph = copy;
2360  }
2361 
2362  {
2363  FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
2365  FT_Outline* outline = &oglyph->outline;
2366  FT_UInt num_points, num_contours;
2367 
2368 
2369  border = FT_Outline_GetOutsideBorder( outline );
2370  if ( inside )
2371  {
2372  if ( border == FT_STROKER_BORDER_LEFT )
2373  border = FT_STROKER_BORDER_RIGHT;
2374  else
2375  border = FT_STROKER_BORDER_LEFT;
2376  }
2377 
2378  error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
2379  if ( error )
2380  goto Fail;
2381 
2382  (void)FT_Stroker_GetBorderCounts( stroker, border,
2383  &num_points, &num_contours );
2384 
2385  FT_Outline_Done( glyph->library, outline );
2386 
2387  error = FT_Outline_New( glyph->library,
2388  num_points,
2389  num_contours,
2390  outline );
2391  if ( error )
2392  goto Fail;
2393 
2394  outline->n_points = 0;
2395  outline->n_contours = 0;
2396 
2397  FT_Stroker_ExportBorder( stroker, border, outline );
2398  }
2399 
2400  if ( destroy )
2401  FT_Done_Glyph( *pglyph );
2402 
2403  *pglyph = glyph;
2404  goto Exit;
2405 
2406  Fail:
2407  FT_Done_Glyph( glyph );
2408  glyph = NULL;
2409 
2410  if ( !destroy )
2411  *pglyph = NULL;
2412 
2413  Exit:
2414  return error;
2415  }
2416 
2417 
2418 /* END */
GLenum GLuint GLenum GLsizei length
enum FT_Stroker_LineCap_ FT_Stroker_LineCap
int FT_Error
Definition: fttypes.h:296
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:586
FT_Stroker_GetCounts(FT_Stroker stroker, FT_UInt *anum_points, FT_UInt *anum_contours)
Definition: ftstroke.c:1977
FT_Stroker_GetBorderCounts(FT_Stroker stroker, FT_StrokerBorder border, FT_UInt *anum_points, FT_UInt *anum_contours)
Definition: ftstroke.c:1946
for(n=1;n< outline->n_points;n++)
Definition: ftbbox.c:593
#define FT_ARC_CUBIC_ANGLE
Definition: ftstroke.c:521
angle2
Definition: cordic.py:18
#define FT_IS_SMALL(x)
Definition: ftstroke.c:67
const FT_Glyph_Class * clazz
Definition: ftglyph.h:111
struct FT_OutlineGlyphRec_ * FT_OutlineGlyph
Definition: ftglyph.h:179
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:59
#define FT_ANGLE_PI2
Definition: fttrigon.h:88
struct FT_StrokeBorderRec_ FT_StrokeBorderRec
GLboolean GLboolean GLboolean GLboolean a
GLsizei const GLfloat * points
FT_Glyph_StrokeBorder(FT_Glyph *pglyph, FT_Stroker stroker, FT_Bool inside, FT_Bool destroy)
Definition: ftstroke.c:2332
fvec2 vec2
Defined as: &#39;typedef fvec2 vec2&#39;. See also VL_PIPELINE_PRECISION.
Definition: Vector2.hpp:299
FT_Stroker_BeginSubPath(FT_Stroker stroker, FT_Vector *to, FT_Bool open)
Definition: ftstroke.c:1757
typedefFT_BEGIN_HEADER struct FT_Glyph_Class_ FT_Glyph_Class
Definition: ftglyph.h:69
int write(int fd, const char *buf, int nbytes)
Definition: tif_acorn.c:325
int read(int fd, char *buf, int nbytes)
Definition: tif_acorn.c:331
#define FT_CURVE_TAG_CUBIC
Definition: ftimage.h:518
#define NULL
Definition: ftobjs.h:61
const FT_Glyph_Class ft_outline_glyph_class
GLint GLint GLint GLint GLint GLint y
signed int FT_Int
Definition: fttypes.h:216
short n_contours
Definition: ftimage.h:385
#define FT_ARRAY_COPY(dest, source, count)
Definition: ftmemory.h:216
struct FT_StrokeBorderRec_ * FT_StrokeBorder
enum FT_Orientation_ FT_Orientation
return FT_THROW(Missing_Property)
short * contours
Definition: ftimage.h:390
T step(T edge, T a)
Definition: glsl_math.hpp:990
#define FT_UNUSED(arg)
Definition: ftconfig.h:76
FT_Tan(FT_Angle angle)
Definition: fttrigon.c:303
char * tags
Definition: ftimage.h:389
FT_Glyph_Copy(FT_Glyph source, FT_Glyph *target)
Definition: ftglyph.c:308
GLuint start
FT_Outline_Get_Orientation(FT_Outline *outline)
Definition: ftoutln.c:1025
#define FT_SMALL_CONIC_THRESHOLD
Definition: ftstroke.c:62
GLint GLint GLint GLint GLint x
local void rotate(unsigned char *list, unsigned len, unsigned rot)
Definition: gzappend.c:123
FT_Library library
Definition: cffdrivr.c:414
return FT_Err_Ok
Definition: ftbbox.c:645
typedef void(APIENTRY *GLDEBUGPROCARB)(GLenum source
GLboolean GLboolean GLboolean b
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
FT_Stroker_Rewind(FT_Stroker stroker)
Definition: ftstroke.c:845
unsigned char FT_Byte
Definition: fttypes.h:150
#define FT_ASSERT(condition)
Definition: ftdebug.h:211
FT_Memory memory
Definition: ftobjs.h:860
GLint GLint GLsizei GLsizei GLsizei GLint border
FT_Library library
Definition: ftglyph.h:110
FT_Outline outline
Definition: ftglyph.h:211
FT_Vector_From_Polar(FT_Vector *vec, FT_Fixed length, FT_Angle angle)
Definition: fttrigon.c:461
#define FT_FREE(ptr)
Definition: ftmemory.h:286
GLdouble GLdouble right
enum FT_StrokeTags_ FT_StrokeTags
#define FT_EXPORT_DEF(x)
Definition: ftconfig.h:32
FT_Stroker_LineTo(FT_Stroker stroker, FT_Vector *to)
Definition: ftstroke.c:1279
FT_Glyph_Stroke(FT_Glyph *pglyph, FT_Stroker stroker, FT_Bool destroy)
Definition: ftstroke.c:2257
#define FT_STROKE_TAG_BEGIN_END
Definition: ftstroke.c:300
FT_Outline_New(FT_Library library, FT_UInt numPoints, FT_Int numContours, FT_Outline *anoutline)
Definition: ftoutln.c:337
FT_Atan2(FT_Fixed x, FT_Fixed y)
Definition: fttrigon.c:319
enum FT_StrokerBorder_ FT_StrokerBorder
GLint left
FT_UInt idx
Definition: cffcmap.c:127
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:412
#define FT_ERR(e)
Definition: fttypes.h:582
FT_Error error
Definition: cffdrivr.c:411
#define FT_ANGLE_PI
Definition: fttrigon.h:64
FT_Outline_Done(FT_Library library, FT_Outline *outline)
Definition: ftoutln.c:453
FT_Pos x
Definition: ftimage.h:77
struct FT_StrokerRec_ FT_StrokerRec
FT_Pos y
Definition: ftimage.h:78
FT_Sin(FT_Angle angle)
Definition: fttrigon.c:294
GLdouble n
FT_Stroker_ConicTo(FT_Stroker stroker, FT_Vector *control, FT_Vector *to)
Definition: ftstroke.c:1352
const GLubyte * c
FT_BEGIN_HEADER typedef FT_Fixed FT_Angle
Definition: fttrigon.h:52
GLfloat angle
#define FT_RENEW_ARRAY(ptr, curcnt, newcnt)
Definition: ftmemory.h:293
const GLint * first
FT_Vector * vec
Definition: ftbbox.c:566
FT_StrokeTags_
Definition: ftstroke.c:291
#define FT_SIDE_TO_ROTATE(s)
Definition: ftstroke.c:759
#define FALSE
Definition: ftobjs.h:57
FT_Cos(FT_Angle angle)
Definition: fttrigon.c:278
FT_Stroker_CubicTo(FT_Stroker stroker, FT_Vector *control1, FT_Vector *control2, FT_Vector *to)
Definition: ftstroke.c:1547
short n_points
Definition: ftimage.h:386
FT_Stroker_Done(FT_Stroker stroker)
Definition: ftstroke.c:858
FT_Stroker_Export(FT_Stroker stroker, FT_Outline *outline)
Definition: ftstroke.c:2028
GLuint GLuint end
signed short FT_Short
Definition: fttypes.h:194
#define FT_SMALL_CUBIC_THRESHOLD
Definition: ftstroke.c:63
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
#define FT_BOOL(x)
Definition: fttypes.h:574
enum FT_Stroker_LineJoin_ FT_Stroker_LineJoin
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:485
FT_Outline_Check(FT_Outline *outline)
Definition: ftoutln.c:353
#define FT_OUTLINE_GLYPH_CLASS_GET
Definition: basepic.h:29
FT_Stroker_ExportBorder(FT_Stroker stroker, FT_StrokerBorder border, FT_Outline *outline)
Definition: ftstroke.c:2009
signed long FT_Fixed
Definition: fttypes.h:284
FT_Angle_Diff(FT_Angle angle1, FT_Angle angle2)
Definition: fttrigon.c:475
int open(const char *name, int flags, int mode)
Definition: tif_acorn.c:285
unsigned int FT_UInt
Definition: fttypes.h:227
FT_Stroker_Set(FT_Stroker stroker, FT_Fixed radius, FT_Stroker_LineCap line_cap, FT_Stroker_LineJoin line_join, FT_Fixed miter_limit)
Definition: ftstroke.c:819
typedefFT_BEGIN_HEADER struct FT_StrokerRec_ * FT_Stroker
Definition: ftstroke.h:60
FT_Vector_Length(FT_Vector *vec)
Definition: fttrigon.c:400
GLuint GLuint GLsizei count
#define FT_CURVE_TAG_ON
Definition: ftimage.h:516
#define FT_CURVE_TAG_CONIC
Definition: ftimage.h:517
#define FT_NEW(ptr)
Definition: ftmemory.h:288
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:514
FT_Outline_GetInsideBorder(FT_Outline *outline)
Definition: ftstroke.c:31
FT_Done_Glyph(FT_Glyph glyph)
Definition: ftglyph.c:613
#define TRUE
Definition: ftobjs.h:53
FT_Vector * points
Definition: ftimage.h:388
FT_Stroker_New(FT_Library library, FT_Stroker *astroker)
Definition: ftstroke.c:789
FT_Outline_GetOutsideBorder(FT_Outline *outline)
Definition: ftstroke.c:44
GLint limit
FT_Stroker_EndSubPath(FT_Stroker stroker)
Definition: ftstroke.c:1856
FT_Stroker_ParseOutline(FT_Stroker stroker, FT_Outline *outline, FT_Bool opened)
Definition: ftstroke.c:2043