Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / emf.trm
1 /* Hey Emacs this is -*- C -*-
2  * $Id: emf.trm,v 1.42.2.10 2008/12/14 05:16:25 sfeam Exp $
3  */
4
5 /* GNUPLOT - emf.trm */
6
7 /*[
8  * Copyright 1998, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * This file is included by ../term.c and ../docs/termdoc.c.
39  *
40  * This terminal driver supports:
41  *   Enhanced Metafile Format
42  *
43  * TODO
44  *
45  * HISTORY
46  *
47  * 4.3.1 12-Sep-2008 Ethan A Merritt
48  * - enhanced text mode
49  * - Two variants are here. One uses the TA_UPDATECP mode to track character position.
50  *   This works great horizontally, but I could not find a way to introduce a vertical
51  *   offset to handle subscripts and superscripts.
52  * - The second variant tracks both x and y by estimating the character width/height.
53  *   This causes visible imperfections in the character spacing.
54  * - Rotated enhanced text not yet supported
55  *
56  * 1.0.11 06-Dec-2004 Ethan A Merritt
57  * - implement term->set_color(), term->filled_polygon(), and term->fillbox()
58  *   RGB colors supported, but not yet PM3D palettes
59  * 1.0.10 08-Jul-2004 Hans-Bernhard Broeker
60  * - cleaned up to match gnuplot CodeStyle conventions (one line per statement,
61  *   even in macro bodies, no meddling with assert()).
62  * - purged K&R definitions
63  * 1.0.9 03-Jun-2004 Stephane Barbaray <stephane.barbaray@compodata.com>, Ethan Merritt <merritt@u.washington.edu>
64  * - fixed linewidth bug
65  * - all is now really assumed as 1024x768@96dpi,
66  *   before it was a mix between 1600x1200@120dpi and 1024x768@96dpi,
67  *   so font may now render differently than before...
68  * - pointsize rework (size twice also now)
69  * - HCHAR and VCHAR are more efficiently computed
70  * 1.0.8 06-May-2004 Stephane Barbaray <stephane.barbaray@compodata.com> 
71  * - fixed to work with MS security patch (kb835732) applied, because MS introduced bugs!!!
72  * - EMR_EXTTEXTOUTW (84) is now EMR_EXTTEXTOUTA (83)
73  * 1.0.7 3-Feb-2003 Ethan A Merritt 
74  * - modify text and point color handling to match other terminal types
75  * - FIXME! alignment of rotated text is not correct.
76  * 1.0.6 25-Jul-2002 Ethan A Merritt <merritt@u.washington.edu> 
77  * - generalized text rotation and justification
78  * 1.0.5 2000/07/20
79  * - Handles were not freed at all, resulting to resource leaks when viewing on Windows 9x (not on NT4/W2000!!!)
80  * 1.0.4 2000/06/28
81  * - Emulated dashed vectors are now looking better
82  * - 15 colors * 8 pointstyles = 120 pointtypes
83  * 1.0.3 2000/03/29
84  * - default font is now Arial 12
85  * - implemented options (color/mono,dashed/solid,font)
86  * - 15 colors * 5 dashtypes = 75 linetypes
87  * 1.0.2 2000/03/22
88  * - Polygon and Polyline structures are not working for Windows 9X, I
89  *   really don't know why, replaced with lineto/moveto couples...
90  * - Texts are now displayed in GM_Compatible mode because GM_Advanced is
91  *   displaying correctly but it does not print correctly with Word97!
92  * - Text centering now works best according to escapement/orientation
93  * - Now there is 8 colors * 5 dashtypes = 40 linetypes
94  * - Successfully Working on Linux Suse 6.1 (x86)
95  *
96  * 1.0.1 2000/03/16
97  * - Unicode text have be to long aligned in EMF files (exttextoutw)
98  * - Problems with text transparence (SetBkMode was not called)
99  * - Null brush created for *not* filling polygon
100  *
101  * 1.0.0 2000/03/15
102  * - Only tested on x86 Win32
103  *
104  * AUTHOR
105  *   Stephane Barbaray <stephane.barbaray@compodata.com>
106  *   Some code based on cgm.trm
107  *
108  * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
109  */
110
111 #include "driver.h"
112
113 #ifdef TERM_REGISTER
114 register_term(emf)
115 #endif
116
117 #ifdef TERM_PROTO
118 TERM_PUBLIC void EMF_options __PROTO((void));
119 TERM_PUBLIC void EMF_init __PROTO((void));
120 TERM_PUBLIC void EMF_reset __PROTO((void));
121 TERM_PUBLIC void EMF_text __PROTO((void));
122 TERM_PUBLIC void EMF_graphics __PROTO((void));
123 TERM_PUBLIC void EMF_move __PROTO((unsigned int x, unsigned int y));
124 TERM_PUBLIC void EMF_dashed_vector __PROTO((unsigned int ux, unsigned int uy));
125 TERM_PUBLIC void EMF_solid_vector __PROTO((unsigned int ux, unsigned int uy));
126 TERM_PUBLIC void EMF_linetype __PROTO((int linetype));
127 TERM_PUBLIC void EMF_linecolor __PROTO((int color));
128 TERM_PUBLIC void EMF_dashtype __PROTO((int dashtype));
129 TERM_PUBLIC void EMF_linewidth __PROTO((double width));
130 TERM_PUBLIC void EMF_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
131 TERM_PUBLIC int EMF_text_angle __PROTO((int ang));
132 TERM_PUBLIC int EMF_justify_text __PROTO((enum JUSTIFY mode));
133 TERM_PUBLIC void EMF_point __PROTO((unsigned int x, unsigned int y, int number));
134 TERM_PUBLIC void EMF_set_pointsize __PROTO((double size));
135 TERM_PUBLIC int EMF_set_font __PROTO((const char *));
136 TERM_PUBLIC int EMF_make_palette __PROTO((t_sm_palette *palette));
137 TERM_PUBLIC void EMF_previous_palette __PROTO((void));
138 TERM_PUBLIC void EMF_set_color __PROTO((t_colorspec *colorspec));
139 TERM_PUBLIC void EMF_filled_polygon __PROTO((int, gpiPoint *));
140 TERM_PUBLIC void EMF_fillbox __PROTO((int, unsigned int, unsigned int, unsigned int, unsigned int));
141
142 /* Enhanced text support */
143 TERM_PUBLIC void ENHemf_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
144 TERM_PUBLIC void ENHemf_OPEN __PROTO((char * fontname, double fontsize,
145                         double base, TBOOLEAN widthflag, TBOOLEAN showflag,
146                         int overprint));
147 TERM_PUBLIC void ENHemf_FLUSH __PROTO((void));
148
149 #undef RGB
150 #define RGB(r,g,b) ((long)                                      \
151                     (((unsigned char)(r)                        \
152                       | ((short) ((unsigned char) (g)) << 8))   \
153                      | (((long) (unsigned char) (b)) << 16)))
154
155 #ifndef GPMIN
156 # define GPMIN(a,b) (a < b ? a : b)
157 #endif
158
159 #ifndef GPMAX
160 # define GPMAX(a,b) (a > b ? a : b)
161 #endif
162
163 #define EMF_PX2HM 26.37
164 #define EMF_PT2HM 35.28
165 #define EMF_10THDEG2RAD (3.14159265359/1800)
166 #define EMF_XMAX (1024 * EMF_PX2HM)
167 #define EMF_YMAX (768 * EMF_PX2HM)
168 #define EMF_HTIC (EMF_XMAX / 160)
169 #define EMF_VTIC EMF_HTIC
170 #define EMF_FONTNAME "Arial"
171 #define EMF_FONTSIZE 12
172 #define EMF_HCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 0.6)
173 #define EMF_VCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 1.3)
174 #define EMF_LINE_TYPES 5        /* number of line types we support */
175 #define EMF_COLORS 15           /* number of colors we support */
176 #define EMF_POINTS 13           /* number of markers we support */
177 #define EMF_MAX_SEGMENTS 104    /* maximum # polyline coordinates */
178
179 #define EMF_HANDLE_PEN          1
180 #define EMF_HANDLE_FONT         2
181 #define EMF_HANDLE_BRUSH        3
182 #define EMF_HANDLE_MAX          4
183
184 #define EMF_STOCK_OBJECT_FLAG   ((unsigned long)0x1 << 31)
185 #define EMF_STOCK_OBJECT_WHITE_BRUSH    (EMF_STOCK_OBJECT_FLAG + 0x00)
186 #define EMF_STOCK_OBJECT_BLACK_PEN      (EMF_STOCK_OBJECT_FLAG + 0x07)
187 #define EMF_STOCK_OBJECT_DEFAULT_FONT   (EMF_STOCK_OBJECT_FLAG + 0x0A)
188
189 #define EMF_write_emr(type, size) {             \
190     EMF_write_long(type);                       \
191     EMF_write_long(size);                       \
192     emf_record_count++;                         \
193 }
194 #define EMF_write_sizel(width, height) {        \
195     EMF_write_long(width);                      \
196     EMF_write_long(height);                     \
197 }
198 #define EMF_write_points(x, y) {                \
199     EMF_write_short(x);                         \
200     EMF_write_short(y);                         \
201 }
202 #define EMF_write_pointl(x, y) {                \
203     EMF_write_long(x);                          \
204     EMF_write_long(y);                          \
205 }
206 #define EMF_write_rectl(left, top, right, bottom) {     \
207     EMF_write_long(left);                               \
208     EMF_write_long(top);                                \
209     EMF_write_long(right);                              \
210     EMF_write_long(bottom);                             \
211 }
212
213 #define EMF_EOF() {                             \
214     EMF_write_emr(14, 20);                      \
215     EMF_write_long(0);                          \
216     EMF_write_long(0x10);                       \
217     EMF_write_long(20);                         \
218 }
219 #define EMF_SetMapMode(mode) {                  \
220     EMF_write_emr(17, 0x0C);                    \
221     EMF_write_long(mode);                       \
222 }
223 #define EMF_SetWindowExtEx(width, height) {     \
224     EMF_write_emr(9, 0x10);                     \
225     EMF_write_sizel(width, height);             \
226 }
227 #define EMF_SetWindowOrgEx(width, height) {     \
228     EMF_write_emr(10, 0x10);                    \
229     EMF_write_sizel(width, height);             \
230 }
231 #define EMF_SetViewportExtEx(width, height) {   \
232     EMF_write_emr(11, 0x10);                    \
233     EMF_write_sizel(width, height);             \
234 }
235 #define EMF_SetViewportOrgEx(width, height) {   \
236     EMF_write_emr(12, 0x10);                    \
237     EMF_write_sizel(width, height);             \
238 }
239 #define EMF_SetTextColor(color) {               \
240     EMF_write_emr(24, 0x0C);                    \
241     EMF_write_long(color);                      \
242 }
243 #define EMF_MoveToEx(x,y) {                     \
244     EMF_write_emr(27, 0x10);                    \
245     EMF_write_pointl(x, y);                     \
246 }
247 #define EMF_LineTo(x,y) {                       \
248     EMF_write_emr(54, 0x10);                    \
249     EMF_write_pointl(x, y);                     \
250 }
251 #define EMF_CreatePen(handle, type, width, color) {     \
252     EMF_write_emr(38, 0x1C);                            \
253     EMF_write_long(handle);                             \
254     EMF_write_long(type);                               \
255     EMF_write_long(width);                              \
256     EMF_write_long(0);                                  \
257     EMF_write_long(color);                              \
258 }
259 #define EMF_CreateBrush(handle, type, color, hatch) {   \
260     EMF_write_emr(39, 0x18);                            \
261     EMF_write_long(handle);                             \
262     EMF_write_long(type);                               \
263     EMF_write_long(color);                              \
264     EMF_write_long(hatch);                              \
265 }
266 #define EMF_SelectObject(handle) {              \
267     EMF_write_emr(37, 0x0C);                    \
268     EMF_write_long(handle);                     \
269 }
270 #define EMF_DeleteObject(handle) {              \
271     EMF_write_emr(40, 0x0C);                    \
272     EMF_write_long(handle);                     \
273 }
274 #define EMF_SetTextAlign(align) {               \
275     EMF_write_emr(22, 0x0C);                    \
276     EMF_write_long(align);                      \
277 }
278 #define EMF_SetBkMode(mode) {                   \
279     EMF_write_emr(18, 0x0C);                    \
280     EMF_write_long(mode);                       \
281 }
282 #define EMF_SaveDC() {                          \
283     EMF_write_emr(33, 0x0C);                    \
284     EMF_write_long(0);                          \
285 }
286 #define EMF_RestoreDC() {                       \
287     EMF_write_emr(34, 0x0C);                    \
288     EMF_write_long(1);                          \
289 }
290
291 #endif /* TERM_PROTO */
292
293 #ifndef TERM_PROTO_ONLY
294 #ifdef TERM_BODY
295
296 #include <ctype.h>              /* for isspace() */
297
298 static unsigned int emf_posx;
299 static unsigned int emf_posy;
300 static unsigned int emf_record_count = 0;
301 static unsigned int emf_linetype = 1;
302 static unsigned int emf_dashtype = 0;
303 static unsigned long emf_color = 0L;
304 static unsigned long emf_textcolor = LT_UNDEFINED;
305 static unsigned int emf_colors = EMF_COLORS;
306 static unsigned int emf_polyline[EMF_MAX_SEGMENTS];     /* stored polyline coordinates */
307 static unsigned int emf_graphics = FALSE;
308 static unsigned int emf_dashed = TRUE;
309 static unsigned int emf_monochrome = FALSE;
310 static double emf_linewidth;    /* line width in plot units */
311 static double emf_linewidth_factor = 1.0;
312 static double emf_dashlength = 1.0;
313 static int emf_coords = 0;      /* # polyline coordinates saved */
314 static char emf_fontname[255] = EMF_FONTNAME;
315 static float emf_fontsize = EMF_FONTSIZE;
316 static enum JUSTIFY emf_justify = LEFT;
317 static char emf_defaultfontname[255] = EMF_FONTNAME;
318 static float emf_defaultfontsize = EMF_FONTSIZE;
319 static int emf_vert_text = 0;   /* text orientation -- nonzero for vertical */
320 static int emf_step_sizes[8];   /* array of currently used dash lengths in plot units */
321 static int emf_step_index = 0;  /* index into emf_step_sizes[] */
322 static int emf_step = 0;        /* amount of current dash not yet drawn, in plot units */
323 static int emf_tic, emf_tic707, emf_tic866, emf_tic500, emf_tic1241, emf_tic1077, emf_tic621;   /* marker dimensions */
324
325 static TBOOLEAN emf_tweak = TRUE;       /* Empirical hack to adjust character widths */
326
327 static void EMF_flush_polyline __PROTO((void));
328 static void EMF_flush_polygon __PROTO((void));
329 static void EMF_write_byte __PROTO((int)); 
330 static void EMF_write_short __PROTO((int)); 
331 static void EMF_write_long __PROTO((unsigned long));
332 static void EMF_write_float __PROTO((double)); 
333 static void EMF_setfont __PROTO((void));
334
335 #define ANSI_CHARSET         0
336 #define DEFAULT_CHARSET      1
337 #define GREEK_CHARSET      161
338 #define TURKISH_CHARSET    162
339 #define BALTIC_CHARSET     186
340 #define RUSSIAN_CHARSET    204
341 #define EASTEUROPE_CHARSET 238
342 #define KOI8_CHARSET       242
343
344 /* Text alignment */
345 #define TA_NOUPDATECP       0x00
346 #define TA_UPDATECP         0x01
347 #define TA_LEFT             0x00
348 #define TA_RIGHT            0x02
349 #define TA_CENTER           0x06
350 #define TA_TOP              0x00
351 #define TA_BOTTOM           0x08
352 #define TA_BASELINE         0x18
353
354 /* ExtTextOut options */
355 #define ETO_NO_RECT        0x100
356 #define ETO_PDY           0x2000
357
358 static void 
359 EMF_setfont()
360 {
361     int i, count;
362     int bold = 400;
363     char italic = 0, underline = 0, strikeout = 0;
364     char font[32];
365     char *sub;
366
367     if (!emf_graphics)
368         return;
369
370     count = GPMIN (strlen(emf_fontname), 31);
371     if (((sub = strstr(emf_fontname, " bold")) != NULL)
372         || ((sub = strstr(emf_fontname, " Bold")) != NULL)) {
373         bold = 700;
374         count = GPMIN(sub - emf_fontname, count);
375     }
376     if (((sub = strstr(emf_fontname, " italic")) != NULL)
377         || ((sub = strstr(emf_fontname, " Italic")) != NULL)) {
378         italic = 1;
379         count = GPMIN(sub - emf_fontname, count);
380     }
381     if (((sub = strstr(emf_fontname, " underline")) != NULL)
382         || ((sub = strstr(emf_fontname, " Underline")) != NULL)) {
383         underline = 1;
384         count = GPMIN(sub - emf_fontname, count);
385     }
386     if (((sub = strstr(emf_fontname, " strikeout")) != NULL)
387         || ((sub = strstr(emf_fontname, " Strikeout")) != NULL)
388         || ((sub = strstr(emf_fontname, " StrikeOut")) != NULL)
389         ) {
390         strikeout = 1;
391         count = GPMIN(sub - emf_fontname, count);
392     }
393
394     safe_strncpy(font, emf_fontname, count + 1);
395
396     EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
397     EMF_DeleteObject(EMF_HANDLE_FONT);
398
399     /* SB 20040506: was not complete size was 104, now it is 332 */
400     EMF_write_emr(82, 332); 
401     EMF_write_long(EMF_HANDLE_FONT);
402     EMF_write_long((long) (-emf_fontsize * EMF_PT2HM)); /* height */
403     EMF_write_long(0);                  /* width */
404     EMF_write_long(emf_vert_text);      /* escapement */
405     EMF_write_long(emf_vert_text);      /* orientation */
406     EMF_write_long(bold);               /* weight */
407     EMF_write_byte(italic);             /* italic */
408     EMF_write_byte(underline);          /* underline */
409     EMF_write_byte(strikeout);          /* strikeout */
410
411     /* charset: could be extended? */
412     switch (encoding) {
413     case S_ENC_CP1250:
414     case S_ENC_ISO8859_2:
415         EMF_write_byte(EASTEUROPE_CHARSET);
416         break;
417     case S_ENC_KOI8_R:
418     case S_ENC_KOI8_U:
419         EMF_write_byte(KOI8_CHARSET);
420         break;
421     default:
422         EMF_write_byte(DEFAULT_CHARSET);
423     }
424
425     EMF_write_byte(0);                  /* out precision */
426     EMF_write_byte(0);                  /* clip precision */
427     EMF_write_byte(0);                  /* quality */
428     EMF_write_byte(0);                  /* pitch and family */
429     for (i = 0; i < 32; i++) {
430         /* face name (max 32) */
431         EMF_write_byte((char) (i < strlen(font) ? font[i] : 0));
432         EMF_write_byte(0);
433     }
434     
435     /* SB 20040506: modification following */
436     for (i = 0; i < 64; i++) {
437         /* FULL face name (max 64) */
438         EMF_write_byte((char) (i < strlen(font) ? font[i] : 0));
439         EMF_write_byte(0);
440     }
441     for (i = 0; i < 32; i++) {
442         /* style name (max 32) */
443         EMF_write_byte(0);
444         EMF_write_byte(0);
445     }
446     EMF_write_long(0);          /* version */
447     EMF_write_long(0);          /* Style size */
448     EMF_write_long(0);          /* Match */
449     EMF_write_long(0);          /* reserved */
450     EMF_write_long(0);          /* VendorId */
451     EMF_write_long(0);          /* Culture */
452     for (i = 0; i < 10; i++)
453         EMF_write_byte(0); /* Panose (ignored) */
454     EMF_write_byte(0);          /* pad (long aligned) */
455     EMF_write_byte(0);          /* pad (long aligned) */
456     /* SB 20040506: End of modification */
457
458     EMF_SelectObject(EMF_HANDLE_FONT);
459 }
460
461 static void 
462 EMF_flush_polygon()
463 {
464     int i = 0;
465
466     if (emf_coords == 0)
467         return;
468
469     EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
470     while (i < emf_coords * 2)
471         EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
472     EMF_LineTo(emf_polyline[0], term->ymax - emf_polyline[1]);
473
474     emf_coords = 0;
475 }
476
477 static void 
478 EMF_flush_polyline()
479 {
480     if (emf_coords == 0)
481         return;
482     
483     if (emf_coords <= 2) {
484         EMF_MoveToEx(emf_polyline[0], term->ymax - emf_polyline[1]);
485         EMF_LineTo(emf_polyline[2], term->ymax - emf_polyline[3]);
486     } else {
487         int i = 0;
488
489 #if 0 /* was commented out */
490         /* Polyline works for NT4 but not on W9x */
491         EMF_write_emr(4,(7+emf_coords*2)*4);
492         EMF_write_rectl(0,0,0,0);
493         EMF_write_long(emf_coords);
494         while(i < emf_coords*2)
495             EMF_write_pointl(emf_polyline[i++],term->ymax-emf_polyline[i++]);
496 #endif /* 0 */
497
498         EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
499         while (i < emf_coords * 2)
500             EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
501     }
502     emf_coords = 0;
503 }
504
505 /* HBB 20040708: the following keep K&R argument types for now */
506 static void 
507 EMF_write_byte(int value)
508 {
509     char c = value;
510     fwrite(&c, 1, 1, gpoutfile);
511 }
512
513 static void 
514 EMF_write_short(int value)
515 {
516     short actual_value = value;
517     char c[2];
518
519     c[1] = (actual_value >> 8) & 255;   /* convert to x86 order */
520     c[0] = actual_value & 255;
521
522     fwrite(c, 1, 2, gpoutfile);
523 }
524
525 static void 
526 EMF_write_long(unsigned long value)
527 {
528     char c[4];
529
530     c[3] = (value >> 24) & 0xFFL;       /* convert to x86 order */
531     c[2] = (value >> 16) & 0xFFL;
532     c[1] = (value >> 8) & 0xFFL;
533     c[0] = value & 0xFFL;
534
535     fwrite(c, 1, 4, gpoutfile);
536 }
537
538 /* FIXME HBB 20001103: this only works as given iff 'float' is the
539  * same format as on x86's, i.e. IEEE 4-byte floating point format */
540 static void 
541 EMF_write_float(double value)
542 {
543     char c[4];
544
545     union {
546         long l;
547         float f;
548     } u;
549
550     u.f = value;
551
552     c[3] = (u.l >> 24) & 0xFFL; /* convert to x86 order */
553     c[2] = (u.l >> 16) & 0xFFL;
554     c[1] = (u.l >> 8) & 0xFFL;
555     c[0] = u.l & 0xFFL;
556
557     fwrite(c, 1, 4, gpoutfile);
558 }
559
560 TERM_PUBLIC void 
561 EMF_options()
562 {
563     char *s;
564
565     /* Annoying hack to handle the case of 'set termoption' after */
566     /* we have already initialized the terminal.                  */
567     if (c_token != 2) {
568         term->xmax = EMF_XMAX;
569         term->ymax = EMF_YMAX;
570         emf_dashed = TRUE;
571         emf_monochrome = FALSE;
572         emf_tweak = TRUE;
573     }
574
575     while (!END_OF_COMMAND) {
576         if (almost_equals(c_token, "de$fault")) {
577             strcpy(emf_defaultfontname, EMF_FONTNAME);
578             emf_defaultfontsize = EMF_FONTSIZE;
579             emf_monochrome = FALSE;
580             emf_dashed = TRUE;
581             c_token++;
582             continue;
583         }
584         if (almost_equals(c_token, "m$onochrome")) {
585             emf_monochrome = TRUE;
586             c_token++;
587             continue;
588         }
589         if (almost_equals(c_token, "c$olor") || almost_equals(c_token, "c$olour")) {
590             emf_monochrome = FALSE;
591             c_token++;
592             continue;
593         }
594         if (almost_equals(c_token, "da$shed")) {
595             emf_dashed = TRUE;
596             c_token++;
597             continue;
598         }
599         if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
600             struct value a;
601             c_token++;
602             emf_dashlength = real(const_express(&a));
603             if (emf_dashlength < 0.5)
604                 emf_dashlength = 1.0;
605             continue;
606         }
607         if (almost_equals(c_token, "s$olid")) {
608             emf_dashed = FALSE;
609             c_token++;
610             continue;
611         }
612         if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) {
613             struct value a;
614             c_token++;
615             emf_linewidth_factor = real(const_express(&a));
616             if (emf_linewidth_factor < 0.1)
617                 emf_linewidth_factor = 1.0;
618             continue;
619         }
620
621         if (almost_equals(c_token,"enh$anced")) {
622             c_token++;
623             term->put_text = ENHemf_put_text;
624             term->flags |= TERM_ENHANCED_TEXT;
625             continue;
626         } else if (almost_equals(c_token,"noenh$anced")) {
627             c_token++;
628             term->put_text = EMF_put_text;
629             term->flags &= ~TERM_ENHANCED_TEXT;
630         }
631
632         if (almost_equals(c_token,"nopro$portional")) {
633             c_token++;
634             emf_tweak = FALSE;
635         }
636
637         if (almost_equals(c_token, "si$ze")) {
638             int tempxmax = 1024;
639             int tempymax = 768;
640             struct value a;
641             c_token++;
642             if (!END_OF_COMMAND) {
643                 tempxmax = real(const_express(&a));
644                 if (equals(c_token, ",")) {
645                     c_token++;
646                     tempymax = real(const_express(&a));
647                 }
648             }
649             if (tempxmax > 0)
650                 term->xmax = tempxmax * EMF_PX2HM;
651             if (tempymax > 0)
652                 term->ymax = tempymax * EMF_PX2HM;
653             term->h_tic = term->xmax / 160;
654             term->v_tic = term->h_tic;
655             continue;
656         }
657         if (equals(c_token, "font"))
658             c_token++;
659         /* Fall through to old-style bare font name */
660         if ((s = try_to_get_string())) {
661             char *comma = strrchr(s,',');
662             if (comma && (1 == sscanf(comma+1,"%g",&emf_defaultfontsize))) {
663                 *comma = '\0';
664             }
665             if (*s)
666                 strncpy(emf_defaultfontname, s, sizeof(emf_defaultfontname));
667             free(s);
668             if (isanumber(c_token)) {
669                 struct value a;
670                 emf_defaultfontsize = (int) real(const_express(&a));
671             }
672             continue;
673         }
674         break;
675     } /* while(!end of command) */
676
677     if (!END_OF_COMMAND) {
678         /* We have old-style bare font size specified */
679         struct value a;
680         emf_defaultfontsize = (int) real(const_express(&a));
681     }
682     EMF_set_font(NULL);         /* set default font */
683     
684     emf_colors = emf_monochrome ? 1 : EMF_COLORS;
685
686     sprintf(term_options, "%s %s \"%s\" %g",
687             emf_monochrome ? "monochrome" : "color",
688             emf_dashed ? "dashed" : "solid",
689             emf_defaultfontname, emf_defaultfontsize);
690
691     if (term->flags & TERM_ENHANCED_TEXT)
692         strcat(term_options, " enhanced ");
693     if (term->xmax != (int)EMF_XMAX || term->ymax != (int)EMF_YMAX)
694         sprintf(&(term_options[strlen(term_options)]), " size %d,%d ",
695             (int)(0.5+term->xmax/EMF_PX2HM), (int)(0.5+term->ymax/EMF_PX2HM));
696     if (emf_linewidth_factor != 1.0)
697         sprintf(&(term_options[strlen(term_options)]), " lw %.1f",
698                 emf_linewidth_factor);
699     if (emf_dashlength != 1.0)
700         sprintf(&(term_options[strlen(term_options)]), " dashlength %.1f",
701                 emf_dashlength);
702 }
703
704 TERM_PUBLIC void 
705 EMF_init()
706 {
707     emf_posx = emf_posy = 0;
708     emf_linetype = 0;
709     emf_vert_text = 0;
710     emf_graphics = FALSE;
711 }
712
713 TERM_PUBLIC void 
714 EMF_graphics()
715 {
716     int width = 0.5 + term->xmax/EMF_PX2HM;
717     int height = 0.5 + term->ymax/EMF_PX2HM;
718     int mmwidth = 0.5 + (term->xmax/EMF_PX2HM) * (270./1024.);
719     int mmheight = 0.5 + (term->ymax/EMF_PX2HM) * (200./768.);
720
721     /* header start */
722     emf_record_count = 0;
723     EMF_write_emr(1, 100);
724     EMF_write_long(0);          /* rclBounds */
725     EMF_write_long(0);
726     EMF_write_long(term->xmax / EMF_PX2HM);
727     EMF_write_long(term->ymax / EMF_PX2HM);
728     EMF_write_long(0);          /* rclFrame */
729     EMF_write_long(0);
730     EMF_write_long(term->xmax);
731     EMF_write_long(term->ymax);
732     EMF_write_long(0x464D4520); /* signature */
733     EMF_write_long(0x00010000); /* version */
734     EMF_write_long(0);          /* nBytes */
735     EMF_write_long(0);          /* nRecords */
736     EMF_write_short(EMF_HANDLE_MAX);    /* nHandles, MUST NOT BE 0 */
737     EMF_write_short(0);         /* reserved */
738     EMF_write_long(0);          /* descSize */
739     EMF_write_long(0);          /* descOff */
740     EMF_write_long(0);          /* nPalEntries */
741     EMF_write_long(width);      /* ref dev pixwidth, default 1024 */
742     EMF_write_long(height);     /* ref dev pixheight, default 768 */
743     EMF_write_long(mmwidth);    /* ref dev mwidth, default 270 */
744     EMF_write_long(mmheight);   /* ref dev mheight, default 200 */
745     EMF_write_long(0);          /* cbPixelFormat  */
746     EMF_write_long(0);          /* offPixelFormat  */
747     EMF_write_long(0);          /* bOpenGL */
748     emf_graphics = TRUE;
749     /* header end */
750
751     EMF_SetMapMode(8);          /* forcing anisotropic mode */
752     EMF_SetWindowExtEx(term->xmax, term->ymax);         /* setting logical (himetric) size      */
753     EMF_SetViewportExtEx(term->xmax / EMF_PX2HM, term->ymax / EMF_PX2HM);       /* setting device (pixel) size */
754     EMF_CreatePen(EMF_HANDLE_PEN, 0, 1, 0x000000);      /* init default pen */
755     EMF_SelectObject(EMF_HANDLE_PEN);
756     EMF_SetBkMode(1);           /* transparent background for text */
757     EMF_CreateBrush(EMF_HANDLE_BRUSH, 1, 0, 0);         /* transparent brush for polygons */
758     EMF_SelectObject(EMF_HANDLE_BRUSH);
759     EMF_set_font(NULL);         /* init default font */
760 }
761
762 TERM_PUBLIC int 
763 EMF_set_font(const char *font)
764 {
765     static float last_fontsize = -1;
766     static char last_fontname[256] = {'\0'};
767
768     if (font && *font) {
769         float tempsize;
770         int sep = strcspn(font,",");
771         if (sep > 0)
772             safe_strncpy(emf_fontname, font, GPMIN(sep + 1, 32));
773         if (sep < strlen(font) && sscanf(font+sep+1, "%f", &tempsize))
774             emf_fontsize = tempsize;
775     } else {
776         strcpy(emf_fontname, emf_defaultfontname);
777         emf_fontsize = emf_defaultfontsize;
778     }
779
780     /* Optimization only */
781     if (!strcmp(last_fontname,emf_fontname) && last_fontsize == emf_fontsize) {
782         return TRUE;
783     }
784
785     term->h_char = (emf_fontsize * EMF_PT2HM)*0.6;
786     term->v_char = (emf_fontsize * EMF_PT2HM)*1.3;
787     EMF_setfont();
788     return TRUE;
789 }
790
791 TERM_PUBLIC void 
792 EMF_text()
793 {
794     long pos;
795     EMF_flush_polyline();
796
797     /* writing end of metafile */
798     EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
799     EMF_DeleteObject(EMF_HANDLE_FONT);
800     EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
801     EMF_DeleteObject(EMF_HANDLE_PEN);
802     EMF_SelectObject(EMF_STOCK_OBJECT_WHITE_BRUSH);
803     EMF_DeleteObject(EMF_HANDLE_BRUSH);
804     EMF_EOF();
805
806     /* updating header */
807     pos = ftell(gpoutfile);
808     fseek(gpoutfile, 48, SEEK_SET);
809     EMF_write_long(pos);
810     EMF_write_long(emf_record_count);
811     /* HBB 20010228: have to make known that we're no longer in graphics
812      * status. */
813     emf_graphics = FALSE;
814 }
815
816 TERM_PUBLIC void 
817 EMF_linetype(int linetype)
818 {
819     /* Note : separating linetype and color would have not been futile, but anyway... */
820
821 #if (0)  /* Not safe because linetype/color/pen are intermixed */
822     if (linetype == emf_linetype)
823         return;
824 #endif
825
826     if (linetype == LT_NODRAW)
827         linetype = LT_BACKGROUND;
828         
829     emf_linetype = linetype;
830
831     EMF_linecolor(linetype);
832     EMF_dashtype(linetype);
833 }
834
835 TERM_PUBLIC void 
836 EMF_linecolor(int linecolor)
837 {
838     static long GPFAR color_table_data[] =
839     {
840         RGB(255, 0, 0),         /* red */
841         RGB(0, 255, 0),         /* green */
842         RGB(0, 0, 255),         /* blue */
843         RGB(255, 0, 255),       /* magenta */
844         RGB(0, 0, 128),         /* dark blue */
845         RGB(128, 0, 0),         /* dark red */
846         RGB(0, 128, 128),       /* dark cyan */
847         RGB(0, 0, 0),           /* black */
848         RGB(128, 128, 128),     /* grey */
849         RGB(0, 128, 64),        /* very dark cyan */
850         RGB(128, 128, 0),       /* dark yellow */
851         RGB(128, 0, 128),       /* dark magenta */
852         RGB(192, 192, 192),     /* light grey */
853         RGB(0, 255, 255),       /* cyan */
854         RGB(255, 255, 0)        /* yellow */
855     };
856
857     if (linecolor == LT_BACKGROUND)
858         emf_color = RGB(255, 255, 255); /* white (background) */
859     else {
860         linecolor = (linecolor < 0 || emf_monochrome) ? 7 : (linecolor % EMF_COLORS);
861         emf_color = color_table_data[linecolor];
862     }
863
864     EMF_flush_polyline();
865 }
866
867 TERM_PUBLIC int EMF_make_palette(t_sm_palette *palette)
868 {
869     return 0; /* can do continous colors */
870 }
871
872 TERM_PUBLIC void EMF_previous_palette()
873 {
874     /* do nothing */
875 }
876
877 TERM_PUBLIC void
878 EMF_set_color(t_colorspec *colorspec)
879 {
880     rgb255_color rgb255;
881
882     if (colorspec->type == TC_LT) {
883         EMF_linecolor(colorspec->lt);
884     } else if (colorspec->type == TC_FRAC) {
885         rgb255maxcolors_from_gray(colorspec->value, &rgb255);
886         emf_color = RGB(rgb255.r, rgb255.g, rgb255.b);
887     } else if (colorspec->type == TC_RGB) {
888         emf_color = RGB( colorspec->lt >> 16 & 0xff,
889                          colorspec->lt >> 8 & 0xff,
890                          colorspec->lt & 0xff );
891     }
892
893     /*
894     else {
895         fprintf(stderr, "unhandled colorspec type %d\n", colorspec->type);
896     }
897     */
898
899     /* Force reevaluation of dash type */
900     emf_dashtype = LT_UNDEFINED;
901     EMF_dashtype(emf_linetype);
902 }
903
904 TERM_PUBLIC void
905 EMF_filled_polygon(int points, gpiPoint *corners)
906 {
907     int i;
908     unsigned long color = emf_color;
909     int fillpar = corners->style >> 4;
910     int style = corners->style & 0xf;
911
912 #define EMF_POLYGON 3
913
914     switch (style) {
915         case FS_EMPTY: /* fill with background color */
916                 color = RGB(255,255,255);
917                 break;
918         case FS_PATTERN: /* pattern fill implemented as partial density */
919                 fillpar *= 12;
920         case FS_SOLID: /* solid fill */
921                 if (fillpar >= 0 && fillpar < 100) {
922                     double density = (double)fillpar / 100.;
923                     color = ((int)((double)((emf_color>>16)&0xff)*density) << 16)
924                           + ((int)((double)((emf_color>>8)&0xff)*density) << 8)
925                           + ((int)((double)(emf_color&0xff)*density));
926                     color += ((int)(255.*(1.-density)) << 16)
927                            + ((int)(255.*(1.-density)) << 8)
928                            + ((int)(255.*(1.-density)));
929                 }
930                 break;
931         default:
932                 break;
933     }
934
935     /* Sequence of operations cribbed from Windows example */
936         EMF_CreateBrush(EMF_HANDLE_BRUSH, 0, color, 0);
937         EMF_SelectObject(EMF_HANDLE_BRUSH);
938
939         EMF_write_emr(EMF_POLYGON, (7 + 2*points) * 4);
940         EMF_write_rectl(0,0,0,0);  /* What are these? */
941         EMF_write_long(points);
942         for (i=0; i<points; i++)
943             EMF_write_pointl(corners[i].x, term->ymax - corners[i].y);
944
945         EMF_DeleteObject(EMF_HANDLE_BRUSH);
946
947     /* Force re-evaluation of linetype next time we draw a line */
948     emf_linetype = LT_UNDEFINED;
949     emf_dashtype = LT_UNDEFINED;
950 }
951
952 TERM_PUBLIC void
953 EMF_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
954 {
955     gpiPoint corner[4];
956
957         corner[0].x = x1;        corner[0].y = y1;
958         corner[1].x = x1+width;  corner[1].y = y1;
959         corner[2].x = x1+width;  corner[2].y = y1+height;
960         corner[3].x = x1;        corner[3].y = y1+height;
961         corner->style = style;
962
963         EMF_filled_polygon(4, corner);
964 }
965
966 TERM_PUBLIC void 
967 EMF_linewidth(double width)
968 {
969         int current_dashtype = emf_dashtype;
970     
971     width *= emf_linewidth_factor;
972     if (width == emf_linewidth)
973         return;
974     emf_linewidth = width;
975
976         emf_dashtype = LT_UNDEFINED;      /* Invalidate current dash type     */
977         EMF_dashtype(current_dashtype);    /* Force re-evaluation of dash type */
978 }
979
980 /*
981  * Resets _both_ line color and dash type!
982  */
983 TERM_PUBLIC void 
984 EMF_dashtype(int dashtype)
985 {
986     int i, j;
987     /* Each group of 8 entries in dot_length[] defines a dash
988        pattern.  Entries in each group are alternately length of
989        whitespace and length of line, in units of 2/3 of the
990        linewidth. */
991     static int dot_length[EMF_LINE_TYPES * 8] =
992     {                           /* 0 - solid             */
993         5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes            */
994         4, 2, 4, 2, 4, 2, 4, 2, /* 2 - dotted            */
995         4, 8, 4, 2, 4, 8, 4, 2, /* 3 - dash-dot          */
996         4, 9, 4, 2, 4, 2, 0, 0, /* 4 - dash-dot-dot      */
997     };
998
999     emf_dashtype = dashtype;
1000
1001     EMF_flush_polyline();
1002
1003     if (dashtype >= 0)
1004         dashtype = (dashtype / emf_colors) % EMF_LINE_TYPES;
1005
1006     if (dashtype == LT_AXIS)
1007         dashtype = 2;
1008
1009     if (dashtype < 1 || !emf_dashed) {  /* solid mode */
1010         EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
1011         EMF_DeleteObject(EMF_HANDLE_PEN);
1012         EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
1013         EMF_SelectObject(EMF_HANDLE_PEN);
1014
1015         term->vector = EMF_solid_vector;
1016     } else {                    /* Since win32 dashed lines works only with 1 pixel linewith we must emulate */
1017         EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
1018         EMF_DeleteObject(EMF_HANDLE_PEN);
1019         EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
1020         EMF_SelectObject(EMF_HANDLE_PEN);
1021
1022         term->vector = EMF_dashed_vector;
1023
1024         /* set up dash dimensions */
1025         j = (dashtype - 1) * 8;
1026         for (i = 0; i < 8; i++, j++) {
1027             emf_step_sizes[i] = dot_length[j] * emf_dashlength * EMF_PX2HM;
1028         }
1029         /* first thing drawn will be a line */
1030         emf_step = emf_step_sizes[1];
1031         emf_step_index = 1;
1032     }
1033 }
1034
1035 TERM_PUBLIC void 
1036 EMF_move(unsigned int x, unsigned int y)
1037 {
1038     if (x >= term->xmax || y >= term->ymax) {
1039         int_warn(NO_CARET, "emf_move: (%d,%d) out of range",x,y);
1040         x = GPMIN(x, term->xmax); y = GPMIN(y, term->ymax);
1041     }
1042     if (x == emf_posx && y == emf_posy)
1043         return;
1044     EMF_flush_polyline();
1045     emf_posx = x;
1046     emf_posy = y;
1047 }
1048
1049 TERM_PUBLIC void 
1050 EMF_dashed_vector(unsigned int ux, unsigned int uy)
1051 {
1052     int xa, ya;
1053     int dx, dy, adx, ady;
1054     int dist;                   /* approximate distance in plot units from starting point to specified end point. */
1055     long remain;                /* approximate distance in plot units remaining to specified end point. */
1056
1057     if (ux >= term->xmax || uy >= term->ymax)
1058         int_warn(NO_CARET, "emf_dashed_vector: (%d,%d) out of range",ux,uy);
1059
1060     dx = (ux - emf_posx);
1061     dy = (uy - emf_posy);
1062     adx = abs(dx);
1063     ady = abs(dy * 10);
1064
1065     /* using the approximation sqrt(x**2 + y**2)  ~  x + (5*x*x)/(12*y)   when x > y.  
1066        Note ordering of calculations to avoid overflow on 16 bit architectures */
1067     if (10 * adx < ady)
1068         dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5;
1069     else {
1070         if (adx == 0)
1071             return;
1072         dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10;
1073     }
1074     remain = dist;
1075     xa = emf_posx;
1076     ya = emf_posy;
1077     while (remain > emf_step) {
1078         remain -= emf_step;
1079         if (emf_step_index & 1)
1080             EMF_solid_vector((int) (ux - (remain * dx) / dist),
1081                              (int) (uy - (remain * dy) / dist));
1082         else {
1083             xa = (int) (ux - (remain * dx) / dist);
1084             ya = (int) (uy - (remain * dy) / dist);
1085             EMF_move(xa, ya);
1086         }
1087         if (++emf_step_index >= 8)
1088             emf_step_index = 0;
1089         emf_step = emf_step_sizes[emf_step_index];
1090     }
1091     if (emf_step_index & 1)
1092         EMF_solid_vector(ux, uy);
1093     else
1094         EMF_move(ux, uy);
1095     emf_step -= (int) remain;
1096 }
1097
1098 TERM_PUBLIC void 
1099 EMF_solid_vector(unsigned int ux, unsigned int uy)
1100 {
1101     if (ux >= term->xmax || uy >= term->ymax)
1102         int_warn(NO_CARET, "emf_solid_vector: (%d,%d) out of range",ux,uy);
1103     if (ux == emf_posx && uy == emf_posy)
1104         return;
1105     if (emf_coords * 2 > EMF_MAX_SEGMENTS - 2)
1106         EMF_flush_polyline();
1107     if (emf_coords == 0) {
1108         emf_polyline[0] = emf_posx;
1109         emf_polyline[1] = emf_posy;
1110         emf_coords++;
1111     }
1112     emf_posx = emf_polyline[emf_coords * 2] = ux;
1113     emf_posy = emf_polyline[emf_coords * 2 + 1] = uy;
1114     emf_coords++;
1115 }
1116
1117 TERM_PUBLIC void 
1118 EMF_put_text(unsigned int x, unsigned int y, const char str[])
1119 {
1120     int i, len = strlen(str);
1121
1122     EMF_flush_polyline();
1123     if (emf_textcolor != emf_color) {
1124         EMF_SetTextColor(emf_color);    /* since text doesn't use pens, we must initialize with this */
1125         emf_textcolor = emf_color;
1126     }
1127
1128     /* SB 20040506: offset array now included since it won't work with MS Security patch (kb835732) */
1129     /* SB 20040506: also changed function from unicode to ansi version */
1130     if (len % 4)
1131         len += 4 - (len % 4); /* Structure must be long aligned! */
1132     EMF_write_emr(83, 76 + len + strlen(str)*4);/* ExtTextOutA, ANSI char version! */
1133     EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */
1134     EMF_write_long(1);          /* GM_Compatible mode for advanced scaling */
1135     EMF_write_float(EMF_PX2HM); /* x scale */
1136     EMF_write_float(EMF_PX2HM); /* y scale */
1137     /* positioning... y is recentered from bottom reference set in
1138      * text align */
1139     EMF_write_pointl(
1140         x + (long) ((EMF_VCHAR / 2) * sin(emf_vert_text * EMF_10THDEG2RAD)),
1141         term->ymax - y + (long) (EMF_VCHAR / 2
1142                                  * cos(emf_vert_text * EMF_10THDEG2RAD)));
1143     EMF_write_long(strlen(str)); /* real char size */
1144     EMF_write_long(76);         /* offset to text */
1145     EMF_write_long(0);          /* options, none */
1146     EMF_write_rectl(0, 0, 0, 0); /* rectangle clipping not used */
1147     EMF_write_long(0);          /* offset to intercharacter spacing array, can't be used since really we don't know anything about the face properties used */
1148     for (i = 0; i < len; i++) 
1149         EMF_write_byte(i<strlen(str)?str[i]:0); /* writing text */
1150     for (i = 0; i < strlen(str); i++)
1151         /* writing intercharacter spacing array (but we don't use it) */
1152         EMF_write_long(300); 
1153     /* SB 20040506: end of modification */
1154
1155     emf_posx = emf_posy = -2000;
1156 }
1157
1158 TERM_PUBLIC int 
1159 EMF_text_angle(int ang)
1160 {
1161     /* Win GDI rotation is scaled in tenth of degrees, so... */
1162     switch (ang) {
1163     case 0:                     /* left right */
1164         if (emf_vert_text != 0) {
1165             emf_vert_text = 0;
1166             EMF_setfont();
1167         }
1168         break;
1169     case TEXT_VERTICAL:         /* bottom up */
1170         if (emf_vert_text != 900) {
1171             emf_vert_text = 900;
1172             EMF_setfont();
1173         }
1174         break;
1175     default:                    /* the general case */
1176         emf_vert_text = 10 * ang;
1177         EMF_setfont();
1178         break;
1179     }
1180     return TRUE;
1181 }
1182
1183 TERM_PUBLIC int 
1184 EMF_justify_text(enum JUSTIFY mode)
1185 {
1186     int align = TA_BOTTOM;
1187
1188     emf_justify = mode;
1189
1190     switch (mode) {
1191     case LEFT:
1192         align |= TA_LEFT;
1193         break;
1194     case RIGHT:
1195         align |= TA_RIGHT;
1196         break;
1197     case CENTRE:
1198         align |= TA_CENTER;
1199         break;
1200     }
1201     EMF_SetTextAlign(align);
1202
1203     return (TRUE);
1204 }
1205
1206 TERM_PUBLIC void 
1207 EMF_reset()
1208 {
1209     emf_posx = emf_posy = 0;
1210     emf_graphics = FALSE;
1211 }
1212
1213 TERM_PUBLIC void 
1214 EMF_point(unsigned int x, unsigned int y, int number)
1215 {
1216     int old_dashtype;
1217     gpiPoint corners[12];
1218     corners->style = FS_OPAQUE;
1219
1220     EMF_flush_polyline();
1221     old_dashtype = emf_dashtype;
1222     EMF_dashtype(0);
1223
1224     /* if (number < 0)*/
1225     {
1226         /* draw dot */
1227         EMF_move(x, y);
1228         EMF_solid_vector(x + 1, y);
1229         /* goto end_points;*/
1230     }
1231     number = number % EMF_POINTS;
1232
1233     switch (number) {
1234     case 0:                     /* draw plus */
1235         EMF_move(x - emf_tic, y);
1236         EMF_solid_vector(x + emf_tic, y);
1237         EMF_move(x, y - emf_tic);
1238         EMF_solid_vector(x, y + emf_tic);
1239         break;
1240     case 1:                     /* draw X */
1241         EMF_move(x - emf_tic707, y - emf_tic707);
1242         EMF_solid_vector(x + emf_tic707, y + emf_tic707);
1243         EMF_move(x - emf_tic707, y + emf_tic707);
1244         EMF_solid_vector(x + emf_tic707, y - emf_tic707);
1245         break;
1246     case 2:                     /* draw star (asterisk) */
1247         EMF_move(x, y - emf_tic);
1248         EMF_solid_vector(x, y + emf_tic);
1249         EMF_move(x + emf_tic866, y - emf_tic500);
1250         EMF_solid_vector(x - emf_tic866, y + emf_tic500);
1251         EMF_move(x + emf_tic866, y + emf_tic500);
1252         EMF_solid_vector(x - emf_tic866, y - emf_tic500);
1253         break;
1254     case 3:                     /* draw box */
1255         EMF_move(x - emf_tic707, y - emf_tic707);
1256         EMF_solid_vector(x + emf_tic707, y - emf_tic707);
1257         EMF_solid_vector(x + emf_tic707, y + emf_tic707);
1258         EMF_solid_vector(x - emf_tic707, y + emf_tic707);
1259         EMF_flush_polygon();
1260         break;
1261     case 4:                     /* draw filled box */
1262         corners[0].x = x - emf_tic707; corners[0].y = y - emf_tic707;
1263         corners[1].x = x + emf_tic707; corners[1].y = y - emf_tic707;
1264         corners[2].x = x + emf_tic707; corners[2].y = y + emf_tic707;
1265         corners[3].x = x - emf_tic707; corners[3].y = y + emf_tic707;
1266         EMF_filled_polygon(4, corners);
1267         break;
1268     case 5:
1269         /* draw circle (actually, dodecagon) (WinWord 6 accepts the
1270          * CGM "circle" element, but the resulting circle is not
1271          * correctly centered!) */
1272         EMF_move(x, y - emf_tic);
1273         EMF_solid_vector(x + emf_tic500, y - emf_tic866);
1274         EMF_solid_vector(x + emf_tic866, y - emf_tic500);
1275         EMF_solid_vector(x + emf_tic, y);
1276         EMF_solid_vector(x + emf_tic866, y + emf_tic500);
1277         EMF_solid_vector(x + emf_tic500, y + emf_tic866);
1278         EMF_solid_vector(x, y + emf_tic);
1279         EMF_solid_vector(x - emf_tic500, y + emf_tic866);
1280         EMF_solid_vector(x - emf_tic866, y + emf_tic500);
1281         EMF_solid_vector(x - emf_tic, y);
1282         EMF_solid_vector(x - emf_tic866, y - emf_tic500);
1283         EMF_solid_vector(x - emf_tic500, y - emf_tic866);
1284         EMF_flush_polygon();
1285         break;
1286     case 6: /* filled circle */
1287         corners [0].x = x             ; corners [0].y = y - emf_tic;
1288         corners [1].x = x + emf_tic500; corners [1].y = y - emf_tic866;
1289         corners [2].x = x + emf_tic866; corners [2].y = y - emf_tic500;
1290         corners [3].x = x + emf_tic   ; corners [3].y = y;
1291         corners [4].x = x + emf_tic866; corners [4].y = y + emf_tic500;
1292         corners [5].x = x + emf_tic500; corners [5].y = y + emf_tic866;
1293         corners [6].x = x             ; corners [6].y = y + emf_tic;
1294         corners [7].x = x - emf_tic500; corners [7].y = y + emf_tic866;
1295         corners [8].x = x - emf_tic866; corners [8].y = y + emf_tic500;
1296         corners [9].x = x - emf_tic   ; corners [9].y = y;
1297         corners[10].x = x - emf_tic866; corners[10].y = y - emf_tic500;
1298         corners[11].x = x - emf_tic500; corners[11].y = y - emf_tic866;
1299         EMF_filled_polygon(12, corners);
1300         break;
1301     case 7:                     /* draw triangle (point up) */
1302         EMF_move(x, y + emf_tic1241);
1303         EMF_solid_vector(x - emf_tic1077, y - emf_tic621);
1304         EMF_solid_vector(x + emf_tic1077, y - emf_tic621);
1305         EMF_flush_polygon();
1306         break;
1307     case 8: /* filled triangle point up */
1308         corners[0].x = x               ; corners[0].y = y + emf_tic1241;
1309         corners[1].x = x - emf_tic1077 ; corners[1].y = y - emf_tic621;
1310         corners[2].x = x + emf_tic1077 ; corners[2].y = y - emf_tic621;
1311         EMF_filled_polygon(3, corners);
1312         break;
1313     case 9:                     /* draw triangle (point down) */
1314         EMF_move(x, y - emf_tic1241);
1315         EMF_solid_vector(x - emf_tic1077, y + emf_tic621);
1316         EMF_solid_vector(x + emf_tic1077, y + emf_tic621);
1317         EMF_flush_polygon();
1318         break;
1319     case 10: /* filled triangle point down */
1320         corners[0].x = x               ; corners[0].y = y - emf_tic1241;
1321         corners[1].x = x - emf_tic1077 ; corners[1].y = y + emf_tic621;
1322         corners[2].x = x + emf_tic1077 ; corners[2].y = y + emf_tic621;
1323         EMF_filled_polygon(3, corners);
1324         break;
1325     case 11:                    /* draw diamond */
1326         EMF_move(x - emf_tic, y);
1327         EMF_solid_vector(x, y - emf_tic);
1328         EMF_solid_vector(x + emf_tic, y);
1329         EMF_solid_vector(x, y + emf_tic);
1330         EMF_flush_polygon();
1331         break;
1332     case 12: /* filled diamond */
1333         corners[0].x = x - emf_tic ; corners[0].y = y;
1334         corners[1].x = x           ; corners[1].y = y - emf_tic;
1335         corners[2].x = x + emf_tic ; corners[2].y = y;
1336         corners[3].x = x           ; corners[3].y = y + emf_tic;
1337         EMF_filled_polygon(4, corners);
1338         break;
1339     }
1340 /* end_points: */
1341     EMF_dashtype(old_dashtype);
1342 }
1343
1344
1345 TERM_PUBLIC void 
1346 EMF_set_pointsize(double size)
1347 {
1348     if (size < 0)
1349         size = 1;
1350     emf_tic = (size * term->h_tic);
1351     emf_tic707 = emf_tic * 12 / 17;
1352     emf_tic866 = emf_tic * 13 / 15;
1353     emf_tic500 = emf_tic / 2;
1354     emf_tic1241 = emf_tic * 36 / 29;
1355     emf_tic1077 = emf_tic * 14 / 13;
1356     emf_tic621 = emf_tic * 18 / 29;
1357 }
1358
1359 /*
1360  * Ethan A Merritt September 2008
1361  *      - Support for enhanced text mode
1362  * PROBLEMS:
1363  *      - Rotated enhanced text is not handled
1364  *      - The proportional spacing hack is really ugly
1365  *        ETO_PDY is supposed to handle this, but pre-Vista Windows
1366  *        doesn't support the flag so it's of no real use.
1367  */
1368
1369 static TBOOLEAN ENHemf_opened_string;
1370
1371 /* used in determining height of processed text */
1372 static float ENHemf_base;
1373
1374 /* use these so that we don't over-write the current font settings */
1375 static float ENHemf_fontsize;
1376 static char   *ENHemf_font;
1377
1378 static TBOOLEAN ENHemf_show = TRUE;
1379 static int ENHemf_overprint = 0;
1380
1381 TERM_PUBLIC void
1382 ENHemf_OPEN(
1383     char *fontname,
1384     double fontsize, double base,
1385     TBOOLEAN widthflag,
1386     TBOOLEAN showflag,
1387     int overprint)
1388 {
1389
1390     /* If the overprint code requests a save or restore, that's all we do */
1391 #define EMF_AVG_WID 0.8
1392 #undef TA_UPDATECP_MODE
1393 #ifdef TA_UPDATECP_MODE
1394     if (overprint == 3) {
1395         EMF_SaveDC();
1396         return;
1397     } else if (overprint == 4) {
1398         EMF_RestoreDC();
1399         return;
1400     }
1401 #else
1402     static int save_x, save_y;
1403     if (overprint == 3) {
1404         save_x = emf_posx;
1405         save_y = emf_posy;
1406         return;
1407     } else if (overprint == 4) {
1408         emf_posx = save_x;
1409         emf_posy = save_y;
1410         return;
1411     }
1412 #endif
1413
1414     if (!ENHemf_opened_string) {
1415         ENHemf_opened_string = TRUE;
1416         enhanced_cur_text = &enhanced_text[0];
1417         ENHemf_font = fontname;
1418         ENHemf_fontsize = fontsize;
1419         ENHemf_base = base;
1420         ENHemf_show = showflag;
1421         ENHemf_overprint = overprint;
1422     }
1423 }
1424
1425 /* Write a string fragment and update the current position */
1426 TERM_PUBLIC void
1427 ENHemf_FLUSH()
1428 {
1429     unsigned int x, y;
1430     char *str;
1431     int i;
1432     int incr_x;
1433     double strl;
1434
1435         if (ENHemf_opened_string) {
1436             *enhanced_cur_text = '\0';
1437             ENHemf_opened_string = FALSE;
1438             x = emf_posx;
1439             y = emf_posy;
1440
1441             FPRINTF((stderr,"ENHemf_FLUSH: Write string \"%s\" len %d at %g with font %s,%g\n",
1442                     enhanced_text,strlen(enhanced_text),
1443                     (double)x/EMF_PX2HM,ENHemf_font,ENHemf_fontsize));
1444
1445             if (1) {
1446                 char save_font[256];
1447                 float save_fontsize = emf_fontsize;
1448                 strcpy(save_font,emf_fontname);
1449                 emf_fontsize = ENHemf_fontsize;
1450
1451                 EMF_set_font(ENHemf_font);
1452                 
1453                 emf_fontsize = save_fontsize;
1454                 strcpy(emf_fontname,save_font);
1455             }
1456
1457             /* Don't know how to do a pure move; instead write in white */
1458             if (!ENHemf_show) {
1459                 EMF_SetTextColor(0xffffff);
1460                 emf_textcolor = 0xffffff;
1461             } else if (ENHemf_show && emf_textcolor != emf_color) {
1462                 EMF_SetTextColor(emf_color);
1463                 emf_textcolor = emf_color;
1464             }
1465
1466             str = enhanced_text;
1467
1468 #ifndef TA_UPDATEPC_MODE
1469             /* We are especially bad at guessing the width of whitespace. */
1470             /* Best is to pile up all our errors on top of leading space. */
1471             i = strspn(enhanced_text," ");
1472             if (i > 0) {
1473                 x += i * term->h_char 
1474                    * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize;
1475                 emf_posx = x;
1476                 str += i;
1477             }
1478 #endif
1479
1480             /* Copied from put_text(). Is all this really necessary? */
1481             {
1482             int record_length;
1483             int len = strlen(str);
1484             if (len % 4)
1485                 len += 4 - (len % 4);           /* Structure must be long aligned! */
1486             record_length = 76 + len + strlen(str)*4;
1487
1488             EMF_write_emr(83, record_length);/* ExtTextOutA, ANSI char version! */
1489             EMF_write_rectl(0, 0, 0, 0);        /* bounding, never used */
1490             EMF_write_long(1);                  /* GM_Compatible mode for advanced scaling */
1491             EMF_write_float(EMF_PX2HM);         /* x scale */
1492             EMF_write_float(EMF_PX2HM);         /* y scale */
1493             if (emf_vert_text == 0) {           /* x,y position (ignored if TA_UPDATECP) */
1494                 float yo = 1.3 * EMF_PX2HM * ENHemf_base;
1495                 EMF_write_pointl(
1496                         x, term->ymax - (y + yo));
1497             } else {
1498                 float a = emf_vert_text * EMF_10THDEG2RAD;
1499                 float yo = 1.3 * EMF_PX2HM * ENHemf_base;
1500                 EMF_write_pointl(
1501                         x - (long) (yo * sin(a)),
1502                         term->ymax - (long) (y + (yo * cos(a))) );
1503             }
1504             EMF_write_long(strlen(str));        /* true number of characters */
1505             EMF_write_long(76);                 /* offset to text */
1506             EMF_write_long(ETO_NO_RECT);        /* ExtTextOut options */
1507             EMF_write_rectl(0, 0, 0, 0);        /* bounding, never used */
1508             EMF_write_long(0);                  /* offset to intercharacter spacing array */
1509             for (i = 0; i < len; i++) 
1510                 EMF_write_byte(i<strlen(str)?str[i]:0); /* character string */
1511             for (i = 0; i < strlen(str); i++)
1512                 EMF_write_long(300);            /* intercharacter spacing array (not used) */
1513             }
1514
1515             /* Empirical hack */
1516             strl = strlen(str);
1517             if (emf_vert_text != 0)
1518                 strl += 1.0;
1519
1520             if (emf_tweak) {
1521                 /* Tweak estimated length of rendered string by counting "thin" characters */
1522                 /* In principle EMF will accept an array of char widths. But in practice   */
1523                 /* none of the EMF viewers implement this option (ETO_PDY).                */
1524                 {
1525                 int thin = 0, wide = 0;
1526                 for (i=0; i<strlen(str); i++) {
1527                     if (strchr(" ijl.,;:|!()[]1I",str[i]))
1528                         thin++;
1529                     if (('A' <= str[i] && str[i] <= 'Z') || strchr("mw<>",str[i]))
1530                         wide++;
1531                     if('i' == str[i])
1532                         thin++;
1533                 }
1534                 incr_x = (strl * EMF_AVG_WID + (double)(wide-thin) * 0.2)
1535                         * term->h_char;
1536                 }
1537             } else {
1538                 incr_x = strl * EMF_AVG_WID * term->h_char;
1539             }
1540
1541             /* Attempt to handle slanted text. Not entirely successful */
1542             emf_posx += incr_x * cos(emf_vert_text * EMF_10THDEG2RAD);
1543             emf_posy += incr_x * sin(emf_vert_text * EMF_10THDEG2RAD);
1544
1545             if (ENHemf_overprint == 1)
1546                 emf_posx -= strlen(str) * term->h_char 
1547                           * (0.5) * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize;
1548
1549         }
1550 }
1551
1552 TERM_PUBLIC void
1553 ENHemf_put_text(unsigned int x, unsigned int y, const char *str)
1554 {
1555     int tmp_justify = emf_justify;
1556     int len;
1557
1558     if (ignore_enhanced_text) {
1559         EMF_put_text(x,y,str);
1560         return;
1561     }
1562
1563     if (!strlen(str))
1564         return;
1565     len = estimate_strlen((char *)str);
1566
1567     /* if there are no magic characters, we should just be able
1568      * punt the string to EMF_put_text()
1569      */
1570     if (!strpbrk(str, "{}^_@&~")) {
1571         /* FIXME: do something to ensure default font is selected */
1572         EMF_put_text(x,y,str);
1573         return;
1574     }
1575
1576     if (emf_textcolor != emf_color) {
1577         EMF_SetTextColor(emf_color);
1578         emf_textcolor = emf_color;
1579     }
1580
1581     /* set up the global variables needed by enhanced_recursion() */
1582     enhanced_fontscale = 1.0;
1583     strncpy(enhanced_escape_format,"&#x%2.2x;",sizeof(enhanced_escape_format));
1584
1585     ENHemf_opened_string = FALSE;
1586     ENHemf_show = TRUE;
1587     ENHemf_overprint = 0;
1588
1589     /* EAM - post.trm wasn't doing this, but how else do they get initialized? */
1590         ENHemf_font = emf_fontname;
1591         ENHemf_fontsize = emf_fontsize;
1592
1593     if (emf_justify == RIGHT) {
1594         EMF_MoveToEx(x - term->h_char * len, term->ymax-y);
1595         EMF_move(x - EMF_AVG_WID * term->h_char * len, y);
1596     } else if (emf_justify == CENTRE) {
1597         EMF_MoveToEx(x - term->h_char * len/2, term->ymax-y);
1598         EMF_move(x - EMF_AVG_WID * term->h_char * len/2, y);
1599     } else {
1600         EMF_MoveToEx(x, term->ymax-y);
1601         EMF_move(x, y);
1602     }
1603
1604     emf_justify = LEFT;
1605 #ifdef UPDATECP_MODE
1606     EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_UPDATECP);
1607 #else
1608     EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_NOUPDATECP);
1609 #endif
1610
1611     /* Set the recursion going. We say to keep going until a
1612      * closing brace, but we don't really expect to find one.
1613      * If the return value is not the nul-terminator of the
1614      * string, that can only mean that we did find an unmatched
1615      * closing brace in the string. We increment past it (else
1616      * we get stuck in an infinite loop) and try again.
1617      */
1618     while (*(str = enhanced_recursion((char *)str, TRUE,
1619                         ENHemf_font, ENHemf_fontsize,
1620                         0.0, TRUE, TRUE, 0))) {
1621         (term->enhanced_flush)();
1622
1623         /* I think we can only get here if *str == '}' */
1624             enh_err_check(str);
1625
1626         if (!*++str)
1627             break; /* end of string */
1628
1629         /* else carry on and process the rest of the string */
1630     }
1631
1632     /* Restore everything we messed with */
1633     emf_justify = tmp_justify;
1634     EMF_setfont(); /* Necessary? */
1635 }
1636
1637 #endif /* TERM_BODY */
1638
1639 #ifdef TERM_TABLE
1640 TERM_TABLE_START(emf_driver)
1641     "emf", "Enhanced Metafile format",
1642     EMF_XMAX, EMF_YMAX, EMF_VCHAR, EMF_HCHAR,
1643     EMF_VTIC, EMF_HTIC, EMF_options, EMF_init, EMF_reset,
1644     EMF_text, null_scale, EMF_graphics, EMF_move, EMF_solid_vector,
1645     EMF_linetype, EMF_put_text, EMF_text_angle,
1646     EMF_justify_text, EMF_point, do_arrow, EMF_set_font,
1647     EMF_set_pointsize,
1648     TERM_BINARY,                /* various flags */
1649     NULL,                               /* suspend */
1650     NULL,                               /* resume  */
1651     EMF_fillbox,
1652     EMF_linewidth
1653 #ifdef USE_MOUSE
1654    , 0, 0, 0, 0, 0 /* no mouse support for emf */
1655 #endif
1656    , EMF_make_palette,
1657    EMF_previous_palette,
1658    EMF_set_color,
1659    EMF_filled_polygon
1660 #ifdef WITH_IMAGE
1661     , NULL
1662 #endif
1663     , ENHemf_OPEN, ENHemf_FLUSH, do_enh_writec
1664 TERM_TABLE_END(emf_driver)
1665 #undef LAST_TERM
1666 #define LAST_TERM emf_driver
1667
1668 #endif /* TERM_TABLE */
1669 #endif /* TERM_PROTO_ONLY */
1670
1671 #ifdef TERM_HELP
1672 START_HELP(emf)
1673 "1 emf",
1674 "?commands set terminal emf",
1675 "?set terminal emf",
1676 "?set term emf",
1677 "?terminal emf",
1678 "?term emf",
1679 "?emf",
1680 " The `emf` terminal generates an Enhanced Metafile Format file.",
1681 " This file format is recognized by many Windows applications.",
1682 "",
1683 " Syntax:",
1684 "       set terminal emf {color | monochrome} {solid | dashed}",
1685 "                        {enhanced {noproportional}}",
1686 "                        {linewidth <LW>} {dashlength <DL>} {size XX,YY}",
1687 "                        {\"<fontname>\"} {<fontsize>}    #old syntax",
1688 "                        {font \"<fontname>,<fontsize>\"} #new syntax",
1689 "",
1690 " In `monochrome` mode successive line types cycle through dash patterns.",
1691 " In `color` mode successive line types use successive colors, and only after",
1692 " all 8 default colors are exhausted is the dash pattern incremented.",
1693 " `solid` draws all curves with solid lines, overriding any dashed patterns;",
1694 " `linewidth <factor>` multiplies all line widths by this factor.",
1695 " `dashlength <factor>` is useful for thick lines.",
1696 " <font> is the name of a font; and ",
1697 " `<fontsize>` is the size of the font in points.",
1698 "",
1699 " The nominal size of the output image defaults to 1024x768 in arbitrary",
1700 " units. You may specify a different nominal size using the `size` option.",
1701 "",
1702 " Enhanced text mode tries to approximate proportional character spacing.",
1703 " If you are using a monospaced font, or don't like the approximation, you",
1704 " can turn off this correction using the `noproportional` option.",
1705 "",
1706 " The default settings are `color dashed font \"Arial,12\" size 1024,768`",
1707 " Selecting `default` sets all options to their default values.",
1708 "",
1709 " Examples:",
1710 "       set terminal emf 'Times Roman Italic' 12",
1711 "       set terminal emf color solid    # no pesky dashes!"
1712 END_HELP(emf)
1713 #endif /* TERM_HELP */