41
41
#include " truetype.h"
42
42
#include < algorithm>
43
43
#include < stack>
44
+ #include < list>
44
45
45
46
class GlyphToType3
46
47
{
@@ -73,7 +74,10 @@ class GlyphToType3
73
74
int nextoutctr (int co);
74
75
int nearout (int ci);
75
76
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);
77
81
void PSMoveto (TTStreamWriter& stream, int x, int y);
78
82
void PSLineto (TTStreamWriter& stream, int x, int y);
79
83
void do_composite (TTStreamWriter& stream, struct TTFONT *font, BYTE *glyph);
@@ -83,6 +87,18 @@ class GlyphToType3
83
87
~GlyphToType3 ();
84
88
};
85
89
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
+
86
102
double area (FWord *x, FWord *y, int n);
87
103
#define sqr (x ) ((x)*(x))
88
104
@@ -150,8 +166,7 @@ double area(FWord *x, FWord *y, int n)
150
166
*/
151
167
void GlyphToType3::PSConvert (TTStreamWriter& stream)
152
168
{
153
- int i,j,k,fst,start_offpt;
154
- int end_offpt = 0 ;
169
+ int i,j,k;
155
170
156
171
assert (area_ctr == NULL );
157
172
area_ctr=(double *)calloc (num_ctr, sizeof (double ));
@@ -191,56 +206,79 @@ void GlyphToType3::PSConvert(TTStreamWriter& stream)
191
206
i=j=k=0 ;
192
207
while ( i < num_ctr )
193
208
{
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;
195
216
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++)
204
219
{
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]));
215
224
}
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)
217
235
{
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 ));
230
240
}
241
+ prev = *it;
231
242
}
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 )
236
247
{
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 () );
239
250
}
240
251
else
241
252
{
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
+ }
244
282
}
245
283
246
284
k=nextinctr (i,k);
@@ -392,36 +430,34 @@ void GlyphToType3::PSLineto(TTStreamWriter& stream, int x, int y)
392
430
}
393
431
394
432
/*
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.
396
437
*/
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)
398
442
{
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
+ }
425
461
426
462
/*
427
463
** Deallocate the structures which stored
0 commit comments