Code

Win32 post-GSoC fixups.
[inkscape.git] / src / extension / internal / emf-win32-print.cpp
1 /** @file
2  * @brief Enhanced Metafile printing
3  */
4 /* Authors:
5  *   Ulf Erikson <ulferikson@users.sf.net>
6  *   Jon A. Cruz <jon@joncruz.org>
7  *   Abhishek Sharma
8  *
9  * Copyright (C) 2006-2009 Authors
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
13 /*
14  * References:
15  *  - How to Create & Play Enhanced Metafiles in Win32
16  *      http://support.microsoft.com/kb/q145999/
17  *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
18  *      http://support.microsoft.com/kb/q66949/
19  *  - Metafile Functions
20  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
21  *  - Metafile Structures
22  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
23  */
25 #ifdef WIN32
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 //#include <string.h>
32 //#include <signal.h>
33 //#include <errno.h>
35 #include <2geom/pathvector.h>
36 #include <2geom/rect.h>
37 #include <2geom/bezier-curve.h>
38 #include <2geom/hvlinesegment.h>
39 #include "helper/geom.h"
40 #include "helper/geom-curves.h"
41 //#include "display/canvas-bpath.h"
42 #include "sp-item.h"
44 //#include "glib.h"
45 //#include "gtk/gtkdialog.h"
46 //#include "gtk/gtkbox.h"
47 //#include "gtk/gtkstock.h"
49 //#include "glibmm/i18n.h"
50 //#include "enums.h"
51 //#include "document.h"
52 #include "style.h"
53 //#include "sp-paint-server.h"
54 #include "inkscape-version.h"
56 //#include "libnrtype/FontFactory.h"
57 //#include "libnrtype/font-instance.h"
58 //#include "libnrtype/font-style-to-pos.h"
60 #define WIN32_LEAN_AND_MEAN
61 #include <windows.h>
63 #include "win32.h"
64 #include "emf-win32-print.h"
66 #include "unit-constants.h"
68 //#include "extension/extension.h"
69 #include "extension/system.h"
70 #include "extension/print.h"
72 //#include "io/sys.h"
74 //#include "macros.h"
76 namespace Inkscape {
77 namespace Extension {
78 namespace Internal {
80 static float dwDPI = 2540;
83 PrintEmfWin32::PrintEmfWin32 (void):
84     hdc(NULL),
85     hbrush(NULL),
86     hbrushOld(NULL),
87     hpen(NULL),
88     stroke_and_fill(false),
89     fill_only(false),
90     simple_shape(false)
91 {
92 }
95 PrintEmfWin32::~PrintEmfWin32 (void)
96 {
97     if (hdc) {
98         HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
99         if ( metafile ) {
100             DeleteEnhMetaFile( metafile );
101         }
102         DeleteDC( hdc );
103     }
105     /* restore default signal handling for SIGPIPE */
106 #if !defined(_WIN32) && !defined(__WIN32__)
107     (void) signal(SIGPIPE, SIG_DFL);
108 #endif
109     return;
113 unsigned int
114 PrintEmfWin32::setup (Inkscape::Extension::Print * /*mod*/)
116     return TRUE;
120 unsigned int
121 PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
123     gchar const *utf8_fn = mod->get_param_string("destination");
125     gsize bytesRead = 0;
126     gsize bytesWritten = 0;
127     GError* error = NULL;
128     gchar *local_fn =
129         g_filename_from_utf8( utf8_fn, -1,  &bytesRead,  &bytesWritten, &error );
131     if (local_fn == NULL) {
132         return 1;
133     }
135     CHAR *ansi_uri = (CHAR *) local_fn;
136     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
137     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
139     // width and height in px
140     _width = doc->getWidth();
141     _height = doc->getHeight();
143     NRRect d;
144     bool pageBoundingBox;
145     pageBoundingBox = mod->get_param_bool("pageBoundingBox");
146     if (pageBoundingBox) {
147         d.x0 = d.y0 = 0;
148         d.x1 = _width;
149         d.y1 = _height;
150     } else {
151         SPItem* doc_item = SP_ITEM(doc->getRoot());
152         doc_item->invoke_bbox(&d, doc_item->i2d_affine(), TRUE);
153     }
155     d.x0 *= IN_PER_PX;
156     d.y0 *= IN_PER_PX;
157     d.x1 *= IN_PER_PX;
158     d.y1 *= IN_PER_PX;
160     float dwInchesX = (d.x1 - d.x0);
161     float dwInchesY = (d.y1 - d.y0);
163     // dwInchesX x dwInchesY in .01mm units
164     SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );
166     // Get a Reference DC
167     HDC hScreenDC = GetDC( NULL );
169     // Get the physical characteristics of the reference DC
170     int PixelsX = GetDeviceCaps( hScreenDC, HORZRES );
171     int PixelsY = GetDeviceCaps( hScreenDC, VERTRES );
172     int MMX = GetDeviceCaps( hScreenDC, HORZSIZE );
173     int MMY = GetDeviceCaps( hScreenDC, VERTSIZE );
175     CHAR buff[1024];
176     ZeroMemory(buff, sizeof(buff));
177     snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", Inkscape::version_string, __DATE__);
178     INT len = strlen(buff);
179     CHAR *p1 = strrchr(ansi_uri, '\\');
180     CHAR *p2 = strrchr(ansi_uri, '/');
181     CHAR *p = MAX(p1, p2);
182     if (p)
183         p++;
184     else
185         p = ansi_uri;
186     snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p);
187     
188     // Create the Metafile
189     if (PrintWin32::is_os_wide()) {
190         WCHAR wbuff[1024];
191         ZeroMemory(wbuff, sizeof(wbuff));
192         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0]));
193         hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff );
194     }
195     else {
196         hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, buff );
197     }
199     // Release the reference DC
200     ReleaseDC( NULL, hScreenDC );
202     // Did we get a good metafile?
203     if (hdc == NULL)
204     {
205         g_free(local_fn);
206         g_free(unicode_fn);
207         return 1;
208     }
210     // Anisotropic mapping mode
211     SetMapMode( hdc, MM_ANISOTROPIC );
213     // Set the Windows extent
214     int windowextX = (int) ceil(dwInchesX*dwDPI);
215     int windowextY = (int) ceil(dwInchesY*dwDPI);
216     SetWindowExtEx( hdc, windowextX, windowextY, NULL );
218     // Set the viewport extent to reflect
219     // dwInchesX" x dwInchesY" in device units
220     int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX);
221     int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY);
222     SetViewportExtEx( hdc, viewportextX, viewportextY, NULL );
224     if (1) {
225         snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
226         GdiComment(hdc, strlen(buff), (BYTE*) buff);
228         snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
229         GdiComment(hdc, strlen(buff), (BYTE*) buff);
230     }
232     SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
234     g_free(local_fn);
235     g_free(unicode_fn);
237     m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight()));
239     return 0;
243 unsigned int
244 PrintEmfWin32::finish (Inkscape::Extension::Print * /*mod*/)
246     if (!hdc) return 0;
248     flush_fill(); // flush any pending fills
250     HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
251     if ( metafile ) {
252         DeleteEnhMetaFile( metafile );
253     }
254     DeleteDC( hdc );
256     hdc = NULL;
258     return 0;
262 unsigned int
263 PrintEmfWin32::comment (Inkscape::Extension::Print * /*module*/,
264                         const char * /*comment*/)
266     if (!hdc) return 0;
268     flush_fill(); // flush any pending fills
270     return 0;
274 int
275 PrintEmfWin32::create_brush(SPStyle const *style)
277     float rgb[3];
279     if (style) {
280         float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
281         if (opacity <= 0.0)
282             return 1;
284         sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
285         hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
286         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
288         SetPolyFillMode( hdc,
289                          style->fill_rule.computed == 0 ? WINDING :
290                          style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
291     } else { // if (!style)
292         hbrush = CreateSolidBrush( RGB(255, 255, 255) );
293         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
294         SetPolyFillMode( hdc, ALTERNATE );
295     }
297     return 0;
301 void
302 PrintEmfWin32::destroy_brush()
304     SelectObject( hdc, hbrushOld );
305     if (hbrush)
306         DeleteObject( hbrush );
307     hbrush = NULL;
308     hbrushOld = NULL;
312 void
313 PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Matrix &transform)
315     if (style) {
316         float rgb[3];
318         sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
320         LOGBRUSH lb;
321         ZeroMemory(&lb, sizeof(lb));
322         lb.lbStyle = BS_SOLID;
323         lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
325         int linestyle = PS_SOLID;
326         int linecap = 0;
327         int linejoin = 0;
328         DWORD n_dash = 0;
329         DWORD *dash = NULL;
331         using Geom::X;
332         using Geom::Y;
334         Geom::Point zero(0, 0);
335         Geom::Point one(1, 1);
336         Geom::Point p0(zero * transform);
337         Geom::Point p1(one * transform);
338         Geom::Point p(p1 - p0);
340         double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
342         DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
344         if (style->stroke_linecap.computed == 0) {
345             linecap = PS_ENDCAP_FLAT;
346         }
347         else if (style->stroke_linecap.computed == 1) {
348             linecap = PS_ENDCAP_ROUND;
349         }
350         else if (style->stroke_linecap.computed == 2) {
351             linecap = PS_ENDCAP_SQUARE;
352         }
354         if (style->stroke_linejoin.computed == 0) {
355             linejoin = PS_JOIN_MITER;
356         }
357         else if (style->stroke_linejoin.computed == 1) {
358             linejoin = PS_JOIN_ROUND;
359         }
360         else if (style->stroke_linejoin.computed == 2) {
361             linejoin = PS_JOIN_BEVEL;
362         }
364         if (style->stroke_dash.n_dash   &&
365             style->stroke_dash.dash       )
366         {
367             int i = 0;
368             while (linestyle != PS_USERSTYLE &&
369                    (i < style->stroke_dash.n_dash)) {
370                 if (style->stroke_dash.dash[i] > 0.00000001)
371                     linestyle = PS_USERSTYLE;
372                 i++;
373             }
375             if (linestyle == PS_USERSTYLE) {
376                 n_dash = style->stroke_dash.n_dash;
377                 dash = new DWORD[n_dash];
378                 for (i = 0; i < style->stroke_dash.n_dash; i++) {
379                     dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
380                 }
381             }
382         }
384         hpen = ExtCreatePen(
385             PS_GEOMETRIC | linestyle | linecap | linejoin,
386             linewidth,
387             &lb,
388             n_dash,
389             dash );
391         if ( !hpen && linestyle == PS_USERSTYLE ) {
392             hpen = ExtCreatePen(
393                 PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
394                 linewidth,
395                 &lb,
396                 0,
397                 NULL );
398         }
400         if ( !hpen ) {
401             hpen = CreatePen(
402                 PS_SOLID,
403                 linewidth,
404                 lb.lbColor );
405         }
407         hpenOld = (HPEN) SelectObject( hdc, hpen );
409         if (linejoin == PS_JOIN_MITER) {
410             float oldmiterlimit;
411             float miterlimit = style->stroke_miterlimit.value;
413             miterlimit = miterlimit * 10.0 / 4.0;
414             if (miterlimit < 1)
415                 miterlimit = 10.0;
417             miterlimit = miterlimit * IN_PER_PX * dwDPI;
419             SetMiterLimit(
420                 hdc,
421                 miterlimit,
422                 &oldmiterlimit );
423         }
425         if (n_dash) {
426             delete[] dash;
427         }
428     }
429     else { // if (!style)
430         hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
431         hpenOld = (HPEN) SelectObject( hdc, hpen );
432     }
436 void
437 PrintEmfWin32::destroy_pen()
439     SelectObject( hdc, hpenOld );
440     if (hpen)
441         DeleteObject( hpen );
442     hpen = NULL;
446 void
447 PrintEmfWin32::flush_fill()
449     if (!fill_pathv.empty()) {
450         stroke_and_fill = false;
451         fill_only = true;
452         print_pathv(fill_pathv, fill_transform);
453         fill_only = false;
454         if (!simple_shape)
455             FillPath( hdc );
456         destroy_brush();
457         fill_pathv.clear();
458     }
461 unsigned int
462 PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Matrix const *transform, float /*opacity*/)
464     Geom::Matrix tr = *transform;
465     
466     if (m_tr_stack.size()) {
467         Geom::Matrix tr_top = m_tr_stack.top();
468         m_tr_stack.push(tr * tr_top);
469     } else {
470         m_tr_stack.push(tr);
471     }
473     return 1;
476 unsigned int
477 PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/)
479     m_tr_stack.pop();
480     return 1;
483 unsigned int
484 PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/,
485                     Geom::PathVector const &pathv, Geom::Matrix const * /*transform*/, SPStyle const *style,
486                     NRRect const * /*pbox*/, NRRect const * /*dbox*/, NRRect const * /*bbox*/)
488     if (!hdc) return 0;
490     Geom::Matrix tf = m_tr_stack.top();
492     flush_fill(); // flush any pending fills
494     if (style->fill.isColor()) {
495         if (create_brush(style))
496             return 0;
497     } else {
498         // create_brush(NULL);
499         return 0;
500     }
502     fill_pathv.clear();
503     std::copy(pathv.begin(), pathv.end(), std::back_inserter(fill_pathv));
504     fill_transform = tf;
506     // postpone fill in case of stroke-and-fill
508     return 0;
512 unsigned int
513 PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/,
514                        Geom::PathVector const &pathv, const Geom::Matrix * /*transform*/, const SPStyle *style,
515                        const NRRect * /*pbox*/, const NRRect * /*dbox*/, const NRRect * /*bbox*/)
517     if (!hdc) return 0;
519     Geom::Matrix tf = m_tr_stack.top();
521     stroke_and_fill = ( pathv == fill_pathv );
523     if (!stroke_and_fill) {
524         flush_fill(); // flush any pending fills
525     }
527     if (style->stroke.isColor()) {
528         create_pen(style, tf);
529     } else {
530         // create_pen(NULL, tf);
531         return 0;
532     }
534     print_pathv(pathv, tf);
536     if (stroke_and_fill) {
537         if (!simple_shape)
538             StrokeAndFillPath( hdc );
539         destroy_brush();
540         fill_pathv.clear();
541     } else {
542         if (!simple_shape)
543             StrokePath( hdc );
544     }
546     destroy_pen();
548     return 0;
552 bool
553 PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Matrix &transform)
555     Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
556     
557     int nodes = 0;
558     int moves = 0;
559     int lines = 0;
560     int curves = 0;
562     for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
563     {
564         moves++;
565         nodes++;
566         
567         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
568         {
569             nodes++;
570             
571             if ( is_straight_curve(*cit) ) {
572                 lines++;
573             }
574             else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) {
575                 cubic = cubic;
576                 curves++;
577             }
578         }
579     }
581     if (!nodes)
582         return false;
583     
584     POINT *lpPoints = new POINT[moves + lines + curves*3];
585     int i = 0;
587     /**
588      * For all Subpaths in the <path>
589      */      
590     for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
591     {
592         using Geom::X;
593         using Geom::Y;
595         Geom::Point p0 = pit->initialPoint();
597         p0[X] = (p0[X] * IN_PER_PX * dwDPI);
598         p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
599                 
600         LONG const x0 = (LONG) round(p0[X]);
601         LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
603         lpPoints[i].x = x0;
604         lpPoints[i].y = y0;
605         i = i + 1;
607         /**
608          * For all segments in the subpath
609          */
610         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
611         {
612             if ( is_straight_curve(*cit) )
613             {
614                 //Geom::Point p0 = cit->initialPoint();
615                 Geom::Point p1 = cit->finalPoint();
617                 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
618                 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
619                 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
620                 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
621                 
622                 //LONG const x0 = (LONG) round(p0[X]);
623                 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
624                 LONG const x1 = (LONG) round(p1[X]);
625                 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
627                 lpPoints[i].x = x1;
628                 lpPoints[i].y = y1;
629                 i = i + 1;
630             }
631             else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
632             {
633                 std::vector<Geom::Point> points = cubic->points();
634                 //Geom::Point p0 = points[0];
635                 Geom::Point p1 = points[1];
636                 Geom::Point p2 = points[2];
637                 Geom::Point p3 = points[3];
639                 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
640                 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
641                 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
642                 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
643                 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
644                 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
645                 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
646                 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
647                 
648                 //LONG const x0 = (LONG) round(p0[X]);
649                 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
650                 LONG const x1 = (LONG) round(p1[X]);
651                 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
652                 LONG const x2 = (LONG) round(p2[X]);
653                 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
654                 LONG const x3 = (LONG) round(p3[X]);
655                 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
657                 POINT pt[3];
658                 pt[0].x = x1;
659                 pt[0].y = y1;
660                 pt[1].x = x2;
661                 pt[1].y = y2;
662                 pt[2].x = x3;
663                 pt[2].y = y3;
665                 lpPoints[i].x = x1;
666                 lpPoints[i].y = y1;
667                 lpPoints[i+1].x = x2;
668                 lpPoints[i+1].y = y2;
669                 lpPoints[i+2].x = x3;
670                 lpPoints[i+2].y = y3;
671                 i = i + 3;
672             }
673         }
674     }
676     bool done = false;
677     bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
678     bool polygon = false;
679     bool rectangle = false;
680     bool ellipse = false;
681     
682     if (moves == 1 && moves+lines == nodes && closed) {
683         polygon = true;
684         if (nodes==5) {
685             if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
686                 lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
687             {
688                 rectangle = true;
689             }
690         }
691     }
692     else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
693         if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
694             lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
695             lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
696             lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
697             lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
698             lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
699         {
700             ellipse = true;
701         }
702     }
704     if (polygon || ellipse) {
705         HPEN hpenTmp = NULL;
706         HPEN hpenOld = NULL;
707         HBRUSH hbrushTmp = NULL;
708         HBRUSH hbrushOld = NULL;
710         if (!stroke_and_fill) {
711             if (fill_only) {
712                 hpenTmp = (HPEN) GetStockObject(NULL_PEN);
713                 hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
714             }
715             else { // if (stroke_only)
716                 hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
717                 hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
718             }
719         }
721         if (polygon) {
722             if (rectangle)
723                 Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y );
724             else
725                 Polygon( hdc, lpPoints, nodes );
726         }
727         else if (ellipse) {
728             Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
729         }
730         
731         done = true;
733         if (hpenOld)
734             SelectObject( hdc, hpenOld );
735         if (hpenTmp)
736             DeleteObject( hpenTmp );
737         if (hbrushOld)
738             SelectObject( hdc, hbrushOld );
739         if (hbrushTmp)
740             DeleteObject( hbrushTmp );
741     }
743     delete[] lpPoints;
744     
745     return done;
748 unsigned int
749 PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Matrix &transform)
751     simple_shape = print_simple_shape(pathv, transform);
753     if (simple_shape)
754         return TRUE;
756     Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
757     
758     BeginPath( hdc );
760     /**
761      * For all Subpaths in the <path>
762      */      
763     for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
764     {
765         using Geom::X;
766         using Geom::Y;
768         Geom::Point p0 = pit->initialPoint();
770         p0[X] = (p0[X] * IN_PER_PX * dwDPI);
771         p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
772                 
773         LONG const x0 = (LONG) round(p0[X]);
774         LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
776         MoveToEx( hdc, x0, y0, NULL );
778         /**
779          * For all segments in the subpath
780          */
781         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
782         {
783             if ( is_straight_curve(*cit) )
784             {
785                 //Geom::Point p0 = cit->initialPoint();
786                 Geom::Point p1 = cit->finalPoint();
788                 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
789                 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
790                 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
791                 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
792                 
793                 //LONG const x0 = (LONG) round(p0[X]);
794                 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
795                 LONG const x1 = (LONG) round(p1[X]);
796                 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
798                 LineTo( hdc, x1, y1 );
799             }
800             else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
801             {
802                 std::vector<Geom::Point> points = cubic->points();
803                 //Geom::Point p0 = points[0];
804                 Geom::Point p1 = points[1];
805                 Geom::Point p2 = points[2];
806                 Geom::Point p3 = points[3];
808                 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
809                 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
810                 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
811                 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
812                 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
813                 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
814                 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
815                 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
816                 
817                 //LONG const x0 = (LONG) round(p0[X]);
818                 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
819                 LONG const x1 = (LONG) round(p1[X]);
820                 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
821                 LONG const x2 = (LONG) round(p2[X]);
822                 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
823                 LONG const x3 = (LONG) round(p3[X]);
824                 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
826                 POINT pt[3];
827                 pt[0].x = x1;
828                 pt[0].y = y1;
829                 pt[1].x = x2;
830                 pt[1].y = y2;
831                 pt[2].x = x3;
832                 pt[2].y = y3;
834                 PolyBezierTo( hdc, pt, 3 );
835             }
836             else
837             {
838                 g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used");
839             }
840         }
842         if (pit->end_default() == pit->end_closed()) {
843             CloseFigure( hdc );
844         }
845     }
847     EndPath( hdc );
849     return TRUE;
853 bool
854 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
856     return ext->get_param_bool("textToPath");
859 unsigned int
860 PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point p,
861                     SPStyle const *const style)
863     if (!hdc) return 0;
865     HFONT hfont = NULL;
866     
867 #ifdef USE_PANGO_WIN32
868 /*
869     font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
870     if (tf) {
871         LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
872         tf->Unref();
873         hfont = CreateFontIndirect(lf);
874         g_free(lf);
875     }
876 */
877 #endif
879     if (!hfont) {
880         if (PrintWin32::is_os_wide()) {
881             LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
882             g_assert(lf != NULL);
883             
884             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
885             lf->lfWidth = 0;
886             lf->lfEscapement = 0;
887             lf->lfOrientation = 0;
888             lf->lfWeight =
889                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
890                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
891                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
892                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
893                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
894                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
895                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
896                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
897                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
898                 FW_NORMAL;
899             lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
900             lf->lfUnderline = style->text_decoration.underline;
901             lf->lfStrikeOut = style->text_decoration.line_through;
902             lf->lfCharSet = DEFAULT_CHARSET;
903             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
904             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
905             lf->lfQuality = DEFAULT_QUALITY;
906             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
907             
908             gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
909             wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
910             g_free(unicode_name);
911             
912             hfont = CreateFontIndirectW(lf);
913             
914             g_free(lf);
915         }
916         else {
917             LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
918             g_assert(lf != NULL);
919             
920             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
921             lf->lfWidth = 0;
922             lf->lfEscapement = 0;
923             lf->lfOrientation = 0;
924             lf->lfWeight =
925                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
926                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
927                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
928                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
929                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
930                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
931                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
932                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
933                 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
934                 FW_NORMAL;
935             lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
936             lf->lfUnderline = style->text_decoration.underline;
937             lf->lfStrikeOut = style->text_decoration.line_through;
938             lf->lfCharSet = DEFAULT_CHARSET;
939             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
940             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
941             lf->lfQuality = DEFAULT_QUALITY;
942             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
943             
944             strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
946             hfont = CreateFontIndirectA(lf);
947             
948             g_free(lf);
949         }
950     }
951     
952     HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
954     float rgb[3];
955     sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
956     SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
958     // Text alignment:
959     //   - (x,y) coordinates received by this filter are those of the point where the text
960     //     actually starts, and already takes into account the text object's alignment;
961     //   - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
962     SetTextAlign(hdc, TA_BASELINE | TA_LEFT);
964     // Transparent text background
965     SetBkMode(hdc, TRANSPARENT);
967     Geom::Matrix tf = m_tr_stack.top();
969     p = p * tf;
970     p[Geom::X] = (p[Geom::X] * IN_PER_PX * dwDPI);
971     p[Geom::Y] = (p[Geom::Y] * IN_PER_PX * dwDPI);
973     LONG const xpos = (LONG) round(p[Geom::X]);
974     LONG const ypos = (LONG) round(rc.bottom-p[Geom::Y]);
976     if (PrintWin32::is_os_wide()) {
977         gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
978         TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
979     }
980     else {
981         TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text));
982     }
984     SelectObject(hdc, hfontOld);
985     DeleteObject(hfont);
986     
987     return 0;
990 void
991 PrintEmfWin32::init (void)
993     Inkscape::Extension::Extension * ext;
995     /* EMF print */
996     ext = Inkscape::Extension::build_from_mem(
997         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
998         "<name>Enhanced Metafile Print</name>\n"
999         "<id>org.inkscape.print.emf.win32</id>\n"
1000         "<param name=\"destination\" type=\"string\"></param>\n"
1001         "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
1002         "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
1003         "<print/>\n"
1004         "</inkscape-extension>", new PrintEmfWin32());
1006     return;
1010 }  /* namespace Internal */
1011 }  /* namespace Extension */
1012 }  /* namespace Inkscape */
1014 #endif /* WIN32 */
1016 /*
1017   Local Variables:
1018   mode:c++
1019   c-file-style:"stroustrup"
1020   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1021   indent-tabs-mode:nil
1022   fill-column:99
1023   End:
1024 */
1025 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :