]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/dcps.cpp
wxMimeTypesManagerImpl::GetFileTypeFromMimeType() implemented
[wxWidgets.git] / src / gtk1 / dcps.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dcps.cpp
3 // Purpose: wxPostScriptDC implementation
4 // Author: Julian Smart, Robert Roebling, Markus Holzhem
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifndef __WXMOTIF__
13 #ifdef __GNUG__
14 #pragma implementation
15 #pragma interface
16 #endif
17 #endif
18
19 #include "wx/defs.h"
20
21 #if wxUSE_POSTSCRIPT
22
23 #include "wx/postscrp.h"
24 #include "wx/dcmemory.h"
25 #include "wx/utils.h"
26 #include "wx/intl.h"
27 #include "wx/filedlg.h"
28 #include "wx/app.h"
29 #include "wx/msgdlg.h"
30 #include "wx/image.h"
31 #include "wx/log.h"
32
33 #include <math.h>
34
35 #ifdef __WXGTK__
36 #include "gdk/gdk.h"
37 #include "gtk/gtk.h"
38 #endif
39
40 //-----------------------------------------------------------------------------
41 // start and end of document/page
42 //-----------------------------------------------------------------------------
43
44 static const char *wxPostScriptHeaderEllipse = "\
45 /ellipsedict 8 dict def\n\
46 ellipsedict /mtrx matrix put\n\
47 /ellipse {\n\
48 ellipsedict begin\n\
49 /endangle exch def\n\
50 /startangle exch def\n\
51 /yrad exch def\n\
52 /xrad exch def\n\
53 /y exch def\n\
54 /x exch def\n\
55 /savematrix mtrx currentmatrix def\n\
56 x y translate\n\
57 xrad yrad scale\n\
58 0 0 1 startangle endangle arc\n\
59 savematrix setmatrix\n\
60 end\n\
61 } def\n\
62 ";
63
64 static const char *wxPostScriptHeaderEllipticArc= "\
65 /ellipticarcdict 8 dict def\n\
66 ellipticarcdict /mtrx matrix put\n\
67 /ellipticarc\n\
68 { ellipticarcdict begin\n\
69 /do_fill exch def\n\
70 /endangle exch def\n\
71 /startangle exch def\n\
72 /yrad exch def\n\
73 /xrad exch def \n\
74 /y exch def\n\
75 /x exch def\n\
76 /savematrix mtrx currentmatrix def\n\
77 x y translate\n\
78 xrad yrad scale\n\
79 do_fill { 0 0 moveto } if\n\
80 0 0 1 startangle endangle arc\n\
81 savematrix setmatrix\n\
82 do_fill { fill }{ stroke } ifelse\n\
83 end\n\
84 } def\n";
85
86 static const char *wxPostScriptHeaderSpline = "\
87 /DrawSplineSection {\n\
88 /y3 exch def\n\
89 /x3 exch def\n\
90 /y2 exch def\n\
91 /x2 exch def\n\
92 /y1 exch def\n\
93 /x1 exch def\n\
94 /xa x1 x2 x1 sub 0.666667 mul add def\n\
95 /ya y1 y2 y1 sub 0.666667 mul add def\n\
96 /xb x3 x2 x3 sub 0.666667 mul add def\n\
97 /yb y3 y2 y3 sub 0.666667 mul add def\n\
98 x1 y1 lineto\n\
99 xa ya xb yb x3 y3 curveto\n\
100 } def\n\
101 ";
102
103 static const char *wxPostScriptHeaderColourImage = "\
104 % define 'colorimage' if it isn't defined\n\
105 % ('colortogray' and 'mergeprocs' come from xwd2ps\n\
106 % via xgrab)\n\
107 /colorimage where % do we know about 'colorimage'?\n\
108 { pop } % yes: pop off the 'dict' returned\n\
109 { % no: define one\n\
110 /colortogray { % define an RGB->I function\n\
111 /rgbdata exch store % call input 'rgbdata'\n\
112 rgbdata length 3 idiv\n\
113 /npixls exch store\n\
114 /rgbindx 0 store\n\
115 0 1 npixls 1 sub {\n\
116 grays exch\n\
117 rgbdata rgbindx get 20 mul % Red\n\
118 rgbdata rgbindx 1 add get 32 mul % Green\n\
119 rgbdata rgbindx 2 add get 12 mul % Blue\n\
120 add add 64 idiv % I = .5G + .31R + .18B\n\
121 put\n\
122 /rgbindx rgbindx 3 add store\n\
123 } for\n\
124 grays 0 npixls getinterval\n\
125 } bind def\n\
126 \n\
127 % Utility procedure for colorimage operator.\n\
128 % This procedure takes two procedures off the\n\
129 % stack and merges them into a single procedure.\n\
130 \n\
131 /mergeprocs { % def\n\
132 dup length\n\
133 3 -1 roll\n\
134 dup\n\
135 length\n\
136 dup\n\
137 5 1 roll\n\
138 3 -1 roll\n\
139 add\n\
140 array cvx\n\
141 dup\n\
142 3 -1 roll\n\
143 0 exch\n\
144 putinterval\n\
145 dup\n\
146 4 2 roll\n\
147 putinterval\n\
148 } bind def\n\
149 \n\
150 /colorimage { % def\n\
151 pop pop % remove 'false 3' operands\n\
152 {colortogray} mergeprocs\n\
153 image\n\
154 } bind def\n\
155 } ifelse % end of 'false' case\n\
156 ";
157
158 static char wxPostScriptHeaderReencodeISO1[] =
159 "\n/reencodeISO {\n"
160 "dup dup findfont dup length dict begin\n"
161 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n"
162 "/Encoding ISOLatin1Encoding def\n"
163 "currentdict end definefont\n"
164 "} def\n"
165 "/ISOLatin1Encoding [\n"
166 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
167 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
168 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
169 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
170 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n"
171 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n"
172 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n"
173 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n"
174 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n"
175 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n"
176 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n"
177 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
178 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
179 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n"
180 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n";
181
182 static char wxPostScriptHeaderReencodeISO2[] =
183 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n"
184 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n"
185 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n"
186 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n"
187 "/guillemotright/onequarter/onehalf/threequarters/questiondown\n"
188 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n"
189 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n"
190 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n"
191 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n"
192 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n"
193 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n"
194 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n"
195 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n"
196 "/yacute/thorn/ydieresis\n"
197 "] def\n\n";
198
199 //-------------------------------------------------------------------------------
200 // wxPostScriptDC
201 //-------------------------------------------------------------------------------
202
203 wxPostScriptDC::wxPostScriptDC ()
204 {
205 m_pstream = (ofstream*) NULL;
206
207 m_currentRed = 0;
208 m_currentGreen = 0;
209 m_currentBlue = 0;
210
211 m_pageNumber = 0;
212
213 m_clipping = FALSE;
214
215 m_underlinePosition = 0.0;
216 m_underlineThickness = 0.0;
217
218 m_signX = 1; // default x-axis left to right
219 m_signY = -1; // default y-axis bottom up -> top down
220 }
221
222 wxPostScriptDC::wxPostScriptDC (const wxString& file, bool interactive, wxWindow *parent)
223 {
224 m_pstream = (ofstream*) NULL;
225
226 m_currentRed = 0;
227 m_currentGreen = 0;
228 m_currentBlue = 0;
229
230 m_pageNumber = 0;
231
232 m_clipping = FALSE;
233
234 m_underlinePosition = 0.0;
235 m_underlineThickness = 0.0;
236
237 m_signX = 1; // default x-axis left to right
238 m_signY = -1; // default y-axis bottom up -> top down
239
240 Create(file, interactive, parent);
241 }
242
243 bool wxPostScriptDC::Create(const wxString& file, bool interactive, wxWindow *parent)
244 {
245 m_isInteractive = interactive;
246
247 m_title = "";
248 m_filename = file;
249
250 #ifdef __WXMSW__
251 // Can only send to file in Windows
252 wxThePrintSetupData->SetPrinterMode(PS_FILE);
253 #endif
254
255 if (m_isInteractive)
256 {
257 if ((m_ok = PrinterDialog (parent) ) == FALSE) return FALSE;
258 }
259 else
260 {
261 m_ok = TRUE;
262 }
263
264 return m_ok;
265 }
266
267 wxPostScriptDC::~wxPostScriptDC ()
268 {
269 if (m_pstream) delete m_pstream;
270 }
271
272 bool wxPostScriptDC::Ok() const
273 {
274 return m_ok;
275 }
276
277 bool wxPostScriptDC::PrinterDialog(wxWindow *parent)
278 {
279 wxPostScriptPrintDialog dialog( parent, _("Printer Settings"), wxPoint(150, 150), wxSize(400, 400),
280 wxDEFAULT_DIALOG_STYLE | wxDIALOG_MODAL );
281 m_ok = (dialog.ShowModal () == wxID_OK);
282
283 if (!m_ok) return FALSE;
284
285 if ((m_filename == "") &&
286 (wxThePrintSetupData->GetPrinterMode() == PS_PREVIEW ||
287 wxThePrintSetupData->GetPrinterMode() == PS_PRINTER))
288 {
289 // steve, 05.09.94
290 #ifdef __VMS__
291 wxThePrintSetupData->SetPrinterFile("preview");
292 #else
293 // For PS_PRINTER action this depends on a Unix-style print spooler
294 // since the wx_printer_file can be destroyed during a session
295 // @@@ TODO: a Windows-style answer for non-Unix
296 char userId[256];
297 wxGetUserId (userId, sizeof (userId) / sizeof (char));
298 char tmp[256];
299 strcpy (tmp, "/tmp/preview_");
300 strcat (tmp, userId);
301 wxThePrintSetupData->SetPrinterFile(tmp);
302 #endif
303 char tmp2[256];
304 strcpy(tmp2, wxThePrintSetupData->GetPrinterFile());
305 strcat (tmp2, ".ps");
306 wxThePrintSetupData->SetPrinterFile(tmp2);
307 m_filename = tmp2;
308 }
309 else if ((m_filename == "") && (wxThePrintSetupData->GetPrinterMode() == PS_FILE))
310 {
311 char *file = wxSaveFileSelector (_("PostScript"), "ps");
312 if (!file)
313 {
314 m_ok = FALSE;
315 return FALSE;
316 }
317 wxThePrintSetupData->SetPrinterFile(file);
318 m_filename = file;
319 m_ok = TRUE;
320 }
321
322 return m_ok;
323 }
324
325 void wxPostScriptDC::SetClippingRegion (long x, long y, long w, long h)
326 {
327 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
328
329 if (m_clipping) return;
330
331 wxDC::SetClippingRegion( x, y, w, h );
332
333 m_clipping = TRUE;
334 *m_pstream << "gsave\n"
335 << "newpath\n"
336 << XLOG2DEV(x) << " " << YLOG2DEV(y) << " moveto\n"
337 << XLOG2DEV(x+w) << " " << YLOG2DEV(y) << " lineto\n"
338 << XLOG2DEV(x+w) << " " << YLOG2DEV(y+h) << " lineto\n"
339 << XLOG2DEV(x) << " " << YLOG2DEV(y+h) << " lineto\n"
340 << "closepath clip newpath\n";
341 }
342
343 void wxPostScriptDC::SetClippingRegion( const wxRegion &WXUNUSED(region) )
344 {
345 }
346
347 void wxPostScriptDC::DestroyClippingRegion()
348 {
349 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
350
351 wxDC::DestroyClippingRegion();
352
353 if (m_clipping)
354 {
355 m_clipping = FALSE;
356 *m_pstream << "grestore\n";
357 }
358 }
359
360 void wxPostScriptDC::Clear()
361 {
362 wxFAIL_MSG( "wxPostScriptDC::Clear not implemented." );
363 }
364
365 void wxPostScriptDC::FloodFill (long WXUNUSED(x), long WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style))
366 {
367 wxFAIL_MSG( "wxPostScriptDC::FloodFill not implemented." );
368 }
369
370 bool wxPostScriptDC::GetPixel (long WXUNUSED(x), long WXUNUSED(y), wxColour * WXUNUSED(col)) const
371 {
372 wxFAIL_MSG( "wxPostScriptDC::GetPixel not implemented." );
373 return FALSE;
374 }
375
376 void wxPostScriptDC::CrossHair (long WXUNUSED(x), long WXUNUSED(y))
377 {
378 wxFAIL_MSG( "wxPostScriptDC::CrossHair not implemented." );
379 }
380
381 void wxPostScriptDC::DrawLine (long x1, long y1, long x2, long y2)
382 {
383 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
384
385 if (m_pen.GetStyle() == wxTRANSPARENT) return;
386
387 SetPen( m_pen );
388
389 *m_pstream << "newpath\n"
390 << XLOG2DEV(x1) << " " << YLOG2DEV (y1) << " moveto\n"
391 << XLOG2DEV(x2) << " " << YLOG2DEV (y2) << " lineto\n"
392 << "stroke\n";
393
394 CalcBoundingBox( x1, y1 );
395 CalcBoundingBox( x2, y2 );
396 }
397
398 #define RAD2DEG 57.29577951308
399
400 void wxPostScriptDC::DrawArc (long x1, long y1, long x2, long y2, long xc, long yc)
401 {
402 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
403
404 long dx = x1 - xc;
405 long dy = y1 - yc;
406 long radius = (long) sqrt(dx*dx+dy*dy);
407 double alpha1, alpha2;
408
409 if (x1 == x2 && y1 == y2)
410 {
411 alpha1 = 0.0;
412 alpha2 = 360.0;
413 } else if (radius == 0.0)
414 {
415 alpha1 = alpha2 = 0.0;
416 } else
417 {
418 alpha1 = (x1 - xc == 0) ?
419 (y1 - yc < 0) ? 90.0 : -90.0 :
420 -atan2(double(y1-yc), double(x1-xc)) * RAD2DEG;
421 alpha2 = (x2 - xc == 0) ?
422 (y2 - yc < 0) ? 90.0 : -90.0 :
423 -atan2(double(y2-yc), double(x2-xc)) * RAD2DEG;
424 }
425 while (alpha1 <= 0) alpha1 += 360;
426 while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between
427 while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree
428 while (alpha2 > 360) alpha2 -= 360;
429
430 if (m_brush.GetStyle() != wxTRANSPARENT)
431 {
432 SetBrush( m_brush );
433 *m_pstream << "newpath\n"
434 << XLOG2DEV(xc) << " "
435 << YLOG2DEV(yc) << " "
436 << XLOG2DEVREL(radius) << " "
437 << YLOG2DEVREL(radius) << " "
438 << alpha1 << " "
439 << alpha2 << " ellipse\n"
440 << XLOG2DEV(xc) << " "
441 << YLOG2DEV(yc) << " lineto\n"
442 << "closepath\n"
443 << "fill\n";
444 }
445
446 if (m_pen.GetStyle() != wxTRANSPARENT)
447 {
448 SetPen( m_pen );
449 *m_pstream << "newpath\n"
450 << XLOG2DEV(xc) << " "
451 << YLOG2DEV(yc) << " "
452 << XLOG2DEVREL(radius) << " "
453 << YLOG2DEVREL(radius) << " "
454 << alpha1 << " "
455 << alpha2 << " ellipse\n"
456 << "stroke\n";
457 }
458
459 CalcBoundingBox( xc-radius, yc-radius );
460 CalcBoundingBox( xc+radius, yc+radius );
461 }
462
463 void wxPostScriptDC::DrawEllipticArc(long x,long y,long w,long h,double sa,double ea)
464 {
465 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
466
467 if (sa>=360 || sa<=-360) sa=sa-int(sa/360)*360;
468 if (ea>=360 || ea<=-360) ea=ea-int(ea/360)*360;
469 if (sa<0) sa+=360;
470 if (ea<0) ea+=360;
471
472 if (sa==ea)
473 {
474 DrawEllipse(x,y,w,h);
475 return;
476 }
477
478 if (m_brush.GetStyle () != wxTRANSPARENT)
479 {
480 SetBrush( m_brush );
481
482 *m_pstream << "newpath\n"
483 << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
484 << XLOG2DEVREL(w/2) << " " << YLOG2DEVREL(h/2) << " "
485 << int(sa) <<" "<< int(ea) << " true ellipticarc\n";
486
487 CalcBoundingBox( x ,y );
488 CalcBoundingBox( x+w, y+h );
489 }
490
491 if (m_pen.GetStyle () != wxTRANSPARENT)
492 {
493 SetPen( m_pen );
494
495 *m_pstream << "newpath\n"
496 << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
497 << XLOG2DEVREL(w/2) << " " << XLOG2DEVREL(h/2) << " "
498 << int(sa) <<" "<< int(ea) << " false ellipticarc\n";
499
500 CalcBoundingBox( x, y );
501 CalcBoundingBox( x+w, y+h );
502 }
503 }
504
505 void wxPostScriptDC::DrawPoint (long x, long y)
506 {
507 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
508
509 if (m_pen.GetStyle() == wxTRANSPARENT) return;
510
511 SetPen (m_pen);
512
513 *m_pstream << "newpath\n"
514 << XLOG2DEV(x) << " " << YLOG2DEV (y) << " moveto\n"
515 << XLOG2DEV(x+1) << " " << YLOG2DEV (y) << " lineto\n"
516 << "stroke\n";
517
518 CalcBoundingBox( x, y );
519 }
520
521 void wxPostScriptDC::DrawPolygon (int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle))
522 {
523 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
524
525 if (n <= 0) return;
526
527 if (m_brush.GetStyle () != wxTRANSPARENT)
528 {
529 SetBrush( m_brush );
530
531 *m_pstream << "newpath\n";
532
533 long xx = XLOG2DEV(points[0].x + xoffset);
534 long yy = YLOG2DEV(points[0].y + yoffset);
535 *m_pstream << xx << " " << yy << " moveto\n";
536 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
537
538 for (int i = 1; i < n; i++)
539 {
540 xx = XLOG2DEV(points[i].x + xoffset);
541 yy = YLOG2DEV(points[i].y + yoffset);
542 *m_pstream << xx << " " << yy << " lineto\n";
543 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
544 }
545 *m_pstream << "fill\n";
546 }
547
548 if (m_pen.GetStyle () != wxTRANSPARENT)
549 {
550 SetPen( m_pen );
551
552 *m_pstream << "newpath\n";
553
554 long xx = XLOG2DEV(points[0].x + xoffset);
555 long yy = YLOG2DEV(points[0].y + yoffset);
556 *m_pstream << xx << " " << yy << " moveto\n";
557 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
558
559 for (int i = 1; i < n; i++)
560 {
561 xx = XLOG2DEV(points[i].x + xoffset);
562 yy = YLOG2DEV(points[i].y + yoffset);
563 *m_pstream << xx << " " << yy << " lineto\n";
564 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
565 }
566
567 *m_pstream << "stroke\n";
568 }
569 }
570
571 void wxPostScriptDC::DrawLines (int n, wxPoint points[], long xoffset, long yoffset)
572 {
573 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
574
575 if (m_pen.GetStyle() == wxTRANSPARENT) return;
576 if (n <= 0) return;
577
578 SetPen (m_pen);
579
580 for (int i=0; i<n ; ++i)
581 {
582 CalcBoundingBox( XLOG2DEV(points[i].x+xoffset), YLOG2DEV(points[i].y+yoffset));
583 }
584
585 *m_pstream << "newpath\n"
586 << XLOG2DEV(points[0].x+xoffset) << " "
587 << YLOG2DEV(points[0].y+yoffset) << " moveto\n";
588
589 for (int i = 1; i < n; i++)
590 {
591 *m_pstream << XLOG2DEV(points[i].x+xoffset) << " "
592 << YLOG2DEV(points[i].y+yoffset) << " lineto\n";
593 }
594
595 *m_pstream << "stroke\n";
596 }
597
598 void wxPostScriptDC::DrawRectangle (long x, long y, long width, long height)
599 {
600 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
601
602 if (m_brush.GetStyle () != wxTRANSPARENT)
603 {
604 SetBrush( m_brush );
605
606 *m_pstream << "newpath\n"
607 << XLOG2DEV(x) << " " << YLOG2DEV(y) << " moveto\n"
608 << XLOG2DEV(x + width) << " " << YLOG2DEV(y) << " lineto\n"
609 << XLOG2DEV(x + width) << " " << YLOG2DEV(y + height) << " lineto\n"
610 << XLOG2DEV(x) << " " << YLOG2DEV(y + height) << " lineto\n"
611 << "closepath\n"
612 << "fill\n";
613
614 CalcBoundingBox( x, y );
615 CalcBoundingBox( x + width, y + height );
616 }
617
618 if (m_pen.GetStyle () != wxTRANSPARENT)
619 {
620 SetPen (m_pen);
621
622 *m_pstream << "newpath\n"
623 << XLOG2DEV(x) << " " << YLOG2DEV(y) << " moveto\n"
624 << XLOG2DEV(x + width) << " " << YLOG2DEV(y) << " lineto\n"
625 << XLOG2DEV(x + width) << " " << YLOG2DEV(y + height) << " lineto\n"
626 << XLOG2DEV(x) << " " << YLOG2DEV(y + height) << " lineto\n"
627 << "closepath\n"
628 << "stroke\n";
629
630 CalcBoundingBox( x, y );
631 CalcBoundingBox( x + width, y + height );
632 }
633 }
634
635 void wxPostScriptDC::DrawRoundedRectangle (long x, long y, long width, long height, double radius)
636 {
637 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
638
639 if (radius < 0.0)
640 {
641 // Now, a negative radius is interpreted to mean
642 // 'the proportion of the smallest X or Y dimension'
643 double smallest = 0.0;
644 if (width < height)
645 smallest = width;
646 else
647 smallest = height;
648 radius = (-radius * smallest);
649 }
650
651 long rad = (long) radius;
652
653 if (m_brush.GetStyle () != wxTRANSPARENT)
654 {
655 SetBrush( m_brush );
656
657 // Draw rectangle anticlockwise
658 *m_pstream << "newpath\n"
659 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 90 180 arc\n"
660 << XLOG2DEV(x) << " " << YLOG2DEV(y + rad) << " moveto\n"
661 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y + height - rad) << " " << XLOG2DEVREL(rad) << " 180 270 arc\n"
662 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + height) << " lineto\n"
663 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + height - rad) << " " << XLOG2DEVREL(rad) << " 270 0 arc\n"
664 << XLOG2DEV(x + width) << " " << YLOG2DEV(y + rad) << " lineto\n"
665 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 0 90 arc\n"
666 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y) << " lineto\n"
667 << "closepath\n"
668 << "fill\n";
669
670 CalcBoundingBox( x, y );
671 CalcBoundingBox( x + width, y + height );
672 }
673
674 if (m_pen.GetStyle () != wxTRANSPARENT)
675 {
676 SetPen (m_pen);
677
678 // Draw rectangle anticlockwise
679 *m_pstream << "newpath\n"
680 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 90 180 arc\n"
681 << XLOG2DEV(x) << " " << YLOG2DEV(y + rad) << " moveto\n"
682 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y + height - rad) << " " << XLOG2DEVREL(rad) << " 180 270 arc\n"
683 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + height) << " lineto\n"
684 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + height - rad) << " " << XLOG2DEVREL(rad) << " 270 0 arc\n"
685 << XLOG2DEV(x + width) << " " << YLOG2DEV(y + rad) << " lineto\n"
686 << XLOG2DEV(x + width - rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 0 90 arc\n"
687 << XLOG2DEV(x + rad) << " " << YLOG2DEV(y) << " lineto\n"
688 << "closepath\n"
689 << "stroke\n";
690
691 CalcBoundingBox( x, y );
692 CalcBoundingBox( x + width, y + height );
693 }
694 }
695
696 void wxPostScriptDC::DrawEllipse (long x, long y, long width, long height)
697 {
698 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
699
700 if (m_brush.GetStyle () != wxTRANSPARENT)
701 {
702 SetBrush (m_brush);
703
704 *m_pstream << "newpath\n"
705 << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
706 << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
707 << "fill\n";
708
709 CalcBoundingBox( x - width, y - height );
710 CalcBoundingBox( x + width, y + height );
711 }
712
713 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
714 {
715 SetPen (m_pen);
716
717 *m_pstream << "newpath\n"
718 << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
719 << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
720 << "stroke\n";
721
722 CalcBoundingBox( x - width, y - height );
723 CalcBoundingBox( x + width, y + height );
724 }
725 }
726
727 void wxPostScriptDC::DrawIcon (const wxIcon& icon, long x, long y)
728 {
729 DrawBitmap( icon, x, y, TRUE );
730 }
731
732 void wxPostScriptDC::DrawBitmap( const wxBitmap& bitmap, long x, long y, bool WXUNUSED(useMask) )
733 {
734 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
735
736 if (!bitmap.Ok()) return;
737
738 wxImage image( bitmap );
739
740 if (!image.Ok()) return;
741
742 int ww = XLOG2DEVREL(image.GetWidth());
743 int hh = YLOG2DEVREL(image.GetHeight());
744
745 image = image.Scale( ww, hh );
746
747 if (!image.Ok()) return;
748
749 int xx = XLOG2DEV(x);
750 int yy = YLOG2DEV(y + bitmap.GetHeight());
751
752 *m_pstream << "/origstate save def\n"
753 << "20 dict begin\n"
754 << "/pix " << ww << " string def\n"
755 << "/grays " << ww << " string def\n"
756 << "/npixels 0 def\n"
757 << "/rgbindx 0 def\n"
758 << xx << " " << yy << " translate\n"
759 << ww << " " << hh << " scale\n"
760 << ww << " " << hh << " 8\n"
761 << "[" << ww << " 0 0 " << (-hh) << " 0 " << hh << "]\n"
762 << "{currentfile pix readhexstring pop}\n"
763 << "false 3 colorimage\n";
764
765 for (int j = 0; j < hh; j++)
766 {
767 for (int i = 0; i < ww; i++)
768 {
769 char buffer[5];
770 buffer[2] = 0;
771 wxDecToHex( image.GetRed(i,j), buffer );
772 *m_pstream << buffer;
773 wxDecToHex( image.GetGreen(i,j), buffer );
774 *m_pstream << buffer;
775 wxDecToHex( image.GetBlue(i,j), buffer );
776 *m_pstream << buffer;
777 }
778 *m_pstream << "\n";
779 }
780
781 *m_pstream << "end\n";
782 *m_pstream << "origstate restore\n";
783
784 }
785
786 void wxPostScriptDC::SetFont (const wxFont& font)
787 {
788 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
789
790 if (!font.Ok()) return;
791
792 m_font = font;
793
794 #ifdef __WXGTK__
795 char *name = wxTheFontNameDirectory->GetPostScriptName( m_font.GetFamily(),
796 m_font.GetWeight(),
797 m_font.GetStyle() );
798 if (!name) name = "Times-Roman";
799
800 *m_pstream << "/" << name << " reencodeISO def\n"
801 << "/" << name << " findfont\n"
802 << YLOG2DEVREL(font.GetPointSize())
803 << " scalefont setfont\n";
804 #else
805 char buf[100];
806 const char *name;
807 const char *style = "";
808 int Style = m_font.GetStyle ();
809 int Weight = m_font.GetWeight ();
810
811 switch (m_font.GetFamily ())
812 {
813 case wxTELETYPE:
814 case wxMODERN:
815 name = "/Courier";
816 break;
817 case wxSWISS:
818 name = "/Helvetica";
819 break;
820 case wxROMAN:
821 // name = "/Times-Roman";
822 name = "/Times"; // Altered by EDZ
823 break;
824 case wxSCRIPT:
825 name = "/Zapf-Chancery-MediumItalic";
826 Style = wxNORMAL;
827 Weight = wxNORMAL;
828 break;
829 default:
830 case wxDEFAULT: // Sans Serif Font
831 name = "/LucidaSans";
832 }
833
834 if (Style == wxNORMAL && (Weight == wxNORMAL || Weight == wxLIGHT))
835 {
836 if (m_font.GetFamily () == wxROMAN)
837 style = "-Roman";
838 else
839 style = "";
840 }
841 else if (Style == wxNORMAL && Weight == wxBOLD)
842 style = "-Bold";
843
844 else if (Style == wxITALIC && (Weight == wxNORMAL || Weight == wxLIGHT))
845 {
846 if (m_font.GetFamily () == wxROMAN)
847 style = "-Italic";
848 else
849 style = "-Oblique";
850 }
851 else if (Style == wxITALIC && Weight == wxBOLD)
852 {
853 if (m_font.GetFamily () == wxROMAN)
854 style = "-BoldItalic";
855 else
856 style = "-BoldOblique";
857 }
858 else if (Style == wxSLANT && (Weight == wxNORMAL || Weight == wxLIGHT))
859 {
860 if (m_font.GetFamily () == wxROMAN)
861 style = "-Italic";
862 else
863 style = "-Oblique";
864 }
865 else if (Style == wxSLANT && Weight == wxBOLD)
866 {
867 if (m_font.GetFamily () == wxROMAN)
868 style = "-BoldItalic";
869 else
870 style = "-BoldOblique";
871 }
872 else
873 style = "";
874
875 strcpy (buf, name);
876 strcat (buf, style);
877 *m_pstream << buf << " findfont\n";
878 // *m_pstream << (m_font.GetPointSize() * m_scaleFactor) << " scalefont setfont\n";
879 // No scale factor in this implementation?
880 *m_pstream << (m_font.GetPointSize()) << " scalefont setfont\n";
881 #endif
882 }
883
884 void wxPostScriptDC::SetPen( const wxPen& pen )
885 {
886 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
887
888 if (!pen.Ok()) return;
889
890 int oldStyle = m_pen.GetStyle();
891
892 m_pen = pen;
893
894 *m_pstream << XLOG2DEVREL(m_pen.GetWidth()) << " setlinewidth\n";
895
896 /*
897 Line style - WRONG: 2nd arg is OFFSET
898
899 Here, I'm afraid you do not conceive meaning of parameters of 'setdash'
900 operator correctly. You should look-up this in the Red Book: the 2nd parame-
901 ter is not number of values in the array of the first one, but an offset
902 into this description of the pattern. I mean a real *offset* not index
903 into array. I.e. If the command is [3 4] 1 setdash is used, then there
904 will be first black line *2* units long, then space 4 units, then the
905 pattern of *3* units black, 4 units space will be repeated.
906 */
907
908 static const char *dotted = "[2 5] 2";
909 static const char *short_dashed = "[4 4] 2";
910 static const char *long_dashed = "[4 8] 2";
911 static const char *dotted_dashed = "[6 6 2 6] 4";
912
913 const char *psdash = (char *) NULL;
914 switch (m_pen.GetStyle ())
915 {
916 case wxDOT: psdash = dotted; break;
917 case wxSHORT_DASH: psdash = short_dashed; break;
918 case wxLONG_DASH: psdash = long_dashed; break;
919 case wxDOT_DASH: psdash = dotted_dashed; break;
920 case wxSOLID:
921 case wxTRANSPARENT:
922 default: psdash = "[] 0"; break;
923 }
924
925 if (oldStyle != m_pen.GetStyle())
926 {
927 *m_pstream << psdash << " setdash\n";
928 }
929
930 // Line colour
931 unsigned char red = m_pen.GetColour().Red();
932 unsigned char blue = m_pen.GetColour().Blue();
933 unsigned char green = m_pen.GetColour().Green();
934
935 if (!m_colour)
936 {
937 // Anything not white is black
938 if (!(red == (unsigned char) 255 && blue == (unsigned char) 255
939 && green == (unsigned char) 255))
940 {
941 red = (unsigned char) 0;
942 green = (unsigned char) 0;
943 blue = (unsigned char) 0;
944 }
945
946 // setgray here ?
947 }
948
949 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
950 {
951 long redPS = (long) (((int) red) / 255.0);
952 long bluePS = (long) (((int) blue) / 255.0);
953 long greenPS = (long) (((int) green) / 255.0);
954
955 *m_pstream << redPS << " " << greenPS << " " << bluePS << " setrgbcolor\n";
956
957 m_currentRed = red;
958 m_currentBlue = blue;
959 m_currentGreen = green;
960 }
961 }
962
963 void wxPostScriptDC::SetBrush( const wxBrush& brush )
964 {
965 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
966
967 if (!brush.Ok()) return;
968
969 m_brush = brush;
970
971 // Brush colour
972 unsigned char red = m_brush.GetColour ().Red ();
973 unsigned char blue = m_brush.GetColour ().Blue ();
974 unsigned char green = m_brush.GetColour ().Green ();
975
976 if (!m_colour)
977 {
978 // Anything not black is white
979 if (!(red == (unsigned char) 0 && blue == (unsigned char) 0
980 && green == (unsigned char) 0))
981 {
982 red = (unsigned char) 255;
983 green = (unsigned char) 255;
984 blue = (unsigned char) 255;
985 }
986
987 // setgray here ?
988 }
989
990 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
991 {
992 long redPS = (long) (((int) red) / 255.0);
993 long bluePS = (long) (((int) blue) / 255.0);
994 long greenPS = (long) (((int) green) / 255.0);
995 *m_pstream << redPS << " " << greenPS << " " << bluePS << " setrgbcolor\n";
996 m_currentRed = red;
997 m_currentBlue = blue;
998 m_currentGreen = green;
999 }
1000 }
1001
1002 void wxPostScriptDC::DrawText( const wxString& text, long x, long y, bool WXUNUSED(use16bit) )
1003 {
1004 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1005
1006 SetFont( m_font );
1007
1008 if (m_textForegroundColour.Ok ())
1009 {
1010 unsigned char red = m_textForegroundColour.Red ();
1011 unsigned char blue = m_textForegroundColour.Blue ();
1012 unsigned char green = m_textForegroundColour.Green ();
1013
1014 if (!m_colour)
1015 {
1016 // Anything not white is black
1017 if (!(red == (unsigned char) 255 && blue == (unsigned char) 255
1018 && green == (unsigned char) 255))
1019 {
1020 red = (unsigned char) 0;
1021 green = (unsigned char) 0;
1022 blue = (unsigned char) 0;
1023 }
1024 }
1025
1026 // maybe setgray here ?
1027
1028 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1029 {
1030 long redPS = (long) (((int) red) / 255.0);
1031 long bluePS = (long) (((int) blue) / 255.0);
1032 long greenPS = (long) (((int) green) / 255.0);
1033 *m_pstream << redPS << " " << greenPS << " " << bluePS << " setrgbcolor\n";
1034
1035 m_currentRed = red;
1036 m_currentBlue = blue;
1037 m_currentGreen = green;
1038 }
1039 }
1040
1041 int size = m_font.GetPointSize();
1042
1043 long by = y + (long)floor( float(size) * 2.0 / 3.0 ); // approximate baseline
1044 *m_pstream << XLOG2DEV(x) << " " << YLOG2DEV(by) << " moveto\n";
1045
1046 *m_pstream << "(";
1047 int len = strlen ((char *)(const char *)text);
1048 int i;
1049 for (i = 0; i < len; i++)
1050 {
1051 int c = (unsigned char) text[i];
1052 if ( c == ')' || c == '(' || c == '\\')
1053 {
1054 *m_pstream << "\\" << (char) c;
1055 }
1056 else if ( c >= 128 )
1057 {
1058 // Cope with character codes > 127
1059 char tmp[5];
1060 sprintf(tmp, "\\%o", c);
1061 *m_pstream << tmp;
1062 }
1063 else
1064 *m_pstream << (char) c;
1065 }
1066
1067 *m_pstream << ")" << " show\n";
1068
1069 if (m_font.GetUnderlined())
1070 {
1071 long uy = (long)(y + size - m_underlinePosition);
1072 long w, h;
1073 GetTextExtent(text, &w, &h);
1074
1075 *m_pstream << "gsave " << XLOG2DEV(x) << " " << YLOG2DEV(uy)
1076 << " moveto\n"
1077 << (long)m_underlineThickness << " setlinewidth "
1078 << XLOG2DEV(x + w) << " " << YLOG2DEV(uy)
1079 << " lineto stroke grestore\n";
1080 }
1081
1082 CalcBoundingBox( x, y );
1083 CalcBoundingBox( x + size * text.Length() * 2/3 , y );
1084 }
1085
1086
1087 void wxPostScriptDC::SetBackground (const wxBrush& brush)
1088 {
1089 m_backgroundBrush = brush;
1090 }
1091
1092 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function))
1093 {
1094 wxFAIL_MSG( "wxPostScriptDC::SetLogicalFunction not implemented." );
1095 }
1096
1097 void wxPostScriptDC::DrawSpline( wxList *points )
1098 {
1099 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1100
1101 SetPen( m_pen );
1102
1103 double a, b, c, d, x1, y1, x2, y2, x3, y3;
1104 wxPoint *p, *q;
1105
1106 wxNode *node = points->First();
1107 p = (wxPoint *)node->Data();
1108 x1 = p->x;
1109 y1 = p->y;
1110
1111 node = node->Next();
1112 p = (wxPoint *)node->Data();
1113 c = p->x;
1114 d = p->y;
1115 x3 = a = (double)(x1 + c) / 2;
1116 y3 = b = (double)(y1 + d) / 2;
1117
1118 *m_pstream << "newpath "
1119 << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " moveto "
1120 << XLOG2DEV((long)x3) << " " << YLOG2DEV((long)y3) << " lineto\n";
1121
1122 CalcBoundingBox( (long)x1, (long)y1 );
1123 CalcBoundingBox( (long)x3, (long)y3 );
1124
1125 while ((node = node->Next()) != NULL)
1126 {
1127 q = (wxPoint *)node->Data();
1128
1129 x1 = x3;
1130 y1 = y3;
1131 x2 = c;
1132 y2 = d;
1133 c = q->x;
1134 d = q->y;
1135 x3 = (double)(x2 + c) / 2;
1136 y3 = (double)(y2 + d) / 2;
1137 *m_pstream << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " "
1138 << XLOG2DEV((long)x2) << " " << YLOG2DEV((long)y2) << " "
1139 << XLOG2DEV((long)x3) << " " << YLOG2DEV((long)y3) << " DrawSplineSection\n";
1140
1141 CalcBoundingBox( (long)x1, (long)y1 );
1142 CalcBoundingBox( (long)x3, (long)y3 );
1143 }
1144
1145 /*
1146 At this point, (x2,y2) and (c,d) are the position of the
1147 next-to-last and last point respectively, in the point list
1148 */
1149
1150 *m_pstream << XLOG2DEV((long)c) << " " << YLOG2DEV((long)d) << " lineto stroke\n";
1151 }
1152
1153 long wxPostScriptDC::GetCharWidth ()
1154 {
1155 // Chris Breeze: reasonable approximation using wxMODERN/Courier
1156 return (long) (GetCharHeight() * 72.0 / 120.0);
1157 }
1158
1159
1160 void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1161 {
1162 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1163
1164 m_signX = (xLeftRight ? 1 : -1);
1165 m_signY = (yBottomUp ? 1 : -1);
1166
1167 ComputeScaleAndOrigin();
1168 }
1169
1170 void wxPostScriptDC::SetDeviceOrigin( long x, long y )
1171 {
1172 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1173
1174 int h = 0;
1175 int w = 0;
1176 GetSize( &w, &h );
1177
1178 wxDC::SetDeviceOrigin( x, h-y );
1179 }
1180
1181 void wxPostScriptDC::GetSize(int* width, int* height) const
1182 {
1183 const char *paperType = wxThePrintSetupData->GetPaperName();
1184
1185 if (!paperType) paperType = _("A4 210 x 297 mm");
1186
1187 wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType);
1188
1189 if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(_("A4 210 x 297 mm"));
1190
1191 if (paper)
1192 {
1193 if (width) *width = paper->widthPixels;
1194 if (height) *height = paper->heightPixels;
1195 }
1196 else
1197 {
1198 if (width) *width = 595;
1199 if (height) *height = 842;
1200 }
1201 }
1202
1203 bool wxPostScriptDC::StartDoc (const wxString& message)
1204 {
1205 wxCHECK_MSG( m_ok, FALSE, "invalid postscript dc" );
1206
1207 if (m_filename == "")
1208 {
1209 m_filename = wxGetTempFileName("ps");
1210 wxThePrintSetupData->SetPrinterFile((char *)(const char *)m_filename);
1211 m_ok = TRUE;
1212 }
1213 else
1214 {
1215 wxThePrintSetupData->SetPrinterFile((char *)(const char *)m_filename);
1216 }
1217
1218 m_pstream = new ofstream (wxThePrintSetupData->GetPrinterFile());
1219
1220 if (!m_pstream || !m_pstream->good())
1221 {
1222 wxMessageBox (_("Cannot open file!"), _("Error"), wxOK);
1223 m_ok = FALSE;
1224 return FALSE;
1225 }
1226
1227 m_ok = TRUE;
1228
1229 SetBrush( *wxBLACK_BRUSH );
1230 SetPen( *wxBLACK_PEN );
1231 SetBackground( *wxWHITE_BRUSH );
1232 SetTextForeground( *wxBLACK );
1233
1234 // set origin according to paper size
1235 SetDeviceOrigin( 0,0 );
1236
1237 wxPageNumber = 1;
1238 m_pageNumber = 1;
1239 m_title = message;
1240 return TRUE;
1241 }
1242
1243 void wxPostScriptDC::EndDoc ()
1244 {
1245 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1246
1247 if (m_clipping)
1248 {
1249 m_clipping = FALSE;
1250 *m_pstream << "grestore\n";
1251 }
1252
1253 if (m_pstream)
1254 {
1255 delete m_pstream;
1256 m_pstream = (ofstream *) NULL;
1257 }
1258
1259 char *header_file = wxGetTempFileName("ps");
1260
1261 m_pstream = new ofstream( header_file );
1262
1263 *m_pstream << "%!PS-Adobe-2.0\n"; /* PostScript magic strings */
1264 *m_pstream << "%%Title: " << (const char *) m_title << "\n";
1265 *m_pstream << "%%Creator: " << wxTheApp->argv[0] << "\n";
1266 *m_pstream << "%%CreationDate: " << wxNow() << "\n";
1267
1268 char userID[256];
1269 if ( wxGetEmailAddress(userID, sizeof(userID)) )
1270 {
1271 *m_pstream << "%%For: " << (char *)userID;
1272 char userName[245];
1273 if (wxGetUserName(userName, sizeof(userName)))
1274 *m_pstream << " (" << (char *)userName << ")";
1275 *m_pstream << "\n";
1276 }
1277 else if ( wxGetUserName(userID, sizeof(userID)) )
1278 {
1279 *m_pstream << "%%For: " << (char *)userID << "\n";
1280 }
1281
1282 // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com>
1283
1284 long wx_printer_translate_x, wx_printer_translate_y;
1285 double wx_printer_scale_x, wx_printer_scale_y;
1286 wxThePrintSetupData->GetPrinterTranslation(&wx_printer_translate_x, &wx_printer_translate_y);
1287 wxThePrintSetupData->GetPrinterScaling(&wx_printer_scale_x, &wx_printer_scale_y);
1288
1289 if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
1290 {
1291 *m_pstream << "%%Orientation: Landscape\n";
1292 }
1293 else
1294 {
1295 *m_pstream << "%%Orientation: Portrait\n";
1296 }
1297
1298 // Compute the bounding box. Note that it is in the default user
1299 // coordinate system, thus we have to convert the values.
1300 long llx = (long) ((XLOG2DEV(m_minX)+wx_printer_translate_x)*wx_printer_scale_x);
1301 long lly = (long) ((YLOG2DEV(m_minY)+wx_printer_translate_y)*wx_printer_scale_y);
1302 long urx = (long) ((XLOG2DEV(m_maxX)+wx_printer_translate_x)*wx_printer_scale_x);
1303 long ury = (long) ((YLOG2DEV(m_maxY)+wx_printer_translate_y)*wx_printer_scale_y);
1304
1305 // If we're landscape, our sense of "x" and "y" is reversed.
1306 if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
1307 {
1308 long tmp;
1309 tmp = llx; llx = lly; lly = tmp;
1310 tmp = urx; urx = ury; ury = tmp;
1311
1312 // We need either the two lines that follow, or we need to subtract
1313 // min_x from real_translate_y, which is commented out below.
1314 llx = llx - (long)(m_minX*wx_printer_scale_y);
1315 urx = urx - (long)(m_minX*wx_printer_scale_y);
1316 }
1317
1318 // The Adobe specifications call for integers; we round as to make
1319 // the bounding larger.
1320 *m_pstream << "%%BoundingBox: "
1321 << floor((double)llx) << " " << floor((double)lly) << " "
1322 << ceil((double)urx) << " " << ceil((double)ury) << "\n";
1323 *m_pstream << "%%Pages: " << (wxPageNumber - 1) << "\n";
1324 *m_pstream << "%%EndComments\n\n";
1325
1326 // To check the correctness of the bounding box, postscript commands
1327 // to draw a box corresponding to the bounding box are generated below.
1328 // But since we typically don't want to print such a box, the postscript
1329 // commands are generated within comments. These lines appear before any
1330 // adjustment of scale, rotation, or translation, and hence are in the
1331 // default user coordinates.
1332 *m_pstream << "% newpath\n";
1333 *m_pstream << "% " << llx << " " << lly << " moveto\n";
1334 *m_pstream << "% " << urx << " " << lly << " lineto\n";
1335 *m_pstream << "% " << urx << " " << ury << " lineto\n";
1336 *m_pstream << "% " << llx << " " << ury << " lineto closepath stroke\n";
1337
1338 *m_pstream << "%%BeginProlog\n";
1339 *m_pstream << wxPostScriptHeaderEllipse;
1340 *m_pstream << wxPostScriptHeaderEllipticArc;
1341 *m_pstream << wxPostScriptHeaderColourImage;
1342 *m_pstream << wxPostScriptHeaderReencodeISO1;
1343 *m_pstream << wxPostScriptHeaderReencodeISO2;
1344
1345 if (wxPostScriptHeaderSpline)
1346 *m_pstream << wxPostScriptHeaderSpline;
1347 *m_pstream << "%%EndProlog\n";
1348
1349 delete m_pstream;
1350 m_pstream = (ofstream *) NULL;
1351
1352 char *tmp_file = wxGetTempFileName("ps");
1353
1354 // Paste header Before wx_printer_file
1355 wxConcatFiles (header_file, wxThePrintSetupData->GetPrinterFile(), tmp_file);
1356 wxRemoveFile (header_file);
1357 wxRemoveFile (wxThePrintSetupData->GetPrinterFile());
1358 wxRenameFile(tmp_file, wxThePrintSetupData->GetPrinterFile());
1359
1360 #if defined(__X__) || defined(__WXGTK__)
1361 if (m_ok)
1362 {
1363 switch (wxThePrintSetupData->GetPrinterMode()) {
1364 case PS_PREVIEW:
1365 {
1366 char *argv[3];
1367 argv[0] = wxThePrintSetupData->GetPrintPreviewCommand();
1368 argv[1] = wxThePrintSetupData->GetPrinterFile();
1369 argv[2] = (char *) NULL;
1370 wxExecute (argv, TRUE);
1371 wxRemoveFile(wxThePrintSetupData->GetPrinterFile());
1372 }
1373 break;
1374
1375 case PS_PRINTER:
1376 {
1377 char *argv[4];
1378 int argc = 0;
1379 argv[argc++] = wxThePrintSetupData->GetPrinterCommand();
1380
1381 // !SM! If we simply assign to argv[1] here, if printer options
1382 // are blank, we get an annoying and confusing message from lpr.
1383 char * opts = wxThePrintSetupData->GetPrinterOptions();
1384 if (opts && *opts)
1385 argv[argc++] = opts;
1386
1387 argv[argc++] = wxThePrintSetupData->GetPrinterFile();
1388 argv[argc++] = (char *) NULL;
1389 wxExecute (argv, TRUE);
1390 wxRemoveFile(wxThePrintSetupData->GetPrinterFile());
1391 }
1392 break;
1393
1394 case PS_FILE:
1395 break;
1396 }
1397 }
1398 #endif
1399 }
1400
1401 void wxPostScriptDC::StartPage ()
1402 {
1403 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1404
1405 *m_pstream << "%%Page: " << (wxPageNumber++) << "\n";
1406
1407 // *m_pstream << "matrix currentmatrix\n";
1408
1409 // Added by Chris Breeze
1410
1411 // Each page starts with an "initgraphics" which resets the
1412 // transformation and so we need to reset the origin
1413 // (and rotate the page for landscape printing)
1414
1415 /*
1416 m_scaleFactor = 1.0;
1417 m_logicalOriginX = 0;
1418 m_logicalOriginY = 0;
1419 */
1420
1421 // Output scaling
1422 long translate_x, translate_y;
1423 double scale_x, scale_y;
1424 wxThePrintSetupData->GetPrinterTranslation(&translate_x, &translate_y);
1425 wxThePrintSetupData->GetPrinterScaling(&scale_x, &scale_y);
1426
1427 if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
1428 {
1429 translate_y -= m_maxY;
1430 *m_pstream << "90 rotate\n";
1431 }
1432
1433 *m_pstream << scale_x << " " << scale_y << " scale\n";
1434 *m_pstream << translate_x << " " << translate_y << " translate\n";
1435 }
1436
1437 void wxPostScriptDC::EndPage ()
1438 {
1439 wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
1440
1441 *m_pstream << "showpage\n";
1442 }
1443
1444 bool wxPostScriptDC::Blit( long WXUNUSED(xdest), long WXUNUSED(ydest),
1445 long WXUNUSED(fwidth), long WXUNUSED(fheight),
1446 wxDC *WXUNUSED(source),
1447 long WXUNUSED(xsrc), long WXUNUSED(ysrc),
1448 int WXUNUSED(rop), bool WXUNUSED(useMask) )
1449 {
1450 wxCHECK_MSG( m_ok && m_pstream, FALSE, "invalid postscript dc" );
1451
1452 wxFAIL_MSG( "wxPostScriptDC::Blit no yet implemented." );
1453
1454 return TRUE;
1455 }
1456
1457 long wxPostScriptDC::GetCharHeight ()
1458 {
1459 if (m_font.Ok())
1460 return m_font.GetPointSize();
1461 else
1462 return 12;
1463 }
1464
1465 void wxPostScriptDC::GetTextExtent (const wxString& string, long *x, long *y,
1466 long *descent, long *externalLeading, wxFont *theFont,
1467 bool WXUNUSED(use16))
1468 {
1469 // if (!m_pstream) return;
1470
1471 wxFont *fontToUse = theFont;
1472
1473 if (!fontToUse) fontToUse = (wxFont*) &m_font;
1474
1475 #if !USE_AFM_FOR_POSTSCRIPT
1476 // Provide a VERY rough estimate (avoid using it)
1477 // Chris Breeze 5/11/97: produces accurate results for mono-spaced
1478 // font such as Courier (aka wxMODERN)
1479 int height = 12;
1480 if (fontToUse)
1481 {
1482 height = fontToUse->GetPointSize();
1483 }
1484 *x = strlen (string) * height * 72 / 120;
1485 *y = (long) (height * 1.32); // allow for descender
1486
1487 if (descent)
1488 *descent = 0;
1489 if (externalLeading)
1490 *externalLeading = 0;
1491 #else
1492 // +++++ start of contributed code +++++
1493
1494 // ************************************************************
1495 // method for calculating string widths in postscript:
1496 // read in the AFM (adobe font metrics) file for the
1497 // actual font, parse it and extract the character widths
1498 // and also the descender. this may be improved, but for now
1499 // it works well. the AFM file is only read in if the
1500 // font is changed. this may be chached in the future.
1501 // calls to GetTextExtent with the font unchanged are rather
1502 // efficient!!!
1503 //
1504 // for each font and style used there is an AFM file necessary.
1505 // currently i have only files for the roman font family.
1506 // i try to get files for the other ones!
1507 //
1508 // CAVE: the size of the string is currently always calculated
1509 // in 'points' (1/72 of an inch). this should later on be
1510 // changed to depend on the mapping mode.
1511 // CAVE: the path to the AFM files must be set before calling this
1512 // function. this is usually done by a call like the following:
1513 // wxSetAFMPath("d:\\wxw161\\afm\\");
1514 //
1515 // example:
1516 //
1517 // wxPostScriptDC dc(NULL, TRUE);
1518 // if (dc.Ok()){
1519 // wxSetAFMPath("d:\\wxw161\\afm\\");
1520 // dc.StartDoc("Test");
1521 // dc.StartPage();
1522 // long w,h;
1523 // dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
1524 // dc.GetTextExtent("Hallo",&w,&h);
1525 // dc.EndPage();
1526 // dc.EndDoc();
1527 // }
1528 //
1529 // by steve (stefan.hammes@urz.uni-heidelberg.de)
1530 // created: 10.09.94
1531 // updated: 14.05.95
1532
1533 assert(fontToUse && "void wxPostScriptDC::GetTextExtent: no font defined");
1534 assert(x && "void wxPostScriptDC::GetTextExtent: x == NULL");
1535 assert(y && "void wxPostScriptDC::GetTextExtent: y == NULL");
1536
1537 // these static vars are for storing the state between calls
1538 static int lastFamily= INT_MIN;
1539 static int lastSize= INT_MIN;
1540 static int lastStyle= INT_MIN;
1541 static int lastWeight= INT_MIN;
1542 static int lastDescender = INT_MIN;
1543 static int lastWidths[256]; // widths of the characters
1544
1545 // get actual parameters
1546 const int Family = fontToUse->GetFamily();
1547 const int Size = fontToUse->GetPointSize();
1548 const int Style = fontToUse->GetStyle();
1549 const int Weight = fontToUse->GetWeight();
1550
1551 // if we have another font, read the font-metrics
1552 if(Family!=lastFamily||Size!=lastSize||Style!=lastStyle||Weight!=lastWeight){
1553 // store actual values
1554 lastFamily = Family;
1555 lastSize = Size;
1556 lastStyle = Style;
1557 lastWeight = Weight;
1558
1559 // read in new font metrics **************************************
1560
1561 // 1. construct filename ******************************************
1562 /* MATTHEW: [2] Use wxTheFontNameDirectory */
1563 const char *name;
1564
1565 // Julian - we'll need to do this a different way now we've removed the
1566 // font directory system. Must find Stefan's original code.
1567
1568 name = wxTheFontNameDirectory->GetAFMName(Family, Weight, Style);
1569 if (!name)
1570 name = "unknown";
1571
1572 // get the directory of the AFM files
1573 char afmName[256];
1574 afmName[0] = 0;
1575 if (wxGetAFMPath())
1576 strcpy(afmName,wxGetAFMPath());
1577
1578 // 2. open and process the file **********************************
1579
1580 // a short explanation of the AFM format:
1581 // we have for each character a line, which gives its size
1582 // e.g.:
1583 //
1584 // C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
1585 //
1586 // that means, we have a character with ascii code 63, and width
1587 // (444/1000 * fontSize) points.
1588 // the other data is ignored for now!
1589 //
1590 // when the font has changed, we read in the right AFM file and store the
1591 // character widths in an array, which is processed below (see point 3.).
1592
1593 // new elements JC Sun Aug 25 23:21:44 MET DST 1996
1594
1595
1596 strcat(afmName,name);
1597 strcat(afmName,".afm");
1598 FILE *afmFile = fopen(afmName,"r");
1599 if(afmFile==NULL){
1600 wxLogDebug("GetTextExtent: can't open AFM file '%s'\n",afmName);
1601 wxLogDebug(" using approximate values\n");
1602 int i;
1603 for (i=0; i<256; i++) lastWidths[i] = 500; // an approximate value
1604 lastDescender = -150; // dito.
1605 }else{
1606 int i;
1607 // init the widths array
1608 for(i=0; i<256; i++) lastWidths[i]= INT_MIN;
1609 // some variables for holding parts of a line
1610 char cString[10],semiString[10],WXString[10],descString[20];
1611 char upString[30], utString[30], encString[50];
1612 char line[256];
1613 int ascii,cWidth;
1614 // read in the file and parse it
1615 while(fgets(line,sizeof(line),afmFile)!=NULL){
1616 // A.) check for descender definition
1617 if(strncmp(line,"Descender",9)==0){
1618 if((sscanf(line,"%s%d",descString,&lastDescender)!=2)
1619 || (strcmp(descString,"Descender")!=0)) {
1620 wxLogDebug("AFM-file '%s': line '%s' has error (bad descender)\n",
1621 afmName,line);
1622 }
1623 }
1624 // JC 1.) check for UnderlinePosition
1625 else if(strncmp(line,"UnderlinePosition",17)==0){
1626 if((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2)
1627 || (strcmp(upString,"UnderlinePosition")!=0)) {
1628 wxLogDebug("AFM-file '%s': line '%s' has error (bad UnderlinePosition)\n",
1629 afmName,line);
1630 }
1631 }
1632 // JC 2.) check for UnderlineThickness
1633 else if(strncmp(line,"UnderlineThickness",18)==0){
1634 if((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2)
1635 || (strcmp(utString,"UnderlineThickness")!=0)) {
1636 wxLogDebug("AFM-file '%s': line '%s' has error (bad UnderlineThickness)\n",
1637 afmName,line);
1638 }
1639 }
1640 // JC 3.) check for EncodingScheme
1641 else if(strncmp(line,"EncodingScheme",14)==0){
1642 if((sscanf(line,"%s%s",utString,encString)!=2)
1643 || (strcmp(utString,"EncodingScheme")!=0)) {
1644 wxLogDebug("AFM-file '%s': line '%s' has error (bad EncodingScheme)\n",
1645 afmName,line);
1646 }
1647 else if (strncmp(encString, "AdobeStandardEncoding", 21))
1648 {
1649 wxLogDebug("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)\n",
1650 afmName,line, encString);
1651 }
1652 }
1653 // B.) check for char-width
1654 else if(strncmp(line,"C ",2)==0){
1655 if(sscanf(line,"%s%d%s%s%d",
1656 cString,&ascii,semiString,WXString,&cWidth)!=5){
1657 wxLogDebug("AFM-file '%s': line '%s' has an error (bad character width)\n",afmName,line);
1658 }
1659 if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 ||
1660 strcmp(WXString,"WX")!=0){
1661 wxLogDebug("AFM-file '%s': line '%s' has a format error\n",afmName,line);
1662 }
1663 //printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth);
1664 if(ascii>=0 && ascii<256){
1665 lastWidths[ascii] = cWidth; // store width
1666 }else{
1667 /* MATTHEW: this happens a lot; don't print an error */
1668 // wxLogDebug("AFM-file '%s': ASCII value %d out of range\n",afmName,ascii);
1669 }
1670 }
1671 // C.) ignore other entries.
1672 }
1673 fclose(afmFile);
1674 }
1675 // hack to compute correct values for german 'Umlaute'
1676 // the correct way would be to map the character names
1677 // like 'adieresis' to corresp. positions of ISOEnc and read
1678 // these values from AFM files, too. Maybe later ...
1679 lastWidths[196] = lastWidths['A']; // Ä
1680 lastWidths[228] = lastWidths['a']; // ä
1681 lastWidths[214] = lastWidths['O']; // Ö
1682 lastWidths[246] = lastWidths['o']; // ö
1683 lastWidths[220] = lastWidths['U']; // Ü
1684 lastWidths[252] = lastWidths['u']; // ü
1685 lastWidths[223] = lastWidths[251]; // ß
1686 }
1687
1688 // JC: calculate UnderlineThickness/UnderlinePosition
1689 m_underlinePosition = m_underlinePosition * fontToUse->GetPointSize() / 1000.0f;
1690 m_underlineThickness = m_underlineThickness * fontToUse->GetPointSize() / 1000.0f * m_scaleFactor;
1691
1692 // 3. now the font metrics are read in, calc size *******************
1693 // this is done by adding the widths of the characters in the
1694 // string. they are given in 1/1000 of the size!
1695
1696 long widthSum=0;
1697 long height=Size; // by default
1698 unsigned char *p;
1699 for(p=(unsigned char *)(const char *)string; *p; p++){
1700 if(lastWidths[*p]== INT_MIN){
1701 wxLogDebug("GetTextExtent: undefined width for character '%c' (%d)\n",
1702 *p,*p);
1703 widthSum += (long)(lastWidths[' ']/1000.0F * Size); // assume space
1704 }else{
1705 widthSum += (long)((lastWidths[*p]/1000.0F)*Size);
1706 }
1707 }
1708 // add descender to height (it is usually a negative value)
1709 if(lastDescender!=INT_MIN){
1710 height += (long)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
1711 }
1712
1713 // return size values
1714 *x = widthSum;
1715 *y = height;
1716
1717 // return other parameters
1718 if (descent){
1719 if(lastDescender!=INT_MIN){
1720 *descent = (long)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
1721 }else{
1722 *descent = 0;
1723 }
1724 }
1725
1726 // currently no idea how to calculate this!
1727 // if (externalLeading) *externalLeading = 0;
1728 if (externalLeading)
1729 *externalLeading = 0;
1730
1731 // ----- end of contributed code -----
1732 #endif
1733 }
1734
1735 void wxPostScriptDC::GetSizeMM(long *width, long *height) const
1736 {
1737 const char *paperType = wxThePrintSetupData->GetPaperName();
1738
1739 if (!paperType) paperType = _("A4 210 x 297 mm");
1740
1741 wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType);
1742
1743 if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(_("A4 210 x 297 mm"));
1744
1745 if (paper)
1746 {
1747 if (width) *width = paper->widthMM;
1748 if (height) *height = paper->heightMM;
1749 }
1750 else
1751 {
1752 if (width) *width = 210;
1753 if (height) *height = 297;
1754 }
1755 }
1756
1757 #endif
1758 // wxUSE_POSTSCRIPT