Code

2geomify print, fill and stroke methods of extensions
[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     // Create the Metafile
177     if (PrintWin32::is_os_wide())
178         hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, NULL );
179     else
180         hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, NULL );
182     // Release the reference DC
183     ReleaseDC( NULL, hScreenDC );
185     // Did we get a good metafile?
186     if (hdc == NULL)
187     {
188         g_free(local_fn);
189         g_free(unicode_fn);
190         return 1;
191     }
193     // Anisotropic mapping mode
194     SetMapMode( hdc, MM_ANISOTROPIC );
196     // Set the Windows extent
197     SetWindowExtEx( hdc, (int) (dwInchesX*dwDPI), (int) (dwInchesY*dwDPI), NULL );
199     // Set the viewport extent to reflect
200     // dwInchesX" x dwInchesY" in device units
201     SetViewportExtEx( hdc,
202                       (int) ((float) dwInchesX*25.4f*PX_PER_MM),
203                       (int) ((float) dwInchesY*25.4f*PX_PER_MM),
204                       NULL );
206     SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
208     g_free(local_fn);
209     g_free(unicode_fn);
211     m_tr_stack.push( NR::scale(1, -1) * NR::translate(0, sp_document_height(doc)));
212     return 0;
216 unsigned int
217 PrintEmfWin32::finish (Inkscape::Extension::Print *mod)
219     if (!hdc) return 0;
221     flush_fill(); // flush any pending fills
223     HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
224     if ( metafile ) {
225         DeleteEnhMetaFile( metafile );
226     }
227     DeleteDC( hdc );
229     hdc = NULL;
231     return 0;
235 unsigned int
236 PrintEmfWin32::comment (Inkscape::Extension::Print * module,
237                                 const char *comment)
239     if (!hdc) return 0;
241     flush_fill(); // flush any pending fills
243     return 0;
247 int
248 PrintEmfWin32::create_brush(SPStyle const *style)
250     float rgb[3];
252     if (style) {
253         float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
254         if (opacity <= 0.0)
255             return 1;
257         sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
258         hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
259         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
261         SetPolyFillMode( hdc,
262                          style->fill_rule.computed == 0 ? WINDING :
263                          style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
264     } else { // if (!style)
265         hbrush = CreateSolidBrush( RGB(255, 255, 255) );
266         hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
267         SetPolyFillMode( hdc, ALTERNATE );
268     }
270     return 0;
274 void
275 PrintEmfWin32::destroy_brush()
277     SelectObject( hdc, hbrushOld );
278     if (hbrush)
279         DeleteObject( hbrush );
280     hbrush = NULL;
281     hbrushOld = NULL;
285 void
286 PrintEmfWin32::create_pen(SPStyle const *style, const NR::Matrix *transform)
288     if (style) {
289         float rgb[3];
291         sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
293         LOGBRUSH lb = {0};
294         lb.lbStyle = BS_SOLID;
295         lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
297         int linestyle = PS_SOLID;
298         int linecap = 0;
299         int linejoin = 0;
300         DWORD n_dash = 0;
301         DWORD *dash = NULL;
302         float oldmiterlimit;
304         using NR::X;
305         using NR::Y;
307         NR::Matrix tf = *transform;
309         NR::Point zero(0, 0);
310         NR::Point one(1, 1);
311         NR::Point p0(zero * tf);
312         NR::Point p1(one * tf);
313         NR::Point p(p1 - p0);
315         double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
317         DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
319         if (style->stroke_linecap.computed == 0) {
320             linecap = PS_ENDCAP_FLAT;
321         }
322         else if (style->stroke_linecap.computed == 1) {
323             linecap = PS_ENDCAP_ROUND;
324         }
325         else if (style->stroke_linecap.computed == 2) {
326             linecap = PS_ENDCAP_SQUARE;
327         }
329         if (style->stroke_linejoin.computed == 0) {
330             linejoin = PS_JOIN_MITER;
331         }
332         else if (style->stroke_linejoin.computed == 1) {
333             linejoin = PS_JOIN_ROUND;
334         }
335         else if (style->stroke_linejoin.computed == 2) {
336             linejoin = PS_JOIN_BEVEL;
337         }
339         if (style->stroke_dash.n_dash   &&
340             style->stroke_dash.dash       )
341         {
342             int i = 0;
343             while (linestyle != PS_USERSTYLE &&
344                    (i < style->stroke_dash.n_dash)) {
345                 if (style->stroke_dash.dash[i] > 0.00000001)
346                     linestyle = PS_USERSTYLE;
347                 i++;
348             }
350             if (linestyle == PS_USERSTYLE) {
351                 n_dash = style->stroke_dash.n_dash;
352                 dash = new DWORD[n_dash];
353                 for (i = 0; i < style->stroke_dash.n_dash; i++) {
354                     dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
355                 }
356             }
357         }
359         hpen = ExtCreatePen(
360             PS_GEOMETRIC | linestyle | linecap | linejoin,
361             linewidth,
362             &lb,
363             n_dash,
364             dash );
366         if ( !hpen && linestyle == PS_USERSTYLE ) {
367             hpen = ExtCreatePen(
368                 PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
369                 linewidth,
370                 &lb,
371                 0,
372                 NULL );
373         }
375         if ( !hpen ) {
376             hpen = CreatePen(
377                 PS_SOLID,
378                 linewidth,
379                 lb.lbColor );
380         }
382         hpenOld = (HPEN) SelectObject( hdc, hpen );
384         if (linejoin == PS_JOIN_MITER) {
385             float miterlimit = style->stroke_miterlimit.value;
386             if (miterlimit < 1)
387                 miterlimit = 4.0;
388             SetMiterLimit(
389                 hdc,
390                 miterlimit * IN_PER_PX * dwDPI,
391                 &oldmiterlimit );
392         }
394         if (n_dash) {
395             delete[] dash;
396         }
397     }
398     else { // if (!style)
399         hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
400         hpenOld = (HPEN) SelectObject( hdc, hpen );
401     }
405 void
406 PrintEmfWin32::destroy_pen()
408     SelectObject( hdc, hpenOld );
409     if (hpen)
410         DeleteObject( hpen );
411     hpen = NULL;
415 void
416 PrintEmfWin32::flush_fill()
418     if (fill_path) {
419         stroke_and_fill = false;
420         fill_only = true;
421         print_bpath(fill_path, &fill_transform, &fill_pbox);
422         fill_only = false;
423         if (!simple_shape)
424             FillPath( hdc );
425         destroy_brush();
426         delete[] fill_path;
427         fill_path = NULL;
428     }
432 NArtBpath *
433 PrintEmfWin32::copy_bpath(const NArtBpath *bp)
435     NArtBpath *tmp = (NArtBpath *) bp;
436     int num = 1;
437     
438     while (tmp->code != NR_END) {
439         num++;
440         tmp += 1;
441     }
443     tmp = new NArtBpath[num];
444     while (num--) {
445         tmp[num] = bp[num];
446     }
448     return tmp;
452 int
453 PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2)
455     if (!bp1 || !bp2) {
456         return 1;
457     }
458     
459     while (bp1->code != NR_END && bp2->code != NR_END) {
460         if (bp1->code != bp2->code) {
461             return 1;
462         }
464         if ( fabs(bp1->x1 - bp2->x1) > 0.00000001 ||
465              fabs(bp1->y1 - bp2->y1) > 0.00000001 ||
466              fabs(bp1->x2 - bp2->x2) > 0.00000001 ||
467              fabs(bp1->y2 - bp2->y2) > 0.00000001 ||
468              fabs(bp1->x3 - bp2->x3) > 0.00000001 ||
469              fabs(bp1->y3 - bp2->y3) > 0.00000001 )
470         {
471             return 1;
472         }
473         
474         bp1 += 1;
475         bp2 += 1;
476     }
477     
478     return bp1->code != NR_END || bp2->code != NR_END;
481 unsigned int
482 PrintEmfWin32::bind(Inkscape::Extension::Print *mod, NR::Matrix const *transform, float opacity)
484     NR::Matrix tr = *transform;
485     
486     if (m_tr_stack.size()) {
487         NR::Matrix tr_top = m_tr_stack.top();
488         m_tr_stack.push(tr * tr_top);
489     } else {
490         m_tr_stack.push(tr);
491     }
493     return 1;
496 unsigned int
497 PrintEmfWin32::release(Inkscape::Extension::Print *mod)
499     m_tr_stack.pop();
500     return 1;
503 unsigned int
504 PrintEmfWin32::fill(Inkscape::Extension::Print *mod,
505                Geom::PathVector const &pathv, NR::Matrix const *transform, SPStyle const *style,
506                NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
508     if (!hdc) return 0;
510     NR::Matrix tf = m_tr_stack.top();
512     flush_fill(); // flush any pending fills
514     if (style->fill.isColor()) {
515         if (create_brush(style))
516             return 0;
517     } else {
518         // create_brush(NULL);
519         return 0;
520     }
522     NArtBpath * bpath = BPath_from_2GeomPath(pathv);
523     fill_path = copy_bpath( bpath );
524     g_free(bpath);
525     fill_transform = tf;
526     fill_pbox = *pbox;
528     // postpone fill in case of stroke-and-fill
530     return 0;
534 unsigned int
535 PrintEmfWin32::stroke (Inkscape::Extension::Print *mod,
536                   Geom::PathVector const &pathv, const NR::Matrix *transform, const SPStyle *style,
537                   const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)
539     if (!hdc) return 0;
541     NR::Matrix tf = m_tr_stack.top();
543     NArtBpath * bpath = BPath_from_2GeomPath(pathv);
545     stroke_and_fill = ( cmp_bpath( bpath, fill_path ) == 0 );
547     if (!stroke_and_fill) {
548         flush_fill(); // flush any pending fills
549     }
551     if (style->stroke.isColor()) {
552         create_pen(style, &tf);
553     } else {
554         // create_pen(NULL, &tf);
555         return 0;
556     }
558     print_bpath(bpath, &tf, pbox);
560     if (stroke_and_fill) {
561         if (!simple_shape)
562             StrokeAndFillPath( hdc );
563         destroy_brush();
564         delete[] fill_path;
565         fill_path = NULL;
566     } else {
567         if (!simple_shape)
568             StrokePath( hdc );
569     }
571     g_free(bpath);
572     destroy_pen();
574     return 0;
578 bool
579 PrintEmfWin32::print_simple_shape(const NArtBpath *bpath, const NR::Matrix *transform, NRRect const *pbox)
581     NR::Matrix tf = *transform;
582     const NArtBpath *bp = bpath;
583     
584     int nodes = 0;
585     int moves = 0;
586     int lines = 0;
587     int curves = 0;
589     while (bp->code != NR_END) {
590         nodes++;
591         switch (bp->code) {
592             case NR_MOVETO:
593             case NR_MOVETO_OPEN:
594                 moves++;
595                 break;
596             case NR_LINETO:
597                 lines++;
598                 break;
599             case NR_CURVETO:
600                 curves++;
601                 break;
602         }
603         bp += 1;
604     }
606     if (!nodes)
607         return false;
608     
609     POINT *lpPoints = new POINT[moves + lines + curves*3];
610     int i = 0;
611     bp = bpath;
612     while (bp->code != NR_END)
613     {
614         using NR::X;
615         using NR::Y;
617         NR::Point p1(bp->c(1) * tf);
618         NR::Point p2(bp->c(2) * tf);
619         NR::Point p3(bp->c(3) * tf);
621         p1[X] = (p1[X] * IN_PER_PX * dwDPI);
622         p2[X] = (p2[X] * IN_PER_PX * dwDPI);
623         p3[X] = (p3[X] * IN_PER_PX * dwDPI);
624         p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
625         p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
626         p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
628         LONG const x1 = (LONG) round(p1[X]);
629         LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
630         LONG const x2 = (LONG) round(p2[X]);
631         LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
632         LONG const x3 = (LONG) round(p3[X]);
633         LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
635         switch (bp->code) {
636             case NR_MOVETO:
637             case NR_MOVETO_OPEN:
638             case NR_LINETO:
639                 lpPoints[i].x = x3;
640                 lpPoints[i].y = y3;
641                 i = i + 1;
642                 break;
643             case NR_CURVETO:
644                 lpPoints[i].x = x1;
645                 lpPoints[i].y = y1;
646                 lpPoints[i+1].x = x2;
647                 lpPoints[i+1].y = y2;
648                 lpPoints[i+2].x = x3;
649                 lpPoints[i+2].y = y3;
650                 i = i + 3;
651                 break;
652         }
653         
654         bp += 1;
655     }
657     bool done = false;
658     bool circular = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
659     bool polygon = false;
660     bool ellipse = false;
661     
662     if (moves == 1 && moves+lines == nodes && circular) {
663         polygon = true;
664     }
665     else if (moves == 1 && nodes == 5 && moves+curves == nodes && circular) {
666         if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
667             lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
668             lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
669             lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
670             lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
671             lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
672         {
673             ellipse = true;
674         }
675     }
677     if (polygon || ellipse) {
678         HPEN hpenTmp = NULL;
679         HPEN hpenOld = NULL;
680         HBRUSH hbrushTmp = NULL;
681         HBRUSH hbrushOld = NULL;
683         if (!stroke_and_fill) {
684             if (fill_only) {
685                 hpenTmp = (HPEN) GetStockObject(NULL_PEN);
686                 hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
687             }
688             else { // if (stroke_only)
689                 hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
690                 hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
691             }
692         }
694         if (polygon) {
695             Polygon( hdc, lpPoints, nodes );
696         }
697         else if (ellipse) {
698             Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
699         }
700         
701         done = true;
703         if (hpenOld)
704             SelectObject( hdc, hpenOld );
705         if (hpenTmp)
706             DeleteObject( hpenTmp );
707         if (hbrushOld)
708             SelectObject( hdc, hbrushOld );
709         if (hbrushTmp)
710             DeleteObject( hbrushTmp );
711     }
713     delete[] lpPoints;
714     
715     return done;
718 unsigned int
719 PrintEmfWin32::print_bpath(const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox)
721     unsigned int closed;
722     NR::Matrix tf = *transform;
724     simple_shape = print_simple_shape(bp, &tf, pbox);
726     if (simple_shape)
727         return TRUE;
728     
729     BeginPath( hdc );
730     closed = FALSE;
731     while (bp->code != NR_END) {
732         using NR::X;
733         using NR::Y;
735         NR::Point p1(bp->c(1) * tf);
736         NR::Point p2(bp->c(2) * tf);
737         NR::Point p3(bp->c(3) * tf);
739         p1[X] = (p1[X] * IN_PER_PX * dwDPI);
740         p2[X] = (p2[X] * IN_PER_PX * dwDPI);
741         p3[X] = (p3[X] * IN_PER_PX * dwDPI);
742         p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
743         p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
744         p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
746         LONG const x1 = (LONG) round(p1[X]);
747         LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
748         LONG const x2 = (LONG) round(p2[X]);
749         LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
750         LONG const x3 = (LONG) round(p3[X]);
751         LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
753         switch (bp->code) {
754             case NR_MOVETO:
755                 if (closed) {
756                     CloseFigure( hdc );
757                 }
758                 closed = TRUE;
759                 MoveToEx( hdc, x3, y3, NULL );
760                 break;
761             case NR_MOVETO_OPEN:
762                 if (closed) {
763                     CloseFigure( hdc );
764                 }
765                 closed = FALSE;
766                 MoveToEx( hdc, x3, y3, NULL );
767                 break;
768             case NR_LINETO:
769                 LineTo( hdc, x3, y3 );
770                 break;
771             case NR_CURVETO:
772             {
773                 POINT pt[3];
774                 pt[0].x = x1;
775                 pt[0].y = y1;
776                 pt[1].x = x2;
777                 pt[1].y = y2;
778                 pt[2].x = x3;
779                 pt[2].y = y3;
781                 PolyBezierTo( hdc, pt, 3 );
782                 break;
783             }
784             default:
785                 break;
786         }
787         bp += 1;
788     }
789     if (closed) {
790         CloseFigure( hdc );
791     }
792     EndPath( hdc );
794     return closed;
798 bool
799 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
801     return ext->get_param_bool("textToPath");
804 unsigned int
805 PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p,
806               SPStyle const *const style)
808     if (!hdc) return 0;
810     HFONT hfont = NULL;
811     
812 #ifdef USE_PANGO_WIN32
813 /*
814     font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
815     if (tf) {
816         LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
817         tf->Unref();
818         hfont = CreateFontIndirect(lf);
819         g_free(lf);
820     }
821 */
822 #endif
824     if (!hfont) {
825         if (PrintWin32::is_os_wide()) {
826             LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
827             g_assert(lf != NULL);
828             
829             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
830             lf->lfWidth = 0;
831             lf->lfEscapement = 0;
832             lf->lfOrientation = 0;
833             lf->lfWeight =
834                 style->font_weight.value == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
835                 style->font_weight.value == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
836                 style->font_weight.value == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
837                 style->font_weight.value == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
838                 style->font_weight.value == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
839                 style->font_weight.value == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
840                 style->font_weight.value == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
841                 style->font_weight.value == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
842                 style->font_weight.value == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
843                 style->font_weight.value == SP_CSS_FONT_WEIGHT_NORMAL ? FW_NORMAL :
844                 style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD ? FW_BOLD :
845                 style->font_weight.value == SP_CSS_FONT_WEIGHT_LIGHTER ? FW_EXTRALIGHT :
846                 style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLDER ? FW_EXTRABOLD :
847                 FW_NORMAL;
848             lf->lfItalic = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);
849             lf->lfUnderline = style->text_decoration.underline;
850             lf->lfStrikeOut = style->text_decoration.line_through;
851             lf->lfCharSet = DEFAULT_CHARSET;
852             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
853             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
854             lf->lfQuality = DEFAULT_QUALITY;
855             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
856             
857             gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
858             wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
859             g_free(unicode_name);
860             
861             hfont = CreateFontIndirectW(lf);
862             
863             g_free(lf);
864         }
865         else {
866             LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
867             g_assert(lf != NULL);
868             
869             lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
870             lf->lfWidth = 0;
871             lf->lfEscapement = 0;
872             lf->lfOrientation = 0;
873             lf->lfWeight =
874                 style->font_weight.value == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
875                 style->font_weight.value == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
876                 style->font_weight.value == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
877                 style->font_weight.value == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
878                 style->font_weight.value == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
879                 style->font_weight.value == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
880                 style->font_weight.value == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
881                 style->font_weight.value == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
882                 style->font_weight.value == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
883                 style->font_weight.value == SP_CSS_FONT_WEIGHT_NORMAL ? FW_NORMAL :
884                 style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD ? FW_BOLD :
885                 style->font_weight.value == SP_CSS_FONT_WEIGHT_LIGHTER ? FW_EXTRALIGHT :
886                 style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLDER ? FW_EXTRABOLD :
887                 FW_NORMAL;
888             lf->lfItalic = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);
889             lf->lfUnderline = style->text_decoration.underline;
890             lf->lfStrikeOut = style->text_decoration.line_through;
891             lf->lfCharSet = DEFAULT_CHARSET;
892             lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
893             lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
894             lf->lfQuality = DEFAULT_QUALITY;
895             lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
896             
897             strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
899             hfont = CreateFontIndirectA(lf);
900             
901             g_free(lf);
902         }
903     }
904     
905     HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
907     float rgb[3];
908     sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
909     SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
911     int align =
912         style->text_align.value == SP_CSS_TEXT_ALIGN_RIGHT ? TA_RIGHT :
913         style->text_align.value == SP_CSS_TEXT_ALIGN_CENTER ? TA_CENTER : TA_LEFT;
914     SetTextAlign(hdc, TA_BASELINE | align);
915     SetBkMode(hdc, TRANSPARENT);
917     NR::Matrix tf = m_tr_stack.top();
919     p = p * tf;
920     p[NR::X] = (p[NR::X] * IN_PER_PX * dwDPI);
921     p[NR::Y] = (p[NR::Y] * IN_PER_PX * dwDPI);
923     LONG const xpos = (LONG) round(p[NR::X]);
924     LONG const ypos = (LONG) round(rc.bottom-p[NR::Y]);
926     if (PrintWin32::is_os_wide()) {
927         gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
928         TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
929     }
930     else {
931         TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text));
932     }
934     SelectObject(hdc, hfontOld);
935     DeleteObject(hfont);
936     
937     return 0;
940 void
941 PrintEmfWin32::init (void)
943     Inkscape::Extension::Extension * ext;
945     /* EMF print */
946     ext = Inkscape::Extension::build_from_mem(
947         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
948         "<name>Enhanced Metafile Print</name>\n"
949         "<id>org.inkscape.print.emf.win32</id>\n"
950         "<param name=\"destination\" type=\"string\"></param>\n"
951         "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
952         "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
953         "<print/>\n"
954         "</inkscape-extension>", new PrintEmfWin32());
956     return;
960 }  /* namespace Internal */
961 }  /* namespace Extension */
962 }  /* namespace Inkscape */
964 #endif /* WIN32 */
966 /*
967   Local Variables:
968   mode:c++
969   c-file-style:"stroustrup"
970   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
971   indent-tabs-mode:nil
972   fill-column:99
973   End:
974 */
975 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :