e696df06d0360cce599e85e026c2b7a8fad24a32
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)
103 {
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;
117 }
120 unsigned int
121 PrintEmfWin32::setup (Inkscape::Extension::Print *mod)
122 {
123 return TRUE;
124 }
127 unsigned int
128 PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
129 {
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;
213 }
216 unsigned int
217 PrintEmfWin32::finish (Inkscape::Extension::Print *mod)
218 {
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;
232 }
235 unsigned int
236 PrintEmfWin32::comment (Inkscape::Extension::Print * module,
237 const char *comment)
238 {
239 if (!hdc) return 0;
241 flush_fill(); // flush any pending fills
243 return 0;
244 }
247 int
248 PrintEmfWin32::create_brush(SPStyle const *style)
249 {
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;
271 }
274 void
275 PrintEmfWin32::destroy_brush()
276 {
277 SelectObject( hdc, hbrushOld );
278 if (hbrush)
279 DeleteObject( hbrush );
280 hbrush = NULL;
281 hbrushOld = NULL;
282 }
285 void
286 PrintEmfWin32::create_pen(SPStyle const *style, const NR::Matrix *transform)
287 {
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 }
402 }
405 void
406 PrintEmfWin32::destroy_pen()
407 {
408 SelectObject( hdc, hpenOld );
409 if (hpen)
410 DeleteObject( hpen );
411 hpen = NULL;
412 }
415 void
416 PrintEmfWin32::flush_fill()
417 {
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 }
429 }
432 NArtBpath *
433 PrintEmfWin32::copy_bpath(const NArtBpath *bp)
434 {
435 NArtBpath *tmp = (NArtBpath *) bp;
436 int num = 1;
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;
449 }
452 int
453 PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2)
454 {
455 if (!bp1 || !bp2) {
456 return 1;
457 }
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 }
474 bp1 += 1;
475 bp2 += 1;
476 }
478 return bp1->code != NR_END || bp2->code != NR_END;
479 }
481 unsigned int
482 PrintEmfWin32::bind(Inkscape::Extension::Print *mod, NR::Matrix const *transform, float opacity)
483 {
484 NR::Matrix tr = *transform;
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;
494 }
496 unsigned int
497 PrintEmfWin32::release(Inkscape::Extension::Print *mod)
498 {
499 m_tr_stack.pop();
500 return 1;
501 }
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)
507 {
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;
531 }
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)
538 {
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;
575 }
578 bool
579 PrintEmfWin32::print_simple_shape(const NArtBpath *bpath, const NR::Matrix *transform, NRRect const *pbox)
580 {
581 NR::Matrix tf = *transform;
582 const NArtBpath *bp = bpath;
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;
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 }
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;
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 }
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;
715 return done;
716 }
718 unsigned int
719 PrintEmfWin32::print_bpath(const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox)
720 {
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;
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;
795 }
798 bool
799 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
800 {
801 return ext->get_param_bool("textToPath");
802 }
804 unsigned int
805 PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p,
806 SPStyle const *const style)
807 {
808 if (!hdc) return 0;
810 HFONT hfont = NULL;
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);
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;
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);
861 hfont = CreateFontIndirectW(lf);
863 g_free(lf);
864 }
865 else {
866 LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
867 g_assert(lf != NULL);
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;
897 strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
899 hfont = CreateFontIndirectA(lf);
901 g_free(lf);
902 }
903 }
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);
937 return 0;
938 }
940 void
941 PrintEmfWin32::init (void)
942 {
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;
957 }
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 :