1 /*
2  * TransFig: Facility for Translating Fig code
3  * Copyright (c) 1999 by Philippe Bekaert
4  * Parts Copyright (c) 1989-2002 by Brian V. Smith
5  *
6  * Any party obtaining a copy of these files is granted, free of charge, a
7  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
8  * nonexclusive right and license to deal in this software and
9  * documentation files (the "Software"), including without limitation the
10  * rights to use, copy, modify, merge, publish and/or distribute copies of
11  * the Software, and to permit persons who receive copies from any such
12  * party to do so, with the only requirement being that this copyright
13  * notice remain intact.
14  *
15  */
16 
17 /*
18  * genemf.c -- convert fig to Enhanced MetaFile
19  *
20  * Written by Michael Schrick (2001-03-04)
21  *
22  * Revision History:
23  *
24  *   2004/02/10 - Added support for locale text (if iconv() is available),
25  *		  arc box, open arc, rotated ellipse, picture,
26  *		  dash-triple-dotted line style, and all fill patterns.
27  *		  (ITOH Yasufumi)
28  *
29  *   2003/01/14 - Added text orientation, text alignment.  Corrected color
30  *		  table and added text color.  Added transparency, fill
31  *		  colors and patterns. (M. Schrick)
32  *
33  *   2001/10/03 - Added htof functions for big endian machines (M. Schrick)
34  *
35  *   2001/09/24 - Added filled polygons, circles and ellipses (M. Schrick)
36  *
37  *   2001/03/04 - Created from gencgm.c (M. Schrick)
38  *
39  * Limitations:
40  *
41  * - old style splines are not supported by this driver. New style
42  *   (X) splines are automatically converted to polylines and thus
43  *   are supported.
44  *
45  * - Windows 95 supports linestyles only for the thin line.  Lines with
46  *   styles will converted to the thin width.  Dash-triple-dotted linestyle
47  *   is not supported.
48  *   Windows 98/Me don't seem to support linestyles well.
49  *
50  * - Windows 95/98/Me supports only 12 patterns out of FIG's 22 fill pattern.
51  *   Unsupported patterns will be shown differently.
52  *
53  * - Windows 95/98/Me doesn't support line cap and join styles. The correct
54  *   appearance of arrows depends on the cap style the viewer uses (not
55  *   known at conversion time, but can be set using the -r driver option).
56  *
57  * - an EMF file may look quite different when viewed with different
58  *   EMF capable drawing programs. This is especially so for text:
59  *   the text font e.g. needs to be recognized and supported by the
60  *   viewer.  Same is True for special characters in text strings, etc.
61  *
62  */
63 
64 #include <stdio.h>
65 #include <stdlib.h>
66 #if defined(I18N) && defined(USE_ICONV)
67 #include <iconv.h>
68 #endif
69 #include "fig2dev.h"
70 #include "object.h"
71 #include "genemf.h"
72 
73 #define UNDEFVALUE	-100	/* UNDEFined attribute value */
74 #define EPSILON		1e-4	/* small floating point value */
75 
76 typedef enum {EMH_RECORD, EMH_DATA} emh_flag;
77 static ENHMETAHEADER emh;	/* The Enhanced MetaFile header, which is the
78 				 * first record in the file must be updated
79 				 * to reflect the total number of records and
80 				 * the total number of bytes.  This record
81 				 * contains little endian data and should not
82 				 * be used internally without a conversion. */
83 /* Internal variables in host format */
84 static unsigned emh_nBytes;	/* Size of the metafile in bytes */
85 static unsigned emh_nRecords;	/* Number of records in the metafile */
86 static unsigned emh_nHandles;	/* Number of handles in the handle table */
87 
88 /*
89  * Limit maximum number of handles.
90  * XXX limit to which number?
91  */
92 static unsigned maxHandles = 50;
93 
94 /* Data types for keeping track of the device context handles */
95 enum emfhandletype { EMFH_PEN, EMFH_BRUSH, EMFH_FONT, EMFH_MAX } type;
96 
97 static unsigned lasthandle[EMFH_MAX];	/* Last device handle */
98 
99 struct emfhandle {
100     struct emfhandle *next;	/* This field must be first */
101     struct emfhandle **prev;
102     enum emfhandletype type;
103     Boolean	is_current;	/* True: currently selected */
104     unsigned	handle;
105     union {
106 	struct pen {
107 	    int pstyle, pwidth, prgb;
108 	} p;
109 	struct brush {
110 	    int bstyle;
111 	    int brgb, bpattern, bhatchbkrgb;
112 	} b;
113 	struct font {
114 	    int ffont;
115 	    int fsize;
116 	    int fangle;
117 	} f;
118     } eh_un;
119 };
120 
121 static struct emfhandle *handles;
122 static struct emfhandle *latesthandle;
123 
124 
125 static int rounded_arrows;	/* If rounded_arrows is False, the position
126 				 * of arrows will be corrected for
127 				 * compensating line width effects. This
128 				 * correction is not needed if arrows appear
129 				 * rounded with the used EMF viewer.
130 				 * See -r driver command line option. */
131 
132 /* EMF compatibility level */
133 static enum emfcompatlevel {
134     EMF_LEVEL_WIN95,	/* Windows 95 */
135     EMF_LEVEL_WIN98,	/* Windows 98/Me */
136     EMF_LEVEL_WINNT	/* Windows NT/2000/XP (Windows NT 3.1 and later) */
137 } emflevel = EMF_LEVEL_WINNT;
138 const char *const emflevelname[] = { "win95", "win98", "winnt" };
139 
140 typedef struct Dir {double x, y;} Dir;
141 #define ARROW_INDENT_DIST	0.8
142 #define ARROW_POINT_DIST	1.2
143 /* Arrows appear this much longer with projected line caps. */
144 #define ARROW_EXTRA_LEN(a)	((double)a->ht / (double)a->wid * a->thickness)
145 
146 /* update bounding box */
147 #define UPDATE_BBX_X(x) \
148     do { \
149 	if (bbx_left>(x)) bbx_left=(x); else if (bbx_right<(x)) bbx_right=(x);\
150     } while (0)
151 #define UPDATE_BBX_Y(y) \
152     do { \
153 	if (bbx_top>(y)) bbx_top=(y); else if (bbx_bottom<(y)) bbx_bottom=(y);\
154     } while (0)
155 
156 
157 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
158 
159 /*
160  * fill pattern bitmaps
161  */
162 
163 /* pat0.xbm */
164 #define pat0_width 8
165 #define pat0_height 4
166 static unsigned char pat0_bits[] = {
167    0x03, 0x0c, 0x30, 0xc0};
168 
169 /* pat1.xbm */
170 #define pat1_width 8
171 #define pat1_height 4
172 static unsigned char pat1_bits[] = {
173    0xc0, 0x30, 0x0c, 0x03};
174 
175 /* pat2.xbm */
176 #define pat2_width 8
177 #define pat2_height 4
178 static unsigned char pat2_bits[] = {
179    0x81, 0x66, 0x18, 0x66};
180 
181 #if 0	/* mapped to EMF pattern */
182 /* pat3.xbm */
183 #define pat3_width 8
184 #define pat3_height 8
185 static unsigned char pat3_bits[] = {
186    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
187 
188 /* pat4.xbm */
189 #define pat4_width 8
190 #define pat4_height 8
191 static unsigned char pat4_bits[] = {
192    0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
193 
194 /* pat5.xbm */
195 #define pat5_width 8
196 #define pat5_height 8
197 static unsigned char pat5_bits[] = {
198    0x11, 0x0a, 0x04, 0x0a, 0x11, 0xa0, 0x40, 0xa0};
199 #endif
200 
201 /* pat6.xbm */
202 #define pat6_width 16
203 #define pat6_height 16
204 static unsigned char pat6_bits[] = {
205    0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
206    0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
207    0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff};
208 
209 /* pat7.xbm */
210 #define pat7_width 16
211 #define pat7_height 16
212 static unsigned char pat7_bits[] = {
213    0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
214    0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
215    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
216 
217 #if 0	/* mapped to EMF pattern */
218 /* pat8.xbm */
219 #define pat8_width 8
220 #define pat8_height 4
221 static unsigned char pat8_bits[] = {
222    0xff, 0x00, 0x00, 0x00};
223 
224 /* pat9.xbm */
225 #define pat9_width 8
226 #define pat9_height 4
227 static unsigned char pat9_bits[] = {
228    0x88, 0x88, 0x88, 0x88};
229 
230 /* pat10.xbm */
231 #define pat10_width 8
232 #define pat10_height 4
233 static unsigned char pat10_bits[] = {
234    0xff, 0x88, 0x88, 0x88};
235 #endif
236 
237 /* pat11.xbm */
238 #define pat11_width 24
239 #define pat11_height 24
240 static unsigned char pat11_bits[] = {
241    0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
242    0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff,
243    0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00,
244    0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff,
245    0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
246    0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff};
247 
248 /* pat12.xbm */
249 #define pat12_width 24
250 #define pat12_height 24
251 static unsigned char pat12_bits[] = {
252    0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20,
253    0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
254    0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00,
255    0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff,
256    0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
257    0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff};
258 
259 /* pat13.xbm */
260 #define pat13_width 24
261 #define pat13_height 24
262 static unsigned char pat13_bits[] = {
263    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
264    0x80, 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0,
265    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
266    0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80,
267    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
268    0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80, 0x80};
269 
270 /* pat14.xbm */
271 #define pat14_width 24
272 #define pat14_height 24
273 static unsigned char pat14_bits[] = {
274    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
275    0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80,
276    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
277    0x80, 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83,
278    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
279    0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80, 0x80};
280 
281 /* pat15.xbm */
282 #define pat15_width 16
283 #define pat15_height 8
284 static unsigned char pat15_bits[] = {
285    0x40, 0x02, 0x30, 0x0c, 0x0e, 0x70, 0x01, 0x80, 0x02, 0x40, 0x0c, 0x30,
286    0x70, 0x0e, 0x80, 0x01};
287 
288 /* pat16.xbm */
289 #define pat16_width 8
290 #define pat16_height 8
291 static unsigned char pat16_bits[] = {
292    0x01, 0x01, 0x82, 0x6c, 0x10, 0x10, 0x28, 0xc6};
293 
294 /* pat17.xbm */
295 #define pat17_width 16
296 #define pat17_height 16
297 static unsigned char pat17_bits[] = {
298    0xe0, 0x0f, 0x18, 0x30, 0x04, 0x40, 0x02, 0x80, 0x02, 0x80, 0x01, 0x00,
299    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
300    0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0x18, 0x30};
301 
302 /* pat18.xbm */
303 #define pat18_width 30
304 #define pat18_height 18
305 static unsigned char pat18_bits[] = {
306    0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,
307    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
308    0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x3f,
309    0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
310    0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
311    0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00};
312 
313 /* pat19.xbm */
314 #define pat19_width 16
315 #define pat19_height 16
316 static unsigned char pat19_bits[] = {
317    0xe0, 0x0f, 0x10, 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00,
318    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
319    0x02, 0x80, 0x04, 0x40, 0x08, 0x20, 0x10, 0x10};
320 
321 /* pat20.xbm */
322 #define pat20_width 8
323 #define pat20_height 8
324 static unsigned char pat20_bits[] = {
325    0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x80};
326 
327 /* pat21.xbm */
328 #define pat21_width 8
329 #define pat21_height 8
330 static unsigned char pat21_bits[] = {
331    0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x01};
332 
333 const struct emf_bmpat {
334     unsigned width, height;
335     unsigned char *bits;
336 } emf_bm_pattern[22] = {
337     { pat0_width, pat0_height, pat0_bits },
338     { pat1_width, pat1_height, pat1_bits },
339     { pat2_width, pat2_height, pat2_bits },
340     { 0, 0, 0 },	/* mapped to EMF pattern */
341     { 0, 0, 0 },	/* mapped to EMF pattern */
342     { 0, 0, 0 },	/* mapped to EMF pattern */
343     { pat6_width, pat6_height, pat6_bits },
344     { pat7_width, pat7_height, pat7_bits },
345     { 0, 0, 0 },	/* mapped to EMF pattern */
346     { 0, 0, 0 },	/* mapped to EMF pattern */
347     { 0, 0, 0 },	/* mapped to EMF pattern */
348     { pat11_width, pat11_height, pat11_bits },
349     { pat12_width, pat12_height, pat12_bits },
350     { pat13_width, pat13_height, pat13_bits },
351     { pat14_width, pat14_height, pat14_bits },
352     { pat15_width, pat15_height, pat15_bits },
353     { pat16_width, pat16_height, pat16_bits },
354     { pat17_width, pat17_height, pat17_bits },
355     { pat18_width, pat18_height, pat18_bits },
356     { pat19_width, pat19_height, pat19_bits },
357     { pat20_width, pat20_height, pat20_bits },
358     { pat21_width, pat21_height, pat21_bits }
359 };
360 
361 /* EMF patterns are numbered 0-5 (I use -1 for bitmap patterns) */
362 int emf_map_pattern[22] = { -1, -1, -1, HS_FDIAGONAL,
363 			 HS_BDIAGONAL, HS_DIAGCROSS, -1, -1,
364 			 HS_HORIZONTAL, HS_VERTICAL, HS_CROSS, -1,
365 			 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
366 
367 
368 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
369 
370 static int ltFonts[] = {	/* Convert from LaTeX fonts to PostScript */
371 		0,		/* default */
372 		0,		/* Roman */
373 		2,		/* Bold */
374 		1,		/* Italic */
375 		4,		/* Modern */
376 		12,		/* Typewriter */
377 		};
378 
379 static char *lfFaceName[] = {
380 		"Times",		/* Times-Roman */
381 		"Times",		/* Times-Italic */
382 		"Times",		/* Times-Bold */
383 		"Times",		/* Times-BoldItalic */
384 		"AvantGarde",		/* AvantGarde */
385 		"AvantGarde",		/* AvantGarde-BookOblique */
386 		"AvantGarde",		/* AvantGarde-Demi */
387 		"AvantGarde",		/* AvantGarde-DemiOblique */
388 		"Bookman",		/* Bookman-Light */
389 		"Bookman",		/* Bookman-LightItalic */
390 		"Bookman",		/* Bookman-Demi */
391 		"Bookman",		/* Bookman-DemiItalic */
392 		"Courier",		/* Courier */
393 		"Courier",		/* Courier-Oblique */
394 		"Courier",		/* Courier-Bold */
395 		"Courier",		/* Courier-BoldItalic */
396 		"Helvetica",		/* Helvetica */
397 		"Helvetica",		/* Helvetica-Oblique */
398 		"Helvetica",		/* Helvetica-Bold */
399 		"Helvetica",		/* Helvetica-BoldOblique */
400 		"Helvetica-Narrow",	/* Helvetica-Narrow */
401 		"Helvetica-Narrow",	/* Helvetica-Narrow-Oblique */
402 		"Helvetica-Narrow",	/* Helvetica-Narrow-Bold */
403 		"Helvetica-Narrow",	/* Helvetica-Narrow-BoldOblique */
404 		"NewCenturySchlbk",	/* NewCenturySchlbk-Roman */
405 		"NewCenturySchlbk",	/* NewCenturySchlbk-Italic */
406 		"NewCenturySchlbk",	/* NewCenturySchlbk-Bold */
407 		"NewCenturySchlbk",	/* NewCenturySchlbk-BoldItalic */
408 		"Palatino",		/* Palatino-Roman */
409 		"Palatino",		/* Palatino-Italic */
410 		"Palatino",		/* Palatino-Bold */
411 		"Palatino",		/* Palatino-BoldItalic */
412 		"Symbol",		/* Symbol */
413 		"ZapfChancery",		/* ZapfChancery-MediumItalic */
414 		"ZapfDingbats"		/* ZapfDingbats */
415 		};
416 
417 static int	lfWeight[] = {
418 		FW_NORMAL,		/* Times-Roman */
419 		FW_NORMAL,		/* Times-Italic */
420 		FW_BOLD,		/* Times-Bold */
421 		FW_BOLD,		/* Times-BoldItalic */
422 		FW_NORMAL,		/* AvantGarde */
423 		FW_NORMAL,		/* AvantGarde-BookOblique */
424 		FW_DEMIBOLD,		/* AvantGarde-Demi */
425 		FW_DEMIBOLD,		/* AvantGarde-DemiOblique */
426 		FW_LIGHT,		/* Bookman-Light */
427 		FW_LIGHT,		/* Bookman-LightItalic */
428 		FW_DEMIBOLD,		/* Bookman-Demi */
429 		FW_DEMIBOLD,		/* Bookman-DemiItalic */
430 		FW_NORMAL,		/* Courier */
431 		FW_NORMAL,		/* Courier-Oblique */
432 		FW_BOLD,		/* Courier-Bold */
433 		FW_BOLD,		/* Courier-BoldItalic */
434 		FW_NORMAL,		/* Helvetica */
435 		FW_NORMAL,		/* Helvetica-Oblique */
436 		FW_BOLD,		/* Helvetica-Bold */
437 		FW_BOLD,		/* Helvetica-BoldOblique */
438 		FW_NORMAL,		/* Helvetica-Narrow */
439 		FW_NORMAL,		/* Helvetica-Narrow-Oblique */
440 		FW_BOLD,		/* Helvetica-Narrow-Bold */
441 		FW_BOLD,		/* Helvetica-Narrow-BoldOblique */
442 		FW_NORMAL,		/* NewCenturySchlbk-Roman */
443 		FW_NORMAL,		/* NewCenturySchlbk-Italic */
444 		FW_BOLD,		/* NewCenturySchlbk-Bold */
445 		FW_BOLD,		/* NewCenturySchlbk-BoldItalic */
446 		FW_NORMAL,		/* Palatino-Roman */
447 		FW_NORMAL,		/* Palatino-Italic */
448 		FW_BOLD,		/* Palatino-Bold */
449 		FW_BOLD,		/* Palatino-BoldItalic */
450 		FW_NORMAL,		/* Symbol */
451 		FW_NORMAL,		/* ZapfChancery-MediumItalic */
452 		FW_NORMAL		/* ZapfDingbats */
453 		};
454 
455 static uchar	lfItalic[] = {
456 		False,			/* Times-Roman */
457 		True,			/* Times-Italic */
458 		False,			/* Times-Bold */
459 		True,			/* Times-BoldItalic */
460 		False,			/* AvantGarde */
461 		True,			/* AvantGarde-BookOblique */
462 		False,			/* AvantGarde-Demi */
463 		True,			/* AvantGarde-DemiOblique */
464 		False,			/* Bookman-Light */
465 		True,			/* Bookman-LightItalic */
466 		False,			/* Bookman-Demi */
467 		True,			/* Bookman-DemiItalic */
468 		False,			/* Courier */
469 		True,			/* Courier-Oblique */
470 		False,			/* Courier-Bold */
471 		True,			/* Courier-BoldItalic */
472 		False,			/* Helvetica */
473 		True,			/* Helvetica-Oblique */
474 		False,			/* Helvetica-Bold */
475 		True,			/* Helvetica-BoldOblique */
476 		False,			/* Helvetica-Narrow */
477 		True,			/* Helvetica-Narrow-Oblique */
478 		False,			/* Helvetica-Narrow-Bold */
479 		True,			/* Helvetica-Narrow-BoldOblique */
480 		False,			/* NewCenturySchlbk-Roman */
481 		True,			/* NewCenturySchlbk-Italic */
482 		False,			/* NewCenturySchlbk-Bold */
483 		True,			/* NewCenturySchlbk-BoldItalic */
484 		False,			/* Palatino-Roman */
485 		True,			/* Palatino-Italic */
486 		False,			/* Palatino-Bold */
487 		True,			/* Palatino-BoldItalic */
488 		False,			/* Symbol */
489 		False,			/* ZapfChancery-MediumItalic */
490 		False			/* ZapfDingbats */
491 		};
492 
493 static uchar	lfCharSet[] = {
494 		ANSI_CHARSET,		/* Times-Roman */
495 		ANSI_CHARSET,		/* Times-Italic */
496 		ANSI_CHARSET,		/* Times-Bold */
497 		ANSI_CHARSET,		/* Times-BoldItalic */
498 		ANSI_CHARSET,		/* AvantGarde */
499 		ANSI_CHARSET,		/* AvantGarde-BookOblique */
500 		ANSI_CHARSET,		/* AvantGarde-Demi */
501 		ANSI_CHARSET,		/* AvantGarde-DemiOblique */
502 		ANSI_CHARSET,		/* Bookman-Light */
503 		ANSI_CHARSET,		/* Bookman-LightItalic */
504 		ANSI_CHARSET,		/* Bookman-Demi */
505 		ANSI_CHARSET,		/* Bookman-DemiItalic */
506 		ANSI_CHARSET,		/* Courier */
507 		ANSI_CHARSET,		/* Courier-Oblique */
508 		ANSI_CHARSET,		/* Courier-Bold */
509 		ANSI_CHARSET,		/* Courier-BoldItalic */
510 		ANSI_CHARSET,		/* Helvetica */
511 		ANSI_CHARSET,		/* Helvetica-Oblique */
512 		ANSI_CHARSET,		/* Helvetica-Bold */
513 		ANSI_CHARSET,		/* Helvetica-BoldOblique */
514 		ANSI_CHARSET,		/* Helvetica-Narrow */
515 		ANSI_CHARSET,		/* Helvetica-Narrow-Oblique */
516 		ANSI_CHARSET,		/* Helvetica-Narrow-Bold */
517 		ANSI_CHARSET,		/* Helvetica-Narrow-BoldOblique */
518 		ANSI_CHARSET,		/* NewCenturySchlbk-Roman */
519 		ANSI_CHARSET,		/* NewCenturySchlbk-Italic */
520 		ANSI_CHARSET,		/* NewCenturySchlbk-Bold */
521 		ANSI_CHARSET,		/* NewCenturySchlbk-BoldItalic */
522 		ANSI_CHARSET,		/* Palatino-Roman */
523 		ANSI_CHARSET,		/* Palatino-Italic */
524 		ANSI_CHARSET,		/* Palatino-Bold */
525 		ANSI_CHARSET,		/* Palatino-BoldItalic */
526 		SYMBOL_CHARSET,		/* Symbol */
527 		SYMBOL_CHARSET,		/* ZapfChancery-MediumItalic */
528 		SYMBOL_CHARSET		/* ZapfDingbats */
529 		};
530 
531 static uchar	lfPitchAndFamily[] = {
532 	VARIABLE_PITCH | FF_ROMAN,	/* Times-Roman */
533 	VARIABLE_PITCH | FF_ROMAN,	/* Times-Italic */
534 	VARIABLE_PITCH | FF_ROMAN,	/* Times-Bold */
535 	VARIABLE_PITCH | FF_ROMAN,	/* Times-BoldItalic */
536 	VARIABLE_PITCH | FF_ROMAN,	/* AvantGarde */
537 	VARIABLE_PITCH | FF_ROMAN,	/* AvantGarde-BookOblique */
538 	VARIABLE_PITCH | FF_ROMAN,	/* AvantGarde-Demi */
539 	VARIABLE_PITCH | FF_ROMAN,	/* AvantGarde-DemiOblique */
540 	VARIABLE_PITCH | FF_ROMAN,	/* Bookman-Light */
541 	VARIABLE_PITCH | FF_ROMAN,	/* Bookman-LightItalic */
542 	VARIABLE_PITCH | FF_ROMAN,	/* Bookman-Demi */
543 	VARIABLE_PITCH | FF_ROMAN,	/* Bookman-DemiItalic */
544 	   FIXED_PITCH | FF_MODERN,	/* Courier */
545 	   FIXED_PITCH | FF_MODERN,	/* Courier-Oblique */
546 	   FIXED_PITCH | FF_MODERN,	/* Courier-Bold */
547 	   FIXED_PITCH | FF_MODERN,	/* Courier-BoldItalic */
548 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica */
549 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Oblique */
550 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Bold */
551 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-BoldOblique */
552 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Narrow */
553 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Narrow-Oblique */
554 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Narrow-Bold */
555 	VARIABLE_PITCH | FF_ROMAN,	/* Helvetica-Narrow-BoldOblique */
556 	VARIABLE_PITCH | FF_ROMAN,	/* NewCenturySchlbk-Roman */
557 	VARIABLE_PITCH | FF_ROMAN,	/* NewCenturySchlbk-Italic */
558 	VARIABLE_PITCH | FF_ROMAN,	/* NewCenturySchlbk-Bold */
559 	VARIABLE_PITCH | FF_ROMAN,	/* NewCenturySchlbk-BoldItalic */
560 	VARIABLE_PITCH | FF_ROMAN,	/* Palatino-Roman */
561 	VARIABLE_PITCH | FF_ROMAN,	/* Palatino-Italic */
562 	VARIABLE_PITCH | FF_ROMAN,	/* Palatino-Bold */
563 	VARIABLE_PITCH | FF_ROMAN,	/* Palatino-BoldItalic */
564 	VARIABLE_PITCH | FF_ROMAN,	/* Symbol */
565 	VARIABLE_PITCH | FF_ROMAN,	/* ZapfChancery-MediumItalic */
566 	VARIABLE_PITCH | FF_ROMAN,	/* ZapfDingbats */
567 		};
568 
569 #if defined(I18N) && defined(USE_ICONV)
570 extern Boolean support_i18n;  /* enable i18n support? */
571 
572 #define FONT_TIMES_ROMAN	0
573 #define FONT_TIMES_BOLD		2
574 #define IS_LOCALE_FONT(f) ((f) == FONT_TIMES_ROMAN || (f) == FONT_TIMES_BOLD)
575 
576 #define FONT_LOCALE_ROMAN	-1
577 #define FONT_LOCALE_BOLD	-2
578 
579 enum genemf_lang {
580     LANG_DEFAULT,
581     LANG_ZH_CN,
582     LANG_ZH_TW,
583     LANG_JA,
584     LANG_KO
585 } figLanguage;
586 
587 /* EUC codeset name for iconv(3) */
588 static const char *const iconvCharset[] = {
589     "ASCII",	/* placeholder */
590     "eucCN",
591     "eucTW",
592     "eucJP",
593     "eucKR"
594 };
595 
596 /* EMF codeset name for iconv(3) */
597 #ifdef __hpux
598 # define EMF_ICONV_CODESET	"ucs2"	/* convert to big endian Unicode */
599 # define EMF_ICONV_NEED_SWAP	1	/* and swap the byte order */
600 #else
601 # define EMF_ICONV_CODESET	"UTF-16LE"
602 #endif
603 
604 /* localized fonts */
605 static const struct localefnt {
606 	const char *FaceName;	/* font name in EUC of the language */
607 	int Weight;
608 	uchar Italic, Charset, PitchAndFamily;
609 } localeFonts[2][5] = { {
610     { "Times", FW_NORMAL, False, DEFAULT_CHARSET, FIXED_PITCH|FF_DONTCARE },
611     { "SimSun",
612       FW_NORMAL, False, GB2312_CHARSET, FIXED_PITCH|FF_DONTCARE },
613     { "MingLiU",
614       FW_NORMAL, False, CHINESEBIG5_CHARSET, FIXED_PITCH|FF_DONTCARE },
615     { "\243\315\243\323 \314\300\304\253",	/* MS Mincho */
616       FW_NORMAL, False, SHIFTJIS_CHARSET, FIXED_PITCH|FF_DONTCARE },
617     { "Batang",
618       FW_NORMAL, False, HANGUL_CHARSET, FIXED_PITCH|FF_DONTCARE }
619 }, {
620     { "Times", FW_BOLD, False, DEFAULT_CHARSET, FIXED_PITCH|FF_DONTCARE },
621     { "SimHei",
622       FW_MEDIUM, False, GB2312_CHARSET, FIXED_PITCH|FF_DONTCARE },
623     { "MingLiU",
624       FW_BOLD,   False, CHINESEBIG5_CHARSET, FIXED_PITCH|FF_DONTCARE },
625     { "\243\315\243\323 \245\264\245\267\245\303\245\257", /* MS Gothic */
626       FW_MEDIUM, False, SHIFTJIS_CHARSET, FIXED_PITCH|FF_DONTCARE },
627     { "Gungsuh",
628       FW_MEDIUM, False, HANGUL_CHARSET, FIXED_PITCH|FF_DONTCARE }
629 } };
630 #endif	/* defined(I18N) && defined(USE_ICONV) */
631 
632 
633 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
634 
635 
636 static void delete_handle();
637 static void clear_current_handle();
638 static void select_object();
639 static void use_handle();
640 static struct emfhandle *get_handle();
641 static int conv_color();
642 static int conv_fill_color();
643 static int conv_fontindex();
644 static int conv_capstyle();
645 static int conv_joinstyle();
646 static int conv_linetype();
647 static void edgeattr();
648 static void edgevis();
649 static void bkmode();
650 static void bkcolor();
651 static void create_brush_pattern();
652 static void fillstyle();
653 static void textfont();
654 static void warn_32bit_pos();
655 static void pos2point();
656 static double arrow_length();
657 static void arrow();
658 static void arc_arrow();
659 static void arc_arrow_adjust();
660 static double arc_radius();
661 static void translate();
662 static void rotate();
663 static void arc_rotate();
664 static void arcoutline();
665 static void arcinterior();
666 static void arc_reverse();
667 static void circle();
668 static void ellipse();
669 static void rotated_ellipse();
670 static int icprod();
671 static int cwarc();
672 static int direction();
673 static double distance();
674 static size_t emh_write();
675 static int is_flip();
676 static void encode_bitmap();
677 static void picbox();
678 static void polygon();
679 static int polyline_adjust();
680 static void polyline();
681 static void rect();
682 static void roundrect();
683 static void shape();
684 static void shape_interior();
685 static void textunicode();
686 static void text();
687 static void textcolr();
688 static void textalign();
689 #if defined(I18N) && defined(USE_ICONV)
690 static void moveto();
691 #endif
692 
693 extern FILE *open_picfile();
694 extern void close_picfile();
695 #ifdef USE_PNG
696 extern	int read_png();
697 #endif
698 
699 /* Piece of code to avoid unnecessary attribute changes */
700 #define chkcache(val, cachedval)	\
701     if (val == cachedval)		\
702 	return;				\
703     else				\
704 	cachedval = val;
705 
706 
707 /* Delete an object by handle structure. */
delete_handle(h)708 static void delete_handle(h)
709     struct emfhandle *h;
710 {
711     EMRSELECTOBJECT em_so;	/* EMRDELETEOBJECT */
712 
713     /* If this is selected, select a stock object before deleting it. */
714     if (h->is_current) {
715 	em_so.emr.iType = htofl(EMR_SELECTOBJECT);
716 	em_so.emr.nSize = htofl(sizeof(EMRSELECTOBJECT));
717 	switch (h->type) {
718 	case EMFH_PEN:
719 	    em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | BLACK_PEN);
720 	    lasthandle[EMFH_PEN] = ENHMETA_STOCK_OBJECT | BLACK_PEN;
721 	    break;
722 	case EMFH_BRUSH:
723 	    em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | WHITE_BRUSH);
724 	    lasthandle[EMFH_BRUSH] = ENHMETA_STOCK_OBJECT | WHITE_BRUSH;
725 	    break;
726 	case EMFH_FONT:
727 	    em_so.ihObject = htofl(ENHMETA_STOCK_OBJECT | SYSTEM_FONT);
728 	    lasthandle[EMFH_FONT] = ENHMETA_STOCK_OBJECT | SYSTEM_FONT;
729 	    break;
730 	default:
731 	    fprintf(stderr, "genemf: unknown handle type %d.\n", h->type);
732 	    exit(1);
733 	}
734 
735 # ifdef __EMF_DEBUG__
736 	fprintf(stderr, "SelectObject: %u\n", ftohl(em_so.ihObject));
737 # endif
738 
739 	emh_write(&em_so, sizeof(EMRSELECTOBJECT), (size_t) 1, EMH_RECORD);
740 	h->is_current = False;
741     }
742 
743     em_so.emr.iType = htofl(EMR_DELETEOBJECT);
744     em_so.emr.nSize = htofl(sizeof(EMRDELETEOBJECT));
745 
746     em_so.ihObject = htofl(h->handle);
747 
748 # ifdef __EMF_DEBUG__
749     fprintf(stderr, "DeleteObject: %u\n", ftohl(em_so.ihObject));
750 # endif
751 
752     emh_write(&em_so, sizeof(EMRDELETEOBJECT), (size_t) 1, EMH_RECORD);
753 }
754 
755 
756 /* Clear current mark from objects of the specified type. */
clear_current_handle(type)757 static void clear_current_handle(type)
758     enum emfhandletype type;
759 {
760     struct emfhandle *h;
761 
762     for (h = handles; h; h = h->next)
763 	if (h->is_current && h->type == type) {
764 	    h->is_current = False;
765 	    break;
766 	}
767 }
768 
769 
770 /* Select object by handle number. */
select_object(handle)771 static void select_object(handle)
772     unsigned handle;
773 {
774     EMRSELECTOBJECT em_so;
775 
776     em_so.emr.iType = htofl(EMR_SELECTOBJECT);
777     em_so.emr.nSize = htofl(sizeof(EMRSELECTOBJECT));
778     em_so.ihObject = htofl(handle);
779 
780 # ifdef __EMF_DEBUG__
781     fprintf(stderr, "SelectObject: %u\n", ftohl(em_so.ihObject));
782 # endif
783 
784     emh_write(&em_so, sizeof(EMRSELECTOBJECT), (size_t) 1, EMH_RECORD);
785 }
786 
787 
788 /* Add a handle structure to the newest position of handle list. */
use_handle(h)789 static void use_handle(h)
790     struct emfhandle *h;
791 {
792 
793     if (h != latesthandle) {
794 	if (h->prev) {
795 	    /* unlink from list */
796 	    if (h->next)
797 		h->next->prev = h->prev;
798 	    *h->prev = h->next;
799 	}
800 	if (handles == NULL) {
801 	    handles = h;
802 	    h->prev = &handles;
803 	} else
804 	    h->prev = &latesthandle->next;
805 	*h->prev = h;
806 	h->next = NULL;
807 	latesthandle = h;
808     }
809 }
810 
811 
812 /*
813  * Allocate handle structure.  If the number of currently allocated handle
814  * exceeds maximum limit, reuse the least recently used handle.
815  */
get_handle(type)816 static struct emfhandle *get_handle(type)
817     enum emfhandletype type;
818 {
819     struct emfhandle *h;
820 
821     if (emh_nHandles >= maxHandles) {
822 	/* reuse handle (LRU) */
823 	for (h = handles; h; h = h->next) {
824 	    if (!h->is_current) {
825 		/* use it */
826 		delete_handle(h);
827 		goto use;
828 	    }
829 	}
830 	/*
831 	 * All handles are currently in use.
832 	 * Although exceeds maxHandles, create new one
833 	 */
834 	/* FALLTHROUGH */
835     }
836 
837     /* allocate new handle */
838     if ((h = malloc(sizeof(struct emfhandle))) == NULL) {
839 	perror("fig2dev: malloc");
840 	exit(1);
841     }
842     emh_nHandles++;
843     h->handle = emh_nHandles;
844     h->prev = NULL;
845     h->next = NULL;
846     h->is_current = False;
847 use:
848     h->type = type;
849 
850     return h;
851 }
852 
853 
854 /* Given an index into either the standard color list or into the
855  * user defined color list, return the hex RGB value of the color. */
conv_color(colorIndex)856 static int conv_color(colorIndex)
857     int colorIndex;
858 {
859     int   rgb;
860     static const int rgbColors[NUM_STD_COLS] = {
861       /* Black     Blue      Green     Cyan      Red       Magenta */
862 	0x000000, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF,
863       /* Yellow    White     Blue4     Blue3     Blue2     LtBlue */
864 	0xFFFF00, 0xFFFFFF, 0x000090, 0x0000B0, 0x0000D0, 0x87CEFF,
865       /* Green4    Green3    Green2    Cyan4     Cyan3     Cyan2  */
866 	0x009000, 0x00B000, 0x00D000, 0x009090, 0x00B0B0, 0x00D0D0,
867       /* Red4      Red3      Red2      Magenta4  Magenta3  Magenta2 */
868 	0x900000, 0xB00000, 0xD00000, 0x900090, 0xB000B0, 0xD000D0,
869       /* Brown4    Brown3    Brown2    Pink4     Pink3     Pink2  */
870 	0x803000, 0xA04000, 0xC06000, 0xFF8080, 0xFFA0A0, 0xFFC0C0,
871       /* Pink      Gold   */
872 	0xFFE0E0, 0xFFD700
873     };
874 
875     if (colorIndex == DEFAULT)
876 	colorIndex = 0;
877 
878     if (colorIndex < NUM_STD_COLS)
879 	rgb = RGB(rgbColors[colorIndex] >> 16,
880 		  (rgbColors[colorIndex] >> 8) & 0xff,
881 		  rgbColors[colorIndex] & 0xff);
882     else
883 	rgb = RGB(user_colors[colorIndex-NUM_STD_COLS].r,
884 		  user_colors[colorIndex-NUM_STD_COLS].g,
885 		  user_colors[colorIndex-NUM_STD_COLS].b);
886     return rgb;
887 }/* end conv_color */
888 
889 
890 /* Converts fill pattern color.  The style contains the fill intensity.
891  * 0 - 20 - 40 is equivalent to -1.0 - 0.0 - +1.0. */
conv_fill_color(style,color)892 static int conv_fill_color(style, color)
893     int style;
894     int color;
895 {
896     int   rgb, b, g, r;
897     float f;
898 
899     rgb = conv_color(color);
900     b = GetBValue(rgb);
901     g = GetGValue(rgb);
902     r = GetRValue(rgb);
903 
904     if (style <= 0) {				/* Black */
905 
906 	b = 0;
907 	g = 0;
908 	r = 0;
909 
910     } else if (style < 20) {			/* Darkened */
911 
912 	f = (float)style / 20.0;
913 	b = round(b * f);
914 	g = round(g * f);
915 	r = round(r * f);
916 
917     } else if (style == 20) {			/* Normal */
918 
919 	/* : */
920 
921     } else if (style < 40) {			/* Lightened */
922 
923 	f = (float)(style - 20) / 20.0;
924 	b = round(b + f*(255-b));
925 	g = round(g + f*(255-g));
926 	r = round(r + f*(255-r));
927 
928     } else {/* if (style >= 40) */		/* White */
929 
930 	b = 0xFF;
931 	g = 0xFF;
932 	r = 0xFF;
933 
934     }/* end if (style >= 40) */
935 
936     return RGB(r, g, b);
937 }/* end conv_fill_color */
938 
939 
940 /* Converts Fig font index to index into font table in the pre-amble,
941  * taking into account the flags. */
conv_fontindex(font,flags)942 static int conv_fontindex(font, flags)
943     int font;
944     int flags;
945 {
946 
947     if (flags&4) {			/* PostScript fonts */
948 	if (font == (-1)) {
949 	    font = 0;			/* Default PostScript is Roman */
950 	} else if ((font < 0) || (font >= NUM_PS_FONTS)) {
951 	    fprintf(stderr, "Unsupported Fig PostScript font index %d.\n",
952 		    font);
953 	    font = 0;			/* Default font */
954 	}
955     } else {				/* LaTeX fonts */
956 	if ((font < 0) || (font > NUM_LATEX_FONTS)) {
957 	    fprintf(stderr, "Unsupported Fig LaTeX font index %d.\n", font);
958 	    font = 0;			/* Default font */
959 	}
960 	else
961 	    font = ltFonts[font];	/* Convert to PostScript fonts */
962     }
963     return font;
964 }/* end conv_fontindex */
965 
966 
967 /* Convert fig cap style to EMF line style. */
conv_capstyle(cap)968 static int conv_capstyle(cap)
969     int	cap;
970 {
971 
972     switch (cap) {
973     case 0:	/* Butt. */
974 	cap = PS_ENDCAP_FLAT;
975 	break;
976     case 1:	/* Round. */
977 	cap = PS_ENDCAP_ROUND;
978 	break;
979     case 2:	/* Projecting. */
980 	cap = PS_ENDCAP_SQUARE;
981 	break;
982     default:
983 	fprintf(stderr, "genemf: unknown cap style %d.\n", cap);
984 	cap = PS_ENDCAP_FLAT;
985 	break;
986     }
987     return cap;
988 }/* end conv_capstyle */
989 
990 
991 /* Convert fig join style to EMF join style. */
conv_joinstyle(join)992 static int conv_joinstyle(join)
993     int	join;
994 {
995 
996     switch (join) {
997     case 0:	/* Miter. */
998 	join = PS_JOIN_MITER;
999 	break;
1000     case 1:	/* Round. */
1001 	join = PS_JOIN_ROUND;
1002 	break;
1003     case 2:	/* Bevel. */
1004 	join = PS_JOIN_BEVEL;
1005 	break;
1006     default:
1007 	fprintf(stderr, "genemf: unknown join style %d.\n", join);
1008 	join = PS_JOIN_MITER;
1009 	break;
1010     }
1011     return join;
1012 }/* end conv_joinstyle */
1013 
1014 
1015 /* Convert fig line style to EMF line style.  EMF knows 5 styles with
1016  * fortunately correspond to the first 5 fig line styles.  The triple
1017  * dotted fig line style is handled as a solid line here. */
conv_linetype(type)1018 static int conv_linetype(type)
1019     int	type;
1020 {
1021 
1022     if (type < 0)
1023 	type = -1;
1024     else if (type > 4)
1025 	type %= 5;
1026     return type;
1027 }/* end conv_linetype */
1028 
1029 
1030 /* This procedure sets the pen line attributes and selects the pen into
1031  * the device context. */
edgeattr(vis,type,width,color,join,cap)1032 static void edgeattr(vis, type, width, color, join, cap)
1033     int vis;		/* visible */
1034     int type;		/* line type */
1035     int width, color;
1036     int join;		/* join style */
1037     int cap;		/* cap style */
1038 {
1039     unsigned handle;
1040     int rgb;
1041     EMREXTCREATEPEN em_pn;
1042     struct emfhandle *h = NULL;
1043     int style;
1044     unsigned styleEntry[8];	/* "- . . . " */
1045     int user_style = False;
1046 
1047     if (width == 0)
1048 	vis = 0;
1049 
1050     /* if a stock object is available, use it */
1051     if (vis == 0) {
1052 	handle = ENHMETA_STOCK_OBJECT | NULL_PEN;
1053 	goto selectpen;
1054     }
1055 
1056     rgb = conv_color(color);
1057     style = PS_GEOMETRIC;
1058 
1059     switch (emflevel) {
1060     case EMF_LEVEL_WIN98:
1061 	if (type >= 1 && type <= 4) {
1062 	    fprintf(stderr, "Warning: line style may be ignored\n");
1063 	}
1064 	break;
1065 
1066     case EMF_LEVEL_WIN95:
1067 	if (type >= 1 && type <= 4) {
1068 	    if (width < 20) {
1069 		fprintf(stderr, "Warning: this style of line is converted to thin line\n");
1070 		style = PS_COSMETIC;
1071 	    } else
1072 		fprintf(stderr, "Warning: line style may be ignored\n");
1073 	}
1074 	break;
1075 
1076     default:
1077 	break;
1078     }
1079 
1080     switch (emflevel) {
1081     case EMF_LEVEL_WINNT:
1082 	if (type == 5) {
1083 	    style |= PS_USERSTYLE;
1084 	    user_style = True;
1085 	} else
1086 	    style |= conv_linetype(type);
1087 	break;
1088 
1089     default:
1090 	if (type == 5) {
1091 	    fprintf(stderr, "Warning: dash-triple-dotted style is converted to solid style\n");
1092 	    type = 0;
1093 	}
1094 	style |= conv_linetype(type);
1095 	break;
1096     }
1097     style |= conv_capstyle(cap) | conv_joinstyle(join);
1098 
1099     /* search for the same pen */
1100     for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1101 	if (h->type == EMFH_PEN &&
1102 		h->eh_un.p.pstyle == style && h->eh_un.p.pwidth == width &&
1103 		h->eh_un.p.prgb == rgb) {
1104 	    /* found */
1105 	    use_handle(h);
1106 	    handle = h->handle;
1107 	    goto selectpen;
1108 	}
1109     }
1110 
1111     /* not found -- create new pen */
1112     h = get_handle(EMFH_PEN);
1113     handle = h->handle;
1114     use_handle(h);
1115 
1116     h->eh_un.p.pstyle = style;
1117     h->eh_un.p.pwidth = width;
1118     h->eh_un.p.prgb = rgb;
1119 
1120     memset(&em_pn, 0, sizeof(EMREXTCREATEPEN));
1121     em_pn.emr.iType = htofl(EMR_EXTCREATEPEN);
1122     em_pn.ihPen = htofl(handle);
1123     em_pn.offBmi  = htofl(sizeof(EMREXTCREATEPEN));
1124     em_pn.offBits = htofl(sizeof(EMREXTCREATEPEN));
1125     em_pn.elp.elpPenStyle = htofl(style);
1126     em_pn.elp.elpWidth = htofl(width);
1127     em_pn.elp.elpColor = htofl(rgb);
1128 
1129     if (user_style) {
1130 	/* create dash-triple-dotted style */
1131 	styleEntry[0] = htofl(width * 4);	/* dash */
1132 	styleEntry[1] =				/* gap */
1133 	styleEntry[2] =				/* dot */
1134 	styleEntry[3] =				/* gap */
1135 	styleEntry[4] =				/* dot */
1136 	styleEntry[5] =				/* gap */
1137 	styleEntry[6] =				/* dot */
1138 	styleEntry[7] = htofl(width);		/* gap */
1139 	em_pn.elp.elpNumEntries = htofl(sizeof styleEntry/sizeof styleEntry[0]);
1140 	em_pn.emr.nSize = htofl(sizeof(EMREXTCREATEPEN) + sizeof styleEntry);
1141     } else {
1142 	em_pn.emr.nSize = htofl(sizeof(EMREXTCREATEPEN));
1143     }
1144 
1145 # ifdef __EMF_DEBUG__
1146     fprintf(stderr, "CreatePen (%d): style %d, width %d, rgb %x\n",
1147 	handle, style, width, rgb);
1148 # endif
1149 
1150     emh_write(&em_pn, sizeof(EMREXTCREATEPEN), (size_t) 1, EMH_RECORD);
1151     if (user_style)
1152 	emh_write(&styleEntry, sizeof styleEntry, (size_t) 1, EMH_DATA);
1153 
1154 selectpen:
1155     chkcache(handle, lasthandle[EMFH_PEN]);
1156     clear_current_handle(EMFH_PEN);
1157     if (h)
1158 	h->is_current = True;
1159 # ifdef __EMF_DEBUG__
1160     fprintf(stderr, "Pen:   ");
1161 # endif
1162     select_object(handle);
1163 }/* end edgeattr */
1164 
1165 
1166 /* This procedure turns off the edge visibility. */
edgevis(onoff)1167 static void edgevis(onoff)
1168     int onoff;
1169 {
1170 
1171     edgeattr(onoff, 0, 0, 0, 0, 0);
1172 }/* end edgevis */
1173 
1174 
bkmode(mode)1175 static void bkmode(mode)
1176     int mode;
1177 {
1178     static int oldbkmode = 0;
1179     EMRSETBKMODE em_bm;
1180 
1181     chkcache(mode, oldbkmode);
1182     memset(&em_bm, 0, sizeof(EMRSETBKMODE));
1183     em_bm.emr.iType = htofl(EMR_SETBKMODE);
1184     em_bm.emr.nSize = htofl(sizeof(EMRSETBKMODE));
1185     em_bm.iMode = htofl(mode);
1186 
1187 # ifdef __EMF_DEBUG__
1188     fprintf(stderr, "SetBKMode (mode): %d\n", mode);
1189 # endif
1190 
1191     emh_write(&em_bm, sizeof(EMRSETBKMODE), (size_t) 1, EMH_RECORD);
1192 }
1193 
1194 
bkcolor(rgb)1195 static void bkcolor(rgb)
1196     int rgb;
1197 {
1198     static int oldbkcolor = UNDEFVALUE;
1199     EMRSETBKCOLOR em_bc;
1200 
1201     chkcache(rgb, oldbkcolor);
1202     memset(&em_bc, 0, sizeof(EMRSETBKCOLOR));
1203     em_bc.emr.iType = htofl(EMR_SETBKCOLOR);
1204     em_bc.emr.nSize = htofl(sizeof(EMRSETBKCOLOR));
1205     em_bc.crColor = htofl(rgb);
1206 
1207 # ifdef __EMF_DEBUG__
1208     fprintf(stderr, "SetBKColor (rgb): %x\n", rgb);
1209 # endif
1210 
1211     emh_write(&em_bc, sizeof(EMRSETBKCOLOR), (size_t) 1, EMH_RECORD);
1212 }
1213 
1214 
create_brush_pattern(bits,pattern)1215 static void create_brush_pattern(bits, pattern)
1216     unsigned char *bits;
1217     int pattern;
1218 {
1219     const struct emf_bmpat *pat = &emf_bm_pattern[pattern];
1220     unsigned char *b = pat->bits;
1221     int xbmhbytecnt;
1222     unsigned x;
1223     int y;
1224     unsigned byte, bit;
1225 
1226     xbmhbytecnt = (pat->width + 7) / 8;
1227 
1228     /* EMF bitmap is encoded from bottom to top */
1229     byte = 0;
1230     for (y = pat->height - 1; y >=0; y--) {
1231 	bit = 7;
1232 	for (x = 0; x < pat->width; x++) {
1233 	    if (b[xbmhbytecnt * y + x / 8] & (1 << x % 8))
1234 		bits[byte] |= 1 << bit;
1235 	    if (bit-- == 0) {
1236 		byte++;
1237 		bit = 7;
1238 	    }
1239 	}
1240 	/* size of a line must be a multiple of 4 byte */
1241 	if (bit != 7)
1242 	    byte++;
1243 	byte = (byte + 3) & ~(unsigned)3;
1244     }
1245 }
1246 
1247 
1248 /* Computes and sets fill color for solid filled shapes (fill style 0 to 40). */
fillstyle(fill_color,fill_style,pen_color)1249 static void fillstyle(fill_color, fill_style, pen_color)
1250     int fill_color, fill_style, pen_color;
1251 {
1252     unsigned handle;
1253     int pattern, hatch;
1254     int rgb, hatchbkrgb;
1255     int style;
1256     EMRCREATEBRUSHINDIRECT em_bi;
1257     EMRCREATEDIBPATTERNBRUSHPT em_pb;
1258     BITMAPINFO bmi;
1259     RGBQUAD hatchcolors[2];
1260     int width, height;
1261     size_t bsize;
1262     unsigned char *bits;
1263     struct emfhandle *h = NULL;
1264 
1265     if (fill_style < 0) {		/* Unfilled shape */
1266 	style = BS_HOLLOW;
1267 	rgb = 0;
1268 	hatchbkrgb = 0;
1269 	pattern = 0;
1270     } else if (fill_style <= 40) {	/* Solid filled shape */
1271 	style = BS_SOLID;
1272 	rgb = conv_fill_color(fill_style, fill_color);
1273 	hatchbkrgb = 0;
1274 	pattern = 0;
1275     } else /* if (fill_style > 40) */ {	/* Pattern filled shape */
1276 	style = BS_HATCHED;
1277 	rgb = conv_color(pen_color);
1278 	hatchbkrgb = conv_color(fill_color);
1279 	pattern = fill_style - 41;
1280     }
1281 
1282     if ((unsigned)pattern > sizeof emf_bm_pattern / sizeof emf_bm_pattern[0]) {
1283 	fprintf(stderr, "fig2dev: emf: fill pattern %d is not supported\n",
1284 		pattern);
1285 	return;
1286     }
1287 
1288     if (style == BS_HATCHED && emf_map_pattern[pattern] != -1) {
1289 	/*
1290 	 * Use EMF hatch pattern.  Setting of background color is not in brush.
1291 	 */
1292 	bkmode(OPAQUE);
1293 	bkcolor(hatchbkrgb);
1294 
1295 	/* The background color is now handled. */
1296 	hatchbkrgb = 0;
1297     }
1298 
1299     /* if a stock object is available, use it */
1300     switch (style) {
1301     case BS_HOLLOW:
1302 	handle = ENHMETA_STOCK_OBJECT | NULL_BRUSH;
1303 	goto selectbrush;
1304     case BS_SOLID:
1305 	switch (rgb) {
1306 	case 0xffffff:
1307 	    handle = ENHMETA_STOCK_OBJECT | WHITE_BRUSH;
1308 	    goto selectbrush;
1309 	case 0xc0c0c0:
1310 	    handle = ENHMETA_STOCK_OBJECT | LTGRAY_BRUSH;
1311 	    goto selectbrush;
1312 	case 0x808080:
1313 	    handle = ENHMETA_STOCK_OBJECT | GRAY_BRUSH;
1314 	    goto selectbrush;
1315 	case 0x404040:
1316 	    handle = ENHMETA_STOCK_OBJECT | DKGRAY_BRUSH;
1317 	    goto selectbrush;
1318 	case 0x000000:
1319 	    handle = ENHMETA_STOCK_OBJECT | BLACK_BRUSH;
1320 	    goto selectbrush;
1321 	default:
1322 	    break;
1323 	}
1324 	break;
1325     default:
1326 	break;
1327     }
1328 
1329     /* search for the same brush */
1330     for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1331 	if (h->type == EMFH_BRUSH &&
1332 		h->eh_un.b.bstyle == style && h->eh_un.b.brgb == rgb &&
1333 		h->eh_un.b.bpattern == pattern &&
1334 		h->eh_un.b.bhatchbkrgb == hatchbkrgb) {
1335 	    /* found */
1336 	    use_handle(h);
1337 	    handle = h->handle;
1338 	    goto selectbrush;
1339 	}
1340     }
1341 
1342     /* not found -- create new brush */
1343     h = get_handle(EMFH_BRUSH);
1344     handle = h->handle;
1345     use_handle(h);
1346 
1347     h->eh_un.b.bstyle = style;
1348     h->eh_un.b.brgb = rgb;
1349     h->eh_un.b.bpattern = pattern;
1350     h->eh_un.b.bhatchbkrgb = hatchbkrgb;
1351 
1352     hatch = 0;
1353     if (style == BS_HATCHED && (hatch = emf_map_pattern[pattern]) == -1) {
1354 	/*
1355 	 * create a pattern brush
1356 	 */
1357 	memset(&em_pb, 0, sizeof(EMRCREATEDIBPATTERNBRUSHPT));
1358 	memset(&bmi, 0, sizeof(BITMAPINFO));
1359 	em_pb.emr.iType = htofl(EMR_CREATEDIBPATTERNBRUSHPT);
1360 	em_pb.ihBrush = htofl(handle);
1361 	/* em_pb.iUsage = htofl(DIB_RGB_COLORS);	this is default */
1362 	em_pb.offBmi = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT));
1363 	em_pb.cbBmi = htofl(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
1364 	em_pb.offBits = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT) +
1365 			      sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
1366 
1367 	width = emf_bm_pattern[pattern].width;
1368 	height = emf_bm_pattern[pattern].height;
1369 
1370 	if (emflevel != EMF_LEVEL_WINNT && (width > 8 || height > 8))
1371 	    fprintf(stderr, "Warning: fill pattern %d will not appear properly on Windows 95/98/Me\n",
1372 		    pattern);
1373 
1374 	/* Windows 95/98/Me doesn't show 8x4 pat properly.  Convert to 8x8. */
1375 	if (height == 4)
1376 	    height = 8;
1377 
1378 	bsize = (width + 31) / 32 * height * 4;
1379 
1380 	bmi.bmiHeader.biSizeImage = em_pb.cbBits = htofl((EMFulong) bsize);
1381 	em_pb.emr.nSize = htofl(sizeof(EMRCREATEDIBPATTERNBRUSHPT) +
1382 		sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD) + bsize);
1383 
1384 	bmi.bmiHeader.biSize = htofl(sizeof(BITMAPINFOHEADER));
1385 	bmi.bmiHeader.biWidth  = htofl(width);
1386 	bmi.bmiHeader.biHeight = htofl(height);
1387 	bmi.bmiHeader.biPlanes = bmi.bmiHeader.biBitCount = htofs(1);
1388 	bmi.bmiHeader.biCompression = htofl(BI_RGB);	/* uncompressed */
1389 	bmi.bmiHeader.biXPelsPerMeter =
1390 		bmi.bmiHeader.biYPelsPerMeter = htofl(2953);	/* 75dpi ? */
1391 	bmi.bmiHeader.biClrUsed = htofl(2);
1392 	/* bmi.bmiHeader.biClrImportant = htofl(0); */
1393 
1394 	/* background and foreground colors */
1395 	hatchcolors[0].rgbBlue  = GetBValue(hatchbkrgb);
1396 	hatchcolors[0].rgbGreen = GetGValue(hatchbkrgb);
1397 	hatchcolors[0].rgbRed   = GetRValue(hatchbkrgb);
1398 	hatchcolors[0].rgbReserved = 0;
1399 	hatchcolors[1].rgbBlue  = GetBValue(rgb);
1400 	hatchcolors[1].rgbGreen = GetGValue(rgb);
1401 	hatchcolors[1].rgbRed   = GetRValue(rgb);
1402 	hatchcolors[1].rgbReserved = 0;
1403 
1404 	if ((bits = malloc(bsize)) == NULL) {
1405 	    perror("fig2dev: malloc");
1406 	    exit(1);
1407 	}
1408 	memset(bits, 0, bsize);
1409 
1410 	create_brush_pattern(bits, pattern);
1411 
1412 	/* Windows 95/98/Me doesn't show 8x4 pat properly.  Convert to 8x8. */
1413 	if (emf_bm_pattern[pattern].height == 4)
1414 	    create_brush_pattern(bits + bsize / 2, pattern); /* latter half */
1415 
1416 # ifdef __EMF_DEBUG__
1417 	fprintf(stderr, "CreatePatternBrush (%d): pattern %d, rgb %x, bkrgb %x\n",
1418 	    handle, pattern, rgb, hatchbkrgb);
1419 # endif
1420 
1421 	emh_write(&em_pb, sizeof(EMRCREATEDIBPATTERNBRUSHPT), (size_t) 1,
1422 		  EMH_RECORD);
1423 	emh_write(&bmi, sizeof(BITMAPINFO), (size_t) 1, EMH_DATA);
1424 	emh_write(hatchcolors, sizeof(RGBQUAD), (size_t) 2, EMH_DATA);
1425 	emh_write(bits, bsize, (size_t) 1, EMH_DATA);
1426 	free(bits);
1427     } else {
1428 	memset(&em_bi, 0, sizeof(EMRCREATEBRUSHINDIRECT));
1429 	em_bi.emr.iType = htofl(EMR_CREATEBRUSHINDIRECT);
1430 	em_bi.emr.nSize = htofl(sizeof(EMRCREATEBRUSHINDIRECT));
1431 	em_bi.ihBrush = htofl(handle);
1432 	em_bi.lb.lbStyle = htofl(style);
1433 	em_bi.lb.lbColor = htofl(rgb);
1434 	em_bi.lb.lbHatch = htofl(hatch);
1435 
1436 # ifdef __EMF_DEBUG__
1437 	fprintf(stderr, "CreateBrush (%d): style %d, rgb %x, hatch %d\n",
1438 	    handle, style, rgb, hatch);
1439 # endif
1440 
1441 	emh_write(&em_bi, sizeof(EMRCREATEBRUSHINDIRECT), (size_t) 1,
1442 		  EMH_RECORD);
1443     }
1444 
1445 selectbrush:
1446     chkcache(handle, lasthandle[EMFH_BRUSH]);
1447     clear_current_handle(EMFH_BRUSH);
1448     if (h)
1449 	h->is_current = True;
1450 # ifdef __EMF_DEBUG__
1451     fprintf(stderr, "Brush: ");
1452 # endif
1453     select_object(handle);
1454 }/* end fillstyle */
1455 
1456 
textfont(font,size,angle)1457 static void textfont(font, size, angle)
1458     int     font;
1459     double  size;
1460     int     angle;	/* tenths degree */
1461 {
1462     EMREXTCREATEFONTINDIRECTW em_fn;
1463     short *utext;
1464     int    n_chars, n_unicode;
1465     struct emfhandle *h = NULL;
1466     unsigned handle;
1467     int fontsz;
1468 
1469     fontsz = -(int)(size * (1200/72.27 * 0.88/*?? font is a bit large*/) + 0.5);
1470 
1471     /* search for the same font */
1472     for (h = latesthandle; h != (void *)&handles; h = (void *) h->prev) {
1473 	if (h->type == EMFH_FONT &&
1474 		h->eh_un.f.ffont == font && h->eh_un.f.fsize == fontsz &&
1475 		h->eh_un.f.fangle == angle) {
1476 	    /* found */
1477 	    use_handle(h);
1478 	    handle = h->handle;
1479 	    goto selectfont;
1480 	}
1481     }
1482 
1483     /* not found -- create new font */
1484     h = get_handle(EMFH_FONT);
1485     handle = h->handle;
1486     use_handle(h);
1487 
1488     h->eh_un.f.ffont = font;
1489     h->eh_un.f.fsize = fontsz;
1490     h->eh_un.f.fangle = angle;
1491 
1492     memset(&em_fn, 0, sizeof(EMREXTCREATEFONTINDIRECTW));
1493     em_fn.emr.iType = htofl(EMR_EXTCREATEFONTINDIRECTW);
1494     em_fn.emr.nSize = htofl(sizeof(EMREXTCREATEFONTINDIRECTW));
1495 
1496     em_fn.ihFont = htofl(handle);
1497 
1498     utext = (short *) em_fn.elfw.elfLogFont.lfFaceName;
1499     n_unicode = sizeof (em_fn.elfw.elfLogFont.lfFaceName);
1500     textunicode(
1501 #if defined(I18N) && defined(USE_ICONV)
1502       (font < 0 /* locale font */)? localeFonts[-1-font][figLanguage].FaceName :
1503 #endif
1504 	    lfFaceName[font],
1505       &n_chars, &utext, &n_unicode);
1506 
1507     em_fn.elfw.elfLogFont.lfHeight = htofl(fontsz);
1508     em_fn.elfw.elfLogFont.lfEscapement = em_fn.elfw.elfLogFont.lfOrientation
1509 	= htofl(angle);
1510 #if defined(I18N) && defined(USE_ICONV)
1511     if (font < 0 /* locale font */) {
1512 	const struct localefnt *lf = &localeFonts[-1-font][figLanguage];
1513 
1514 	em_fn.elfw.elfLogFont.lfWeight = htofl(lf->Weight);
1515 	em_fn.elfw.elfLogFont.lfItalic = /*uchar*/lf->Italic;
1516 	em_fn.elfw.elfLogFont.lfCharSet = /*uchar*/lf->Charset;
1517 	em_fn.elfw.elfLogFont.lfPitchAndFamily = /*uchar*/lf->PitchAndFamily;
1518 	HTOFL(em_fn.elfw.elfLogFont.lfWidth,
1519 	    (int)(size * (1200/72.27 *0.40/*?? font is a bit wide*/) + 0.5));
1520     } else
1521 #endif
1522     {
1523 	em_fn.elfw.elfLogFont.lfWeight = htofl(lfWeight[font]);
1524 	em_fn.elfw.elfLogFont.lfItalic = /*uchar*/lfItalic[font];
1525 	em_fn.elfw.elfLogFont.lfCharSet = /*uchar*/lfCharSet[font];
1526 	em_fn.elfw.elfLogFont.lfPitchAndFamily =/*uchar*/lfPitchAndFamily[font];
1527     }
1528 
1529     emh_write(&em_fn, sizeof(EMREXTCREATEFONTINDIRECTW), (size_t)1, EMH_RECORD);
1530 
1531 # ifdef __EMF_DEBUG__
1532     fprintf(stderr,
1533 	"Textfont (%d): %s  Size: %d  Weight: %d  Italic: %d  Angle: %d\n",
1534 	handle,
1535 #  if defined(I18N) && defined(USE_ICONV)
1536       (font < 0 /* locale font */)? localeFonts[-1-font][figLanguage].FaceName :
1537 #  endif
1538 	lfFaceName[font], -ftohl(em_fn.elfw.elfLogFont.lfHeight),
1539 	lfWeight[font], lfItalic[font], angle);
1540 # endif
1541 
1542 selectfont:
1543     chkcache(handle, lasthandle[EMFH_FONT]);
1544     clear_current_handle(EMFH_FONT);
1545     if (h)
1546 	h->is_current = True;
1547 # ifdef __EMF_DEBUG__
1548     fprintf(stderr, "Font:  ");
1549 # endif
1550     select_object(handle);
1551 }/* end textfont */
1552 
1553 
warn_32bit_pos()1554 static void warn_32bit_pos()
1555 {
1556     static int wgiv;
1557 
1558     if (emflevel != EMF_LEVEL_WINNT && !wgiv) {
1559 	fprintf(stderr, "\
1560 Warning: Coordinates exceed 16bit value.\n\
1561 Some figures will be invisible on Windows 95/98/Me.\n");
1562 	wgiv = 1;
1563     }
1564 }
1565 
1566 
1567 /* Copies coordinates of pos p to point P. */
pos2point(P,p)1568 static void pos2point(P, p)
1569     F_point *P;
1570     F_pos *p;
1571 {
1572 
1573     P->x = p->x; P->y = p->y;
1574 }/* end pos2point */
1575 
1576 
1577 /* Returns length of the arrow. used to shorten lines/arcs at
1578  * an end where an arrow needs to be drawn. */
arrow_length(a)1579 static double arrow_length(a)
1580     F_arrow *a;
1581 {
1582     double len;
1583 
1584     switch (a->type) {
1585     case 0:				/* stick type */
1586 	len = ARROW_EXTRA_LEN(a);
1587 	break;
1588     case 1:				/* closed triangle */
1589 	len =  a->ht;
1590 	break;
1591     case 2:				/* indented hat */
1592 	len =  ARROW_INDENT_DIST * a->ht;
1593 	break;
1594     case 3:				/* pointed hat */
1595 	len =  ARROW_POINT_DIST * a->ht;
1596 	break;
1597     default:
1598 	len =  0.;
1599     }
1600     if (rounded_arrows)
1601 	len -= ARROW_EXTRA_LEN(a);
1602 
1603     return len;
1604 }
1605 
1606 
1607 /* Draws an arrow ending at point p pointing into direction dir.
1608  * type and attributes as required by a and l.  This routine works
1609  * for both lines and arc (in that case l should be a F_arc *). */
arrow(P,a,l,dir)1610 static void arrow(P, a, l, dir)
1611     F_point	*P;
1612     F_arrow	*a;
1613     F_line	*l;
1614     Dir		*dir;
1615 {
1616     F_point s1, s2, t, p;
1617     EMRPOLYLINE	em_pl;		/* Little endian format */
1618     POINTL      aptl[4];	/* Maximum of four points required for arrows */
1619     POINTS      apts[4];
1620     unsigned    cpt;		/* Number of points in the array */
1621     unsigned itype, itype16;
1622     int bbx_top, bbx_bottom, bbx_left, bbx_right;	/* Bounding box */
1623 
1624     t.x = 0;
1625     t.y = 0;
1626     p = *P;
1627     if (!rounded_arrows) {
1628 	/* Move the arrow backwards in order to let it end
1629 	 * at the correct spot */
1630 	double f = ARROW_EXTRA_LEN(a);
1631 	p.x = round(p.x - f * dir->x);
1632 	p.y = round(p.y - f * dir->y);
1633     }
1634 
1635     if (a->type == 0) {		/* Old style stick arrow */
1636 	edgeattr(1, 0, (int)a->thickness, l->pen_color, 0, 0);
1637     } else {			/* Polygonal arrows */
1638 	/* miter join style, butt line cap */
1639 	edgeattr(1, 0, (int)a->thickness, l->pen_color, 0, 0);
1640 	switch (a->style) {
1641 	case 0:
1642 	    fillstyle(7, 20, 0);		/* Fill with white (7) */
1643 	    break;
1644 	case 1:
1645 	    fillstyle(l->pen_color, 20, 0);	/* Use pen color to fill */
1646 	    break;
1647 	default:
1648 	    fprintf(stderr, "Unsupported fig arrow style %d !!\n", a->style);
1649 	}
1650     }
1651 
1652     /* Start the bounding box */
1653 
1654     bbx_left = bbx_right  = P->x;	/* Use original point for bounding */
1655     bbx_top  = bbx_bottom = P->y;
1656 
1657     itype = EMR_POLYGON;
1658     itype16 = EMR_POLYGON16;
1659 
1660     switch (a->type) {
1661 
1662     case 0:				/* Stick type */
1663 	itype = EMR_POLYLINE;
1664 	itype16 = EMR_POLYLINE16;
1665 	cpt = 3;
1666 
1667 	s1.x = round(p.x - a->ht * dir->x + a->wid*0.5 * dir->y);
1668 	s1.y = round(p.y - a->ht * dir->y - a->wid*0.5 * dir->x);
1669 	s2.x = round(p.x - a->ht * dir->x - a->wid*0.5 * dir->y);
1670 	s2.y = round(p.y - a->ht * dir->y + a->wid*0.5 * dir->x);
1671 	break;
1672 
1673     case 1:				/* Closed triangle */
1674 	cpt = 3;
1675 
1676 	s1.x = round(p.x - a->ht * dir->x + a->wid*0.5 * dir->y);
1677 	s1.y = round(p.y - a->ht * dir->y - a->wid*0.5 * dir->x);
1678 	s2.x = round(p.x - a->ht * dir->x - a->wid*0.5 * dir->y);
1679 	s2.y = round(p.y - a->ht * dir->y + a->wid*0.5 * dir->x);
1680 	break;
1681 
1682     case 2:				/* Indented hat */
1683 	cpt = 4;
1684 
1685 	s1.x = round(p.x - a->ht*ARROW_POINT_DIST * dir->x
1686 			 + a->wid*0.5 * dir->y);
1687 	s1.y = round(p.y - a->ht*ARROW_POINT_DIST * dir->y
1688 			 - a->wid*0.5 * dir->x);
1689 	s2.x = round(p.x - a->ht*ARROW_POINT_DIST * dir->x
1690 			 - a->wid*0.5 * dir->y);
1691 	s2.y = round(p.y - a->ht*ARROW_POINT_DIST * dir->y
1692 			 + a->wid*0.5 * dir->x);
1693 
1694 	t.x = round(p.x - a->ht * dir->x);
1695 	t.y = round(p.y - a->ht * dir->y);
1696 
1697 	UPDATE_BBX_X(t.x);
1698 	UPDATE_BBX_Y(t.y);
1699 	break;
1700 
1701     case 3:				/* Pointed hat */
1702 	cpt = 4;
1703 
1704 	s1.x = round(p.x - a->ht*ARROW_INDENT_DIST * dir->x
1705 			 + a->wid*0.5 * dir->y);
1706 	s1.y = round(p.y - a->ht*ARROW_INDENT_DIST * dir->y
1707 			 - a->wid*0.5 * dir->x);
1708 	s2.x = round(p.x - a->ht*ARROW_INDENT_DIST * dir->x
1709 			 - a->wid*0.5 * dir->y);
1710 	s2.y = round(p.y - a->ht*ARROW_INDENT_DIST * dir->y
1711 			 + a->wid*0.5 * dir->x);
1712 
1713 	t.x = round(p.x - a->ht * dir->x);
1714 	t.y = round(p.y - a->ht * dir->y);
1715 
1716 	UPDATE_BBX_X(t.x);
1717 	UPDATE_BBX_Y(t.y);
1718 	break;
1719 
1720     default:
1721 	fprintf(stderr, "Unsupported fig arrow type %d.\n", a->type);
1722 	return;
1723 
1724     }/* end case */
1725 
1726     UPDATE_BBX_X(s1.x);
1727     UPDATE_BBX_Y(s1.y);
1728 
1729     UPDATE_BBX_X(s2.x);
1730     UPDATE_BBX_Y(s2.y);
1731 
1732     em_pl.rclBounds.left   = htofl(bbx_left);	/* Store bounding box */
1733     em_pl.rclBounds.right  = htofl(bbx_right);
1734     em_pl.rclBounds.top    = htofl(bbx_top);
1735     em_pl.rclBounds.bottom = htofl(bbx_bottom);
1736     em_pl.cptl = htofl(cpt);			/* Number of points */
1737 
1738     if (bbx_left >= -32768 && bbx_right <= 32767
1739 	&& bbx_top >= -32768 && bbx_bottom <= 32767) {
1740 
1741 # ifdef __EMF_DEBUG__
1742     fprintf(stderr, "Arrowhead16 %d rclBounds (ltrb): %d %d %d %d\n",
1743       cpt,
1744       bbx_left,  bbx_top, bbx_right, bbx_bottom);
1745 # endif
1746 
1747 	/* use 16bit point */
1748 	em_pl.emr.iType = htofl(itype16);
1749 
1750 	apts[0].x = htofs(s1.x);
1751 	apts[0].y = htofs(s1.y);
1752 	apts[1].x = htofs(p.x);
1753 	apts[1].y = htofs(p.y);
1754 	apts[2].x = htofs(s2.x);
1755 	apts[2].y = htofs(s2.y);
1756 	apts[3].x = htofs(t.x);
1757 	apts[3].y = htofs(t.y);
1758 
1759 	HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE16) + cpt*sizeof(POINTS));
1760 	emh_write(&em_pl, sizeof(EMRPOLYLINE16), (size_t) 1, EMH_RECORD);
1761 	emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
1762     } else {
1763 
1764 # ifdef __EMF_DEBUG__
1765     fprintf(stderr, "Arrowhead %d rclBounds (ltrb): %d %d %d %d\n",
1766       cpt,
1767       bbx_left,  bbx_top, bbx_right, bbx_bottom);
1768 # endif
1769 
1770 	/* use 32bit point */
1771 	warn_32bit_pos();
1772 
1773 	em_pl.emr.iType = htofl(itype);
1774 
1775 	aptl[0].x = htofl(s1.x);
1776 	aptl[0].y = htofl(s1.y);
1777 	aptl[1].x = htofl(p.x);
1778 	aptl[1].y = htofl(p.y);
1779 	aptl[2].x = htofl(s2.x);
1780 	aptl[2].y = htofl(s2.y);
1781 	aptl[3].x = htofl(t.x);
1782 	aptl[3].y = htofl(t.y);
1783 
1784 	HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE) + cpt*sizeof(POINTL));
1785 	emh_write(&em_pl, sizeof(EMRPOLYLINE), (size_t) 1, EMH_RECORD);
1786 	emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
1787     }
1788 }
1789 
1790 
1791 /* Draws arc arrow ending at p and starting at q. */
arc_arrow(p,q,arw,arc)1792 static void arc_arrow(p, q, arw, arc)
1793     F_pos	*p;
1794     F_point	*q;
1795     F_arrow	*arw;
1796     F_arc	*arc;
1797 {
1798     F_point P;
1799     Dir dir; double d;
1800 
1801     if (!arw) return;
1802 
1803     pos2point(&P, p);
1804     direction(&P, q, &dir, &d);
1805     arrow(&P, arw, (F_line *)arc, &dir);
1806 }
1807 
1808 
1809 /* Replaces p by the starting point of the arc arrow ending at p. */
arc_arrow_adjust(p,arwpos,arc,r,arw,adir)1810 static void arc_arrow_adjust(p, arwpos, arc, r, arw, adir)
1811     F_point *p;		/* in: end of the arc, out: fixed end of arc */
1812     F_point *arwpos;	/* out: origin of arrow */
1813     F_arc *arc;
1814     double r;
1815     F_arrow *arw;
1816     double adir;
1817 {
1818     double l;
1819     double alen, th;
1820     Dir dir; double dirlen;
1821     double d2, d3;
1822     F_point origpos, p1, p2, p3;
1823     struct dpoint {
1824 	double x, y;
1825     } p4;
1826     double X, Y, d;
1827     double cx, cy;
1828 
1829     if (!arw) return;
1830 
1831     cx = arc->center.x; cy = arc->center.y;	/* arc center */
1832     origpos = *p;	/* save original arc end (to be used later) */
1833 
1834     l = arw->type != 0 ? arrow_length(arw) : arw->ht;
1835     arc_rotate(p, cx, cy, adir * l / (1.8 * r + l));
1836 
1837     /* length of arrow head */
1838     alen = arw->ht;
1839     if (!rounded_arrows)
1840 	alen += ARROW_EXTRA_LEN(arw);
1841 
1842     /*
1843      * fix arrow root pos
1844      */
1845 
1846     /* if the arrow is longer than the diameter, no way to fix arrow root pos */
1847     if (alen >= 2 * r) {
1848 	*arwpos = *p;	/* use the fixed arc end */
1849 	goto fix_cap;
1850     }
1851 
1852     /* make a chord with the arc and the center line of the arrow head */
1853     th = 2 * atan(sqrt(1 / (4 * r * r / (alen * alen) - 1)));
1854     *arwpos = origpos;
1855     arc_rotate(arwpos, cx, cy, adir * th);
1856 
1857     /*
1858      * fix arc end pos
1859      */
1860 
1861     /* direction from arow root to arrow top */
1862     if (direction(&origpos, arwpos, &dir, &dirlen) == False)
1863 	goto fix_cap;	/* no way to fix */
1864 
1865     /* Calculate the center of the line of arrow top. */
1866     p1 = origpos;
1867     if (!rounded_arrows) {
1868 	d = ARROW_EXTRA_LEN(arw);
1869 	p1.x = round(p1.x - d * dir.x);
1870 	p1.y = round(p1.y - d * dir.y);
1871     }
1872 
1873     /* Calculate other points of the arrow head. */
1874     d = p1.x - arw->ht * dir.x + arw->wid*0.5 * dir.y; p2.x = round(d);
1875     d = p1.y - arw->ht * dir.y - arw->wid*0.5 * dir.x; p2.y = round(d);
1876     d = p1.x - arw->ht * dir.x - arw->wid*0.5 * dir.y; p3.x = round(d);
1877     d = p1.y - arw->ht * dir.y + arw->wid*0.5 * dir.x; p3.y = round(d);
1878 
1879     /* Calculate distance from the center of the arc to the points. */
1880     d2 = distance(cx, cy, (double) p2.x, (double) p2.y);
1881     d3 = distance(cx, cy, (double) p3.x, (double) p3.y);
1882 
1883     /* Use the farther point. */
1884     if (d3 > d2) {
1885 	p2 = p3;
1886 	d2 = d3;
1887     }
1888 
1889     /* The farther point shall be out of the arc. */
1890     if (d2 < r)
1891 	goto fix_cap;
1892 
1893     /* direction from p1 to p2 */
1894     if (direction(&p2, &p1, &dir, &dirlen) == False)
1895 	goto fix_cap;
1896 
1897     /*
1898      * Drop a perpendicular line from the arc center
1899      * to the line on which p1 and p2 are.
1900      */
1901     /*
1902      * The line of the arrow head is
1903      *	x = p2.x + t * dir.x,
1904      *	y = p2.y + t * dir.y,  where t is an intermediate parameter.
1905      *
1906      * The distance^2 from the center of the arc to a point on the line is
1907      * (x - cx)^2 + (y - cy)^2 = (dir.x^2 + dir.y^2) * t^2
1908      *		+ 2*((p2.x - cx) * dir.x + (p2.y - cy) * dir.y) * t
1909      *		+ (p2.x - cx)^2 + (p2.y - cy)^2
1910      *	= t^2 + 2*(X * dir.x + Y * dir.y) * t + X^2 + Y^2
1911      *			where	dir.x^2 + dir.y^2 = 1 (dir is a unit vector),
1912      *				X = p2.x - cx, Y = p2.y - cy
1913      *	= t^2 + 2*(X * dir.x + Y * dir.y) * t + (X * dir.x + Y * dir.y)^2
1914      *		- (X * dir.x + Y * dir.y)^2
1915      *		+ X^2 + Y^2
1916      *	= (t + (X * dir.x + Y * dir.y))^2
1917      *		- X^2*dir.x^2 - 2*X*Y*dir.x*dir.y - Y^2*dir.y^2
1918      *		+ X^2*(dir.x^2 + dir.y^2) + Y^2*(dir.x^2 + dir.y^2)
1919      *			where	dir.x^2 + dir.y^2 = 1
1920      *	= (t + (X * dir.x + Y * dir.y))^2
1921      *		+ X^2*dir.y^2 - 2*X*Y*dir.x*dir.y + Y^2*dir.x^2
1922      *	= (t + (X * dir.x + Y * dir.y))^2 + (X * dir.y - Y * dir.x)^2
1923      */
1924     X = p2.x - cx;
1925     Y = p2.y - cy;
1926 
1927     /* Calculate the pedal point of the perpendicular line. */
1928     d = X * dir.x + Y * dir.y;
1929     p4.x = p2.x - d * dir.x;
1930     p4.y = p2.y - d * dir.y;
1931 
1932     /* and the length^2 of the perpendicular line segment is */
1933     d = X * dir.y - Y * dir.x;
1934     d = d * d;
1935 
1936     /* length from p4 to the target point */
1937     d = sqrt(r * r - d);
1938 
1939     /* Calculate target point. */
1940     p4.x = p4.x + d * dir.x;
1941     p4.y = p4.y + d * dir.y;
1942 
1943     p->x = round(p4.x);
1944     p->y = round(p4.y);
1945 
1946 fix_cap:
1947     if (arc->cap_style == 2) {
1948 	/* Projecting cap style is a little longer.  Shorten the arc. */
1949 	arc_rotate(p, cx, cy, adir * (double)arc->thickness / (2.0 * r));
1950     }
1951 }
1952 
1953 
arc_radius(a)1954 static double arc_radius(a)
1955     F_arc *a;
1956 {
1957 
1958     return (distance((double)a->point[0].x, (double)a->point[0].y,
1959 			a->center.x, a->center.y) +
1960 	    distance((double)a->point[1].x, (double)a->point[1].y,
1961 			a->center.x, a->center.y) +
1962 	    distance((double)a->point[2].x, (double)a->point[2].y,
1963 			a->center.x, a->center.y)) / 3.;
1964 }
1965 
1966 
translate(x,y,tx,ty)1967 static void translate(x, y, tx, ty)
1968     double *x, *y, tx, ty;
1969 {
1970 
1971     *x += tx; *y += ty;
1972 }/* end translate */
1973 
1974 
1975 /* Rotates counter clockwise around origin */
rotate(x,y,angle)1976 static void rotate(x, y, angle)
1977     double *x, *y, angle;
1978 {
1979     double s = sin(angle), c = cos(angle), xt = *x, yt = *y;
1980 
1981     *x =  c * xt + s * yt;
1982     *y = -s * xt + c * yt;
1983 }/* end rotate */
1984 
1985 
1986 /* Rotates the point p counter clockwise along the arc with center c. */
arc_rotate(p,cx,cy,angle)1987 static void arc_rotate(p, cx, cy, angle)
1988     F_point *p;
1989     double cx, cy, angle;
1990 {
1991     double x = p->x, y = p->y;
1992 
1993     translate(&x, &y, -cx, -cy);
1994     rotate(&x, &y, angle);
1995     translate(&x, &y, +cx, +cy);
1996     p->x = round(x); p->y = round(y);
1997 }
1998 
1999 
arcoutline(a)2000 static void arcoutline(a)
2001     F_arc *a;
2002 {
2003     EMRARC em_ar;
2004     double r = arc_radius(a);
2005     F_point p0, p2;
2006     F_point arwp0, arwp2;
2007     int i;
2008 
2009     pos2point(&p0, &a->point[0]);
2010     pos2point(&p2, &a->point[2]);
2011     if (a->type == T_OPEN_ARC && a->thickness != 0) {
2012 	/* adjust for arrow heads */
2013 	arc_arrow_adjust(&p0, &arwp0, a, r, a->back_arrow, +1.);
2014 	arc_arrow_adjust(&p2, &arwp2, a, r, a->for_arrow, -1.);
2015 
2016 	/* calculate inner product */
2017 	if ((a->point[0].x - a->point[2].x) * (p0.x - p2.x) +
2018 	    (a->point[0].y - a->point[2].y) * (p0.y - p2.y) < 0) {
2019 	    /*
2020 	     * This is probably because the arc is very short and hidden
2021 	     * in the arrow heads.  Skip drawing the arc in this case.
2022 	     */
2023 	    goto draw_arrows;
2024 	}
2025     }
2026 
2027     i = (a->type == T_OPEN_ARC) ? EMR_ARC : EMR_PIE;
2028     em_ar.emr.iType = htofl(i);
2029     em_ar.emr.nSize = htofl(sizeof(EMRARC));
2030     HTOFL(em_ar.rclBox.left,   round(a->center.x - r));
2031     HTOFL(em_ar.rclBox.top,    round(a->center.y - r));
2032     HTOFL(em_ar.rclBox.right,  round(a->center.x + r));
2033     HTOFL(em_ar.rclBox.bottom, round(a->center.y + r));
2034     em_ar.ptlStart.x = htofl(p0.x);
2035     em_ar.ptlStart.y = htofl(p0.y);
2036     em_ar.ptlEnd.x = htofl(p2.x);
2037     em_ar.ptlEnd.y = htofl(p2.y);
2038 
2039 # ifdef __EMF_DEBUG__
2040     fprintf(stderr, "Arc outline rclBox (ltrb): %d %d %d %d\n",
2041 	ftohl(em_ar.rclBox.left),  ftohl(em_ar.rclBox.top),
2042 	ftohl(em_ar.rclBox.right), ftohl(em_ar.rclBox.bottom));
2043 # endif
2044 
2045     emh_write(&em_ar, sizeof(EMRARC), (size_t) 1, EMH_RECORD);
2046 
2047 draw_arrows:
2048     if (a->type == T_OPEN_ARC && a->thickness != 0) {
2049 	/* draw arrow heads */
2050 	arc_arrow(&a->point[0], &arwp0, a->back_arrow, a);
2051 	arc_arrow(&a->point[2], &arwp2, a->for_arrow, a);
2052     }
2053 }
2054 
2055 
arcinterior(a)2056 static void arcinterior(a)
2057     F_arc *a;
2058 {
2059     EMRCHORD em_ch;
2060     double r = arc_radius(a);
2061 
2062     em_ch.emr.iType = htofl(EMR_CHORD);
2063     em_ch.emr.nSize = htofl(sizeof(EMRCHORD));
2064     HTOFL(em_ch.rclBox.left,   round(a->center.x - r));
2065     HTOFL(em_ch.rclBox.top,    round(a->center.y - r));
2066     HTOFL(em_ch.rclBox.right,  round(a->center.x + r));
2067     HTOFL(em_ch.rclBox.bottom, round(a->center.y + r));
2068     em_ch.ptlStart.x = htofl(a->point[0].x);
2069     em_ch.ptlStart.y = htofl(a->point[0].y);
2070     em_ch.ptlEnd.x = htofl(a->point[2].x);
2071     em_ch.ptlEnd.y = htofl(a->point[2].y);
2072 
2073 # ifdef __EMF_DEBUG__
2074     fprintf(stderr, "Arc interior rclBox (ltrb): %d %d %d %d\n",
2075 	ftohl(em_ch.rclBox.left),  ftohl(em_ch.rclBox.top),
2076 	ftohl(em_ch.rclBox.right), ftohl(em_ch.rclBox.bottom));
2077 # endif
2078 
2079     emh_write(&em_ch, sizeof(EMRCHORD), (size_t) 1, EMH_RECORD);
2080 }/* end arcinterior */
2081 
2082 
2083 /* Reverses arc direction by swapping endpoints and arrows */
arc_reverse(arc)2084 static void arc_reverse(arc)
2085     F_arc *arc;
2086 {
2087     F_arrow *arw;
2088     F_pos pp;
2089 
2090     pp = arc->point[0]; arc->point[0] = arc->point[2]; arc->point[2] = pp;
2091     arw = arc->for_arrow;
2092     arc->for_arrow = arc->back_arrow;
2093     arc->back_arrow = arw;
2094 }
2095 
2096 
circle(e)2097 static void circle(e)
2098     F_ellipse *e;
2099 {
2100     EMRELLIPSE em_el;
2101 
2102     em_el.emr.iType = htofl(EMR_ELLIPSE);
2103     em_el.emr.nSize = htofl(sizeof(EMRELLIPSE));
2104     em_el.rclBox.left   = htofl(e->center.x - e->radiuses.x);
2105     em_el.rclBox.top    = htofl(e->center.y - e->radiuses.x);
2106     em_el.rclBox.right  = htofl(e->center.x + e->radiuses.x);
2107     em_el.rclBox.bottom = htofl(e->center.y + e->radiuses.x);
2108 
2109 # ifdef __EMF_DEBUG__
2110     fprintf(stderr, "Circle rclBox (ltrb): %d %d %d %d\n",
2111 	ftohl(em_el.rclBox.left),  ftohl(em_el.rclBox.top),
2112 	ftohl(em_el.rclBox.right), ftohl(em_el.rclBox.bottom));
2113 # endif
2114 
2115     emh_write(&em_el, sizeof(EMRELLIPSE), (size_t) 1, EMH_RECORD);
2116 }/* end circle */
2117 
2118 
2119 /* non-rotated ellipses */
ellipse(e)2120 static void ellipse(e)
2121     F_ellipse *e;
2122 {
2123     EMRELLIPSE em_el;
2124 
2125     em_el.emr.iType = htofl(EMR_ELLIPSE);
2126     em_el.emr.nSize = htofl(sizeof(EMRELLIPSE));
2127     em_el.rclBox.left   = htofl(e->center.x - e->radiuses.x);
2128     em_el.rclBox.top    = htofl(e->center.y - e->radiuses.y);
2129     em_el.rclBox.right  = htofl(e->center.x + e->radiuses.x);
2130     em_el.rclBox.bottom = htofl(e->center.y + e->radiuses.y);
2131 
2132 # ifdef __EMF_DEBUG__
2133     fprintf(stderr, "Ellipse rclBox (ltrb): %d %d %d %d\n",
2134 	ftohl(em_el.rclBox.left),  ftohl(em_el.rclBox.top),
2135 	ftohl(em_el.rclBox.right), ftohl(em_el.rclBox.bottom));
2136 # endif
2137 
2138     emh_write(&em_el, sizeof(EMRELLIPSE), (size_t) 1, EMH_RECORD);
2139 }/* end ellipse */
2140 
2141 
2142 /* draw rotated ellipse as a polygon */
2143 #define ELLIPSE_NPOINT	72
rotated_ellipse(e)2144 static void rotated_ellipse(e)
2145     F_ellipse *e;
2146 {
2147     F_line l;
2148     F_point pnt[ELLIPSE_NPOINT];
2149     int i;
2150     const double delta = 2 * M_PI / (double)ELLIPSE_NPOINT;
2151     double th;
2152     double sina = sin(e->angle), cosa = cos(e->angle);
2153     double ex, ey;
2154 
2155     for (i = 0; i < ELLIPSE_NPOINT; i++) {
2156 	th = delta * i;
2157 	ex = (double) e->radiuses.x * cos(th);
2158 	ey = (double) e->radiuses.y * sin(th);
2159 	pnt[i].x = e->center.x + (int) (cosa * ex + sina * ey);
2160 	pnt[i].y = e->center.y + (int) (-sina * ex + cosa * ey);
2161 	pnt[i].next = &pnt[i + 1];
2162     }
2163     pnt[ELLIPSE_NPOINT - 1].next = NULL;
2164 
2165     /*
2166      * fabricate polygon structure
2167      */
2168 
2169     /* copy common fields */
2170 
2171     l.style = e->style;
2172     l.thickness = e->thickness;
2173     l.pen_color = e->pen_color;
2174     l.fill_color = e->fill_color;
2175     l.depth = e->depth;
2176     l.pen = e->pen;
2177     l.fill_style = e->fill_style;
2178     l.style_val = e->style_val;
2179 
2180     /* setup other fields */
2181     l.points = pnt;
2182     l.type = T_POLYGON;
2183 
2184     /* just in case... */
2185     l.for_arrow = l.back_arrow = NULL;
2186     l.cap_style = 0;
2187     l.join_style = 0;
2188     l.radius = 0;
2189     l.pic = NULL;
2190     l.comments = NULL;
2191     l.next = NULL;
2192 
2193     shape(&l, 0, 0, polygon);
2194 }/* end rotated_ellipse */
2195 
2196 
2197 /* Integer cross product */
icprod(x1,y1,x2,y2)2198 static int icprod(x1, y1, x2, y2)
2199     int x1, y1, x2, y2;
2200 {
2201 
2202     return x1 * y2 - y1 * x2;
2203 }/* end icprod */
2204 
2205 
2206 /* Returns True if the arc is a clockwise arc. */
cwarc(a)2207 static int cwarc(a)
2208     F_arc *a;
2209 {
2210     int x1 = a->point[1].x - a->point[0].x,
2211 	y1 = a->point[1].y - a->point[0].y,
2212 	x2 = a->point[2].x - a->point[1].x,
2213 	y2 = a->point[2].y - a->point[1].y;
2214 
2215     return (icprod(x1,y1,x2,y2) > 0);
2216 }/* end cwarc */
2217 
2218 
2219 /* Computes distance and normalized direction vector from q to p.
2220  * returns True if the points do not coincide and False if they do. */
direction(p,q,dir,dist)2221 static int direction(p, q, dir, dist)
2222     F_point	*p;
2223     F_point	*q;
2224     Dir		*dir;
2225     double	*dist;
2226 {
2227 
2228     dir->x = p->x - q->x;
2229     dir->y = p->y - q->y;
2230     *dist = sqrt((dir->x) * (dir->x) + (dir->y) * (dir->y));
2231     if (*dist < EPSILON)
2232 	return False;
2233     dir->x /= *dist;
2234     dir->y /= *dist;
2235     return True;
2236 }/* end direction */
2237 
2238 
distance(x1,y1,x2,y2)2239 static double distance(x1, y1, x2, y2)
2240     double x1, y1, x2, y2;
2241 {
2242     double dx = x2-x1, dy=y2-y1;
2243 
2244     return sqrt(dx*dx + dy*dy);
2245 }/* end distance */
2246 
2247 
2248 /* Write an enhanced metarecord and keep track of number of bytes written
2249  * and number of records written in the global header record "emh". */
emh_write(ptr,size,nmemb,flag)2250 static size_t emh_write(ptr, size, nmemb, flag)
2251     const void *ptr;
2252     size_t	size;
2253     size_t	nmemb;
2254     emh_flag	flag;
2255 {
2256 
2257     if (flag == EMH_RECORD) emh_nRecords++;
2258     emh_nBytes += size * nmemb;
2259     return fwrite(ptr, size, nmemb, tfp);
2260 }/* end emh_write */
2261 
2262 
is_flip(rot,flip)2263 static int is_flip(rot, flip)
2264     int rot, flip;
2265 {
2266 
2267     return (rot == 90 || rot == 270) ? !flip : flip;
2268 }
2269 
2270 
encode_bitmap(pic,bpp,rot)2271 static void encode_bitmap(pic, bpp, rot)
2272     F_pic *pic;
2273     int bpp, rot;
2274 {
2275     int img_w = pic->bit_size.x;
2276     int img_h = pic->bit_size.y;
2277     int flip;
2278     int i, initi, endi, diri;
2279     int j, initj, endj, dirj;
2280     int pos;
2281     int freebits = 32;
2282     unsigned bits = 0;
2283     unsigned char cbits[4];
2284     unsigned u;
2285 
2286     /*
2287      * Note: on EMF, you must output the image
2288      * from left to right and FROM BOTTOM TO TOP.
2289      */
2290     switch (rot) {
2291     case 0:	diri =  1; dirj = -1; break;
2292     case 90:	diri =  1; dirj =  1; break;
2293     case 180:	diri = -1; dirj =  1; break;
2294     case 270:	diri = -1; dirj = -1; break;
2295     default:
2296 	fprintf(stderr, "fig2dev: emf: pic rotation %d is not supported\n",
2297 		rot);
2298 	return;
2299 	/*NOTREACHED*/
2300 	break;
2301     }
2302 
2303     if (pic->flipped && (rot == 0 || rot == 180)) {
2304 	diri = -diri;
2305 	dirj = -dirj;
2306     }
2307 
2308     flip = is_flip(rot, pic->flipped);
2309 
2310     if (diri < 0) {
2311 	initi = img_w - 1; endi = 0;
2312     } else {
2313 	initi = 0; endi = img_w - 1;
2314     }
2315     if (dirj < 0) {
2316 	initj = img_h - 1; endj = 0;
2317     } else {
2318 	initj = 0; endj = img_h - 1;
2319     }
2320 
2321 #   define SWAP(v1, v2) do { int tmp = v1; v1 = v2; v2 = tmp; } while (0)
2322     if (flip) {
2323 	SWAP(initi, initj);
2324 	SWAP(endi, endj);
2325 	SWAP(diri, dirj);
2326     }
2327 #   undef SWAP
2328 
2329 #   define WRITEBITS	\
2330 	    do {/* MSB first */						\
2331 		cbits[0] = bits >> 24; cbits[1] = bits >> 16;		\
2332 		cbits[2] = bits >> 8; cbits[3] = bits;			\
2333 		emh_write(cbits, (size_t) 4, (size_t) 1, EMH_DATA);	\
2334 		freebits = 32;						\
2335 		bits = 0;						\
2336 	    } while (0)
2337 
2338     endi += diri;
2339     endj += dirj;
2340     for (j = initj; j != endj; j += dirj) {
2341 	for (i = initi; i != endi; i += diri) {
2342 	    /*
2343 	     * normal: x: i, y: j
2344 	     * flip:   x: j, y: i
2345 	     */
2346 	    pos = flip ? i * img_w + j : j * img_w + i;
2347 
2348 	    switch (bpp) {
2349 	    case 1: case 4: case 8:
2350 		freebits -= bpp;
2351 		bits |= pic->bitmap[pos] << freebits;
2352 		if (freebits == 0)
2353 		    WRITEBITS;
2354 		break;
2355 	    case 24:
2356 		for (u = 0; u < 3; u++) {
2357 		    freebits -= 8;
2358 		    bits |= pic->bitmap[pos*3 + u] << freebits;
2359 		    if (freebits == 0)
2360 			WRITEBITS;
2361 		}
2362 		break;
2363 	    default:
2364 		/* should not happen */
2365 		fprintf(stderr, "unsupported bpp %d\n", bpp);
2366 		break;
2367 	    }
2368 	}
2369 	/* size of a line of EMF bitmap must be a multiple of 4 byte */
2370 	if (freebits != 32)
2371 	    WRITEBITS;
2372     }
2373 #   undef WRITEBITS
2374 }
2375 
2376 
picbox(l)2377 static void picbox(l)
2378     F_line *l;
2379 {
2380     EMRSTRETCHDIBITS em_sd;
2381     BITMAPINFO bmi;
2382     char buf[512], realname[PATH_MAX];
2383     int filtype;
2384     int dx, dy;
2385     FILE *picf;
2386     int pllx, plly;
2387     int img_w, img_h;
2388     int rotation;
2389     size_t bsize, coltabsize;
2390     int bpp;
2391     unsigned ncol;
2392     static RGBQUAD coltab[256];
2393     unsigned u;
2394     int flip;
2395 
2396     dx = l->points->next->next->x - l->points->x;
2397     dy = l->points->next->next->y - l->points->y;
2398 
2399     /* rotation (counter clockwise) */
2400     rotation = 0;
2401     if (dx < 0 && dy < 0)
2402        rotation = 180;
2403     else if (dx < 0 && dy >= 0)
2404        rotation = 270;
2405     else if (dy < 0 && dx >= 0)
2406        rotation = 90;
2407 
2408     if ((picf = open_picfile(l->pic->file, &filtype, True, realname)) == NULL) {
2409 	fprintf(stderr, "fig2dev: %s: No such picture file\n", l->pic->file);
2410 	return;
2411     }
2412     if (fread(buf, (size_t) 16, (size_t) 1, picf) != 1) {
2413 	fprintf(stderr, "fig2dev: %s: short read\n", l->pic->file);
2414 	close_picfile(picf, filtype);
2415 	return;
2416     }
2417     close_picfile(picf, filtype);
2418 
2419     memset(&em_sd, 0, sizeof(EMRSTRETCHDIBITS));
2420     em_sd.emr.iType = htofl(EMR_STRETCHDIBITS);
2421 
2422     memset(&bmi, 0, sizeof(BITMAPINFO));
2423     bmi.bmiHeader.biSize = htofl(sizeof(BITMAPINFOHEADER));
2424 
2425 #ifdef USE_PNG
2426     if (strncmp(buf, "\211\120\116\107\015\012\032\012", (size_t) 8) == 0) {
2427 	/* png file */
2428 	if ((picf = open_picfile(l->pic->file, &filtype, True, realname)) == NULL) {
2429 	    perror(l->pic->file);
2430 	    return;
2431 	}
2432 	if (read_png(picf, filtype, l->pic, &pllx, &plly) == 0) {
2433 	    fprintf(stderr, "fig2dev: %s: illegal format\n", l->pic->file);
2434 	    close_picfile(picf, filtype);
2435 	    return;
2436 	}
2437 	close_picfile(picf, filtype);
2438     }
2439 #endif
2440     if (l->pic->subtype == P_GIF || l->pic->subtype == P_PCX ||
2441 	l->pic->subtype == P_JPEG || l->pic->subtype == P_PNG) {
2442 
2443 	img_w = l->pic->bit_size.x;
2444 	img_h = l->pic->bit_size.y;
2445 	ncol = l->pic->numcols;
2446 
2447 	flip = is_flip(rotation, l->pic->flipped);
2448 
2449 	/* EMF bitmap requires the every scan line be a multiple of 4 byte */
2450 	if (ncol <= 2) {
2451 	    bpp = 1;
2452 	    bsize = (flip ? (img_h + 31) / 32 * img_w :
2453 			    (img_w + 31) / 32 * img_h) * 4;
2454 	    coltabsize = 2 * sizeof(RGBQUAD);
2455 	} else if (ncol <= 16) {
2456 	    bpp = 4;
2457 	    bsize = (flip ? (img_h + 7) / 8 * img_w :
2458 			    (img_w + 7) / 8 * img_h) * 4;
2459 	    coltabsize = ncol * sizeof(RGBQUAD);
2460 	} else if (ncol <= 256) {
2461 	    bpp = 8;
2462 	    bsize = (flip ? (img_h + 3) / 4 * img_w :
2463 			    (img_w + 3) / 4 * img_h) * 4;
2464 	    coltabsize = ncol * sizeof(RGBQUAD);
2465 	} else {
2466 	    bpp = 24;
2467 	    bsize = (flip ? (img_h * 3 + 3) / 4 * img_w :
2468 			    (img_w * 3 + 3) / 4 * img_h) * 4;
2469 	    coltabsize = 0;
2470 	}
2471 
2472 # ifdef __EMF_DEBUG__
2473 	fprintf(stderr, "PicBox: %s: %u cols, %d bpp, bsize %u, img(%d,%d), fig(%d,%d)\n",
2474 	    l->pic->file, ncol, bpp, bsize, img_w, img_h, dx, dy);
2475 # endif
2476 
2477 	if (dx >= 0) {
2478 	    em_sd.xDest = em_sd.rclBounds.left = htofl(l->points->x);
2479 	    em_sd.rclBounds.right = htofl(l->points->next->next->x);
2480 	    em_sd.cxDest = htofl(dx);
2481 	} else {
2482 	    em_sd.xDest = em_sd.rclBounds.left =htofl(l->points->next->next->x);
2483 	    em_sd.rclBounds.right = htofl(l->points->x);
2484 	    em_sd.cxDest = htofl(-dx);
2485 	}
2486 	if (dy >= 0) {
2487 	    em_sd.yDest = em_sd.rclBounds.top = htofl(l->points->y);
2488 	    em_sd.rclBounds.bottom = htofl(l->points->next->next->y);
2489 	    em_sd.cyDest = htofl(dy);
2490 	} else {
2491 	    em_sd.yDest = em_sd.rclBounds.top = htofl(l->points->next->next->y);
2492 	    em_sd.rclBounds.bottom = htofl(l->points->y);
2493 	    em_sd.cyDest = htofl(-dy);
2494 	}
2495 
2496 	/* em_sd.xSrc = em_sd.ySrc = htofl(0);		already cleared */
2497 
2498 	if (flip) {
2499 	    bmi.bmiHeader.biWidth  = em_sd.cxSrc = htofl(img_h);
2500 	    bmi.bmiHeader.biHeight = em_sd.cySrc = htofl(img_w);
2501 	} else {
2502 	    bmi.bmiHeader.biWidth  = em_sd.cxSrc = htofl(img_w);
2503 	    bmi.bmiHeader.biHeight = em_sd.cySrc = htofl(img_h);
2504 	}
2505 
2506 	/* em_sd.iUsageSrc = htofl(DIB_RGB_COLORS);	this is default */
2507 	em_sd.dwRop = htofl(SRCCOPY);
2508 
2509 	em_sd.offBmiSrc = htofl(sizeof(EMRSTRETCHDIBITS));
2510 	em_sd.cbBmiSrc = htofl(sizeof(BITMAPINFO) + coltabsize);
2511 	em_sd.offBitsSrc = htofl(sizeof(EMRSTRETCHDIBITS) +
2512 				 sizeof(BITMAPINFO) + coltabsize);
2513 
2514 	bmi.bmiHeader.biSizeImage = em_sd.cbBitsSrc = htofl(bsize);
2515 
2516 	em_sd.emr.nSize = htofl(sizeof(EMRSTRETCHDIBITS) + sizeof(BITMAPINFO) +
2517 				coltabsize + bsize);
2518 
2519 	bmi.bmiHeader.biPlanes = htofs(1);
2520 	bmi.bmiHeader.biBitCount = htofs(bpp);
2521 	bmi.bmiHeader.biCompression = htofl(BI_RGB);	/* uncompressed */
2522 	bmi.bmiHeader.biXPelsPerMeter =
2523 		bmi.bmiHeader.biYPelsPerMeter = htofl(2953);	/* 75dpi ? */
2524 	if (bpp <= 8)
2525 	    bmi.bmiHeader.biClrUsed = htofl(ncol);
2526 	/* bmi.bmiHeader.biClrImportant = htofl(0); */
2527 
2528 	emh_write(&em_sd, sizeof(EMRSTRETCHDIBITS), (size_t) 1, EMH_RECORD);
2529 	emh_write(&bmi, sizeof(BITMAPINFO), (size_t) 1, EMH_DATA);
2530 
2531 	/* color table */
2532 	if (coltabsize) {
2533 	    coltab[0].rgbBlue = coltab[0].rgbGreen = coltab[0].rgbRed = 0;
2534 	    coltab[1].rgbBlue = coltab[1].rgbGreen = coltab[1].rgbRed = 0;
2535 	    for (u = 0; u < ncol; u++) {
2536 		coltab[u].rgbBlue  = l->pic->cmap[BLUE][u];
2537 		coltab[u].rgbGreen = l->pic->cmap[GREEN][u];
2538 		coltab[u].rgbRed   = l->pic->cmap[RED][u];
2539 	    }
2540 	    emh_write(coltab, coltabsize, (size_t) 1, EMH_DATA);
2541 	}
2542 
2543 	/* bitmap */
2544 	encode_bitmap(l->pic, bpp, rotation);
2545 
2546 	/* need 4 byte align, but the size of EMF bitmap is 4 byte aligned */
2547     } else {
2548 	fprintf(stderr, "fig2dev: %s: emf: unsupported picture format\n",
2549 	    l->pic->file);
2550 	return;
2551     }
2552 }/* end picbox */
2553 
2554 
2555 /* Draws polygon boundary */
polygon(l)2556 static void polygon(l)
2557     F_line *l;
2558 {
2559     F_point *p;
2560     int count;
2561     EMRPOLYGON em_pg;	/* Polygon in little endian format */
2562     POINTL *aptl;
2563     POINTS *apts;
2564     int bbx_top, bbx_bottom, bbx_left, bbx_right;	/* Bounding box */
2565     unsigned  cpt;	/* Number of points in the array */
2566 
2567     /* Calculate the number of points and the bounding box. */
2568     if (!(p = l->points)) return;
2569     bbx_left = p->x;
2570     bbx_top  = p->y;
2571     bbx_right  = p->x;
2572     bbx_bottom = p->y;
2573     for (cpt = 0; p; p = p->next) {
2574 	UPDATE_BBX_X(p->x);
2575 	UPDATE_BBX_Y(p->y);
2576 	cpt++;
2577     }
2578 
2579     /* Windows 95/98/Me: maximum points allowed is approx. 1360 */
2580     if (cpt > 1360 && emflevel != EMF_LEVEL_WINNT)
2581 	fprintf(stderr, "Warning: polygon has too many points -- may be partially invisible\n");
2582 
2583     /* Store bounding box in little endian format */
2584     em_pg.cptl = htofl(cpt);
2585     em_pg.rclBounds.left = htofl(bbx_left);
2586     em_pg.rclBounds.top  = htofl(bbx_top);
2587     em_pg.rclBounds.right  = htofl(bbx_right);
2588     em_pg.rclBounds.bottom = htofl(bbx_bottom);
2589 
2590     if (bbx_left >= -32768 && bbx_right <= 32767
2591 	&& bbx_top >= -32768 && bbx_bottom <= 32767) {
2592 
2593 # ifdef __EMF_DEBUG__
2594     fprintf(stderr, "Polygon16 %d rclBounds (ltrb): %d %d %d %d\n",
2595 	cpt,
2596 	bbx_left,  bbx_top, bbx_right, bbx_bottom);
2597 # endif
2598 
2599 	/* use 16bit point */
2600 	/* Fill the array with the points of the polygon */
2601 	if ((apts = malloc(cpt * sizeof(POINTS))) == NULL) {
2602 	    perror("fig2dev: malloc");
2603 	    exit(1);
2604 	}
2605 	for (p=l->points, count=0; p; p=p->next, count++) {
2606 	    apts[count].x = htofs(p->x);
2607 	    apts[count].y = htofs(p->y);
2608 	}
2609 
2610 	em_pg.emr.iType = htofl(EMR_POLYGON16);
2611 	em_pg.emr.nSize = htofl(sizeof(EMRPOLYGON16) + cpt * sizeof(POINTS));
2612 
2613 	emh_write(&em_pg, sizeof(EMRPOLYGON16), (size_t) 1, EMH_RECORD);
2614 	emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
2615 
2616 	free(apts);
2617     } else {
2618 # ifdef __EMF_DEBUG__
2619     fprintf(stderr, "Polygon %d rclBounds (ltrb): %d %d %d %d\n",
2620 	cpt,
2621 	bbx_left,  bbx_top, bbx_right, bbx_bottom);
2622 # endif
2623 
2624 	/* use 32bit point */
2625 	warn_32bit_pos();
2626 
2627 	/* Fill the array with the points of the polygon */
2628 	if ((aptl = malloc(cpt * sizeof(POINTL))) == NULL) {
2629 	    perror("fig2dev: malloc");
2630 	    exit(1);
2631 	}
2632 	for (p=l->points, count=0; p; p=p->next, count++) {
2633 	    aptl[count].x = htofl(p->x);
2634 	    aptl[count].y = htofl(p->y);
2635 	}
2636 
2637 	em_pg.emr.iType = htofl(EMR_POLYGON);
2638 	em_pg.emr.nSize = htofl(sizeof(EMRPOLYGON) + cpt * sizeof(POINTL));
2639 
2640 	emh_write(&em_pg, sizeof(EMRPOLYGON), (size_t) 1, EMH_RECORD);
2641 	emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
2642 
2643 	free(aptl);
2644     }
2645 }/* end polygon */
2646 
2647 
2648 /* Replaces p by the shortened starting point of the line segment. */
polyline_adjust(p,q,l)2649 static int polyline_adjust(p, q, l)
2650     F_point *p;
2651     F_point *q;
2652     double l;
2653 {
2654     double d; Dir dir;
2655 
2656     if (direction(p, q, &dir, &d)) {
2657 	p->x = round(p->x - l * dir.x);
2658 	p->y = round(p->y - l * dir.y);
2659 	return (l < d);
2660     }
2661     fprintf(stderr, "Warning: Arrow at zero-length line segment omitted.\n");
2662     return True;
2663 }/* end polyline_arrow_adjust */
2664 
2665 
2666 /* Draws polyline boundary (with arrows if needed) */
polyline(l)2667 static void polyline(l)
2668     F_line *l;
2669 {
2670     F_point *p, *q, p0, pn;
2671     Dir dir;
2672     double d;
2673     EMRPOLYLINE em_pl;	/* Polyline in little endian format */
2674     POINTL *aptl;
2675     POINTS *apts;
2676     double alen, seglen;
2677 
2678     int bbx_top, bbx_bottom, bbx_left, bbx_right;	/* Bounding box */
2679     unsigned cpt;	/* Number of points in the array */
2680     unsigned u;
2681 
2682     /* Calculate the number of points and the bounding box. */
2683     if (!(p = l->points)) return;
2684     bbx_left = p->x;
2685     bbx_top  = p->y;
2686     bbx_right  = p->x;
2687     bbx_bottom = p->y;
2688     for (cpt = 0, q = p; p; q = p, p = p->next) {
2689 	UPDATE_BBX_X(p->x);
2690 	UPDATE_BBX_Y(p->y);
2691 	cpt++;
2692     }
2693     p0 = *l->points;	/* first point */
2694     pn = *q;		/* last point */
2695 
2696     if (cpt == 1) {
2697 	/* Draw single point as a short line. */
2698 	cpt = 2;
2699 	pn.y++;
2700     } else {
2701 	/*
2702 	 * Delete line segments which may overlap arrow heads.
2703 	 */
2704 	if (l->back_arrow) {		/* First point with arrow */
2705 	    alen = arrow_length(l->back_arrow);
2706 	    while (cpt > 1) {
2707 		q = p0.next;
2708 		seglen = distance((double)p0.x, (double)p0.y, (double)q->x, (double)q->y);
2709 		if (seglen > alen) {
2710 		    break;
2711 		} else {
2712 		    /* delete this segment */
2713 		    cpt--;
2714 		    p0 = *q;
2715 		    alen -= seglen;
2716 		}
2717 	    }
2718 	    if (cpt > 1)
2719 		polyline_adjust(&p0, p0.next, alen); /* shorten line segment */
2720 	}
2721 	if (l->for_arrow) {	/* Last point with arrow */
2722 	    alen = arrow_length(l->for_arrow);
2723 	    while (cpt > 1) {
2724 		for (p = &p0, u = cpt; --u > 0; q = p, p = p->next)
2725 		    ;
2726 		seglen = distance((double)p->x, (double)p->y, (double)q->x, (double)q->y);
2727 		if (seglen > alen) {
2728 		    break;
2729 		} else {
2730 		    /* delete this segment */
2731 		    cpt--;
2732 		    pn = *q;
2733 		    alen -= seglen;
2734 		}
2735 	    }
2736 	    if (cpt > 1)
2737 		polyline_adjust(&pn, q, alen);	/* shorten line segment */
2738 	}
2739 	if (cpt <= 1)		/* if all line segments are removed, */
2740 	    goto draw_arrows;	/* skip drawing line segments */
2741     }
2742 
2743     /* Windows 95/98/Me: maximum points allowed is approx. 1360 */
2744     if (cpt > 1360 && emflevel != EMF_LEVEL_WINNT)
2745 	fprintf(stderr, "Warning: polyline has too many points -- may be partially invisible\n");
2746 
2747     /* Store bounding box in little endian format */
2748     em_pl.cptl = htofl(cpt);
2749     em_pl.rclBounds.left = htofl(bbx_left);
2750     em_pl.rclBounds.top  = htofl(bbx_top);
2751     em_pl.rclBounds.right  = htofl(bbx_right);
2752     em_pl.rclBounds.bottom = htofl(bbx_bottom);
2753 
2754     if (bbx_left >= -32768 && bbx_right <= 32767
2755 	&& bbx_top >= -32768 && bbx_bottom <= 32767) {
2756 
2757 # ifdef __EMF_DEBUG__
2758     fprintf(stderr, "Polyline16 %d rclBounds (ltrb): %d %d %d %d\n",
2759 	cpt,
2760 	bbx_left,  bbx_top, bbx_right, bbx_bottom);
2761 # endif
2762 
2763 	/* use 16bit point */
2764 	/* Fill the array with the points of the polyline */
2765 	if ((apts = malloc(cpt * sizeof(POINTS))) == NULL) {
2766 	    perror("fig2dev: malloc");
2767 	    exit(1);
2768 	}
2769 	for (p = &p0, u = 0; u + 1 < cpt; p= p->next, u++) {
2770 	    apts[u].x = htofs(p->x);
2771 	    apts[u].y = htofs(p->y);
2772 	}
2773 	apts[u].x = htofs(pn.x);
2774 	apts[u].y = htofs(pn.y);
2775 
2776 	em_pl.emr.iType = htofl(EMR_POLYLINE16);
2777 	HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE16) + cpt * sizeof(POINTS));
2778 
2779 	emh_write(&em_pl, sizeof(EMRPOLYLINE16), (size_t) 1, EMH_RECORD);
2780 	emh_write(apts, sizeof(POINTS), (size_t) cpt, EMH_DATA);
2781 	free(apts);
2782     } else {
2783 
2784 # ifdef __EMF_DEBUG__
2785     fprintf(stderr, "Polyline %d rclBounds (ltrb): %d %d %d %d\n",
2786 	cpt,
2787 	bbx_left,  bbx_top, bbx_right, bbx_bottom);
2788 # endif
2789 
2790 	/* use 32bit point */
2791 	warn_32bit_pos();
2792 
2793 	/* Fill the array with the points of the polyline */
2794 	if ((aptl = malloc(cpt * sizeof(POINTL))) == NULL) {
2795 	    perror("fig2dev: malloc");
2796 	    exit(1);
2797 	}
2798 	for (p = &p0, u = 0; u + 1 < cpt; p= p->next, u++) {
2799 	    aptl[u].x = htofl(p->x);
2800 	    aptl[u].y = htofl(p->y);
2801 	}
2802 	aptl[u].x = htofl(pn.x);
2803 	aptl[u].y = htofl(pn.y);
2804 
2805 	em_pl.emr.iType = htofl(EMR_POLYLINE);
2806 	HTOFL(em_pl.emr.nSize, sizeof(EMRPOLYLINE) + cpt * sizeof(POINTL));
2807 
2808 	emh_write(&em_pl, sizeof(EMRPOLYLINE), (size_t) 1, EMH_RECORD);
2809 	emh_write(aptl, sizeof(POINTL), (size_t) cpt, EMH_DATA);
2810 	free(aptl);
2811     }
2812 
2813 draw_arrows:
2814     if (!l->points->next) {
2815 	if (l->for_arrow || l->back_arrow)
2816 	    fprintf(stderr, "Warning: Arrow at zero-length line segment omitted.\n");
2817 	return;
2818     }		/* At least two different points now */
2819 
2820 
2821     if (l->back_arrow) {
2822 	p = l->points;
2823 	q = l->points->next;
2824 	if (direction(p, q, &dir, &d)) {
2825 	    arrow(p, l->back_arrow, l, &dir);
2826 	}
2827     }
2828 
2829     if (l->for_arrow) {
2830 	for (q=l->points, p=l->points->next; p->next; q=p, p=p->next) {}
2831 	/* q is the one but last point */
2832 	if (direction(p, q, &dir, &d)) {
2833 	    arrow(p, l->for_arrow, l, &dir);
2834 	}
2835     }
2836 }/* end polyline */
2837 
2838 
rect(l)2839 static void rect(l)
2840     F_line *l;
2841 {
2842     EMRRECTANGLE em_rt;
2843 
2844     if (!l->points || !l->points->next || !l->points->next->next) {
2845 	fprintf(stderr, "Warning: Invalid fig box omitted.\n");
2846 	return;
2847     }
2848 
2849     em_rt.emr.iType = htofl(EMR_RECTANGLE);
2850     em_rt.emr.nSize = htofl(sizeof(EMRRECTANGLE));
2851     em_rt.rclBox.left = htofl(l->points->x);
2852     em_rt.rclBox.top  = htofl(l->points->y);
2853     em_rt.rclBox.right  = htofl(l->points->next->next->x);
2854     em_rt.rclBox.bottom = htofl(l->points->next->next->y);
2855 
2856 # ifdef __EMF_DEBUG__
2857     fprintf(stderr, "Rectangle rclBox (ltrb): %d %d %d %d\n",
2858 	ftohl(em_rt.rclBox.left), ftohl(em_rt.rclBox.top),
2859 	ftohl(em_rt.rclBox.right), ftohl(em_rt.rclBox.bottom));
2860 # endif
2861 
2862     emh_write(&em_rt, sizeof(EMRRECTANGLE), (size_t) 1, EMH_RECORD);
2863 }/* end rect */
2864 
2865 
roundrect(l)2866 static void roundrect(l)
2867     F_line *l;
2868 {
2869     EMRROUNDRECT em_rr;
2870 
2871     if (!l->points || !l->points->next || !l->points->next->next) {
2872 	fprintf(stderr, "Warning: Invalid fig box omitted.\n");
2873 	return;
2874     }
2875 
2876     em_rr.emr.iType = htofl(EMR_ROUNDRECT);
2877     em_rr.emr.nSize = htofl(sizeof(EMRROUNDRECT));
2878     em_rr.rclBox.left = htofl(l->points->x);
2879     em_rr.rclBox.top  = htofl(l->points->y);
2880     em_rr.rclBox.right  = htofl(l->points->next->next->x);
2881     em_rr.rclBox.bottom = htofl(l->points->next->next->y);
2882     em_rr.szlCorner.cx = em_rr.szlCorner.cy = htofl(l->radius * 2);
2883 
2884 # ifdef __EMF_DEBUG__
2885     fprintf(stderr, "RoundRectangle rclBox (ltrb): %d %d %d %d\n",
2886 	ftohl(em_rr.rclBox.left), ftohl(em_rr.rclBox.top),
2887 	ftohl(em_rr.rclBox.right), ftohl(em_rr.rclBox.bottom));
2888 # endif
2889 
2890     emh_write(&em_rr, sizeof(EMRROUNDRECT), (size_t) 1, EMH_RECORD);
2891 }
2892 
2893 
2894 /* Draws interior and outline of a simple closed shape.  Cannot be
2895  * used for polylines and arcs (open shapes) or for arcboxes
2896  * (closed but not a simple emf primitive). */
shape(l,join,cap,drawshape)2897 static void shape(l, join, cap, drawshape)
2898     F_line *l;
2899     int join;		/* join style */
2900     int cap;		/* cap style */
2901     void (*drawshape)(F_line *);
2902 {
2903 
2904     edgeattr(1, l->style, l->thickness, l->pen_color, join, cap);
2905     fillstyle(l->fill_color, l->fill_style, l->pen_color);
2906     drawshape(l);
2907 }/* end shape */
2908 
2909 
2910 /* Draws interior of a closed shape, taking into account fill color
2911  * and pattern.  Boundary must be drawn separately.  Used for
2912  * polylines, arcboxes and arcs. */
shape_interior(l,drawshape)2913 static void shape_interior(l, drawshape)
2914     F_line *l;
2915     void (*drawshape)(F_line *);
2916 {
2917 
2918     if (l->fill_style >= 0) {
2919 	edgevis(0);				/* Don't draw edges */
2920 	fillstyle(l->fill_color, l->fill_style, l->pen_color);
2921 	drawshape(l);
2922     }
2923 }/* end shape_interior */
2924 
2925 
2926 /* Converts regular strings to unicode strings.  If the utext pointer is
2927  * null, memory is allocated.  Note, that carriage returns are converted
2928  * to nulls. */
textunicode(str,n_chars,utext,n_unicode)2929 static void textunicode(str, n_chars, utext, n_unicode)
2930     char   *str;
2931     int    *n_chars;
2932     short  **utext;		/* If *utext is null, memory is allocated */
2933     int    *n_unicode;
2934 {
2935 #if defined(I18N) && defined(USE_ICONV)
2936     iconv_t icd = (iconv_t) -1;
2937     const char *src;
2938     char *dst, *p;
2939     size_t srcleft, srccnt, dstleft, dstcnt;
2940     int i;
2941 
2942     if (figLanguage != LANG_DEFAULT) {
2943 	if ((icd = iconv_open(EMF_ICONV_CODESET, iconvCharset[figLanguage])) ==
2944 		(iconv_t) -1)
2945 	    perror("genemf: iconv");
2946     }
2947 
2948     src = str;
2949     srcleft = srccnt = strlen(str);
2950     if ((dst = (char *) *utext) == NULL) {
2951 	dst = (char *) (*utext = calloc(srcleft + 2/*null termination + align*/,
2952 	    sizeof(short)));
2953 	dstleft = dstcnt = srcleft * sizeof(short);
2954     } else
2955 	dstleft = dstcnt = *n_unicode;
2956 
2957     if (icd != (iconv_t) -1) {
2958 	if (iconv(icd, &src, &srcleft, &dst, &dstleft) == (size_t) -1)
2959 	    fprintf(stderr, "genemf: iconv: illegal byte sequence\n");
2960 
2961 	(void) iconv_close(icd);
2962 
2963 	*n_chars = srccnt - srcleft;
2964 	*n_unicode = dstcnt - dstleft;
2965 
2966 	/* Convert '\n' to 0 */
2967 	p = (void *)*utext;
2968 	for (i = 0; i < *n_unicode; i += 2) {
2969 #ifdef EMF_ICONV_NEED_SWAP
2970 	    /* swap byte order */
2971 	    char c = p[i];
2972 	    p[i] = p[i + 1];
2973 	    p[i + 1] = c;
2974 #endif
2975 	    if (p[i] == '\n' && p[i+1] == 0)
2976 		p[i] = 0;
2977 	}
2978     } else {
2979 	*n_chars = srccnt;
2980 	*n_unicode = srccnt * 2;
2981 	for (i = 0; i < srccnt; i++) {
2982 	    if (str[i] == '\n')
2983 		(*utext)[i] = 0;
2984 	    else
2985 		(*utext)[i] = htofs(str[i]);
2986 	}
2987     }
2988 #else	/* !(defined(I18N) && defined(USE_ICONV)) */
2989     int    i;
2990 
2991     *n_chars = strlen(str);
2992     *n_unicode = *n_chars * 2;
2993     if (*utext == NULL) {
2994 	*utext = (short *)calloc((size_t) *n_unicode + 4 /* null + align */,
2995 	    (size_t) 1);
2996     }
2997     for (i = 0; i < *n_chars; i++) {		/* Convert to unicode. */
2998 	if (str[i] == '\n') {
2999 	    (*utext)[i] = 0;
3000 	} else {
3001 	    (*utext)[i] = htofs(str[i]);
3002 	}
3003     }
3004 #endif
3005 }/* end textunicode */
3006 
3007 
text(x,y,bbx,str)3008 static void text(x, y, bbx, str)
3009     int     x, y;		/* reference point */
3010     RECTL  *bbx;		/* bounding box */
3011     char   *str;
3012 {
3013     int    n_chars, n_unicode;
3014     short	 *utext = NULL;
3015     EMREXTTEXTOUTW em_tx;	/* Text structure in little endian format */
3016 
3017     memset(&em_tx, 0, sizeof(EMREXTTEXTOUTW));
3018     em_tx.emr.iType = htofl(EMR_EXTTEXTOUTW);
3019 
3020     em_tx.rclBounds = *bbx;
3021 
3022 # ifdef __EMF_DEBUG__
3023     fprintf(stderr, "Textout |%s| rclBounds (ltrb): %d %d %d %d\n",
3024 	str,
3025 	ftohl(em_tx.rclBounds.left),  ftohl(em_tx.rclBounds.top),
3026 	ftohl(em_tx.rclBounds.right), ftohl(em_tx.rclBounds.bottom));
3027 # endif
3028 
3029     em_tx.iGraphicsMode = htofl(GM_COMPATIBLE);
3030     em_tx.exScale.bit_uint = htofl(PIXEL_01MM_BITPATTERN);
3031     em_tx.eyScale.bit_uint = htofl(PIXEL_01MM_BITPATTERN);
3032 
3033     em_tx.emrtext.ptlReference.x = htofl(x);
3034     em_tx.emrtext.ptlReference.y = htofl(y);
3035 
3036     textunicode(str, &n_chars, &utext, &n_unicode);
3037 
3038     em_tx.emrtext.nChars = htofl(n_unicode / 2); /* number of unicode chars */
3039     em_tx.emrtext.offString = htofl(sizeof(EMREXTTEXTOUTW));
3040 
3041     n_unicode = (n_unicode + 4) & ~3;	/* null termination + align */
3042     em_tx.emr.nSize = htofl(sizeof(EMREXTTEXTOUTW) + n_unicode);
3043 
3044     emh_write(&em_tx, sizeof(EMREXTTEXTOUTW), (size_t) 1, EMH_RECORD);
3045     emh_write(utext, (size_t) 1, (size_t) n_unicode, EMH_DATA);
3046 
3047     free(utext);
3048 }/* end text */
3049 
3050 
textcolr(color)3051 static void textcolr(color)
3052     int color;
3053 {
3054     static int oldcolor = UNDEFVALUE;
3055     EMRSETTEXTCOLOR em_tc;
3056 
3057     bkmode(TRANSPARENT);		/* fig doesn't have text background */
3058     chkcache(color, oldcolor);
3059 
3060     memset(&em_tc, 0, sizeof(EMRSETTEXTCOLOR));
3061     em_tc.emr.iType = htofl(EMR_SETTEXTCOLOR);
3062     em_tc.emr.nSize = htofl(sizeof(EMRSETTEXTCOLOR));
3063     HTOFL(em_tc.crColor, conv_color(color));
3064 
3065 # ifdef __EMF_DEBUG__
3066     fprintf(stderr, "SetTextColor (rgb): %x\n", ftohl(em_tc.crColor));
3067 # endif
3068 
3069     emh_write(&em_tc, sizeof(EMRSETTEXTCOLOR), (size_t) 1, EMH_RECORD);
3070 }/* end textcolr */
3071 
3072 
textalign(align)3073 static void textalign(align)
3074     int align;
3075 {
3076     static int oldalign = TA_LEFT|TA_TOP|TA_NOUPDATECP;	/* startup default */
3077     EMRSETTEXTALIGN em_ta;
3078 
3079     chkcache(align, oldalign);
3080     em_ta.emr.iType = htofl(EMR_SETTEXTALIGN);
3081     em_ta.emr.nSize = htofl(sizeof(EMRSETTEXTALIGN));
3082     em_ta.iMode = htofl(align);
3083 
3084 # ifdef __EMF_DEBUG__
3085     fprintf(stderr, "SetTextAlign (mode): 0x%x\n", align);
3086 # endif
3087 
3088     emh_write(&em_ta, sizeof(EMRSETTEXTALIGN), (size_t) 1, EMH_RECORD);
3089 }
3090 
3091 
3092 #if defined(I18N) && defined(USE_ICONV)
moveto(x,y)3093 static void moveto(x, y)
3094     int x, y;
3095 {
3096     EMRMOVETOEX em_mv;
3097 
3098     em_mv.emr.iType = htofl(EMR_MOVETOEX);
3099     em_mv.emr.nSize = htofl(sizeof(EMRMOVETOEX));
3100     em_mv.ptl.x = htofl(x);
3101     em_mv.ptl.y = htofl(y);
3102 
3103 # ifdef __EMF_DEBUG__
3104     fprintf(stderr, "MoveTo (x, y): %d, %d\n", x, y);
3105 # endif
3106 
3107     emh_write(&em_mv, sizeof(EMRMOVETOEX), (size_t) 1, EMH_RECORD);
3108 }
3109 #endif	/* defined(I18N) && defined(USE_ICONV) */
3110 
3111 
3112 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_option(opt,optarg)3113 void genemf_option(opt, optarg)
3114     char	 opt;
3115     char	*optarg;
3116 {
3117 
3118     rounded_arrows = False;
3119     switch (opt) {
3120     case 'r':
3121 	rounded_arrows = True;
3122 	break;
3123 
3124     case 'l':
3125 	if (strcasecmp(optarg, "win95") == 0)
3126 	    emflevel = EMF_LEVEL_WIN95;
3127 	else if (strcasecmp(optarg, "win98") == 0)
3128 	    emflevel = EMF_LEVEL_WIN98;
3129 	else if (strcasecmp(optarg, "winnt") == 0)
3130 	    emflevel = EMF_LEVEL_WINNT;
3131 	else
3132 	    fprintf(stderr, "warning: unknown level %s ignored\n", optarg);
3133 	break;
3134 
3135     case 'f':	/* Ignore magnification, font sizes and lang here */
3136     case 'm':
3137     case 's':
3138     case 'L':
3139 	break;
3140 
3141     default:
3142 	put_msg(Err_badarg, opt, "emf");
3143 	exit(1);
3144     }
3145 }/* end genemf_option */
3146 
3147 
3148 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_start(objects)3149 void genemf_start(objects)
3150      F_compound	*objects;
3151 {
3152     EMRSETMAPMODE em_sm;
3153     short *uni_description = NULL;	/* Unitext description. */
3154     int n_chars, n_unicode;
3155     F_comment comm, *p;
3156     size_t commlen;
3157     short *ud;
3158     char *figname;
3159 
3160 #if defined(I18N) && defined(USE_ICONV)
3161     if (support_i18n) {
3162 	char *locale;
3163 
3164 	locale = getenv("LANG");
3165 	if (locale == NULL) {
3166 	    fprintf(stderr, "fig2dev: LANG not defined; assuming C locale\n");
3167 	    locale = "C";
3168 	}
3169 	if (strncmp(locale, "zh_CN", (size_t) 5) == 0)
3170 	    figLanguage = LANG_ZH_CN;
3171 	else if (strncmp(locale, "zh_TW", (size_t) 5) == 0)
3172 	    figLanguage = LANG_ZH_TW;
3173 	else if (strncmp(locale, "ja", (size_t) 2) == 0)
3174 	    figLanguage = LANG_JA;
3175 	else if (strncmp(locale, "ko", (size_t) 2) == 0)
3176 	    figLanguage = LANG_KO;
3177     }
3178 #endif
3179 
3180     memset(&emh, 0, sizeof(ENHMETAHEADER));
3181     emh.iType = htofl(EMR_HEADER);
3182 
3183     emh.dSignature = htofl(ENHMETA_SIGNATURE);
3184     emh.nVersion = htofl(ENHMETA_VERSION);
3185     emh_nHandles = 0;
3186     handles = NULL;
3187     latesthandle = (void *) &handles;
3188 
3189     memset(lasthandle, 0, sizeof(lasthandle));	/* Initialize the DC handles */
3190 
3191     /* Create a description string. */
3192 
3193     if (from)
3194 	figname=from;
3195     else
3196 	figname=strdup("stdin");
3197 
3198     comm.next = objects->comments;
3199     if ((comm.comment = malloc(strlen(figname) +
3200 		80 + sizeof VERSION + sizeof PATCHLEVEL)) == NULL) {
3201 	perror("fig2dev: malloc");
3202 	exit(1);
3203     }
3204     sprintf(comm.comment,
3205 	"Converted from %s using fig2dev %s.%s for %s",
3206        figname, VERSION, PATCHLEVEL, emflevelname[emflevel]);
3207 
3208     /* prescan comment strings and (over)estimate the total length */
3209     commlen = 0;
3210     for (p = &comm; p; p = p->next)
3211 	commlen += strlen(p->comment) + 1;
3212 
3213     commlen = commlen * 2 + 2;	/* 2byte/char (+ align) */
3214     if ((uni_description = malloc(commlen)) == NULL) {
3215 	perror("fig2dev: malloc");
3216 	exit(1);
3217     }
3218 
3219     /* convert comment strings to unicode */
3220     ud = uni_description;
3221     for (p = &comm; p; p = p->next) {
3222 # ifdef __EMF_DEBUG__
3223 	fprintf(stderr, "%s\n", p->comment);
3224 # endif
3225 	n_unicode = commlen;
3226 	textunicode(p->comment, &n_chars, &ud, &n_unicode);
3227 	commlen -= n_unicode;
3228 	ud += n_unicode/2;
3229 	*ud++ = 0;
3230     }
3231     *ud = 0;	/* for align */
3232     n_unicode = (char *)ud - (char *)uni_description;	/* length in byte */
3233 
3234     emh.nDescription = htofl(n_unicode / 2);
3235     emh.offDescription = htofl(sizeof(ENHMETAHEADER));
3236 
3237     /* The size of the reference device in pixels.  We will define a pixel
3238      * in xfig uints of 1200 dots per inch and we'll use an 250 x 200 mm
3239      * or 10.24 x 8.46 inch viewing area. */
3240 
3241     emh.szlMillimeters.cx = htofl(260);		/* 10.24 inches wide. */
3242     emh.szlMillimeters.cy = htofl(215);		/*  8.46 inches high. */
3243 
3244     HTOFL(emh.szlDevice.cx, round(260 * 47.244094));
3245     HTOFL(emh.szlDevice.cy, round(215 * 47.244094));
3246 
3247     /* Inclusive-inclusive bounds in device units (1200 dpi) and
3248      * 0.01 mm units.  Add 1/20 inch all the way around. */
3249 
3250     emh.rclBounds.left   = htofl(llx - 48);
3251     emh.rclBounds.top    = htofl(lly - 48);
3252     emh.rclBounds.right  = htofl(urx + 48);
3253     emh.rclBounds.bottom = htofl(ury + 48);
3254 
3255     HTOFL(emh.rclFrame.left,  floor((llx - 48) * PIXEL_01MM));
3256     HTOFL(emh.rclFrame.top,   floor((lly - 48) * PIXEL_01MM));
3257     HTOFL(emh.rclFrame.right,  ceil((urx + 48) * PIXEL_01MM));
3258     HTOFL(emh.rclFrame.bottom, ceil((ury + 48) * PIXEL_01MM));
3259 
3260 # ifdef __EMF_DEBUG__
3261     fprintf(stderr, "rclBounds (ltrb): %d %d %d %d\n",
3262 	ftohl(emh.rclBounds.left),  ftohl(emh.rclBounds.top),
3263 	ftohl(emh.rclBounds.right), ftohl(emh.rclBounds.bottom));
3264     fprintf(stderr, "rclFrame  (ltrb): %d %d %d %d\n",
3265 	ftohl(emh.rclFrame.left),  ftohl(emh.rclFrame.top),
3266 	ftohl(emh.rclFrame.right), ftohl(emh.rclFrame.bottom));
3267 # endif
3268 
3269     n_unicode = (n_unicode + 3) & ~3;	/* null termination + align */
3270     emh.nSize = htofl(sizeof(ENHMETAHEADER) + n_unicode);
3271 
3272     emh_write(&emh, sizeof(ENHMETAHEADER), (size_t) 1, EMH_RECORD);
3273     emh_write(uni_description, (size_t) 1, (size_t) n_unicode, EMH_DATA);
3274 
3275     /* The SetMapMode function sets the mapping mode of the specified
3276      * device context.  The mapping mode defines the unit of measure used
3277      * to transform page-space units into device-space units, and also
3278      * defines the orientation of the device's x and y axes. */
3279     em_sm.emr.iType = htofl(EMR_SETMAPMODE);
3280     em_sm.emr.nSize = htofl(sizeof(EMRSETMAPMODE));
3281 
3282     /* MM_TEXT Each logical unit is mapped to one device pixel.  Positive
3283      * x is to the right; positive y is down.  The MM_TEXT mode allows
3284      * applications to work in device pixels, whose size varies from device
3285      * to device. */
3286     em_sm.iMode = htofl(MM_TEXT);
3287 # ifdef __EMF_DEBUG__
3288     fprintf(stderr, "SetMapMode: %d\n", ftohl(em_sm.iMode));
3289 # endif
3290     emh_write(&em_sm, sizeof(EMRSETMAPMODE), (size_t) 1, EMH_RECORD);
3291 
3292     free(comm.comment);
3293     free(uni_description);
3294 }/* end genemf_start */
3295 
3296 
3297 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_arc(_a)3298 void genemf_arc(_a)
3299     F_arc *_a;
3300 {
3301     F_arc a = *_a;
3302 
3303     if (cwarc(&a))
3304 	arc_reverse(&a);	/* make counter clockwise arc */
3305 
3306     switch (a.type) {
3307     case T_OPEN_ARC:
3308 	/* open arcs should be drawn separately */
3309 	shape_interior((F_line *)(void *)&a, (void (*)(F_line *))arcinterior);
3310 	if (a.thickness > 0) {
3311 	    edgeattr(1, a.style, a.thickness, a.pen_color, 0, a.cap_style);
3312 	    arcoutline(&a);
3313 	}
3314 	break;
3315     case T_PIE_WEDGE_ARC:
3316 	shape((F_line *)(void *)&a, a.cap_style, 0,
3317 	      (void (*)(F_line *))arcoutline);
3318 	break;
3319     default:
3320 	fprintf(stderr, "Unsupported fig arc type %d.\n", a.type);
3321     }
3322 }/* end genemf_arc */
3323 
3324 
3325 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_ellipse(e)3326 void genemf_ellipse(e)
3327     F_ellipse *e;
3328 {
3329 
3330     switch (e->type) {
3331     case T_ELLIPSE_BY_RAD:
3332     case T_ELLIPSE_BY_DIA:
3333 	if (fabs(e->angle) > EPSILON && fabs(sin(e->angle)) > EPSILON)
3334 	    rotated_ellipse(e);
3335 	else
3336 	    shape((F_line *)e, 0, 0, (void (*)(F_line *))ellipse);
3337 	break;
3338     case T_CIRCLE_BY_RAD:
3339     case T_CIRCLE_BY_DIA:
3340 	shape((F_line *)e, 0, 0, (void (*)(F_line *))circle);
3341 	break;
3342     default:
3343 	fprintf(stderr, "Unsupported FIG ellipse type %d.\n", e->type);
3344     }
3345 }/* end genemf_ellipse */
3346 
3347 
3348 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_line(l)3349 void genemf_line(l)
3350     F_line *l;
3351 {
3352 
3353     switch (l->type) {
3354     case T_POLYLINE:
3355 	shape_interior(l, polygon);		/* draw interior */
3356 
3357 	if (l->points->next == NULL	/* single point line */
3358 	    && l->cap_style == 0) {	/* butt style */
3359 	    /* draw as projecting style but in smaller size */
3360 	    edgeattr(1, l->style, (l->thickness + 1) / 2, l->pen_color,
3361 		     l->join_style, 2);
3362 	} else {
3363 	    edgeattr(1, l->style, l->thickness, l->pen_color,
3364 		     l->join_style, l->cap_style);
3365 	}
3366 
3367 	polyline(l);			/* draw boundary */
3368 	break;
3369     case T_BOX:
3370 	shape(l, l->join_style, l->cap_style, rect); /* simple closed shape */
3371 	break;
3372     case T_POLYGON:
3373 	shape(l, l->join_style, l->cap_style, polygon);
3374 	break;
3375     case T_ARC_BOX:
3376 	shape(l, 0, 0, roundrect);		/* simple closed shape */
3377 	break;
3378     case T_PIC_BOX:
3379 	picbox(l);
3380 	break;
3381     default:
3382 	fprintf(stderr, "Unsupported FIG polyline type %d.\n", l->type);
3383 	return;
3384     }
3385 }/* end genemf_line */
3386 
3387 
3388 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3389 /*ARGSUSED*/
genemf_spline(s)3390 void genemf_spline(s)
3391     F_spline *s;
3392 {
3393     static int wgiv = 0;
3394 
3395     if (!wgiv) {
3396 	fprintf(stderr, "\
3397 Warning: the EMF driver doesn't support (old style) FIG splines.\n\
3398 Suggestion: convert your (old?) FIG image by loading it into xfig v3.2 or\n\
3399 or higher and saving again.\n");
3400 	wgiv = 1;
3401     }
3402 }/* end genemf_spline */
3403 
3404 
3405 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_text(t)3406 void genemf_text(t)
3407     F_text *t;
3408 {
3409     int font;
3410     RECTL rclBounds;
3411     int x, y;
3412     double sin_theta, cos_theta;
3413 #if defined(I18N) && defined(USE_ICONV)
3414     unsigned char *s, *s1, bak;
3415     int nascii, neuc;
3416 #endif
3417 
3418     textcolr(t->color);
3419     font = conv_fontindex(t->font, t->flags);	/* Convert the font index */
3420 
3421     /*
3422      * calculate start position
3423      */
3424     x = t->base_x;
3425     y = t->base_y;
3426     sin_theta = sin(t->angle);
3427     cos_theta = cos(t->angle);
3428     switch (t->type) {
3429     case T_LEFT_JUSTIFIED:
3430 	break;
3431     case T_CENTER_JUSTIFIED:
3432 	x = x + (-(t->length/2.0) * cos_theta);
3433 	y = y + ((t->length/2.0) * sin_theta);
3434 	break;
3435     case T_RIGHT_JUSTIFIED:
3436 	x = x + (-t->length * cos_theta);
3437 	y = y + (t->length * sin_theta);
3438 	break;
3439     default:
3440 	fprintf(stderr, "Unsupported fig text type %d.\n", t->type);
3441     }
3442 
3443     HTOFL(rclBounds.left,   round(x - t->size * sin_theta));
3444     HTOFL(rclBounds.top,    round(y - t->size * cos_theta));
3445     HTOFL(rclBounds.right,  round(x + t->length * cos_theta));
3446     HTOFL(rclBounds.bottom, round(y + t->length * sin_theta));
3447 
3448 #if defined(I18N) && defined(USE_ICONV)
3449     if (figLanguage != LANG_DEFAULT && IS_LOCALE_FONT(font)) {
3450 	/* prescan text to decide if font switching is needed */
3451 	nascii = neuc = 0;
3452 	for (s = (void *) t->cstring; *s; s++) {
3453 	    if (*s > 127)
3454 		neuc++;
3455 	    else
3456 		nascii++;
3457 	}
3458 
3459 	if (neuc == 0)
3460 	    ;		/* ASCII only */
3461 	else if (nascii == 0) {
3462 	    /* locale font only */
3463 	    font = (font == FONT_TIMES_ROMAN) ?
3464 		FONT_LOCALE_ROMAN : FONT_LOCALE_BOLD;
3465 	} else {
3466 	    /*
3467 	     * need font switching
3468 	     */
3469 
3470 	    /*
3471 	     * use home grown alignment
3472 	     */
3473 	    /* use and update current position */
3474 	    textalign(TA_LEFT | TA_BASELINE | TA_UPDATECP);
3475 
3476 	    /* move to the first (left) position */
3477 	    moveto(x, y);
3478 
3479 	    for (s = (void *) t->cstring; *s; s = s1) {
3480 		if (*s & 0x80) {
3481 		    /* EUC 2byte char */
3482 		    for (s1 = s; *s1 & 0x80; s1 += 2)
3483 			;
3484 		    textfont((font == FONT_TIMES_ROMAN) ?
3485 			    FONT_LOCALE_ROMAN : FONT_LOCALE_BOLD,
3486 			t->size, round(t->angle * RAD_01DEG));
3487 		} else {
3488 		    /* ascii */
3489 		    for (s1 = s; *s1 && (*s1 & 0x80) == 0; s1++)
3490 			;
3491 		    textfont(font, t->size, round(t->angle * RAD_01DEG));
3492 		}
3493 		bak = *s1;
3494 		*s1 = '\0';
3495 
3496 		text(0, 0, &rclBounds, s);
3497 
3498 		*s1 = bak;
3499 	    }
3500 	    return;
3501 	}
3502     }
3503 #endif	/* defined(I18N) && defined(USE_ICONV) */
3504 
3505     /*
3506      * Use alignment of EMF, which shall be better than that of home grown.
3507      * Do not use current position.
3508      */
3509     switch (t->type) {
3510     case T_LEFT_JUSTIFIED:
3511 	textalign(TA_LEFT | TA_BASELINE | TA_NOUPDATECP);
3512 	break;
3513     case T_CENTER_JUSTIFIED:
3514 	textalign(TA_CENTER | TA_BASELINE | TA_NOUPDATECP);
3515 	break;
3516     case T_RIGHT_JUSTIFIED:
3517 	textalign(TA_RIGHT | TA_BASELINE | TA_NOUPDATECP);
3518 	break;
3519     }
3520 
3521     textfont(font, t->size, round(t->angle * RAD_01DEG));
3522     text(t->base_x, t->base_y, &rclBounds, t->cstring);
3523 }/* end genemf_text */
3524 
3525 
3526 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
genemf_end()3527 int genemf_end()
3528 {
3529     EMREOF em_eof;
3530     struct emfhandle *h, *h1;
3531 
3532     /* delete all created handles */
3533     for (h = handles; h; h = h1) {
3534 	delete_handle(h);
3535 	h1 = h->next;
3536 	free(h);
3537     }
3538 
3539     memset(&em_eof, 0, sizeof(EMREOF));
3540     em_eof.emr.iType = htofl(EMR_EOF);
3541     em_eof.emr.nSize = htofl(sizeof(EMREOF));
3542     em_eof.offPalEntries = htofl(sizeof(EMREOF) - sizeof(EMFulong));
3543     em_eof.nSizeLast = htofl(sizeof(EMREOF));
3544     emh_write(&em_eof, sizeof(EMREOF), (size_t) 1, EMH_RECORD);
3545 
3546 # ifdef __EMF_DEBUG__
3547     fprintf(stderr, "Metafile Bytes: %d    Records: %d    Handles: %d\n",
3548 	emh_nBytes, emh_nRecords, emh_nHandles);
3549 # endif
3550 
3551     /* Rewrite the updated header record at the beginning of the file. */
3552 
3553     emh.nBytes   = htofl(emh_nBytes);
3554     emh.nRecords = htofl(emh_nRecords);
3555     emh_nHandles++;	/* size of handle table is last handle number + 1 */
3556     emh.nHandles = htofs(emh_nHandles);
3557 
3558     if (fseek(tfp, 0L, SEEK_SET) < 0) {
3559 	fprintf(stderr,"\
3560 fig2dev: error: fseek() failed.  EMF language requires the output is seekable.\
3561 \n\t\tOutput to a plain file, not to a pipe.\n");
3562 	return -1;
3563     }
3564     if (fwrite(&emh, (size_t) 1, sizeof(ENHMETAHEADER), tfp)
3565 	    != sizeof(ENHMETAHEADER) || fseek(tfp, 0L, SEEK_END) < 0) {
3566 	fprintf(stderr,"fig2dev: error: failed to write EMF header\n");
3567 	return -1;
3568     }
3569 
3570     /* all ok */
3571     return 0;
3572 }/* end genemf_end */
3573 
3574 
3575 /*~~~~~|><|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
3576 struct driver dev_emf = {
3577 	genemf_option,
3578 	genemf_start,
3579 	gendev_null,		/* TODO - Create genemf_grid for 3.2.4 */
3580 	genemf_arc,
3581 	genemf_ellipse,
3582 	genemf_line,
3583 	genemf_spline,
3584 	genemf_text,
3585 	genemf_end,
3586 	INCLUDE_TEXT
3587 };
3588