1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Generic wxPostScriptDC implementation 
   4 // Author:      Julian Smart, Robert Roebling, Markus Holzhem 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation 
  17 #include "wx/wxprec.h" 
  26 #if wxUSE_PRINTING_ARCHITECTURE 
  30 #include "wx/window.h" 
  31 #include "wx/dcmemory.h" 
  34 #include "wx/filedlg.h" 
  36 #include "wx/msgdlg.h" 
  39 #include "wx/generic/dcpsg.h" 
  40 #include "wx/printdlg.h" 
  41 #include "wx/button.h" 
  42 #include "wx/stattext.h" 
  43 #include "wx/radiobox.h" 
  44 #include "wx/textctrl.h" 
  45 #include "wx/prntbase.h" 
  47 #include "wx/filefn.h" 
  71 //----------------------------------------------------------------------------- 
  72 // start and end of document/page 
  73 //----------------------------------------------------------------------------- 
  75 static const char *wxPostScriptHeaderEllipse 
= "\ 
  76 /ellipsedict 8 dict def\n\ 
  77 ellipsedict /mtrx matrix put\n\ 
  81     /startangle exch def\n\ 
  86     /savematrix mtrx currentmatrix def\n\ 
  89     0 0 1 startangle endangle arc\n\ 
  90     savematrix setmatrix\n\ 
  95 static const char *wxPostScriptHeaderEllipticArc
= "\ 
  96 /ellipticarcdict 8 dict def\n\ 
  97 ellipticarcdict /mtrx matrix put\n\ 
  99 { ellipticarcdict begin\n\ 
 101   /endangle exch def\n\ 
 102   /startangle exch def\n\ 
 107   /savematrix mtrx currentmatrix def\n\ 
 110   do_fill { 0 0 moveto } if\n\ 
 111   0 0 1 startangle endangle arc\n\ 
 112   savematrix setmatrix\n\ 
 113   do_fill { fill }{ stroke } ifelse\n\ 
 117 static const char *wxPostScriptHeaderSpline 
= "\ 
 118 /DrawSplineSection {\n\ 
 125     /xa x1 x2 x1 sub 0.666667 mul add def\n\ 
 126     /ya y1 y2 y1 sub 0.666667 mul add def\n\ 
 127     /xb x3 x2 x3 sub 0.666667 mul add def\n\ 
 128     /yb y3 y2 y3 sub 0.666667 mul add def\n\ 
 130     xa ya xb yb x3 y3 curveto\n\ 
 134 static const char *wxPostScriptHeaderColourImage 
= "\ 
 135 %% define 'colorimage' if it isn't defined\n\ 
 136 %%   ('colortogray' and 'mergeprocs' come from xwd2ps\n\ 
 138 /colorimage where   %% do we know about 'colorimage'?\n\ 
 139   { pop }           %% yes: pop off the 'dict' returned\n\ 
 140   {                 %% no:  define one\n\ 
 141     /colortogray {  %% define an RGB->I function\n\ 
 142       /rgbdata exch store    %% call input 'rgbdata'\n\ 
 143       rgbdata length 3 idiv\n\ 
 144       /npixls exch store\n\ 
 146       0 1 npixls 1 sub {\n\ 
 148         rgbdata rgbindx       get 20 mul    %% Red\n\ 
 149         rgbdata rgbindx 1 add get 32 mul    %% Green\n\ 
 150         rgbdata rgbindx 2 add get 12 mul    %% Blue\n\ 
 151         add add 64 idiv      %% I = .5G + .31R + .18B\n\ 
 153         /rgbindx rgbindx 3 add store\n\ 
 155       grays 0 npixls getinterval\n\ 
 158     %% Utility procedure for colorimage operator.\n\ 
 159     %% This procedure takes two procedures off the\n\ 
 160     %% stack and merges them into a single procedure.\n\ 
 162     /mergeprocs { %% def\n\ 
 181     /colorimage { %% def\n\ 
 182       pop pop     %% remove 'false 3' operands\n\ 
 183       {colortogray} mergeprocs\n\ 
 186   } ifelse          %% end of 'false' case\n\ 
 189 static char wxPostScriptHeaderReencodeISO1
[] = 
 191 "dup dup findfont dup length dict begin\n" 
 192 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" 
 193 "/Encoding ISOLatin1Encoding def\n" 
 194 "currentdict end definefont\n" 
 196 "/ISOLatin1Encoding [\n" 
 197 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 198 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 199 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 200 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 201 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" 
 202 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" 
 203 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" 
 204 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" 
 205 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" 
 206 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" 
 207 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" 
 208 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 209 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 210 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" 
 211 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; 
 213 static char wxPostScriptHeaderReencodeISO2
[] = 
 214 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" 
 215 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" 
 216 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" 
 217 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" 
 218 "/guillemotright/onequarter/onehalf/threequarters/questiondown\n" 
 219 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" 
 220 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" 
 221 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" 
 222 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" 
 223 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" 
 224 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" 
 225 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" 
 226 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" 
 227 "/yacute/thorn/ydieresis\n" 
 230 //------------------------------------------------------------------------------- 
 232 //------------------------------------------------------------------------------- 
 234 float wxPostScriptDC::ms_PSScaleFactor 
= 10.0; 
 236 void wxPostScriptDC::SetResolution(int ppi
) 
 238     ms_PSScaleFactor 
= (float)ppi 
/ 72.0; 
 241 int wxPostScriptDC::GetResolution() 
 243     return (int)(ms_PSScaleFactor 
* 72.0); 
 248 wxPostScriptDC::wxPostScriptDC () 
 250     m_pstream 
= (FILE*) NULL
; 
 260     m_underlinePosition 
= 0.0; 
 261     m_underlineThickness 
= 0.0; 
 263     m_signX 
=  1;  // default x-axis left to right 
 264     m_signY 
= -1;  // default y-axis bottom up -> top down 
 266     // Compatibility only 
 267     // HH: Doesn't seem to work for wxMSW... 
 269     m_printData 
= * wxThePrintSetupData
; 
 273 wxPostScriptDC::wxPostScriptDC (const wxString
& file
, bool interactive
, wxWindow 
*parent
) 
 275     m_pstream 
= (FILE*) NULL
; 
 285     m_underlinePosition 
= 0.0; 
 286     m_underlineThickness 
= 0.0; 
 288     m_signX 
=  1;  // default x-axis left to right 
 289     m_signY 
= -1;  // default y-axis bottom up -> top down 
 291     Create(file
, interactive
, parent
); 
 294 bool wxPostScriptDC::Create(const wxString
& file
, bool interactive
, wxWindow 
*parent
) 
 296     m_isInteractive 
= interactive
; 
 299     m_printData
.SetFilename(file
); 
 302     // Can only send to file in Windows 
 303     m_printData
.SetPrintMode(wxPRINT_MODE_FILE
); 
 308         if ((m_ok 
= PrinterDialog (parent
) ) == FALSE
) return FALSE
; 
 318 wxPostScriptDC::wxPostScriptDC (const wxPrintData
& printData
) 
 320     m_pstream 
= (FILE*) NULL
; 
 330     m_underlinePosition 
= 0.0; 
 331     m_underlineThickness 
= 0.0; 
 333     m_signX 
=  1;  // default x-axis left to right 
 334     m_signY 
= -1;  // default y-axis bottom up -> top down 
 336     m_printData 
= printData
; 
 341 wxPostScriptDC::~wxPostScriptDC () 
 346         m_pstream 
= (FILE*) NULL
; 
 350 bool wxPostScriptDC::Ok() const 
 355 // This dialog is deprecated now: use wxGenericPrintDialog or the printing framework 
 356 bool wxPostScriptDC::PrinterDialog(wxWindow 
*parent
) 
 358     wxPostScriptPrintDialog 
dialog( parent
, _("Printer Settings"), wxPoint(150, 150), wxSize(400, 400), 
 359                                     wxDEFAULT_DIALOG_STYLE 
| wxDIALOG_MODAL 
); 
 360     m_ok 
= (dialog
.ShowModal () == wxID_OK
); 
 362     if (!m_ok
) return FALSE
; 
 364     if ((m_printData
.GetFilename() == "") && 
 365         (m_printData
.GetPrintMode() == wxPRINT_MODE_PREVIEW  
|| 
 366          m_printData
.GetPrintMode() == wxPRINT_MODE_PRINTER
)) 
 370       m_printData
.SetFilename("preview"); 
 372       // For PS_PRINTER action this depends on a Unix-style print spooler 
 373       // since the wx_printer_file can be destroyed during a session 
 374       // @@@ TODO: a Windows-style answer for non-Unix 
 376       wxGetUserId (userId
, sizeof (userId
) / sizeof (char)); 
 378       wxStrcpy (tmp
, wxT("/tmp/preview_")); 
 379       wxStrcat (tmp
, userId
); 
 380       m_printData
.SetFilename(tmp
); 
 383       wxStrcpy(tmp2
, m_printData
.GetFilename()); 
 384       wxStrcat (tmp2
, wxT(".ps")); 
 385       m_printData
.SetFilename(tmp2
); 
 387     else if ((m_printData
.GetFilename() == wxT("")) && (m_printData
.GetPrintMode() == wxPRINT_MODE_FILE
)) 
 389       wxString file 
= wxSaveFileSelector (_("PostScript"), wxT("ps")); 
 390       if ( file
.IsEmpty() ) 
 396       m_printData
.SetFilename(file
); 
 403 void wxPostScriptDC::DoSetClippingRegion (wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 405     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 407     if (m_clipping
) DestroyClippingRegion(); 
 409     wxDC::DoSetClippingRegion(x
, y
, w
, h
); 
 418             "closepath clip newpath\n", 
 419             XLOG2DEV(x
),   YLOG2DEV(y
), 
 420             XLOG2DEV(x
+w
), YLOG2DEV(y
), 
 421             XLOG2DEV(x
+w
), YLOG2DEV(y
+h
), 
 422             XLOG2DEV(x
),   YLOG2DEV(y
+h
) ); 
 426 void wxPostScriptDC::DestroyClippingRegion() 
 428     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 433         fprintf( m_pstream
, "grestore\n" ); 
 436     wxDC::DestroyClippingRegion(); 
 439 void wxPostScriptDC::Clear() 
 441     wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); 
 444 void wxPostScriptDC::DoFloodFill (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
)) 
 446     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); 
 449 bool wxPostScriptDC::DoGetPixel (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxColour 
* WXUNUSED(col
)) const 
 451     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); 
 455 void wxPostScriptDC::DoCrossHair (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) 
 457     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); 
 460 void wxPostScriptDC::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 462     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 464     if  (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 473             XLOG2DEV(x1
), YLOG2DEV(y1
), 
 474             XLOG2DEV(x2
), YLOG2DEV (y2
) ); 
 476     CalcBoundingBox( x1
, y1 
); 
 477     CalcBoundingBox( x2
, y2 
); 
 480 #define RAD2DEG 57.29577951308 
 482 void wxPostScriptDC::DoDrawArc (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 484     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 486     wxCoord dx 
= x1 
- xc
; 
 487     wxCoord dy 
= y1 
- yc
; 
 488     wxCoord radius 
= (wxCoord
) sqrt( (double)(dx
*dx
+dy
*dy
) ); 
 489     double alpha1
, alpha2
; 
 491     if (x1 
== x2 
&& y1 
== y2
) 
 496     else if (radius 
== 0.0) 
 498         alpha1 
= alpha2 
= 0.0; 
 502         alpha1 
= (x1 
- xc 
== 0) ? 
 503             (y1 
- yc 
< 0) ? 90.0 : -90.0 : 
 504                 -atan2(double(y1
-yc
), double(x1
-xc
)) * RAD2DEG
; 
 505         alpha2 
= (x2 
- xc 
== 0) ? 
 506             (y2 
- yc 
< 0) ? 90.0 : -90.0 : 
 507                 -atan2(double(y2
-yc
), double(x2
-xc
)) * RAD2DEG
; 
 509     while (alpha1 
<= 0)   alpha1 
+= 360; 
 510     while (alpha2 
<= 0)   alpha2 
+= 360; // adjust angles to be between 
 511     while (alpha1 
> 360)  alpha1 
-= 360; // 0 and 360 degree 
 512     while (alpha2 
> 360)  alpha2 
-= 360; 
 514     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 520                 "%d %d %d %d %d %d ellipse\n" 
 524                 XLOG2DEV(xc
), YLOG2DEV(yc
), XLOG2DEVREL(radius
), YLOG2DEVREL(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 525                 XLOG2DEV(xc
), YLOG2DEV(yc
) ); 
 527         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 528         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 531     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 537                 "%d %d %d %d %d %d ellipse\n" 
 541                 XLOG2DEV(xc
), YLOG2DEV(yc
), XLOG2DEVREL(radius
), YLOG2DEVREL(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 542                 XLOG2DEV(xc
), YLOG2DEV(yc
) ); 
 544         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 545         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 549 void wxPostScriptDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 551     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 553     if (sa
>=360 || sa
<=-360) sa
=sa
-int(sa
/360)*360; 
 554     if (ea
>=360 || ea
<=-360) ea
=ea
-int(ea
/360)*360; 
 560         DrawEllipse(x
,y
,w
,h
); 
 564     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 570                 "%d %d %d %d %d %d true ellipticarc\n", 
 571                 XLOG2DEV(x
+w
/2), YLOG2DEV(y
+h
/2), XLOG2DEVREL(w
/2), YLOG2DEVREL(h
/2), (wxCoord
)sa
, (wxCoord
)ea 
); 
 573         CalcBoundingBox( x 
,y 
); 
 574         CalcBoundingBox( x
+w
, y
+h 
); 
 577     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 583                 "%d %d %d %d %d %d false ellipticarc\n", 
 584                 XLOG2DEV(x
+w
/2), YLOG2DEV(y
+h
/2), XLOG2DEVREL(w
/2), YLOG2DEVREL(h
/2), (wxCoord
)sa
, (wxCoord
)ea 
); 
 586         CalcBoundingBox( x 
,y 
); 
 587         CalcBoundingBox( x
+w
, y
+h 
); 
 591 void wxPostScriptDC::DoDrawPoint (wxCoord x
, wxCoord y
) 
 593     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 595     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 604             XLOG2DEV(x
),   YLOG2DEV(y
), 
 605             XLOG2DEV(x
+1), YLOG2DEV(y
) ); 
 607     CalcBoundingBox( x
, y 
); 
 610 void wxPostScriptDC::DoDrawPolygon (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
)) 
 612     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 616     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 620         fprintf( m_pstream
, "newpath\n" ); 
 622         wxCoord xx 
