f9b65875acf0b11086975c5d97128082f957c567
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-pixblock.h"
45 #include <libnr/n-art-bpath-2geom.h>
46 #include "display/canvas-bpath.h"
47 #include "sp-item.h"
49 #include "glib.h"
50 #include "gtk/gtkdialog.h"
51 #include "gtk/gtkbox.h"
52 #include "gtk/gtkstock.h"
54 #include "glibmm/i18n.h"
55 #include "enums.h"
56 #include "document.h"
57 #include "style.h"
58 #include "sp-paint-server.h"
59 #include "inkscape_version.h"
61 #include "libnrtype/FontFactory.h"
62 #include "libnrtype/font-instance.h"
63 #include "libnrtype/font-style-to-pos.h"
65 #include "win32.h"
66 #include "emf-win32-print.h"
68 #include "unit-constants.h"
70 #include "extension/extension.h"
71 #include "extension/system.h"
72 #include "extension/print.h"
74 #include "io/sys.h"
76 #include "macros.h"
78 #define WIN32_LEAN_AND_MEAN
79 #include <windows.h>
81 namespace Inkscape {
82 namespace Extension {
83 namespace Internal {
85 static float dwDPI = 2540;
88 PrintEmfWin32::PrintEmfWin32 (void):
89 hdc(NULL),
90 hbrush(NULL),
91 hbrushOld(NULL),
92 hpen(NULL),
93 fill_path(NULL),
94 stroke_and_fill(false),
95 fill_only(false),
96 simple_shape(false)
97 {
98 }
101 PrintEmfWin32::~PrintEmfWin32 (void)
102 {
103 if (hdc) {
104 HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
105 if ( metafile ) {
106 DeleteEnhMetaFile( metafile );
107 }
108 DeleteDC( hdc );
109 }
111 /* restore default signal handling for SIGPIPE */
112 #if !defined(_WIN32) && !defined(__WIN32__)
113 (void) signal(SIGPIPE, SIG_DFL);
114 #endif
115 return;
116 }
119 unsigned int
120 PrintEmfWin32::setup (Inkscape::Extension::Print *mod)
121 {
122 return TRUE;
123 }
126 unsigned int
127 PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
128 {
129 gchar const *utf8_fn = mod->get_param_string("destination");
131 gsize bytesRead = 0;
132 gsize bytesWritten = 0;
133 GError* error = NULL;
134 gchar *local_fn =
135 g_filename_from_utf8( utf8_fn, -1, &bytesRead, &bytesWritten, &error );
137 if (local_fn == NULL) {
138 return 1;
139 }
141 CHAR *ansi_uri = (CHAR *) local_fn;
142 gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
143 WCHAR *unicode_uri = (WCHAR *) unicode_fn;
145 // width and height in px
146 _width = sp_document_width(doc);
147 _height = sp_document_height(doc);
149 NRRect d;
150 bool pageBoundingBox;
151 pageBoundingBox = mod->get_param_bool("pageBoundingBox");
152 if (pageBoundingBox) {
153 d.x0 = d.y0 = 0;
154 d.x1 = _width;
155 d.y1 = _height;
156 } else {
157 SPItem* doc_item = SP_ITEM(sp_document_root(doc));
158 sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);
159 }
161 d.x0 *= IN_PER_PX;
162 d.y0 *= IN_PER_PX;
163 d.x1 *= IN_PER_PX;
164 d.y1 *= IN_PER_PX;
166 float dwInchesX = (d.x1 - d.x0);
167 float dwInchesY = (d.y1 - d.y0);
169 // dwInchesX x dwInchesY in .01mm units
170 SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );
172 // Get a Reference DC
173 HDC hScreenDC = GetDC( NULL );
175 // Get the physical characteristics of the reference DC
176 int PixelsX = GetDeviceCaps( hScreenDC, HORZRES );
177 int PixelsY = GetDeviceCaps( hScreenDC, VERTRES );
178 int MMX = GetDeviceCaps( hScreenDC, HORZSIZE );
179 int MMY = GetDeviceCaps( hScreenDC, VERTSIZE );
181 CHAR buff[1024];
182 ZeroMemory(buff, sizeof(buff));
183 snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", INKSCAPE_VERSION, __DATE__);
184 INT len = strlen(buff);
185 CHAR *p1 = strrchr(ansi_uri, '\\');
186 CHAR *p2 = strrchr(ansi_uri, '/');
187 CHAR *p = MAX(p1, p2);
188 if (p)
189 p++;
190 else
191 p = ansi_uri;
192 snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p);
194 // Create the Metafile
195 if (PrintWin32::is_os_wide()) {
196 WCHAR wbuff[1024];
197 ZeroMemory(wbuff, sizeof(wbuff));
198 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0]));
199 hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff );
200 }
201 else {
202 hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, buff );
203 }
205 // Release the reference DC
206 ReleaseDC( NULL, hScreenDC );
208 // Did we get a good metafile?
209 if (hdc == NULL)
210 {
211 g_free(local_fn);
212 g_free(unicode_fn);
213 return 1;
214 }
216 // Anisotropic mapping mode
217 SetMapMode( hdc, MM_ANISOTROPIC );
219 // Set the Windows extent
220 int windowextX = (int) ceil(dwInchesX*dwDPI);
221 int windowextY = (int) ceil(dwInchesY*dwDPI);
222 SetWindowExtEx( hdc, windowextX, windowextY, NULL );
224 // Set the viewport extent to reflect
225 // dwInchesX" x dwInchesY" in device units
226 int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX);
227 int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY);
228 SetViewportExtEx( hdc, viewportextX, viewportextY, NULL );
230 if (1) {
231 snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
232 GdiComment(hdc, strlen(buff), (BYTE*) buff);
234 snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
235 GdiComment(hdc, strlen(buff), (BYTE*) buff);
236 }
238 SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
240 g_free(local_fn);
241 g_free(unicode_fn);
243 m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, sp_document_height(doc)));
245 return 0;
246 }
249 unsigned int
250 PrintEmfWin32::finish (Inkscape::Extension::Print *mod)
251 {
252 if (!hdc) return 0;
254 flush_fill(); // flush any pending fills
256 HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
257 if ( metafile ) {
258 DeleteEnhMetaFile( metafile );
259 }
260 DeleteDC( hdc );
262 hdc = NULL;
264 return 0;
265 }
268 unsigned int
269 PrintEmfWin32::comment (Inkscape::Extension::Print * module,
270 const char *comment)
271 {
272 if (!hdc) return 0;
274 flush_fill(); // flush any pending fills
276 return 0;
277 }
280 int
281 PrintEmfWin32::create_brush(SPStyle const *style)
282 {
283 float rgb[3];
285 if (style) {
286 float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
287 if (opacity <= 0.0)
288 return 1;
290 sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
291 hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
292 hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
294 SetPolyFillMode( hdc,
295 style->fill_rule.computed == 0 ? WINDING :
296 style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
297 } else { // if (!style)
298 hbrush = CreateSolidBrush( RGB(255, 255, 255) );
299 hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
300 SetPolyFillMode( hdc, ALTERNATE );
301 }
303 return 0;
304 }
307 void
308 PrintEmfWin32::destroy_brush()
309 {
310 SelectObject( hdc, hbrushOld );
311 if (hbrush)
312 DeleteObject( hbrush );
313 hbrush = NULL;
314 hbrushOld = NULL;
315 }
318 void
319 PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Matrix *transform)
320 {
321 if (style) {
322 float rgb[3];
324 sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
326 LOGBRUSH lb = {0};
327 lb.lbStyle = BS_SOLID;
328 lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
330 int linestyle = PS_SOLID;
331 int linecap = 0;
332 int linejoin = 0;
333 DWORD n_dash = 0;
334 DWORD *dash = NULL;
335 float oldmiterlimit;
337 using Geom::X;
338 using Geom::Y;
340 Geom::Matrix tf = *transform;
342 Geom::Point zero(0, 0);
343 Geom::Point one(1, 1);
344 Geom::Point p0(zero * tf);
345 Geom::Point p1(one * tf);
346 Geom::Point p(p1 - p0);
348 double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
350 DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
352 if (style->stroke_linecap.computed == 0) {
353 linecap = PS_ENDCAP_FLAT;
354 }
355 else if (style->stroke_linecap.computed == 1) {
356 linecap = PS_ENDCAP_ROUND;
357 }
358 else if (style->stroke_linecap.computed == 2) {
359 linecap = PS_ENDCAP_SQUARE;
360 }
362 if (style->stroke_linejoin.computed == 0) {
363 linejoin = PS_JOIN_MITER;
364 }
365 else if (style->stroke_linejoin.computed == 1) {
366 linejoin = PS_JOIN_ROUND;
367 }
368 else if (style->stroke_linejoin.computed == 2) {
369 linejoin = PS_JOIN_BEVEL;
370 }
372 if (style->stroke_dash.n_dash &&
373 style->stroke_dash.dash )
374 {
375 int i = 0;
376 while (linestyle != PS_USERSTYLE &&
377 (i < style->stroke_dash.n_dash)) {
378 if (style->stroke_dash.dash[i] > 0.00000001)
379 linestyle = PS_USERSTYLE;
380 i++;
381 }
383 if (linestyle == PS_USERSTYLE) {
384 n_dash = style->stroke_dash.n_dash;
385 dash = new DWORD[n_dash];
386 for (i = 0; i < style->stroke_dash.n_dash; i++) {
387 dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
388 }
389 }
390 }
392 hpen = ExtCreatePen(
393 PS_GEOMETRIC | linestyle | linecap | linejoin,
394 linewidth,
395 &lb,
396 n_dash,
397 dash );
399 if ( !hpen && linestyle == PS_USERSTYLE ) {
400 hpen = ExtCreatePen(
401 PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
402 linewidth,
403 &lb,
404 0,
405 NULL );
406 }
408 if ( !hpen ) {
409 hpen = CreatePen(
410 PS_SOLID,
411 linewidth,
412 lb.lbColor );
413 }
415 hpenOld = (HPEN) SelectObject( hdc, hpen );
417 if (linejoin == PS_JOIN_MITER) {
418 float miterlimit = style->stroke_miterlimit.value;
419 if (miterlimit < 1)
420 miterlimit = 4.0;
421 SetMiterLimit(
422 hdc,
423 miterlimit * IN_PER_PX * dwDPI,
424 &oldmiterlimit );
425 }
427 if (n_dash) {
428 delete[] dash;
429 }
430 }
431 else { // if (!style)
432 hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
433 hpenOld = (HPEN) SelectObject( hdc, hpen );
434 }
435 }
438 void
439 PrintEmfWin32::destroy_pen()
440 {
441 SelectObject( hdc, hpenOld );
442 if (hpen)
443 DeleteObject( hpen );
444 hpen = NULL;
445 }
448 void
449 PrintEmfWin32::flush_fill()
450 {
451 if (fill_path) {
452 stroke_and_fill = false;
453 fill_only = true;
454 print_bpath(fill_path, fill_transform);
455 fill_only = false;
456 if (!simple_shape)
457 FillPath( hdc );
458 destroy_brush();
459 delete[] fill_path;
460 fill_path = NULL;
461 }
462 }
465 NArtBpath *
466 PrintEmfWin32::copy_bpath(const NArtBpath *bp)
467 {
468 NArtBpath *tmp = (NArtBpath *) bp;
469 int num = 1;
471 while (tmp->code != NR_END) {
472 num++;
473 tmp += 1;
474 }
476 tmp = new NArtBpath[num];
477 while (num--) {
478 tmp[num] = bp[num];
479 }
481 return tmp;
482 }
485 int
486 PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2)
487 {
488 if (!bp1 || !bp2) {
489 return 1;
490 }
492 while (bp1->code != NR_END && bp2->code != NR_END) {
493 if (bp1->code != bp2->code) {
494 return 1;
495 }
497 if ( fabs(bp1->x1 - bp2->x1) > 0.00000001 ||
498 fabs(bp1->y1 - bp2->y1) > 0.00000001 ||
499 fabs(bp1->x2 - bp2->x2) > 0.00000001 ||
500 fabs(bp1->y2 - bp2->y2) > 0.00000001 ||
501 fabs(bp1->x3 - bp2->x3) > 0.00000001 ||
502 fabs(bp1->y3 - bp2->y3) > 0.00000001 )
503 {
504 return 1;
505 }
507 bp1 += 1;
508 bp2 += 1;
509 }
511 return bp1->code != NR_END || bp2->code != NR_END;
512 }
514 unsigned int
515 PrintEmfWin32::bind(Inkscape::Extension::Print *mod, Geom::Matrix const *transform, float opacity)
516 {
517 Geom::Matrix tr = *transform;
519 if (m_tr_stack.size()) {
520 Geom::Matrix tr_top = m_tr_stack.top();
521 m_tr_stack.push(tr * tr_top);
522 } else {
523 m_tr_stack.push(tr);
524 }
526 return 1;
527 }
529 unsigned int
530 PrintEmfWin32::release(Inkscape::Extension::Print *mod)
531 {
532 m_tr_stack.pop();
533 return 1;
534 }
536 unsigned int
537 PrintEmfWin32::fill(Inkscape::Extension::Print *mod,
538 Geom::PathVector const &pathv, Geom::Matrix const *transform, SPStyle const *style,
539 NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
540 {
541 if (!hdc) return 0;
543 Geom::Matrix tf = m_tr_stack.top();
545 flush_fill(); // flush any pending fills
547 if (style->fill.isColor()) {
548 if (create_brush(style))
549 return 0;
550 } else {
551 // create_brush(NULL);
552 return 0;
553 }
555 NArtBpath * bpath = BPath_from_2GeomPath(pathv);
556 fill_path = copy_bpath( bpath );
557 g_free(bpath);
558 fill_transform = tf;
560 // postpone fill in case of stroke-and-fill
562 return 0;
563 }
566 unsigned int
567 PrintEmfWin32::stroke (Inkscape::Extension::Print *mod,
568 Geom::PathVector const &pathv, const Geom::Matrix *transform, const SPStyle *style,
569 const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)
570 {
571 if (!hdc) return 0;
573 Geom::Matrix tf = m_tr_stack.top();
575 NArtBpath * bpath = BPath_from_2GeomPath(pathv);
577 stroke_and_fill = ( cmp_bpath( bpath, fill_path ) == 0 );
579 if (!stroke_and_fill) {
580 flush_fill(); // flush any pending fills
581 }
583 if (style->stroke.isColor()) {
584 create_pen(style, &tf);
585 } else {
586 // create_pen(NULL, &tf);
587 return 0;
588 }
590 print_bpath(bpath, tf);
592 if (stroke_and_fill) {
593 if (!simple_shape)
594 StrokeAndFillPath( hdc );
595 destroy_brush();
596 delete[] fill_path;
597 fill_path = NULL;
598 } else {
599 if (!simple_shape)
600 StrokePath( hdc );
601 }
603 g_free(bpath);
604 destroy_pen();
606 return 0;
607 }
610 bool
611 PrintEmfWin32::print_simple_shape(const NArtBpath *bpath, const Geom::Matrix &transform)
612 {
613 NR::Matrix tf = transform;
614 const NArtBpath *bp = bpath;
616 int nodes = 0;
617 int moves = 0;
618 int lines = 0;
619 int curves = 0;
621 while (bp->code != NR_END) {
622 nodes++;
623 switch (bp->code) {
624 case NR_MOVETO:
625 case NR_MOVETO_OPEN:
626 moves++;
627 break;
628 case NR_LINETO:
629 lines++;
630 break;
631 case NR_CURVETO:
632 curves++;
633 break;
634 }
635 bp += 1;
636 }
638 if (!nodes)
639 return false;
641 POINT *lpPoints = new POINT[moves + lines + curves*3];
642 int i = 0;
643 bp = bpath;
644 while (bp->code != NR_END)
645 {
646 using Geom::X;
647 using Geom::Y;
649 Geom::Point p1(bp->c(1) * tf);
650 Geom::Point p2(bp->c(2) * tf);
651 Geom::Point p3(bp->c(3) * tf);
653 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
654 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
655 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
656 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
657 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
658 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
660 LONG const x1 = (LONG) round(p1[X]);
661 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
662 LONG const x2 = (LONG) round(p2[X]);
663 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
664 LONG const x3 = (LONG) round(p3[X]);
665 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
667 switch (bp->code) {
668 case NR_MOVETO:
669 case NR_MOVETO_OPEN:
670 case NR_LINETO:
671 lpPoints[i].x = x3;
672 lpPoints[i].y = y3;
673 i = i + 1;
674 break;
675 case NR_CURVETO:
676 lpPoints[i].x = x1;
677 lpPoints[i].y = y1;
678 lpPoints[i+1].x = x2;
679 lpPoints[i+1].y = y2;
680 lpPoints[i+2].x = x3;
681 lpPoints[i+2].y = y3;
682 i = i + 3;
683 break;
684 }
686 bp += 1;
687 }
689 bool done = false;
690 bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
691 bool polygon = false;
692 bool polyline = false;
693 bool rectangle = false;
694 bool ellipse = false;
696 if (moves == 1 && moves+lines == nodes && closed) {
697 polygon = true;
698 if (nodes==5) {
699 if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
700 lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
701 {
702 rectangle = true;
703 }
704 }
705 }
706 else if (moves == 1 && moves+lines == nodes) {
707 polyline = true;
708 }
709 else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
710 if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
711 lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
712 lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
713 lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
714 lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
715 lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
716 {
717 ellipse = true;
718 }
719 }
721 if (polygon || polyline || ellipse) {
722 HPEN hpenTmp = NULL;
723 HPEN hpenOld = NULL;
724 HBRUSH hbrushTmp = NULL;
725 HBRUSH hbrushOld = NULL;
727 if (!stroke_and_fill) {
728 if (fill_only) {
729 hpenTmp = (HPEN) GetStockObject(NULL_PEN);
730 hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
731 }
732 else { // if (stroke_only)
733 hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
734 hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
735 }
736 }
738 if (polygon) {
739 if (rectangle)
740 Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y );
741 else
742 Polygon( hdc, lpPoints, nodes );
743 }
744 else if (polyline) {
745 Polyline( hdc, lpPoints, nodes );
746 }
747 else if (ellipse) {
748 Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
749 }
751 done = true;
753 if (hpenOld)
754 SelectObject( hdc, hpenOld );
755 if (hpenTmp)
756 DeleteObject( hpenTmp );
757 if (hbrushOld)
758 SelectObject( hdc, hbrushOld );
759 if (hbrushTmp)
760 DeleteObject( hbrushTmp );
761 }
763 delete[] lpPoints;
765 return done;
766 }
768 unsigned int
769 PrintEmfWin32::print_bpath(NArtBpath const *bp, Geom::Matrix const &transform)
770 {
771 unsigned int closed;
772 NR::Matrix tf = transform;
774 simple_shape = print_simple_shape(bp, transform);
776 if (simple_shape)
777 return TRUE;
779 BeginPath( hdc );
780 closed = FALSE;
781 while (bp->code != NR_END) {
782 using Geom::X;
783 using Geom::Y;
785 Geom::Point p1(bp->c(1) * tf);
786 Geom::Point p2(bp->c(2) * tf);
787 Geom::Point p3(bp->c(3) * tf);
789 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
790 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
791 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
792 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
793 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
794 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
796 LONG const x1 = (LONG) round(p1[X]);
797 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
798 LONG const x2 = (LONG) round(p2[X]);
799 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
800 LONG const x3 = (LONG) round(p3[X]);
801 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
803 switch (bp->code) {
804 case NR_MOVETO:
805 if (closed) {
806 CloseFigure( hdc );
807 }
808 closed = TRUE;
809 MoveToEx( hdc, x3, y3, NULL );
810 break;
811 case NR_MOVETO_OPEN:
812 if (closed) {
813 CloseFigure( hdc );
814 }
815 closed = FALSE;
816 MoveToEx( hdc, x3, y3, NULL );
817 break;
818 case NR_LINETO:
819 LineTo( hdc, x3, y3 );
820 break;
821 case NR_CURVETO:
822 {
823 POINT pt[3];
824 pt[0].x = x1;
825 pt[0].y = y1;
826 pt[1].x = x2;
827 pt[1].y = y2;
828 pt[2].x = x3;
829 pt[2].y = y3;
831 PolyBezierTo( hdc, pt, 3 );
832 break;
833 }
834 default:
835 break;
836 }
837 bp += 1;
838 }
839 if (closed) {
840 CloseFigure( hdc );
841 }
842 EndPath( hdc );
844 return closed;
845 }
848 bool
849 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
850 {
851 return ext->get_param_bool("textToPath");
852 }
854 unsigned int
855 PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, Geom::Point p,
856 SPStyle const *const style)
857 {
858 if (!hdc) return 0;
860 HFONT hfont = NULL;
862 #ifdef USE_PANGO_WIN32
863 /*
864 font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
865 if (tf) {
866 LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
867 tf->Unref();
868 hfont = CreateFontIndirect(lf);
869 g_free(lf);
870 }
871 */
872 #endif
874 if (!hfont) {
875 if (PrintWin32::is_os_wide()) {
876 LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
877 g_assert(lf != NULL);
879 lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
880 lf->lfWidth = 0;
881 lf->lfEscapement = 0;
882 lf->lfOrientation = 0;
883 lf->lfWeight =
884 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
885 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
886 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
887 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
888 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
889 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
890 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
891 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
892 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
893 FW_NORMAL;
894 lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
895 lf->lfUnderline = style->text_decoration.underline;
896 lf->lfStrikeOut = style->text_decoration.line_through;
897 lf->lfCharSet = DEFAULT_CHARSET;
898 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
899 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
900 lf->lfQuality = DEFAULT_QUALITY;
901 lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
903 gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
904 wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
905 g_free(unicode_name);
907 hfont = CreateFontIndirectW(lf);
909 g_free(lf);
910 }
911 else {
912 LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
913 g_assert(lf != NULL);
915 lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
916 lf->lfWidth = 0;
917 lf->lfEscapement = 0;
918 lf->lfOrientation = 0;
919 lf->lfWeight =
920 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
921 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
922 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
923 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
924 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
925 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
926 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
927 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
928 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
929 FW_NORMAL;
930 lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
931 lf->lfUnderline = style->text_decoration.underline;
932 lf->lfStrikeOut = style->text_decoration.line_through;
933 lf->lfCharSet = DEFAULT_CHARSET;
934 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
935 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
936 lf->lfQuality = DEFAULT_QUALITY;
937 lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
939 strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
941 hfont = CreateFontIndirectA(lf);
943 g_free(lf);
944 }
945 }
947 HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
949 float rgb[3];
950 sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
951 SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
953 // Text alignment:
954 // - (x,y) coordinates received by this filter are those of the point where the text
955 // actually starts, and already takes into account the text object's alignment;
956 // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
957 SetTextAlign(hdc, TA_BASELINE | TA_LEFT);
959 // Transparent text background
960 SetBkMode(hdc, TRANSPARENT);
962 Geom::Matrix tf = m_tr_stack.top();
964 p = p * tf;
965 p[Geom::X] = (p[Geom::X] * IN_PER_PX * dwDPI);
966 p[Geom::Y] = (p[Geom::Y] * IN_PER_PX * dwDPI);
968 LONG const xpos = (LONG) round(p[Geom::X]);
969 LONG const ypos = (LONG) round(rc.bottom-p[Geom::Y]);
971 if (PrintWin32::is_os_wide()) {
972 gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
973 TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
974 }
975 else {
976 TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text));
977 }
979 SelectObject(hdc, hfontOld);
980 DeleteObject(hfont);
982 return 0;
983 }
985 void
986 PrintEmfWin32::init (void)
987 {
988 Inkscape::Extension::Extension * ext;
990 /* EMF print */
991 ext = Inkscape::Extension::build_from_mem(
992 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
993 "<name>Enhanced Metafile Print</name>\n"
994 "<id>org.inkscape.print.emf.win32</id>\n"
995 "<param name=\"destination\" type=\"string\"></param>\n"
996 "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
997 "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
998 "<print/>\n"
999 "</inkscape-extension>", new PrintEmfWin32());
1001 return;
1002 }
1005 } /* namespace Internal */
1006 } /* namespace Extension */
1007 } /* namespace Inkscape */
1009 #endif /* WIN32 */
1011 /*
1012 Local Variables:
1013 mode:c++
1014 c-file-style:"stroustrup"
1015 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1016 indent-tabs-mode:nil
1017 fill-column:99
1018 End:
1019 */
1020 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :