--- /dev/null
+/* Hey Emacs this is -*- C -*-
+ * $Id: emf.trm,v 1.42.2.10 2008/12/14 05:16:25 sfeam Exp $
+ */
+
+/* GNUPLOT - emf.trm */
+
+/*[
+ * Copyright 1998, 2004
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code. Modifications are to
+ * be distributed as patches to the released version. Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ * 1. distribute the corresponding source modifications from the
+ * released version in the form of a patch file along with the binaries,
+ * 2. add special version identification to distinguish your version
+ * in addition to the base release version number,
+ * 3. provide your name and address as the primary contact for the
+ * support of your modified version, and
+ * 4. retain our contact information in regard to use of the base
+ * software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+/*
+ * This file is included by ../term.c and ../docs/termdoc.c.
+ *
+ * This terminal driver supports:
+ * Enhanced Metafile Format
+ *
+ * TODO
+ *
+ * HISTORY
+ *
+ * 4.3.1 12-Sep-2008 Ethan A Merritt
+ * - enhanced text mode
+ * - Two variants are here. One uses the TA_UPDATECP mode to track character position.
+ * This works great horizontally, but I could not find a way to introduce a vertical
+ * offset to handle subscripts and superscripts.
+ * - The second variant tracks both x and y by estimating the character width/height.
+ * This causes visible imperfections in the character spacing.
+ * - Rotated enhanced text not yet supported
+ *
+ * 1.0.11 06-Dec-2004 Ethan A Merritt
+ * - implement term->set_color(), term->filled_polygon(), and term->fillbox()
+ * RGB colors supported, but not yet PM3D palettes
+ * 1.0.10 08-Jul-2004 Hans-Bernhard Broeker
+ * - cleaned up to match gnuplot CodeStyle conventions (one line per statement,
+ * even in macro bodies, no meddling with assert()).
+ * - purged K&R definitions
+ * 1.0.9 03-Jun-2004 Stephane Barbaray <stephane.barbaray@compodata.com>, Ethan Merritt <merritt@u.washington.edu>
+ * - fixed linewidth bug
+ * - all is now really assumed as 1024x768@96dpi,
+ * before it was a mix between 1600x1200@120dpi and 1024x768@96dpi,
+ * so font may now render differently than before...
+ * - pointsize rework (size twice also now)
+ * - HCHAR and VCHAR are more efficiently computed
+ * 1.0.8 06-May-2004 Stephane Barbaray <stephane.barbaray@compodata.com>
+ * - fixed to work with MS security patch (kb835732) applied, because MS introduced bugs!!!
+ * - EMR_EXTTEXTOUTW (84) is now EMR_EXTTEXTOUTA (83)
+ * 1.0.7 3-Feb-2003 Ethan A Merritt
+ * - modify text and point color handling to match other terminal types
+ * - FIXME! alignment of rotated text is not correct.
+ * 1.0.6 25-Jul-2002 Ethan A Merritt <merritt@u.washington.edu>
+ * - generalized text rotation and justification
+ * 1.0.5 2000/07/20
+ * - Handles were not freed at all, resulting to resource leaks when viewing on Windows 9x (not on NT4/W2000!!!)
+ * 1.0.4 2000/06/28
+ * - Emulated dashed vectors are now looking better
+ * - 15 colors * 8 pointstyles = 120 pointtypes
+ * 1.0.3 2000/03/29
+ * - default font is now Arial 12
+ * - implemented options (color/mono,dashed/solid,font)
+ * - 15 colors * 5 dashtypes = 75 linetypes
+ * 1.0.2 2000/03/22
+ * - Polygon and Polyline structures are not working for Windows 9X, I
+ * really don't know why, replaced with lineto/moveto couples...
+ * - Texts are now displayed in GM_Compatible mode because GM_Advanced is
+ * displaying correctly but it does not print correctly with Word97!
+ * - Text centering now works best according to escapement/orientation
+ * - Now there is 8 colors * 5 dashtypes = 40 linetypes
+ * - Successfully Working on Linux Suse 6.1 (x86)
+ *
+ * 1.0.1 2000/03/16
+ * - Unicode text have be to long aligned in EMF files (exttextoutw)
+ * - Problems with text transparence (SetBkMode was not called)
+ * - Null brush created for *not* filling polygon
+ *
+ * 1.0.0 2000/03/15
+ * - Only tested on x86 Win32
+ *
+ * AUTHOR
+ * Stephane Barbaray <stephane.barbaray@compodata.com>
+ * Some code based on cgm.trm
+ *
+ * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
+ */
+
+#include "driver.h"
+
+#ifdef TERM_REGISTER
+register_term(emf)
+#endif
+
+#ifdef TERM_PROTO
+TERM_PUBLIC void EMF_options __PROTO((void));
+TERM_PUBLIC void EMF_init __PROTO((void));
+TERM_PUBLIC void EMF_reset __PROTO((void));
+TERM_PUBLIC void EMF_text __PROTO((void));
+TERM_PUBLIC void EMF_graphics __PROTO((void));
+TERM_PUBLIC void EMF_move __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void EMF_dashed_vector __PROTO((unsigned int ux, unsigned int uy));
+TERM_PUBLIC void EMF_solid_vector __PROTO((unsigned int ux, unsigned int uy));
+TERM_PUBLIC void EMF_linetype __PROTO((int linetype));
+TERM_PUBLIC void EMF_linecolor __PROTO((int color));
+TERM_PUBLIC void EMF_dashtype __PROTO((int dashtype));
+TERM_PUBLIC void EMF_linewidth __PROTO((double width));
+TERM_PUBLIC void EMF_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC int EMF_text_angle __PROTO((int ang));
+TERM_PUBLIC int EMF_justify_text __PROTO((enum JUSTIFY mode));
+TERM_PUBLIC void EMF_point __PROTO((unsigned int x, unsigned int y, int number));
+TERM_PUBLIC void EMF_set_pointsize __PROTO((double size));
+TERM_PUBLIC int EMF_set_font __PROTO((const char *));
+TERM_PUBLIC int EMF_make_palette __PROTO((t_sm_palette *palette));
+TERM_PUBLIC void EMF_previous_palette __PROTO((void));
+TERM_PUBLIC void EMF_set_color __PROTO((t_colorspec *colorspec));
+TERM_PUBLIC void EMF_filled_polygon __PROTO((int, gpiPoint *));
+TERM_PUBLIC void EMF_fillbox __PROTO((int, unsigned int, unsigned int, unsigned int, unsigned int));
+
+/* Enhanced text support */
+TERM_PUBLIC void ENHemf_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC void ENHemf_OPEN __PROTO((char * fontname, double fontsize,
+ double base, TBOOLEAN widthflag, TBOOLEAN showflag,
+ int overprint));
+TERM_PUBLIC void ENHemf_FLUSH __PROTO((void));
+
+#undef RGB
+#define RGB(r,g,b) ((long) \
+ (((unsigned char)(r) \
+ | ((short) ((unsigned char) (g)) << 8)) \
+ | (((long) (unsigned char) (b)) << 16)))
+
+#ifndef GPMIN
+# define GPMIN(a,b) (a < b ? a : b)
+#endif
+
+#ifndef GPMAX
+# define GPMAX(a,b) (a > b ? a : b)
+#endif
+
+#define EMF_PX2HM 26.37
+#define EMF_PT2HM 35.28
+#define EMF_10THDEG2RAD (3.14159265359/1800)
+#define EMF_XMAX (1024 * EMF_PX2HM)
+#define EMF_YMAX (768 * EMF_PX2HM)
+#define EMF_HTIC (EMF_XMAX / 160)
+#define EMF_VTIC EMF_HTIC
+#define EMF_FONTNAME "Arial"
+#define EMF_FONTSIZE 12
+#define EMF_HCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 0.6)
+#define EMF_VCHAR ((EMF_FONTSIZE * EMF_PT2HM) * 1.3)
+#define EMF_LINE_TYPES 5 /* number of line types we support */
+#define EMF_COLORS 15 /* number of colors we support */
+#define EMF_POINTS 13 /* number of markers we support */
+#define EMF_MAX_SEGMENTS 104 /* maximum # polyline coordinates */
+
+#define EMF_HANDLE_PEN 1
+#define EMF_HANDLE_FONT 2
+#define EMF_HANDLE_BRUSH 3
+#define EMF_HANDLE_MAX 4
+
+#define EMF_STOCK_OBJECT_FLAG ((unsigned long)0x1 << 31)
+#define EMF_STOCK_OBJECT_WHITE_BRUSH (EMF_STOCK_OBJECT_FLAG + 0x00)
+#define EMF_STOCK_OBJECT_BLACK_PEN (EMF_STOCK_OBJECT_FLAG + 0x07)
+#define EMF_STOCK_OBJECT_DEFAULT_FONT (EMF_STOCK_OBJECT_FLAG + 0x0A)
+
+#define EMF_write_emr(type, size) { \
+ EMF_write_long(type); \
+ EMF_write_long(size); \
+ emf_record_count++; \
+}
+#define EMF_write_sizel(width, height) { \
+ EMF_write_long(width); \
+ EMF_write_long(height); \
+}
+#define EMF_write_points(x, y) { \
+ EMF_write_short(x); \
+ EMF_write_short(y); \
+}
+#define EMF_write_pointl(x, y) { \
+ EMF_write_long(x); \
+ EMF_write_long(y); \
+}
+#define EMF_write_rectl(left, top, right, bottom) { \
+ EMF_write_long(left); \
+ EMF_write_long(top); \
+ EMF_write_long(right); \
+ EMF_write_long(bottom); \
+}
+
+#define EMF_EOF() { \
+ EMF_write_emr(14, 20); \
+ EMF_write_long(0); \
+ EMF_write_long(0x10); \
+ EMF_write_long(20); \
+}
+#define EMF_SetMapMode(mode) { \
+ EMF_write_emr(17, 0x0C); \
+ EMF_write_long(mode); \
+}
+#define EMF_SetWindowExtEx(width, height) { \
+ EMF_write_emr(9, 0x10); \
+ EMF_write_sizel(width, height); \
+}
+#define EMF_SetWindowOrgEx(width, height) { \
+ EMF_write_emr(10, 0x10); \
+ EMF_write_sizel(width, height); \
+}
+#define EMF_SetViewportExtEx(width, height) { \
+ EMF_write_emr(11, 0x10); \
+ EMF_write_sizel(width, height); \
+}
+#define EMF_SetViewportOrgEx(width, height) { \
+ EMF_write_emr(12, 0x10); \
+ EMF_write_sizel(width, height); \
+}
+#define EMF_SetTextColor(color) { \
+ EMF_write_emr(24, 0x0C); \
+ EMF_write_long(color); \
+}
+#define EMF_MoveToEx(x,y) { \
+ EMF_write_emr(27, 0x10); \
+ EMF_write_pointl(x, y); \
+}
+#define EMF_LineTo(x,y) { \
+ EMF_write_emr(54, 0x10); \
+ EMF_write_pointl(x, y); \
+}
+#define EMF_CreatePen(handle, type, width, color) { \
+ EMF_write_emr(38, 0x1C); \
+ EMF_write_long(handle); \
+ EMF_write_long(type); \
+ EMF_write_long(width); \
+ EMF_write_long(0); \
+ EMF_write_long(color); \
+}
+#define EMF_CreateBrush(handle, type, color, hatch) { \
+ EMF_write_emr(39, 0x18); \
+ EMF_write_long(handle); \
+ EMF_write_long(type); \
+ EMF_write_long(color); \
+ EMF_write_long(hatch); \
+}
+#define EMF_SelectObject(handle) { \
+ EMF_write_emr(37, 0x0C); \
+ EMF_write_long(handle); \
+}
+#define EMF_DeleteObject(handle) { \
+ EMF_write_emr(40, 0x0C); \
+ EMF_write_long(handle); \
+}
+#define EMF_SetTextAlign(align) { \
+ EMF_write_emr(22, 0x0C); \
+ EMF_write_long(align); \
+}
+#define EMF_SetBkMode(mode) { \
+ EMF_write_emr(18, 0x0C); \
+ EMF_write_long(mode); \
+}
+#define EMF_SaveDC() { \
+ EMF_write_emr(33, 0x0C); \
+ EMF_write_long(0); \
+}
+#define EMF_RestoreDC() { \
+ EMF_write_emr(34, 0x0C); \
+ EMF_write_long(1); \
+}
+
+#endif /* TERM_PROTO */
+
+#ifndef TERM_PROTO_ONLY
+#ifdef TERM_BODY
+
+#include <ctype.h> /* for isspace() */
+
+static unsigned int emf_posx;
+static unsigned int emf_posy;
+static unsigned int emf_record_count = 0;
+static unsigned int emf_linetype = 1;
+static unsigned int emf_dashtype = 0;
+static unsigned long emf_color = 0L;
+static unsigned long emf_textcolor = LT_UNDEFINED;
+static unsigned int emf_colors = EMF_COLORS;
+static unsigned int emf_polyline[EMF_MAX_SEGMENTS]; /* stored polyline coordinates */
+static unsigned int emf_graphics = FALSE;
+static unsigned int emf_dashed = TRUE;
+static unsigned int emf_monochrome = FALSE;
+static double emf_linewidth; /* line width in plot units */
+static double emf_linewidth_factor = 1.0;
+static double emf_dashlength = 1.0;
+static int emf_coords = 0; /* # polyline coordinates saved */
+static char emf_fontname[255] = EMF_FONTNAME;
+static float emf_fontsize = EMF_FONTSIZE;
+static enum JUSTIFY emf_justify = LEFT;
+static char emf_defaultfontname[255] = EMF_FONTNAME;
+static float emf_defaultfontsize = EMF_FONTSIZE;
+static int emf_vert_text = 0; /* text orientation -- nonzero for vertical */
+static int emf_step_sizes[8]; /* array of currently used dash lengths in plot units */
+static int emf_step_index = 0; /* index into emf_step_sizes[] */
+static int emf_step = 0; /* amount of current dash not yet drawn, in plot units */
+static int emf_tic, emf_tic707, emf_tic866, emf_tic500, emf_tic1241, emf_tic1077, emf_tic621; /* marker dimensions */
+
+static TBOOLEAN emf_tweak = TRUE; /* Empirical hack to adjust character widths */
+
+static void EMF_flush_polyline __PROTO((void));
+static void EMF_flush_polygon __PROTO((void));
+static void EMF_write_byte __PROTO((int));
+static void EMF_write_short __PROTO((int));
+static void EMF_write_long __PROTO((unsigned long));
+static void EMF_write_float __PROTO((double));
+static void EMF_setfont __PROTO((void));
+
+#define ANSI_CHARSET 0
+#define DEFAULT_CHARSET 1
+#define GREEK_CHARSET 161
+#define TURKISH_CHARSET 162
+#define BALTIC_CHARSET 186
+#define RUSSIAN_CHARSET 204
+#define EASTEUROPE_CHARSET 238
+#define KOI8_CHARSET 242
+
+/* Text alignment */
+#define TA_NOUPDATECP 0x00
+#define TA_UPDATECP 0x01
+#define TA_LEFT 0x00
+#define TA_RIGHT 0x02
+#define TA_CENTER 0x06
+#define TA_TOP 0x00
+#define TA_BOTTOM 0x08
+#define TA_BASELINE 0x18
+
+/* ExtTextOut options */
+#define ETO_NO_RECT 0x100
+#define ETO_PDY 0x2000
+
+static void
+EMF_setfont()
+{
+ int i, count;
+ int bold = 400;
+ char italic = 0, underline = 0, strikeout = 0;
+ char font[32];
+ char *sub;
+
+ if (!emf_graphics)
+ return;
+
+ count = GPMIN (strlen(emf_fontname), 31);
+ if (((sub = strstr(emf_fontname, " bold")) != NULL)
+ || ((sub = strstr(emf_fontname, " Bold")) != NULL)) {
+ bold = 700;
+ count = GPMIN(sub - emf_fontname, count);
+ }
+ if (((sub = strstr(emf_fontname, " italic")) != NULL)
+ || ((sub = strstr(emf_fontname, " Italic")) != NULL)) {
+ italic = 1;
+ count = GPMIN(sub - emf_fontname, count);
+ }
+ if (((sub = strstr(emf_fontname, " underline")) != NULL)
+ || ((sub = strstr(emf_fontname, " Underline")) != NULL)) {
+ underline = 1;
+ count = GPMIN(sub - emf_fontname, count);
+ }
+ if (((sub = strstr(emf_fontname, " strikeout")) != NULL)
+ || ((sub = strstr(emf_fontname, " Strikeout")) != NULL)
+ || ((sub = strstr(emf_fontname, " StrikeOut")) != NULL)
+ ) {
+ strikeout = 1;
+ count = GPMIN(sub - emf_fontname, count);
+ }
+
+ safe_strncpy(font, emf_fontname, count + 1);
+
+ EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
+ EMF_DeleteObject(EMF_HANDLE_FONT);
+
+ /* SB 20040506: was not complete size was 104, now it is 332 */
+ EMF_write_emr(82, 332);
+ EMF_write_long(EMF_HANDLE_FONT);
+ EMF_write_long((long) (-emf_fontsize * EMF_PT2HM)); /* height */
+ EMF_write_long(0); /* width */
+ EMF_write_long(emf_vert_text); /* escapement */
+ EMF_write_long(emf_vert_text); /* orientation */
+ EMF_write_long(bold); /* weight */
+ EMF_write_byte(italic); /* italic */
+ EMF_write_byte(underline); /* underline */
+ EMF_write_byte(strikeout); /* strikeout */
+
+ /* charset: could be extended? */
+ switch (encoding) {
+ case S_ENC_CP1250:
+ case S_ENC_ISO8859_2:
+ EMF_write_byte(EASTEUROPE_CHARSET);
+ break;
+ case S_ENC_KOI8_R:
+ case S_ENC_KOI8_U:
+ EMF_write_byte(KOI8_CHARSET);
+ break;
+ default:
+ EMF_write_byte(DEFAULT_CHARSET);
+ }
+
+ EMF_write_byte(0); /* out precision */
+ EMF_write_byte(0); /* clip precision */
+ EMF_write_byte(0); /* quality */
+ EMF_write_byte(0); /* pitch and family */
+ for (i = 0; i < 32; i++) {
+ /* face name (max 32) */
+ EMF_write_byte((char) (i < strlen(font) ? font[i] : 0));
+ EMF_write_byte(0);
+ }
+
+ /* SB 20040506: modification following */
+ for (i = 0; i < 64; i++) {
+ /* FULL face name (max 64) */
+ EMF_write_byte((char) (i < strlen(font) ? font[i] : 0));
+ EMF_write_byte(0);
+ }
+ for (i = 0; i < 32; i++) {
+ /* style name (max 32) */
+ EMF_write_byte(0);
+ EMF_write_byte(0);
+ }
+ EMF_write_long(0); /* version */
+ EMF_write_long(0); /* Style size */
+ EMF_write_long(0); /* Match */
+ EMF_write_long(0); /* reserved */
+ EMF_write_long(0); /* VendorId */
+ EMF_write_long(0); /* Culture */
+ for (i = 0; i < 10; i++)
+ EMF_write_byte(0); /* Panose (ignored) */
+ EMF_write_byte(0); /* pad (long aligned) */
+ EMF_write_byte(0); /* pad (long aligned) */
+ /* SB 20040506: End of modification */
+
+ EMF_SelectObject(EMF_HANDLE_FONT);
+}
+
+static void
+EMF_flush_polygon()
+{
+ int i = 0;
+
+ if (emf_coords == 0)
+ return;
+
+ EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
+ while (i < emf_coords * 2)
+ EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
+ EMF_LineTo(emf_polyline[0], term->ymax - emf_polyline[1]);
+
+ emf_coords = 0;
+}
+
+static void
+EMF_flush_polyline()
+{
+ if (emf_coords == 0)
+ return;
+
+ if (emf_coords <= 2) {
+ EMF_MoveToEx(emf_polyline[0], term->ymax - emf_polyline[1]);
+ EMF_LineTo(emf_polyline[2], term->ymax - emf_polyline[3]);
+ } else {
+ int i = 0;
+
+#if 0 /* was commented out */
+ /* Polyline works for NT4 but not on W9x */
+ EMF_write_emr(4,(7+emf_coords*2)*4);
+ EMF_write_rectl(0,0,0,0);
+ EMF_write_long(emf_coords);
+ while(i < emf_coords*2)
+ EMF_write_pointl(emf_polyline[i++],term->ymax-emf_polyline[i++]);
+#endif /* 0 */
+
+ EMF_MoveToEx(emf_polyline[i++], term->ymax - emf_polyline[i++]);
+ while (i < emf_coords * 2)
+ EMF_LineTo(emf_polyline[i++], term->ymax - emf_polyline[i++]);
+ }
+ emf_coords = 0;
+}
+
+/* HBB 20040708: the following keep K&R argument types for now */
+static void
+EMF_write_byte(int value)
+{
+ char c = value;
+ fwrite(&c, 1, 1, gpoutfile);
+}
+
+static void
+EMF_write_short(int value)
+{
+ short actual_value = value;
+ char c[2];
+
+ c[1] = (actual_value >> 8) & 255; /* convert to x86 order */
+ c[0] = actual_value & 255;
+
+ fwrite(c, 1, 2, gpoutfile);
+}
+
+static void
+EMF_write_long(unsigned long value)
+{
+ char c[4];
+
+ c[3] = (value >> 24) & 0xFFL; /* convert to x86 order */
+ c[2] = (value >> 16) & 0xFFL;
+ c[1] = (value >> 8) & 0xFFL;
+ c[0] = value & 0xFFL;
+
+ fwrite(c, 1, 4, gpoutfile);
+}
+
+/* FIXME HBB 20001103: this only works as given iff 'float' is the
+ * same format as on x86's, i.e. IEEE 4-byte floating point format */
+static void
+EMF_write_float(double value)
+{
+ char c[4];
+
+ union {
+ long l;
+ float f;
+ } u;
+
+ u.f = value;
+
+ c[3] = (u.l >> 24) & 0xFFL; /* convert to x86 order */
+ c[2] = (u.l >> 16) & 0xFFL;
+ c[1] = (u.l >> 8) & 0xFFL;
+ c[0] = u.l & 0xFFL;
+
+ fwrite(c, 1, 4, gpoutfile);
+}
+
+TERM_PUBLIC void
+EMF_options()
+{
+ char *s;
+
+ /* Annoying hack to handle the case of 'set termoption' after */
+ /* we have already initialized the terminal. */
+ if (c_token != 2) {
+ term->xmax = EMF_XMAX;
+ term->ymax = EMF_YMAX;
+ emf_dashed = TRUE;
+ emf_monochrome = FALSE;
+ emf_tweak = TRUE;
+ }
+
+ while (!END_OF_COMMAND) {
+ if (almost_equals(c_token, "de$fault")) {
+ strcpy(emf_defaultfontname, EMF_FONTNAME);
+ emf_defaultfontsize = EMF_FONTSIZE;
+ emf_monochrome = FALSE;
+ emf_dashed = TRUE;
+ c_token++;
+ continue;
+ }
+ if (almost_equals(c_token, "m$onochrome")) {
+ emf_monochrome = TRUE;
+ c_token++;
+ continue;
+ }
+ if (almost_equals(c_token, "c$olor") || almost_equals(c_token, "c$olour")) {
+ emf_monochrome = FALSE;
+ c_token++;
+ continue;
+ }
+ if (almost_equals(c_token, "da$shed")) {
+ emf_dashed = TRUE;
+ c_token++;
+ continue;
+ }
+ if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
+ struct value a;
+ c_token++;
+ emf_dashlength = real(const_express(&a));
+ if (emf_dashlength < 0.5)
+ emf_dashlength = 1.0;
+ continue;
+ }
+ if (almost_equals(c_token, "s$olid")) {
+ emf_dashed = FALSE;
+ c_token++;
+ continue;
+ }
+ if (equals(c_token, "lw") || almost_equals(c_token, "linew$idth")) {
+ struct value a;
+ c_token++;
+ emf_linewidth_factor = real(const_express(&a));
+ if (emf_linewidth_factor < 0.1)
+ emf_linewidth_factor = 1.0;
+ continue;
+ }
+
+ if (almost_equals(c_token,"enh$anced")) {
+ c_token++;
+ term->put_text = ENHemf_put_text;
+ term->flags |= TERM_ENHANCED_TEXT;
+ continue;
+ } else if (almost_equals(c_token,"noenh$anced")) {
+ c_token++;
+ term->put_text = EMF_put_text;
+ term->flags &= ~TERM_ENHANCED_TEXT;
+ }
+
+ if (almost_equals(c_token,"nopro$portional")) {
+ c_token++;
+ emf_tweak = FALSE;
+ }
+
+ if (almost_equals(c_token, "si$ze")) {
+ int tempxmax = 1024;
+ int tempymax = 768;
+ struct value a;
+ c_token++;
+ if (!END_OF_COMMAND) {
+ tempxmax = real(const_express(&a));
+ if (equals(c_token, ",")) {
+ c_token++;
+ tempymax = real(const_express(&a));
+ }
+ }
+ if (tempxmax > 0)
+ term->xmax = tempxmax * EMF_PX2HM;
+ if (tempymax > 0)
+ term->ymax = tempymax * EMF_PX2HM;
+ term->h_tic = term->xmax / 160;
+ term->v_tic = term->h_tic;
+ continue;
+ }
+ if (equals(c_token, "font"))
+ c_token++;
+ /* Fall through to old-style bare font name */
+ if ((s = try_to_get_string())) {
+ char *comma = strrchr(s,',');
+ if (comma && (1 == sscanf(comma+1,"%g",&emf_defaultfontsize))) {
+ *comma = '\0';
+ }
+ if (*s)
+ strncpy(emf_defaultfontname, s, sizeof(emf_defaultfontname));
+ free(s);
+ if (isanumber(c_token)) {
+ struct value a;
+ emf_defaultfontsize = (int) real(const_express(&a));
+ }
+ continue;
+ }
+ break;
+ } /* while(!end of command) */
+
+ if (!END_OF_COMMAND) {
+ /* We have old-style bare font size specified */
+ struct value a;
+ emf_defaultfontsize = (int) real(const_express(&a));
+ }
+ EMF_set_font(NULL); /* set default font */
+
+ emf_colors = emf_monochrome ? 1 : EMF_COLORS;
+
+ sprintf(term_options, "%s %s \"%s\" %g",
+ emf_monochrome ? "monochrome" : "color",
+ emf_dashed ? "dashed" : "solid",
+ emf_defaultfontname, emf_defaultfontsize);
+
+ if (term->flags & TERM_ENHANCED_TEXT)
+ strcat(term_options, " enhanced ");
+ if (term->xmax != (int)EMF_XMAX || term->ymax != (int)EMF_YMAX)
+ sprintf(&(term_options[strlen(term_options)]), " size %d,%d ",
+ (int)(0.5+term->xmax/EMF_PX2HM), (int)(0.5+term->ymax/EMF_PX2HM));
+ if (emf_linewidth_factor != 1.0)
+ sprintf(&(term_options[strlen(term_options)]), " lw %.1f",
+ emf_linewidth_factor);
+ if (emf_dashlength != 1.0)
+ sprintf(&(term_options[strlen(term_options)]), " dashlength %.1f",
+ emf_dashlength);
+}
+
+TERM_PUBLIC void
+EMF_init()
+{
+ emf_posx = emf_posy = 0;
+ emf_linetype = 0;
+ emf_vert_text = 0;
+ emf_graphics = FALSE;
+}
+
+TERM_PUBLIC void
+EMF_graphics()
+{
+ int width = 0.5 + term->xmax/EMF_PX2HM;
+ int height = 0.5 + term->ymax/EMF_PX2HM;
+ int mmwidth = 0.5 + (term->xmax/EMF_PX2HM) * (270./1024.);
+ int mmheight = 0.5 + (term->ymax/EMF_PX2HM) * (200./768.);
+
+ /* header start */
+ emf_record_count = 0;
+ EMF_write_emr(1, 100);
+ EMF_write_long(0); /* rclBounds */
+ EMF_write_long(0);
+ EMF_write_long(term->xmax / EMF_PX2HM);
+ EMF_write_long(term->ymax / EMF_PX2HM);
+ EMF_write_long(0); /* rclFrame */
+ EMF_write_long(0);
+ EMF_write_long(term->xmax);
+ EMF_write_long(term->ymax);
+ EMF_write_long(0x464D4520); /* signature */
+ EMF_write_long(0x00010000); /* version */
+ EMF_write_long(0); /* nBytes */
+ EMF_write_long(0); /* nRecords */
+ EMF_write_short(EMF_HANDLE_MAX); /* nHandles, MUST NOT BE 0 */
+ EMF_write_short(0); /* reserved */
+ EMF_write_long(0); /* descSize */
+ EMF_write_long(0); /* descOff */
+ EMF_write_long(0); /* nPalEntries */
+ EMF_write_long(width); /* ref dev pixwidth, default 1024 */
+ EMF_write_long(height); /* ref dev pixheight, default 768 */
+ EMF_write_long(mmwidth); /* ref dev mwidth, default 270 */
+ EMF_write_long(mmheight); /* ref dev mheight, default 200 */
+ EMF_write_long(0); /* cbPixelFormat */
+ EMF_write_long(0); /* offPixelFormat */
+ EMF_write_long(0); /* bOpenGL */
+ emf_graphics = TRUE;
+ /* header end */
+
+ EMF_SetMapMode(8); /* forcing anisotropic mode */
+ EMF_SetWindowExtEx(term->xmax, term->ymax); /* setting logical (himetric) size */
+ EMF_SetViewportExtEx(term->xmax / EMF_PX2HM, term->ymax / EMF_PX2HM); /* setting device (pixel) size */
+ EMF_CreatePen(EMF_HANDLE_PEN, 0, 1, 0x000000); /* init default pen */
+ EMF_SelectObject(EMF_HANDLE_PEN);
+ EMF_SetBkMode(1); /* transparent background for text */
+ EMF_CreateBrush(EMF_HANDLE_BRUSH, 1, 0, 0); /* transparent brush for polygons */
+ EMF_SelectObject(EMF_HANDLE_BRUSH);
+ EMF_set_font(NULL); /* init default font */
+}
+
+TERM_PUBLIC int
+EMF_set_font(const char *font)
+{
+ static float last_fontsize = -1;
+ static char last_fontname[256] = {'\0'};
+
+ if (font && *font) {
+ float tempsize;
+ int sep = strcspn(font,",");
+ if (sep > 0)
+ safe_strncpy(emf_fontname, font, GPMIN(sep + 1, 32));
+ if (sep < strlen(font) && sscanf(font+sep+1, "%f", &tempsize))
+ emf_fontsize = tempsize;
+ } else {
+ strcpy(emf_fontname, emf_defaultfontname);
+ emf_fontsize = emf_defaultfontsize;
+ }
+
+ /* Optimization only */
+ if (!strcmp(last_fontname,emf_fontname) && last_fontsize == emf_fontsize) {
+ return TRUE;
+ }
+
+ term->h_char = (emf_fontsize * EMF_PT2HM)*0.6;
+ term->v_char = (emf_fontsize * EMF_PT2HM)*1.3;
+ EMF_setfont();
+ return TRUE;
+}
+
+TERM_PUBLIC void
+EMF_text()
+{
+ long pos;
+ EMF_flush_polyline();
+
+ /* writing end of metafile */
+ EMF_SelectObject(EMF_STOCK_OBJECT_DEFAULT_FONT);
+ EMF_DeleteObject(EMF_HANDLE_FONT);
+ EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
+ EMF_DeleteObject(EMF_HANDLE_PEN);
+ EMF_SelectObject(EMF_STOCK_OBJECT_WHITE_BRUSH);
+ EMF_DeleteObject(EMF_HANDLE_BRUSH);
+ EMF_EOF();
+
+ /* updating header */
+ pos = ftell(gpoutfile);
+ fseek(gpoutfile, 48, SEEK_SET);
+ EMF_write_long(pos);
+ EMF_write_long(emf_record_count);
+ /* HBB 20010228: have to make known that we're no longer in graphics
+ * status. */
+ emf_graphics = FALSE;
+}
+
+TERM_PUBLIC void
+EMF_linetype(int linetype)
+{
+ /* Note : separating linetype and color would have not been futile, but anyway... */
+
+#if (0) /* Not safe because linetype/color/pen are intermixed */
+ if (linetype == emf_linetype)
+ return;
+#endif
+
+ if (linetype == LT_NODRAW)
+ linetype = LT_BACKGROUND;
+
+ emf_linetype = linetype;
+
+ EMF_linecolor(linetype);
+ EMF_dashtype(linetype);
+}
+
+TERM_PUBLIC void
+EMF_linecolor(int linecolor)
+{
+ static long GPFAR color_table_data[] =
+ {
+ RGB(255, 0, 0), /* red */
+ RGB(0, 255, 0), /* green */
+ RGB(0, 0, 255), /* blue */
+ RGB(255, 0, 255), /* magenta */
+ RGB(0, 0, 128), /* dark blue */
+ RGB(128, 0, 0), /* dark red */
+ RGB(0, 128, 128), /* dark cyan */
+ RGB(0, 0, 0), /* black */
+ RGB(128, 128, 128), /* grey */
+ RGB(0, 128, 64), /* very dark cyan */
+ RGB(128, 128, 0), /* dark yellow */
+ RGB(128, 0, 128), /* dark magenta */
+ RGB(192, 192, 192), /* light grey */
+ RGB(0, 255, 255), /* cyan */
+ RGB(255, 255, 0) /* yellow */
+ };
+
+ if (linecolor == LT_BACKGROUND)
+ emf_color = RGB(255, 255, 255); /* white (background) */
+ else {
+ linecolor = (linecolor < 0 || emf_monochrome) ? 7 : (linecolor % EMF_COLORS);
+ emf_color = color_table_data[linecolor];
+ }
+
+ EMF_flush_polyline();
+}
+
+TERM_PUBLIC int EMF_make_palette(t_sm_palette *palette)
+{
+ return 0; /* can do continous colors */
+}
+
+TERM_PUBLIC void EMF_previous_palette()
+{
+ /* do nothing */
+}
+
+TERM_PUBLIC void
+EMF_set_color(t_colorspec *colorspec)
+{
+ rgb255_color rgb255;
+
+ if (colorspec->type == TC_LT) {
+ EMF_linecolor(colorspec->lt);
+ } else if (colorspec->type == TC_FRAC) {
+ rgb255maxcolors_from_gray(colorspec->value, &rgb255);
+ emf_color = RGB(rgb255.r, rgb255.g, rgb255.b);
+ } else if (colorspec->type == TC_RGB) {
+ emf_color = RGB( colorspec->lt >> 16 & 0xff,
+ colorspec->lt >> 8 & 0xff,
+ colorspec->lt & 0xff );
+ }
+
+ /*
+ else {
+ fprintf(stderr, "unhandled colorspec type %d\n", colorspec->type);
+ }
+ */
+
+ /* Force reevaluation of dash type */
+ emf_dashtype = LT_UNDEFINED;
+ EMF_dashtype(emf_linetype);
+}
+
+TERM_PUBLIC void
+EMF_filled_polygon(int points, gpiPoint *corners)
+{
+ int i;
+ unsigned long color = emf_color;
+ int fillpar = corners->style >> 4;
+ int style = corners->style & 0xf;
+
+#define EMF_POLYGON 3
+
+ switch (style) {
+ case FS_EMPTY: /* fill with background color */
+ color = RGB(255,255,255);
+ break;
+ case FS_PATTERN: /* pattern fill implemented as partial density */
+ fillpar *= 12;
+ case FS_SOLID: /* solid fill */
+ if (fillpar >= 0 && fillpar < 100) {
+ double density = (double)fillpar / 100.;
+ color = ((int)((double)((emf_color>>16)&0xff)*density) << 16)
+ + ((int)((double)((emf_color>>8)&0xff)*density) << 8)
+ + ((int)((double)(emf_color&0xff)*density));
+ color += ((int)(255.*(1.-density)) << 16)
+ + ((int)(255.*(1.-density)) << 8)
+ + ((int)(255.*(1.-density)));
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Sequence of operations cribbed from Windows example */
+ EMF_CreateBrush(EMF_HANDLE_BRUSH, 0, color, 0);
+ EMF_SelectObject(EMF_HANDLE_BRUSH);
+
+ EMF_write_emr(EMF_POLYGON, (7 + 2*points) * 4);
+ EMF_write_rectl(0,0,0,0); /* What are these? */
+ EMF_write_long(points);
+ for (i=0; i<points; i++)
+ EMF_write_pointl(corners[i].x, term->ymax - corners[i].y);
+
+ EMF_DeleteObject(EMF_HANDLE_BRUSH);
+
+ /* Force re-evaluation of linetype next time we draw a line */
+ emf_linetype = LT_UNDEFINED;
+ emf_dashtype = LT_UNDEFINED;
+}
+
+TERM_PUBLIC void
+EMF_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
+{
+ gpiPoint corner[4];
+
+ corner[0].x = x1; corner[0].y = y1;
+ corner[1].x = x1+width; corner[1].y = y1;
+ corner[2].x = x1+width; corner[2].y = y1+height;
+ corner[3].x = x1; corner[3].y = y1+height;
+ corner->style = style;
+
+ EMF_filled_polygon(4, corner);
+}
+
+TERM_PUBLIC void
+EMF_linewidth(double width)
+{
+ int current_dashtype = emf_dashtype;
+
+ width *= emf_linewidth_factor;
+ if (width == emf_linewidth)
+ return;
+ emf_linewidth = width;
+
+ emf_dashtype = LT_UNDEFINED; /* Invalidate current dash type */
+ EMF_dashtype(current_dashtype); /* Force re-evaluation of dash type */
+}
+
+/*
+ * Resets _both_ line color and dash type!
+ */
+TERM_PUBLIC void
+EMF_dashtype(int dashtype)
+{
+ int i, j;
+ /* Each group of 8 entries in dot_length[] defines a dash
+ pattern. Entries in each group are alternately length of
+ whitespace and length of line, in units of 2/3 of the
+ linewidth. */
+ static int dot_length[EMF_LINE_TYPES * 8] =
+ { /* 0 - solid */
+ 5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes */
+ 4, 2, 4, 2, 4, 2, 4, 2, /* 2 - dotted */
+ 4, 8, 4, 2, 4, 8, 4, 2, /* 3 - dash-dot */
+ 4, 9, 4, 2, 4, 2, 0, 0, /* 4 - dash-dot-dot */
+ };
+
+ emf_dashtype = dashtype;
+
+ EMF_flush_polyline();
+
+ if (dashtype >= 0)
+ dashtype = (dashtype / emf_colors) % EMF_LINE_TYPES;
+
+ if (dashtype == LT_AXIS)
+ dashtype = 2;
+
+ if (dashtype < 1 || !emf_dashed) { /* solid mode */
+ EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
+ EMF_DeleteObject(EMF_HANDLE_PEN);
+ EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
+ EMF_SelectObject(EMF_HANDLE_PEN);
+
+ term->vector = EMF_solid_vector;
+ } else { /* Since win32 dashed lines works only with 1 pixel linewith we must emulate */
+ EMF_SelectObject(EMF_STOCK_OBJECT_BLACK_PEN);
+ EMF_DeleteObject(EMF_HANDLE_PEN);
+ EMF_CreatePen(EMF_HANDLE_PEN, 0, emf_linewidth * EMF_PX2HM, emf_color);
+ EMF_SelectObject(EMF_HANDLE_PEN);
+
+ term->vector = EMF_dashed_vector;
+
+ /* set up dash dimensions */
+ j = (dashtype - 1) * 8;
+ for (i = 0; i < 8; i++, j++) {
+ emf_step_sizes[i] = dot_length[j] * emf_dashlength * EMF_PX2HM;
+ }
+ /* first thing drawn will be a line */
+ emf_step = emf_step_sizes[1];
+ emf_step_index = 1;
+ }
+}
+
+TERM_PUBLIC void
+EMF_move(unsigned int x, unsigned int y)
+{
+ if (x >= term->xmax || y >= term->ymax) {
+ int_warn(NO_CARET, "emf_move: (%d,%d) out of range",x,y);
+ x = GPMIN(x, term->xmax); y = GPMIN(y, term->ymax);
+ }
+ if (x == emf_posx && y == emf_posy)
+ return;
+ EMF_flush_polyline();
+ emf_posx = x;
+ emf_posy = y;
+}
+
+TERM_PUBLIC void
+EMF_dashed_vector(unsigned int ux, unsigned int uy)
+{
+ int xa, ya;
+ int dx, dy, adx, ady;
+ int dist; /* approximate distance in plot units from starting point to specified end point. */
+ long remain; /* approximate distance in plot units remaining to specified end point. */
+
+ if (ux >= term->xmax || uy >= term->ymax)
+ int_warn(NO_CARET, "emf_dashed_vector: (%d,%d) out of range",ux,uy);
+
+ dx = (ux - emf_posx);
+ dy = (uy - emf_posy);
+ adx = abs(dx);
+ ady = abs(dy * 10);
+
+ /* using the approximation sqrt(x**2 + y**2) ~ x + (5*x*x)/(12*y) when x > y.
+ Note ordering of calculations to avoid overflow on 16 bit architectures */
+ if (10 * adx < ady)
+ dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5;
+ else {
+ if (adx == 0)
+ return;
+ dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10;
+ }
+ remain = dist;
+ xa = emf_posx;
+ ya = emf_posy;
+ while (remain > emf_step) {
+ remain -= emf_step;
+ if (emf_step_index & 1)
+ EMF_solid_vector((int) (ux - (remain * dx) / dist),
+ (int) (uy - (remain * dy) / dist));
+ else {
+ xa = (int) (ux - (remain * dx) / dist);
+ ya = (int) (uy - (remain * dy) / dist);
+ EMF_move(xa, ya);
+ }
+ if (++emf_step_index >= 8)
+ emf_step_index = 0;
+ emf_step = emf_step_sizes[emf_step_index];
+ }
+ if (emf_step_index & 1)
+ EMF_solid_vector(ux, uy);
+ else
+ EMF_move(ux, uy);
+ emf_step -= (int) remain;
+}
+
+TERM_PUBLIC void
+EMF_solid_vector(unsigned int ux, unsigned int uy)
+{
+ if (ux >= term->xmax || uy >= term->ymax)
+ int_warn(NO_CARET, "emf_solid_vector: (%d,%d) out of range",ux,uy);
+ if (ux == emf_posx && uy == emf_posy)
+ return;
+ if (emf_coords * 2 > EMF_MAX_SEGMENTS - 2)
+ EMF_flush_polyline();
+ if (emf_coords == 0) {
+ emf_polyline[0] = emf_posx;
+ emf_polyline[1] = emf_posy;
+ emf_coords++;
+ }
+ emf_posx = emf_polyline[emf_coords * 2] = ux;
+ emf_posy = emf_polyline[emf_coords * 2 + 1] = uy;
+ emf_coords++;
+}
+
+TERM_PUBLIC void
+EMF_put_text(unsigned int x, unsigned int y, const char str[])
+{
+ int i, len = strlen(str);
+
+ EMF_flush_polyline();
+ if (emf_textcolor != emf_color) {
+ EMF_SetTextColor(emf_color); /* since text doesn't use pens, we must initialize with this */
+ emf_textcolor = emf_color;
+ }
+
+ /* SB 20040506: offset array now included since it won't work with MS Security patch (kb835732) */
+ /* SB 20040506: also changed function from unicode to ansi version */
+ if (len % 4)
+ len += 4 - (len % 4); /* Structure must be long aligned! */
+ EMF_write_emr(83, 76 + len + strlen(str)*4);/* ExtTextOutA, ANSI char version! */
+ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */
+ EMF_write_long(1); /* GM_Compatible mode for advanced scaling */
+ EMF_write_float(EMF_PX2HM); /* x scale */
+ EMF_write_float(EMF_PX2HM); /* y scale */
+ /* positioning... y is recentered from bottom reference set in
+ * text align */
+ EMF_write_pointl(
+ x + (long) ((EMF_VCHAR / 2) * sin(emf_vert_text * EMF_10THDEG2RAD)),
+ term->ymax - y + (long) (EMF_VCHAR / 2
+ * cos(emf_vert_text * EMF_10THDEG2RAD)));
+ EMF_write_long(strlen(str)); /* real char size */
+ EMF_write_long(76); /* offset to text */
+ EMF_write_long(0); /* options, none */
+ EMF_write_rectl(0, 0, 0, 0); /* rectangle clipping not used */
+ 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 */
+ for (i = 0; i < len; i++)
+ EMF_write_byte(i<strlen(str)?str[i]:0); /* writing text */
+ for (i = 0; i < strlen(str); i++)
+ /* writing intercharacter spacing array (but we don't use it) */
+ EMF_write_long(300);
+ /* SB 20040506: end of modification */
+
+ emf_posx = emf_posy = -2000;
+}
+
+TERM_PUBLIC int
+EMF_text_angle(int ang)
+{
+ /* Win GDI rotation is scaled in tenth of degrees, so... */
+ switch (ang) {
+ case 0: /* left right */
+ if (emf_vert_text != 0) {
+ emf_vert_text = 0;
+ EMF_setfont();
+ }
+ break;
+ case TEXT_VERTICAL: /* bottom up */
+ if (emf_vert_text != 900) {
+ emf_vert_text = 900;
+ EMF_setfont();
+ }
+ break;
+ default: /* the general case */
+ emf_vert_text = 10 * ang;
+ EMF_setfont();
+ break;
+ }
+ return TRUE;
+}
+
+TERM_PUBLIC int
+EMF_justify_text(enum JUSTIFY mode)
+{
+ int align = TA_BOTTOM;
+
+ emf_justify = mode;
+
+ switch (mode) {
+ case LEFT:
+ align |= TA_LEFT;
+ break;
+ case RIGHT:
+ align |= TA_RIGHT;
+ break;
+ case CENTRE:
+ align |= TA_CENTER;
+ break;
+ }
+ EMF_SetTextAlign(align);
+
+ return (TRUE);
+}
+
+TERM_PUBLIC void
+EMF_reset()
+{
+ emf_posx = emf_posy = 0;
+ emf_graphics = FALSE;
+}
+
+TERM_PUBLIC void
+EMF_point(unsigned int x, unsigned int y, int number)
+{
+ int old_dashtype;
+ gpiPoint corners[12];
+ corners->style = FS_OPAQUE;
+
+ EMF_flush_polyline();
+ old_dashtype = emf_dashtype;
+ EMF_dashtype(0);
+
+ /* if (number < 0)*/
+ {
+ /* draw dot */
+ EMF_move(x, y);
+ EMF_solid_vector(x + 1, y);
+ /* goto end_points;*/
+ }
+ number = number % EMF_POINTS;
+
+ switch (number) {
+ case 0: /* draw plus */
+ EMF_move(x - emf_tic, y);
+ EMF_solid_vector(x + emf_tic, y);
+ EMF_move(x, y - emf_tic);
+ EMF_solid_vector(x, y + emf_tic);
+ break;
+ case 1: /* draw X */
+ EMF_move(x - emf_tic707, y - emf_tic707);
+ EMF_solid_vector(x + emf_tic707, y + emf_tic707);
+ EMF_move(x - emf_tic707, y + emf_tic707);
+ EMF_solid_vector(x + emf_tic707, y - emf_tic707);
+ break;
+ case 2: /* draw star (asterisk) */
+ EMF_move(x, y - emf_tic);
+ EMF_solid_vector(x, y + emf_tic);
+ EMF_move(x + emf_tic866, y - emf_tic500);
+ EMF_solid_vector(x - emf_tic866, y + emf_tic500);
+ EMF_move(x + emf_tic866, y + emf_tic500);
+ EMF_solid_vector(x - emf_tic866, y - emf_tic500);
+ break;
+ case 3: /* draw box */
+ EMF_move(x - emf_tic707, y - emf_tic707);
+ EMF_solid_vector(x + emf_tic707, y - emf_tic707);
+ EMF_solid_vector(x + emf_tic707, y + emf_tic707);
+ EMF_solid_vector(x - emf_tic707, y + emf_tic707);
+ EMF_flush_polygon();
+ break;
+ case 4: /* draw filled box */
+ corners[0].x = x - emf_tic707; corners[0].y = y - emf_tic707;
+ corners[1].x = x + emf_tic707; corners[1].y = y - emf_tic707;
+ corners[2].x = x + emf_tic707; corners[2].y = y + emf_tic707;
+ corners[3].x = x - emf_tic707; corners[3].y = y + emf_tic707;
+ EMF_filled_polygon(4, corners);
+ break;
+ case 5:
+ /* draw circle (actually, dodecagon) (WinWord 6 accepts the
+ * CGM "circle" element, but the resulting circle is not
+ * correctly centered!) */
+ EMF_move(x, y - emf_tic);
+ EMF_solid_vector(x + emf_tic500, y - emf_tic866);
+ EMF_solid_vector(x + emf_tic866, y - emf_tic500);
+ EMF_solid_vector(x + emf_tic, y);
+ EMF_solid_vector(x + emf_tic866, y + emf_tic500);
+ EMF_solid_vector(x + emf_tic500, y + emf_tic866);
+ EMF_solid_vector(x, y + emf_tic);
+ EMF_solid_vector(x - emf_tic500, y + emf_tic866);
+ EMF_solid_vector(x - emf_tic866, y + emf_tic500);
+ EMF_solid_vector(x - emf_tic, y);
+ EMF_solid_vector(x - emf_tic866, y - emf_tic500);
+ EMF_solid_vector(x - emf_tic500, y - emf_tic866);
+ EMF_flush_polygon();
+ break;
+ case 6: /* filled circle */
+ corners [0].x = x ; corners [0].y = y - emf_tic;
+ corners [1].x = x + emf_tic500; corners [1].y = y - emf_tic866;
+ corners [2].x = x + emf_tic866; corners [2].y = y - emf_tic500;
+ corners [3].x = x + emf_tic ; corners [3].y = y;
+ corners [4].x = x + emf_tic866; corners [4].y = y + emf_tic500;
+ corners [5].x = x + emf_tic500; corners [5].y = y + emf_tic866;
+ corners [6].x = x ; corners [6].y = y + emf_tic;
+ corners [7].x = x - emf_tic500; corners [7].y = y + emf_tic866;
+ corners [8].x = x - emf_tic866; corners [8].y = y + emf_tic500;
+ corners [9].x = x - emf_tic ; corners [9].y = y;
+ corners[10].x = x - emf_tic866; corners[10].y = y - emf_tic500;
+ corners[11].x = x - emf_tic500; corners[11].y = y - emf_tic866;
+ EMF_filled_polygon(12, corners);
+ break;
+ case 7: /* draw triangle (point up) */
+ EMF_move(x, y + emf_tic1241);
+ EMF_solid_vector(x - emf_tic1077, y - emf_tic621);
+ EMF_solid_vector(x + emf_tic1077, y - emf_tic621);
+ EMF_flush_polygon();
+ break;
+ case 8: /* filled triangle point up */
+ corners[0].x = x ; corners[0].y = y + emf_tic1241;
+ corners[1].x = x - emf_tic1077 ; corners[1].y = y - emf_tic621;
+ corners[2].x = x + emf_tic1077 ; corners[2].y = y - emf_tic621;
+ EMF_filled_polygon(3, corners);
+ break;
+ case 9: /* draw triangle (point down) */
+ EMF_move(x, y - emf_tic1241);
+ EMF_solid_vector(x - emf_tic1077, y + emf_tic621);
+ EMF_solid_vector(x + emf_tic1077, y + emf_tic621);
+ EMF_flush_polygon();
+ break;
+ case 10: /* filled triangle point down */
+ corners[0].x = x ; corners[0].y = y - emf_tic1241;
+ corners[1].x = x - emf_tic1077 ; corners[1].y = y + emf_tic621;
+ corners[2].x = x + emf_tic1077 ; corners[2].y = y + emf_tic621;
+ EMF_filled_polygon(3, corners);
+ break;
+ case 11: /* draw diamond */
+ EMF_move(x - emf_tic, y);
+ EMF_solid_vector(x, y - emf_tic);
+ EMF_solid_vector(x + emf_tic, y);
+ EMF_solid_vector(x, y + emf_tic);
+ EMF_flush_polygon();
+ break;
+ case 12: /* filled diamond */
+ corners[0].x = x - emf_tic ; corners[0].y = y;
+ corners[1].x = x ; corners[1].y = y - emf_tic;
+ corners[2].x = x + emf_tic ; corners[2].y = y;
+ corners[3].x = x ; corners[3].y = y + emf_tic;
+ EMF_filled_polygon(4, corners);
+ break;
+ }
+/* end_points: */
+ EMF_dashtype(old_dashtype);
+}
+
+
+TERM_PUBLIC void
+EMF_set_pointsize(double size)
+{
+ if (size < 0)
+ size = 1;
+ emf_tic = (size * term->h_tic);
+ emf_tic707 = emf_tic * 12 / 17;
+ emf_tic866 = emf_tic * 13 / 15;
+ emf_tic500 = emf_tic / 2;
+ emf_tic1241 = emf_tic * 36 / 29;
+ emf_tic1077 = emf_tic * 14 / 13;
+ emf_tic621 = emf_tic * 18 / 29;
+}
+
+/*
+ * Ethan A Merritt September 2008
+ * - Support for enhanced text mode
+ * PROBLEMS:
+ * - Rotated enhanced text is not handled
+ * - The proportional spacing hack is really ugly
+ * ETO_PDY is supposed to handle this, but pre-Vista Windows
+ * doesn't support the flag so it's of no real use.
+ */
+
+static TBOOLEAN ENHemf_opened_string;
+
+/* used in determining height of processed text */
+static float ENHemf_base;
+
+/* use these so that we don't over-write the current font settings */
+static float ENHemf_fontsize;
+static char *ENHemf_font;
+
+static TBOOLEAN ENHemf_show = TRUE;
+static int ENHemf_overprint = 0;
+
+TERM_PUBLIC void
+ENHemf_OPEN(
+ char *fontname,
+ double fontsize, double base,
+ TBOOLEAN widthflag,
+ TBOOLEAN showflag,
+ int overprint)
+{
+
+ /* If the overprint code requests a save or restore, that's all we do */
+#define EMF_AVG_WID 0.8
+#undef TA_UPDATECP_MODE
+#ifdef TA_UPDATECP_MODE
+ if (overprint == 3) {
+ EMF_SaveDC();
+ return;
+ } else if (overprint == 4) {
+ EMF_RestoreDC();
+ return;
+ }
+#else
+ static int save_x, save_y;
+ if (overprint == 3) {
+ save_x = emf_posx;
+ save_y = emf_posy;
+ return;
+ } else if (overprint == 4) {
+ emf_posx = save_x;
+ emf_posy = save_y;
+ return;
+ }
+#endif
+
+ if (!ENHemf_opened_string) {
+ ENHemf_opened_string = TRUE;
+ enhanced_cur_text = &enhanced_text[0];
+ ENHemf_font = fontname;
+ ENHemf_fontsize = fontsize;
+ ENHemf_base = base;
+ ENHemf_show = showflag;
+ ENHemf_overprint = overprint;
+ }
+}
+
+/* Write a string fragment and update the current position */
+TERM_PUBLIC void
+ENHemf_FLUSH()
+{
+ unsigned int x, y;
+ char *str;
+ int i;
+ int incr_x;
+ double strl;
+
+ if (ENHemf_opened_string) {
+ *enhanced_cur_text = '\0';
+ ENHemf_opened_string = FALSE;
+ x = emf_posx;
+ y = emf_posy;
+
+ FPRINTF((stderr,"ENHemf_FLUSH: Write string \"%s\" len %d at %g with font %s,%g\n",
+ enhanced_text,strlen(enhanced_text),
+ (double)x/EMF_PX2HM,ENHemf_font,ENHemf_fontsize));
+
+ if (1) {
+ char save_font[256];
+ float save_fontsize = emf_fontsize;
+ strcpy(save_font,emf_fontname);
+ emf_fontsize = ENHemf_fontsize;
+
+ EMF_set_font(ENHemf_font);
+
+ emf_fontsize = save_fontsize;
+ strcpy(emf_fontname,save_font);
+ }
+
+ /* Don't know how to do a pure move; instead write in white */
+ if (!ENHemf_show) {
+ EMF_SetTextColor(0xffffff);
+ emf_textcolor = 0xffffff;
+ } else if (ENHemf_show && emf_textcolor != emf_color) {
+ EMF_SetTextColor(emf_color);
+ emf_textcolor = emf_color;
+ }
+
+ str = enhanced_text;
+
+#ifndef TA_UPDATEPC_MODE
+ /* We are especially bad at guessing the width of whitespace. */
+ /* Best is to pile up all our errors on top of leading space. */
+ i = strspn(enhanced_text," ");
+ if (i > 0) {
+ x += i * term->h_char
+ * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize;
+ emf_posx = x;
+ str += i;
+ }
+#endif
+
+ /* Copied from put_text(). Is all this really necessary? */
+ {
+ int record_length;
+ int len = strlen(str);
+ if (len % 4)
+ len += 4 - (len % 4); /* Structure must be long aligned! */
+ record_length = 76 + len + strlen(str)*4;
+
+ EMF_write_emr(83, record_length);/* ExtTextOutA, ANSI char version! */
+ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */
+ EMF_write_long(1); /* GM_Compatible mode for advanced scaling */
+ EMF_write_float(EMF_PX2HM); /* x scale */
+ EMF_write_float(EMF_PX2HM); /* y scale */
+ if (emf_vert_text == 0) { /* x,y position (ignored if TA_UPDATECP) */
+ float yo = 1.3 * EMF_PX2HM * ENHemf_base;
+ EMF_write_pointl(
+ x, term->ymax - (y + yo));
+ } else {
+ float a = emf_vert_text * EMF_10THDEG2RAD;
+ float yo = 1.3 * EMF_PX2HM * ENHemf_base;
+ EMF_write_pointl(
+ x - (long) (yo * sin(a)),
+ term->ymax - (long) (y + (yo * cos(a))) );
+ }
+ EMF_write_long(strlen(str)); /* true number of characters */
+ EMF_write_long(76); /* offset to text */
+ EMF_write_long(ETO_NO_RECT); /* ExtTextOut options */
+ EMF_write_rectl(0, 0, 0, 0); /* bounding, never used */
+ EMF_write_long(0); /* offset to intercharacter spacing array */
+ for (i = 0; i < len; i++)
+ EMF_write_byte(i<strlen(str)?str[i]:0); /* character string */
+ for (i = 0; i < strlen(str); i++)
+ EMF_write_long(300); /* intercharacter spacing array (not used) */
+ }
+
+ /* Empirical hack */
+ strl = strlen(str);
+ if (emf_vert_text != 0)
+ strl += 1.0;
+
+ if (emf_tweak) {
+ /* Tweak estimated length of rendered string by counting "thin" characters */
+ /* In principle EMF will accept an array of char widths. But in practice */
+ /* none of the EMF viewers implement this option (ETO_PDY). */
+ {
+ int thin = 0, wide = 0;
+ for (i=0; i<strlen(str); i++) {
+ if (strchr(" ijl.,;:|!()[]1I",str[i]))
+ thin++;
+ if (('A' <= str[i] && str[i] <= 'Z') || strchr("mw<>",str[i]))
+ wide++;
+ if('i' == str[i])
+ thin++;
+ }
+ incr_x = (strl * EMF_AVG_WID + (double)(wide-thin) * 0.2)
+ * term->h_char;
+ }
+ } else {
+ incr_x = strl * EMF_AVG_WID * term->h_char;
+ }
+
+ /* Attempt to handle slanted text. Not entirely successful */
+ emf_posx += incr_x * cos(emf_vert_text * EMF_10THDEG2RAD);
+ emf_posy += incr_x * sin(emf_vert_text * EMF_10THDEG2RAD);
+
+ if (ENHemf_overprint == 1)
+ emf_posx -= strlen(str) * term->h_char
+ * (0.5) * EMF_AVG_WID * ENHemf_fontsize/emf_defaultfontsize;
+
+ }
+}
+
+TERM_PUBLIC void
+ENHemf_put_text(unsigned int x, unsigned int y, const char *str)
+{
+ int tmp_justify = emf_justify;
+ int len;
+
+ if (ignore_enhanced_text) {
+ EMF_put_text(x,y,str);
+ return;
+ }
+
+ if (!strlen(str))
+ return;
+ len = estimate_strlen((char *)str);
+
+ /* if there are no magic characters, we should just be able
+ * punt the string to EMF_put_text()
+ */
+ if (!strpbrk(str, "{}^_@&~")) {
+ /* FIXME: do something to ensure default font is selected */
+ EMF_put_text(x,y,str);
+ return;
+ }
+
+ if (emf_textcolor != emf_color) {
+ EMF_SetTextColor(emf_color);
+ emf_textcolor = emf_color;
+ }
+
+ /* set up the global variables needed by enhanced_recursion() */
+ enhanced_fontscale = 1.0;
+ strncpy(enhanced_escape_format,"&#x%2.2x;",sizeof(enhanced_escape_format));
+
+ ENHemf_opened_string = FALSE;
+ ENHemf_show = TRUE;
+ ENHemf_overprint = 0;
+
+ /* EAM - post.trm wasn't doing this, but how else do they get initialized? */
+ ENHemf_font = emf_fontname;
+ ENHemf_fontsize = emf_fontsize;
+
+ if (emf_justify == RIGHT) {
+ EMF_MoveToEx(x - term->h_char * len, term->ymax-y);
+ EMF_move(x - EMF_AVG_WID * term->h_char * len, y);
+ } else if (emf_justify == CENTRE) {
+ EMF_MoveToEx(x - term->h_char * len/2, term->ymax-y);
+ EMF_move(x - EMF_AVG_WID * term->h_char * len/2, y);
+ } else {
+ EMF_MoveToEx(x, term->ymax-y);
+ EMF_move(x, y);
+ }
+
+ emf_justify = LEFT;
+#ifdef UPDATECP_MODE
+ EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_UPDATECP);
+#else
+ EMF_SetTextAlign(TA_BASELINE|TA_LEFT|TA_NOUPDATECP);
+#endif
+
+ /* Set the recursion going. We say to keep going until a
+ * closing brace, but we don't really expect to find one.
+ * If the return value is not the nul-terminator of the
+ * string, that can only mean that we did find an unmatched
+ * closing brace in the string. We increment past it (else
+ * we get stuck in an infinite loop) and try again.
+ */
+ while (*(str = enhanced_recursion((char *)str, TRUE,
+ ENHemf_font, ENHemf_fontsize,
+ 0.0, TRUE, TRUE, 0))) {
+ (term->enhanced_flush)();
+
+ /* I think we can only get here if *str == '}' */
+ enh_err_check(str);
+
+ if (!*++str)
+ break; /* end of string */
+
+ /* else carry on and process the rest of the string */
+ }
+
+ /* Restore everything we messed with */
+ emf_justify = tmp_justify;
+ EMF_setfont(); /* Necessary? */
+}
+
+#endif /* TERM_BODY */
+
+#ifdef TERM_TABLE
+TERM_TABLE_START(emf_driver)
+ "emf", "Enhanced Metafile format",
+ EMF_XMAX, EMF_YMAX, EMF_VCHAR, EMF_HCHAR,
+ EMF_VTIC, EMF_HTIC, EMF_options, EMF_init, EMF_reset,
+ EMF_text, null_scale, EMF_graphics, EMF_move, EMF_solid_vector,
+ EMF_linetype, EMF_put_text, EMF_text_angle,
+ EMF_justify_text, EMF_point, do_arrow, EMF_set_font,
+ EMF_set_pointsize,
+ TERM_BINARY, /* various flags */
+ NULL, /* suspend */
+ NULL, /* resume */
+ EMF_fillbox,
+ EMF_linewidth
+#ifdef USE_MOUSE
+ , 0, 0, 0, 0, 0 /* no mouse support for emf */
+#endif
+ , EMF_make_palette,
+ EMF_previous_palette,
+ EMF_set_color,
+ EMF_filled_polygon
+#ifdef WITH_IMAGE
+ , NULL
+#endif
+ , ENHemf_OPEN, ENHemf_FLUSH, do_enh_writec
+TERM_TABLE_END(emf_driver)
+#undef LAST_TERM
+#define LAST_TERM emf_driver
+
+#endif /* TERM_TABLE */
+#endif /* TERM_PROTO_ONLY */
+
+#ifdef TERM_HELP
+START_HELP(emf)
+"1 emf",
+"?commands set terminal emf",
+"?set terminal emf",
+"?set term emf",
+"?terminal emf",
+"?term emf",
+"?emf",
+" The `emf` terminal generates an Enhanced Metafile Format file.",
+" This file format is recognized by many Windows applications.",
+"",
+" Syntax:",
+" set terminal emf {color | monochrome} {solid | dashed}",
+" {enhanced {noproportional}}",
+" {linewidth <LW>} {dashlength <DL>} {size XX,YY}",
+" {\"<fontname>\"} {<fontsize>} #old syntax",
+" {font \"<fontname>,<fontsize>\"} #new syntax",
+"",
+" In `monochrome` mode successive line types cycle through dash patterns.",
+" In `color` mode successive line types use successive colors, and only after",
+" all 8 default colors are exhausted is the dash pattern incremented.",
+" `solid` draws all curves with solid lines, overriding any dashed patterns;",
+" `linewidth <factor>` multiplies all line widths by this factor.",
+" `dashlength <factor>` is useful for thick lines.",
+" <font> is the name of a font; and ",
+" `<fontsize>` is the size of the font in points.",
+"",
+" The nominal size of the output image defaults to 1024x768 in arbitrary",
+" units. You may specify a different nominal size using the `size` option.",
+"",
+" Enhanced text mode tries to approximate proportional character spacing.",
+" If you are using a monospaced font, or don't like the approximation, you",
+" can turn off this correction using the `noproportional` option.",
+"",
+" The default settings are `color dashed font \"Arial,12\" size 1024,768`",
+" Selecting `default` sets all options to their default values.",
+"",
+" Examples:",
+" set terminal emf 'Times Roman Italic' 12",
+" set terminal emf color solid # no pesky dashes!"
+END_HELP(emf)
+#endif /* TERM_HELP */