= XLOG2DEV(points
[0].x 
+ xoffset
); 
 623         wxCoord yy 
= YLOG2DEV(points
[0].y 
+ yoffset
); 
 625         fprintf( m_pstream
, "%d %d moveto\n", xx
, yy 
); 
 627         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 629         for (int i 
= 1; i 
< n
; i
++) 
 631             xx 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 632             yy 
= YLOG2DEV(points
[i
].y 
+ yoffset
); 
 634             fprintf( m_pstream
, "%d %d lineto\n", xx
, yy 
); 
 636             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 639         fprintf( m_pstream
, "fill\n" ); 
 642     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 646         fprintf( m_pstream
, "newpath\n" ); 
 648         wxCoord xx 
= XLOG2DEV(points
[0].x 
+ xoffset
); 
 649         wxCoord yy 
= YLOG2DEV(points
[0].y 
+ yoffset
); 
 651         fprintf( m_pstream
, "%d %d moveto\n", xx
, yy 
); 
 653         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 655         for (int i 
= 1; i 
< n
; i
++) 
 657             xx 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 658             yy 
= YLOG2DEV(points
[i
].y 
+ yoffset
); 
 660             fprintf( m_pstream
, "%d %d lineto\n", xx
, yy 
); 
 662             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 665         fprintf( m_pstream
, "closepath\n" ); 
 666         fprintf( m_pstream
, "stroke\n" ); 
 670 void wxPostScriptDC::DoDrawLines (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 672     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 674     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 681     for ( i 
=0; i
<n 
; i
++ ) 
 683         CalcBoundingBox( XLOG2DEV(points
[i
].x
+xoffset
), YLOG2DEV(points
[i
].y
+yoffset
)); 
 689             XLOG2DEV(points
[0].x
+xoffset
), YLOG2DEV(points
[0].y
+yoffset
) ); 
 691     for (i 
= 1; i 
< n
; i
++) 
 695                 XLOG2DEV(points
[i
].x
+xoffset
), YLOG2DEV(points
[i
].y
+yoffset
) ); 
 698     fprintf( m_pstream
, "stroke\n" ); 
 701 void wxPostScriptDC::DoDrawRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 703     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 705     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 717                 XLOG2DEV(x
),         YLOG2DEV(y
), 
 718                 XLOG2DEV(x 
+ width
), YLOG2DEV(y
), 
 719                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ height
), 
 720                 XLOG2DEV(x
),         YLOG2DEV(y 
+ height
) ); 
 722         CalcBoundingBox( x
, y 
); 
 723         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 726     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 738                 XLOG2DEV(x
),         YLOG2DEV(y
), 
 739                 XLOG2DEV(x 
+ width
), YLOG2DEV(y
), 
 740                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ height
), 
 741                 XLOG2DEV(x
),         YLOG2DEV(y 
+ height
) ); 
 743         CalcBoundingBox( x
, y 
); 
 744         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 748 void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 750     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 754         // Now, a negative radius is interpreted to mean 
 755         // 'the proportion of the smallest X or Y dimension' 
 756         double smallest 
= 0.0; 
 761         radius 
=  (-radius 
* smallest
); 
 764     wxCoord rad 
= (wxCoord
) radius
; 
 766     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 770         /* Draw rectangle anticlockwise */ 
 773                 "%d %d %d 90 180 arc\n" 
 775                 "%d %d %d 180 270 arc\n" 
 777                 "%d %d %d 270 0 arc\n" 
 779                 "%d %d %d 0 90 arc\n" 
 783                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 784                 XLOG2DEV(x
), YLOG2DEV(y 
+ rad
), 
 785                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 786                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height
), 
 787                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 788                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ rad
), 
 789                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 790                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y
) ); 
 792         CalcBoundingBox( x
, y 
); 
 793         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 796     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 800         /* Draw rectangle anticlockwise */ 
 803                 "%d %d %d 90 180 arc\n" 
 805                 "%d %d %d 180 270 arc\n" 
 807                 "%d %d %d 270 0 arc\n" 
 809                 "%d %d %d 0 90 arc\n" 
 813                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 814                 XLOG2DEV(x
), YLOG2DEV(y 
+ rad
), 
 815                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 816                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height
), 
 817                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 818                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ rad
), 
 819                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 820                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y
) ); 
 822         CalcBoundingBox( x
, y 
); 
 823         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 827 void wxPostScriptDC::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 829     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 831     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 837                 "%d %d %d %d 0 360 ellipse\n" 
 839                 XLOG2DEV(x 
+ width 
/ 2), YLOG2DEV(y 
+ height 
/ 2), 
 840                 XLOG2DEVREL(width 
/ 2), YLOG2DEVREL(height 
/ 2) ); 
 842         CalcBoundingBox( x 
- width
, y 
- height 
); 
 843         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 846     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 852                 "%d %d %d %d 0 360 ellipse\n" 
 854                 XLOG2DEV(x 
+ width 
/ 2), YLOG2DEV(y 
+ height 
/ 2), 
 855                 XLOG2DEVREL(width 
/ 2), YLOG2DEVREL(height 
/ 2) ); 
 857         CalcBoundingBox( x 
- width
, y 
- height 
); 
 858         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 862 void wxPostScriptDC::DoDrawIcon( const wxIcon
& icon
, wxCoord x
, wxCoord y 
) 
 864     DrawBitmap( icon
, x
, y
, TRUE 
); 
 867 /* this has to be char, not wxChar */ 
 868 static char hexArray
