Code

69277440fc5331580f71c85d87f57a35ab29a566
[inkscape.git] / src / extension / internal / emf-win32-print.cpp
1 /** \file
2  * Enhanced Metafile Printing.
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 <string.h>
31 #include <signal.h>
32 #include <errno.h>
34 #include "libnr/n-art-bpath.h"
35 #include "libnr/nr-point-matrix-ops.h"
36 #include "libnr/nr-rect.h"
37 #include "libnr/nr-matrix.h"
38 #include "libnr/nr-matrix-ops.h"
39 #include "libnr/nr-matrix-scale-ops.h"
40 #include "libnr/nr-matrix-translate-ops.h"
41 #include "libnr/nr-scale-translate-ops.h"
42 #include "libnr/nr-translate-scale-ops.h"
43 #include "libnr/nr-matrix-fns.h"
44 #include "libnr/nr-path.h"
45 #include "libnr/nr-pixblock.h"
46 #include <libnr/n-art-bpath-2geom.h>
47 #include "display/canvas-bpath.h"
48 #include "sp-item.h"
50 #include "glib.h"
51 #include "gtk/gtkdialog.h"
52 #include "gtk/gtkbox.h"
53 #include "gtk/gtkstock.h"
55 #include "glibmm/i18n.h"
56 #include "enums.h"
57 #include "document.h"
58 #include "style.h"
59 #include "sp-paint-server.h"
60 #include "inkscape_version.h"
62 #include "libnrtype/FontFactory.h"
63 #include "libnrtype/font-instance.h"
64 #include "libnrtype/font-style-to-pos.h"
66 #include "win32.h"
67 #include "emf-win32-print.h"
69 #include "unit-constants.h"
71 #include "extension/extension.h"
72 #include "extension/system.h"
73 #include "extension/print.h"
75 #include "io/sys.h"
77 #include "macros.h"
79 #define WIN32_LEAN_AND_MEAN
80 #include <windows.h>
82 namespace Inkscape {
83 namespace Extension {
84 namespace Internal {
86 static float dwDPI = 2540;
89 PrintEmfWin32::PrintEmfWin32 (void):
90     hdc(NULL),
91     hbrush(NULL),
92     hbrushOld(NULL),
93     hpen(NULL),
94     fill_path(NULL),
95     stroke_and_fill(false),
96     fill_only(false),
97     simple_shape(false)
98 {
99 }
102 PrintEmfWin32::~PrintEmfWin32 (void)
104     if (hdc) {
105         HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
106         if ( metafile ) {
107             DeleteEnhMetaFile( metafile );
108         }
109         DeleteDC( hdc );
110     }
112     /* restore default signal handling for SIGPIPE */
113 #if !defined(_WIN32) && !defined(__WIN32__)
114     (void) signal(SIGPIPE, SIG_DFL);
115 #endif
116     return;
120 unsigned int
121 PrintEmfWin32::setup (Inkscape::Extension::Print *mod)
123     return TRUE;
127 unsigned int
128 PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
130     gchar const *utf8_fn = mod->get_param_string("destination");
132     gsize bytesRead = 0;
133     gsize bytesWritten = 0;
134     GError* error = NULL;
135     gchar *local_fn =
136         g_filename_from_utf8( utf8_fn, -1,  &bytesRead,  &bytesWritten, &error );
138     if (local_fn == NULL) {
139         return 1;
140     }
142     CHAR *ansi_uri = (CHAR *) local_fn;
143     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
144     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
146     // width and height in px
147     _width = sp_document_width(doc);
148     _height = sp_document_height(doc);
150     NRRect d;
151     bool pageBoundingBox;
152     pageBoundingBox = mod->get_param_bool("pageBoundingBox");
153     if (pageBoundingBox) {
154         d.x0 = d.y0 = 0;
155         d.x1 = _width;
156         d.y1 = _height;
157     } else {
158         SPItem* doc_item = SP_ITEM(sp_document_root(doc));
159         sp_item_invoke_bbox(doc_item, &d, from_2geom(sp_item_i2r_affine(doc_item)), TRUE);
160     }
162     d.x0 *= IN_PER_PX;
163     d.y0 *= IN_PER_PX;
164     d.x1 *= IN_PER_PX;
165     d.y1 *= IN_PER_PX;
167     float dwInchesX = (d.x1 - d.x0);
168     float dwInchesY = (d.y1 - d.y0);
170     // dwInchesX x dwInchesY in .01mm units
171     SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );
173     // Get a Reference DC
174     HDC hScreenDC = GetDC( NULL );
176     // Get the physical characteristics of the reference DC
177     int PixelsX = GetDeviceCaps( hScreenDC, HORZRES );
178     int PixelsY = GetDeviceCaps( hScreenDC, VERTRES );
179     int MMX = GetDeviceCaps( hScreenDC, HORZSIZE );
180     int MMY = GetDeviceCaps( hScreenDC, VERTSIZE );
182     CHAR buff[1024];
183     ZeroMemory(buff, sizeof(buff));
184     snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", INKSCAPE_VERSION, __DATE__);
185     INT len = strlen(buff);
186     CHAR *p1 = strrchr(ansi_uri, '\\');
187     CHAR *p2 = strrchr(ansi_uri, '/');
188     CHAR *p = MAX(p1, p2);
189     if (p)
190         p++;
191     else
192         p = ansi_uri;
193     snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p);
194     
195     // Create the Metafile
196     if (PrintWin32::is_os_wide()) {
197         WCHAR wbuff[1024];
198         ZeroMemory(wbuff, sizeof(wbuff));
199         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0]));
200         hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff );
201     }
202     else {
203         hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, buff );
204     }
206     // Release the reference DC
207     ReleaseDC( NULL, hScreenDC );
209     // Did we get a good metafile?
210     if (hdc == NULL)
211     {
212         g_free(local_fn);
213         g_free(unicode_fn);
214         return 1;
215     }
217     // Anisotropic mapping mode
218     SetMapMode( hdc, MM_ANISOTROPIC );
220     // Set the Windows extent
221     int windowextX = (int) ceil(dwInchesX*dwDPI);
222     int windowextY = (int) ceil(dwInchesY*dwDPI);
223     SetWindowExtEx( hdc, windowextX, windowextY, NULL );
225     // Set the viewport extent to reflect
226     // dwInchesX" x dwInchesY" in device units
227     int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX);
228     int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY);
229     SetViewportExtEx( hdc, viewportextX, viewportextY, NULL );
231     if (1) {
232         snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
233         GdiComment(hdc, strlen(buff), (BYTE*) buff);
235         snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
236         GdiComment(hdc, strlen(buff), (BYTE*) buff);
237     }
239     SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
241     g_free(local_fn);
242     g_free(unicode_fn);
244     m_tr_stack.push( NR::scale(1, -1) * NR::translate(0, sp_document_height(doc)));
246     return 0;
250 unsigned int
251 PrintEmfWin32::finish (Inkscape::Extension::Print *mod)
253     if (!hdc) return 0;
255     flush_fill(); // flush any pending fills
257     HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
258     if ( metafile ) {
259         DeleteEnhMetaFile( metafile );
260     }
261     DeleteDC( hdc );
263     hdc = NULL;
265     return 0;
269 unsigned int
270 PrintEmfWin32::comment (Inkscape::Extension::Print * module,
271                                 const char *comment)
273     if (!hdc) return 0;
275     flush_fill(); // flush any pending fills
277     return 0;
281 int
282 PrintEmfWin32::create_brush(SPStyle const *style)
284     float rgb[3];
286     if (style) {
287         float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
288         if (opacity <= 0.0)
289             return 1;
291         sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
292         hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
293         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
295         SetPolyFillMode( hdc,
296                          style->fill_rule.computed == 0 ? WINDING :
297                          style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
298     } else { // if (!style)
299         hbrush = CreateSolidBrush( RGB(255, 255, 255) );
300         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
301         SetPolyFillMode( hdc, ALTERNATE );
302     }
304     return 0;
308 void
309 PrintEmfWin32::destroy_brush()
311     SelectObject( hdc, hbrushOld );
312     if (hbrush)
313         DeleteObject( hbrush );
314     hbrush = NULL;
315     hbrushOld = NULL;
319 void
320 PrintEmfWin32::create_pen(SPStyle const *style, const NR::Matrix *transform)
322     if (style) {
323         float rgb[3];
325         sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
327         LOGBRUSH lb = {0};
328         lb.lbStyle = BS_SOLID;
329         lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
331         int linestyle = PS_SOLID;
332         int linecap = 0;
333         int linejoin = 0;
334         DWORD n_dash = 0;
335         DWORD *dash = NULL;
336         float oldmiterlimit;
338         using NR::X;
339         using NR::Y;
341         NR::Matrix tf = *transform;
343         NR::Point zero(0, 0);
344         NR::Point one(1, 1);
345         NR::Point p0(zero * tf);
346         NR::Point p1(one * tf);
347         NR::Point p(p1 - p0);
349         double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
351         DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
353         if (style->stroke_linecap.computed == 0) {
354             linecap = PS_ENDCAP_FLAT;
355         }
356         else if (style->stroke_linecap.computed == 1) {
357             linecap = PS_ENDCAP_ROUND;
358         }
359         else if (style->stroke_linecap.computed == 2) {
360             linecap = PS_ENDCAP_SQUARE;
361         }
363         if (style->stroke_linejoin.computed == 0) {
364             linejoin = PS_JOIN_MITER;
365         }
366         else if (style->stroke_linejoin.computed == 1) {
367             linejoin = PS_JOIN_ROUND;
368         }
369         else if (style->stroke_linejoin.computed == 2) {
370             linejoin = PS_JOIN_BEVEL;
371         }
373         if (style->stroke_dash.n_dash   &&
374             style->stroke_dash.dash       )
375         {
376             int i = 0;
377             while (linestyle != PS_USERSTYLE &&
378                    (i < style->stroke_dash.n_dash)) {
379                 if (style->stroke_dash.dash[i] > 0.00000001)
380                     linestyle = PS_USERSTYLE;
381                 i++;
382             }
384             if (linestyle == PS_USERSTYLE) {
385                 n_dash = style->stroke_dash.n_dash;
386                 dash = new DWORD[n_dash];
387                 for (i = 0; i < style->stroke_dash.n_dash; i++) {
388                     dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
389                 }
390             }
391         }
393         hpen = ExtCreatePen(
394             PS_GEOMETRIC | linestyle | linecap | linejoin,
395             linewidth,
396             &lb,
397             n_dash,
398             dash );
400         if ( !hpen && linestyle == PS_USERSTYLE ) {
401             hpen = ExtCreatePen(
402                 PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
403                 linewidth,
404                 &lb,
405                 0,
406                 NULL );
407         }
409         if ( !hpen ) {
410             hpen = CreatePen(
411                 PS_SOLID,
412                 linewidth,
413                 lb.lbColor );
414         }
416         hpenOld = (HPEN) SelectObject( hdc, hpen );
418         if (linejoin == PS_JOIN_MITER) {
419             float miterlimit = style->stroke_miterlimit.value;
420             if (miterlimit < 1)
421                 miterlimit = 4.0;
422             SetMiterLimit(
423                 hdc,
424                 miterlimit * IN_PER_PX * dwDPI,
425                 &oldmiterlimit );
426         }
428         if (n_dash) {
429             delete[] dash;
430         }
431     }
432     else { // if (!style)
433         hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
434         hpenOld = (HPEN) SelectObject( hdc, hpen );
435     }
439 void
440 PrintEmfWin32::destroy_pen()
442     SelectObject( hdc, hpenOld );
443     if (hpen)
444         DeleteObject( hpen );
445     hpen = NULL;
449 void
450 PrintEmfWin32::flush_fill()
452     if (fill_path) {
453         stroke_and_fill = false;
454         fill_only = true;
455         print_bpath(fill_path, &fill_transform, &fill_pbox);
456         fill_only = false;
457         if (!simple_shape)
458             FillPath( hdc );
459         destroy_brush();
460         delete[] fill_path;
461         fill_path = NULL;
462     }
466 NArtBpath *
467 PrintEmfWin32::copy_bpath(const NArtBpath *bp)
469     NArtBpath *tmp = (NArtBpath *) bp;
470     int num = 1;
471     
472     while (tmp->code != NR_END) {
473         num++;
474         tmp += 1;
475     }
477     tmp = new NArtBpath[num];
478     while (num--) {
479         tmp[num] = bp[num];
480     }
482     return tmp;
486 int
487 PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2)
489     if (!bp1 || !bp2) {
490         return 1;
491     }
492     
493     while (bp1->code != NR_END && bp2->code != NR_END) {
494         if (bp1->code != bp2->code) {
495             return 1;
496         }
498         if ( fabs(bp1->x1 - bp2->x1) > 0.00000001 ||
499              fabs(bp1->y1 - bp2->y1) > 0.00000001 ||
500              fabs(bp1->x2 - bp2->x2) > 0.00000001 ||
501              fabs(bp1->y2 - bp2->y2) > 0.00000001 ||
502              fabs(bp1->x3 - bp2->x3) > 0.00000001 ||
503              fabs(bp1->y3 - bp2->y3) > 0.00000001 )
504         {
505             return 1;
506         }
507         
508         bp1 += 1;
509         bp2 += 1;
510     }
511     
512     return bp1->code != NR_END || bp2->code != NR_END;
515 unsigned int
516 PrintEmfWin32::bind(Inkscape::Extension::Print *mod, NR::Matrix const *transform, float opacity)
518     NR::Matrix tr = *transform;
519     
520     if (m_tr_stack.size()) {
521         NR::Matrix tr_top = m_tr_stack.top();
522         m_tr_stack.push(tr * tr_top);
523     } else {
524         m_tr_stack.push(tr);
525     }
527     return 1;
530 unsigned int
531 PrintEmfWin32::release(Inkscape::Extension::Print *mod)
533     m_tr_stack.pop();
534     return 1;
537 unsigned int
538 PrintEmfWin32::fill(Inkscape::Extension::Print *mod,
539                Geom::PathVector const &pathv, NR::Matrix const *transform, SPStyle const *style,
540                NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
542     if (!hdc) return 0;
544     NR::Matrix tf = m_tr_stack.top();
546     flush_fill(); // flush any pending fills
548     if (style->fill.isColor()) {
549         if (create_brush(style))
550             return 0;
551     } else {
552         // create_brush(NULL);
553         return 0;
554     }
556     NArtBpath * bpath = BPath_from_2GeomPath(pathv);
557     fill_path = copy_bpath( bpath );
558     g_free(bpath);
559     fill_transform = tf;
560     fill_pbox = *pbox;
562     // postpone fill in case of stroke-and-fill
564     return 0;
568 unsigned int
569 PrintEmfWin32::stroke (Inkscape::Extension::Print *mod,
570                   Geom::PathVector const &pathv, const NR::Matrix *transform, const SPStyle *style,
571                   const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)
573     if (!hdc) return 0;
575     NR::Matrix tf = m_tr_stack.top();
577     NArtBpath * bpath = BPath_from_2GeomPath(pathv);
579     stroke_and_fill = ( cmp_bpath( bpath, fill_path ) == 0 );
581     if (!stroke_and_fill) {
582         flush_fill(); // flush any pending fills
583     }
585     if (style->stroke.isColor()) {
586         create_pen(style, &tf);
587     } else {
588         // create_pen(NULL, &tf);
589         return 0;
590     }
592     print_bpath(bpath, &tf, pbox);
594     if (stroke_and_fill) {
595         if (!simple_shape)
596             StrokeAndFillPath( hdc );
597         destroy_brush();
598         delete[] fill_path;
599         fill_path = NULL;
600     } else {
601         if (!simple_shape)
602             StrokePath( hdc );
603     }
605     g_free(bpath);
606     destroy_pen();
608     return 0;
612 bool
613 PrintEmfWin32::print_simple_shape(const NArtBpath *bpath, const NR::Matrix *transform, NRRect const *pbox)
615     NR::Matrix tf = *transform;
616     const NArtBpath *bp = bpath;
617     
618     int nodes = 0;
619     int moves = 0;
620     int lines = 0;
621     int curves = 0;
623     while (bp->code != NR_END) {
624         nodes++;
625         switch (bp->code) {
626             case NR_MOVETO:
627             case NR_MOVETO_OPEN:
628                 moves++;
629                 break;
630             case NR_LINETO:
631                 lines++;
632                 break;
633             case NR_CURVETO:
634                 curves++;
635                 break;
636         }
637         bp += 1;
638     }
640     if (!nodes)
641         return false;
642     
643     POINT *lpPoints = new POINT[moves + lines + curves*3];
644     int i = 0;
645     bp = bpath;
646     while (bp->code != NR_END)
647     {
648         using NR::X;
649         using NR::Y;
651         NR::Point p1(bp->c(1) * tf);
652         NR::Point p2(bp->c(2) * tf);
653         NR::Point p3(bp->c(3) * tf);
655         p1[X] = (p1[X] * IN_PER_PX * dwDPI);
656         p2[X] = (p2[X] * IN_PER_PX * dwDPI);
657         p3[X] = (p3[X] * IN_PER_PX * dwDPI);
658         p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
659         p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
660         p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
662         LONG const x1 = (LONG) round(p1[X]);
663         LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
664         LONG const x2 = (LONG) round(p2[X]);
665         LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
666         LONG const x3 = (LONG) round(p3[X]);
667         LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
669         switch (bp->code) {
670             case NR_MOVETO:
671             case NR_MOVETO_OPEN:
672             case NR_LINETO:
673                 lpPoints[i].x = x3;
674                 lpPoints[i].y = y3;
675                 i = i + 1;
676                 break;
677             case NR_CURVETO:
678                 lpPoints[i].x = x1;
679                 lpPoints[i].y = y1;
680                 lpPoints[i+1].x = x2;
681                 lpPoints[i+1].y = y2;
682                 lpPoints[i+2].x = x3;
683                 lpPoints[i+2].y = y3;
684                 i = i + 3;
685                 break;
686         }
687         
688         bp += 1;
689     }
691     bool done = false;
692     bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
693     bool polygon = false;
694     bool polyline = false;
695     bool rectangle = false;
696     bool ellipse = false;
697     
698     if (moves == 1 && moves+lines == nodes && closed) {
699         polygon = true;
700         if (nodes==5) {
701             if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
702                 lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
703             {
704                 rectangle = true;
705             }
706         }
707     }
708     else if (moves == 1 && moves+lines == nodes) {
709         polyline = true;
710     }
711     else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
712         if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
713             lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
714             lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
715             lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
716             lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
717             lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
718         {
719             ellipse = true;
720         }
721     }
723     if (polygon || polyline || ellipse) {
724         HPEN hpenTmp = NULL;
725         HPEN hpenOld = NULL;
726         HBRUSH hbrushTmp = NULL;
727         HBRUSH hbrushOld = NULL;
729         if (!stroke_and_fill) {
730             if (fill_only) {
731                 hpenTmp = (HPEN) GetStockObject(NULL_PEN);
732                 hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
733             }
734             else { // if (stroke_only)
735                 hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
736                 hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
737             }
738         }
740         if (polygon) {
741             if (rectangle)
742                 Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y );
743             else
744                 Polygon( hdc, lpPoints, nodes );
745         }
746         else if (polyline) {
747             Polyline( hdc, lpPoints, nodes );
748         }
749         else if (ellipse) {
750             Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
751         }
752         
753         done = true;
755         if (hpenOld)
756             SelectObject( hdc, hpenOld );
757         if (hpenTmp)
758             DeleteObject( hpenTmp );
759         if (hbrushOld)
760             SelectObject( hdc, hbrushOld );
761         if (hbrushTmp)
762             DeleteObject( hbrushTmp );
763     }
765     delete[] lpPoints;
766     
767     return done;
770 unsigned int
771 PrintEmfWin32::print_bpath(const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox)
773     unsigned int closed;
774     NR::Matrix tf = *transform;
776     simple_shape = print_simple_shape(bp, &tf, pbox);
778     if (simple_shape)
779         return TRUE;
780     
781     BeginPath( hdc );
782     closed = FALSE;
783     while (bp->code != NR_END) {
784         using NR::X;
785         using NR::Y;
787         NR::Point p1(bp->c(1) * tf);
788         NR::Point p2(bp->c(2) * tf);
789         NR::Point p3(bp->c(3) * tf);
791         p1[X] = (p1[X] * IN_PER_PX * dwDPI);
792         p2[X] = (p2[X] * IN_PER_PX * dwDPI);
793         p3[X] = (p3[X] * IN_PER_PX * dwDPI);
794         p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
795         p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
796         p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
798         LONG const x1 = (LONG) round(p1[X]);
799         LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
800         LONG const x2 = (LONG) round(p2[X]);
801         LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
802         LONG const x3 = (LONG) round(p3[X]);
803         LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
805         switch (bp->code) {
806             case NR_MOVETO:
807                 if (closed) {
808                     CloseFigure( hdc );
809                 }
810                 closed = TRUE;
811                 MoveToEx( hdc, x3, y3, NULL );
812                 break;
813             case NR_MOVETO_OPEN:
814                 if (closed) {
815                     CloseFigure( hdc );
816                 }
817                 closed = FALSE;
818                 MoveToEx( hdc, x3, y3, NULL );
819                 break;
820             case NR_LINETO:
821                 LineTo( hdc, x3, y3 );
822                 break;
823             case NR_CURVETO:
824             {
825                 POINT pt[3];
826                 pt[0].x = x1;
827                 pt[0].y = y1;
828                 pt[1].x = x2;
829                 pt[1].y = y2;
830                 pt[2].x = x3;
831                 pt[2].y = y3;
833                 PolyBezierTo( hdc, pt, 3 );
834                 break;
835             }
836             default:
837                 break;
838         }
839         bp += 1;
840     }
841     if (closed) {
842         CloseFigure( hdc );
843     }
844     EndPath( hdc );
846     return closed;
850 bool
851 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
853     return ext->get_param_bool("textToPath");
856 unsigned int
857 PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p,
858               SPStyle const *const style)
860     if (!hdc) return 0;
862     HFONT hfont = NULL;
863     
864 #ifdef USE_PANGO_WIN32
865 /*
866     font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
867     if (tf) {
868         LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
869         tf->Unref();
870         hfont = CreateFontIndirect(lf);
871         g_free(lf);
872     }
873 */
874 #endif
876     if (!hfont) {
877         if (PrintWin32::is_os_wide()) {
878             LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
879             g_assert(lf != NULL);
880             
881             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
882             lf->lfWidth = 0;
883             lf->lfEscapement = 0;
884             lf->lfOrientation = 0;
885             lf->lfWeight =
886                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
887                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
888                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
889                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
890                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
891                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
892                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
893                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
894                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
895                 FW_NORMAL;
896             lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
897             lf->lfUnderline = style->text_decoration.underline;
898             lf->lfStrikeOut = style->text_decoration.line_through;
899             lf->lfCharSet = DEFAULT_CHARSET;
900             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
901             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
902             lf->lfQuality = DEFAULT_QUALITY;
903             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
904             
905             gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
906             wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
907             g_free(unicode_name);
908             
909             hfont = CreateFontIndirectW(lf);
910             
911             g_free(lf);
912         }
913         else {
914             LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
915             g_assert(lf != NULL);
916             
917             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
918             lf->lfWidth = 0;
919             lf->lfEscapement = 0;
920             lf->lfOrientation = 0;
921             lf->lfWeight =
922                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
923                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
924                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
925                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
926                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
927                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
928                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
929                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
930                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
931                 FW_NORMAL;
932             lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
933             lf->lfUnderline = style->text_decoration.underline;
934             lf->lfStrikeOut = style->text_decoration.line_through;
935             lf->lfCharSet = DEFAULT_CHARSET;
936             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
937             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
938             lf->lfQuality = DEFAULT_QUALITY;
939             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
940             
941             strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
943             hfont = CreateFontIndirectA(lf);
944             
945             g_free(lf);
946         }
947     }
948     
949     HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
951     float rgb[3];
952     sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
953     SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
955     // Text alignment:
956     //   - (x,y) coordinates received by this filter are those of the point where the text
957     //     actually starts, and already takes into account the text object's alignment;
958     //   - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
959     SetTextAlign(hdc, TA_BASELINE | TA_LEFT);
961     // Transparent text background
962     SetBkMode(hdc, TRANSPARENT);
964     NR::Matrix tf = m_tr_stack.top();
966     p = p * tf;
967     p[NR::X] = (p[NR::X] * IN_PER_PX * dwDPI);
968     p[NR::Y] = (p[NR::Y] * IN_PER_PX * dwDPI);
970     LONG const xpos = (LONG) round(p[NR::X]);
971     LONG const ypos = (LONG) round(rc.bottom-p[NR::Y]);
973     if (PrintWin32::is_os_wide()) {
974         gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
975         TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
976     }
977     else {
978         TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text));
979     }
981     SelectObject(hdc, hfontOld);
982     DeleteObject(hfont);
983     
984     return 0;
987 void
988 PrintEmfWin32::init (void)
990     Inkscape::Extension::Extension * ext;
992     /* EMF print */
993     ext = Inkscape::Extension::build_from_mem(
994         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
995         "<name>Enhanced Metafile Print</name>\n"
996         "<id>org.inkscape.print.emf.win32</id>\n"
997         "<param name=\"destination\" type=\"string\"></param>\n"
998         "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
999         "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
1000         "<print/>\n"
1001         "</inkscape-extension>", new PrintEmfWin32());
1003     return;
1007 }  /* namespace Internal */
1008 }  /* namespace Extension */
1009 }  /* namespace Inkscape */
1011 #endif /* WIN32 */
1013 /*
1014   Local Variables:
1015   mode:c++
1016   c-file-style:"stroustrup"
1017   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1018   indent-tabs-mode:nil
1019   fill-column:99
1020   End:
1021 */
1022 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :