4141#include " truetype.h"
4242#include < algorithm>
4343#include < stack>
44+ #include < list>
4445
4546class GlyphToType3
4647{
@@ -73,7 +74,10 @@ class GlyphToType3
7374 int nextoutctr (int co);
7475 int nearout (int ci);
7576 double intest (int co, int ci);
76- void PSCurveto (TTStreamWriter& stream, FWord x, FWord y, int s, int t);
77+ void PSCurveto (TTStreamWriter& stream,
78+ FWord x0, FWord y0,
79+ FWord x1, FWord y1,
80+ FWord x2, FWord y2);
7781 void PSMoveto (TTStreamWriter& stream, int x, int y);
7882 void PSLineto (TTStreamWriter& stream, int x, int y);
7983 void do_composite (TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph);
@@ -83,6 +87,18 @@ class GlyphToType3
8387 ~GlyphToType3 ();
8488};
8589
90+ // Each point on a TrueType contour is either on the path or off it (a
91+ // control point); here's a simple representation for building such
92+ // contours. Added by Jouni Seppänen 2012-05-27.
93+ enum Flag { ON_PATH, OFF_PATH };
94+ struct FlaggedPoint
95+ {
96+ enum Flag flag;
97+ FWord x;
98+ FWord y;
99+ FlaggedPoint (Flag flag_, FWord x_, FWord y_): flag(flag_), x(x_), y(y_) {};
100+ };
101+
86102double area (FWord *x, FWord *y, int n);
87103#define sqr (x ) ((x)*(x))
88104
@@ -150,8 +166,7 @@ double area(FWord *x, FWord *y, int n)
150166*/
151167void GlyphToType3::PSConvert (TTStreamWriter& stream)
152168{
153- int i,j,k,fst,start_offpt;
154- int end_offpt = 0 ;
169+ int i,j,k;
155170
156171 assert (area_ctr == NULL );
157172 area_ctr=(double *)calloc (num_ctr, sizeof (double ));
@@ -191,56 +206,79 @@ void GlyphToType3::PSConvert(TTStreamWriter& stream)
191206 i=j=k=0 ;
192207 while ( i < num_ctr )
193208 {
194- fst = j = (k==0 ) ? 0 : (epts_ctr[k-1 ]+1 );
209+ // A TrueType contour consists of on-path and off-path points.
210+ // Two consecutive on-path points are to be joined with a
211+ // line; off-path points between on-path points indicate a
212+ // quadratic spline, where the off-path point is the control
213+ // point. Two consecutive off-path points have an implicit
214+ // on-path point midway between them.
215+ std::list<FlaggedPoint> points;
195216
196- /* Move to the first point on the contour. */
197- stack (stream, 3 );
198- PSMoveto (stream,xcoor[j],ycoor[j]);
199-
200- start_offpt = 0 ; /* No off curve points yet. */
201-
202- /* Step thru the remaining points of this contour. */
203- for (j++; j <= epts_ctr[k]; j++)
217+ // Represent flags and x/y coordinates as a C++ list
218+ for (; j <= epts_ctr[k]; j++)
204219 {
205- if (!(tt_flags[j]&1 )) /* Off curve */
206- {
207- if (!start_offpt)
208- {
209- start_offpt = end_offpt = j;
210- }
211- else
212- {
213- end_offpt++;
214- }
220+ if (!(tt_flags[j] & 1 )) {
221+ points.push_back (FlaggedPoint (OFF_PATH, xcoor[j], ycoor[j]));
222+ } else {
223+ points.push_back (FlaggedPoint (ON_PATH, xcoor[j], ycoor[j]));
215224 }
216- else
225+ }
226+
227+ // For any two consecutive off-path points, insert the implied
228+ // on-path point.
229+ FlaggedPoint prev = points.back ();
230+ for (std::list<FlaggedPoint>::iterator it = points.begin ();
231+ it != points.end ();
232+ it++)
233+ {
234+ if (prev.flag == OFF_PATH && it->flag == OFF_PATH)
217235 {
218- /* On Curve */
219- if (start_offpt)
220- {
221- stack (stream, 7 );
222- PSCurveto (stream, xcoor[j],ycoor[j],start_offpt,end_offpt);
223- start_offpt = 0 ;
224- }
225- else
226- {
227- stack (stream, 3 );
228- PSLineto (stream, xcoor[j], ycoor[j]);
229- }
236+ points.insert (it,
237+ FlaggedPoint (ON_PATH,
238+ (prev.x + it->x ) / 2 ,
239+ (prev.y + it->y ) / 2 ));
230240 }
241+ prev = *it;
231242 }
232-
233- /* Do the final curve or line */
234- /* of this coutour. */
235- if (start_offpt )
243+ // Handle the wrap-around: insert a point either at the beginning
244+ // or at the end that has the same coordinates as the opposite point.
245+ // This also ensures that the initial point is ON_PATH.
246+ if (points. front (). flag == OFF_PATH )
236247 {
237- stack (stream, 7 );
238- PSCurveto (stream, xcoor[fst],ycoor[fst],start_offpt,end_offpt );
248+ assert (points. back (). flag == ON_PATH );
249+ points. insert (points. begin (), points. back () );
239250 }
240251 else
241252 {
242- stack (stream, 3 );
243- PSLineto (stream, xcoor[fst],ycoor[fst]);
253+ assert (points.front ().flag == ON_PATH);
254+ points.push_back (points.front ());
255+ }
256+
257+ // For output, a vector is more convenient than a list.
258+ std::vector<FlaggedPoint> points_v (points.begin (), points.end ());
259+ // The first point
260+ stack (stream, 3 );
261+ PSMoveto (stream, points_v.front ().x , points_v.front ().y );
262+
263+ // Step through the remaining points
264+ for (size_t p = 1 ; p < points_v.size (); )
265+ {
266+ const FlaggedPoint& point = points_v.at (p);
267+ if (point.flag == ON_PATH)
268+ {
269+ stack (stream, 3 );
270+ PSLineto (stream, point.x , point.y );
271+ p++;
272+ } else {
273+ assert (points_v.at (p-1 ).flag == ON_PATH);
274+ assert (points_v.at (p+1 ).flag == ON_PATH);
275+ stack (stream, 7 );
276+ PSCurveto (stream,
277+ points_v.at (p-1 ).x , points_v.at (p-1 ).y ,
278+ point.x , point.y ,
279+ points_v.at (p+1 ).x , points_v.at (p+1 ).y );
280+ p += 2 ;
281+ }
244282 }
245283
246284 k=nextinctr (i,k);
@@ -392,36 +430,34 @@ void GlyphToType3::PSLineto(TTStreamWriter& stream, int x, int y)
392430}
393431
394432/*
395- ** Emmit a PostScript "curveto" command.
433+ ** Emit a PostScript "curveto" command, assuming the current point
434+ ** is (x0, y0), the control point of a quadratic spline is (x1, y1),
435+ ** and the endpoint is (x2, y2). Note that this requires a conversion,
436+ ** since PostScript splines are cubic.
396437*/
397- void GlyphToType3::PSCurveto (TTStreamWriter& stream, FWord x, FWord y, int s, int t)
438+ void GlyphToType3::PSCurveto (TTStreamWriter& stream,
439+ FWord x0, FWord y0,
440+ FWord x1, FWord y1,
441+ FWord x2, FWord y2)
398442{
399- int N, i;
400- double sx[3 ], sy[3 ], cx[4 ], cy[4 ];
401-
402- N = t-s+2 ;
403- for (i=0 ; i<N-1 ; i++)
404- {
405- sx[0 ] = i==0 ?xcoor[s-1 ]:(xcoor[i+s]+xcoor[i+s-1 ])/2 ;
406- sy[0 ] = i==0 ?ycoor[s-1 ]:(ycoor[i+s]+ycoor[i+s-1 ])/2 ;
407- sx[1 ] = xcoor[s+i];
408- sy[1 ] = ycoor[s+i];
409- sx[2 ] = i==N-2 ?x:(xcoor[s+i]+xcoor[s+i+1 ])/2 ;
410- sy[2 ] = i==N-2 ?y:(ycoor[s+i]+ycoor[s+i+1 ])/2 ;
411- cx[3 ] = sx[2 ];
412- cy[3 ] = sy[2 ];
413- cx[1 ] = (2 *sx[1 ]+sx[0 ])/3 ;
414- cy[1 ] = (2 *sy[1 ]+sy[0 ])/3 ;
415- cx[2 ] = (sx[2 ]+2 *sx[1 ])/3 ;
416- cy[2 ] = (sy[2 ]+2 *sy[1 ])/3 ;
417-
418- stream.printf (pdf_mode ?
419- " %d %d %d %d %d %d c\n " :
420- " %d %d %d %d %d %d _c\n " ,
421- (int )cx[1 ], (int )cy[1 ], (int )cx[2 ], (int )cy[2 ],
422- (int )cx[3 ], (int )cy[3 ]);
423- }
424- } /* end of PSCurveto() */
443+ double sx[3 ], sy[3 ], cx[3 ], cy[3 ];
444+
445+ sx[0 ] = x0;
446+ sy[0 ] = y0;
447+ sx[1 ] = x1;
448+ sy[1 ] = y1;
449+ sx[2 ] = x2;
450+ sy[2 ] = y2;
451+ cx[0 ] = (2 *sx[1 ]+sx[0 ])/3 ;
452+ cy[0 ] = (2 *sy[1 ]+sy[0 ])/3 ;
453+ cx[1 ] = (sx[2 ]+2 *sx[1 ])/3 ;
454+ cy[1 ] = (sy[2 ]+2 *sy[1 ])/3 ;
455+ cx[2 ] = sx[2 ];
456+ cy[2 ] = sy[2 ];
457+ stream.printf (" %d %d %d %d %d %d %s\n " ,
458+ (int )cx[0 ], (int )cy[0 ], (int )cx[1 ], (int )cy[1 ],
459+ (int )cx[2 ], (int )cy[2 ], pdf_mode ? " c" : " _c" );
460+ }
425461
426462/*
427463** Deallocate the structures which stored
0 commit comments