[] = "0123456789ABCDEF"; 
 869 static void LocalDecToHex( int dec
, char *buf 
) 
 871     int firstDigit 
= (int)(dec
/16.0); 
 872     int secondDigit 
= (int)(dec 
- (firstDigit
*16.0)); 
 873     buf
[0] = hexArray
[firstDigit
]; 
 874     buf
[1] = hexArray
[secondDigit
]; 
 878 void wxPostScriptDC::DoDrawBitmap( const wxBitmap
& bitmap
, wxCoord x
, wxCoord y
, bool WXUNUSED(useMask
) ) 
 880     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 882     if (!bitmap
.Ok()) return; 
 884     wxImage 
image( bitmap 
); 
 886     if (!image
.Ok()) return; 
 888     wxCoord w 
= image
.GetWidth(); 
 889     wxCoord h 
= image
.GetHeight(); 
 891     wxCoord ww 
= XLOG2DEVREL(image
.GetWidth()); 
 892     wxCoord hh 
= YLOG2DEVREL(image
.GetHeight()); 
 894     wxCoord xx 
= XLOG2DEV(x
); 
 895     wxCoord yy 
= YLOG2DEV(y 
+ bitmap
.GetHeight()); 
 898             "/origstate save def\n" 
 900             "/pix %d string def\n" 
 901             "/grays %d string def\n" 
 908             "{currentfile pix readhexstring pop}\n" 
 909             "false 3 colorimage\n", 
 910             w
, w
, xx
, yy
, ww
, hh
, w
, h
, w
, -h
, h 
); 
 913     for (int j 
= 0; j 
< h
; j
++) 
 915         for (int i 
= 0; i 
< w
; i
++) 
 918             LocalDecToHex( image
.GetRed(i
,j
), buffer 
); 
 919             fprintf( m_pstream
, buffer 
); 
 920             LocalDecToHex( image
.GetGreen(i
,j
), buffer 
); 
 921             fprintf( m_pstream
, buffer 
); 
 922             LocalDecToHex( image
.GetBlue(i
,j
), buffer 
); 
 923             fprintf( m_pstream
, buffer 
); 
 925         fprintf( m_pstream
, "\n" ); 
 928     fprintf( m_pstream
, "end\n" ); 
 929     fprintf( m_pstream
, "origstate restore\n" ); 
 932 void wxPostScriptDC::SetFont( const wxFont
& font 
) 
 934     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 936     if (!font
.Ok())  return; 
 940     int Style 
= m_font
.GetStyle(); 
 941     int Weight 
= m_font
.GetWeight(); 
 944     switch (m_font
.GetFamily()) 
 949             if (Style 
== wxITALIC
) 
 951                 if (Weight 
== wxBOLD
) 
 952                     name 
= "/Courier-BoldOblique"; 
 954                     name 
= "/Courier-Oblique"; 
 958                 if (Weight 
== wxBOLD
) 
 959                     name 
= "/Courier-Bold"; 
 967             if (Style 
== wxITALIC
) 
 969                 if (Weight 
== wxBOLD
) 
 970                     name 
= "/Times-BoldItalic"; 
 972                     name 
= "/Times-Italic"; 
 976                 if (Weight 
== wxBOLD
) 
 977                     name 
= "/Times-Bold"; 
 979                     name 
= "/Times-Roman"; 
 985             name 
= "/ZapfChancery-MediumItalic"; 
 993             if (Style 
== wxITALIC
) 
 995                 if (Weight 
== wxBOLD
) 
 996                     name 
= "/Helvetica-BoldOblique"; 
 998                     name 
