Code

functional noop: (EmfWin32::save): Remove an unneeded strdup operation.
[inkscape.git] / src / extension / internal / emf-win32-inout.cpp
1 /** @file
2  * @brief Windows-only Enhanced Metafile input and output.
3  */
4 /* Authors:
5  *   Ulf Erikson <ulferikson@users.sf.net>
6  *
7  * Copyright (C) 2006-2008 Authors
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  *
11  * References:
12  *  - How to Create & Play Enhanced Metafiles in Win32
13  *      http://support.microsoft.com/kb/q145999/
14  *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
15  *      http://support.microsoft.com/kb/q66949/
16  *  - Metafile Functions
17  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
18  *  - Metafile Structures
19  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
20  */
22 #ifdef WIN32
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 //#include "inkscape.h"
29 #include "sp-path.h"
30 #include "style.h"
31 //#include "color.h"
32 //#include "display/curve.h"
33 //#include "libnr/nr-point-matrix-ops.h"
34 //#include "gtk/gtk.h"
35 #include "print.h"
36 //#include "glibmm/i18n.h"
37 //#include "extension/extension.h"
38 #include "extension/system.h"
39 #include "extension/print.h"
40 #include "extension/db.h"
41 #include "extension/output.h"
42 //#include "document.h"
43 #include "display/nr-arena.h"
44 #include "display/nr-arena-item.h"
46 //#include "libnr/nr-rect.h"
47 //#include "libnr/nr-matrix.h"
48 //#include "libnr/nr-pixblock.h"
50 //#include <stdio.h>
51 //#include <string.h>
53 //#include <vector>
54 //#include <string>
56 //#include "io/sys.h"
58 #include "unit-constants.h"
60 #include "clear-n_.h"
62 #define WIN32_LEAN_AND_MEAN
63 #include <windows.h>
65 #include "win32.h"
66 #include "emf-win32-print.h"
67 #include "emf-win32-inout.h"
70 #define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32"
72 #ifndef PS_JOIN_MASK
73 #define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND)
74 #endif
77 namespace Inkscape {
78 namespace Extension {
79 namespace Internal {
82 EmfWin32::EmfWin32 (void) // The null constructor
83 {
84     return;
85 }
88 EmfWin32::~EmfWin32 (void) //The destructor
89 {
90     return;
91 }
94 bool
95 EmfWin32::check (Inkscape::Extension::Extension * /*module*/)
96 {
97     if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32))
98         return FALSE;
99     return TRUE;
103 static void
104 emf_print_document_to_file(SPDocument *doc, gchar const *filename)
106     Inkscape::Extension::Print *mod;
107     SPPrintContext context;
108     gchar const *oldconst;
109     gchar *oldoutput;
110     unsigned int ret;
112     sp_document_ensure_up_to_date(doc);
114     mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32);
115     oldconst = mod->get_param_string("destination");
116     oldoutput = g_strdup(oldconst);
117     mod->set_param_string("destination", filename);
119 /* Start */
120     context.module = mod;
121     /* fixme: This has to go into module constructor somehow */
122     /* Create new arena */
123     mod->base = SP_ITEM(sp_document_root(doc));
124     mod->arena = NRArena::create();
125     mod->dkey = sp_item_display_key_new(1);
126     mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);
127     /* Print document */
128     ret = mod->begin(doc);
129     if (ret) {
130         throw Inkscape::Extension::Output::save_failed();
131     }
132     sp_item_invoke_print(mod->base, &context);
133     ret = mod->finish();
134     /* Release arena */
135     sp_item_invoke_hide(mod->base, mod->dkey);
136     mod->base = NULL;
137     mod->root = NULL;
138     nr_object_unref((NRObject *) mod->arena);
139     mod->arena = NULL;
140 /* end */
142     mod->set_param_string("destination", oldoutput);
143     g_free(oldoutput);
145     return;
149 void
150 EmfWin32::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
152     Inkscape::Extension::Extension * ext;
154     ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32);
155     if (ext == NULL)
156         return;
158     bool old_textToPath  = ext->get_param_bool("textToPath");
159     bool new_val         = mod->get_param_bool("textToPath");
160     ext->set_param_bool("textToPath", new_val);
162     emf_print_document_to_file(doc, filename);
164     ext->set_param_bool("textToPath", old_textToPath);
166     return;
171 typedef struct {
172     int type;
173     int level;
174     ENHMETARECORD *lpEMFR;
175 } EMF_OBJECT, *PEMF_OBJECT;
177 typedef struct emf_device_context {
178     struct SPStyle style;
179     class SPTextStyle tstyle;
180     bool stroke_set;
181     bool fill_set;
183     SIZEL sizeWnd;
184     SIZEL sizeView;
185     float PixelsInX, PixelsInY;
186     float PixelsOutX, PixelsOutY;
187     POINTL winorg;
188     POINTL vieworg;
189     double ScaleInX, ScaleInY;
190     double ScaleOutX, ScaleOutY;
191     COLORREF textColor;
192     bool textColorSet;
193     DWORD textAlign;
194     XFORM worldTransform;
195     POINTL cur;
196 } EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT;
198 #define EMF_MAX_DC 128
200 typedef struct emf_callback_data {
201     Glib::ustring *outsvg;
202     Glib::ustring *path;
204     EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
205     int level;
206     
207     double xDPI, yDPI;
208     bool pathless_stroke;
209     bool inpath;
211     float MMX;
212     float MMY;
213     float dwInchesX;
214     float dwInchesY;
216     unsigned int id;
217     CHAR *pDesc;
219     int n_obj;
220     PEMF_OBJECT emf_obj;
221 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
224 static void
225 output_style(PEMF_CALLBACK_DATA d, int iType)
227     SVGOStringStream tmp_id;
228     SVGOStringStream tmp_style;
229     char tmp[1024] = {0};
231     float fill_rgb[3];
232     sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
233     
234     float stroke_rgb[3];
235     sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
237     tmp_id << "\n\tid=\"" << (d->id++) << "\"";
238     *(d->outsvg) += tmp_id.str().c_str();
239     *(d->outsvg) += "\n\tstyle=\"";
240     if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) {
241         tmp_style << "fill:none;";
242     } else {
243         snprintf(tmp, 1023,
244                  "fill:#%02x%02x%02x;",
245                  SP_COLOR_F_TO_U(fill_rgb[0]),
246                  SP_COLOR_F_TO_U(fill_rgb[1]),
247                  SP_COLOR_F_TO_U(fill_rgb[2]));
248         tmp_style << tmp;
249         snprintf(tmp, 1023,
250                  "fill-rule:%s;",
251                  d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero");
252         tmp_style << tmp;
253         tmp_style << "fill-opacity:1;";
255         if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 &&
256             fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
257         {
258             d->dc[d->level].stroke_set = false;
259         }
260     }
262     if (iType == EMR_FILLPATH || !d->dc[d->level].stroke_set) {
263         tmp_style << "stroke:none;";
264     } else {
265         snprintf(tmp, 1023,
266                  "stroke:#%02x%02x%02x;",
267                  SP_COLOR_F_TO_U(stroke_rgb[0]),
268                  SP_COLOR_F_TO_U(stroke_rgb[1]),
269                  SP_COLOR_F_TO_U(stroke_rgb[2]));
270         tmp_style << tmp;
272         tmp_style << "stroke-width:" <<
273             MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
275         tmp_style << "stroke-linecap:" <<
276             (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
277              d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
278              d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
279              "unknown") << ";";
281         tmp_style << "stroke-linejoin:" <<
282             (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
283              d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
284              d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
285              "unknown") << ";";
287         if (d->dc[d->level].style.stroke_linejoin.computed == 0) {
288             tmp_style << "stroke-miterlimit:" <<
289                 MAX( 0.01, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
290         }
292         if (d->dc[d->level].style.stroke_dasharray_set &&
293             d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash)
294         {
295             tmp_style << "stroke-dasharray:";
296             for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) {
297                 if (i)
298                     tmp_style << ",";
299                 tmp_style << d->dc[d->level].style.stroke_dash.dash[i];
300             }
301             tmp_style << ";";
302             tmp_style << "stroke-dashoffset:0;";
303         } else {
304             tmp_style << "stroke-dasharray:none;";
305         }
306         tmp_style << "stroke-opacity:1;";
307     }
308     tmp_style << "\" ";
310     *(d->outsvg) += tmp_style.str().c_str();
314 static double
315 _pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
317     double tmp = px - d->dc[d->level].winorg.x;
318     tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0;
319     tmp += d->dc[d->level].vieworg.x;
320     return tmp;
323 static double
324 _pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
326     double tmp = px - d->dc[d->level].winorg.y;
327     tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0;
328     tmp += d->dc[d->level].vieworg.y;
329     return tmp;
333 static double
334 pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
336     double ppx = _pix_x_to_point(d, px);
337     double ppy = _pix_y_to_point(d, py);
339     double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
340     x *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE;
341     
342     return x;
345 static double
346 pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
348     double ppx = _pix_x_to_point(d, px);
349     double ppy = _pix_y_to_point(d, py);
351     double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
352     y *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE;
353     
354     return y;
357 static double
358 pix_to_size_point(PEMF_CALLBACK_DATA d, double px)
360     double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
361     double ppy = 0;
363     double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21;
364     dx *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE;
365     double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22;
366     dy *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE;
368     double tmp = sqrt(dx * dx + dy * dy);
369     return tmp;
373 static void
374 select_pen(PEMF_CALLBACK_DATA d, int index)
376     PEMRCREATEPEN pEmr = NULL;
378     if (index >= 0 && index < d->n_obj)
379         pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
381     if (!pEmr)
382         return;
384     switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) {
385         case PS_DASH:
386         case PS_DOT:
387         case PS_DASHDOT:
388         case PS_DASHDOTDOT:
389         {
390             int i = 0;
391             int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK);
392             d->dc[d->level].style.stroke_dash.n_dash =
393                 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
394             if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
395                 delete[] d->dc[d->level].style.stroke_dash.dash;
396             d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
397             if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
398                 d->dc[d->level].style.stroke_dash.dash[i++] = 3;
399                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
400             }
401             if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
402                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
403                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
404             }
405             if (penstyle==PS_DASHDOTDOT) {
406                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
407                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
408             }
409             
410             d->dc[d->level].style.stroke_dasharray_set = 1;
411             break;
412         }
413         
414         case PS_SOLID:
415         default:
416         {
417             d->dc[d->level].style.stroke_dasharray_set = 0;
418             break;
419         }
420     }
422     switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) {
423         case PS_ENDCAP_ROUND:
424         {
425             d->dc[d->level].style.stroke_linecap.computed = 1;
426             break;
427         }
428         case PS_ENDCAP_SQUARE:
429         {
430             d->dc[d->level].style.stroke_linecap.computed = 2;
431             break;
432         }
433         case PS_ENDCAP_FLAT:
434         default:
435         {
436             d->dc[d->level].style.stroke_linecap.computed = 0;
437             break;
438         }
439     }
441     switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) {
442         case PS_JOIN_BEVEL:
443         {
444             d->dc[d->level].style.stroke_linejoin.computed = 2;
445             break;
446         }
447         case PS_JOIN_MITER:
448         {
449             d->dc[d->level].style.stroke_linejoin.computed = 0;
450             break;
451         }
452         case PS_JOIN_ROUND:
453         default:
454         {
455             d->dc[d->level].style.stroke_linejoin.computed = 1;
456             break;
457         }
458     }
460     d->dc[d->level].stroke_set = true;
462     if (pEmr->lopn.lopnStyle == PS_NULL) {
463         d->dc[d->level].style.stroke_width.value = 0;
464         d->dc[d->level].stroke_set = false;
465     } else if (pEmr->lopn.lopnWidth.x) {
466         int cur_level = d->level;
467         d->level = d->emf_obj[index].level;
468         double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x );
469         d->level = cur_level;
470         d->dc[d->level].style.stroke_width.value = pen_width;
471     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
472         //d->dc[d->level].style.stroke_width.value = 1.0;
473         int cur_level = d->level;
474         d->level = d->emf_obj[index].level;
475         double pen_width = pix_to_size_point( d, 1 );
476         d->level = cur_level;
477         d->dc[d->level].style.stroke_width.value = pen_width;
478     }
480     double r, g, b;
481     r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
482     g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
483     b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
484     d->dc[d->level].style.stroke.value.color.set( r, g, b );
488 static void
489 select_extpen(PEMF_CALLBACK_DATA d, int index)
491     PEMREXTCREATEPEN pEmr = NULL;
493     if (index >= 0 && index < d->n_obj)
494         pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
496     if (!pEmr)
497         return;
499     switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
500         case PS_USERSTYLE:
501         {
502             if (pEmr->elp.elpNumEntries) {
503                 d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
504                 if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
505                     delete[] d->dc[d->level].style.stroke_dash.dash;
506                 d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
507                 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
508                     int cur_level = d->level;
509                     d->level = d->emf_obj[index].level;
510                     double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] );
511                     d->level = cur_level;
512                     d->dc[d->level].style.stroke_dash.dash[i] = dash_length;
513                 }
514                 d->dc[d->level].style.stroke_dasharray_set = 1;
515             } else {
516                 d->dc[d->level].style.stroke_dasharray_set = 0;
517             }
518             break;
519         }
521         case PS_DASH:
522         case PS_DOT:
523         case PS_DASHDOT:
524         case PS_DASHDOTDOT:
525         {
526             int i = 0;
527             int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK);
528             d->dc[d->level].style.stroke_dash.n_dash =
529                 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
530             if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash)))
531                 delete[] d->dc[d->level].style.stroke_dash.dash;
532             d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
533             if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
534                 d->dc[d->level].style.stroke_dash.dash[i++] = 3;
535                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
536             }
537             if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
538                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
539                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
540             }
541             if (penstyle==PS_DASHDOTDOT) {
542                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
543                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
544             }
545             
546             d->dc[d->level].style.stroke_dasharray_set = 1;
547             break;
548         }
549         
550         case PS_SOLID:
551         default:
552         {
553             d->dc[d->level].style.stroke_dasharray_set = 0;
554             break;
555         }
556     }
558     switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
559         case PS_ENDCAP_ROUND:
560         {
561             d->dc[d->level].style.stroke_linecap.computed = 1;
562             break;
563         }
564         case PS_ENDCAP_SQUARE:
565         {
566             d->dc[d->level].style.stroke_linecap.computed = 2;
567             break;
568         }
569         case PS_ENDCAP_FLAT:
570         default:
571         {
572             d->dc[d->level].style.stroke_linecap.computed = 0;
573             break;
574         }
575     }
577     switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
578         case PS_JOIN_BEVEL:
579         {
580             d->dc[d->level].style.stroke_linejoin.computed = 2;
581             break;
582         }
583         case PS_JOIN_MITER:
584         {
585             d->dc[d->level].style.stroke_linejoin.computed = 0;
586             break;
587         }
588         case PS_JOIN_ROUND:
589         default:
590         {
591             d->dc[d->level].style.stroke_linejoin.computed = 1;
592             break;
593         }
594     }
596     d->dc[d->level].stroke_set = true;
598     if (pEmr->elp.elpPenStyle == PS_NULL) {
599         d->dc[d->level].style.stroke_width.value = 0;
600         d->dc[d->level].stroke_set = false;
601     } else if (pEmr->elp.elpWidth) {
602         int cur_level = d->level;
603         d->level = d->emf_obj[index].level;
604         double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth );
605         d->level = cur_level;
606         d->dc[d->level].style.stroke_width.value = pen_width;
607     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
608         //d->dc[d->level].style.stroke_width.value = 1.0;
609         int cur_level = d->level;
610         d->level = d->emf_obj[index].level;
611         double pen_width = pix_to_size_point( d, 1 );
612         d->level = cur_level;
613         d->dc[d->level].style.stroke_width.value = pen_width;
614     }
616     double r, g, b;
617     r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
618     g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
619     b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
621     d->dc[d->level].style.stroke.value.color.set( r, g, b );
625 static void
626 select_brush(PEMF_CALLBACK_DATA d, int index)
628     PEMRCREATEBRUSHINDIRECT pEmr = NULL;
630     if (index >= 0 && index < d->n_obj)
631         pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
633     if (!pEmr)
634         return;
636     if (pEmr->lb.lbStyle == BS_SOLID) {
637         double r, g, b;
638         r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
639         g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
640         b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
641         d->dc[d->level].style.fill.value.color.set( r, g, b );
642     }
644     d->dc[d->level].fill_set = true;
648 static void
649 select_font(PEMF_CALLBACK_DATA d, int index)
651     PEMREXTCREATEFONTINDIRECTW pEmr = NULL;
653     if (index >= 0 && index < d->n_obj)
654         pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
656     if (!pEmr)
657         return;
659     int cur_level = d->level;
660     d->level = d->emf_obj[index].level;
661     double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight );
662     d->level = cur_level;
663     d->dc[d->level].style.font_size.computed = font_size;
664     d->dc[d->level].style.font_weight.value =
665         pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
666         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
667         pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
668         pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
669         pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
670         pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
671         pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
672         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
673         pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
674         pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
675         pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
676         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
677         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
678         FW_NORMAL;
679     d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
680     d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline;
681     d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
682     if (d->dc[d->level].tstyle.font_family.value)
683         g_free(d->dc[d->level].tstyle.font_family.value);
684     d->dc[d->level].tstyle.font_family.value =
685         (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL );
686     d->dc[d->level].style.text_transform.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10;
689 static void
690 delete_object(PEMF_CALLBACK_DATA d, int index)
692     if (index >= 0 && index < d->n_obj) {
693         d->emf_obj[index].type = 0;
694         if (d->emf_obj[index].lpEMFR)
695             free(d->emf_obj[index].lpEMFR);
696         d->emf_obj[index].lpEMFR = NULL;
697     }
701 static void
702 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
704     if (index >= 0 && index < d->n_obj) {
705         delete_object(d, index);
706         d->emf_obj[index].type = type;
707         d->emf_obj[index].level = d->level;
708         d->emf_obj[index].lpEMFR = pObj;
709     }
712 static void
713 assert_empty_path(PEMF_CALLBACK_DATA d, const char * /*fun*/)
715     if (!d->path->empty()) {
716         // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun);
718         *(d->outsvg) += "<!--\n";
719         *(d->outsvg) += "    <path \t";
720         output_style(d, EMR_STROKEPATH);
721         if (strstr(d->path->c_str(), "d=\"") == NULL) {
722             *(d->outsvg) += "d=\"";
723             *(d->outsvg) += "\n\t";
724         }
725         *(d->outsvg) += *(d->path);
726         *(d->outsvg) += " \" /> \n";
727         *(d->outsvg) += "-->\n";
729         *(d->path) = "";
730     }
734 static int CALLBACK
735 myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD *lpEMFR, int /*nObj*/, LPARAM lpData)
737     PEMF_CALLBACK_DATA d;
738     SVGOStringStream tmp_outsvg;
739     SVGOStringStream tmp_path;
740     SVGOStringStream tmp_str;
741     SVGOStringStream dbg_str;
743     d = (PEMF_CALLBACK_DATA) lpData;
745     if (d->pathless_stroke) {
746         if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 &&
747             lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 &&
748             lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO &&
749             lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 &&
750             lpEMFR->iType!=EMR_SETBKMODE)
751         {
752             *(d->outsvg) += "    <path ";
753             output_style(d, EMR_STROKEPATH);
754             *(d->outsvg) += "\n\t";
755             *(d->outsvg) += *(d->path);
756             *(d->outsvg) += " \" /> \n";
757             *(d->path) = "";
758             d->pathless_stroke = false;
759         }
760     }
762     switch (lpEMFR->iType)
763     {
764         case EMR_HEADER:
765         {
766             dbg_str << "<!-- EMR_HEADER -->\n";
768             *(d->outsvg) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
770             if (d->pDesc) {
771                 *(d->outsvg) += "<!-- ";
772                 *(d->outsvg) += d->pDesc;
773                 *(d->outsvg) += " -->\n";
774             }
776             ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
777             tmp_outsvg << "<svg\n";
778             tmp_outsvg << "  xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
779             tmp_outsvg << "  xmlns=\"http://www.w3.org/2000/svg\"\n";
780             tmp_outsvg << "  version=\"1.0\"\n";
782             d->xDPI = 2540;
783             d->yDPI = 2540;
785             d->dc[d->level].PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left;
786             d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;
788             d->MMX = d->dc[d->level].PixelsInX / 100.0;
789             d->MMY = d->dc[d->level].PixelsInY / 100.0;
791             d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM;
792             d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM;
793             
794             tmp_outsvg <<
795                 "  width=\"" << d->MMX << "mm\"\n" <<
796                 "  height=\"" << d->MMY << "mm\"\n";
797             tmp_outsvg <<
798                 "  id=\"" << (d->id++) << "\">\n";
800             tmp_outsvg <<
801                 "<g\n" <<
802                 "  id=\"" << (d->id++) << "\">\n";
804             if (pEmr->nHandles) {
805                 d->n_obj = pEmr->nHandles;
806                 d->emf_obj = new EMF_OBJECT[d->n_obj];
807                 
808                 // Init the new emf_obj list elements to null, provided the
809                 // dynamic allocation succeeded.
810                 if ( d->emf_obj != NULL )
811                 {
812                     for( int i=0; i < d->n_obj; ++i )
813                         d->emf_obj[i].lpEMFR = NULL;
814                 } //if
816             } else {
817                 d->emf_obj = NULL;
818             }
820             break;
821         }
822         case EMR_POLYBEZIER:
823         {
824             dbg_str << "<!-- EMR_POLYBEZIER -->\n";
826             PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
827             DWORD i,j;
829             if (pEmr->cptl<4)
830                 break;
832             if (!d->inpath) {
833                 assert_empty_path(d, "EMR_POLYBEZIER");
835                 *(d->outsvg) += "    <path ";
836                 output_style(d, EMR_STROKEPATH);
837                 *(d->outsvg) += "\n\td=\"";
838             }
840             tmp_str <<
841                 "\n\tM " <<
842                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
843                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
845             for (i=1; i<pEmr->cptl; ) {
846                 tmp_str << "\n\tC ";
847                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
848                     tmp_str <<
849                         pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
850                         pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
851                 }
852             }
854             if (d->inpath) {
855                 tmp_path << tmp_str.str().c_str();
856             }
857             else {
858                 *(d->outsvg) += tmp_str.str().c_str();
859                 *(d->outsvg) += " \" /> \n";
860             }
862             break;
863         }
864         case EMR_POLYGON:
865         {
866             dbg_str << "<!-- EMR_POLYGON -->\n";
868             EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
869             DWORD i;
871             if (pEmr->cptl < 2)
872                 break;
874             assert_empty_path(d, "EMR_POLYGON");
876             *(d->outsvg) += "    <path ";
877             output_style(d, EMR_STROKEANDFILLPATH);
878             *(d->outsvg) += "\n\td=\"";
880             tmp_str <<
881                 "\n\tM " <<
882                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
883                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
885             for (i=1; i<pEmr->cptl; i++) {
886                 tmp_str <<
887                     "\n\tL " <<
888                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
889                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
890             }
892             *(d->outsvg) += tmp_str.str().c_str();
893             *(d->outsvg) += " z \" /> \n";
895             break;
896         }
897         case EMR_POLYLINE:
898         {
899             dbg_str << "<!-- EMR_POLYLINE -->\n";
901             EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
902             DWORD i;
904             if (pEmr->cptl<2)
905                 break;
907             if (!d->inpath) {
908                 assert_empty_path(d, "EMR_POLYLINE");
910                 *(d->outsvg) += "    <path ";
911                 output_style(d, EMR_STROKEPATH);
912                 *(d->outsvg) += "\n\td=\"";
913             }
915             tmp_str <<
916                 "\n\tM " <<
917                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
918                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
920             for (i=1; i<pEmr->cptl; i++) {
921                 tmp_str <<
922                     "\n\tL " <<
923                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
924                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
925             }
927             if (d->inpath) {
928                 tmp_path << tmp_str.str().c_str();
929             }
930             else {
931                 *(d->outsvg) += tmp_str.str().c_str();
932                 *(d->outsvg) += " \" /> \n";
933             }
935             break;
936         }
937         case EMR_POLYBEZIERTO:
938         {
939             dbg_str << "<!-- EMR_POLYBEZIERTO -->\n";
941             PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
942             DWORD i,j;
944             if (d->path->empty()) {
945                 d->pathless_stroke = true;
946                 *(d->path) = "d=\"";
947             }
949             for (i=0; i<pEmr->cptl;) {
950                 tmp_path << "\n\tC ";
951                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
952                     tmp_path <<
953                         pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
954                         pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
955                 }
956             }
958             break;
959         }
960         case EMR_POLYLINETO:
961         {
962             dbg_str << "<!-- EMR_POLYLINETO -->\n";
964             PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
965             DWORD i;
967             if (d->path->empty()) {
968                 d->pathless_stroke = true;
969                 *(d->path) = "d=\"";
970             }
972             for (i=0; i<pEmr->cptl;i++) {
973                 tmp_path <<
974                     "\n\tL " <<
975                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
976                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
977             }
979             break;
980         }
981         case EMR_POLYPOLYLINE:
982         case EMR_POLYPOLYGON:
983         {
984             if (lpEMFR->iType == EMR_POLYPOLYLINE)
985                 dbg_str << "<!-- EMR_POLYPOLYLINE -->\n";
986             if (lpEMFR->iType == EMR_POLYPOLYGON)
987                 dbg_str << "<!-- EMR_POLYPOLYGON -->\n";
989             PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR;
990             unsigned int n, i, j;
992             if (!d->inpath) {
993                 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE");
995                 *(d->outsvg) += "    <path ";
996                 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
997                 *(d->outsvg) += "\n\td=\"";
998             }
1000             POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys];
1002             i = 0;
1003             for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
1004                 SVGOStringStream poly_path;
1006                 poly_path << "\n\tM " <<
1007                     pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
1008                     pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
1009                 i++;
1011                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
1012                     poly_path << "\n\tL " <<
1013                         pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
1014                         pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
1015                     i++;
1016                 }
1018                 tmp_str << poly_path.str().c_str();
1019                 if (lpEMFR->iType == EMR_POLYPOLYGON)
1020                     tmp_str << " z";
1021                 tmp_str << " \n";
1022             }
1024             if (d->inpath) {
1025                 tmp_path << tmp_str.str().c_str();
1026             }
1027             else {
1028                 *(d->outsvg) += tmp_str.str().c_str();
1029                 *(d->outsvg) += " \" /> \n";
1030             }
1032             break;
1033         }
1034         case EMR_SETWINDOWEXTEX:
1035         {
1036             dbg_str << "<!-- EMR_SETWINDOWEXTEX -->\n";
1038             PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
1040             d->dc[d->level].sizeWnd = pEmr->szlExtent;
1042             if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1043                 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1044                 if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1045                     d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX;
1046                     d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY;
1047                 }
1048             }
1050             if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1051                 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
1052             }
1054             d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
1055             d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
1056             
1057             if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
1058                 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
1059                 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
1060             }
1061             else {
1062                 d->dc[d->level].ScaleInX = 1;
1063                 d->dc[d->level].ScaleInY = 1;
1064             }
1066             if (d->dc[d->level].sizeView.cx && d->dc[d->level].sizeView.cy) {
1067                 d->dc[d->level].ScaleOutX = (double) d->dc[d->level].PixelsOutX / (double) d->dc[d->level].sizeView.cx;
1068                 d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy;
1069             }
1070             else {
1071                 d->dc[d->level].ScaleOutX = DEVICESCALE;
1072                 d->dc[d->level].ScaleOutY = DEVICESCALE;
1073             }
1075             break;
1076         }
1077         case EMR_SETWINDOWORGEX:
1078         {
1079             dbg_str << "<!-- EMR_SETWINDOWORGEX -->\n";
1081             PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
1082             d->dc[d->level].winorg = pEmr->ptlOrigin;
1083             break;
1084         }
1085         case EMR_SETVIEWPORTEXTEX:
1086         {
1087             dbg_str << "<!-- EMR_SETVIEWPORTEXTEX -->\n";
1089             PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
1091             d->dc[d->level].sizeView = pEmr->szlExtent;
1093             if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1094                 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
1095                 if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1096                     d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX;
1097                     d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY;
1098                 }
1099             }
1101             if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1102                 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1103             }
1105             d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
1106             d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
1107             
1108             if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
1109                 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
1110                 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
1111             }
1112             else {
1113                 d->dc[d->level].ScaleInX = 1;
1114                 d->dc[d->level].ScaleInY = 1;
1115             }
1117             if (d->dc[d->level].sizeView.cx && d->dc[d->level].sizeView.cy) {
1118                 d->dc[d->level].ScaleOutX = (double) d->dc[d->level].PixelsOutX / (double) d->dc[d->level].sizeView.cx;
1119                 d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy;
1120             }
1121             else {
1122                 d->dc[d->level].ScaleOutX = DEVICESCALE;
1123                 d->dc[d->level].ScaleOutY = DEVICESCALE;
1124             }
1126             break;
1127         }
1128         case EMR_SETVIEWPORTORGEX:
1129         {
1130             dbg_str << "<!-- EMR_SETVIEWPORTORGEX -->\n";
1132             PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
1133             d->dc[d->level].vieworg = pEmr->ptlOrigin;
1134             break;
1135         }
1136         case EMR_SETBRUSHORGEX:
1137             dbg_str << "<!-- EMR_SETBRUSHORGEX -->\n";
1138             break;
1139         case EMR_EOF:
1140         {
1141             dbg_str << "<!-- EMR_EOF -->\n";
1143             assert_empty_path(d, "EMR_EOF");
1144             tmp_outsvg << "</g>\n";
1145             tmp_outsvg << "</svg>\n";
1146             break;
1147         }
1148         case EMR_SETPIXELV:
1149             dbg_str << "<!-- EMR_SETPIXELV -->\n";
1150             break;
1151         case EMR_SETMAPPERFLAGS:
1152             dbg_str << "<!-- EMR_SETMAPPERFLAGS -->\n";
1153             break;
1154         case EMR_SETMAPMODE:
1155             dbg_str << "<!-- EMR_SETMAPMODE -->\n";
1156             break;
1157         case EMR_SETBKMODE:
1158             dbg_str << "<!-- EMR_SETBKMODE -->\n";
1159             break;
1160         case EMR_SETPOLYFILLMODE:
1161         {
1162             dbg_str << "<!-- EMR_SETPOLYFILLMODE -->\n";
1164             PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
1165             d->dc[d->level].style.fill_rule.value =
1166                 (pEmr->iMode == ALTERNATE ? 0 :
1167                  pEmr->iMode == WINDING ? 1 : 0);
1168             break;
1169         }
1170         case EMR_SETROP2:
1171             dbg_str << "<!-- EMR_SETROP2 -->\n";
1172             break;
1173         case EMR_SETSTRETCHBLTMODE:
1174             dbg_str << "<!-- EMR_SETSTRETCHBLTMODE -->\n";
1175             break;
1176         case EMR_SETTEXTALIGN:
1177         {
1178             dbg_str << "<!-- EMR_SETTEXTALIGN -->\n";
1180             PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR;
1181             d->dc[d->level].textAlign = pEmr->iMode;
1182             break;
1183         }
1184         case EMR_SETCOLORADJUSTMENT:
1185             dbg_str << "<!-- EMR_SETCOLORADJUSTMENT -->\n";
1186             break;
1187         case EMR_SETTEXTCOLOR:
1188         {
1189             dbg_str << "<!-- EMR_SETTEXTCOLOR -->\n";
1191             PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR;
1192             d->dc[d->level].textColor = pEmr->crColor;
1193             d->dc[d->level].textColorSet = true;
1194             break;
1195         }
1196         case EMR_SETBKCOLOR:
1197             dbg_str << "<!-- EMR_SETBKCOLOR -->\n";
1198             break;
1199         case EMR_OFFSETCLIPRGN:
1200             dbg_str << "<!-- EMR_OFFSETCLIPRGN -->\n";
1201             break;
1202         case EMR_MOVETOEX:
1203         {
1204             dbg_str << "<!-- EMR_MOVETOEX -->\n";
1206             PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
1208             if (d->path->empty()) {
1209                 d->pathless_stroke = true;
1210                 *(d->path) = "d=\"";
1211             }
1213             d->dc[d->level].cur = pEmr->ptl;
1215             tmp_path <<
1216                 "\n\tM " <<
1217                 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1218                 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1219             break;
1220         }
1221         case EMR_SETMETARGN:
1222             dbg_str << "<!-- EMR_SETMETARGN -->\n";
1223             break;
1224         case EMR_EXCLUDECLIPRECT:
1225             dbg_str << "<!-- EMR_EXCLUDECLIPRECT -->\n";
1226             break;
1227         case EMR_INTERSECTCLIPRECT:
1228             dbg_str << "<!-- EMR_INTERSECTCLIPRECT -->\n";
1229             break;
1230         case EMR_SCALEVIEWPORTEXTEX:
1231             dbg_str << "<!-- EMR_SCALEVIEWPORTEXTEX -->\n";
1232             break;
1233         case EMR_SCALEWINDOWEXTEX:
1234             dbg_str << "<!-- EMR_SCALEWINDOWEXTEX -->\n";
1235             break;
1236         case EMR_SAVEDC:
1237             dbg_str << "<!-- EMR_SAVEDC -->\n";
1239             if (d->level < EMF_MAX_DC) {
1240                 d->dc[d->level + 1] = d->dc[d->level];
1241                 d->level = d->level + 1;
1242             }
1243             break;
1244         case EMR_RESTOREDC:
1245         {
1246             dbg_str << "<!-- EMR_RESTOREDC -->\n";
1247             
1248             PEMRRESTOREDC pEmr = (PEMRRESTOREDC) lpEMFR;
1249             int old_level = d->level;
1250             if (pEmr->iRelative >= 0) {
1251                 if (pEmr->iRelative < d->level)
1252                     d->level = pEmr->iRelative;
1253             }
1254             else {
1255                 if (d->level + pEmr->iRelative >= 0)
1256                     d->level = d->level + pEmr->iRelative;
1257             }
1258             while (old_level > d->level) {
1259                 if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash)))
1260                     delete[] d->dc[old_level].style.stroke_dash.dash;
1261                 old_level--;
1262             }
1263             break;
1264         }
1265         case EMR_SETWORLDTRANSFORM:
1266         {
1267             dbg_str << "<!-- EMR_SETWORLDTRANSFORM -->\n";
1269             PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR;
1270             d->dc[d->level].worldTransform = pEmr->xform;
1271             break;
1272         }
1273         case EMR_MODIFYWORLDTRANSFORM:
1274         {
1275             dbg_str << "<!-- EMR_MODIFYWORLDTRANSFORM -->\n";
1277             PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR;
1278             switch (pEmr->iMode)
1279             {
1280                 case MWT_IDENTITY:
1281                     d->dc[d->level].worldTransform.eM11 = 1.0;
1282                     d->dc[d->level].worldTransform.eM12 = 0.0;
1283                     d->dc[d->level].worldTransform.eM21 = 0.0;
1284                     d->dc[d->level].worldTransform.eM22 = 1.0;
1285                     d->dc[d->level].worldTransform.eDx  = 0.0;
1286                     d->dc[d->level].worldTransform.eDy  = 0.0;
1287                     break;
1288                 case MWT_LEFTMULTIPLY:
1289                 {
1290 //                    d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
1292                     float a11 = pEmr->xform.eM11;
1293                     float a12 = pEmr->xform.eM12;
1294                     float a13 = 0.0;
1295                     float a21 = pEmr->xform.eM21;
1296                     float a22 = pEmr->xform.eM22;
1297                     float a23 = 0.0;
1298                     float a31 = pEmr->xform.eDx;
1299                     float a32 = pEmr->xform.eDy;
1300                     float a33 = 1.0;
1302                     float b11 = d->dc[d->level].worldTransform.eM11;
1303                     float b12 = d->dc[d->level].worldTransform.eM12;
1304                     //float b13 = 0.0;
1305                     float b21 = d->dc[d->level].worldTransform.eM21;
1306                     float b22 = d->dc[d->level].worldTransform.eM22;
1307                     //float b23 = 0.0;
1308                     float b31 = d->dc[d->level].worldTransform.eDx;
1309                     float b32 = d->dc[d->level].worldTransform.eDy;
1310                     //float b33 = 1.0;
1312                     float c11 = a11*b11 + a12*b21 + a13*b31;;
1313                     float c12 = a11*b12 + a12*b22 + a13*b32;;
1314                     //float c13 = a11*b13 + a12*b23 + a13*b33;;
1315                     float c21 = a21*b11 + a22*b21 + a23*b31;;
1316                     float c22 = a21*b12 + a22*b22 + a23*b32;;
1317                     //float c23 = a21*b13 + a22*b23 + a23*b33;;
1318                     float c31 = a31*b11 + a32*b21 + a33*b31;;
1319                     float c32 = a31*b12 + a32*b22 + a33*b32;;
1320                     //float c33 = a31*b13 + a32*b23 + a33*b33;;
1322                     d->dc[d->level].worldTransform.eM11 = c11;;
1323                     d->dc[d->level].worldTransform.eM12 = c12;;
1324                     d->dc[d->level].worldTransform.eM21 = c21;;
1325                     d->dc[d->level].worldTransform.eM22 = c22;;
1326                     d->dc[d->level].worldTransform.eDx = c31;
1327                     d->dc[d->level].worldTransform.eDy = c32;
1328                     
1329                     break;
1330                 }
1331                 case MWT_RIGHTMULTIPLY:
1332                 {
1333 //                    d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
1335                     float a11 = d->dc[d->level].worldTransform.eM11;
1336                     float a12 = d->dc[d->level].worldTransform.eM12;
1337                     float a13 = 0.0;
1338                     float a21 = d->dc[d->level].worldTransform.eM21;
1339                     float a22 = d->dc[d->level].worldTransform.eM22;
1340                     float a23 = 0.0;
1341                     float a31 = d->dc[d->level].worldTransform.eDx;
1342                     float a32 = d->dc[d->level].worldTransform.eDy;
1343                     float a33 = 1.0;
1345                     float b11 = pEmr->xform.eM11;
1346                     float b12 = pEmr->xform.eM12;
1347                     //float b13 = 0.0;
1348                     float b21 = pEmr->xform.eM21;
1349                     float b22 = pEmr->xform.eM22;
1350                     //float b23 = 0.0;
1351                     float b31 = pEmr->xform.eDx;
1352                     float b32 = pEmr->xform.eDy;
1353                     //float b33 = 1.0;
1355                     float c11 = a11*b11 + a12*b21 + a13*b31;;
1356                     float c12 = a11*b12 + a12*b22 + a13*b32;;
1357                     //float c13 = a11*b13 + a12*b23 + a13*b33;;
1358                     float c21 = a21*b11 + a22*b21 + a23*b31;;
1359                     float c22 = a21*b12 + a22*b22 + a23*b32;;
1360                     //float c23 = a21*b13 + a22*b23 + a23*b33;;
1361                     float c31 = a31*b11 + a32*b21 + a33*b31;;
1362                     float c32 = a31*b12 + a32*b22 + a33*b32;;
1363                     //float c33 = a31*b13 + a32*b23 + a33*b33;;
1365                     d->dc[d->level].worldTransform.eM11 = c11;;
1366                     d->dc[d->level].worldTransform.eM12 = c12;;
1367                     d->dc[d->level].worldTransform.eM21 = c21;;
1368                     d->dc[d->level].worldTransform.eM22 = c22;;
1369                     d->dc[d->level].worldTransform.eDx = c31;
1370                     d->dc[d->level].worldTransform.eDy = c32;
1372                     break;
1373                 }
1374 //                case MWT_SET:
1375                 default:
1376                     d->dc[d->level].worldTransform = pEmr->xform;
1377                     break;
1378             }
1379             break;
1380         }
1381         case EMR_SELECTOBJECT:
1382         {
1383             dbg_str << "<!-- EMR_SELECTOBJECT -->\n";
1385             PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
1386             unsigned int index = pEmr->ihObject;
1388             if (index >= ENHMETA_STOCK_OBJECT) {
1389                 index -= ENHMETA_STOCK_OBJECT;
1390                 switch (index) {
1391                     case NULL_BRUSH:
1392                         d->dc[d->level].fill_set = false;
1393                         break;
1394                     case BLACK_BRUSH:
1395                     case DKGRAY_BRUSH:
1396                     case GRAY_BRUSH:
1397                     case LTGRAY_BRUSH:
1398                     case WHITE_BRUSH:
1399                     {
1400                         float val = 0;
1401                         switch (index) {
1402                             case BLACK_BRUSH:
1403                                 val = 0.0 / 255.0;
1404                                 break;
1405                             case DKGRAY_BRUSH:
1406                                 val = 64.0 / 255.0;
1407                                 break;
1408                             case GRAY_BRUSH:
1409                                 val = 128.0 / 255.0;
1410                                 break;
1411                             case LTGRAY_BRUSH:
1412                                 val = 192.0 / 255.0;
1413                                 break;
1414                             case WHITE_BRUSH:
1415                                 val = 255.0 / 255.0;
1416                                 break;
1417                         }
1418                         d->dc[d->level].style.fill.value.color.set( val, val, val );
1420                         d->dc[d->level].fill_set = true;
1421                         break;
1422                     }
1423                     case NULL_PEN:
1424                         d->dc[d->level].stroke_set = false;
1425                         break;
1426                     case BLACK_PEN:
1427                     case WHITE_PEN:
1428                     {
1429                         float val = index == BLACK_PEN ? 0 : 1;
1430                         d->dc[d->level].style.stroke_dasharray_set = 0;
1431                         d->dc[d->level].style.stroke_width.value = 1.0;
1432                         d->dc[d->level].style.stroke.value.color.set( val, val, val );
1434                         d->dc[d->level].stroke_set = true;
1436                         break;
1437                     }
1438                 }
1439             } else {
1440                 if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
1441                     switch (d->emf_obj[index].type)
1442                     {
1443                         case EMR_CREATEPEN:
1444                             select_pen(d, index);
1445                             break;
1446                         case EMR_CREATEBRUSHINDIRECT:
1447                             select_brush(d, index);
1448                             break;
1449                         case EMR_EXTCREATEPEN:
1450                             select_extpen(d, index);
1451                             break;
1452                         case EMR_EXTCREATEFONTINDIRECTW:
1453                             select_font(d, index);
1454                             break;
1455                     }
1456                 }
1457             }
1458             break;
1459         }
1460         case EMR_CREATEPEN:
1461         {
1462             dbg_str << "<!-- EMR_CREATEPEN -->\n";
1464             PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
1465             int index = pEmr->ihPen;
1467             EMRCREATEPEN *pPen =
1468                 (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) );
1469             pPen->lopn = pEmr->lopn;
1470             insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
1472             break;
1473         }
1474         case EMR_CREATEBRUSHINDIRECT:
1475         {
1476             dbg_str << "<!-- EMR_CREATEBRUSHINDIRECT -->\n";
1478             PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
1479             int index = pEmr->ihBrush;
1481             EMRCREATEBRUSHINDIRECT *pBrush =
1482                 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
1483             pBrush->lb = pEmr->lb;
1484             insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
1486             break;
1487         }
1488         case EMR_DELETEOBJECT:
1489             dbg_str << "<!-- EMR_DELETEOBJECT -->\n";
1490             break;
1491         case EMR_ANGLEARC:
1492             dbg_str << "<!-- EMR_ANGLEARC -->\n";
1493             break;
1494         case EMR_ELLIPSE:
1495         {
1496             dbg_str << "<!-- EMR_ELLIPSE -->\n";
1498             PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR;
1499             RECTL rclBox = pEmr->rclBox;
1501             double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1502             double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1503             double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1504             double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1506             double cx = (l + r) / 2.0;
1507             double cy = (t + b) / 2.0;
1508             double rx = fabs(l - r) / 2.0;
1509             double ry = fabs(t - b) / 2.0;
1511             SVGOStringStream tmp_ellipse;
1512             tmp_ellipse << "cx=\"" << cx << "\" ";
1513             tmp_ellipse << "cy=\"" << cy << "\" ";
1514             tmp_ellipse << "rx=\"" << rx << "\" ";
1515             tmp_ellipse << "ry=\"" << ry << "\" ";
1517             assert_empty_path(d, "EMR_ELLIPSE");
1519             *(d->outsvg) += "    <ellipse ";
1520             output_style(d, lpEMFR->iType);
1521             *(d->outsvg) += "\n\t";
1522             *(d->outsvg) += tmp_ellipse.str().c_str();
1523             *(d->outsvg) += "/> \n";
1524             *(d->path) = "";
1525             break;
1526         }
1527         case EMR_RECTANGLE:
1528         {
1529             dbg_str << "<!-- EMR_RECTANGLE -->\n";
1531             PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR;
1532             RECTL rc = pEmr->rclBox;
1534             double l = pix_to_x_point( d, rc.left, rc.top );
1535             double t = pix_to_y_point( d, rc.left, rc.top );
1536             double r = pix_to_x_point( d, rc.right, rc.bottom );
1537             double b = pix_to_y_point( d, rc.right, rc.bottom );
1539             SVGOStringStream tmp_rectangle;
1540             tmp_rectangle << "d=\"";
1541             tmp_rectangle << "\n\tM " << l << " " << t << " ";
1542             tmp_rectangle << "\n\tL " << r << " " << t << " ";
1543             tmp_rectangle << "\n\tL " << r << " " << b << " ";
1544             tmp_rectangle << "\n\tL " << l << " " << b << " ";
1545             tmp_rectangle << "\n\tz";
1547             assert_empty_path(d, "EMR_RECTANGLE");
1549             *(d->outsvg) += "    <path ";
1550             output_style(d, lpEMFR->iType);
1551             *(d->outsvg) += "\n\t";
1552             *(d->outsvg) += tmp_rectangle.str().c_str();
1553             *(d->outsvg) += " \" /> \n";
1554             *(d->path) = "";
1555             break;
1556         }
1557         case EMR_ROUNDRECT:
1558             dbg_str << "<!-- EMR_ROUNDRECT -->\n";
1559             break;
1560         case EMR_ARC:
1561             dbg_str << "<!-- EMR_ARC -->\n";
1562             break;
1563         case EMR_CHORD:
1564             dbg_str << "<!-- EMR_CHORD -->\n";
1565             break;
1566         case EMR_PIE:
1567             dbg_str << "<!-- EMR_PIE -->\n";
1568             break;
1569         case EMR_SELECTPALETTE:
1570             dbg_str << "<!-- EMR_SELECTPALETTE -->\n";
1571             break;
1572         case EMR_CREATEPALETTE:
1573             dbg_str << "<!-- EMR_CREATEPALETTE -->\n";
1574             break;
1575         case EMR_SETPALETTEENTRIES:
1576             dbg_str << "<!-- EMR_SETPALETTEENTRIES -->\n";
1577             break;
1578         case EMR_RESIZEPALETTE:
1579             dbg_str << "<!-- EMR_RESIZEPALETTE -->\n";
1580             break;
1581         case EMR_REALIZEPALETTE:
1582             dbg_str << "<!-- EMR_REALIZEPALETTE -->\n";
1583             break;
1584         case EMR_EXTFLOODFILL:
1585             dbg_str << "<!-- EMR_EXTFLOODFILL -->\n";
1586             break;
1587         case EMR_LINETO:
1588         {
1589             dbg_str << "<!-- EMR_LINETO -->\n";
1591             PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
1593             if (d->path->empty()) {
1594                 d->pathless_stroke = true;
1595                 *(d->path) = "d=\"";
1596             }
1598             tmp_path <<
1599                 "\n\tL " <<
1600                 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1601                 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1602             break;
1603         }
1604         case EMR_ARCTO:
1605             dbg_str << "<!-- EMR_ARCTO -->\n";
1606             break;
1607         case EMR_POLYDRAW:
1608             dbg_str << "<!-- EMR_POLYDRAW -->\n";
1609             break;
1610         case EMR_SETARCDIRECTION:
1611             dbg_str << "<!-- EMR_SETARCDIRECTION -->\n";
1612             break;
1613         case EMR_SETMITERLIMIT:
1614         {
1615             dbg_str << "<!-- EMR_SETMITERLIMIT -->\n";
1617             PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
1619             float miterlimit = pEmr->eMiterLimit;
1620             miterlimit = miterlimit * 4.0 / 10.0;
1621             d->dc[d->level].style.stroke_miterlimit.value = pix_to_size_point( d, miterlimit );
1622             if (d->dc[d->level].style.stroke_miterlimit.value < 1)
1623                 d->dc[d->level].style.stroke_miterlimit.value = 4.0;
1624             break;
1625         }
1626         case EMR_BEGINPATH:
1627         {
1628             dbg_str << "<!-- EMR_BEGINPATH -->\n";
1630             tmp_path << "d=\"";
1631             *(d->path) = "";
1632             d->inpath = true;
1633             break;
1634         }
1635         case EMR_ENDPATH:
1636         {
1637             dbg_str << "<!-- EMR_ENDPATH -->\n";
1639             tmp_path << "\"";
1640             d->inpath = false;
1641             break;
1642         }
1643         case EMR_CLOSEFIGURE:
1644         {
1645             dbg_str << "<!-- EMR_CLOSEFIGURE -->\n";
1647             tmp_path << "\n\tz";
1648             break;
1649         }
1650         case EMR_FILLPATH:
1651         case EMR_STROKEANDFILLPATH:
1652         case EMR_STROKEPATH:
1653         {
1654             if (lpEMFR->iType == EMR_FILLPATH)
1655                 dbg_str << "<!-- EMR_FILLPATH -->\n";
1656             if (lpEMFR->iType == EMR_STROKEANDFILLPATH)
1657                 dbg_str << "<!-- EMR_STROKEANDFILLPATH -->\n";
1658             if (lpEMFR->iType == EMR_STROKEPATH)
1659                 dbg_str << "<!-- EMR_STROKEPATH -->\n";
1661             *(d->outsvg) += "    <path ";
1662             output_style(d, lpEMFR->iType);
1663             *(d->outsvg) += "\n\t";
1664             *(d->outsvg) += *(d->path);
1665             *(d->outsvg) += " /> \n";
1666             *(d->path) = "";
1667             break;
1668         }
1669         case EMR_FLATTENPATH:
1670             dbg_str << "<!-- EMR_FLATTENPATH -->\n";
1671             break;
1672         case EMR_WIDENPATH:
1673             dbg_str << "<!-- EMR_WIDENPATH -->\n";
1674             break;
1675         case EMR_SELECTCLIPPATH:
1676             dbg_str << "<!-- EMR_SELECTCLIPPATH -->\n";
1677             break;
1678         case EMR_ABORTPATH:
1679             dbg_str << "<!-- EMR_ABORTPATH -->\n";
1680             break;
1681         case EMR_GDICOMMENT:
1682         {
1683             dbg_str << "<!-- EMR_GDICOMMENT -->\n";
1684             
1685             PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR;
1687             CHAR *szTxt = (CHAR *) pEmr->Data;
1689             for (DWORD i = 0; i < pEmr->cbData; i++) {
1690                 if ( *szTxt) {
1691                     if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
1692                         tmp_str << *szTxt;
1693                     }
1694                     szTxt++;
1695                 }
1696             }
1698             if (0 && strlen(tmp_str.str().c_str())) {
1699                 tmp_outsvg << "    <!-- \"";
1700                 tmp_outsvg << tmp_str.str().c_str();
1701                 tmp_outsvg << "\" -->\n";
1702             }
1703             
1704             break;
1705         }
1706         case EMR_FILLRGN:
1707             dbg_str << "<!-- EMR_FILLRGN -->\n";
1708             break;
1709         case EMR_FRAMERGN:
1710             dbg_str << "<!-- EMR_FRAMERGN -->\n";
1711             break;
1712         case EMR_INVERTRGN:
1713             dbg_str << "<!-- EMR_INVERTRGN -->\n";
1714             break;
1715         case EMR_PAINTRGN:
1716             dbg_str << "<!-- EMR_PAINTRGN -->\n";
1717             break;
1718         case EMR_EXTSELECTCLIPRGN:
1719             dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n";
1720             break;
1721         case EMR_BITBLT:
1722             dbg_str << "<!-- EMR_BITBLT -->\n";
1723             break;
1724         case EMR_STRETCHBLT:
1725             dbg_str << "<!-- EMR_STRETCHBLT -->\n";
1726             break;
1727         case EMR_MASKBLT:
1728             dbg_str << "<!-- EMR_MASKBLT -->\n";
1729             break;
1730         case EMR_PLGBLT:
1731             dbg_str << "<!-- EMR_PLGBLT -->\n";
1732             break;
1733         case EMR_SETDIBITSTODEVICE:
1734             dbg_str << "<!-- EMR_SETDIBITSTODEVICE -->\n";
1735             break;
1736         case EMR_STRETCHDIBITS:
1737             dbg_str << "<!-- EMR_STRETCHDIBITS -->\n";
1738             break;
1739         case EMR_EXTCREATEFONTINDIRECTW:
1740         {
1741             dbg_str << "<!-- EMR_EXTCREATEFONTINDIRECTW -->\n";
1743             PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR;
1744             int index = pEmr->ihFont;
1746             EMREXTCREATEFONTINDIRECTW *pFont =
1747                 (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) );
1748             pFont->elfw = pEmr->elfw;
1749             insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont);
1750             break;
1751         }
1752         case EMR_EXTTEXTOUTA:
1753         {
1754             dbg_str << "<!-- EMR_EXTTEXTOUTA -->\n";
1755             break;
1756         }
1757         case EMR_EXTTEXTOUTW:
1758         {
1759             dbg_str << "<!-- EMR_EXTTEXTOUTW -->\n";
1761             PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR;
1763             double x1 = pEmr->emrtext.ptlReference.x;
1764             double y1 = pEmr->emrtext.ptlReference.y;
1765             
1766             if (d->dc[d->level].textAlign & TA_UPDATECP) {
1767                 x1 = d->dc[d->level].cur.x;
1768                 y1 = d->dc[d->level].cur.y;
1769             }
1771             if (!(d->dc[d->level].textAlign & TA_BOTTOM))
1772                 y1 += fabs(d->dc[d->level].style.font_size.computed);
1773             
1774             double x = pix_to_x_point(d, x1, y1);
1775             double y = pix_to_y_point(d, x1, y1);
1777             wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString);
1779             gchar *ansi_text =
1780                 (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL );
1782             if (ansi_text) {
1783                 gchar *p = ansi_text;
1784                 while (*p) {
1785                     if (*p < 32 || *p >= 127) {
1786                         g_free(ansi_text);
1787                         ansi_text = g_strdup("");
1788                         break;
1789                     }
1790                     p++;
1791                 }
1793                 SVGOStringStream ts;
1795                 gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
1797                 float text_rgb[3];
1798                 sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb );
1800                 if (!d->dc[d->level].textColorSet) {
1801                     d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]),
1802                                        SP_COLOR_F_TO_U(text_rgb[1]),
1803                                        SP_COLOR_F_TO_U(text_rgb[2]));
1804                 }
1806                 char tmp[128];
1807                 snprintf(tmp, 127,
1808                          "fill:#%02x%02x%02x;",
1809                          GetRValue(d->dc[d->level].textColor),
1810                          GetGValue(d->dc[d->level].textColor),
1811                          GetBValue(d->dc[d->level].textColor));
1813                 bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC);
1814                 //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
1815                 bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
1816                     (d->dc[d->level].style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->dc[d->level].style.font_weight.value <= SP_CSS_FONT_WEIGHT_900);
1817                 int lcr = ((d->dc[d->level].textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0;
1819                 assert_empty_path(d, "EMR_EXTTEXTOUTW");
1821                 ts << "    <text\n";
1822                 ts << "        id=\"" << (d->id++) << "\"\n";
1823                 ts << "        xml:space=\"preserve\"\n";
1824                 ts << "        x=\"" << x << "\"\n";
1825                 ts << "        y=\"" << y << "\"\n";
1826                 if (d->dc[d->level].style.text_transform.value) {
1827                     ts << "        transform=\""
1828                        << "rotate(-" << d->dc[d->level].style.text_transform.value
1829                        << " " << x << " " << y << ")"
1830                        << "\"\n";
1831                 }
1832                 ts << "        style=\""
1833                    << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;"
1834                    << tmp
1835                    << "font-style:" << (i ? "italic" : "normal") << ";"
1836                    << "font-weight:" << (b ? "bold" : "normal") << ";"
1837                    << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";"
1838                    << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";"
1839                    << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";"
1840                    << "\"\n";
1841                 ts << "    >";
1842                 ts << escaped_text;
1843                 ts << "</text>\n";
1844                 
1845                 *(d->outsvg) += ts.str().c_str();
1846                 
1847                 g_free(escaped_text);
1848                 g_free(ansi_text);
1849             }
1850             
1851             break;
1852         }
1853         case EMR_POLYBEZIER16:
1854         {
1855             dbg_str << "<!-- EMR_POLYBEZIER16 -->\n";
1857             PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
1858             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1859             DWORD i,j;
1861             if (pEmr->cpts<4)
1862                 break;
1864             if (!d->inpath) {
1865                 assert_empty_path(d, "EMR_POLYBEZIER16");
1867                 *(d->outsvg) += "    <path ";
1868                 output_style(d, EMR_STROKEPATH);
1869                 *(d->outsvg) += "\n\td=\"";
1870             }
1872             tmp_str <<
1873                 "\n\tM " <<
1874                 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1875                 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1877             for (i=1; i<pEmr->cpts; ) {
1878                 tmp_str << "\n\tC ";
1879                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1880                     tmp_str <<
1881                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1882                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1883                 }
1884             }
1886             if (d->inpath) {
1887                 tmp_path << tmp_str.str().c_str();
1888             }
1889             else {
1890                 *(d->outsvg) += tmp_str.str().c_str();
1891                 *(d->outsvg) += " \" /> \n";
1892             }
1894             break;
1895         }
1896         case EMR_POLYGON16:
1897         {
1898             dbg_str << "<!-- EMR_POLYGON16 -->\n";
1900             PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
1901             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1902             SVGOStringStream tmp_poly;
1903             unsigned int i;
1904             unsigned int first = 0;
1906             assert_empty_path(d, "EMR_POLYGON16");
1908             *(d->outsvg) += "    <path ";
1909             output_style(d, EMR_STROKEANDFILLPATH);
1910             *(d->outsvg) += "\n\td=\"";
1911             
1912             // skip the first point?
1913             tmp_poly << "\n\tM " <<
1914                 pix_to_x_point( d, apts[first].x, apts[first].y ) << " " <<
1915                 pix_to_y_point( d, apts[first].x, apts[first].y ) << " ";
1917             for (i=first+1; i<pEmr->cpts; i++) {
1918                 tmp_poly << "\n\tL " <<
1919                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1920                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1921             }
1923             *(d->outsvg) += tmp_poly.str().c_str();
1924             *(d->outsvg) += " z \" /> \n";
1926             break;
1927         }
1928         case EMR_POLYLINE16:
1929         {
1930             dbg_str << "<!-- EMR_POLYLINE16 -->\n";
1932             EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
1933             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1934             DWORD i;
1936             if (pEmr->cpts<2)
1937                 break;
1939             if (!d->inpath) {
1940                 assert_empty_path(d, "EMR_POLYLINE16");
1942                 *(d->outsvg) += "    <path ";
1943                 output_style(d, EMR_STROKEPATH);
1944                 *(d->outsvg) += "\n\td=\"";
1945             }
1947             tmp_str <<
1948                 "\n\tM " <<
1949                 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1950                 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1952             for (i=1; i<pEmr->cpts; i++) {
1953                 tmp_str <<
1954                     "\n\tL " <<
1955                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1956                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1957             }
1959             if (d->inpath) {
1960                 tmp_path << tmp_str.str().c_str();
1961             }
1962             else {
1963                 *(d->outsvg) += tmp_str.str().c_str();
1964                 *(d->outsvg) += " \" /> \n";
1965             }
1967             break;
1968         }
1969         case EMR_POLYBEZIERTO16:
1970         {
1971             dbg_str << "<!-- EMR_POLYBEZIERTO16 -->\n";
1973             PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
1974             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1975             DWORD i,j;
1977             if (d->path->empty()) {
1978                 d->pathless_stroke = true;
1979                 *(d->path) = "d=\"";
1980             }
1982             for (i=0; i<pEmr->cpts;) {
1983                 tmp_path << "\n\tC ";
1984                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1985                     tmp_path <<
1986                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1987                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1988                 }
1989             }
1991             break;
1992         }
1993         case EMR_POLYLINETO16:
1994         {
1995             dbg_str << "<!-- EMR_POLYLINETO16 -->\n";
1997             PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
1998             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1999             DWORD i;
2001             if (d->path->empty()) {
2002                 d->pathless_stroke = true;
2003                 *(d->path) = "d=\"";
2004             }
2006             for (i=0; i<pEmr->cpts;i++) {
2007                 tmp_path <<
2008                     "\n\tL " <<
2009                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2010                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2011             }
2013             break;
2014         }
2015         case EMR_POLYPOLYLINE16:
2016         case EMR_POLYPOLYGON16:
2017         {
2018             if (lpEMFR->iType == EMR_POLYPOLYLINE16)
2019                 dbg_str << "<!-- EMR_POLYPOLYLINE16 -->\n";
2020             if (lpEMFR->iType == EMR_POLYPOLYGON16)
2021                 dbg_str << "<!-- EMR_POLYPOLYGON16 -->\n";
2023             PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
2024             unsigned int n, i, j;
2026             if (!d->inpath) {
2027                 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16");
2029                 *(d->outsvg) += "    <path ";
2030                 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
2031                 *(d->outsvg) += "\n\td=\"";
2032             }
2034             POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys];
2036             i = 0;
2037             for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
2038                 SVGOStringStream poly_path;
2040                 poly_path << "\n\tM " <<
2041                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2042                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2043                 i++;
2045                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
2046                     poly_path << "\n\tL " <<
2047                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2048                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2049                     i++;
2050                 }
2052                 tmp_str << poly_path.str().c_str();
2053                 if (lpEMFR->iType == EMR_POLYPOLYGON16)
2054                     tmp_str << " z";
2055                 tmp_str << " \n";
2056             }
2058             if (d->inpath) {
2059                 tmp_path << tmp_str.str().c_str();
2060             }
2061             else {
2062                 *(d->outsvg) += tmp_str.str().c_str();
2063                 *(d->outsvg) += " \" /> \n";
2064             }
2066             break;
2067         }
2068         case EMR_POLYDRAW16:
2069             dbg_str << "<!-- EMR_POLYDRAW16 -->\n";
2070             break;
2071         case EMR_CREATEMONOBRUSH:
2072             dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n";
2073             break;
2074         case EMR_CREATEDIBPATTERNBRUSHPT:
2075             dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n";
2076             break;
2077         case EMR_EXTCREATEPEN:
2078         {
2079             dbg_str << "<!-- EMR_EXTCREATEPEN -->\n";
2081             PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
2082             int index = pEmr->ihPen;
2084             EMREXTCREATEPEN *pPen =
2085                 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
2086                                             sizeof(DWORD) * pEmr->elp.elpNumEntries );
2087             pPen->ihPen = pEmr->ihPen;
2088             pPen->offBmi = pEmr->offBmi;
2089             pPen->cbBmi = pEmr->cbBmi;
2090             pPen->offBits = pEmr->offBits;
2091             pPen->cbBits = pEmr->cbBits;
2092             pPen->elp = pEmr->elp;
2093             for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
2094                 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
2095             }
2096             insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
2098             break;
2099         }
2100         case EMR_POLYTEXTOUTA:
2101             dbg_str << "<!-- EMR_POLYTEXTOUTA -->\n";
2102             break;
2103         case EMR_POLYTEXTOUTW:
2104             dbg_str << "<!-- EMR_POLYTEXTOUTW -->\n";
2105             break;
2106         case EMR_SETICMMODE:
2107             dbg_str << "<!-- EMR_SETICMMODE -->\n";
2108             break;
2109         case EMR_CREATECOLORSPACE:
2110             dbg_str << "<!-- EMR_CREATECOLORSPACE -->\n";
2111             break;
2112         case EMR_SETCOLORSPACE:
2113             dbg_str << "<!-- EMR_SETCOLORSPACE -->\n";
2114             break;
2115         case EMR_DELETECOLORSPACE:
2116             dbg_str << "<!-- EMR_DELETECOLORSPACE -->\n";
2117             break;
2118         case EMR_GLSRECORD:
2119             dbg_str << "<!-- EMR_GLSRECORD -->\n";
2120             break;
2121         case EMR_GLSBOUNDEDRECORD:
2122             dbg_str << "<!-- EMR_GLSBOUNDEDRECORD -->\n";
2123             break;
2124         case EMR_PIXELFORMAT:
2125             dbg_str << "<!-- EMR_PIXELFORMAT -->\n";
2126             break;
2127         default:
2128             dbg_str << "<!-- EMR_??? -->\n";
2129             break;
2130     }
2131     
2132 //    *(d->outsvg) += dbg_str.str().c_str();
2133     *(d->outsvg) += tmp_outsvg.str().c_str();
2134     *(d->path) += tmp_path.str().c_str();
2136     return 1;
2139 static int CALLBACK
2140 myMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, METARECORD * /*lpMFR*/, int /*nObj*/, LPARAM /*lpData*/)
2142     g_warning("Unable to import Windows Meta File.\n");
2143     return 0;
2146 // Aldus Placeable Header ===================================================
2147 // Since we are a 32bit app, we have to be sure this structure compiles to
2148 // be identical to a 16 bit app's version. To do this, we use the #pragma
2149 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
2150 // for the bbox rectangle.
2151 #pragma pack( push )
2152 #pragma pack( 2 )
2153 typedef struct
2155     DWORD       dwKey;
2156     WORD        hmf;
2157     SMALL_RECT  bbox;
2158     WORD        wInch;
2159     DWORD       dwReserved;
2160     WORD        wCheckSum;
2161 } APMHEADER, *PAPMHEADER;
2162 #pragma pack( pop )
2165 SPDocument *
2166 EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
2168     EMF_CALLBACK_DATA d;
2170     memset(&d, 0, sizeof(d));
2172     d.dc[0].worldTransform.eM11 = 1.0;
2173     d.dc[0].worldTransform.eM12 = 0.0;
2174     d.dc[0].worldTransform.eM21 = 0.0;
2175     d.dc[0].worldTransform.eM22 = 1.0;
2176     d.dc[0].worldTransform.eDx  = 0.0;
2177     d.dc[0].worldTransform.eDy  = 0.0;
2178     
2179     gsize bytesRead = 0;
2180     gsize bytesWritten = 0;
2181     GError* error = NULL;
2182     gchar *local_fn =
2183         g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );
2185     if (local_fn == NULL) {
2186         return NULL;
2187     }
2189     d.outsvg = new Glib::ustring("");
2190     d.path = new Glib::ustring("");
2192     CHAR *ansi_uri = (CHAR *) local_fn;
2193     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
2194     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
2196     DWORD filesize = 0;
2197     HANDLE fp = NULL;
2199     HMETAFILE hmf;
2200     HENHMETAFILE hemf;
2202     if (PrintWin32::is_os_wide()) {
2203         fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2204     }
2205     else {
2206         fp = CreateFileA(ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2207     }
2209     if ( fp != INVALID_HANDLE_VALUE ) {
2210         filesize = GetFileSize(fp, NULL);
2211         CloseHandle(fp);
2212     }
2214     // Try open as Enhanced Metafile
2215     if (PrintWin32::is_os_wide())
2216         hemf = GetEnhMetaFileW(unicode_uri);
2217     else
2218         hemf = GetEnhMetaFileA(ansi_uri);
2220     if (!hemf) {
2221         // Try open as Windows Metafile
2222         if (PrintWin32::is_os_wide())
2223             hmf = GetMetaFileW(unicode_uri);
2224         else
2225             hmf = GetMetaFileA(ansi_uri);
2227         METAFILEPICT mp;
2228         HDC hDC;
2230         if (!hmf) {
2231             if (PrintWin32::is_os_wide()) {
2232                 WCHAR szTemp[MAX_PATH];
2234                 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
2235                 if (dw) {
2236                     hmf = GetMetaFileW( szTemp );
2237                 }
2238             } else {
2239                 CHAR szTemp[MAX_PATH];
2241                 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );
2242                 if (dw) {
2243                     hmf = GetMetaFileA( szTemp );
2244                 }
2245             }
2246         }
2248         if (hmf) {
2249             DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
2251             if (!nSize)
2252                 nSize = filesize;
2253             
2254             if (nSize) {
2255                 BYTE *lpvData = new BYTE[nSize];
2256                 if (lpvData) {
2257                     DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
2258                     if (dw) {
2259                         // Fill out a METAFILEPICT structure
2260                         mp.mm = MM_ANISOTROPIC;
2261                         mp.xExt = 1000;
2262                         mp.yExt = 1000;
2263                         mp.hMF = NULL;
2264                         // Get a reference DC
2265                         hDC = GetDC( NULL );
2266                         // Make an enhanced metafile from the windows metafile
2267                         hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
2268                         // Clean up
2269                         ReleaseDC( NULL, hDC );
2270                         DeleteMetaFile( hmf );
2271                         hmf = NULL;
2272                     }
2273                     else {
2274                         // EnumMetaFile
2275                     }
2276                     delete[] lpvData;
2277                 }
2278                 else {
2279                     DeleteMetaFile( hmf );
2280                     hmf = NULL;
2281                 }
2282             }
2283             else {
2284                 DeleteMetaFile( hmf );
2285                 hmf = NULL;
2286             }
2287         }
2288         else {
2289             // Try open as Aldus Placeable Metafile
2290             HANDLE hFile;
2291             if (PrintWin32::is_os_wide())
2292                 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2293             else
2294                 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2296             if (hFile != INVALID_HANDLE_VALUE) {
2297                 DWORD nSize = GetFileSize( hFile, NULL );
2298                 if (nSize) {
2299                     BYTE *lpvData = new BYTE[nSize];
2300                     if (lpvData) {
2301                         DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
2302                         if (dw) {
2303                             if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
2304                                 // Fill out a METAFILEPICT structure
2305                                 mp.mm = MM_ANISOTROPIC;
2306                                 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
2307                                 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2308                                 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
2309                                 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2310                                 mp.hMF = NULL;
2311                                 // Get a reference DC
2312                                 hDC = GetDC( NULL );
2313                                 // Create an enhanced metafile from the bits
2314                                 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
2315                                 // Clean up
2316                                 ReleaseDC( NULL, hDC );
2317                             }
2318                         }
2319                         delete[] lpvData;
2320                     }
2321                 }
2322                 CloseHandle( hFile );
2323             }
2324         }
2325     }
2327     if ((!hemf && !hmf) || !d.outsvg || !d.path) {
2328         if (d.outsvg)
2329             delete d.outsvg;
2330         if (d.path)
2331             delete d.path;
2332         if (local_fn)
2333             g_free(local_fn);
2334         if (unicode_fn)
2335             g_free(unicode_fn);
2336         if (hemf)
2337             DeleteEnhMetaFile(hemf);
2338         if (hmf)
2339             DeleteMetaFile(hmf);
2340         return NULL;
2341     }
2343     d.pDesc = NULL;
2345     if (hemf) {
2346         DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL );
2347         if ( dwNeeded > 0 ) {
2348             d.pDesc = (CHAR *) malloc( dwNeeded + 1 );
2349             if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 )
2350                 lstrcpy( d.pDesc, "" );
2351             if ( lstrlen( d.pDesc ) > 1 )
2352                 d.pDesc[lstrlen(d.pDesc)] = '#';
2353         }
2355         EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);
2356         DeleteEnhMetaFile(hemf);
2357     }
2358     else {
2359         EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d);
2360         DeleteMetaFile(hmf);
2361     }
2362     
2363     if (d.pDesc)
2364         free( d.pDesc );
2366 //    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
2368     SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);
2370     delete d.outsvg;
2371     delete d.path;
2373     if (d.emf_obj) {
2374         int i;
2375         for (i=0; i<d.n_obj; i++)
2376             delete_object(&d, i);
2377         delete[] d.emf_obj;
2378     }
2379     
2380     if (d.dc[0].style.stroke_dash.dash)
2381         delete[] d.dc[0].style.stroke_dash.dash;
2383     if  (local_fn)
2384         g_free(local_fn);
2385     if  (unicode_fn)
2386         g_free(unicode_fn);
2388     return doc;
2392 void
2393 EmfWin32::init (void)
2395     Inkscape::Extension::Extension * ext;
2397     /* EMF in */
2398     ext = Inkscape::Extension::build_from_mem(
2399         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2400             "<name>" N_("EMF Input") "</name>\n"
2401             "<id>org.inkscape.input.emf.win32</id>\n"
2402             "<input>\n"
2403                 "<extension>.emf</extension>\n"
2404                 "<mimetype>image/x-emf</mimetype>\n"
2405                 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
2406                 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
2407                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2408             "</input>\n"
2409         "</inkscape-extension>", new EmfWin32());
2411     /* WMF in */
2412     ext = Inkscape::Extension::build_from_mem(
2413         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2414             "<name>" N_("WMF Input") "</name>\n"
2415             "<id>org.inkscape.input.wmf.win32</id>\n"
2416             "<input>\n"
2417                 "<extension>.wmf</extension>\n"
2418                 "<mimetype>image/x-wmf</mimetype>\n"
2419                 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
2420                 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
2421                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2422             "</input>\n"
2423         "</inkscape-extension>", new EmfWin32());
2425     /* EMF out */
2426     ext = Inkscape::Extension::build_from_mem(
2427         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2428             "<name>" N_("EMF Output") "</name>\n"
2429             "<id>org.inkscape.output.emf.win32</id>\n"
2430             "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
2431             "<output>\n"
2432                 "<extension>.emf</extension>\n"
2433                 "<mimetype>image/x-emf</mimetype>\n"
2434                 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
2435                 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
2436             "</output>\n"
2437         "</inkscape-extension>", new EmfWin32());
2439     return;
2443 } } }  /* namespace Inkscape, Extension, Implementation */
2445 #endif /* WIN32 */
2446 /*
2447   Local Variables:
2448   mode:c++
2449   c-file-style:"stroustrup"
2450   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
2451   indent-tabs-mode:nil
2452   fill-column:99
2453   End:
2454 */
2455 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :