Code

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