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