= "/Helvetica-Oblique"; 
1002                 if (Weight 
== wxBOLD
) 
1003                     name 
= "/Helvetica-Bold"; 
1005                     name 
= "/Helvetica"; 
1011     fprintf( m_pstream
, name 
); 
1012     fprintf( m_pstream
, " reencodeISO def\n" ); 
1013     fprintf( m_pstream
, name 
); 
1014     fprintf( m_pstream
, " findfont\n" ); 
1017     sprintf( buffer
, "%f scalefont setfont\n", YLOG2DEVREL(m_font
.GetPointSize() * 1000) / 1000.0F
); 
1018                 // this is a hack - we must scale font size (in pts) according to m_scaleY but 
1019                 // YLOG2DEVREL works with wxCoord type (int or longint). Se we first convert font size 
1020                 // to 1/1000th of pt and then back. 
1021     for (int i 
= 0; i 
< 100; i
++) 
1022         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1023     fprintf( m_pstream
, buffer 
); 
1026 void wxPostScriptDC::SetPen( const wxPen
& pen 
) 
1028     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1030     if (!pen
.Ok()) return; 
1032     int oldStyle 
= m_pen
.GetStyle(); 
1039         sprintf( buffer
, "%f setlinewidth\n", XLOG2DEVREL(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1041         sprintf( buffer
, "%f setlinewidth\n", XLOG2DEVREL(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1043         for (int i 
= 0; i 
< 100; i
++) 
1044             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1045         fprintf( m_pstream
, buffer 
); 
1049      Line style - WRONG: 2nd arg is OFFSET 
1051      Here, I'm afraid you do not conceive meaning of parameters of 'setdash' 
1052      operator correctly. You should look-up this in the Red Book: the 2nd parame- 
1053      ter is not number of values in the array of the first one, but an offset 
1054      into this description of the pattern. I mean a real *offset* not index 
1055      into array. I.e. If the command is [3 4] 1 setdash   is used, then there 
1056      will be first black line *2* units wxCoord, then space 4 units, then the 
1057      pattern of *3* units black, 4 units space will be repeated. 
1060     static const char *dotted 
= "[2 5] 2"; 
1061     static const char *short_dashed 
= "[4 4] 2"; 
1062     static const char *wxCoord_dashed 
= "[4 8] 2"; 
1063     static const char *dotted_dashed 
= "[6 6 2 6] 4"; 
1065     const char *psdash 
= (char *) NULL
; 
1066     switch (m_pen
.GetStyle()) 
1068         case wxDOT
:           psdash 
= dotted
;         break; 
1069         case wxSHORT_DASH
:    psdash 
= short_dashed
;   break; 
1070         case wxLONG_DASH
:     psdash 
= wxCoord_dashed
;    break; 
1071         case wxDOT_DASH
:      psdash 
= dotted_dashed
;  break; 
1074         default:              psdash 
= "[] 0";         break; 
1077     if (oldStyle 
!= m_pen
.GetStyle()) 
1079         fprintf( m_pstream
, psdash 
); 
1080         fprintf( m_pstream
," setdash\n" ); 
1084     unsigned char red 
= m_pen
.GetColour().Red(); 
1085     unsigned char blue 
= m_pen
.GetColour().Blue(); 
1086     unsigned char green 
= m_pen
.GetColour().Green(); 
1090         // Anything not white is black 
1091         if (! (red 
== (unsigned char) 255 && 
1092                blue 
== (unsigned char) 255 && 
1093                green 
== (unsigned char) 255) ) 
1095             red 
= (unsigned char) 0; 
1096             green 
= (unsigned char) 0; 
1097             blue 
= (unsigned char) 0; 
1102     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1104         double redPS 
= (double)(red
) / 255.0; 
1105         double bluePS 
= (double)(blue
) / 255.0; 
1106         double greenPS 
= (double)(green
) / 255.0; 
1110                 "%.8f %.8f %.8f setrgbcolor\n", 
1111                 redPS
, greenPS
, bluePS 
); 
1112         for (int i 
= 0; i 
< 100; i
++) 
1113             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1114         fprintf( m_pstream
, buffer 
); 
1117         m_currentBlue 
= blue
; 
1118         m_currentGreen 
= green
; 
1122 void wxPostScriptDC::SetBrush( const wxBrush
& brush 
) 
1124     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1126     if (!brush
.Ok()) return; 
1131     unsigned char red 
= m_brush
.GetColour().Red(); 
1132     unsigned char blue 
= m_brush
.GetColour().Blue(); 
1133     unsigned char green 
= m_brush
.GetColour().Green(); 
1137         // Anything not white is black 
1138         if (! (red 
== (unsigned char) 255 && 
1139                blue 
== (unsigned char) 255 && 
1140                green 
== (unsigned char) 255) ) 
1142             red 
= (unsigned char) 0; 
1143             green 
= (unsigned char) 0; 
1144             blue 
= (unsigned char) 0; 
1149     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1151         double redPS 
= (double)(red
) / 255.0; 
1152         double bluePS 
= (double)(blue
) / 255.0; 
1153         double greenPS 
= (double)(green
) / 255.0; 
1157                 "%.8f %.8f %.8f setrgbcolor\n", 
1158                 redPS
, greenPS
, bluePS 
); 
1159         for (int i 
= 0; i 
< 100; i
++) 
1160             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1161         fprintf( m_pstream
, buffer 
); 
1164         m_currentBlue 
= blue
; 
1165         m_currentGreen 
= green
; 
1169 void wxPostScriptDC::DoDrawText( const wxString
& text
, wxCoord x
, wxCoord y 
) 
1171     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1173     wxCoord text_w
, text_h
, text_descent
; 
1175     GetTextExtent(text
, &text_w
, &text_h
, &text_descent
); 
1177     // VZ: this seems to be unnecessary, so taking it out for now, if it 
1178     //     doesn't create any problems, remove this comment entirely 
1179     //SetFont( m_font ); 
1181     if (m_textForegroundColour
.Ok()) 
1183         unsigned char red 
= m_textForegroundColour
.Red(); 
1184         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1185         unsigned char green 
= m_textForegroundColour
.Green(); 
1189             // Anything not white is black 
1190             if (! (red 
== (unsigned char) 255 && 
1191                         blue 
== (unsigned char) 255 && 
1192                         green 
== (unsigned char) 255)) 
1194                 red 
= (unsigned char) 0; 
1195                 green 
= (unsigned char) 0; 
1196                 blue 
= (unsigned char) 0; 
1200         // maybe setgray here ? 
1201         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1203             double redPS 
= (double)(red
) / 255.0; 
1204             double bluePS 
= (double)(blue
) / 255.0; 
1205             double greenPS 
= (double)(green
) / 255.0; 
1209                 "%.8f %.8f %.8f setrgbcolor\n", 
1210                 redPS
, greenPS
, bluePS 
); 
1211             for (int i 
= 0; i 
< 100; i
++) 
1212                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1213             fprintf( m_pstream
, buffer 
); 
1216             m_currentBlue 
= blue
; 
1217             m_currentGreen 
= green
; 
1221     int size 
= m_font
.GetPointSize(); 
1223 //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline 
1224 //    commented by V. Slavik and replaced by accurate version 
1225 //        - note that there is still rounding error in text_descent! 
1226     wxCoord by 
= y 
+ size 
- text_descent
; // baseline 
1227     fprintf( m_pstream
, "%d %d moveto\n", XLOG2DEV(x
), YLOG2DEV(by
) ); 
1229     fprintf( m_pstream
, "(" ); 
1230     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1231     size_t len 
= strlen(textbuf
); 
1233     for (i 
= 0; i 
< len
; i
++) 
1235         int c 
= (unsigned char) textbuf
[i
]; 
1236         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1238             /* Cope with special characters */ 
1239             fprintf( m_pstream
, "\\" ); 
1240             fputc(c
, m_pstream
); 
1242         else if ( c 
>= 128 ) 
1244             /* Cope with character codes > 127 */ 
1245             fprintf(m_pstream
, "\\%o", c
); 
1249             fputc(c
, m_pstream
); 
1253     fprintf( m_pstream
, ") show\n" ); 
1255     if (m_font
.GetUnderlined()) 
1257         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1267                 XLOG2DEV(x
), YLOG2DEV(uy
), 
1268                 m_underlineThickness
, 
1269                 XLOG2DEV(x 
+ text_w
), YLOG2DEV(uy
) ); 
1270         for (i 
= 0; i 
< 100; i
++) 
1271             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1272         fprintf( m_pstream
, buffer 
); 
1275     CalcBoundingBox( x
, y 
); 
1276     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1279 void wxPostScriptDC::DoDrawRotatedText( const wxString
& text
, wxCoord x
, wxCoord y
, double angle 
) 
1283         DoDrawText(text
, x
, y
); 
1287     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1291     if (m_textForegroundColour
.Ok()) 
1293         unsigned char red 
= m_textForegroundColour
.Red(); 
1294         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1295         unsigned char green 
= m_textForegroundColour
.Green(); 
1299             // Anything not white is black 
1300             if (! (red 
== (unsigned char) 255 && 
1301                    blue 
== (unsigned char) 255 && 
1302                    green 
== (unsigned char) 255)) 
1304                 red 
= (unsigned char) 0; 
1305                 green 
= (unsigned char) 0; 
1306                 blue 
= (unsigned char) 0; 
1310         // maybe setgray here ? 
1311         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1313             double redPS 
= (double)(red
) / 255.0; 
1314             double bluePS 
= (double)(blue
) / 255.0; 
1315             double greenPS 
= (double)(green
) / 255.0; 
1319                 "%.8f %.8f %.8f setrgbcolor\n", 
1320                 redPS
, greenPS
, bluePS 
); 
1321             for (int i 
= 0; i 
< 100; i
++) 
1322                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1323             fprintf( m_pstream
, buffer 
); 
1326             m_currentBlue 
= blue
; 
1327             m_currentGreen 
= green
; 
1331     int size 
= m_font
.GetPointSize(); 
1333     long by 
= y 
+ (long)floor( double(size
) * 2.0 / 3.0 ); // approximate baseline 
1335     // FIXME only correct for 90 degrees 
1336     fprintf(m_pstream
, "%d %d moveto\n", 
1337             XLOG2DEV((wxCoord
)(x 
+ size
)), YLOG2DEV((wxCoord
)by
) ); 
1340     sprintf(buffer
, "%.8f rotate\n", angle
); 
1342     for (i 
= 0; i 
< 100; i
++) 
1343         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1344     fprintf(m_pstream
, buffer
); 
1346     fprintf( m_pstream
, "(" ); 
1347     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1348     size_t len 
= strlen(textbuf
); 
1349     for (i 
= 0; i 
< len
; i
++) 
1351         int c 
= (unsigned char) textbuf
[i
]; 
1352         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1354             /* Cope with special characters */ 
1355             fprintf( m_pstream
, "\\" ); 
1356             fputc(c
, m_pstream
); 
1358         else if ( c 
>= 128 ) 
1360             /* Cope with character codes > 127 */ 
1361             fprintf(m_pstream
, "\\%o", c
); 
1365             fputc(c
, m_pstream
); 
1369     fprintf( m_pstream
, ") show\n" ); 
1371     sprintf( buffer
, "%.8f rotate\n", -angle 
); 
1372     for (i 
= 0; i 
< 100; i
++) 
1373         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1374     fprintf( m_pstream
, buffer 
); 
1376     if (m_font
.GetUnderlined()) 
1378         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1381         GetTextExtent(text
, &w
, &h
); 
1390                  XLOG2DEV(x
), YLOG2DEV(uy
), 
1391                  m_underlineThickness
, 
1392                  XLOG2DEV(x 
+ w
), YLOG2DEV(uy
) ); 
1393         for (i 
= 0; i 
< 100; i
++) 
1394             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1395         fprintf( m_pstream
, buffer 
); 
1398     CalcBoundingBox( x
, y 
); 
1399     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1402 void wxPostScriptDC::SetBackground (const wxBrush
& brush
) 
1404     m_backgroundBrush 
= brush
; 
1407 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function
)) 
1409     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); 
1412 void wxPostScriptDC::DoDrawSpline( wxList 
*points 
) 
1414     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1418     double a
, b
, c
, d
, x1
, y1
, x2
, y2
, x3
, y3
; 
1421     wxNode 
*node 
= points
->First(); 
1422     p 
= (wxPoint 
*)node
->Data(); 
1426     node 
= node
->Next(); 
1427     p 
= (wxPoint 
*)node
->Data(); 
1430     x3 
= a 
= (double)(x1 
+ c
) / 2; 
1431     y3 
= b 
= (double)(y1 
+ d
) / 2; 
1437             XLOG2DEV((wxCoord
)x1
), YLOG2DEV((wxCoord
)y1
), 
1438             XLOG2DEV((wxCoord
)x3
), YLOG2DEV((wxCoord
)y3
) ); 
1440     CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1441     CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1443     while ((node 
= node
->Next()) != NULL
) 
1445         q 
= (wxPoint 
*)node
->Data(); 
1453         x3 
= (double)(x2 
+ c
) / 2; 
1454         y3 
= (double)(y2 
+ d
) / 2; 
1457                 "%d %d %d %d %d %d DrawSplineSection\n", 
1458                 XLOG2DEV((wxCoord
)x1
), YLOG2DEV((wxCoord
)y1
), 
1459                 XLOG2DEV((wxCoord
)x2
), YLOG2DEV((wxCoord
)y2
), 
1460                 XLOG2DEV((wxCoord
)x3
), YLOG2DEV((wxCoord
)y3
) ); 
1462         CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1463         CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1467        At this point, (x2,y2) and (c,d) are the position of the 
1468        next-to-last and last point respectively, in the point list 
1474             XLOG2DEV((wxCoord
)c
), YLOG2DEV((wxCoord
)d
) ); 
1477 wxCoord 
wxPostScriptDC::GetCharWidth() const 
1479     // Chris Breeze: reasonable approximation using wxMODERN/Courier 
1480     return (wxCoord
) (GetCharHeight() * 72.0 / 120.0); 
1484 void wxPostScriptDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
1486     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1488     m_signX 
= (xLeftRight 
? 1 : -1); 
1489     m_signY 
= (yBottomUp  
? 1 : -1); 
1491     // FIXME there is no such function in MSW nor in OS2/PM 
1492 #if !defined(__WXMSW__) && !defined(__WXPM__) 
1493     ComputeScaleAndOrigin(); 
1497 void wxPostScriptDC::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
1499     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1505     wxDC::SetDeviceOrigin( x
, h
-y 
); 
1508 void wxPostScriptDC::DoGetSize(int* width
, int* height
) const 
1510     wxPaperSize id 
= m_printData
.GetPaperId(); 
1512     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1514     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1520         w 
= paper
->GetSizeDeviceUnits().x
; 
1521         h 
= paper
->GetSizeDeviceUnits().y
; 
1524     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1531     if (width
) *width 
= (int)(w 
* ms_PSScaleFactor
); 
1532     if (height
) *height 
= (int)(h 
* ms_PSScaleFactor
); 
1535 void wxPostScriptDC::DoGetSizeMM(int *width
, int *height
) const 
1537     wxPaperSize id 
= m_printData
.GetPaperId(); 
1539     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1541     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1547         w 
= paper
->GetWidth() / 10; 
1548         h 
= paper
->GetHeight() / 10; 
1551     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1558     if (width
) *width 
= w
; 
1559     if (height
) *height 
= h
; 
1562 // Resolution in pixels per logical inch 
1563 wxSize 
wxPostScriptDC::GetPPI(void) const 
1565     return wxSize((int)(72 * ms_PSScaleFactor
), 
1566                   (int)(72 * ms_PSScaleFactor
)); 
1570 bool wxPostScriptDC::StartDoc( const wxString
& message 
) 
1572     wxCHECK_MSG( m_ok
, FALSE
, wxT("invalid postscript dc") ); 
1574     if (m_printData
.GetFilename() == "") 
1576         wxString filename 
= wxGetTempFileName("ps"); 
1577         m_printData
.SetFilename(filename
); 
1580     m_pstream 
= wxFopen( m_printData
.GetFilename().fn_str(), wxT("w+") ); 
1584         wxLogError( _("Cannot open file for PostScript printing!")); 
1591     fprintf( m_pstream
, "%%%%BeginProlog\n" ); 
1592     fprintf( m_pstream
, wxPostScriptHeaderEllipse 
); 
1593     fprintf( m_pstream
, wxPostScriptHeaderEllipticArc 
); 
1594     fprintf( m_pstream
, wxPostScriptHeaderColourImage 
); 
1595     fprintf( m_pstream
, wxPostScriptHeaderReencodeISO1 
); 
1596     fprintf( m_pstream
, wxPostScriptHeaderReencodeISO2 
); 
1597     if (wxPostScriptHeaderSpline
) 
1598         fprintf( m_pstream
, wxPostScriptHeaderSpline 
); 
1599     fprintf( m_pstream
, "%%%%EndProlog\n" ); 
1601     SetBrush( *wxBLACK_BRUSH 
); 
1602     SetPen( *wxBLACK_PEN 
); 
1603     SetBackground( *wxWHITE_BRUSH 
); 
1604     SetTextForeground( *wxBLACK 
); 
1606     // set origin according to paper size 
1607     SetDeviceOrigin( 0,0 ); 
1615 void wxPostScriptDC::EndDoc () 
1617     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1622         fprintf( m_pstream
, "grestore\n" ); 
1625     fclose( m_pstream 
); 
1626     m_pstream 
= (FILE *) NULL
; 
1628     wxChar 
*header_file 
= wxGetTempFileName("ps"); 
1630     m_pstream 
= fopen( wxConvFile
.cWX2MB(header_file
) , "w+" ); 
1632     fprintf( m_pstream
, "%%!PS-Adobe-2.0\n" );                     // PostScript magic strings 
1633     fprintf( m_pstream
, "%%%%Title: %s\n", (const char *)m_title
.mb_str() ); 
1634     fprintf( m_pstream
, "%%%%Creator: %s\n", (const char*)wxConvCurrent
->cWX2MB(wxTheApp
->argv
[0]) ); 
1635     fprintf( m_pstream
, "%%%%CreationDate: %s\n", (const char *)wxNow().mb_str() ); 
1638     if ( wxGetEmailAddress(userID
, sizeof(userID
)) ) 
1640         fprintf( m_pstream
, "%%%%For: %s ", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userID
) ); 
1641         wxChar userName
[245]; 
1642         if (wxGetUserName(userName
, sizeof(userName
))) 
1643             fprintf( m_pstream
, " (%s)", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userName
) ); 
1644         fprintf( m_pstream
, "\n" ); 
1646     else if ( wxGetUserName(userID
, sizeof(userID
)) ) 
1648         fprintf( m_pstream
, "%%%%For: %s\n", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userID
) );; 
1651     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com> 
1653     wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
1654     double wx_printer_scale_x
, wx_printer_scale_y
; 
1656     wx_printer_translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1657     wx_printer_translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1659     wx_printer_scale_x 
= m_printData
.GetPrinterScaleX(); 
1660     wx_printer_scale_y 
= m_printData
.GetPrinterScaleY(); 
1662     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1663         fprintf( m_pstream
, "%%%%Orientation: Landscape\n" ); 
1665         fprintf( m_pstream
, "%%%%Orientation: Portrait\n" ); 
1667     // Compute the bounding box.  Note that it is in the default user 
1668     // coordinate system, thus we have to convert the values. 
1669     wxCoord minX 
= (wxCoord
) XLOG2DEV(m_minX
); 
1670     wxCoord minY 
= (wxCoord
) YLOG2DEV(m_minY
); 
1671     wxCoord maxX 
= (wxCoord
) XLOG2DEV(m_maxX
); 
1672     wxCoord maxY 
= (wxCoord
) YLOG2DEV(m_maxY
); 
1674     // LOG2DEV may have changed the minimum to maximum vice versa 
1675     if ( minX 
> maxX 
) { wxCoord tmp 
= minX
; minX 
= maxX
; maxX 
= tmp
; } 
1676     if ( minY 
> maxY 
) { wxCoord tmp 
= minY
; minY 
= maxY
; maxY 
= tmp
; } 
1678     // account for used scaling (boundingbox is before scaling in ps-file) 
1679     double scale_x 
= m_printData
.GetPrinterScaleX() / ms_PSScaleFactor
; 
1680     double scale_y 
= m_printData
.GetPrinterScaleY() / ms_PSScaleFactor
; 
1682     wxCoord llx
, lly
, urx
, ury
; 
1683     llx 
= (wxCoord
) ((minX
+wx_printer_translate_x
)*scale_x
); 
1684     lly 
= (wxCoord
) ((minY
+wx_printer_translate_y
)*scale_y
); 
1685     urx 
= (wxCoord
) ((maxX
+wx_printer_translate_x
)*scale_x
); 
1686     ury 
= (wxCoord
) ((maxY
+wx_printer_translate_y
)*scale_y
); 
1687     // (end of bounding box computation) 
1690     // If we're landscape, our sense of "x" and "y" is reversed. 
1691     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1694         tmp 
= llx
; llx 
= lly
; lly 
= tmp
; 
1695         tmp 
= urx
; urx 
= ury
; ury 
= tmp
; 
1697         // We need either the two lines that follow, or we need to subtract 
1698         // min_x from real_translate_y, which is commented out below. 
1699         llx 
= llx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1700         urx 
= urx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1703     // The Adobe specifications call for integers; we round as to make 
1704     // the bounding larger. 
1706             "%%%%BoundingBox: %d %d %d %d\n", 
1707             (wxCoord
)floor((double)llx
), (wxCoord
)floor((double)lly
), 
1708             (wxCoord
)ceil((double)urx
), (wxCoord
)ceil((double)ury
) ); 
1709     fprintf( m_pstream
, "%%%%Pages: %d\n", (wxPageNumber 
- 1) ); 
1710     fprintf( m_pstream
, "%%%%EndComments\n\n" ); 
1712     // To check the correctness of the bounding box, postscript commands 
1713     // to draw a box corresponding to the bounding box are generated below. 
1714     // But since we typically don't want to print such a box, the postscript 
1715     // commands are generated within comments.  These lines appear before any 
1716     // adjustment of scale, rotation, or translation, and hence are in the 
1717     // default user coordinates. 
1718     fprintf( m_pstream
, "%% newpath\n" ); 
1719     fprintf( m_pstream
, "%% %d %d moveto\n", llx
, lly 
); 
1720     fprintf( m_pstream
, "%% %d %d lineto\n", urx
, lly 
); 
1721     fprintf( m_pstream
, "%% %d %d lineto\n", urx
, ury 
); 
1722     fprintf( m_pstream
, "%% %d %d lineto closepath stroke\n", llx
, ury 
); 
1724     fclose( m_pstream 
); 
1725     m_pstream 
= (FILE*) NULL
; 
1727     wxChar 
*tmp_file 
= wxGetTempFileName("ps"); 
1729     // Paste header Before wx_printer_file 
1730     wxConcatFiles (header_file
, m_printData
.GetFilename(), tmp_file 
); 
1731     wxRemoveFile( header_file 
); 
1732     wxRemoveFile( m_printData
.GetFilename() ); 
1733     wxRenameFile( tmp_file
, m_printData
.GetFilename() ); 
1735 #if defined(__X__) || defined(__WXGTK__) 
1738         wxString 
previewCommand(m_printData
.GetPreviewCommand()); 
1739         wxString 
printerCommand(m_printData
.GetPrinterCommand()); 
1740         wxString 
printerOptions(m_printData
.GetPrinterOptions()); 
1741         wxString 
filename(m_printData
.GetFilename()); 
1743         switch (m_printData
.GetPrintMode()) 
1745             case wxPRINT_MODE_PREVIEW
: 
1748                 argv
[0] = WXSTRINGCAST previewCommand
; 
1749                 argv
[1] = WXSTRINGCAST filename
; 
1750                 argv
[2] = (wxChar
*) NULL
; 
1751                 wxExecute( argv
, TRUE 
); 
1752                 wxRemoveFile( m_printData
.GetFilename() ); 
1755             case wxPRINT_MODE_PRINTER
: 
1759                 argv
[argc
++] = WXSTRINGCAST printerCommand
; 
1761                 // !SM! If we simply assign to argv[1] here, if printer options 
1762                 // are blank, we get an annoying and confusing message from lpr. 
1763                 wxChar 
*opts 
= WXSTRINGCAST printerOptions
; 
1765                     argv
[argc
++] = opts
; 
1767                 argv
[argc
++] = WXSTRINGCAST filename
; 
1768                 argv
[argc
++] = (wxChar 
*) NULL
; 
1769                 wxExecute( argv
, TRUE 
); 
1770                 wxRemoveFile( filename 
); 
1773             case wxPRINT_MODE_FILE
: 
1774             case wxPRINT_MODE_NONE
: 
1781 void wxPostScriptDC::StartPage() 
1783     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1785     fprintf( m_pstream
, "%%%%Page: %d\n", wxPageNumber
++ ); 
1787     //  What is this one supposed to do? RR. 
1788 //  *m_pstream << "matrix currentmatrix\n"; 
1790     // Added by Chris Breeze 
1792     // Each page starts with an "initgraphics" which resets the 
1793     // transformation and so we need to reset the origin 
1794     // (and rotate the page for landscape printing) 
1797     wxCoord translate_x
, translate_y
; 
1798     double scale_x
, scale_y
; 
1800     translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1801     translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1803     scale_x 
= m_printData
.GetPrinterScaleX(); 
1804     scale_y 
= m_printData
.GetPrinterScaleY(); 
1806     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1809         GetSize( (int*) NULL
, &h 
); 
1811         fprintf( m_pstream
, "90 rotate\n" ); 
1813         // I copied this one from a PostScript tutorial, but to no avail. RR. 
1814         // fprintf( m_pstream, "90 rotate llx neg ury nef translate\n" ); 
1818     sprintf( buffer
, "%.8f %.8f scale\n", scale_x 
/ ms_PSScaleFactor
, 
1819                                           scale_y 
/ ms_PSScaleFactor
); 
1820     for (int i 
= 0; i 
< 100; i
++) 
1821         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1822     fprintf( m_pstream
, buffer 
); 
1824     fprintf( m_pstream
, "%d %d translate\n", translate_x
, translate_y 
); 
1827 void wxPostScriptDC::EndPage () 
1829     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1831     fprintf( m_pstream
, "showpage\n" ); 
1834 bool wxPostScriptDC::DoBlit( wxCoord xdest
, wxCoord ydest
, 
1835                            wxCoord fwidth
, wxCoord fheight
, 
1837                            wxCoord xsrc
, wxCoord ysrc
, 
1838                            int rop
, bool WXUNUSED(useMask
), wxCoord 
WXUNUSED(xsrcMask
), wxCoord 
WXUNUSED(ysrcMask
) ) 
1840     wxCHECK_MSG( m_ok 
&& m_pstream
, FALSE
, wxT("invalid postscript dc") ); 
1842     wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") ); 
1844     /* blit into a bitmap */ 
1845     wxBitmap 
bitmap( (int)fwidth
, (int)fheight 
); 
1847     memDC
.SelectObject(bitmap
); 
1848     memDC
.Blit(0, 0, fwidth
, fheight
, source
, xsrc
, ysrc
, rop
); /* TODO: Blit transparently? */ 
1849     memDC
.SelectObject(wxNullBitmap
); 
1851     /* draw bitmap. scaling and positioning is done there */ 
1852     DrawBitmap( bitmap
, xdest
, ydest 
); 
1857 wxCoord 
wxPostScriptDC::GetCharHeight() const 
1860         return m_font
.GetPointSize(); 
1865 void wxPostScriptDC::DoGetTextExtent(const wxString
& string
, 
1866                                      wxCoord 
*x
, wxCoord 
*y
, 
1867                                      wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1868                                      wxFont 
*theFont 
) const 
1870     wxFont 
*fontToUse 
= theFont
; 
1872     if (!fontToUse
) fontToUse 
= (wxFont
*) &m_font
; 
1874     wxCHECK_RET( fontToUse
, wxT("GetTextExtent: no font defined") ); 
1876     const wxWX2MBbuf strbuf 
= string
.mb_str(); 
1878 #if !wxUSE_AFM_FOR_POSTSCRIPT 
1879     /* Provide a VERY rough estimate (avoid using it). 
1880      * Produces accurate results for mono-spaced font 
1881      * such as Courier (aka wxMODERN) */ 
1886         height 
= fontToUse
->GetPointSize(); 
1889         *x 
= strlen (strbuf
) * height 
* 72 / 120; 
1891         *y 
= (wxCoord
) (height 
* 1.32);    /* allow for descender */ 
1892     if (descent
) *descent 
= 0; 
1893     if (externalLeading
) *externalLeading 
= 0; 
1896     /* method for calculating string widths in postscript: 
1897     /  read in the AFM (adobe font metrics) file for the 
1898     /  actual font, parse it and extract the character widths 
1899     /  and also the descender. this may be improved, but for now 
1900     /  it works well. the AFM file is only read in if the 
1901     /  font is changed. this may be chached in the future. 
1902     /  calls to GetTextExtent with the font unchanged are rather 
1905     /  for each font and style used there is an AFM file necessary. 
1906     /  currently i have only files for the roman font family. 
1907     /  I try to get files for the other ones! 
1909     /  CAVE: the size of the string is currently always calculated 
1910     /        in 'points' (1/72 of an inch). this should later on be 
1911     /        changed to depend on the mapping mode. 
1912     /  CAVE: the path to the AFM files must be set before calling this 
1913     /        function. this is usually done by a call like the following: 
1914     /        wxSetAFMPath("d:\\wxw161\\afm\\"); 
1918     /    wxPostScriptDC dc(NULL, TRUE); 
1920     /      wxSetAFMPath("d:\\wxw161\\afm\\"); 
1921     /      dc.StartDoc("Test"); 
1924     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); 
1925     /      dc.GetTextExtent("Hallo",&w,&h); 
1930     /  by steve (stefan.hammes@urz.uni-heidelberg.de) 
1932     /  updated: 14.05.95 */ 
1934     /* these static vars are for storing the state between calls */ 
1935     static int lastFamily
= INT_MIN
; 
1936     static int lastSize
= INT_MIN
; 
1937     static int lastStyle
= INT_MIN
; 
1938     static int lastWeight
= INT_MIN
; 
1939     static int lastDescender 
= INT_MIN
; 
1940     static int lastWidths
[256]; /* widths of the characters */ 
1942     double UnderlinePosition 
= 0.0; 
1943     double UnderlineThickness 
= 0.0; 
1945     /* get actual parameters */ 
1946     int Family 
= fontToUse
->GetFamily(); 
1947     int Size 
=   fontToUse
->GetPointSize(); 
1948     int Style 
=  fontToUse
->GetStyle(); 
1949     int Weight 
= fontToUse
->GetWeight(); 
1951     /* if we have another font, read the font-metrics */ 
1952     if (Family
!=lastFamily 
|| Size
!=lastSize 
|| Style
!=lastStyle 
|| Weight
!=lastWeight
) 
1954         /* store actual values */ 
1955         lastFamily 
= Family
; 
1958         lastWeight 
= Weight
; 
1960         char *name 
= (char*) NULL
; 
1967                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "CourBoO.afm"; 
1968                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "CourBo.afm"; 
1969                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "CourO.afm"; 
1970                 else name 
= "Cour.afm"; 
1975                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "TimesBoO.afm"; 
1976                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "TimesBo.afm"; 
1977                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "TimesO.afm"; 
1978                 else name 
= "TimesRo.afm"; 
1990                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "HelvBoO.afm"; 
1991                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "HelvBo.afm"; 
1992                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "HelvO.afm"; 
1993                 else name 
= "Helv.afm"; 
1998         /* get the directory of the AFM files */ 
1999         wxString afmName 
= wxEmptyString
; 
2000         if (!m_printData
.GetFontMetricPath().IsEmpty()) 
2002             afmName 
= m_printData
.GetFontMetricPath(); 
2005         /* 2. open and process the file 
2006            /  a short explanation of the AFM format: 
2007            /  we have for each character a line, which gives its size 
2010            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; 
2012            /  that means, we have a character with ascii code 63, and width 
2013            /  (444/1000 * fontSize) points. 
2014            /  the other data is ignored for now! 
2016            /  when the font has changed, we read in the right AFM file and store the 
2017            /  character widths in an array, which is processed below (see point 3.). */ 
2019         /* new elements JC Sun Aug 25 23:21:44 MET DST 1996 */ 
2022         FILE *afmFile 
= wxFopen(afmName
,wxT("r")); 
2026            afmName 
= wxThePrintSetupData
->GetAFMPath(); 
2027            afmName 
<< wxFILE_SEP_PATH 
<< name
; 
2028            afmFile 
= wxFopen(afmName
,wxT("r")); 
2031 #if defined(__UNIX__) && !defined(__VMS__) 
2033         /* please do NOT change the line above to "else if (afmFile==NULL)" - 
2034            - afmFile = fopen() may fail and in that case the next if branch 
2035            MUST be executed - and it would not if there was "else" */ 
2037            afmName 
= wxGetDataDir(); 
2038            afmName 
<<  wxFILE_SEP_PATH
 
2039 #if defined(__LINUX__) || defined(__FREEBSD__) 
2040                    << wxT("gs_afm") << wxFILE_SEP_PATH
 
2042                    << wxT("afm") << wxFILE_SEP_PATH
 
2045            afmFile 
= wxFopen(afmName
,wxT("r")); 
2051             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%hs'"), afmName
.c_str() ); 
2052             wxLogDebug( wxT("               using approximate values")); 
2053             for (int i
=0; i
<256; i
++) lastWidths
[i
] = 500; /* an approximate value */ 
2054             lastDescender 
= -150; /* dito. */ 
2058             /* init the widths array */ 
2059             for(int i
=0; i
<256; i
++) lastWidths
[i
] = INT_MIN
; 
2060             /* some variables for holding parts of a line */ 
2061             char cString
[10],semiString
[10],WXString
[10],descString
[20]; 
2062             char upString
[30], utString
[30], encString
[50]; 
2065             /* read in the file and parse it */ 
2066             while(fgets(line
,sizeof(line
),afmFile
)!=NULL
) 
2068                 /* A.) check for descender definition */ 
2069                 if (strncmp(line
,"Descender",9)==0) 
2071                     if ((sscanf(line
,"%s%d",descString
,&lastDescender
)!=2) || 
2072                             (strcmp(descString
,"Descender")!=0)) 
2074                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad descender)"), afmName
.c_str(),line 
); 
2077                 /* JC 1.) check for UnderlinePosition */ 
2078                 else if(strncmp(line
,"UnderlinePosition",17)==0) 
2080                     if ((sscanf(line
,"%s%lf",upString
,&UnderlinePosition
)!=2) || 
2081                             (strcmp(upString
,"UnderlinePosition")!=0)) 
2083                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlinePosition)"), afmName
.c_str(), line 
); 
2086                 /* JC 2.) check for UnderlineThickness */ 
2087                 else if(strncmp(line
,"UnderlineThickness",18)==0) 
2089                     if ((sscanf(line
,"%s%lf",utString
,&UnderlineThickness
)!=2) || 
2090                             (strcmp(utString
,"UnderlineThickness")!=0)) 
2092                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlineThickness)"), afmName
.c_str(), line 
); 
2095                 /* JC 3.) check for EncodingScheme */ 
2096                 else if(strncmp(line
,"EncodingScheme",14)==0) 
2098                     if ((sscanf(line
,"%s%s",utString
,encString
)!=2) || 
2099                             (strcmp(utString
,"EncodingScheme")!=0)) 
2101                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad EncodingScheme)"), afmName
.c_str(), line 
); 
2103                     else if (strncmp(encString
, "AdobeStandardEncoding", 21)) 
2105                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (unsupported EncodingScheme %hs)"), 
2106                                 afmName
.c_str(),line
, encString
); 
2109                 /* B.) check for char-width */ 
2110                 else if(strncmp(line
,"C ",2)==0) 
2112                     if (sscanf(line
,"%s%d%s%s%d",cString
,&ascii
,semiString
,WXString
,&cWidth
)!=5) 
2114                         wxLogDebug(wxT("AFM-file '%hs': line '%hs' has an error (bad character width)"),afmName
.c_str(),line
); 
2116                     if(strcmp(cString
,"C")!=0 || strcmp(semiString
,";")!=0 || strcmp(WXString
,"WX")!=0) 
2118                         wxLogDebug(wxT("AFM-file '%hs': line '%hs' has a format error"),afmName
.c_str(),line
); 
2120                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ 
2121                     if (ascii
>=0 && ascii
<256) 
2123                         lastWidths
[ascii
] = cWidth
; /* store width */ 
2127                         /* MATTHEW: this happens a lot; don't print an error */ 
2128                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ 
2131                 /* C.) ignore other entries. */ 
2135         /* hack to compute correct values for german 'Umlaute' 
2136            /  the correct way would be to map the character names 
2137            /  like 'adieresis' to corresp. positions of ISOEnc and read 
2138            /  these values from AFM files, too. Maybe later ... */ 
2139         lastWidths
[196] = lastWidths
['A'];  // Ä 
2140         lastWidths
[228] = lastWidths
['a'];  // ä 
2141         lastWidths
[214] = lastWidths
['O'];  // Ö 
2142         lastWidths
[246] = lastWidths
['o'];  // ö 
2143         lastWidths
[220] = lastWidths
['U'];  // Ü 
2144         lastWidths
[252] = lastWidths
['u'];  // ü 
2145         lastWidths
[223] = lastWidths
[251];  // ß 
2147         /* JC: calculate UnderlineThickness/UnderlinePosition */ 
2149         // VS: dirty, but is there any better solution? 
2151         pt 
= (double*) &m_underlinePosition
; 
2152         *pt 
= YLOG2DEVREL((wxCoord
)(UnderlinePosition 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2153         pt 
= (double*) &m_underlineThickness
; 
2154         *pt 
= YLOG2DEVREL((wxCoord
)(UnderlineThickness 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2159     /* 3. now the font metrics are read in, calc size this 
2160        /  is done by adding the widths of the characters in the 
2161        /  string. they are given in 1/1000 of the size! */ 
2164     wxCoord height
=Size
; /* by default */ 
2166     for(p
=(unsigned char *)wxMBSTRINGCAST strbuf
; *p
; p
++) 
2168         if(lastWidths
[*p
]== INT_MIN
) 
2170             wxLogDebug(wxT("GetTextExtent: undefined width for character '%hc' (%d)"), *p
,*p
); 
2171             sum 
+= lastWidths
[' ']; /* assume space */ 
2175             sum 
+= lastWidths
[*p
]; 
2179     double widthSum 
= sum
; 
2181     widthSum 
/= 1000.0F
; 
2183     /* add descender to height (it is usually a negative value) */ 
2184     //if (lastDescender != INT_MIN) 
2186     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ 
2188     // - commented by V. Slavik - height already contains descender in it 
2189     //   (judging from few experiments) 
2191     /* return size values */ 
2193         *x 
= (wxCoord
)widthSum
; 
2197     /* return other parameters */ 
2200         if(lastDescender
!=INT_MIN
) 
2202             *descent 
= (wxCoord
)(((-lastDescender
)/1000.0F
) * Size
); /* MATTHEW: forgot scale */ 
2210     /* currently no idea how to calculate this! */ 
2211     if (externalLeading
) *externalLeading 
= 0; 
2216 // Determine the Default Postscript Previewer 
2217 // available on the platform 
2218 #if defined(__SUN__) && defined(__XVIEW__) 
2219 // OpenWindow/NeWS's Postscript Previewer 
2220 # define PS_VIEWER_PROG "pageview" 
2221 #elif defined(__VMS__) 
2222 #define PS_VIEWER_PROG "view/format=ps/select=x_display" 
2223 #elif defined(__SGI__) 
2224 // SGI's Display Postscript Previewer 
2225 //# define PS_VIEWER_PROG "dps" 
2226 # define PS_VIEWER_PROG "xpsview" 
2227 #elif defined(__X__) || defined(__WXGTK__) 
2228 // Front-end to ghostscript 
2229 # define PS_VIEWER_PROG "ghostview" 
2231 // Windows ghostscript/ghostview 
2232 # define PS_VIEWER_PROG "gsview" 
2235 wxPrintSetupData 
*wxThePrintSetupData 
= (wxPrintSetupData 
*) NULL
; 
2237 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC
, wxDC
) 
2238 IMPLEMENT_DYNAMIC_CLASS(wxPrintSetupData
, wxObject
) 
2240 // Redundant now I think 
2242 IMPLEMENT_CLASS(wxPostScriptPrintDialog
, wxDialog
) 
2244 wxPostScriptPrintDialog::wxPostScriptPrintDialog (wxWindow 
*parent
, const wxString
& title
, 
2245             const wxPoint
& pos
, const wxSize
& size
, wxCoord style
): 
2246    wxDialog(parent
, -1, title
, pos
, size
, style
) 
2248    wxBeginBusyCursor(); 
2253       *orientation 
= new wxString
[2], 
2254       *print_modes 
= new wxString
[3]; 
2256    wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
2257    double wx_printer_scale_x
, wx_printer_scale_y
; 
2259    orientation
[0] = _("Portrait"); 
2260    orientation
[1] = _("Landscape"); 
2262    print_modes
[0] = _("Send to Printer"); 
2263    print_modes
[1] = _("Print to File"); 
2264    print_modes
[2] = _("Preview Only"); 
2268    wxButton 
*okBut 
= new wxButton (this, wxID_OK
, _("OK"), wxPoint(5, 5)); 
2269    (void) new wxButton (this, wxID_CANCEL
, _("Cancel"), wxPoint(40, 5)); 
2270    okBut
->SetDefault(); 
2273 #if defined(__WXGTK__) || defined (__WXMOTIF__) 
2274    (void) new wxStaticText( this, -1, _("Printer Command: "), 
2276    (void) new wxTextCtrl( this, wxID_PRINTER_COMMAND
, wxThePrintSetupData
->GetPrinterCommand(), 
2277                           wxPoint(100, yPos
), wxSize(100, -1) ); 
2279    (void) new wxStaticText( this, -1, _("Printer Options: "), 
2280                             wxPoint(210, yPos
) ); 
2281    (void) new wxTextCtrl( this, wxID_PRINTER_OPTIONS
, wxThePrintSetupData
->GetPrinterOptions(), 
2282                           wxPoint(305, yPos
), wxSize(150, -1) ); 
2288    wxRadioBox 
*radio0 
= new wxRadioBox(this, wxID_PRINTER_ORIENTATION
, "Orientation: ", wxPoint(5, yPos
), wxSize(-1,-1), 
2289                                        2,orientation
,2,wxRA_SPECIFY_ROWS
); 
2290    radio0
->SetSelection((int)wxThePrintSetupData
->GetPrinterOrientation() - 1); 
2292   // @@@ Configuration hook 
2293    if ( !wxThePrintSetupData
->GetPrintPreviewCommand() ) 
2294       wxThePrintSetupData
->SetPrintPreviewCommand(PS_VIEWER_PROG
); 
2296    //   wxGetResource ("wxWindows", "PSView", &wxThePrintSetupData->m_previewCommand); 
2298    features 
= (wxThePrintSetupData
->GetPrintPreviewCommand() && 
2299                *wxThePrintSetupData
->GetPrintPreviewCommand()) ? 3 : 2; 
2301    wxRadioBox 
*radio1 
= new wxRadioBox(this, wxID_PRINTER_MODES
, _("PostScript:"), 
2303                                        wxSize(-1,-1), features
, 
2304                                        print_modes
, features
, wxRA_SPECIFY_ROWS
); 
2307    radio1
->Enable(0, FALSE
); 
2308    if (wxThePrintSetupData
->GetPrintPreviewCommand() && *wxThePrintSetupData
->GetPrintPreviewCommand()) 
2309       radio1
->Enable(2, FALSE
); 
2312    radio1
->SetSelection((int)wxThePrintSetupData
->GetPrinterMode()); 
2313    wxThePrintSetupData
->GetPrinterTranslation(&wx_printer_translate_x
, &wx_printer_translate_y
); 
2314    wxThePrintSetupData
->GetPrinterScaling(&wx_printer_scale_x
, &wx_printer_scale_y
); 
2316    sprintf (buf
, "%.2f", wx_printer_scale_x
); 
2319    (void) new wxStaticText(this, -1, _("X Scaling"), wxPoint(5, yPos
)); 
2320    /* wxTextCtrl *text1 = */ (void) new wxTextCtrl(this, wxID_PRINTER_X_SCALE
, buf
, wxPoint(100, yPos
), wxSize(100, -1)); 
2322    sprintf (buf
, "%.2f", wx_printer_scale_y
); 
2323    (void) new wxStaticText(this, -1, _("Y Scaling"), wxPoint(220, yPos
)); 
2324    /* wxTextCtrl *text2 = */ (void) new wxTextCtrl(this, wxID_PRINTER_Y_SCALE
, buf
, wxPoint(320, yPos
), wxSize(100, -1)); 
2328    (void) new wxStaticText(this, -1, _("X Translation"), wxPoint(5, yPos
)); 
2329    sprintf (buf
, "%.2d", wx_printer_translate_x
); 
2330    /* wxTextCtrl *text3 = */ (void) new wxTextCtrl(this, wxID_PRINTER_X_TRANS
, buf
, wxPoint(100, yPos
), wxSize(100, -1)); 
2332    (void) new wxStaticText(this, -1, _("Y Translation"), wxPoint(220, yPos
)); 
2333    sprintf (buf
, "%.2d", wx_printer_translate_y
); 
2334    /* wxTextCtrl *text4 = */ (void) new wxTextCtrl(this, wxID_PRINTER_Y_TRANS
, buf
, wxPoint(320, yPos
), wxSize(100, -1)); 
2338    delete[] orientation
; 
2339    delete[] print_modes
; 
2344 int wxPostScriptPrintDialog::ShowModal () 
2346   if ( wxDialog::ShowModal() == wxID_OK 
) 
2348 //    wxTextCtrl *text0 = (wxTextCtrl *)FindWindow(wxID_PRINTER_OPTIONS); 
2349       wxTextCtrl 
*text1 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_X_SCALE
); 
2350       wxTextCtrl 
*text2 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_Y_SCALE
); 
2351       wxTextCtrl 
*text3 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_X_TRANS
); 
2352       wxTextCtrl 
*text4 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_Y_TRANS
); 
2353 //    wxTextCtrl *text_prt = (wxTextCtrl *)FindWindow(wxID_PRINTER_COMMAND); 
2354       wxRadioBox 
*radio0 
= (wxRadioBox 
*)FindWindow(wxID_PRINTER_ORIENTATION
); 
2355       wxRadioBox 
*radio1 
= (wxRadioBox 
*)FindWindow(wxID_PRINTER_MODES
); 
2357       StringToDouble (WXSTRINGCAST text1
->GetValue (), &wxThePrintSetupData
->m_printerScaleX
); 
2358       StringToDouble (WXSTRINGCAST text2
->GetValue (), &wxThePrintSetupData
->m_printerScaleY
); 
2361       StringToLong (WXSTRINGCAST text3
->GetValue (), &dummy
); 
2362       wxThePrintSetupData
->m_printerTranslateX 
= (wxCoord
)dummy
; 
2363       StringToLong (WXSTRINGCAST text4
->GetValue (), &dummy
); 
2364       wxThePrintSetupData
->m_printerTranslateY 
= (wxCoord
)dummy
; 
2367       //      wxThePrintSetupData->SetPrinterOptions(WXSTRINGCAST text0->GetValue ()); 
2368       //      wxThePrintSetupData->SetPrinterCommand(WXSTRINGCAST text_prt->GetValue ()); 
2371       wxThePrintSetupData
->SetPrinterOrientation((radio0
->GetSelection() == 1 ? wxLANDSCAPE 
: wxPORTRAIT
)); 
2374       switch ( radio1
->GetSelection() ) { 
2375         case 0: wxThePrintSetupData
->SetPrinterMode(PS_PRINTER
); break; 
2376         case 1:  wxThePrintSetupData
->SetPrinterMode(PS_FILE
); break; 
2377         case 2: wxThePrintSetupData
->SetPrinterMode(PS_PREVIEW
); break; 
2386 // PostScript printer settings 
2387 // RETAINED FOR BACKWARD COMPATIBILITY 
2388 void wxSetPrinterCommand(const wxString
& cmd
) 
2390   wxThePrintSetupData
->SetPrinterCommand(cmd
); 
2393 void wxSetPrintPreviewCommand(const wxString
& cmd
) 
2395   wxThePrintSetupData
->SetPrintPreviewCommand(cmd
); 
2398 void wxSetPrinterOptions(const wxString
& flags
) 
2400   wxThePrintSetupData
->SetPrinterOptions(flags
); 
2403 void wxSetPrinterFile(const wxString
& f
) 
2405   wxThePrintSetupData
->SetPrinterFile(f
); 
2408 void wxSetPrinterOrientation(int orient
) 
2410   wxThePrintSetupData
->SetPrinterOrientation(orient
); 
2413 void wxSetPrinterScaling(double x
, double y
) 
2415   wxThePrintSetupData
->SetPrinterScaling(x
, y
); 
2418 void wxSetPrinterTranslation(wxCoord x
, wxCoord y
) 
2420   wxThePrintSetupData
->SetPrinterTranslation(x
, y
); 
2423 // 1 = Preview, 2 = print to file, 3 = send to printer 
2424 void wxSetPrinterMode(int mode
) 
2426   wxThePrintSetupData
->SetPrinterMode(mode
); 
2429 void wxSetAFMPath(const wxString
& f
) 
2431   wxThePrintSetupData
->SetAFMPath(f
); 
2434 // Get current values 
2435 wxString 
wxGetPrinterCommand() 
2437   return wxThePrintSetupData
->GetPrinterCommand(); 
2440 wxString 
wxGetPrintPreviewCommand() 
2442   return wxThePrintSetupData
->GetPrintPreviewCommand(); 
2445 wxString 
wxGetPrinterOptions() 
2447   return wxThePrintSetupData
->GetPrinterOptions(); 
2450 wxString 
wxGetPrinterFile() 
2452   return wxThePrintSetupData
->GetPrinterFile(); 
2455 int wxGetPrinterOrientation() 
2457   return wxThePrintSetupData
->GetPrinterOrientation(); 
2460 void wxGetPrinterScaling(double* x
, double* y
) 
2462   wxThePrintSetupData
->GetPrinterScaling(x
, y
); 
2465 void wxGetPrinterTranslation(wxCoord 
*x
, wxCoord 
*y
) 
2467   wxThePrintSetupData
->GetPrinterTranslation(x
, y
); 
2470 int wxGetPrinterMode() 
2472   return wxThePrintSetupData
->GetPrinterMode(); 
2475 wxString 
wxGetAFMPath() 
2477   return wxThePrintSetupData
->GetAFMPath(); 
2484 wxPrintSetupData::wxPrintSetupData() 
2486   m_printerOrient 
= wxPORTRAIT
; 
2487   m_printerScaleX 
= (double)1.0; 
2488   m_printerScaleY 
= (double)1.0; 
2489   m_printerTranslateX 
= 0; 
2490   m_printerTranslateY 
= 0; 
2491   m_printerMode 
= wxPRINT_MODE_FILE
; 
2492   m_printColour 
= TRUE
; 
2495 wxPrintSetupData::~wxPrintSetupData() 
2499 void wxPrintSetupData::operator=(wxPrintSetupData
& data
) 
2501   SetPrinterCommand(data
.GetPrinterCommand()); 
2502   SetPrintPreviewCommand(data
.GetPrintPreviewCommand()); 
2503   SetPrinterOptions(data
.GetPrinterOptions()); 
2505   data
.GetPrinterTranslation(&x
, &y
); 
2506   SetPrinterTranslation(x
, y
); 
2509   data
.GetPrinterScaling(&x1
, &y1
); 
2510   SetPrinterScaling(x1
, y1
); 
2512   SetPrinterOrientation(data
.GetPrinterOrientation()); 
2513   SetPrinterMode(data
.GetPrinterMode()); 
2514   SetAFMPath(data
.GetAFMPath()); 
2515   SetPaperName(data
.GetPaperName()); 
2516   SetColour(data
.GetColour()); 
2519 // Initialize from a wxPrintData object (wxPrintData should now be used instead of wxPrintSetupData). 
2520 void wxPrintSetupData::operator=(const wxPrintData
& data
) 
2522     SetPrinterCommand(data
.GetPrinterCommand()); 
2523     SetPrintPreviewCommand(data
.GetPreviewCommand()); 
2524     SetPrinterOptions(data
.GetPrinterOptions()); 
2525     SetPrinterTranslation((wxCoord
)data
.GetPrinterTranslateX(), 
2526                           (wxCoord
)data
.GetPrinterTranslateY()); 
2527     SetPrinterScaling(data
.GetPrinterScaleX(), data
.GetPrinterScaleY()); 
2528     SetPrinterOrientation(data
.GetOrientation()); 
2529     SetPrinterMode((int) data
.GetPrintMode()); 
2530     SetAFMPath(data
.GetFontMetricPath()); 
2531     SetPaperName(wxThePrintPaperDatabase
->ConvertIdToName(data
.GetPaperId())); 
2532     SetColour(data
.GetColour()); 
2533     SetPrinterFile(data
.GetFilename()); 
2536 void wxInitializePrintSetupData(bool init
) 
2540     wxThePrintSetupData 
= new wxPrintSetupData
; 
2542     wxThePrintSetupData
->SetPrintPreviewCommand(PS_VIEWER_PROG
); 
2543     wxThePrintSetupData
->SetPrinterOrientation(wxPORTRAIT
); 
2544     wxThePrintSetupData
->SetPrinterMode(wxPRINT_MODE_PREVIEW
); 
2545     wxThePrintSetupData
->SetPaperName(_("A4 sheet, 210 x 297 mm")); 
2547     // Could have a .ini file to read in some defaults 
2548     // - and/or use environment variables, e.g. WXWIN 
2550     wxThePrintSetupData
->SetPrinterCommand("print"); 
2551     wxThePrintSetupData
->SetPrinterOptions("/nonotify/queue=psqueue"); 
2552     wxThePrintSetupData
->SetAFMPath("sys$ps_font_metrics:"); 
2555     wxThePrintSetupData
->SetPrinterCommand("print"); 
2556     wxThePrintSetupData
->SetAFMPath("c:\\windows\\system\\"); 
2557     wxThePrintSetupData
->SetPrinterOptions(""); 
2559 #if !defined(__VMS__) && !defined(__WXMSW__) 
2560     wxThePrintSetupData
->SetPrinterCommand("lpr"); 
2561     wxThePrintSetupData
->SetPrinterOptions(""); 
2562     wxThePrintSetupData
->SetAFMPath(""); 
2567     if (wxThePrintSetupData
) 
2568       delete wxThePrintSetupData
; 
2569      wxThePrintSetupData 
= (wxPrintSetupData 
*) NULL
; 
2573 // A module to allow initialization/cleanup of PostScript-related 
2574 // things without calling these functions from app.cpp. 
2576 class WXDLLEXPORT wxPostScriptModule
: public wxModule
 
2578 DECLARE_DYNAMIC_CLASS(wxPostScriptModule
) 
2580     wxPostScriptModule() {} 
2585 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptModule
, wxModule
) 
2588  * Initialization/cleanup module 
2591 bool wxPostScriptModule::OnInit() 
2593     wxInitializePrintSetupData(); 
2598 void wxPostScriptModule::OnExit() 
2600     wxInitializePrintSetupData(FALSE
); 
2607   // wxUSE_PRINTING_ARCHITECTURE