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