Code

2geomify, remove warnings and other fixes
[inkscape.git] / src / extension / internal / emf-win32-inout.cpp
1 /** \file
2  * Enhanced Metafile Input and Output.
3  */
4 /*
5  * Authors:
6  *   Ulf Erikson <ulferikson@users.sf.net>
7  *
8  * Copyright (C) 2006-2008 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
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     sp_document_ensure_up_to_date(doc);
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", (gchar *)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(sp_document_root(doc));
126     mod->arena = NRArena::create();
127     mod->dkey = sp_item_display_key_new(1);
128     mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);
129     /* Print document */
130     ret = mod->begin(doc);
131     if (ret) {
132         throw Inkscape::Extension::Output::save_failed();
133     }
134     sp_item_invoke_print(mod->base, &context);
135     ret = mod->finish();
136     /* Release arena */
137     sp_item_invoke_hide(mod->base, mod->dkey);
138     mod->base = NULL;
139     nr_arena_item_unref(mod->root);
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, const gchar *uri)
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     gchar * final_name;
166     final_name = g_strdup_printf("%s", uri);
167     emf_print_document_to_file(doc, final_name);
168     g_free(final_name);
170     ext->set_param_bool("textToPath", old_textToPath);
172     return;
177 typedef struct {
178     int type;
179     int level;
180     ENHMETARECORD *lpEMFR;
181 } EMF_OBJECT, *PEMF_OBJECT;
183 typedef struct emf_device_context {
184     struct SPStyle style;
185     class SPTextStyle tstyle;
186     bool stroke_set;
187     bool fill_set;
189     SIZEL sizeWnd;
190     SIZEL sizeView;
191     float PixelsInX, PixelsInY;
192     float PixelsOutX, PixelsOutY;
193     POINTL winorg;
194     POINTL vieworg;
195     double ScaleInX, ScaleInY;
196     double ScaleOutX, ScaleOutY;
197     COLORREF textColor;
198     bool textColorSet;
199     DWORD textAlign;
200     XFORM worldTransform;
201     POINTL cur;
202 } EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT;
204 #define EMF_MAX_DC 128
206 typedef struct emf_callback_data {
207     Glib::ustring *outsvg;
208     Glib::ustring *path;
210     EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
211     int level;
212     
213     double xDPI, yDPI;
214     bool pathless_stroke;
215     bool inpath;
217     float MMX;
218     float MMY;
219     float dwInchesX;
220     float dwInchesY;
222     unsigned int id;
223     CHAR *pDesc;
225     int n_obj;
226     PEMF_OBJECT emf_obj;
227 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
230 static void
231 output_style(PEMF_CALLBACK_DATA d, int iType)
233     SVGOStringStream tmp_id;
234     SVGOStringStream tmp_style;
235     char tmp[1024] = {0};
237     float fill_rgb[3];
238     sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
239     
240     float stroke_rgb[3];
241     sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
243     tmp_id << "\n\tid=\"" << (d->id++) << "\"";
244     *(d->outsvg) += tmp_id.str().c_str();
245     *(d->outsvg) += "\n\tstyle=\"";
246     if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) {
247         tmp_style << "fill:none;";
248     } else {
249         snprintf(tmp, 1023,
250                  "fill:#%02x%02x%02x;",
251                  SP_COLOR_F_TO_U(fill_rgb[0]),
252                  SP_COLOR_F_TO_U(fill_rgb[1]),
253                  SP_COLOR_F_TO_U(fill_rgb[2]));
254         tmp_style << tmp;
255         snprintf(tmp, 1023,
256                  "fill-rule:%s;",
257                  d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero");
258         tmp_style << tmp;
259         tmp_style << "fill-opacity:1;";
261         if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 &&
262             fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
263         {
264             d->dc[d->level].stroke_set = false;
265         }
266     }
268     if (iType == EMR_FILLPATH || !d->dc[d->level].stroke_set) {
269         tmp_style << "stroke:none;";
270     } else {
271         snprintf(tmp, 1023,
272                  "stroke:#%02x%02x%02x;",
273                  SP_COLOR_F_TO_U(stroke_rgb[0]),
274                  SP_COLOR_F_TO_U(stroke_rgb[1]),
275                  SP_COLOR_F_TO_U(stroke_rgb[2]));
276         tmp_style << tmp;
278         tmp_style << "stroke-width:" <<
279             MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
281         tmp_style << "stroke-linecap:" <<
282             (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
283              d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
284              d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
285              "unknown") << ";";
287         tmp_style << "stroke-linejoin:" <<
288             (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
289              d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
290              d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
291              "unknown") << ";";
293         if (d->dc[d->level].style.stroke_linejoin.computed == 0) {
294             tmp_style << "stroke-miterlimit:" <<
295                 MAX( 0.01, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
296         }
298         if (d->dc[d->level].style.stroke_dasharray_set &&
299             d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash)
300         {
301             tmp_style << "stroke-dasharray:";
302             for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) {
303                 if (i)
304                     tmp_style << ",";
305                 tmp_style << d->dc[d->level].style.stroke_dash.dash[i];
306             }
307             tmp_style << ";";
308             tmp_style << "stroke-dashoffset:0;";
309         } else {
310             tmp_style << "stroke-dasharray:none;";
311         }
312         tmp_style << "stroke-opacity:1;";
313     }
314     tmp_style << "\" ";
316     *(d->outsvg) += tmp_style.str().c_str();
320 static double
321 _pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
323     double tmp = px - d->dc[d->level].winorg.x;
324     tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0;
325     tmp += d->dc[d->level].vieworg.x;
326     return tmp;
329 static double
330 _pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
332     double tmp = px - d->dc[d->level].winorg.y;
333     tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0;
334     tmp += d->dc[d->level].vieworg.y;
335     return tmp;
339 static double
340 pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
342     double ppx = _pix_x_to_point(d, px);
343     double ppy = _pix_y_to_point(d, py);
345     double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
346     x *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE;
347     
348     return x;
351 static double
352 pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
354     double ppx = _pix_x_to_point(d, px);
355     double ppy = _pix_y_to_point(d, py);
357     double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
358     y *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE;
359     
360     return y;
363 static double
364 pix_to_size_point(PEMF_CALLBACK_DATA d, double px)
366     double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
367     double ppy = 0;
369     double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21;
370     dx *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE;
371     double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22;
372     dy *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE;
374     double tmp = sqrt(dx * dx + dy * dy);
375     return tmp;
379 static void
380 select_pen(PEMF_CALLBACK_DATA d, int index)
382     PEMRCREATEPEN pEmr = NULL;
384     if (index >= 0 && index < d->n_obj)
385         pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
387     if (!pEmr)
388         return;
390     switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) {
391         case PS_DASH:
392         case PS_DOT:
393         case PS_DASHDOT:
394         case PS_DASHDOTDOT:
395         {
396             int i = 0;
397             int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK);
398             d->dc[d->level].style.stroke_dash.n_dash =
399                 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
400             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)))
401                 delete[] d->dc[d->level].style.stroke_dash.dash;
402             d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
403             if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
404                 d->dc[d->level].style.stroke_dash.dash[i++] = 3;
405                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
406             }
407             if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
408                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
409                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
410             }
411             if (penstyle==PS_DASHDOTDOT) {
412                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
413                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
414             }
415             
416             d->dc[d->level].style.stroke_dasharray_set = 1;
417             break;
418         }
419         
420         case PS_SOLID:
421         default:
422         {
423             d->dc[d->level].style.stroke_dasharray_set = 0;
424             break;
425         }
426     }
428     switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) {
429         case PS_ENDCAP_ROUND:
430         {
431             d->dc[d->level].style.stroke_linecap.computed = 1;
432             break;
433         }
434         case PS_ENDCAP_SQUARE:
435         {
436             d->dc[d->level].style.stroke_linecap.computed = 2;
437             break;
438         }
439         case PS_ENDCAP_FLAT:
440         default:
441         {
442             d->dc[d->level].style.stroke_linecap.computed = 0;
443             break;
444         }
445     }
447     switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) {
448         case PS_JOIN_BEVEL:
449         {
450             d->dc[d->level].style.stroke_linejoin.computed = 2;
451             break;
452         }
453         case PS_JOIN_MITER:
454         {
455             d->dc[d->level].style.stroke_linejoin.computed = 0;
456             break;
457         }
458         case PS_JOIN_ROUND:
459         default:
460         {
461             d->dc[d->level].style.stroke_linejoin.computed = 1;
462             break;
463         }
464     }
466     d->dc[d->level].stroke_set = true;
468     if (pEmr->lopn.lopnStyle == PS_NULL) {
469         d->dc[d->level].style.stroke_width.value = 0;
470         d->dc[d->level].stroke_set = false;
471     } else if (pEmr->lopn.lopnWidth.x) {
472         int cur_level = d->level;
473         d->level = d->emf_obj[index].level;
474         double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x );
475         d->level = cur_level;
476         d->dc[d->level].style.stroke_width.value = pen_width;
477     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
478         //d->dc[d->level].style.stroke_width.value = 1.0;
479         int cur_level = d->level;
480         d->level = d->emf_obj[index].level;
481         double pen_width = pix_to_size_point( d, 1 );
482         d->level = cur_level;
483         d->dc[d->level].style.stroke_width.value = pen_width;
484     }
486     double r, g, b;
487     r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
488     g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
489     b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
490     d->dc[d->level].style.stroke.value.color.set( r, g, b );
494 static void
495 select_extpen(PEMF_CALLBACK_DATA d, int index)
497     PEMREXTCREATEPEN pEmr = NULL;
499     if (index >= 0 && index < d->n_obj)
500         pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
502     if (!pEmr)
503         return;
505     switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
506         case PS_USERSTYLE:
507         {
508             if (pEmr->elp.elpNumEntries) {
509                 d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
510                 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)))
511                     delete[] d->dc[d->level].style.stroke_dash.dash;
512                 d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
513                 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
514                     int cur_level = d->level;
515                     d->level = d->emf_obj[index].level;
516                     double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] );
517                     d->level = cur_level;
518                     d->dc[d->level].style.stroke_dash.dash[i] = dash_length;
519                 }
520                 d->dc[d->level].style.stroke_dasharray_set = 1;
521             } else {
522                 d->dc[d->level].style.stroke_dasharray_set = 0;
523             }
524             break;
525         }
527         case PS_DASH:
528         case PS_DOT:
529         case PS_DASHDOT:
530         case PS_DASHDOTDOT:
531         {
532             int i = 0;
533             int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK);
534             d->dc[d->level].style.stroke_dash.n_dash =
535                 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
536             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)))
537                 delete[] d->dc[d->level].style.stroke_dash.dash;
538             d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash];
539             if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
540                 d->dc[d->level].style.stroke_dash.dash[i++] = 3;
541                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
542             }
543             if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
544                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
545                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
546             }
547             if (penstyle==PS_DASHDOTDOT) {
548                 d->dc[d->level].style.stroke_dash.dash[i++] = 1;
549                 d->dc[d->level].style.stroke_dash.dash[i++] = 2;
550             }
551             
552             d->dc[d->level].style.stroke_dasharray_set = 1;
553             break;
554         }
555         
556         case PS_SOLID:
557         default:
558         {
559             d->dc[d->level].style.stroke_dasharray_set = 0;
560             break;
561         }
562     }
564     switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
565         case PS_ENDCAP_ROUND:
566         {
567             d->dc[d->level].style.stroke_linecap.computed = 1;
568             break;
569         }
570         case PS_ENDCAP_SQUARE:
571         {
572             d->dc[d->level].style.stroke_linecap.computed = 2;
573             break;
574         }
575         case PS_ENDCAP_FLAT:
576         default:
577         {
578             d->dc[d->level].style.stroke_linecap.computed = 0;
579             break;
580         }
581     }
583     switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
584         case PS_JOIN_BEVEL:
585         {
586             d->dc[d->level].style.stroke_linejoin.computed = 2;
587             break;
588         }
589         case PS_JOIN_MITER:
590         {
591             d->dc[d->level].style.stroke_linejoin.computed = 0;
592             break;
593         }
594         case PS_JOIN_ROUND:
595         default:
596         {
597             d->dc[d->level].style.stroke_linejoin.computed = 1;
598             break;
599         }
600     }
602     d->dc[d->level].stroke_set = true;
604     if (pEmr->elp.elpPenStyle == PS_NULL) {
605         d->dc[d->level].style.stroke_width.value = 0;
606         d->dc[d->level].stroke_set = false;
607     } else if (pEmr->elp.elpWidth) {
608         int cur_level = d->level;
609         d->level = d->emf_obj[index].level;
610         double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth );
611         d->level = cur_level;
612         d->dc[d->level].style.stroke_width.value = pen_width;
613     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
614         //d->dc[d->level].style.stroke_width.value = 1.0;
615         int cur_level = d->level;
616         d->level = d->emf_obj[index].level;
617         double pen_width = pix_to_size_point( d, 1 );
618         d->level = cur_level;
619         d->dc[d->level].style.stroke_width.value = pen_width;
620     }
622     double r, g, b;
623     r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
624     g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
625     b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
627     d->dc[d->level].style.stroke.value.color.set( r, g, b );
631 static void
632 select_brush(PEMF_CALLBACK_DATA d, int index)
634     PEMRCREATEBRUSHINDIRECT pEmr = NULL;
636     if (index >= 0 && index < d->n_obj)
637         pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
639     if (!pEmr)
640         return;
642     if (pEmr->lb.lbStyle == BS_SOLID) {
643         double r, g, b;
644         r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
645         g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
646         b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
647         d->dc[d->level].style.fill.value.color.set( r, g, b );
648     }
650     d->dc[d->level].fill_set = true;
654 static void
655 select_font(PEMF_CALLBACK_DATA d, int index)
657     PEMREXTCREATEFONTINDIRECTW pEmr = NULL;
659     if (index >= 0 && index < d->n_obj)
660         pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
662     if (!pEmr)
663         return;
665     int cur_level = d->level;
666     d->level = d->emf_obj[index].level;
667     double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight );
668     d->level = cur_level;
669     d->dc[d->level].style.font_size.computed = font_size;
670     d->dc[d->level].style.font_weight.value =
671         pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
672         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
673         pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
674         pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
675         pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
676         pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
677         pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
678         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
679         pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
680         pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
681         pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
682         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
683         pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
684         FW_NORMAL;
685     d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
686     d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline;
687     d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
688     if (d->dc[d->level].tstyle.font_family.value)
689         g_free(d->dc[d->level].tstyle.font_family.value);
690     d->dc[d->level].tstyle.font_family.value =
691         (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL );
692     d->dc[d->level].style.text_transform.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10;
695 static void
696 delete_object(PEMF_CALLBACK_DATA d, int index)
698     if (index >= 0 && index < d->n_obj) {
699         d->emf_obj[index].type = 0;
700         if (d->emf_obj[index].lpEMFR)
701             free(d->emf_obj[index].lpEMFR);
702         d->emf_obj[index].lpEMFR = NULL;
703     }
707 static void
708 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
710     if (index >= 0 && index < d->n_obj) {
711         delete_object(d, index);
712         d->emf_obj[index].type = type;
713         d->emf_obj[index].level = d->level;
714         d->emf_obj[index].lpEMFR = pObj;
715     }
718 static void
719 assert_empty_path(PEMF_CALLBACK_DATA d, const char * /*fun*/)
721     if (!d->path->empty()) {
722         // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun);
724         *(d->outsvg) += "<!--\n";
725         *(d->outsvg) += "    <path \t";
726         output_style(d, EMR_STROKEPATH);
727         if (strstr(d->path->c_str(), "d=\"") == NULL) {
728             *(d->outsvg) += "d=\"";
729             *(d->outsvg) += "\n\t";
730         }
731         *(d->outsvg) += *(d->path);
732         *(d->outsvg) += " \" /> \n";
733         *(d->outsvg) += "-->\n";
735         *(d->path) = "";
736     }
740 static int CALLBACK
741 myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD *lpEMFR, int /*nObj*/, LPARAM lpData)
743     PEMF_CALLBACK_DATA d;
744     SVGOStringStream tmp_outsvg;
745     SVGOStringStream tmp_path;
746     SVGOStringStream tmp_str;
747     SVGOStringStream dbg_str;
749     d = (PEMF_CALLBACK_DATA) lpData;
751     if (d->pathless_stroke) {
752         if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 &&
753             lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 &&
754             lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO &&
755             lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 &&
756             lpEMFR->iType!=EMR_SETBKMODE)
757         {
758             *(d->outsvg) += "    <path ";
759             output_style(d, EMR_STROKEPATH);
760             *(d->outsvg) += "\n\t";
761             *(d->outsvg) += *(d->path);
762             *(d->outsvg) += " \" /> \n";
763             *(d->path) = "";
764             d->pathless_stroke = false;
765         }
766     }
768     switch (lpEMFR->iType)
769     {
770         case EMR_HEADER:
771         {
772             dbg_str << "<!-- EMR_HEADER -->\n";
774             *(d->outsvg) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
776             if (d->pDesc) {
777                 *(d->outsvg) += "<!-- ";
778                 *(d->outsvg) += d->pDesc;
779                 *(d->outsvg) += " -->\n";
780             }
782             ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
783             tmp_outsvg << "<svg\n";
784             tmp_outsvg << "  xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
785             tmp_outsvg << "  xmlns=\"http://www.w3.org/2000/svg\"\n";
786             tmp_outsvg << "  version=\"1.0\"\n";
788             d->xDPI = 2540;
789             d->yDPI = 2540;
791             d->dc[d->level].PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left;
792             d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;
794             d->MMX = d->dc[d->level].PixelsInX / 100.0;
795             d->MMY = d->dc[d->level].PixelsInY / 100.0;
797             d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM;
798             d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM;
799             
800             tmp_outsvg <<
801                 "  width=\"" << d->MMX << "mm\"\n" <<
802                 "  height=\"" << d->MMY << "mm\"\n";
803             tmp_outsvg <<
804                 "  id=\"" << (d->id++) << "\">\n";
806             tmp_outsvg <<
807                 "<g\n" <<
808                 "  id=\"" << (d->id++) << "\">\n";
810             if (pEmr->nHandles) {
811                 d->n_obj = pEmr->nHandles;
812                 d->emf_obj = new EMF_OBJECT[d->n_obj];
813                 
814                 // Init the new emf_obj list elements to null, provided the
815                 // dynamic allocation succeeded.
816                 if ( d->emf_obj != NULL )
817                 {
818                     for( int i=0; i < d->n_obj; ++i )
819                         d->emf_obj[i].lpEMFR = NULL;
820                 } //if
822             } else {
823                 d->emf_obj = NULL;
824             }
826             break;
827         }
828         case EMR_POLYBEZIER:
829         {
830             dbg_str << "<!-- EMR_POLYBEZIER -->\n";
832             PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
833             DWORD i,j;
835             if (pEmr->cptl<4)
836                 break;
838             if (!d->inpath) {
839                 assert_empty_path(d, "EMR_POLYBEZIER");
841                 *(d->outsvg) += "    <path ";
842                 output_style(d, EMR_STROKEPATH);
843                 *(d->outsvg) += "\n\td=\"";
844             }
846             tmp_str <<
847                 "\n\tM " <<
848                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
849                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
851             for (i=1; i<pEmr->cptl; ) {
852                 tmp_str << "\n\tC ";
853                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
854                     tmp_str <<
855                         pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
856                         pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
857                 }
858             }
860             if (d->inpath) {
861                 tmp_path << tmp_str.str().c_str();
862             }
863             else {
864                 *(d->outsvg) += tmp_str.str().c_str();
865                 *(d->outsvg) += " \" /> \n";
866             }
868             break;
869         }
870         case EMR_POLYGON:
871         {
872             dbg_str << "<!-- EMR_POLYGON -->\n";
874             EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
875             DWORD i;
877             if (pEmr->cptl < 2)
878                 break;
880             assert_empty_path(d, "EMR_POLYGON");
882             *(d->outsvg) += "    <path ";
883             output_style(d, EMR_STROKEANDFILLPATH);
884             *(d->outsvg) += "\n\td=\"";
886             tmp_str <<
887                 "\n\tM " <<
888                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
889                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
891             for (i=1; i<pEmr->cptl; i++) {
892                 tmp_str <<
893                     "\n\tL " <<
894                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
895                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
896             }
898             *(d->outsvg) += tmp_str.str().c_str();
899             *(d->outsvg) += " z \" /> \n";
901             break;
902         }
903         case EMR_POLYLINE:
904         {
905             dbg_str << "<!-- EMR_POLYLINE -->\n";
907             EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
908             DWORD i;
910             if (pEmr->cptl<2)
911                 break;
913             if (!d->inpath) {
914                 assert_empty_path(d, "EMR_POLYLINE");
916                 *(d->outsvg) += "    <path ";
917                 output_style(d, EMR_STROKEPATH);
918                 *(d->outsvg) += "\n\td=\"";
919             }
921             tmp_str <<
922                 "\n\tM " <<
923                 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
924                 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
926             for (i=1; i<pEmr->cptl; i++) {
927                 tmp_str <<
928                     "\n\tL " <<
929                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
930                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
931             }
933             if (d->inpath) {
934                 tmp_path << tmp_str.str().c_str();
935             }
936             else {
937                 *(d->outsvg) += tmp_str.str().c_str();
938                 *(d->outsvg) += " \" /> \n";
939             }
941             break;
942         }
943         case EMR_POLYBEZIERTO:
944         {
945             dbg_str << "<!-- EMR_POLYBEZIERTO -->\n";
947             PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
948             DWORD i,j;
950             if (d->path->empty()) {
951                 d->pathless_stroke = true;
952                 *(d->path) = "d=\"";
953             }
955             for (i=0; i<pEmr->cptl;) {
956                 tmp_path << "\n\tC ";
957                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
958                     tmp_path <<
959                         pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
960                         pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
961                 }
962             }
964             break;
965         }
966         case EMR_POLYLINETO:
967         {
968             dbg_str << "<!-- EMR_POLYLINETO -->\n";
970             PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
971             DWORD i;
973             if (d->path->empty()) {
974                 d->pathless_stroke = true;
975                 *(d->path) = "d=\"";
976             }
978             for (i=0; i<pEmr->cptl;i++) {
979                 tmp_path <<
980                     "\n\tL " <<
981                     pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
982                     pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
983             }
985             break;
986         }
987         case EMR_POLYPOLYLINE:
988         case EMR_POLYPOLYGON:
989         {
990             if (lpEMFR->iType == EMR_POLYPOLYLINE)
991                 dbg_str << "<!-- EMR_POLYPOLYLINE -->\n";
992             if (lpEMFR->iType == EMR_POLYPOLYGON)
993                 dbg_str << "<!-- EMR_POLYPOLYGON -->\n";
995             PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR;
996             unsigned int n, i, j;
998             if (!d->inpath) {
999                 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE");
1001                 *(d->outsvg) += "    <path ";
1002                 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
1003                 *(d->outsvg) += "\n\td=\"";
1004             }
1006             POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys];
1008             i = 0;
1009             for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
1010                 SVGOStringStream poly_path;
1012                 poly_path << "\n\tM " <<
1013                     pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
1014                     pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
1015                 i++;
1017                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
1018                     poly_path << "\n\tL " <<
1019                         pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
1020                         pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
1021                     i++;
1022                 }
1024                 tmp_str << poly_path.str().c_str();
1025                 if (lpEMFR->iType == EMR_POLYPOLYGON)
1026                     tmp_str << " z";
1027                 tmp_str << " \n";
1028             }
1030             if (d->inpath) {
1031                 tmp_path << tmp_str.str().c_str();
1032             }
1033             else {
1034                 *(d->outsvg) += tmp_str.str().c_str();
1035                 *(d->outsvg) += " \" /> \n";
1036             }
1038             break;
1039         }
1040         case EMR_SETWINDOWEXTEX:
1041         {
1042             dbg_str << "<!-- EMR_SETWINDOWEXTEX -->\n";
1044             PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
1046             d->dc[d->level].sizeWnd = pEmr->szlExtent;
1048             if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1049                 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1050                 if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1051                     d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX;
1052                     d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY;
1053                 }
1054             }
1056             if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1057                 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
1058             }
1060             d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
1061             d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
1062             
1063             if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
1064                 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
1065                 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
1066             }
1067             else {
1068                 d->dc[d->level].ScaleInX = 1;
1069                 d->dc[d->level].ScaleInY = 1;
1070             }
1072             if (d->dc[d->level].sizeView.cx && d->dc[d->level].sizeView.cy) {
1073                 d->dc[d->level].ScaleOutX = (double) d->dc[d->level].PixelsOutX / (double) d->dc[d->level].sizeView.cx;
1074                 d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy;
1075             }
1076             else {
1077                 d->dc[d->level].ScaleOutX = DEVICESCALE;
1078                 d->dc[d->level].ScaleOutY = DEVICESCALE;
1079             }
1081             break;
1082         }
1083         case EMR_SETWINDOWORGEX:
1084         {
1085             dbg_str << "<!-- EMR_SETWINDOWORGEX -->\n";
1087             PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
1088             d->dc[d->level].winorg = pEmr->ptlOrigin;
1089             break;
1090         }
1091         case EMR_SETVIEWPORTEXTEX:
1092         {
1093             dbg_str << "<!-- EMR_SETVIEWPORTEXTEX -->\n";
1095             PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
1097             d->dc[d->level].sizeView = pEmr->szlExtent;
1099             if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1100                 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
1101                 if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
1102                     d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX;
1103                     d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY;
1104                 }
1105             }
1107             if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1108                 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1109             }
1111             d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx;
1112             d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy;
1113             
1114             if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) {
1115                 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX;
1116                 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY;
1117             }
1118             else {
1119                 d->dc[d->level].ScaleInX = 1;
1120                 d->dc[d->level].ScaleInY = 1;
1121             }
1123             if (d->dc[d->level].sizeView.cx && d->dc[d->level].sizeView.cy) {
1124                 d->dc[d->level].ScaleOutX = (double) d->dc[d->level].PixelsOutX / (double) d->dc[d->level].sizeView.cx;
1125                 d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy;
1126             }
1127             else {
1128                 d->dc[d->level].ScaleOutX = DEVICESCALE;
1129                 d->dc[d->level].ScaleOutY = DEVICESCALE;
1130             }
1132             break;
1133         }
1134         case EMR_SETVIEWPORTORGEX:
1135         {
1136             dbg_str << "<!-- EMR_SETVIEWPORTORGEX -->\n";
1138             PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
1139             d->dc[d->level].vieworg = pEmr->ptlOrigin;
1140             break;
1141         }
1142         case EMR_SETBRUSHORGEX:
1143             dbg_str << "<!-- EMR_SETBRUSHORGEX -->\n";
1144             break;
1145         case EMR_EOF:
1146         {
1147             dbg_str << "<!-- EMR_EOF -->\n";
1149             assert_empty_path(d, "EMR_EOF");
1150             tmp_outsvg << "</g>\n";
1151             tmp_outsvg << "</svg>\n";
1152             break;
1153         }
1154         case EMR_SETPIXELV:
1155             dbg_str << "<!-- EMR_SETPIXELV -->\n";
1156             break;
1157         case EMR_SETMAPPERFLAGS:
1158             dbg_str << "<!-- EMR_SETMAPPERFLAGS -->\n";
1159             break;
1160         case EMR_SETMAPMODE:
1161             dbg_str << "<!-- EMR_SETMAPMODE -->\n";
1162             break;
1163         case EMR_SETBKMODE:
1164             dbg_str << "<!-- EMR_SETBKMODE -->\n";
1165             break;
1166         case EMR_SETPOLYFILLMODE:
1167         {
1168             dbg_str << "<!-- EMR_SETPOLYFILLMODE -->\n";
1170             PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
1171             d->dc[d->level].style.fill_rule.value =
1172                 (pEmr->iMode == ALTERNATE ? 0 :
1173                  pEmr->iMode == WINDING ? 1 : 0);
1174             break;
1175         }
1176         case EMR_SETROP2:
1177             dbg_str << "<!-- EMR_SETROP2 -->\n";
1178             break;
1179         case EMR_SETSTRETCHBLTMODE:
1180             dbg_str << "<!-- EMR_SETSTRETCHBLTMODE -->\n";
1181             break;
1182         case EMR_SETTEXTALIGN:
1183         {
1184             dbg_str << "<!-- EMR_SETTEXTALIGN -->\n";
1186             PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR;
1187             d->dc[d->level].textAlign = pEmr->iMode;
1188             break;
1189         }
1190         case EMR_SETCOLORADJUSTMENT:
1191             dbg_str << "<!-- EMR_SETCOLORADJUSTMENT -->\n";
1192             break;
1193         case EMR_SETTEXTCOLOR:
1194         {
1195             dbg_str << "<!-- EMR_SETTEXTCOLOR -->\n";
1197             PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR;
1198             d->dc[d->level].textColor = pEmr->crColor;
1199             d->dc[d->level].textColorSet = true;
1200             break;
1201         }
1202         case EMR_SETBKCOLOR:
1203             dbg_str << "<!-- EMR_SETBKCOLOR -->\n";
1204             break;
1205         case EMR_OFFSETCLIPRGN:
1206             dbg_str << "<!-- EMR_OFFSETCLIPRGN -->\n";
1207             break;
1208         case EMR_MOVETOEX:
1209         {
1210             dbg_str << "<!-- EMR_MOVETOEX -->\n";
1212             PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
1214             if (d->path->empty()) {
1215                 d->pathless_stroke = true;
1216                 *(d->path) = "d=\"";
1217             }
1219             d->dc[d->level].cur = pEmr->ptl;
1221             tmp_path <<
1222                 "\n\tM " <<
1223                 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1224                 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1225             break;
1226         }
1227         case EMR_SETMETARGN:
1228             dbg_str << "<!-- EMR_SETMETARGN -->\n";
1229             break;
1230         case EMR_EXCLUDECLIPRECT:
1231             dbg_str << "<!-- EMR_EXCLUDECLIPRECT -->\n";
1232             break;
1233         case EMR_INTERSECTCLIPRECT:
1234             dbg_str << "<!-- EMR_INTERSECTCLIPRECT -->\n";
1235             break;
1236         case EMR_SCALEVIEWPORTEXTEX:
1237             dbg_str << "<!-- EMR_SCALEVIEWPORTEXTEX -->\n";
1238             break;
1239         case EMR_SCALEWINDOWEXTEX:
1240             dbg_str << "<!-- EMR_SCALEWINDOWEXTEX -->\n";
1241             break;
1242         case EMR_SAVEDC:
1243             dbg_str << "<!-- EMR_SAVEDC -->\n";
1245             if (d->level < EMF_MAX_DC) {
1246                 d->dc[d->level + 1] = d->dc[d->level];
1247                 d->level = d->level + 1;
1248             }
1249             break;
1250         case EMR_RESTOREDC:
1251         {
1252             dbg_str << "<!-- EMR_RESTOREDC -->\n";
1253             
1254             PEMRRESTOREDC pEmr = (PEMRRESTOREDC) lpEMFR;
1255             int old_level = d->level;
1256             if (pEmr->iRelative >= 0) {
1257                 if (pEmr->iRelative < d->level)
1258                     d->level = pEmr->iRelative;
1259             }
1260             else {
1261                 if (d->level + pEmr->iRelative >= 0)
1262                     d->level = d->level + pEmr->iRelative;
1263             }
1264             while (old_level > d->level) {
1265                 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)))
1266                     delete[] d->dc[old_level].style.stroke_dash.dash;
1267                 old_level--;
1268             }
1269             break;
1270         }
1271         case EMR_SETWORLDTRANSFORM:
1272         {
1273             dbg_str << "<!-- EMR_SETWORLDTRANSFORM -->\n";
1275             PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR;
1276             d->dc[d->level].worldTransform = pEmr->xform;
1277             break;
1278         }
1279         case EMR_MODIFYWORLDTRANSFORM:
1280         {
1281             dbg_str << "<!-- EMR_MODIFYWORLDTRANSFORM -->\n";
1283             PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR;
1284             switch (pEmr->iMode)
1285             {
1286                 case MWT_IDENTITY:
1287                     d->dc[d->level].worldTransform.eM11 = 1.0;
1288                     d->dc[d->level].worldTransform.eM12 = 0.0;
1289                     d->dc[d->level].worldTransform.eM21 = 0.0;
1290                     d->dc[d->level].worldTransform.eM22 = 1.0;
1291                     d->dc[d->level].worldTransform.eDx  = 0.0;
1292                     d->dc[d->level].worldTransform.eDy  = 0.0;
1293                     break;
1294                 case MWT_LEFTMULTIPLY:
1295                 {
1296 //                    d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
1298                     float a11 = pEmr->xform.eM11;
1299                     float a12 = pEmr->xform.eM12;
1300                     float a13 = 0.0;
1301                     float a21 = pEmr->xform.eM21;
1302                     float a22 = pEmr->xform.eM22;
1303                     float a23 = 0.0;
1304                     float a31 = pEmr->xform.eDx;
1305                     float a32 = pEmr->xform.eDy;
1306                     float a33 = 1.0;
1308                     float b11 = d->dc[d->level].worldTransform.eM11;
1309                     float b12 = d->dc[d->level].worldTransform.eM12;
1310                     //float b13 = 0.0;
1311                     float b21 = d->dc[d->level].worldTransform.eM21;
1312                     float b22 = d->dc[d->level].worldTransform.eM22;
1313                     //float b23 = 0.0;
1314                     float b31 = d->dc[d->level].worldTransform.eDx;
1315                     float b32 = d->dc[d->level].worldTransform.eDy;
1316                     //float b33 = 1.0;
1318                     float c11 = a11*b11 + a12*b21 + a13*b31;;
1319                     float c12 = a11*b12 + a12*b22 + a13*b32;;
1320                     //float c13 = a11*b13 + a12*b23 + a13*b33;;
1321                     float c21 = a21*b11 + a22*b21 + a23*b31;;
1322                     float c22 = a21*b12 + a22*b22 + a23*b32;;
1323                     //float c23 = a21*b13 + a22*b23 + a23*b33;;
1324                     float c31 = a31*b11 + a32*b21 + a33*b31;;
1325                     float c32 = a31*b12 + a32*b22 + a33*b32;;
1326                     //float c33 = a31*b13 + a32*b23 + a33*b33;;
1328                     d->dc[d->level].worldTransform.eM11 = c11;;
1329                     d->dc[d->level].worldTransform.eM12 = c12;;
1330                     d->dc[d->level].worldTransform.eM21 = c21;;
1331                     d->dc[d->level].worldTransform.eM22 = c22;;
1332                     d->dc[d->level].worldTransform.eDx = c31;
1333                     d->dc[d->level].worldTransform.eDy = c32;
1334                     
1335                     break;
1336                 }
1337                 case MWT_RIGHTMULTIPLY:
1338                 {
1339 //                    d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
1341                     float a11 = d->dc[d->level].worldTransform.eM11;
1342                     float a12 = d->dc[d->level].worldTransform.eM12;
1343                     float a13 = 0.0;
1344                     float a21 = d->dc[d->level].worldTransform.eM21;
1345                     float a22 = d->dc[d->level].worldTransform.eM22;
1346                     float a23 = 0.0;
1347                     float a31 = d->dc[d->level].worldTransform.eDx;
1348                     float a32 = d->dc[d->level].worldTransform.eDy;
1349                     float a33 = 1.0;
1351                     float b11 = pEmr->xform.eM11;
1352                     float b12 = pEmr->xform.eM12;
1353                     //float b13 = 0.0;
1354                     float b21 = pEmr->xform.eM21;
1355                     float b22 = pEmr->xform.eM22;
1356                     //float b23 = 0.0;
1357                     float b31 = pEmr->xform.eDx;
1358                     float b32 = pEmr->xform.eDy;
1359                     //float b33 = 1.0;
1361                     float c11 = a11*b11 + a12*b21 + a13*b31;;
1362                     float c12 = a11*b12 + a12*b22 + a13*b32;;
1363                     //float c13 = a11*b13 + a12*b23 + a13*b33;;
1364                     float c21 = a21*b11 + a22*b21 + a23*b31;;
1365                     float c22 = a21*b12 + a22*b22 + a23*b32;;
1366                     //float c23 = a21*b13 + a22*b23 + a23*b33;;
1367                     float c31 = a31*b11 + a32*b21 + a33*b31;;
1368                     float c32 = a31*b12 + a32*b22 + a33*b32;;
1369                     //float c33 = a31*b13 + a32*b23 + a33*b33;;
1371                     d->dc[d->level].worldTransform.eM11 = c11;;
1372                     d->dc[d->level].worldTransform.eM12 = c12;;
1373                     d->dc[d->level].worldTransform.eM21 = c21;;
1374                     d->dc[d->level].worldTransform.eM22 = c22;;
1375                     d->dc[d->level].worldTransform.eDx = c31;
1376                     d->dc[d->level].worldTransform.eDy = c32;
1378                     break;
1379                 }
1380 //                case MWT_SET:
1381                 default:
1382                     d->dc[d->level].worldTransform = pEmr->xform;
1383                     break;
1384             }
1385             break;
1386         }
1387         case EMR_SELECTOBJECT:
1388         {
1389             dbg_str << "<!-- EMR_SELECTOBJECT -->\n";
1391             PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
1392             unsigned int index = pEmr->ihObject;
1394             if (index >= ENHMETA_STOCK_OBJECT) {
1395                 index -= ENHMETA_STOCK_OBJECT;
1396                 switch (index) {
1397                     case NULL_BRUSH:
1398                         d->dc[d->level].fill_set = false;
1399                         break;
1400                     case BLACK_BRUSH:
1401                     case DKGRAY_BRUSH:
1402                     case GRAY_BRUSH:
1403                     case LTGRAY_BRUSH:
1404                     case WHITE_BRUSH:
1405                     {
1406                         float val = 0;
1407                         switch (index) {
1408                             case BLACK_BRUSH:
1409                                 val = 0.0 / 255.0;
1410                                 break;
1411                             case DKGRAY_BRUSH:
1412                                 val = 64.0 / 255.0;
1413                                 break;
1414                             case GRAY_BRUSH:
1415                                 val = 128.0 / 255.0;
1416                                 break;
1417                             case LTGRAY_BRUSH:
1418                                 val = 192.0 / 255.0;
1419                                 break;
1420                             case WHITE_BRUSH:
1421                                 val = 255.0 / 255.0;
1422                                 break;
1423                         }
1424                         d->dc[d->level].style.fill.value.color.set( val, val, val );
1426                         d->dc[d->level].fill_set = true;
1427                         break;
1428                     }
1429                     case NULL_PEN:
1430                         d->dc[d->level].stroke_set = false;
1431                         break;
1432                     case BLACK_PEN:
1433                     case WHITE_PEN:
1434                     {
1435                         float val = index == BLACK_PEN ? 0 : 1;
1436                         d->dc[d->level].style.stroke_dasharray_set = 0;
1437                         d->dc[d->level].style.stroke_width.value = 1.0;
1438                         d->dc[d->level].style.stroke.value.color.set( val, val, val );
1440                         d->dc[d->level].stroke_set = true;
1442                         break;
1443                     }
1444                 }
1445             } else {
1446                 if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
1447                     switch (d->emf_obj[index].type)
1448                     {
1449                         case EMR_CREATEPEN:
1450                             select_pen(d, index);
1451                             break;
1452                         case EMR_CREATEBRUSHINDIRECT:
1453                             select_brush(d, index);
1454                             break;
1455                         case EMR_EXTCREATEPEN:
1456                             select_extpen(d, index);
1457                             break;
1458                         case EMR_EXTCREATEFONTINDIRECTW:
1459                             select_font(d, index);
1460                             break;
1461                     }
1462                 }
1463             }
1464             break;
1465         }
1466         case EMR_CREATEPEN:
1467         {
1468             dbg_str << "<!-- EMR_CREATEPEN -->\n";
1470             PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
1471             int index = pEmr->ihPen;
1473             EMRCREATEPEN *pPen =
1474                 (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) );
1475             pPen->lopn = pEmr->lopn;
1476             insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
1478             break;
1479         }
1480         case EMR_CREATEBRUSHINDIRECT:
1481         {
1482             dbg_str << "<!-- EMR_CREATEBRUSHINDIRECT -->\n";
1484             PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
1485             int index = pEmr->ihBrush;
1487             EMRCREATEBRUSHINDIRECT *pBrush =
1488                 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
1489             pBrush->lb = pEmr->lb;
1490             insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
1492             break;
1493         }
1494         case EMR_DELETEOBJECT:
1495             dbg_str << "<!-- EMR_DELETEOBJECT -->\n";
1496             break;
1497         case EMR_ANGLEARC:
1498             dbg_str << "<!-- EMR_ANGLEARC -->\n";
1499             break;
1500         case EMR_ELLIPSE:
1501         {
1502             dbg_str << "<!-- EMR_ELLIPSE -->\n";
1504             PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR;
1505             RECTL rclBox = pEmr->rclBox;
1507             double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1508             double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1509             double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1510             double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1512             double cx = (l + r) / 2.0;
1513             double cy = (t + b) / 2.0;
1514             double rx = fabs(l - r) / 2.0;
1515             double ry = fabs(t - b) / 2.0;
1517             SVGOStringStream tmp_ellipse;
1518             tmp_ellipse << "cx=\"" << cx << "\" ";
1519             tmp_ellipse << "cy=\"" << cy << "\" ";
1520             tmp_ellipse << "rx=\"" << rx << "\" ";
1521             tmp_ellipse << "ry=\"" << ry << "\" ";
1523             assert_empty_path(d, "EMR_ELLIPSE");
1525             *(d->outsvg) += "    <ellipse ";
1526             output_style(d, lpEMFR->iType);
1527             *(d->outsvg) += "\n\t";
1528             *(d->outsvg) += tmp_ellipse.str().c_str();
1529             *(d->outsvg) += "/> \n";
1530             *(d->path) = "";
1531             break;
1532         }
1533         case EMR_RECTANGLE:
1534         {
1535             dbg_str << "<!-- EMR_RECTANGLE -->\n";
1537             PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR;
1538             RECTL rc = pEmr->rclBox;
1540             double l = pix_to_x_point( d, rc.left, rc.top );
1541             double t = pix_to_y_point( d, rc.left, rc.top );
1542             double r = pix_to_x_point( d, rc.right, rc.bottom );
1543             double b = pix_to_y_point( d, rc.right, rc.bottom );
1545             SVGOStringStream tmp_rectangle;
1546             tmp_rectangle << "d=\"";
1547             tmp_rectangle << "\n\tM " << l << " " << t << " ";
1548             tmp_rectangle << "\n\tL " << r << " " << t << " ";
1549             tmp_rectangle << "\n\tL " << r << " " << b << " ";
1550             tmp_rectangle << "\n\tL " << l << " " << b << " ";
1551             tmp_rectangle << "\n\tz";
1553             assert_empty_path(d, "EMR_RECTANGLE");
1555             *(d->outsvg) += "    <path ";
1556             output_style(d, lpEMFR->iType);
1557             *(d->outsvg) += "\n\t";
1558             *(d->outsvg) += tmp_rectangle.str().c_str();
1559             *(d->outsvg) += " \" /> \n";
1560             *(d->path) = "";
1561             break;
1562         }
1563         case EMR_ROUNDRECT:
1564             dbg_str << "<!-- EMR_ROUNDRECT -->\n";
1565             break;
1566         case EMR_ARC:
1567             dbg_str << "<!-- EMR_ARC -->\n";
1568             break;
1569         case EMR_CHORD:
1570             dbg_str << "<!-- EMR_CHORD -->\n";
1571             break;
1572         case EMR_PIE:
1573             dbg_str << "<!-- EMR_PIE -->\n";
1574             break;
1575         case EMR_SELECTPALETTE:
1576             dbg_str << "<!-- EMR_SELECTPALETTE -->\n";
1577             break;
1578         case EMR_CREATEPALETTE:
1579             dbg_str << "<!-- EMR_CREATEPALETTE -->\n";
1580             break;
1581         case EMR_SETPALETTEENTRIES:
1582             dbg_str << "<!-- EMR_SETPALETTEENTRIES -->\n";
1583             break;
1584         case EMR_RESIZEPALETTE:
1585             dbg_str << "<!-- EMR_RESIZEPALETTE -->\n";
1586             break;
1587         case EMR_REALIZEPALETTE:
1588             dbg_str << "<!-- EMR_REALIZEPALETTE -->\n";
1589             break;
1590         case EMR_EXTFLOODFILL:
1591             dbg_str << "<!-- EMR_EXTFLOODFILL -->\n";
1592             break;
1593         case EMR_LINETO:
1594         {
1595             dbg_str << "<!-- EMR_LINETO -->\n";
1597             PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
1599             if (d->path->empty()) {
1600                 d->pathless_stroke = true;
1601                 *(d->path) = "d=\"";
1602             }
1604             tmp_path <<
1605                 "\n\tL " <<
1606                 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1607                 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1608             break;
1609         }
1610         case EMR_ARCTO:
1611             dbg_str << "<!-- EMR_ARCTO -->\n";
1612             break;
1613         case EMR_POLYDRAW:
1614             dbg_str << "<!-- EMR_POLYDRAW -->\n";
1615             break;
1616         case EMR_SETARCDIRECTION:
1617             dbg_str << "<!-- EMR_SETARCDIRECTION -->\n";
1618             break;
1619         case EMR_SETMITERLIMIT:
1620         {
1621             dbg_str << "<!-- EMR_SETMITERLIMIT -->\n";
1623             PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
1625             float miterlimit = pEmr->eMiterLimit;
1626             miterlimit = miterlimit * 4.0 / 10.0;
1627             d->dc[d->level].style.stroke_miterlimit.value = pix_to_size_point( d, miterlimit );
1628             if (d->dc[d->level].style.stroke_miterlimit.value < 1)
1629                 d->dc[d->level].style.stroke_miterlimit.value = 4.0;
1630             break;
1631         }
1632         case EMR_BEGINPATH:
1633         {
1634             dbg_str << "<!-- EMR_BEGINPATH -->\n";
1636             tmp_path << "d=\"";
1637             *(d->path) = "";
1638             d->inpath = true;
1639             break;
1640         }
1641         case EMR_ENDPATH:
1642         {
1643             dbg_str << "<!-- EMR_ENDPATH -->\n";
1645             tmp_path << "\"";
1646             d->inpath = false;
1647             break;
1648         }
1649         case EMR_CLOSEFIGURE:
1650         {
1651             dbg_str << "<!-- EMR_CLOSEFIGURE -->\n";
1653             tmp_path << "\n\tz";
1654             break;
1655         }
1656         case EMR_FILLPATH:
1657         case EMR_STROKEANDFILLPATH:
1658         case EMR_STROKEPATH:
1659         {
1660             if (lpEMFR->iType == EMR_FILLPATH)
1661                 dbg_str << "<!-- EMR_FILLPATH -->\n";
1662             if (lpEMFR->iType == EMR_STROKEANDFILLPATH)
1663                 dbg_str << "<!-- EMR_STROKEANDFILLPATH -->\n";
1664             if (lpEMFR->iType == EMR_STROKEPATH)
1665                 dbg_str << "<!-- EMR_STROKEPATH -->\n";
1667             *(d->outsvg) += "    <path ";
1668             output_style(d, lpEMFR->iType);
1669             *(d->outsvg) += "\n\t";
1670             *(d->outsvg) += *(d->path);
1671             *(d->outsvg) += " /> \n";
1672             *(d->path) = "";
1673             break;
1674         }
1675         case EMR_FLATTENPATH:
1676             dbg_str << "<!-- EMR_FLATTENPATH -->\n";
1677             break;
1678         case EMR_WIDENPATH:
1679             dbg_str << "<!-- EMR_WIDENPATH -->\n";
1680             break;
1681         case EMR_SELECTCLIPPATH:
1682             dbg_str << "<!-- EMR_SELECTCLIPPATH -->\n";
1683             break;
1684         case EMR_ABORTPATH:
1685             dbg_str << "<!-- EMR_ABORTPATH -->\n";
1686             break;
1687         case EMR_GDICOMMENT:
1688         {
1689             dbg_str << "<!-- EMR_GDICOMMENT -->\n";
1690             
1691             PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR;
1693             CHAR *szTxt = (CHAR *) pEmr->Data;
1695             for (DWORD i = 0; i < pEmr->cbData; i++) {
1696                 if ( *szTxt) {
1697                     if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
1698                         tmp_str << *szTxt;
1699                     }
1700                     szTxt++;
1701                 }
1702             }
1704             if (0 && strlen(tmp_str.str().c_str())) {
1705                 tmp_outsvg << "    <!-- \"";
1706                 tmp_outsvg << tmp_str.str().c_str();
1707                 tmp_outsvg << "\" -->\n";
1708             }
1709             
1710             break;
1711         }
1712         case EMR_FILLRGN:
1713             dbg_str << "<!-- EMR_FILLRGN -->\n";
1714             break;
1715         case EMR_FRAMERGN:
1716             dbg_str << "<!-- EMR_FRAMERGN -->\n";
1717             break;
1718         case EMR_INVERTRGN:
1719             dbg_str << "<!-- EMR_INVERTRGN -->\n";
1720             break;
1721         case EMR_PAINTRGN:
1722             dbg_str << "<!-- EMR_PAINTRGN -->\n";
1723             break;
1724         case EMR_EXTSELECTCLIPRGN:
1725             dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n";
1726             break;
1727         case EMR_BITBLT:
1728             dbg_str << "<!-- EMR_BITBLT -->\n";
1729             break;
1730         case EMR_STRETCHBLT:
1731             dbg_str << "<!-- EMR_STRETCHBLT -->\n";
1732             break;
1733         case EMR_MASKBLT:
1734             dbg_str << "<!-- EMR_MASKBLT -->\n";
1735             break;
1736         case EMR_PLGBLT:
1737             dbg_str << "<!-- EMR_PLGBLT -->\n";
1738             break;
1739         case EMR_SETDIBITSTODEVICE:
1740             dbg_str << "<!-- EMR_SETDIBITSTODEVICE -->\n";
1741             break;
1742         case EMR_STRETCHDIBITS:
1743             dbg_str << "<!-- EMR_STRETCHDIBITS -->\n";
1744             break;
1745         case EMR_EXTCREATEFONTINDIRECTW:
1746         {
1747             dbg_str << "<!-- EMR_EXTCREATEFONTINDIRECTW -->\n";
1749             PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR;
1750             int index = pEmr->ihFont;
1752             EMREXTCREATEFONTINDIRECTW *pFont =
1753                 (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) );
1754             pFont->elfw = pEmr->elfw;
1755             insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont);
1756             break;
1757         }
1758         case EMR_EXTTEXTOUTA:
1759         {
1760             dbg_str << "<!-- EMR_EXTTEXTOUTA -->\n";
1761             break;
1762         }
1763         case EMR_EXTTEXTOUTW:
1764         {
1765             dbg_str << "<!-- EMR_EXTTEXTOUTW -->\n";
1767             PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR;
1769             double x1 = pEmr->emrtext.ptlReference.x;
1770             double y1 = pEmr->emrtext.ptlReference.y;
1771             
1772             if (d->dc[d->level].textAlign & TA_UPDATECP) {
1773                 x1 = d->dc[d->level].cur.x;
1774                 y1 = d->dc[d->level].cur.y;
1775             }
1777             if (!(d->dc[d->level].textAlign & TA_BOTTOM))
1778                 y1 += fabs(d->dc[d->level].style.font_size.computed);
1779             
1780             double x = pix_to_x_point(d, x1, y1);
1781             double y = pix_to_y_point(d, x1, y1);
1783             wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString);
1785             gchar *ansi_text =
1786                 (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL );
1788             if (ansi_text) {
1789                 gchar *p = ansi_text;
1790                 while (*p) {
1791                     if (*p < 32 || *p >= 127) {
1792                         g_free(ansi_text);
1793                         ansi_text = g_strdup("");
1794                         break;
1795                     }
1796                     p++;
1797                 }
1799                 SVGOStringStream ts;
1801                 gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
1803                 float text_rgb[3];
1804                 sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb );
1806                 if (!d->dc[d->level].textColorSet) {
1807                     d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]),
1808                                        SP_COLOR_F_TO_U(text_rgb[1]),
1809                                        SP_COLOR_F_TO_U(text_rgb[2]));
1810                 }
1812                 char tmp[128];
1813                 snprintf(tmp, 127,
1814                          "fill:#%02x%02x%02x;",
1815                          GetRValue(d->dc[d->level].textColor),
1816                          GetGValue(d->dc[d->level].textColor),
1817                          GetBValue(d->dc[d->level].textColor));
1819                 bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC);
1820                 //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
1821                 bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
1822                     (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);
1823                 int lcr = ((d->dc[d->level].textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0;
1825                 assert_empty_path(d, "EMR_EXTTEXTOUTW");
1827                 ts << "    <text\n";
1828                 ts << "        id=\"" << (d->id++) << "\"\n";
1829                 ts << "        xml:space=\"preserve\"\n";
1830                 ts << "        x=\"" << x << "\"\n";
1831                 ts << "        y=\"" << y << "\"\n";
1832                 if (d->dc[d->level].style.text_transform.value) {
1833                     ts << "        transform=\""
1834                        << "rotate(-" << d->dc[d->level].style.text_transform.value
1835                        << " " << x << " " << y << ")"
1836                        << "\"\n";
1837                 }
1838                 ts << "        style=\""
1839                    << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;"
1840                    << tmp
1841                    << "font-style:" << (i ? "italic" : "normal") << ";"
1842                    << "font-weight:" << (b ? "bold" : "normal") << ";"
1843                    << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";"
1844                    << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";"
1845                    << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";"
1846                    << "\"\n";
1847                 ts << "    >";
1848                 ts << escaped_text;
1849                 ts << "</text>\n";
1850                 
1851                 *(d->outsvg) += ts.str().c_str();
1852                 
1853                 g_free(escaped_text);
1854                 g_free(ansi_text);
1855             }
1856             
1857             break;
1858         }
1859         case EMR_POLYBEZIER16:
1860         {
1861             dbg_str << "<!-- EMR_POLYBEZIER16 -->\n";
1863             PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
1864             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1865             DWORD i,j;
1867             if (pEmr->cpts<4)
1868                 break;
1870             if (!d->inpath) {
1871                 assert_empty_path(d, "EMR_POLYBEZIER16");
1873                 *(d->outsvg) += "    <path ";
1874                 output_style(d, EMR_STROKEPATH);
1875                 *(d->outsvg) += "\n\td=\"";
1876             }
1878             tmp_str <<
1879                 "\n\tM " <<
1880                 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1881                 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1883             for (i=1; i<pEmr->cpts; ) {
1884                 tmp_str << "\n\tC ";
1885                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1886                     tmp_str <<
1887                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1888                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1889                 }
1890             }
1892             if (d->inpath) {
1893                 tmp_path << tmp_str.str().c_str();
1894             }
1895             else {
1896                 *(d->outsvg) += tmp_str.str().c_str();
1897                 *(d->outsvg) += " \" /> \n";
1898             }
1900             break;
1901         }
1902         case EMR_POLYGON16:
1903         {
1904             dbg_str << "<!-- EMR_POLYGON16 -->\n";
1906             PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
1907             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1908             SVGOStringStream tmp_poly;
1909             unsigned int i;
1910             unsigned int first = 0;
1912             assert_empty_path(d, "EMR_POLYGON16");
1914             *(d->outsvg) += "    <path ";
1915             output_style(d, EMR_STROKEANDFILLPATH);
1916             *(d->outsvg) += "\n\td=\"";
1917             
1918             // skip the first point?
1919             tmp_poly << "\n\tM " <<
1920                 pix_to_x_point( d, apts[first].x, apts[first].y ) << " " <<
1921                 pix_to_y_point( d, apts[first].x, apts[first].y ) << " ";
1923             for (i=first+1; i<pEmr->cpts; i++) {
1924                 tmp_poly << "\n\tL " <<
1925                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1926                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1927             }
1929             *(d->outsvg) += tmp_poly.str().c_str();
1930             *(d->outsvg) += " z \" /> \n";
1932             break;
1933         }
1934         case EMR_POLYLINE16:
1935         {
1936             dbg_str << "<!-- EMR_POLYLINE16 -->\n";
1938             EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
1939             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1940             DWORD i;
1942             if (pEmr->cpts<2)
1943                 break;
1945             if (!d->inpath) {
1946                 assert_empty_path(d, "EMR_POLYLINE16");
1948                 *(d->outsvg) += "    <path ";
1949                 output_style(d, EMR_STROKEPATH);
1950                 *(d->outsvg) += "\n\td=\"";
1951             }
1953             tmp_str <<
1954                 "\n\tM " <<
1955                 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1956                 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1958             for (i=1; i<pEmr->cpts; i++) {
1959                 tmp_str <<
1960                     "\n\tL " <<
1961                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1962                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1963             }
1965             if (d->inpath) {
1966                 tmp_path << tmp_str.str().c_str();
1967             }
1968             else {
1969                 *(d->outsvg) += tmp_str.str().c_str();
1970                 *(d->outsvg) += " \" /> \n";
1971             }
1973             break;
1974         }
1975         case EMR_POLYBEZIERTO16:
1976         {
1977             dbg_str << "<!-- EMR_POLYBEZIERTO16 -->\n";
1979             PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
1980             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1981             DWORD i,j;
1983             if (d->path->empty()) {
1984                 d->pathless_stroke = true;
1985                 *(d->path) = "d=\"";
1986             }
1988             for (i=0; i<pEmr->cpts;) {
1989                 tmp_path << "\n\tC ";
1990                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1991                     tmp_path <<
1992                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1993                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1994                 }
1995             }
1997             break;
1998         }
1999         case EMR_POLYLINETO16:
2000         {
2001             dbg_str << "<!-- EMR_POLYLINETO16 -->\n";
2003             PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
2004             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
2005             DWORD i;
2007             if (d->path->empty()) {
2008                 d->pathless_stroke = true;
2009                 *(d->path) = "d=\"";
2010             }
2012             for (i=0; i<pEmr->cpts;i++) {
2013                 tmp_path <<
2014                     "\n\tL " <<
2015                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2016                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2017             }
2019             break;
2020         }
2021         case EMR_POLYPOLYLINE16:
2022         case EMR_POLYPOLYGON16:
2023         {
2024             if (lpEMFR->iType == EMR_POLYPOLYLINE16)
2025                 dbg_str << "<!-- EMR_POLYPOLYLINE16 -->\n";
2026             if (lpEMFR->iType == EMR_POLYPOLYGON16)
2027                 dbg_str << "<!-- EMR_POLYPOLYGON16 -->\n";
2029             PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
2030             unsigned int n, i, j;
2032             if (!d->inpath) {
2033                 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16");
2035                 *(d->outsvg) += "    <path ";
2036                 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
2037                 *(d->outsvg) += "\n\td=\"";
2038             }
2040             POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys];
2042             i = 0;
2043             for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
2044                 SVGOStringStream poly_path;
2046                 poly_path << "\n\tM " <<
2047                     pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2048                     pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2049                 i++;
2051                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
2052                     poly_path << "\n\tL " <<
2053                         pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
2054                         pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
2055                     i++;
2056                 }
2058                 tmp_str << poly_path.str().c_str();
2059                 if (lpEMFR->iType == EMR_POLYPOLYGON16)
2060                     tmp_str << " z";
2061                 tmp_str << " \n";
2062             }
2064             if (d->inpath) {
2065                 tmp_path << tmp_str.str().c_str();
2066             }
2067             else {
2068                 *(d->outsvg) += tmp_str.str().c_str();
2069                 *(d->outsvg) += " \" /> \n";
2070             }
2072             break;
2073         }
2074         case EMR_POLYDRAW16:
2075             dbg_str << "<!-- EMR_POLYDRAW16 -->\n";
2076             break;
2077         case EMR_CREATEMONOBRUSH:
2078             dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n";
2079             break;
2080         case EMR_CREATEDIBPATTERNBRUSHPT:
2081             dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n";
2082             break;
2083         case EMR_EXTCREATEPEN:
2084         {
2085             dbg_str << "<!-- EMR_EXTCREATEPEN -->\n";
2087             PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
2088             int index = pEmr->ihPen;
2090             EMREXTCREATEPEN *pPen =
2091                 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
2092                                             sizeof(DWORD) * pEmr->elp.elpNumEntries );
2093             pPen->ihPen = pEmr->ihPen;
2094             pPen->offBmi = pEmr->offBmi;
2095             pPen->cbBmi = pEmr->cbBmi;
2096             pPen->offBits = pEmr->offBits;
2097             pPen->cbBits = pEmr->cbBits;
2098             pPen->elp = pEmr->elp;
2099             for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
2100                 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
2101             }
2102             insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
2104             break;
2105         }
2106         case EMR_POLYTEXTOUTA:
2107             dbg_str << "<!-- EMR_POLYTEXTOUTA -->\n";
2108             break;
2109         case EMR_POLYTEXTOUTW:
2110             dbg_str << "<!-- EMR_POLYTEXTOUTW -->\n";
2111             break;
2112         case EMR_SETICMMODE:
2113             dbg_str << "<!-- EMR_SETICMMODE -->\n";
2114             break;
2115         case EMR_CREATECOLORSPACE:
2116             dbg_str << "<!-- EMR_CREATECOLORSPACE -->\n";
2117             break;
2118         case EMR_SETCOLORSPACE:
2119             dbg_str << "<!-- EMR_SETCOLORSPACE -->\n";
2120             break;
2121         case EMR_DELETECOLORSPACE:
2122             dbg_str << "<!-- EMR_DELETECOLORSPACE -->\n";
2123             break;
2124         case EMR_GLSRECORD:
2125             dbg_str << "<!-- EMR_GLSRECORD -->\n";
2126             break;
2127         case EMR_GLSBOUNDEDRECORD:
2128             dbg_str << "<!-- EMR_GLSBOUNDEDRECORD -->\n";
2129             break;
2130         case EMR_PIXELFORMAT:
2131             dbg_str << "<!-- EMR_PIXELFORMAT -->\n";
2132             break;
2133         default:
2134             dbg_str << "<!-- EMR_??? -->\n";
2135             break;
2136     }
2137     
2138 //    *(d->outsvg) += dbg_str.str().c_str();
2139     *(d->outsvg) += tmp_outsvg.str().c_str();
2140     *(d->path) += tmp_path.str().c_str();
2142     return 1;
2145 static int CALLBACK
2146 myMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, METARECORD * /*lpMFR*/, int /*nObj*/, LPARAM /*lpData*/)
2148     g_warning("Unable to import Windows Meta File.\n");
2149     return 0;
2152 // Aldus Placeable Header ===================================================
2153 // Since we are a 32bit app, we have to be sure this structure compiles to
2154 // be identical to a 16 bit app's version. To do this, we use the #pragma
2155 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
2156 // for the bbox rectangle.
2157 #pragma pack( push )
2158 #pragma pack( 2 )
2159 typedef struct
2161     DWORD       dwKey;
2162     WORD        hmf;
2163     SMALL_RECT  bbox;
2164     WORD        wInch;
2165     DWORD       dwReserved;
2166     WORD        wCheckSum;
2167 } APMHEADER, *PAPMHEADER;
2168 #pragma pack( pop )
2171 SPDocument *
2172 EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
2174     EMF_CALLBACK_DATA d;
2176     memset(&d, 0, sizeof(d));
2178     d.dc[0].worldTransform.eM11 = 1.0;
2179     d.dc[0].worldTransform.eM12 = 0.0;
2180     d.dc[0].worldTransform.eM21 = 0.0;
2181     d.dc[0].worldTransform.eM22 = 1.0;
2182     d.dc[0].worldTransform.eDx  = 0.0;
2183     d.dc[0].worldTransform.eDy  = 0.0;
2184     
2185     gsize bytesRead = 0;
2186     gsize bytesWritten = 0;
2187     GError* error = NULL;
2188     gchar *local_fn =
2189         g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );
2191     if (local_fn == NULL) {
2192         return NULL;
2193     }
2195     d.outsvg = new Glib::ustring("");
2196     d.path = new Glib::ustring("");
2198     CHAR *ansi_uri = (CHAR *) local_fn;
2199     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
2200     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
2202     DWORD filesize = 0;
2203     HANDLE fp = NULL;
2205     HMETAFILE hmf;
2206     HENHMETAFILE hemf;
2208     if (PrintWin32::is_os_wide()) {
2209         fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2210     }
2211     else {
2212         fp = CreateFileA(ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2213     }
2215     if ( fp != INVALID_HANDLE_VALUE ) {
2216         filesize = GetFileSize(fp, NULL);
2217         CloseHandle(fp);
2218     }
2220     // Try open as Enhanced Metafile
2221     if (PrintWin32::is_os_wide())
2222         hemf = GetEnhMetaFileW(unicode_uri);
2223     else
2224         hemf = GetEnhMetaFileA(ansi_uri);
2226     if (!hemf) {
2227         // Try open as Windows Metafile
2228         if (PrintWin32::is_os_wide())
2229             hmf = GetMetaFileW(unicode_uri);
2230         else
2231             hmf = GetMetaFileA(ansi_uri);
2233         METAFILEPICT mp;
2234         HDC hDC;
2236         if (!hmf) {
2237             if (PrintWin32::is_os_wide()) {
2238                 WCHAR szTemp[MAX_PATH];
2240                 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
2241                 if (dw) {
2242                     hmf = GetMetaFileW( szTemp );
2243                 }
2244             } else {
2245                 CHAR szTemp[MAX_PATH];
2247                 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );
2248                 if (dw) {
2249                     hmf = GetMetaFileA( szTemp );
2250                 }
2251             }
2252         }
2254         if (hmf) {
2255             DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
2257             if (!nSize)
2258                 nSize = filesize;
2259             
2260             if (nSize) {
2261                 BYTE *lpvData = new BYTE[nSize];
2262                 if (lpvData) {
2263                     DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
2264                     if (dw) {
2265                         // Fill out a METAFILEPICT structure
2266                         mp.mm = MM_ANISOTROPIC;
2267                         mp.xExt = 1000;
2268                         mp.yExt = 1000;
2269                         mp.hMF = NULL;
2270                         // Get a reference DC
2271                         hDC = GetDC( NULL );
2272                         // Make an enhanced metafile from the windows metafile
2273                         hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
2274                         // Clean up
2275                         ReleaseDC( NULL, hDC );
2276                         DeleteMetaFile( hmf );
2277                         hmf = NULL;
2278                     }
2279                     else {
2280                         // EnumMetaFile
2281                     }
2282                     delete[] lpvData;
2283                 }
2284                 else {
2285                     DeleteMetaFile( hmf );
2286                     hmf = NULL;
2287                 }
2288             }
2289             else {
2290                 DeleteMetaFile( hmf );
2291                 hmf = NULL;
2292             }
2293         }
2294         else {
2295             // Try open as Aldus Placeable Metafile
2296             HANDLE hFile;
2297             if (PrintWin32::is_os_wide())
2298                 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2299             else
2300                 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2302             if (hFile != INVALID_HANDLE_VALUE) {
2303                 DWORD nSize = GetFileSize( hFile, NULL );
2304                 if (nSize) {
2305                     BYTE *lpvData = new BYTE[nSize];
2306                     if (lpvData) {
2307                         DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
2308                         if (dw) {
2309                             if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
2310                                 // Fill out a METAFILEPICT structure
2311                                 mp.mm = MM_ANISOTROPIC;
2312                                 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
2313                                 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2314                                 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
2315                                 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2316                                 mp.hMF = NULL;
2317                                 // Get a reference DC
2318                                 hDC = GetDC( NULL );
2319                                 // Create an enhanced metafile from the bits
2320                                 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
2321                                 // Clean up
2322                                 ReleaseDC( NULL, hDC );
2323                             }
2324                         }
2325                         delete[] lpvData;
2326                     }
2327                 }
2328                 CloseHandle( hFile );
2329             }
2330         }
2331     }
2333     if ((!hemf && !hmf) || !d.outsvg || !d.path) {
2334         if (d.outsvg)
2335             delete d.outsvg;
2336         if (d.path)
2337             delete d.path;
2338         if (local_fn)
2339             g_free(local_fn);
2340         if (unicode_fn)
2341             g_free(unicode_fn);
2342         if (hemf)
2343             DeleteEnhMetaFile(hemf);
2344         if (hmf)
2345             DeleteMetaFile(hmf);
2346         return NULL;
2347     }
2349     d.pDesc = NULL;
2351     if (hemf) {
2352         DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL );
2353         if ( dwNeeded > 0 ) {
2354             d.pDesc = (CHAR *) malloc( dwNeeded + 1 );
2355             if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 )
2356                 lstrcpy( d.pDesc, "" );
2357             if ( lstrlen( d.pDesc ) > 1 )
2358                 d.pDesc[lstrlen(d.pDesc)] = '#';
2359         }
2361         EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);
2362         DeleteEnhMetaFile(hemf);
2363     }
2364     else {
2365         EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d);
2366         DeleteMetaFile(hmf);
2367     }
2368     
2369     if (d.pDesc)
2370         free( d.pDesc );
2372 //    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
2374     SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);
2376     delete d.outsvg;
2377     delete d.path;
2379     if (d.emf_obj) {
2380         int i;
2381         for (i=0; i<d.n_obj; i++)
2382             delete_object(&d, i);
2383         delete[] d.emf_obj;
2384     }
2385     
2386     if (d.dc[0].style.stroke_dash.dash)
2387         delete[] d.dc[0].style.stroke_dash.dash;
2389     if  (local_fn)
2390         g_free(local_fn);
2391     if  (unicode_fn)
2392         g_free(unicode_fn);
2394     return doc;
2398 void
2399 EmfWin32::init (void)
2401     Inkscape::Extension::Extension * ext;
2403     /* EMF in */
2404     ext = Inkscape::Extension::build_from_mem(
2405         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2406             "<name>" N_("EMF Input") "</name>\n"
2407             "<id>org.inkscape.input.emf.win32</id>\n"
2408             "<input>\n"
2409                 "<extension>.emf</extension>\n"
2410                 "<mimetype>image/x-emf</mimetype>\n"
2411                 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
2412                 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
2413                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2414             "</input>\n"
2415         "</inkscape-extension>", new EmfWin32());
2417     /* WMF in */
2418     ext = Inkscape::Extension::build_from_mem(
2419         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2420             "<name>" N_("WMF Input") "</name>\n"
2421             "<id>org.inkscape.input.wmf.win32</id>\n"
2422             "<input>\n"
2423                 "<extension>.wmf</extension>\n"
2424                 "<mimetype>image/x-wmf</mimetype>\n"
2425                 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
2426                 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
2427                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2428             "</input>\n"
2429         "</inkscape-extension>", new EmfWin32());
2431     /* EMF out */
2432     ext = Inkscape::Extension::build_from_mem(
2433         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2434             "<name>" N_("EMF Output") "</name>\n"
2435             "<id>org.inkscape.output.emf.win32</id>\n"
2436             "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
2437             "<output>\n"
2438                 "<extension>.emf</extension>\n"
2439                 "<mimetype>image/x-emf</mimetype>\n"
2440                 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
2441                 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
2442             "</output>\n"
2443         "</inkscape-extension>", new EmfWin32());
2445     return;
2449 } } }  /* namespace Inkscape, Extension, Implementation */
2452 #endif /* WIN32 */
2455 /*
2456   Local Variables:
2457   mode:cpp
2458   c-file-style:"stroustrup"
2459   c-file-offsets:((innamespace . 0)(inline-open . 0))
2460   indent-tabs-mode:nil
2461   fill-column:99
2462   End:
2463 */
2464 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :