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