zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 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
72  {
73  return x >= 0 ? x : -x;
74  }
75 
76 
77  static void
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
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
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
181  FT_Angle angle2 )
182  {
183  return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2;
184  }
185 
186 
187  static FT_Bool
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
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
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
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
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
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
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
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
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
626  {
627  border->num_points = 0;
628  border->start = -1;
629  border->valid = FALSE;
630  }
631 
632 
633  static void
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
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
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;
793  FT_Memory memory;
794  FT_Stroker stroker = NULL;
795 
796 
797  if ( !library )
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
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
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;
922  FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
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;
949  FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
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
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
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_MulFix( radius,
1130  FT_DivFix( 0x10000L - sigma,
1131  ft_pos_abs( FT_Sin( theta ) ) ) );
1132 
1133  FT_Vector_From_Polar( &delta, length, phi + rotate );
1134  delta.x += middle.x;
1135  delta.y += middle.y;
1136 
1137  error = ft_stroke_border_lineto( border, &delta, FALSE );
1138  if ( error )
1139  goto Exit;
1140 
1141  /* compute second angle point */
1142  FT_Vector_From_Polar( &delta, length, phi - rotate );
1143  delta.x += middle.x;
1144  delta.y += middle.y;
1145 
1146  error = ft_stroke_border_lineto( border, &delta, FALSE );
1147  if ( error )
1148  goto Exit;
1149 
1150  /* finally, add an end point; only needed if not lineto */
1151  /* (line_length is zero for curves) */
1152  if ( line_length == 0 )
1153  {
1154  FT_Vector_From_Polar( &delta,
1155  radius,
1156  stroker->angle_out + rotate );
1157 
1158  delta.x += stroker->center.x;
1159  delta.y += stroker->center.y;
1160 
1161  error = ft_stroke_border_lineto( border, &delta, FALSE );
1162  }
1163  }
1164  }
1165  else /* this is a miter (intersection) */
1166  {
1167  FT_Fixed length;
1168  FT_Vector delta;
1169 
1170 
1171  length = FT_DivFix( stroker->radius, thcos );
1172 
1173  FT_Vector_From_Polar( &delta, length, phi );
1174  delta.x += stroker->center.x;
1175  delta.y += stroker->center.y;
1176 
1177  error = ft_stroke_border_lineto( border, &delta, FALSE );
1178  if ( error )
1179  goto Exit;
1180 
1181  /* now add an end point; only needed if not lineto */
1182  /* (line_length is zero for curves) */
1183  if ( line_length == 0 )
1184  {
1185  FT_Vector_From_Polar( &delta,
1186  stroker->radius,
1187  stroker->angle_out + rotate );
1188  delta.x += stroker->center.x;
1189  delta.y += stroker->center.y;
1190 
1191  error = ft_stroke_border_lineto( border, &delta, FALSE );
1192  }
1193  }
1194  }
1195 
1196  Exit:
1197  return error;
1198  }
1199 
1200 
1201  static FT_Error
1203  FT_Fixed line_length )
1204  {
1206  FT_Angle turn;
1207  FT_Int inside_side;
1208 
1209 
1210  turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
1211 
1212  /* no specific corner processing is required if the turn is 0 */
1213  if ( turn == 0 )
1214  goto Exit;
1215 
1216  /* when we turn to the right, the inside side is 0 */
1217  inside_side = 0;
1218 
1219  /* otherwise, the inside side is 1 */
1220  if ( turn < 0 )
1221  inside_side = 1;
1222 
1223  /* process the inside side */
1224  error = ft_stroker_inside( stroker, inside_side, line_length );
1225  if ( error )
1226  goto Exit;
1227 
1228  /* process the outside side */
1229  error = ft_stroker_outside( stroker, 1 - inside_side, line_length );
1230 
1231  Exit:
1232  return error;
1233  }
1234 
1235 
1236  /* add two points to the left and right borders corresponding to the */
1237  /* start of the subpath */
1238  static FT_Error
1240  FT_Angle start_angle,
1241  FT_Fixed line_length )
1242  {
1243  FT_Vector delta;
1244  FT_Vector point;
1245  FT_Error error;
1247 
1248 
1249  FT_Vector_From_Polar( &delta, stroker->radius,
1250  start_angle + FT_ANGLE_PI2 );
1251 
1252  point.x = stroker->center.x + delta.x;
1253  point.y = stroker->center.y + delta.y;
1254 
1255  border = stroker->borders;
1256  error = ft_stroke_border_moveto( border, &point );
1257  if ( error )
1258  goto Exit;
1259 
1260  point.x = stroker->center.x - delta.x;
1261  point.y = stroker->center.y - delta.y;
1262 
1263  border++;
1264  error = ft_stroke_border_moveto( border, &point );
1265 
1266  /* save angle, position, and line length for last join */
1267  /* (line_length is zero for curves) */
1268  stroker->subpath_angle = start_angle;
1269  stroker->first_point = FALSE;
1270  stroker->subpath_line_length = line_length;
1271 
1272  Exit:
1273  return error;
1274  }
1275 
1276 
1277  /* documentation is in ftstroke.h */
1278 
1281  FT_Vector* to )
1282  {
1285  FT_Vector delta;
1286  FT_Angle angle;
1287  FT_Int side;
1288  FT_Fixed line_length;
1289 
1290 
1291  delta.x = to->x - stroker->center.x;
1292  delta.y = to->y - stroker->center.y;
1293 
1294  /* a zero-length lineto is a no-op; avoid creating a spurious corner */
1295  if ( delta.x == 0 && delta.y == 0 )
1296  goto Exit;
1297 
1298  /* compute length of line */
1299  line_length = FT_Vector_Length( &delta );
1300 
1301  angle = FT_Atan2( delta.x, delta.y );
1302  FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
1303 
1304  /* process corner if necessary */
1305  if ( stroker->first_point )
1306  {
1307  /* This is the first segment of a subpath. We need to */
1308  /* add a point to each border at their respective starting */
1309  /* point locations. */
1310  error = ft_stroker_subpath_start( stroker, angle, line_length );
1311  if ( error )
1312  goto Exit;
1313  }
1314  else
1315  {
1316  /* process the current corner */
1317  stroker->angle_out = angle;
1318  error = ft_stroker_process_corner( stroker, line_length );
1319  if ( error )
1320  goto Exit;
1321  }
1322 
1323  /* now add a line segment to both the `inside' and `outside' paths */
1324  for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
1325  {
1326  FT_Vector point;
1327 
1328 
1329  point.x = to->x + delta.x;
1330  point.y = to->y + delta.y;
1331 
1332  /* the ends of lineto borders are movable */
1333  error = ft_stroke_border_lineto( border, &point, TRUE );
1334  if ( error )
1335  goto Exit;
1336 
1337  delta.x = -delta.x;
1338  delta.y = -delta.y;
1339  }
1340 
1341  stroker->angle_in = angle;
1342  stroker->center = *to;
1343  stroker->line_length = line_length;
1344 
1345  Exit:
1346  return error;
1347  }
1348 
1349 
1350  /* documentation is in ftstroke.h */
1351 
1354  FT_Vector* control,
1355  FT_Vector* to )
1356  {
1358  FT_Vector bez_stack[34];
1359  FT_Vector* arc;
1360  FT_Vector* limit = bez_stack + 30;
1361  FT_Bool first_arc = TRUE;
1362 
1363 
1364  /* if all control points are coincident, this is a no-op; */
1365  /* avoid creating a spurious corner */
1366  if ( FT_IS_SMALL( stroker->center.x - control->x ) &&
1367  FT_IS_SMALL( stroker->center.y - control->y ) &&
1368  FT_IS_SMALL( control->x - to->x ) &&
1369  FT_IS_SMALL( control->y - to->y ) )
1370  {
1371  stroker->center = *to;
1372  goto Exit;
1373  }
1374 
1375  arc = bez_stack;
1376  arc[0] = *to;
1377  arc[1] = *control;
1378  arc[2] = stroker->center;
1379 
1380  while ( arc >= bez_stack )
1381  {
1382  FT_Angle angle_in, angle_out;
1383 
1384 
1385  /* initialize with current direction */
1386  angle_in = angle_out = stroker->angle_in;
1387 
1388  if ( arc < limit &&
1389  !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
1390  {
1391  if ( stroker->first_point )
1392  stroker->angle_in = angle_in;
1393 
1394  ft_conic_split( arc );
1395  arc += 2;
1396  continue;
1397  }
1398 
1399  if ( first_arc )
1400  {
1401  first_arc = FALSE;
1402 
1403  /* process corner if necessary */
1404  if ( stroker->first_point )
1405  error = ft_stroker_subpath_start( stroker, angle_in, 0 );
1406  else
1407  {
1408  stroker->angle_out = angle_in;
1409  error = ft_stroker_process_corner( stroker, 0 );
1410  }
1411  }
1412  else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
1414  {
1415  /* if the deviation from one arc to the next is too great, */
1416  /* add a round corner */
1417  stroker->center = arc[2];
1418  stroker->angle_out = angle_in;
1419  stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
1420 
1421  error = ft_stroker_process_corner( stroker, 0 );
1422 
1423  /* reinstate line join style */
1424  stroker->line_join = stroker->line_join_saved;
1425  }
1426 
1427  if ( error )
1428  goto Exit;
1429 
1430  /* the arc's angle is small enough; we can add it directly to each */
1431  /* border */
1432  {
1433  FT_Vector ctrl, end;
1434  FT_Angle theta, phi, rotate, alpha0 = 0;
1435  FT_Fixed length;
1437  FT_Int side;
1438 
1439 
1440  theta = FT_Angle_Diff( angle_in, angle_out ) / 2;
1441  phi = angle_in + theta;
1442  length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
1443 
1444  /* compute direction of original arc */
1445  if ( stroker->handle_wide_strokes )
1446  alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y );
1447 
1448  for ( border = stroker->borders, side = 0;
1449  side <= 1;
1450  side++, border++ )
1451  {
1452  rotate = FT_SIDE_TO_ROTATE( side );
1453 
1454  /* compute control point */
1455  FT_Vector_From_Polar( &ctrl, length, phi + rotate );
1456  ctrl.x += arc[1].x;
1457  ctrl.y += arc[1].y;
1458 
1459  /* compute end point */
1460  FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
1461  end.x += arc[0].x;
1462  end.y += arc[0].y;
1463 
1464  if ( stroker->handle_wide_strokes )
1465  {
1466  FT_Vector start;
1467  FT_Angle alpha1;
1468 
1469 
1470  /* determine whether the border radius is greater than the */
1471  /* radius of curvature of the original arc */
1472  start = border->points[border->num_points - 1];
1473 
1474  alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
1475 
1476  /* is the direction of the border arc opposite to */
1477  /* that of the original arc? */
1478  if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
1479  FT_ANGLE_PI / 2 )
1480  {
1481  FT_Angle beta, gamma;
1482  FT_Vector bvec, delta;
1483  FT_Fixed blen, sinA, sinB, alen;
1484 
1485 
1486  /* use the sine rule to find the intersection point */
1487  beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y );
1488  gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
1489 
1490  bvec.x = end.x - start.x;
1491  bvec.y = end.y - start.y;
1492 
1493  blen = FT_Vector_Length( &bvec );
1494 
1495  sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
1496  sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
1497 
1498  alen = FT_DivFix( FT_MulFix( blen, sinA ), sinB );
1499 
1500  FT_Vector_From_Polar( &delta, alen, beta );
1501  delta.x += start.x;
1502  delta.y += start.y;
1503 
1504  /* circumnavigate the negative sector backwards */
1505  border->movable = FALSE;
1506  error = ft_stroke_border_lineto( border, &delta, FALSE );
1507  if ( error )
1508  goto Exit;
1509  error = ft_stroke_border_lineto( border, &end, FALSE );
1510  if ( error )
1511  goto Exit;
1512  error = ft_stroke_border_conicto( border, &ctrl, &start );
1513  if ( error )
1514  goto Exit;
1515  /* and then move to the endpoint */
1516  error = ft_stroke_border_lineto( border, &end, FALSE );
1517  if ( error )
1518  goto Exit;
1519 
1520  continue;
1521  }
1522 
1523  /* else fall through */
1524  }
1525 
1526  /* simply add an arc */
1527  error = ft_stroke_border_conicto( border, &ctrl, &end );
1528  if ( error )
1529  goto Exit;
1530  }
1531  }
1532 
1533  arc -= 2;
1534 
1535  stroker->angle_in = angle_out;
1536  }
1537 
1538  stroker->center = *to;
1539 
1540  Exit:
1541  return error;
1542  }
1543 
1544 
1545  /* documentation is in ftstroke.h */
1546 
1549  FT_Vector* control1,
1550  FT_Vector* control2,
1551  FT_Vector* to )
1552  {
1554  FT_Vector bez_stack[37];
1555  FT_Vector* arc;
1556  FT_Vector* limit = bez_stack + 32;
1557  FT_Bool first_arc = TRUE;
1558 
1559 
1560  /* if all control points are coincident, this is a no-op; */
1561  /* avoid creating a spurious corner */
1562  if ( FT_IS_SMALL( stroker->center.x - control1->x ) &&
1563  FT_IS_SMALL( stroker->center.y - control1->y ) &&
1564  FT_IS_SMALL( control1->x - control2->x ) &&
1565  FT_IS_SMALL( control1->y - control2->y ) &&
1566  FT_IS_SMALL( control2->x - to->x ) &&
1567  FT_IS_SMALL( control2->y - to->y ) )
1568  {
1569  stroker->center = *to;
1570  goto Exit;
1571  }
1572 
1573  arc = bez_stack;
1574  arc[0] = *to;
1575  arc[1] = *control2;
1576  arc[2] = *control1;
1577  arc[3] = stroker->center;
1578 
1579  while ( arc >= bez_stack )
1580  {
1581  FT_Angle angle_in, angle_mid, angle_out;
1582 
1583 
1584  /* initialize with current direction */
1585  angle_in = angle_out = angle_mid = stroker->angle_in;
1586 
1587  if ( arc < limit &&
1588  !ft_cubic_is_small_enough( arc, &angle_in,
1589  &angle_mid, &angle_out ) )
1590  {
1591  if ( stroker->first_point )
1592  stroker->angle_in = angle_in;
1593 
1594  ft_cubic_split( arc );
1595  arc += 3;
1596  continue;
1597  }
1598 
1599  if ( first_arc )
1600  {
1601  first_arc = FALSE;
1602 
1603  /* process corner if necessary */
1604  if ( stroker->first_point )
1605  error = ft_stroker_subpath_start( stroker, angle_in, 0 );
1606  else
1607  {
1608  stroker->angle_out = angle_in;
1609  error = ft_stroker_process_corner( stroker, 0 );
1610  }
1611  }
1612  else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
1614  {
1615  /* if the deviation from one arc to the next is too great, */
1616  /* add a round corner */
1617  stroker->center = arc[3];
1618  stroker->angle_out = angle_in;
1619  stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
1620 
1621  error = ft_stroker_process_corner( stroker, 0 );
1622 
1623  /* reinstate line join style */
1624  stroker->line_join = stroker->line_join_saved;
1625  }
1626 
1627  if ( error )
1628  goto Exit;
1629 
1630  /* the arc's angle is small enough; we can add it directly to each */
1631  /* border */
1632  {
1633  FT_Vector ctrl1, ctrl2, end;
1634  FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0;
1635  FT_Fixed length1, length2;
1637  FT_Int side;
1638 
1639 
1640  theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2;
1641  theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2;
1642  phi1 = ft_angle_mean( angle_in, angle_mid );
1643  phi2 = ft_angle_mean( angle_mid, angle_out );
1644  length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
1645  length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) );
1646 
1647  /* compute direction of original arc */
1648  if ( stroker->handle_wide_strokes )
1649  alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y );
1650 
1651  for ( border = stroker->borders, side = 0;
1652  side <= 1;
1653  side++, border++ )
1654  {
1655  rotate = FT_SIDE_TO_ROTATE( side );
1656 
1657  /* compute control points */
1658  FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
1659  ctrl1.x += arc[2].x;
1660  ctrl1.y += arc[2].y;
1661 
1662  FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
1663  ctrl2.x += arc[1].x;
1664  ctrl2.y += arc[1].y;
1665 
1666  /* compute end point */
1667  FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
1668  end.x += arc[0].x;
1669  end.y += arc[0].y;
1670 
1671  if ( stroker->handle_wide_strokes )
1672  {
1673  FT_Vector start;
1674  FT_Angle alpha1;
1675 
1676 
1677  /* determine whether the border radius is greater than the */
1678  /* radius of curvature of the original arc */
1679  start = border->points[border->num_points - 1];
1680 
1681  alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
1682 
1683  /* is the direction of the border arc opposite to */
1684  /* that of the original arc? */
1685  if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
1686  FT_ANGLE_PI / 2 )
1687  {
1688  FT_Angle beta, gamma;
1689  FT_Vector bvec, delta;
1690  FT_Fixed blen, sinA, sinB, alen;
1691 
1692 
1693  /* use the sine rule to find the intersection point */
1694  beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y );
1695  gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
1696 
1697  bvec.x = end.x - start.x;
1698  bvec.y = end.y - start.y;
1699 
1700  blen = FT_Vector_Length( &bvec );
1701 
1702  sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
1703  sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
1704 
1705  alen = FT_DivFix( FT_MulFix( blen, sinA ), sinB );
1706 
1707  FT_Vector_From_Polar( &delta, alen, beta );
1708  delta.x += start.x;
1709  delta.y += start.y;
1710 
1711  /* circumnavigate the negative sector backwards */
1712  border->movable = FALSE;
1713  error = ft_stroke_border_lineto( border, &delta, FALSE );
1714  if ( error )
1715  goto Exit;
1716  error = ft_stroke_border_lineto( border, &end, FALSE );
1717  if ( error )
1718  goto Exit;
1719  error = ft_stroke_border_cubicto( border,
1720  &ctrl2,
1721  &ctrl1,
1722  &start );
1723  if ( error )
1724  goto Exit;
1725  /* and then move to the endpoint */
1726  error = ft_stroke_border_lineto( border, &end, FALSE );
1727  if ( error )
1728  goto Exit;
1729 
1730  continue;
1731  }
1732 
1733  /* else fall through */
1734  }
1735 
1736  /* simply add an arc */
1737  error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end );
1738  if ( error )
1739  goto Exit;
1740  }
1741  }
1742 
1743  arc -= 3;
1744 
1745  stroker->angle_in = angle_out;
1746  }
1747 
1748  stroker->center = *to;
1749 
1750  Exit:
1751  return error;
1752  }
1753 
1754 
1755  /* documentation is in ftstroke.h */
1756 
1759  FT_Vector* to,
1760  FT_Bool open )
1761  {
1762  /* We cannot process the first point, because there is not enough */
1763  /* information regarding its corner/cap. The latter will be processed */
1764  /* in the `FT_Stroker_EndSubPath' routine. */
1765  /* */
1766  stroker->first_point = TRUE;
1767  stroker->center = *to;
1768  stroker->subpath_open = open;
1769 
1770  /* Determine if we need to check whether the border radius is greater */
1771  /* than the radius of curvature of a curve, to handle this case */
1772  /* specially. This is only required if bevel joins or butt caps may */
1773  /* be created, because round & miter joins and round & square caps */
1774  /* cover the negative sector created with wide strokes. */
1775  stroker->handle_wide_strokes =
1776  FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND ||
1777  ( stroker->subpath_open &&
1778  stroker->line_cap == FT_STROKER_LINECAP_BUTT ) );
1779 
1780  /* record the subpath start point for each border */
1781  stroker->subpath_start = *to;
1782 
1783  stroker->angle_in = 0;
1784 
1785  return FT_Err_Ok;
1786  }
1787 
1788 
1789  static FT_Error
1791  FT_Bool open )
1792  {
1793  FT_StrokeBorder right = stroker->borders + 0;
1794  FT_StrokeBorder left = stroker->borders + 1;
1795  FT_Int new_points;
1797 
1798 
1799  FT_ASSERT( left->start >= 0 );
1800 
1801  new_points = left->num_points - left->start;
1802  if ( new_points > 0 )
1803  {
1804  error = ft_stroke_border_grow( right, (FT_UInt)new_points );
1805  if ( error )
1806  goto Exit;
1807 
1808  {
1809  FT_Vector* dst_point = right->points + right->num_points;
1810  FT_Byte* dst_tag = right->tags + right->num_points;
1811  FT_Vector* src_point = left->points + left->num_points - 1;
1812  FT_Byte* src_tag = left->tags + left->num_points - 1;
1813 
1814 
1815  while ( src_point >= left->points + left->start )
1816  {
1817  *dst_point = *src_point;
1818  *dst_tag = *src_tag;
1819 
1820  if ( open )
1821  dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END;
1822  else
1823  {
1824  FT_Byte ttag =
1825  (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
1826 
1827 
1828  /* switch begin/end tags if necessary */
1829  if ( ttag == FT_STROKE_TAG_BEGIN ||
1830  ttag == FT_STROKE_TAG_END )
1831  dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END;
1832  }
1833 
1834  src_point--;
1835  src_tag--;
1836  dst_point++;
1837  dst_tag++;
1838  }
1839  }
1840 
1841  left->num_points = left->start;
1842  right->num_points += new_points;
1843 
1844  right->movable = FALSE;
1845  left->movable = FALSE;
1846  }
1847 
1848  Exit:
1849  return error;
1850  }
1851 
1852 
1853  /* documentation is in ftstroke.h */
1854 
1855  /* there's a lot of magic in this function! */
1858  {
1860 
1861 
1862  if ( stroker->subpath_open )
1863  {
1864  FT_StrokeBorder right = stroker->borders;
1865 
1866 
1867  /* All right, this is an opened path, we need to add a cap between */
1868  /* right & left, add the reverse of left, then add a final cap */
1869  /* between left & right. */
1870  error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
1871  if ( error )
1872  goto Exit;
1873 
1874  /* add reversed points from `left' to `right' */
1875  error = ft_stroker_add_reverse_left( stroker, TRUE );
1876  if ( error )
1877  goto Exit;
1878 
1879  /* now add the final cap */
1880  stroker->center = stroker->subpath_start;
1881  error = ft_stroker_cap( stroker,
1882  stroker->subpath_angle + FT_ANGLE_PI, 0 );
1883  if ( error )
1884  goto Exit;
1885 
1886  /* Now end the right subpath accordingly. The left one is */
1887  /* rewind and doesn't need further processing. */
1888  ft_stroke_border_close( right, FALSE );
1889  }
1890  else
1891  {
1892  FT_Angle turn;
1893  FT_Int inside_side;
1894 
1895 
1896  /* close the path if needed */
1897  if ( stroker->center.x != stroker->subpath_start.x ||
1898  stroker->center.y != stroker->subpath_start.y )
1899  {
1900  error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
1901  if ( error )
1902  goto Exit;
1903  }
1904 
1905  /* process the corner */
1906  stroker->angle_out = stroker->subpath_angle;
1907  turn = FT_Angle_Diff( stroker->angle_in,
1908  stroker->angle_out );
1909 
1910  /* no specific corner processing is required if the turn is 0 */
1911  if ( turn != 0 )
1912  {
1913  /* when we turn to the right, the inside side is 0 */
1914  inside_side = 0;
1915 
1916  /* otherwise, the inside side is 1 */
1917  if ( turn < 0 )
1918  inside_side = 1;
1919 
1920  error = ft_stroker_inside( stroker,
1921  inside_side,
1922  stroker->subpath_line_length );
1923  if ( error )
1924  goto Exit;
1925 
1926  /* process the outside side */
1927  error = ft_stroker_outside( stroker,
1928  1 - inside_side,
1929  stroker->subpath_line_length );
1930  if ( error )
1931  goto Exit;
1932  }
1933 
1934  /* then end our two subpaths */
1935  ft_stroke_border_close( stroker->borders + 0, FALSE );
1936  ft_stroke_border_close( stroker->borders + 1, TRUE );
1937  }
1938 
1939  Exit:
1940  return error;
1941  }
1942 
1943 
1944  /* documentation is in ftstroke.h */
1945 
1949  FT_UInt *anum_points,
1950  FT_UInt *anum_contours )
1951  {
1952  FT_UInt num_points = 0, num_contours = 0;
1953  FT_Error error;
1954 
1955 
1956  if ( !stroker || border > 1 )
1957  {
1958  error = FT_Err_Invalid_Argument;
1959  goto Exit;
1960  }
1961 
1962  error = ft_stroke_border_get_counts( stroker->borders + border,
1963  &num_points, &num_contours );
1964  Exit:
1965  if ( anum_points )
1966  *anum_points = num_points;
1967 
1968  if ( anum_contours )
1969  *anum_contours = num_contours;
1970 
1971  return error;
1972  }
1973 
1974 
1975  /* documentation is in ftstroke.h */
1976 
1979  FT_UInt *anum_points,
1980  FT_UInt *anum_contours )
1981  {
1982  FT_UInt count1, count2, num_points = 0;
1983  FT_UInt count3, count4, num_contours = 0;
1984  FT_Error error;
1985 
1986 
1987  error = ft_stroke_border_get_counts( stroker->borders + 0,
1988  &count1, &count2 );
1989  if ( error )
1990  goto Exit;
1991 
1992  error = ft_stroke_border_get_counts( stroker->borders + 1,
1993  &count3, &count4 );
1994  if ( error )
1995  goto Exit;
1996 
1997  num_points = count1 + count3;
1998  num_contours = count2 + count4;
1999 
2000  Exit:
2001  *anum_points = num_points;
2002  *anum_contours = num_contours;
2003  return error;
2004  }
2005 
2006 
2007  /* documentation is in ftstroke.h */
2008 
2009  FT_EXPORT_DEF( void )
2012  FT_Outline* outline )
2013  {
2014  if ( border == FT_STROKER_BORDER_LEFT ||
2015  border == FT_STROKER_BORDER_RIGHT )
2016  {
2017  FT_StrokeBorder sborder = & stroker->borders[border];
2018 
2019 
2020  if ( sborder->valid )
2021  ft_stroke_border_export( sborder, outline );
2022  }
2023  }
2024 
2025 
2026  /* documentation is in ftstroke.h */
2027 
2028  FT_EXPORT_DEF( void )
2030  FT_Outline* outline )
2031  {
2032  FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline );
2033  FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline );
2034  }
2035 
2036 
2037  /* documentation is in ftstroke.h */
2038 
2039  /*
2040  * The following is very similar to FT_Outline_Decompose, except
2041  * that we do support opened paths, and do not scale the outline.
2042  */
2045  FT_Outline* outline,
2046  FT_Bool opened )
2047  {
2048  FT_Vector v_last;
2049  FT_Vector v_control;
2050  FT_Vector v_start;
2051 
2052  FT_Vector* point;
2053  FT_Vector* limit;
2054  char* tags;
2055 
2056  FT_Error error;
2057 
2058  FT_Int n; /* index of contour in outline */
2059  FT_UInt first; /* index of first point in contour */
2060  FT_Int tag; /* current point's state */
2061 
2062 
2063  if ( !outline || !stroker )
2064  return FT_Err_Invalid_Argument;
2065 
2066  FT_Stroker_Rewind( stroker );
2067 
2068  first = 0;
2069 
2070  for ( n = 0; n < outline->n_contours; n++ )
2071  {
2072  FT_UInt last; /* index of last point in contour */
2073 
2074 
2075  last = outline->contours[n];
2076  limit = outline->points + last;
2077 
2078  /* skip empty points; we don't stroke these */
2079  if ( last <= first )
2080  {
2081  first = last + 1;
2082  continue;
2083  }
2084 
2085  v_start = outline->points[first];
2086  v_last = outline->points[last];
2087 
2088  v_control = v_start;
2089 
2090  point = outline->points + first;
2091  tags = outline->tags + first;
2092  tag = FT_CURVE_TAG( tags[0] );
2093 
2094  /* A contour cannot start with a cubic control point! */
2095  if ( tag == FT_CURVE_TAG_CUBIC )
2096  goto Invalid_Outline;
2097 
2098  /* check first point to determine origin */
2099  if ( tag == FT_CURVE_TAG_CONIC )
2100  {
2101  /* First point is conic control. Yes, this happens. */
2102  if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
2103  {
2104  /* start at last point if it is on the curve */
2105  v_start = v_last;
2106  limit--;
2107  }
2108  else
2109  {
2110  /* if both first and last points are conic, */
2111  /* start at their middle */
2112  v_start.x = ( v_start.x + v_last.x ) / 2;
2113  v_start.y = ( v_start.y + v_last.y ) / 2;
2114  }
2115  point--;
2116  tags--;
2117  }
2118 
2119  error = FT_Stroker_BeginSubPath( stroker, &v_start, opened );
2120  if ( error )
2121  goto Exit;
2122 
2123  while ( point < limit )
2124  {
2125  point++;
2126  tags++;
2127 
2128  tag = FT_CURVE_TAG( tags[0] );
2129  switch ( tag )
2130  {
2131  case FT_CURVE_TAG_ON: /* emit a single line_to */
2132  {
2133  FT_Vector vec;
2134 
2135 
2136  vec.x = point->x;
2137  vec.y = point->y;
2138 
2139  error = FT_Stroker_LineTo( stroker, &vec );
2140  if ( error )
2141  goto Exit;
2142  continue;
2143  }
2144 
2145  case FT_CURVE_TAG_CONIC: /* consume conic arcs */
2146  v_control.x = point->x;
2147  v_control.y = point->y;
2148 
2149  Do_Conic:
2150  if ( point < limit )
2151  {
2152  FT_Vector vec;
2153  FT_Vector v_middle;
2154 
2155 
2156  point++;
2157  tags++;
2158  tag = FT_CURVE_TAG( tags[0] );
2159 
2160  vec = point[0];
2161 
2162  if ( tag == FT_CURVE_TAG_ON )
2163  {
2164  error = FT_Stroker_ConicTo( stroker, &v_control, &vec );
2165  if ( error )
2166  goto Exit;
2167  continue;
2168  }
2169 
2170  if ( tag != FT_CURVE_TAG_CONIC )
2171  goto Invalid_Outline;
2172 
2173  v_middle.x = ( v_control.x + vec.x ) / 2;
2174  v_middle.y = ( v_control.y + vec.y ) / 2;
2175 
2176  error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle );
2177  if ( error )
2178  goto Exit;
2179 
2180  v_control = vec;
2181  goto Do_Conic;
2182  }
2183 
2184  error = FT_Stroker_ConicTo( stroker, &v_control, &v_start );
2185  goto Close;
2186 
2187  default: /* FT_CURVE_TAG_CUBIC */
2188  {
2189  FT_Vector vec1, vec2;
2190 
2191 
2192  if ( point + 1 > limit ||
2193  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
2194  goto Invalid_Outline;
2195 
2196  point += 2;
2197  tags += 2;
2198 
2199  vec1 = point[-2];
2200  vec2 = point[-1];
2201 
2202  if ( point <= limit )
2203  {
2204  FT_Vector vec;
2205 
2206 
2207  vec = point[0];
2208 
2209  error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec );
2210  if ( error )
2211  goto Exit;
2212  continue;
2213  }
2214 
2215  error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start );
2216  goto Close;
2217  }
2218  }
2219  }
2220 
2221  Close:
2222  if ( error )
2223  goto Exit;
2224 
2225  /* don't try to end the path if no segments have been generated */
2226  if ( !stroker->first_point )
2227  {
2228  error = FT_Stroker_EndSubPath( stroker );
2229  if ( error )
2230  goto Exit;
2231  }
2232 
2233  first = last + 1;
2234  }
2235 
2236  return FT_Err_Ok;
2237 
2238  Exit:
2239  return error;
2240 
2241  Invalid_Outline:
2242  return FT_Err_Invalid_Outline;
2243  }
2244 
2245 
2246  /* declare an extern to access `ft_outline_glyph_class' globally */
2247  /* allocated in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */
2248  /* macro to access it when FT_CONFIG_OPTION_PIC is defined */
2249 #ifndef FT_CONFIG_OPTION_PIC
2251 #endif
2252 #include "basepic.h"
2253 
2254 
2255  /* documentation is in ftstroke.h */
2256 
2259  FT_Stroker stroker,
2260  FT_Bool destroy )
2261  {
2263  FT_Glyph glyph = NULL;
2264  FT_Library library = stroker->library;
2265 
2266  FT_UNUSED( library );
2267 
2268 
2269  if ( pglyph == NULL )
2270  goto Exit;
2271 
2272  glyph = *pglyph;
2273  if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
2274  goto Exit;
2275 
2276  {
2277  FT_Glyph copy;
2278 
2279 
2280  error = FT_Glyph_Copy( glyph, &copy );
2281  if ( error )
2282  goto Exit;
2283 
2284  glyph = copy;
2285  }
2286 
2287  {
2288  FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
2289  FT_Outline* outline = &oglyph->outline;
2290  FT_UInt num_points, num_contours;
2291 
2292 
2293  error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
2294  if ( error )
2295  goto Fail;
2296 
2297  (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours );
2298 
2299  FT_Outline_Done( glyph->library, outline );
2300 
2301  error = FT_Outline_New( glyph->library,
2302  num_points, num_contours, outline );
2303  if ( error )
2304  goto Fail;
2305 
2306  outline->n_points = 0;
2307  outline->n_contours = 0;
2308 
2309  FT_Stroker_Export( stroker, outline );
2310  }
2311 
2312  if ( destroy )
2313  FT_Done_Glyph( *pglyph );
2314 
2315  *pglyph = glyph;
2316  goto Exit;
2317 
2318  Fail:
2319  FT_Done_Glyph( glyph );
2320  glyph = NULL;
2321 
2322  if ( !destroy )
2323  *pglyph = NULL;
2324 
2325  Exit:
2326  return error;
2327  }
2328 
2329 
2330  /* documentation is in ftstroke.h */
2331 
2334  FT_Stroker stroker,
2335  FT_Bool inside,
2336  FT_Bool destroy )
2337  {
2339  FT_Glyph glyph = NULL;
2340  FT_Library library = stroker->library;
2341 
2342  FT_UNUSED( library );
2343 
2344 
2345  if ( pglyph == NULL )
2346  goto Exit;
2347 
2348  glyph = *pglyph;
2349  if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
2350  goto Exit;
2351 
2352  {
2353  FT_Glyph copy;
2354 
2355 
2356  error = FT_Glyph_Copy( glyph, &copy );
2357  if ( error )
2358  goto Exit;
2359 
2360  glyph = copy;
2361  }
2362 
2363  {
2364  FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
2366  FT_Outline* outline = &oglyph->outline;
2367  FT_UInt num_points, num_contours;
2368 
2369 
2370  border = FT_Outline_GetOutsideBorder( outline );
2371  if ( inside )
2372  {
2373  if ( border == FT_STROKER_BORDER_LEFT )
2374  border = FT_STROKER_BORDER_RIGHT;
2375  else
2376  border = FT_STROKER_BORDER_LEFT;
2377  }
2378 
2379  error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
2380  if ( error )
2381  goto Fail;
2382 
2383  (void)FT_Stroker_GetBorderCounts( stroker, border,
2384  &num_points, &num_contours );
2385 
2386  FT_Outline_Done( glyph->library, outline );
2387 
2388  error = FT_Outline_New( glyph->library,
2389  num_points,
2390  num_contours,
2391  outline );
2392  if ( error )
2393  goto Fail;
2394 
2395  outline->n_points = 0;
2396  outline->n_contours = 0;
2397 
2398  FT_Stroker_ExportBorder( stroker, border, outline );
2399  }
2400 
2401  if ( destroy )
2402  FT_Done_Glyph( *pglyph );
2403 
2404  *pglyph = glyph;
2405  goto Exit;
2406 
2407  Fail:
2408  FT_Done_Glyph( glyph );
2409  glyph = NULL;
2410 
2411  if ( !destroy )
2412  *pglyph = NULL;
2413 
2414  Exit:
2415  return error;
2416  }
2417 
2418 
2419 /* END */
enum FT_Stroker_LineCap_ FT_Stroker_LineCap
int FT_Error
Definition: fttypes.h:296
FT_Stroker_ParseOutline(FT_Stroker stroker, FT_Outline *outline, FT_Bool opened)
Definition: ftstroke.c:2044
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:536
#define FT_ARC_CUBIC_ANGLE
Definition: ftstroke.c:521
angle2
Definition: cordic.py:50
#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
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
typedefFT_BEGIN_HEADER struct FT_Glyph_Class_ FT_Glyph_Class
Definition: ftglyph.h:69
GLint left
Definition: glew.h:7291
FT_Stroker_Rewind(FT_Stroker stroker)
Definition: ftstroke.c:845
#define FT_CURVE_TAG_CUBIC
Definition: ftimage.h:518
#define NULL
Definition: ftobjs.h:61
const FT_Glyph_Class ft_outline_glyph_class
signed int FT_Int
Definition: fttypes.h:216
GLuint start
Definition: glew.h:1239
short n_contours
Definition: ftimage.h:385
#define FT_ARRAY_COPY(dest, source, count)
Definition: ftmemory.h:216
struct FT_StrokeBorderRec_ * FT_StrokeBorder
GLdouble angle
Definition: glew.h:8396
static void ft_conic_split(FT_Vector *base)
Definition: ftstroke.c:78
return FT_Err_Invalid_Argument
Definition: ftbbox.c:584
enum FT_Orientation_ FT_Orientation
GLclampd n
Definition: glew.h:7287
short * contours
Definition: ftimage.h:390
EGLSurface EGLint x
Definition: eglext.h:293
FT_Tan(FT_Angle angle)
Definition: fttrigon.c:358
char * tags
Definition: ftimage.h:389
FT_Glyph_Copy(FT_Glyph source, FT_Glyph *target)
Definition: ftglyph.c:306
FT_Outline_Get_Orientation(FT_Outline *outline)
Definition: ftoutln.c:976
static FT_Error ft_stroker_arcto(FT_Stroker stroker, FT_Int side)
Definition: ftstroke.c:876
#define FT_SMALL_CONIC_THRESHOLD
Definition: ftstroke.c:62
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
FT_Library library
Definition: cffdrivr.c:409
static FT_Error ft_stroker_outside(FT_Stroker stroker, FT_Int side, FT_Fixed line_length)
Definition: ftstroke.c:1040
return FT_Err_Ok
Definition: ftbbox.c:658
FT_Stroker_GetBorderCounts(FT_Stroker stroker, FT_StrokerBorder border, FT_UInt *anum_points, FT_UInt *anum_contours)
Definition: ftstroke.c:1947
static FT_Error ft_stroke_border_lineto(FT_StrokeBorder border, FT_Vector *to, FT_Bool movable)
Definition: ftstroke.c:413
static void ft_stroke_border_close(FT_StrokeBorder border, FT_Bool reverse)
Definition: ftstroke.c:347
return Display return Display Bool Bool int d
Definition: SDL_x11sym.h:30
static FT_Pos ft_pos_abs(FT_Pos x)
Definition: ftstroke.c:71
static FT_Error ft_stroker_subpath_start(FT_Stroker stroker, FT_Angle start_angle, FT_Fixed line_length)
Definition: ftstroke.c:1239
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
FT_Glyph_StrokeBorder(FT_Glyph *pglyph, FT_Stroker stroker, FT_Bool inside, FT_Bool destroy)
Definition: ftstroke.c:2333
FT_Stroker_ConicTo(FT_Stroker stroker, FT_Vector *control, FT_Vector *to)
Definition: ftstroke.c:1353
static FT_Error ft_stroke_border_arcto(FT_StrokeBorder border, FT_Vector *center, FT_Fixed radius, FT_Angle angle_start, FT_Angle angle_diff)
Definition: ftstroke.c:525
unsigned char FT_Byte
Definition: fttypes.h:150
#define FT_ASSERT(condition)
Definition: ftdebug.h:204
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:515
#define FT_FREE(ptr)
Definition: ftmemory.h:286
GLint first
Definition: gl2ext.h:1011
enum FT_StrokeTags_ FT_StrokeTags
#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:329
FT_Atan2(FT_Fixed x, FT_Fixed y)
Definition: fttrigon.c:374
enum FT_StrokerBorder_ FT_StrokerBorder
FT_UInt idx
Definition: cffcmap.c:125
for(;;)
GLsizei GLsizei * length
Definition: gl2ext.h:792
FT_Stroker_ExportBorder(FT_Stroker stroker, FT_StrokerBorder border, FT_Outline *outline)
Definition: ftstroke.c:2010
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:358
FT_Error error
Definition: cffdrivr.c:407
#define FT_ANGLE_PI
Definition: fttrigon.h:64
FT_Stroker_BeginSubPath(FT_Stroker stroker, FT_Vector *to, FT_Bool open)
Definition: ftstroke.c:1758
FT_Outline_Done(FT_Library library, FT_Outline *outline)
Definition: ftoutln.c:445
FT_Pos x
Definition: ftimage.h:77
struct FT_StrokerRec_ FT_StrokerRec
FT_Stroker_LineTo(FT_Stroker stroker, FT_Vector *to)
Definition: ftstroke.c:1280
GLint GLsizei count
Definition: gl2ext.h:1011
static FT_Bool ft_cubic_is_small_enough(FT_Vector *base, FT_Angle *angle_in, FT_Angle *angle_mid, FT_Angle *angle_out)
Definition: ftstroke.c:188
static FT_Error ft_stroker_process_corner(FT_Stroker stroker, FT_Fixed line_length)
Definition: ftstroke.c:1202
static FT_Error ft_stroker_inside(FT_Stroker stroker, FT_Int side, FT_Fixed line_length)
Definition: ftstroke.c:978
FT_Pos y
Definition: ftimage.h:78
const GLfloat * c
Definition: glew.h:14913
FT_Sin(FT_Angle angle)
Definition: fttrigon.c:349
FT_BEGIN_HEADER typedef FT_Fixed FT_Angle
Definition: fttrigon.h:52
FT_Stroker_EndSubPath(FT_Stroker stroker)
Definition: ftstroke.c:1857
GLint limit
Definition: glew.h:11829
#define FT_RENEW_ARRAY(ptr, curcnt, newcnt)
Definition: ftmemory.h:293
FT_Stroker_Export(FT_Stroker stroker, FT_Outline *outline)
Definition: ftstroke.c:2029
GLint GLenum GLsizei GLsizei GLsizei GLint border
Definition: gl2ext.h:845
static void ft_stroke_border_done(FT_StrokeBorder border)
Definition: ftstroke.c:634
FT_Glyph_Stroke(FT_Glyph *pglyph, FT_Stroker stroker, FT_Bool destroy)
Definition: ftstroke.c:2258
FT_Vector * vec
Definition: ftbbox.c:579
FT_StrokeTags_
Definition: ftstroke.c:291
#define FT_SIDE_TO_ROTATE(s)
Definition: ftstroke.c:759
local int destroy(gz_stream *s)
Definition: gzio.c:355
#define FALSE
Definition: ftobjs.h:57
FT_Cos(FT_Angle angle)
Definition: fttrigon.c:333
short n_points
Definition: ftimage.h:386
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
static void ft_stroke_border_reset(FT_StrokeBorder border)
Definition: ftstroke.c:625
#define FT_BOOL(x)
Definition: fttypes.h:581
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
enum FT_Stroker_LineJoin_ FT_Stroker_LineJoin
FT_Stroker_CubicTo(FT_Stroker stroker, FT_Vector *control1, FT_Vector *control2, FT_Vector *to)
Definition: ftstroke.c:1548
EGLSurface EGLint EGLint y
Definition: eglext.h:293
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:435
FT_Outline_GetInsideBorder(FT_Outline *outline)
Definition: ftstroke.c:31
FT_Outline_Check(FT_Outline *outline)
Definition: ftoutln.c:345
#define FT_OUTLINE_GLYPH_CLASS_GET
Definition: basepic.h:28
static FT_Angle ft_angle_mean(FT_Angle angle1, FT_Angle angle2)
Definition: ftstroke.c:180
static FT_Error ft_stroke_border_cubicto(FT_StrokeBorder border, FT_Vector *control1, FT_Vector *control2, FT_Vector *to)
Definition: ftstroke.c:487
signed long FT_Fixed
Definition: fttypes.h:284
static FT_Bool ft_conic_is_small_enough(FT_Vector *base, FT_Angle *angle_in, FT_Angle *angle_out)
Definition: ftstroke.c:98
FT_Angle_Diff(FT_Angle angle1, FT_Angle angle2)
Definition: fttrigon.c:529
#define FT_EXPORT_DEF(x)
Definition: ftconfig.h:511
unsigned int FT_UInt
Definition: fttypes.h:227
FT_Stroker_Done(FT_Stroker stroker)
Definition: ftstroke.c:858
static FT_Error ft_stroke_border_get_counts(FT_StrokeBorder border, FT_UInt *anum_points, FT_UInt *anum_contours)
Definition: ftstroke.c:650
static void ft_stroke_border_export(FT_StrokeBorder border, FT_Outline *outline)
Definition: ftstroke.c:701
static FT_Error ft_stroker_cap(FT_Stroker stroker, FT_Angle angle, FT_Int side)
Definition: ftstroke.c:903
GLdouble GLdouble GLdouble b
Definition: glew.h:8383
GLuint GLuint end
Definition: glew.h:1239
FT_Stroker_New(FT_Library library, FT_Stroker *astroker)
Definition: ftstroke.c:789
typedefFT_BEGIN_HEADER struct FT_StrokerRec_ * FT_Stroker
Definition: ftstroke.h:60
FT_Outline_GetOutsideBorder(FT_Outline *outline)
Definition: ftstroke.c:44
FT_Vector_Length(FT_Vector *vec)
Definition: fttrigon.c:455
#define FT_CURVE_TAG_ON
Definition: ftimage.h:516
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3337
#define FT_CURVE_TAG_CONIC
Definition: ftimage.h:517
static FT_Error ft_stroke_border_moveto(FT_StrokeBorder border, FT_Vector *to)
Definition: ftstroke.c:595
#define FT_NEW(ptr)
Definition: ftmemory.h:288
static void ft_cubic_split(FT_Vector *base)
Definition: ftstroke.c:149
GLfloat right
Definition: glew.h:13816
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:514
FT_Stroker_GetCounts(FT_Stroker stroker, FT_UInt *anum_points, FT_UInt *anum_contours)
Definition: ftstroke.c:1978
static FT_Error ft_stroke_border_conicto(FT_StrokeBorder border, FT_Vector *control, FT_Vector *to)
Definition: ftstroke.c:455
FT_Done_Glyph(FT_Glyph glyph)
Definition: ftglyph.c:611
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
#define TRUE
Definition: ftobjs.h:53
FT_Vector * points
Definition: ftimage.h:388
static FT_Error ft_stroke_border_grow(FT_StrokeBorder border, FT_UInt new_points)
Definition: ftstroke.c:317
return FT_Err_Invalid_Outline
Definition: ftbbox.c:587
static FT_Error ft_stroker_add_reverse_left(FT_Stroker stroker, FT_Bool open)
Definition: ftstroke.c:1790
static void ft_stroke_border_init(FT_StrokeBorder border, FT_Memory memory)
Definition: ftstroke.c:610