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" 
  28 #if wxUSE_PRINTING_ARCHITECTURE 
  32 #include "wx/window.h" 
  33 #include "wx/dcmemory.h" 
  36 #include "wx/filedlg.h" 
  38 #include "wx/msgdlg.h" 
  41 #include "wx/generic/dcpsg.h" 
  42 #include "wx/generic/prntdlgg.h" 
  43 #include "wx/button.h" 
  44 #include "wx/stattext.h" 
  45 #include "wx/radiobox.h" 
  46 #include "wx/textctrl.h" 
  47 #include "wx/prntbase.h" 
  49 #include "wx/filefn.h" 
  73 //----------------------------------------------------------------------------- 
  74 // start and end of document/page 
  75 //----------------------------------------------------------------------------- 
  77 static const char *wxPostScriptHeaderEllipse 
= "\ 
  78 /ellipsedict 8 dict def\n\ 
  79 ellipsedict /mtrx matrix put\n\ 
  83     /startangle exch def\n\ 
  88     /savematrix mtrx currentmatrix def\n\ 
  91     0 0 1 startangle endangle arc\n\ 
  92     savematrix setmatrix\n\ 
  97 static const char *wxPostScriptHeaderEllipticArc
= "\ 
  98 /ellipticarcdict 8 dict def\n\ 
  99 ellipticarcdict /mtrx matrix put\n\ 
 101 { ellipticarcdict begin\n\ 
 103   /endangle exch def\n\ 
 104   /startangle exch def\n\ 
 109   /savematrix mtrx currentmatrix def\n\ 
 112   do_fill { 0 0 moveto } if\n\ 
 113   0 0 1 startangle endangle arc\n\ 
 114   savematrix setmatrix\n\ 
 115   do_fill { fill }{ stroke } ifelse\n\ 
 119 static const char *wxPostScriptHeaderSpline 
= "\ 
 120 /DrawSplineSection {\n\ 
 127     /xa x1 x2 x1 sub 0.666667 mul add def\n\ 
 128     /ya y1 y2 y1 sub 0.666667 mul add def\n\ 
 129     /xb x3 x2 x3 sub 0.666667 mul add def\n\ 
 130     /yb y3 y2 y3 sub 0.666667 mul add def\n\ 
 132     xa ya xb yb x3 y3 curveto\n\ 
 136 static const char *wxPostScriptHeaderColourImage 
= "\ 
 137 %% define 'colorimage' if it isn't defined\n\ 
 138 %%   ('colortogray' and 'mergeprocs' come from xwd2ps\n\ 
 140 /colorimage where   %% do we know about 'colorimage'?\n\ 
 141   { pop }           %% yes: pop off the 'dict' returned\n\ 
 142   {                 %% no:  define one\n\ 
 143     /colortogray {  %% define an RGB->I function\n\ 
 144       /rgbdata exch store    %% call input 'rgbdata'\n\ 
 145       rgbdata length 3 idiv\n\ 
 146       /npixls exch store\n\ 
 148       0 1 npixls 1 sub {\n\ 
 150         rgbdata rgbindx       get 20 mul    %% Red\n\ 
 151         rgbdata rgbindx 1 add get 32 mul    %% Green\n\ 
 152         rgbdata rgbindx 2 add get 12 mul    %% Blue\n\ 
 153         add add 64 idiv      %% I = .5G + .31R + .18B\n\ 
 155         /rgbindx rgbindx 3 add store\n\ 
 157       grays 0 npixls getinterval\n\ 
 160     %% Utility procedure for colorimage operator.\n\ 
 161     %% This procedure takes two procedures off the\n\ 
 162     %% stack and merges them into a single procedure.\n\ 
 164     /mergeprocs { %% def\n\ 
 183     /colorimage { %% def\n\ 
 184       pop pop     %% remove 'false 3' operands\n\ 
 185       {colortogray} mergeprocs\n\ 
 188   } ifelse          %% end of 'false' case\n\ 
 191 static char wxPostScriptHeaderReencodeISO1
[] = 
 193 "dup dup findfont dup length dict begin\n" 
 194 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" 
 195 "/Encoding ISOLatin1Encoding def\n" 
 196 "currentdict end definefont\n" 
 198 "/ISOLatin1Encoding [\n" 
 199 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 200 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 201 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 202 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 203 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" 
 204 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" 
 205 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" 
 206 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" 
 207 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" 
 208 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" 
 209 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" 
 210 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 211 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 212 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" 
 213 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; 
 215 static char wxPostScriptHeaderReencodeISO2
[] = 
 216 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" 
 217 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" 
 218 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" 
 219 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" 
 220 "/guillemotright/onequarter/onehalf/threequarters/questiondown\n" 
 221 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" 
 222 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" 
 223 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" 
 224 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" 
 225 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" 
 226 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" 
 227 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" 
 228 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" 
 229 "/yacute/thorn/ydieresis\n" 
 232 //------------------------------------------------------------------------------- 
 234 //------------------------------------------------------------------------------- 
 236 float wxPostScriptDC::ms_PSScaleFactor 
= 10.0; 
 238 void wxPostScriptDC::SetResolution(int ppi
) 
 240     ms_PSScaleFactor 
= (float)ppi 
/ 72.0; 
 243 int wxPostScriptDC::GetResolution() 
 245     return (int)(ms_PSScaleFactor 
* 72.0); 
 250 wxPostScriptDC::wxPostScriptDC () 
 252     m_pstream 
= (FILE*) NULL
; 
 262     m_underlinePosition 
= 0.0; 
 263     m_underlineThickness 
= 0.0; 
 265     m_signX 
=  1;  // default x-axis left to right 
 266     m_signY 
= -1;  // default y-axis bottom up -> top down 
 268     // Compatibility only 
 269     // HH: Doesn't seem to work for wxMSW... 
 271     m_printData 
= * wxThePrintSetupData
; 
 275 wxPostScriptDC::wxPostScriptDC (const wxString
& file
, bool interactive
, wxWindow 
*parent
) 
 277     m_pstream 
= (FILE*) NULL
; 
 287     m_underlinePosition 
= 0.0; 
 288     m_underlineThickness 
= 0.0; 
 290     m_signX 
=  1;  // default x-axis left to right 
 291     m_signY 
= -1;  // default y-axis bottom up -> top down 
 293     Create(file
, interactive
, parent
); 
 296 bool wxPostScriptDC::Create(const wxString
& file
, bool interactive
, wxWindow 
*parent
) 
 298     m_isInteractive 
= interactive
; 
 301     m_printData
.SetFilename(file
); 
 304     // Can only send to file in Windows 
 305     m_printData
.SetPrintMode(wxPRINT_MODE_FILE
); 
 310         if ((m_ok 
= PrinterDialog (parent
) ) == FALSE
) return FALSE
; 
 320 wxPostScriptDC::wxPostScriptDC (const wxPrintData
& printData
) 
 322     m_pstream 
= (FILE*) NULL
; 
 332     m_underlinePosition 
= 0.0; 
 333     m_underlineThickness 
= 0.0; 
 335     m_signX 
=  1;  // default x-axis left to right 
 336     m_signY 
= -1;  // default y-axis bottom up -> top down 
 338     m_printData 
= printData
; 
 343 wxPostScriptDC::~wxPostScriptDC () 
 348         m_pstream 
= (FILE*) NULL
; 
 352 bool wxPostScriptDC::Ok() const 
 357 // This dialog is deprecated now: use wxGenericPrintDialog or the printing framework 
 358 bool wxPostScriptDC::PrinterDialog(wxWindow 
*parent
) 
 360     wxPostScriptPrintDialog 
dialog( parent
, _("Printer Settings"), wxPoint(150, 150), wxSize(400, 400), 
 361                                     wxDEFAULT_DIALOG_STYLE 
| wxDIALOG_MODAL 
); 
 362     m_ok 
= (dialog
.ShowModal () == wxID_OK
); 
 364     if (!m_ok
) return FALSE
; 
 366     if ((m_printData
.GetFilename() == "") && 
 367         (m_printData
.GetPrintMode() == wxPRINT_MODE_PREVIEW  
|| 
 368          m_printData
.GetPrintMode() == wxPRINT_MODE_PRINTER
)) 
 372       m_printData
.SetFilename("preview"); 
 374       // For PS_PRINTER action this depends on a Unix-style print spooler 
 375       // since the wx_printer_file can be destroyed during a session 
 376       // @@@ TODO: a Windows-style answer for non-Unix 
 378       wxGetUserId (userId
, sizeof (userId
) / sizeof (char)); 
 380       wxStrcpy (tmp
, wxT("/tmp/preview_")); 
 381       wxStrcat (tmp
, userId
); 
 382       m_printData
.SetFilename(tmp
); 
 385       wxStrcpy(tmp2
, m_printData
.GetFilename()); 
 386       wxStrcat (tmp2
, wxT(".ps")); 
 387       m_printData
.SetFilename(tmp2
); 
 389     else if ((m_printData
.GetFilename() == wxT("")) && (m_printData
.GetPrintMode() == wxPRINT_MODE_FILE
)) 
 391       wxString file 
= wxSaveFileSelector (_("PostScript"), wxT("ps")); 
 392       if ( file
.IsEmpty() ) 
 398       m_printData
.SetFilename(file
); 
 405 void wxPostScriptDC::DoSetClippingRegion (wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 407     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 409     if (m_clipping
) DestroyClippingRegion(); 
 411     wxDC::DoSetClippingRegion(x
, y
, w
, h
); 
 420             "closepath clip newpath\n", 
 421             XLOG2DEV(x
),   YLOG2DEV(y
), 
 422             XLOG2DEV(x
+w
), YLOG2DEV(y
), 
 423             XLOG2DEV(x
+w
), YLOG2DEV(y
+h
), 
 424             XLOG2DEV(x
),   YLOG2DEV(y
+h
) ); 
 428 void wxPostScriptDC::DestroyClippingRegion() 
 430     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 435         fprintf( m_pstream
, "grestore\n" ); 
 438     wxDC::DestroyClippingRegion(); 
 441 void wxPostScriptDC::Clear() 
 443     wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); 
 446 void wxPostScriptDC::DoFloodFill (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
)) 
 448     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); 
 451 bool wxPostScriptDC::DoGetPixel (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxColour 
* WXUNUSED(col
)) const 
 453     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); 
 457 void wxPostScriptDC::DoCrossHair (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) 
 459     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); 
 462 void wxPostScriptDC::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 464     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 466     if  (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 475             XLOG2DEV(x1
), YLOG2DEV(y1
), 
 476             XLOG2DEV(x2
), YLOG2DEV (y2
) ); 
 478     CalcBoundingBox( x1
, y1 
); 
 479     CalcBoundingBox( x2
, y2 
); 
 482 #define RAD2DEG 57.29577951308 
 484 void wxPostScriptDC::DoDrawArc (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 486     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 488     wxCoord dx 
= x1 
- xc
; 
 489     wxCoord dy 
= y1 
- yc
; 
 490     wxCoord radius 
= (wxCoord
) sqrt( (double)(dx
*dx
+dy
*dy
) ); 
 491     double alpha1
, alpha2
; 
 493     if (x1 
== x2 
&& y1 
== y2
) 
 498     else if (radius 
== 0.0) 
 500         alpha1 
= alpha2 
= 0.0; 
 504         alpha1 
= (x1 
- xc 
== 0) ? 
 505             (y1 
- yc 
< 0) ? 90.0 : -90.0 : 
 506                 -atan2(double(y1
-yc
), double(x1
-xc
)) * RAD2DEG
; 
 507         alpha2 
= (x2 
- xc 
== 0) ? 
 508             (y2 
- yc 
< 0) ? 90.0 : -90.0 : 
 509                 -atan2(double(y2
-yc
), double(x2
-xc
)) * RAD2DEG
; 
 511     while (alpha1 
<= 0)   alpha1 
+= 360; 
 512     while (alpha2 
<= 0)   alpha2 
+= 360; // adjust angles to be between 
 513     while (alpha1 
> 360)  alpha1 
-= 360; // 0 and 360 degree 
 514     while (alpha2 
> 360)  alpha2 
-= 360; 
 516     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 522                 "%d %d %d %d %d %d ellipse\n" 
 526                 XLOG2DEV(xc
), YLOG2DEV(yc
), XLOG2DEVREL(radius
), YLOG2DEVREL(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 527                 XLOG2DEV(xc
), YLOG2DEV(yc
) ); 
 529         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 530         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 533     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 539                 "%d %d %d %d %d %d ellipse\n" 
 543                 XLOG2DEV(xc
), YLOG2DEV(yc
), XLOG2DEVREL(radius
), YLOG2DEVREL(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 544                 XLOG2DEV(xc
), YLOG2DEV(yc
) ); 
 546         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 547         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 551 void wxPostScriptDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 553     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 555     if (sa
>=360 || sa
<=-360) sa
=sa
-int(sa
/360)*360; 
 556     if (ea
>=360 || ea
<=-360) ea
=ea
-int(ea
/360)*360; 
 562         DrawEllipse(x
,y
,w
,h
); 
 566     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 572                 "%d %d %d %d %d %d true ellipticarc\n", 
 573                 XLOG2DEV(x
+w
/2), YLOG2DEV(y
+h
/2), XLOG2DEVREL(w
/2), YLOG2DEVREL(h
/2), (wxCoord
)sa
, (wxCoord
)ea 
); 
 575         CalcBoundingBox( x 
,y 
); 
 576         CalcBoundingBox( x
+w
, y
+h 
); 
 579     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 585                 "%d %d %d %d %d %d false ellipticarc\n", 
 586                 XLOG2DEV(x
+w
/2), YLOG2DEV(y
+h
/2), XLOG2DEVREL(w
/2), YLOG2DEVREL(h
/2), (wxCoord
)sa
, (wxCoord
)ea 
); 
 588         CalcBoundingBox( x 
,y 
); 
 589         CalcBoundingBox( x
+w
, y
+h 
); 
 593 void wxPostScriptDC::DoDrawPoint (wxCoord x
, wxCoord y
) 
 595     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 597     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 606             XLOG2DEV(x
),   YLOG2DEV(y
), 
 607             XLOG2DEV(x
+1), YLOG2DEV(y
) ); 
 609     CalcBoundingBox( x
, y 
); 
 612 void wxPostScriptDC::DoDrawPolygon (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
)) 
 614     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 618     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 622         fprintf( m_pstream
, "newpath\n" ); 
 624         wxCoord xx 
= XLOG2DEV(points
[0].x 
+ xoffset
); 
 625         wxCoord yy 
= YLOG2DEV(points
[0].y 
+ yoffset
); 
 627         fprintf( m_pstream
, "%d %d moveto\n", xx
, yy 
); 
 629         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 631         for (int i 
= 1; i 
< n
; i
++) 
 633             xx 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 634             yy 
= YLOG2DEV(points
[i
].y 
+ yoffset
); 
 636             fprintf( m_pstream
, "%d %d lineto\n", xx
, yy 
); 
 638             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 641         fprintf( m_pstream
, "fill\n" ); 
 644     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 648         fprintf( m_pstream
, "newpath\n" ); 
 650         wxCoord xx 
= XLOG2DEV(points
[0].x 
+ xoffset
); 
 651         wxCoord yy 
= YLOG2DEV(points
[0].y 
+ yoffset
); 
 653         fprintf( m_pstream
, "%d %d moveto\n", xx
, yy 
); 
 655         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 657         for (int i 
= 1; i 
< n
; i
++) 
 659             xx 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 660             yy 
= YLOG2DEV(points
[i
].y 
+ yoffset
); 
 662             fprintf( m_pstream
, "%d %d lineto\n", xx
, yy 
); 
 664             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 667         fprintf( m_pstream
, "fill\n" ); 
 671 void wxPostScriptDC::DoDrawLines (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 673     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 675     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 682     for ( i 
=0; i
<n 
; i
++ ) 
 684         CalcBoundingBox( XLOG2DEV(points
[i
].x
+xoffset
), YLOG2DEV(points
[i
].y
+yoffset
)); 
 690             XLOG2DEV(points
[0].x
+xoffset
), YLOG2DEV(points
[0].y
+yoffset
) ); 
 692     for (i 
= 1; i 
< n
; i
++) 
 696                 XLOG2DEV(points
[i
].x
+xoffset
), YLOG2DEV(points
[i
].y
+yoffset
) ); 
 699     fprintf( m_pstream
, "stroke\n" ); 
 702 void wxPostScriptDC::DoDrawRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 704     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 706     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 718                 XLOG2DEV(x
),         YLOG2DEV(y
), 
 719                 XLOG2DEV(x 
+ width
), YLOG2DEV(y
), 
 720                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ height
), 
 721                 XLOG2DEV(x
),         YLOG2DEV(y 
+ height
) ); 
 723         CalcBoundingBox( x
, y 
); 
 724         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 727     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 739                 XLOG2DEV(x
),         YLOG2DEV(y
), 
 740                 XLOG2DEV(x 
+ width
), YLOG2DEV(y
), 
 741                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ height
), 
 742                 XLOG2DEV(x
),         YLOG2DEV(y 
+ height
) ); 
 744         CalcBoundingBox( x
, y 
); 
 745         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 749 void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 751     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 755         // Now, a negative radius is interpreted to mean 
 756         // 'the proportion of the smallest X or Y dimension' 
 757         double smallest 
= 0.0; 
 762         radius 
=  (-radius 
* smallest
); 
 765     wxCoord rad 
= (wxCoord
) radius
; 
 767     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 771         /* Draw rectangle anticlockwise */ 
 774                 "%d %d %d 90 180 arc\n" 
 776                 "%d %d %d 180 270 arc\n" 
 778                 "%d %d %d 270 0 arc\n" 
 780                 "%d %d %d 0 90 arc\n" 
 784                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 785                 XLOG2DEV(x
), YLOG2DEV(y 
+ rad
), 
 786                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 787                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height
), 
 788                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 789                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ rad
), 
 790                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 791                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y
) ); 
 793         CalcBoundingBox( x
, y 
); 
 794         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 797     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 801         /* Draw rectangle anticlockwise */ 
 804                 "%d %d %d 90 180 arc\n" 
 806                 "%d %d %d 180 270 arc\n" 
 808                 "%d %d %d 270 0 arc\n" 
 810                 "%d %d %d 0 90 arc\n" 
 814                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 815                 XLOG2DEV(x
), YLOG2DEV(y 
+ rad
), 
 816                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 817                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height
), 
 818                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ height 
- rad
), XLOG2DEVREL(rad
), 
 819                 XLOG2DEV(x 
+ width
), YLOG2DEV(y 
+ rad
), 
 820                 XLOG2DEV(x 
+ width 
- rad
), YLOG2DEV(y 
+ rad
), XLOG2DEVREL(rad
), 
 821                 XLOG2DEV(x 
+ rad
), YLOG2DEV(y
) ); 
 823         CalcBoundingBox( x
, y 
); 
 824         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 828 void wxPostScriptDC::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 830     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 832     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 838                 "%d %d %d %d 0 360 ellipse\n" 
 840                 XLOG2DEV(x 
+ width 
/ 2), YLOG2DEV(y 
+ height 
/ 2), 
 841                 XLOG2DEV(width 
/ 2), YLOG2DEVREL(height 
/ 2) ); 
 843         CalcBoundingBox( x 
- width
, y 
- height 
); 
 844         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 847     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 853                 "%d %d %d %d 0 360 ellipse\n" 
 855                 XLOG2DEV(x 
+ width 
/ 2), YLOG2DEV(y 
+ height 
/ 2), 
 856                 XLOG2DEV(width 
/ 2), YLOG2DEVREL(height 
/ 2) ); 
 858         CalcBoundingBox( x 
- width
, y 
- height 
); 
 859         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 863 void wxPostScriptDC::DoDrawIcon( const wxIcon
& icon
, wxCoord x
, wxCoord y 
) 
 865     DrawBitmap( icon
, x
, y
, TRUE 
); 
 868 /* this has to be char, not wxChar */ 
 869 static char hexArray
[] = "0123456789ABCDEF"; 
 870 static void LocalDecToHex( int dec
, char *buf 
) 
 872     int firstDigit 
= (int)(dec
/16.0); 
 873     int secondDigit 
= (int)(dec 
- (firstDigit
*16.0)); 
 874     buf
[0] = hexArray
[firstDigit
]; 
 875     buf
[1] = hexArray
[secondDigit
]; 
 879 void wxPostScriptDC::DoDrawBitmap( const wxBitmap
& bitmap
, wxCoord x
, wxCoord y
, bool WXUNUSED(useMask
) ) 
 881     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 883     if (!bitmap
.Ok()) return; 
 885     wxImage 
image( bitmap 
); 
 887     if (!image
.Ok()) return; 
 889     wxCoord w 
= image
.GetWidth(); 
 890     wxCoord h 
= image
.GetHeight(); 
 892     wxCoord ww 
= XLOG2DEVREL(image
.GetWidth()); 
 893     wxCoord hh 
= YLOG2DEVREL(image
.GetHeight()); 
 895     wxCoord xx 
= XLOG2DEV(x
); 
 896     wxCoord yy 
= YLOG2DEV(y 
+ bitmap
.GetHeight()); 
 899             "/origstate save def\n" 
 901             "/pix %d string def\n" 
 902             "/grays %d string def\n" 
 909             "{currentfile pix readhexstring pop}\n" 
 910             "false 3 colorimage\n", 
 911             w
, w
, xx
, yy
, ww
, hh
, w
, h
, w
, -h
, h 
); 
 914     for (int j 
= 0; j 
< h
; j
++) 
 916         for (int i 
= 0; i 
< w
; i
++) 
 919             LocalDecToHex( image
.GetRed(i
,j
), buffer 
); 
 920             fprintf( m_pstream
, buffer 
); 
 921             LocalDecToHex( image
.GetGreen(i
,j
), buffer 
); 
 922             fprintf( m_pstream
, buffer 
); 
 923             LocalDecToHex( image
.GetBlue(i
,j
), buffer 
); 
 924             fprintf( m_pstream
, buffer 
); 
 926         fprintf( m_pstream
, "\n" ); 
 929     fprintf( m_pstream
, "end\n" ); 
 930     fprintf( m_pstream
, "origstate restore\n" ); 
 933 void wxPostScriptDC::SetFont( const wxFont
& font 
) 
 935     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
 937     if (!font
.Ok())  return; 
 942     const char *style 
= ""; 
 943     int Style 
= m_font
.GetStyle(); 
 944     int Weight 
= m_font
.GetWeight(); 
 946     switch (m_font
.GetFamily()) 
 956 //          name = "/Times-Roman"; 
 957             name 
= "/Times"; // Altered by EDZ 
 960             name 
= "/Zapf-Chancery-MediumItalic"; 
 965         case wxDEFAULT
: // Sans Serif Font 
 966             name 
= "/LucidaSans"; 
 969     if (Style 
== wxNORMAL 
&& (Weight 
== wxNORMAL 
|| Weight 
== wxLIGHT
)) 
 971         if (m_font
.GetFamily () == wxROMAN
) 
 976     else if (Style 
== wxNORMAL 
&& Weight 
== wxBOLD
) 
 980     else if (Style 
== wxITALIC 
&& (Weight 
== wxNORMAL 
|| Weight 
== wxLIGHT
)) 
 982         if (m_font
.GetFamily () == wxROMAN
) 
 987     else if (Style 
== wxITALIC 
&& Weight 
== wxBOLD
) 
 989         if (m_font
.GetFamily () == wxROMAN
) 
 990             style 
= "-BoldItalic"; 
 992             style 
= "-BoldOblique"; 
 994     else if (Style 
== wxSLANT 
&& (Weight 
== wxNORMAL 
|| Weight 
== wxLIGHT
)) 
 996         if (m_font
.GetFamily () == wxROMAN
) 
1001     else if (Style 
== wxSLANT 
&& Weight 
== wxBOLD
) 
1003         if (m_font
.GetFamily () == wxROMAN
) 
1004             style 
= "-BoldItalic"; 
1006             style 
= "-BoldOblique"; 
1014     strcpy( buffer
, name 
); 
1015     strcat( buffer
, style 
); 
1017     fprintf( m_pstream
, buffer 
); 
1018     fprintf( m_pstream
, " reencodeISO def\n" ); 
1019     fprintf( m_pstream
, buffer 
); 
1020     fprintf( m_pstream
, " findfont\n" ); 
1022     sprintf( buffer
, "%f scalefont setfont\n", YLOG2DEVREL(m_font
.GetPointSize() * 1000) / 1000.0F
); 
1023                 // this is a hack - we must scale font size (in pts) according to m_scaleY but 
1024                 // YLOG2DEVREL works with wxCoord type (int or longint). Se we first convert font size 
1025                 // to 1/1000th of pt and then back. 
1026     for (int i 
= 0; i 
< 100; i
++) 
1027         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1028     fprintf( m_pstream
, buffer 
); 
1031 void wxPostScriptDC::SetPen( const wxPen
& pen 
) 
1033     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1035     if (!pen
.Ok()) return; 
1037     int oldStyle 
= m_pen
.GetStyle(); 
1044         sprintf( buffer
, "%f setlinewidth\n", XLOG2DEVREL(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1046         sprintf( buffer
, "%f setlinewidth\n", XLOG2DEVREL(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1048         for (int i 
= 0; i 
< 100; i
++) 
1049             if (buffer
[i
] == ',') buffer
[i
] = '.';  
1050         fprintf( m_pstream
, buffer 
); 
1054      Line style - WRONG: 2nd arg is OFFSET 
1056      Here, I'm afraid you do not conceive meaning of parameters of 'setdash' 
1057      operator correctly. You should look-up this in the Red Book: the 2nd parame- 
1058      ter is not number of values in the array of the first one, but an offset 
1059      into this description of the pattern. I mean a real *offset* not index 
1060      into array. I.e. If the command is [3 4] 1 setdash   is used, then there 
1061      will be first black line *2* units wxCoord, then space 4 units, then the 
1062      pattern of *3* units black, 4 units space will be repeated. 
1065     static const char *dotted 
= "[2 5] 2"; 
1066     static const char *short_dashed 
= "[4 4] 2"; 
1067     static const char *wxCoord_dashed 
= "[4 8] 2"; 
1068     static const char *dotted_dashed 
= "[6 6 2 6] 4"; 
1070     const char *psdash 
= (char *) NULL
; 
1071     switch (m_pen
.GetStyle()) 
1073         case wxDOT
:           psdash 
= dotted
;         break; 
1074         case wxSHORT_DASH
:    psdash 
= short_dashed
;   break; 
1075         case wxLONG_DASH
:     psdash 
= wxCoord_dashed
;    break; 
1076         case wxDOT_DASH
:      psdash 
= dotted_dashed
;  break; 
1079         default:              psdash 
= "[] 0";         break; 
1082     if (oldStyle 
!= m_pen
.GetStyle()) 
1084         fprintf( m_pstream
, psdash 
); 
1085         fprintf( m_pstream
," setdash\n" ); 
1089     unsigned char red 
= m_pen
.GetColour().Red(); 
1090     unsigned char blue 
= m_pen
.GetColour().Blue(); 
1091     unsigned char green 
= m_pen
.GetColour().Green(); 
1095         // Anything not white is black 
1096         if (! (red 
== (unsigned char) 255 && 
1097                blue 
== (unsigned char) 255 && 
1098                green 
== (unsigned char) 255) ) 
1100             red 
= (unsigned char) 0; 
1101             green 
= (unsigned char) 0; 
1102             blue 
= (unsigned char) 0; 
1107     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1109         double redPS 
= (double)(red
) / 255.0; 
1110         double bluePS 
= (double)(blue
) / 255.0; 
1111         double greenPS 
= (double)(green
) / 255.0; 
1115                 "%.8f %.8f %.8f setrgbcolor\n", 
1116                 redPS
, greenPS
, bluePS 
); 
1117         for (int i 
= 0; i 
< 100; i
++) 
1118             if (buffer
[i
] == ',') buffer
[i
] = '.';  
1119         fprintf( m_pstream
, buffer 
); 
1122         m_currentBlue 
= blue
; 
1123         m_currentGreen 
= green
; 
1127 void wxPostScriptDC::SetBrush( const wxBrush
& brush 
) 
1129     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1131     if (!brush
.Ok()) return; 
1136     unsigned char red 
= m_brush
.GetColour().Red(); 
1137     unsigned char blue 
= m_brush
.GetColour().Blue(); 
1138     unsigned char green 
= m_brush
.GetColour().Green(); 
1142         // Anything not white is black 
1143         if (! (red 
== (unsigned char) 255 && 
1144                blue 
== (unsigned char) 255 && 
1145                green 
== (unsigned char) 255) ) 
1147             red 
= (unsigned char) 0; 
1148             green 
= (unsigned char) 0; 
1149             blue 
= (unsigned char) 0; 
1154     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1156         double redPS 
= (double)(red
) / 255.0; 
1157         double bluePS 
= (double)(blue
) / 255.0; 
1158         double greenPS 
= (double)(green
) / 255.0; 
1162                 "%.8f %.8f %.8f setrgbcolor\n", 
1163                 redPS
, greenPS
, bluePS 
); 
1164         for (int i 
= 0; i 
< 100; i
++) 
1165             if (buffer
[i
] == ',') buffer
[i
] = '.';  
1166         fprintf( m_pstream
, buffer 
); 
1169         m_currentBlue 
= blue
; 
1170         m_currentGreen 
= green
; 
1174 void wxPostScriptDC::DoDrawText( const wxString
& text
, wxCoord x
, wxCoord y 
) 
1176     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1178     wxCoord text_w
, text_h
, text_descent
; 
1180     GetTextExtent(text
, &text_w
, &text_h
, &text_descent
); 
1184     if (m_textForegroundColour
.Ok()) 
1186         unsigned char red 
= m_textForegroundColour
.Red(); 
1187         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1188         unsigned char green 
= m_textForegroundColour
.Green(); 
1192             // Anything not white is black 
1193             if (! (red 
== (unsigned char) 255 && 
1194                         blue 
== (unsigned char) 255 && 
1195                         green 
== (unsigned char) 255)) 
1197                 red 
= (unsigned char) 0; 
1198                 green 
= (unsigned char) 0; 
1199                 blue 
= (unsigned char) 0; 
1203         // maybe setgray here ? 
1204         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1206             double redPS 
= (double)(red
) / 255.0; 
1207             double bluePS 
= (double)(blue
) / 255.0; 
1208             double greenPS 
= (double)(green
) / 255.0; 
1212                 "%.8f %.8f %.8f setrgbcolor\n", 
1213                 redPS
, greenPS
, bluePS 
); 
1214             for (int i 
= 0; i 
< 100; i
++) 
1215                 if (buffer
[i
] == ',') buffer
[i
] = '.';  
1216             fprintf( m_pstream
, buffer 
); 
1219             m_currentBlue 
= blue
; 
1220             m_currentGreen 
= green
; 
1224     int size 
= m_font
.GetPointSize(); 
1226 //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline 
1227 //    commented by V. Slavik and replaced by accurate version 
1228 //        - note that there is still rounding error in text_descent! 
1229     wxCoord by 
= y 
+ size 
- text_descent
; // baseline 
1230     fprintf( m_pstream
, "%d %d moveto\n", XLOG2DEV(x
), YLOG2DEV(by
) ); 
1232     /* I don't know how to write char to a stream, so I use a mini string */ 
1236     fprintf( m_pstream
, "(" ); 
1237     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1238     int len 
= strlen(textbuf
); 
1240     for (i 
= 0; i 
< len
; i
++) 
1242         int c 
= (unsigned char) textbuf
[i
]; 
1243         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1245             /* Cope with special characters */ 
1246             fprintf( m_pstream
, "\\" ); 
1247             tmpbuf
[0] = (char) c
; 
1248             fprintf( m_pstream
, tmpbuf 
); 
1250         else if ( c 
>= 128 ) 
1252             /* Cope with character codes > 127 */ 
1253             fprintf(m_pstream
, "\\%o", c
); 
1257             tmpbuf
[0] = (char) c
; 
1258             fprintf( m_pstream
, tmpbuf 
); 
1262     fprintf( m_pstream
, ") show\n" ); 
1264     if (m_font
.GetUnderlined()) 
1266         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1276                 XLOG2DEV(x
), YLOG2DEV(uy
), 
1277                 m_underlineThickness
, 
1278                 XLOG2DEV(x 
+ text_w
), YLOG2DEV(uy
) ); 
1279         for (i 
= 0; i 
< 100; i
++) 
1280             if (buffer
[i
] == ',') buffer
[i
] = '.';  
1281         fprintf( m_pstream
, buffer 
); 
1284     CalcBoundingBox( x
, y 
); 
1285     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1288 void wxPostScriptDC::DoDrawRotatedText( const wxString
& text
, wxCoord x
, wxCoord y
, double angle 
) 
1292         DoDrawText(text
, x
, y
); 
1296     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1300     if (m_textForegroundColour
.Ok()) 
1302         unsigned char red 
= m_textForegroundColour
.Red(); 
1303         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1304         unsigned char green 
= m_textForegroundColour
.Green(); 
1308             // Anything not white is black 
1309             if (! (red 
== (unsigned char) 255 && 
1310                    blue 
== (unsigned char) 255 && 
1311                    green 
== (unsigned char) 255)) 
1313                 red 
= (unsigned char) 0; 
1314                 green 
= (unsigned char) 0; 
1315                 blue 
= (unsigned char) 0; 
1319         // maybe setgray here ? 
1320         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1322             double redPS 
= (double)(red
) / 255.0; 
1323             double bluePS 
= (double)(blue
) / 255.0; 
1324             double greenPS 
= (double)(green
) / 255.0; 
1328                 "%.8f %.8f %.8f setrgbcolor\n", 
1329                 redPS
, greenPS
, bluePS 
); 
1330             for (int i 
= 0; i 
< 100; i
++) 
1331                 if (buffer
[i
] == ',') buffer
[i
] = '.';  
1332             fprintf( m_pstream
, buffer 
); 
1335             m_currentBlue 
= blue
; 
1336             m_currentGreen 
= green
; 
1340     int size 
= m_font
.GetPointSize(); 
1342     long by 
= y 
+ (long)floor( double(size
) * 2.0 / 3.0 ); // approximate baseline 
1344     // FIXME only correct for 90 degrees 
1345     fprintf(m_pstream
, "%d %d moveto\n", 
1346             XLOG2DEV((wxCoord
)(x 
+ size
)), YLOG2DEV(by
) ); 
1349     sprintf(buffer
, "%.8f rotate\n", angle
); 
1351     for (i 
= 0; i 
< 100; i
++) 
1352         if (buffer
[i
] == ',') buffer
[i
] = '.';  
1353     fprintf(m_pstream
, buffer
); 
1355     /* I don't know how to write char to a stream, so I use a mini string */ 
1359     fprintf( m_pstream
, "(" ); 
1360     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1361     int len 
= strlen(textbuf
); 
1362     for (i 
= 0; i 
< len
; i
++) 
1364         int c 
= (unsigned char) textbuf
[i
]; 
1365         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1367             /* Cope with special characters */ 
1368             fprintf( m_pstream
, "\\" ); 
1369             tmpbuf
[0] = (char) c
; 
1370             fprintf( m_pstream
, tmpbuf 
); 
1372         else if ( c 
>= 128 ) 
1374             /* Cope with character codes > 127 */ 
1375             fprintf(m_pstream
, "\\%o", c
); 
1379             tmpbuf
[0] = (char) c
; 
1380             fprintf( m_pstream
, tmpbuf 
); 
1384     fprintf( m_pstream
, ") show\n" ); 
1386     sprintf( buffer
, "%.8f rotate\n", -angle 
); 
1387     for (i 
= 0; i 
< 100; i
++) 
1388         if (buffer
[i
] == ',') buffer
[i
] = '.';  
1389     fprintf( m_pstream
, buffer 
); 
1391     if (m_font
.GetUnderlined()) 
1393         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1396         GetTextExtent(text
, &w
, &h
); 
1405                  XLOG2DEV(x
), YLOG2DEV(uy
), 
1406                  m_underlineThickness
, 
1407                  XLOG2DEV(x 
+ w
), YLOG2DEV(uy
) ); 
1408         for (i 
= 0; i 
< 100; i
++) 
1409             if (buffer
[i
] == ',') buffer
[i
] = '.';  
1410         fprintf( m_pstream
, buffer 
); 
1413     CalcBoundingBox( x
, y 
); 
1414     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1417 void wxPostScriptDC::SetBackground (const wxBrush
& brush
) 
1419     m_backgroundBrush 
= brush
; 
1422 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function
)) 
1424     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); 
1427 void wxPostScriptDC::DoDrawSpline( wxList 
*points 
) 
1429     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1433     double a
, b
, c
, d
, x1
, y1
, x2
, y2
, x3
, y3
; 
1436     wxNode 
*node 
= points
->First(); 
1437     p 
= (wxPoint 
*)node
->Data(); 
1441     node 
= node
->Next(); 
1442     p 
= (wxPoint 
*)node
->Data(); 
1445     x3 
= a 
= (double)(x1 
+ c
) / 2; 
1446     y3 
= b 
= (double)(y1 
+ d
) / 2; 
1452             XLOG2DEV((wxCoord
)x1
), YLOG2DEV((wxCoord
)y1
), 
1453             XLOG2DEV((wxCoord
)x3
), YLOG2DEV((wxCoord
)y3
) ); 
1455     CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1456     CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1458     while ((node 
= node
->Next()) != NULL
) 
1460         q 
= (wxPoint 
*)node
->Data(); 
1468         x3 
= (double)(x2 
+ c
) / 2; 
1469         y3 
= (double)(y2 
+ d
) / 2; 
1472                 "%d %d %d %d %d %d DrawSplineSection\n", 
1473                 XLOG2DEV((wxCoord
)x1
), YLOG2DEV((wxCoord
)y1
), 
1474                 XLOG2DEV((wxCoord
)x2
), YLOG2DEV((wxCoord
)y2
), 
1475                 XLOG2DEV((wxCoord
)x3
), YLOG2DEV((wxCoord
)y3
) ); 
1477         CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1478         CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1482        At this point, (x2,y2) and (c,d) are the position of the 
1483        next-to-last and last point respectively, in the point list 
1489             XLOG2DEV((wxCoord
)c
), YLOG2DEV((wxCoord
)d
) ); 
1492 wxCoord 
wxPostScriptDC::GetCharWidth() const 
1494     // Chris Breeze: reasonable approximation using wxMODERN/Courier 
1495     return (wxCoord
) (GetCharHeight() * 72.0 / 120.0); 
1499 void wxPostScriptDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
1501     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1503     m_signX 
= (xLeftRight 
? 1 : -1); 
1504     m_signY 
= (yBottomUp  
? 1 : -1); 
1506     // FIXME there is no such function in MSW nor in OS2/PM 
1507 #if !defined(__WXMSW__) && !defined(__WXPM__) 
1508     ComputeScaleAndOrigin(); 
1512 void wxPostScriptDC::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
1514     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1520     wxDC::SetDeviceOrigin( x
, h
-y 
); 
1523 void wxPostScriptDC::DoGetSize(int* width
, int* height
) const 
1525     wxPaperSize id 
= m_printData
.GetPaperId(); 
1527     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1529     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1535         w 
= paper
->GetSizeDeviceUnits().x
; 
1536         h 
= paper
->GetSizeDeviceUnits().y
; 
1539     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1546     if (width
) *width 
= (int)(w 
* ms_PSScaleFactor
); 
1547     if (height
) *height 
= (int)(h 
* ms_PSScaleFactor
); 
1550 void wxPostScriptDC::DoGetSizeMM(int *width
, int *height
) const 
1552     wxPaperSize id 
= m_printData
.GetPaperId(); 
1554     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1556     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1562         w 
= paper
->GetWidth() / 10; 
1563         h 
= paper
->GetHeight() / 10; 
1566     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1573     if (width
) *width 
= w
; 
1574     if (height
) *height 
= h
; 
1577 // Resolution in pixels per logical inch 
1578 wxSize 
wxPostScriptDC::GetPPI(void) const 
1580     return wxSize((int)(72 * ms_PSScaleFactor
),  
1581                   (int)(72 * ms_PSScaleFactor
)); 
1585 bool wxPostScriptDC::StartDoc( const wxString
& message 
) 
1587     wxCHECK_MSG( m_ok
, FALSE
, wxT("invalid postscript dc") ); 
1589     if (m_printData
.GetFilename() == "") 
1591         wxString filename 
= wxGetTempFileName("ps"); 
1592         m_printData
.SetFilename(filename
); 
1595     m_pstream 
= fopen( m_printData
.GetFilename().fn_str(), "w+" ); 
1599         wxLogError( _("Cannot open file for PostScript printing!")); 
1606     fprintf( m_pstream
, "%%%%BeginProlog\n" ); 
1607     fprintf( m_pstream
, wxPostScriptHeaderEllipse 
); 
1608     fprintf( m_pstream
, wxPostScriptHeaderEllipticArc 
); 
1609     fprintf( m_pstream
, wxPostScriptHeaderColourImage 
); 
1610     fprintf( m_pstream
, wxPostScriptHeaderReencodeISO1 
); 
1611     fprintf( m_pstream
, wxPostScriptHeaderReencodeISO2 
); 
1612     if (wxPostScriptHeaderSpline
) 
1613         fprintf( m_pstream
, wxPostScriptHeaderSpline 
); 
1614     fprintf( m_pstream
, "%%%%EndProlog\n" ); 
1616     SetBrush( *wxBLACK_BRUSH 
); 
1617     SetPen( *wxBLACK_PEN 
); 
1618     SetBackground( *wxWHITE_BRUSH 
); 
1619     SetTextForeground( *wxBLACK 
); 
1621     // set origin according to paper size 
1622     SetDeviceOrigin( 0,0 ); 
1630 void wxPostScriptDC::EndDoc () 
1632     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1637         fprintf( m_pstream
, "grestore\n" ); 
1640     fclose( m_pstream 
); 
1641     m_pstream 
= (FILE *) NULL
; 
1643     wxChar 
*header_file 
= wxGetTempFileName("ps"); 
1645     m_pstream 
= fopen( wxConvFile
.cWX2MB(header_file
) , "w+" ); 
1647     fprintf( m_pstream
, "%%!PS-Adobe-2.0\n" );                     // PostScript magic strings 
1648     fprintf( m_pstream
, "%%%%Title: %s\n", (const char *)m_title
.mb_str() ); 
1649     fprintf( m_pstream
, "%%%%Creator: %s\n", (const char*)wxConvCurrent
->cWX2MB(wxTheApp
->argv
[0]) ); 
1650     fprintf( m_pstream
, "%%%%CreationDate: %s\n", (const char *)wxNow().mb_str() ); 
1653     if ( wxGetEmailAddress(userID
, sizeof(userID
)) ) 
1655         fprintf( m_pstream
, "%%%%For: %s ", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userID
) ); 
1656         wxChar userName
[245]; 
1657         if (wxGetUserName(userName
, sizeof(userName
))) 
1658             fprintf( m_pstream
, " (%s)", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userName
) ); 
1659         fprintf( m_pstream
, "\n" ); 
1661     else if ( wxGetUserName(userID
, sizeof(userID
)) ) 
1663         fprintf( m_pstream
, "%%%%For: %s\n", wxMBSTRINGCAST wxConvCurrent
->cWX2MB(userID
) );; 
1666     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com> 
1668     wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
1669     double wx_printer_scale_x
, wx_printer_scale_y
; 
1671     wx_printer_translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1672     wx_printer_translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1674     wx_printer_scale_x 
= m_printData
.GetPrinterScaleX(); 
1675     wx_printer_scale_y 
= m_printData
.GetPrinterScaleY(); 
1677     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1678         fprintf( m_pstream
, "%%%%Orientation: Landscape\n" ); 
1680         fprintf( m_pstream
, "%%%%Orientation: Portrait\n" ); 
1682     // Compute the bounding box.  Note that it is in the default user 
1683     // coordinate system, thus we have to convert the values. 
1684     wxCoord llx 
= (wxCoord
) ((XLOG2DEV(m_minX
)+wx_printer_translate_x
)*wx_printer_scale_x
); 
1685     wxCoord lly 
= (wxCoord
) ((YLOG2DEV(m_minY
)+wx_printer_translate_y
)*wx_printer_scale_y
); 
1686     wxCoord urx 
= (wxCoord
) ((XLOG2DEV(m_maxX
)+wx_printer_translate_x
)*wx_printer_scale_x
); 
1687     wxCoord ury 
= (wxCoord
) ((YLOG2DEV(m_maxY
)+wx_printer_translate_y
)*wx_printer_scale_y
); 
1689     // If we're landscape, our sense of "x" and "y" is reversed. 
1690     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1693         tmp 
= llx
; llx 
= lly
; lly 
= tmp
; 
1694         tmp 
= urx
; urx 
= ury
; ury 
= tmp
; 
1696         // We need either the two lines that follow, or we need to subtract 
1697         // min_x from real_translate_y, which is commented out below. 
1698         llx 
= llx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1699         urx 
= urx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1702     // The Adobe specifications call for integers; we round as to make 
1703     // the bounding larger. 
1705             "%%%%BoundingBox: %d %d %d %d\n", 
1706             (wxCoord
)floor((double)llx
), (wxCoord
)floor((double)lly
), 
1707             (wxCoord
)ceil((double)urx
), (wxCoord
)ceil((double)ury
) ); 
1708     fprintf( m_pstream
, "%%%%Pages: %d\n", (wxPageNumber 
- 1) ); 
1709     fprintf( m_pstream
, "%%%%EndComments\n\n" ); 
1711     // To check the correctness of the bounding box, postscript commands 
1712     // to draw a box corresponding to the bounding box are generated below. 
1713     // But since we typically don't want to print such a box, the postscript 
1714     // commands are generated within comments.  These lines appear before any 
1715     // adjustment of scale, rotation, or translation, and hence are in the 
1716     // default user coordinates. 
1717     fprintf( m_pstream
, "%% newpath\n" ); 
1718     fprintf( m_pstream
, "%% %d %d moveto\n", llx
, lly 
); 
1719     fprintf( m_pstream
, "%% %d %d lineto\n", urx
, lly 
); 
1720     fprintf( m_pstream
, "%% %d %d lineto\n", urx
, ury 
); 
1721     fprintf( m_pstream
, "%% %d %d lineto closepath stroke\n", llx
, ury 
); 
1723     fclose( m_pstream 
); 
1724     m_pstream 
= (FILE*) NULL
; 
1726     wxChar 
*tmp_file 
= wxGetTempFileName("ps"); 
1728     // Paste header Before wx_printer_file 
1729     wxConcatFiles (header_file
, m_printData
.GetFilename(), tmp_file 
); 
1730     wxRemoveFile( header_file 
); 
1731     wxRemoveFile( m_printData
.GetFilename() ); 
1732     wxRenameFile( tmp_file
, m_printData
.GetFilename() ); 
1734 #if defined(__X__) || defined(__WXGTK__) 
1737         wxString 
previewCommand(m_printData
.GetPreviewCommand()); 
1738         wxString 
printerCommand(m_printData
.GetPrinterCommand()); 
1739         wxString 
printerOptions(m_printData
.GetPrinterOptions()); 
1740         wxString 
filename(m_printData
.GetFilename()); 
1742         switch (m_printData
.GetPrintMode()) 
1744             case wxPRINT_MODE_PREVIEW
: 
1747                 argv
[0] = WXSTRINGCAST previewCommand
; 
1748                 argv
[1] = WXSTRINGCAST filename
; 
1749                 argv
[2] = (wxChar
*) NULL
; 
1750                 wxExecute( argv
, TRUE 
); 
1751                 wxRemoveFile( m_printData
.GetFilename() ); 
1754             case wxPRINT_MODE_PRINTER
: 
1758                 argv
[argc
++] = WXSTRINGCAST printerCommand
; 
1760                 // !SM! If we simply assign to argv[1] here, if printer options 
1761                 // are blank, we get an annoying and confusing message from lpr. 
1762                 wxChar 
*opts 
= WXSTRINGCAST printerOptions
; 
1764                     argv
[argc
++] = opts
; 
1766                 argv
[argc
++] = WXSTRINGCAST filename
; 
1767                 argv
[argc
++] = (wxChar 
*) NULL
; 
1768                 wxExecute( argv
, TRUE 
); 
1769                 wxRemoveFile( filename 
); 
1772             case wxPRINT_MODE_FILE
: 
1773             case wxPRINT_MODE_NONE
: 
1780 void wxPostScriptDC::StartPage() 
1782     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1784     fprintf( m_pstream
, "%%%%Page: %d\n", wxPageNumber
++ ); 
1786     //  What is this one supposed to do? RR. 
1787 //  *m_pstream << "matrix currentmatrix\n"; 
1789     // Added by Chris Breeze 
1791     // Each page starts with an "initgraphics" which resets the 
1792     // transformation and so we need to reset the origin 
1793     // (and rotate the page for landscape printing) 
1796     wxCoord translate_x
, translate_y
; 
1797     double scale_x
, scale_y
; 
1799     translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1800     translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1802     scale_x 
= m_printData
.GetPrinterScaleX(); 
1803     scale_y 
= m_printData
.GetPrinterScaleY(); 
1805     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1808         GetSize( (int*) NULL
, &h 
); 
1810         fprintf( m_pstream
, "90 rotate\n" ); 
1812         // I copied this one from a PostScript tutorial, but to no avail. RR. 
1813         // fprintf( m_pstream, "90 rotate llx neg ury nef translate\n" ); 
1817     sprintf( buffer
, "%.8f %.8f scale\n", scale_x 
/ ms_PSScaleFactor
,  
1818                                           scale_y 
/ ms_PSScaleFactor
); 
1819     for (int i 
= 0; i 
< 100; i
++) 
1820         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1821     fprintf( m_pstream
, buffer 
); 
1823     fprintf( m_pstream
, "%d %d translate\n", translate_x
, translate_y 
); 
1826 void wxPostScriptDC::EndPage () 
1828     wxCHECK_RET( m_ok 
&& m_pstream
, wxT("invalid postscript dc") ); 
1830     fprintf( m_pstream
, "showpage\n" ); 
1833 bool wxPostScriptDC::DoBlit( wxCoord xdest
, wxCoord ydest
, 
1834                            wxCoord fwidth
, wxCoord fheight
, 
1836                            wxCoord xsrc
, wxCoord ysrc
, 
1837                            int rop
, bool WXUNUSED(useMask
) ) 
1839     wxCHECK_MSG( m_ok 
&& m_pstream
, FALSE
, wxT("invalid postscript dc") ); 
1841     wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") ); 
1843     /* blit into a bitmap */ 
1844     wxBitmap 
bitmap( (int)fwidth
, (int)fheight 
); 
1846     memDC
.SelectObject(bitmap
); 
1847     memDC
.Blit(0, 0, fwidth
, fheight
, source
, xsrc
, ysrc
, rop
); /* TODO: Blit transparently? */ 
1848     memDC
.SelectObject(wxNullBitmap
); 
1850     /* draw bitmap. scaling and positioning is done there */ 
1851     DrawBitmap( bitmap
, xdest
, ydest 
); 
1856 wxCoord 
wxPostScriptDC::GetCharHeight() const 
1859         return m_font
.GetPointSize(); 
1864 void wxPostScriptDC::DoGetTextExtent(const wxString
& string
, 
1865                                      wxCoord 
*x
, wxCoord 
*y
, 
1866                                      wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1867                                      wxFont 
*theFont 
) const 
1869     wxFont 
*fontToUse 
= theFont
; 
1871     if (!fontToUse
) fontToUse 
= (wxFont
*) &m_font
; 
1873     wxCHECK_RET( fontToUse
, wxT("GetTextExtent: no font defined") ); 
1874     wxCHECK_RET( x
, wxT("GetTextExtent: x == NULL") ); 
1875     wxCHECK_RET( y
, wxT("GetTextExtent: y == NULL") ); 
1877     const wxWX2MBbuf strbuf 
= string
.mb_str(); 
1879 #if !wxUSE_AFM_FOR_POSTSCRIPT 
1880     /* Provide a VERY rough estimate (avoid using it). 
1881      * Produces accurate results for mono-spaced font 
1882      * such as Courier (aka wxMODERN) */ 
1887         height 
= fontToUse
->GetPointSize(); 
1890         *x 
= strlen (strbuf
) * height 
* 72 / 120; 
1892         *y 
= (wxCoord
) (height 
* 1.32);    /* allow for descender */ 
1893     if (descent
) *descent 
= 0; 
1894     if (externalLeading
) *externalLeading 
= 0; 
1897     /* method for calculating string widths in postscript: 
1898     /  read in the AFM (adobe font metrics) file for the 
1899     /  actual font, parse it and extract the character widths 
1900     /  and also the descender. this may be improved, but for now 
1901     /  it works well. the AFM file is only read in if the 
1902     /  font is changed. this may be chached in the future. 
1903     /  calls to GetTextExtent with the font unchanged are rather 
1906     /  for each font and style used there is an AFM file necessary. 
1907     /  currently i have only files for the roman font family. 
1908     /  I try to get files for the other ones! 
1910     /  CAVE: the size of the string is currently always calculated 
1911     /        in 'points' (1/72 of an inch). this should later on be 
1912     /        changed to depend on the mapping mode. 
1913     /  CAVE: the path to the AFM files must be set before calling this 
1914     /        function. this is usually done by a call like the following: 
1915     /        wxSetAFMPath("d:\\wxw161\\afm\\"); 
1919     /    wxPostScriptDC dc(NULL, TRUE); 
1921     /      wxSetAFMPath("d:\\wxw161\\afm\\"); 
1922     /      dc.StartDoc("Test"); 
1925     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); 
1926     /      dc.GetTextExtent("Hallo",&w,&h); 
1931     /  by steve (stefan.hammes@urz.uni-heidelberg.de) 
1933     /  updated: 14.05.95 */ 
1935     /* these static vars are for storing the state between calls */ 
1936     static int lastFamily
= INT_MIN
; 
1937     static int lastSize
= INT_MIN
; 
1938     static int lastStyle
= INT_MIN
; 
1939     static int lastWeight
= INT_MIN
; 
1940     static int lastDescender 
= INT_MIN
; 
1941     static int lastWidths
[256]; /* widths of the characters */ 
1943     double UnderlinePosition 
= 0.0; 
1944     double UnderlineThickness 
= 0.0; 
1946     /* get actual parameters */ 
1947     const int Family 
= fontToUse
->GetFamily(); 
1948     const int Size 
=   fontToUse
->GetPointSize(); 
1949     const int Style 
=  fontToUse
->GetStyle(); 
1950     const int Weight 
= fontToUse
->GetWeight(); 
1952     /* if we have another font, read the font-metrics */ 
1953     if (Family
!=lastFamily 
|| Size
!=lastSize 
|| Style
!=lastStyle 
|| Weight
!=lastWeight
) 
1955         /* store actual values */ 
1956         lastFamily 
= Family
; 
1959         lastWeight 
= Weight
; 
1961         char *name 
= (char*) NULL
; 
1967                     if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "CourBoO"; 
1968                     else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "CourBo"; 
1969                     else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "CourO"; 
1975                     if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "TimesBoO"; 
1976                     else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "TimesBo"; 
1977                     else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "TimesO"; 
1978                     else name 
= "TimesRo"; 
1983                     if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "HelvBoO"; 
1984                     else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= "HelvBo"; 
1985                     else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= "HelvO"; 
1991         /* get the directory of the AFM files */ 
1992         wxString afmName 
= wxEmptyString
; 
1993         if (!m_printData
.GetFontMetricPath().IsEmpty()) 
1995             afmName 
= m_printData
.GetFontMetricPath(); 
1998         /* 2. open and process the file 
1999            /  a short explanation of the AFM format: 
2000            /  we have for each character a line, which gives its size 
2003            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; 
2005            /  that means, we have a character with ascii code 63, and width 
2006            /  (444/1000 * fontSize) points. 
2007            /  the other data is ignored for now! 
2009            /  when the font has changed, we read in the right AFM file and store the 
2010            /  character widths in an array, which is processed below (see point 3.). */ 
2012         /* new elements JC Sun Aug 25 23:21:44 MET DST 1996 */ 
2014         afmName 
<< name 
<< wxT(".afm"); 
2015         FILE *afmFile 
= wxFopen(afmName
,wxT("r")); 
2018            afmName 
= wxThePrintSetupData
->GetAFMPath(); 
2019            afmName 
<< wxFILE_SEP_PATH 
<< name 
<< wxT(".afm"); 
2020            afmFile 
= wxFopen(afmName
,wxT("r")); 
2026         /* please do NOT change the line above to "else if (afmFile==NULL)" - 
2027            - afmFile = fopen() may fail and in that case the next if branch 
2028            MUST be executed - and it would not if there was "else" */ 
2030            afmName 
= wxINSTALL_PREFIX
; 
2031            afmName 
<<  wxFILE_SEP_PATH
 
2032                    << wxT("share") << wxFILE_SEP_PATH
 
2033                    << wxT("wx") << wxFILE_SEP_PATH
 
2034                    << wxT("afm") << wxFILE_SEP_PATH
 
2035                    << name 
<< wxT(".afm"); 
2036            afmFile 
= wxFopen(afmName
,wxT("r")); 
2043             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%hs'\n"), afmName
.c_str() ); 
2044             wxLogDebug( wxT("               using approximate values\n")); 
2045             for (int i
=0; i
<256; i
++) lastWidths
[i
] = 500; /* an approximate value */ 
2046             lastDescender 
= -150; /* dito. */ 
2050             /* init the widths array */ 
2051             for(int i
=0; i
<256; i
++) lastWidths
[i
] = INT_MIN
; 
2052             /* some variables for holding parts of a line */ 
2053             char cString
[10],semiString
[10],WXString
[10],descString
[20]; 
2054             char upString
[30], utString
[30], encString
[50]; 
2057             /* read in the file and parse it */ 
2058             while(fgets(line
,sizeof(line
),afmFile
)!=NULL
) 
2060                 /* A.) check for descender definition */ 
2061                 if (strncmp(line
,"Descender",9)==0) 
2063                     if ((sscanf(line
,"%s%d",descString
,&lastDescender
)!=2) || 
2064                             (strcmp(descString
,"Descender")!=0)) 
2066                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad descender)\n"), afmName
.c_str(),line 
); 
2069                 /* JC 1.) check for UnderlinePosition */ 
2070                 else if(strncmp(line
,"UnderlinePosition",17)==0) 
2072                     if ((sscanf(line
,"%s%lf",upString
,&UnderlinePosition
)!=2) || 
2073                             (strcmp(upString
,"UnderlinePosition")!=0)) 
2075                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlinePosition)\n"), afmName
.c_str(), line 
); 
2078                 /* JC 2.) check for UnderlineThickness */ 
2079                 else if(strncmp(line
,"UnderlineThickness",18)==0) 
2081                     if ((sscanf(line
,"%s%lf",utString
,&UnderlineThickness
)!=2) || 
2082                             (strcmp(utString
,"UnderlineThickness")!=0)) 
2084                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlineThickness)\n"), afmName
.c_str(), line 
); 
2087                 /* JC 3.) check for EncodingScheme */ 
2088                 else if(strncmp(line
,"EncodingScheme",14)==0) 
2090                     if ((sscanf(line
,"%s%s",utString
,encString
)!=2) || 
2091                             (strcmp(utString
,"EncodingScheme")!=0)) 
2093                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad EncodingScheme)\n"), afmName
.c_str(), line 
); 
2095                     else if (strncmp(encString
, "AdobeStandardEncoding", 21)) 
2097                         wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (unsupported EncodingScheme %hs)\n"), 
2098                                 afmName
.c_str(),line
, encString
); 
2101                 /* B.) check for char-width */ 
2102                 else if(strncmp(line
,"C ",2)==0) 
2104                     if (sscanf(line
,"%s%d%s%s%d",cString
,&ascii
,semiString
,WXString
,&cWidth
)!=5) 
2106                         wxLogDebug(wxT("AFM-file '%hs': line '%hs' has an error (bad character width)\n"),afmName
.c_str(),line
); 
2108                     if(strcmp(cString
,"C")!=0 || strcmp(semiString
,";")!=0 || strcmp(WXString
,"WX")!=0) 
2110                         wxLogDebug(wxT("AFM-file '%hs': line '%hs' has a format error\n"),afmName
.c_str(),line
); 
2112                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ 
2113                     if (ascii
>=0 && ascii
<256) 
2115                         lastWidths
[ascii
] = cWidth
; /* store width */ 
2119                         /* MATTHEW: this happens a lot; don't print an error */ 
2120                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range\n",afmName.c_str(),ascii); */ 
2123                 /* C.) ignore other entries. */ 
2127         /* hack to compute correct values for german 'Umlaute' 
2128            /  the correct way would be to map the character names 
2129            /  like 'adieresis' to corresp. positions of ISOEnc and read 
2130            /  these values from AFM files, too. Maybe later ... */ 
2131         lastWidths
[196] = lastWidths
['A'];  // Ä 
2132         lastWidths
[228] = lastWidths
['a'];  // ä 
2133         lastWidths
[214] = lastWidths
['O'];  // Ö 
2134         lastWidths
[246] = lastWidths
['o'];  // ö 
2135         lastWidths
[220] = lastWidths
['U'];  // Ü 
2136         lastWidths
[252] = lastWidths
['u'];  // ü 
2137         lastWidths
[223] = lastWidths
[251];  // ß 
2139         /* JC: calculate UnderlineThickness/UnderlinePosition */ 
2141         // VS: dirty, but is there any better solution? 
2143         pt 
= (double*) &m_underlinePosition
; 
2144         *pt 
= YLOG2DEVREL(UnderlinePosition 
* fontToUse
->GetPointSize()) / 1000.0f
; 
2145         pt 
= (double*) &m_underlineThickness
; 
2146         *pt 
= YLOG2DEVREL(UnderlineThickness 
* fontToUse
->GetPointSize()) / 1000.0f
; 
2151     /* 3. now the font metrics are read in, calc size this 
2152        /  is done by adding the widths of the characters in the 
2153        /  string. they are given in 1/1000 of the size! */ 
2156     wxCoord height
=Size
; /* by default */ 
2158     for(p
=(unsigned char *)wxMBSTRINGCAST strbuf
; *p
; p
++) 
2160         if(lastWidths
[*p
]== INT_MIN
) 
2162             wxLogDebug(wxT("GetTextExtent: undefined width for character '%hc' (%d)\n"), *p
,*p
); 
2163             widthSum 
+= (lastWidths
[' ']/1000.0F 
* Size
); /* assume space */ 
2167             widthSum 
+= ((lastWidths
[*p
]/1000.0F
)*Size
); 
2171     /* add descender to height (it is usually a negative value) */ 
2172     //if (lastDescender != INT_MIN) 
2174     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ 
2176     // - commented by V. Slavik - height already contains descender in it 
2177     //   (judging from few experiments) 
2179     /* return size values */ 
2181         *x 
= (wxCoord
)widthSum
; 
2185     /* return other parameters */ 
2188         if(lastDescender
!=INT_MIN
) 
2190             *descent 
= (wxCoord
)(((-lastDescender
)/1000.0F
) * Size
); /* MATTHEW: forgot scale */ 
2198     /* currently no idea how to calculate this! */ 
2199     if (externalLeading
) *externalLeading 
= 0; 
2204 // Determine the Default Postscript Previewer 
2205 // available on the platform 
2206 #if defined(__SUN__) && defined(__XVIEW__) 
2207 // OpenWindow/NeWS's Postscript Previewer 
2208 # define PS_VIEWER_PROG "pageview" 
2209 #elif defined(__VMS__) 
2210 #define PS_VIEWER_PROG "view/format=ps/select=x_display" 
2211 #elif defined(__SGI__) 
2212 // SGI's Display Postscript Previewer 
2213 //# define PS_VIEWER_PROG "dps" 
2214 # define PS_VIEWER_PROG "xpsview" 
2215 #elif defined(__X__) || defined(__WXGTK__) 
2216 // Front-end to ghostscript 
2217 # define PS_VIEWER_PROG "ghostview" 
2219 // Windows ghostscript/ghostview 
2220 # define PS_VIEWER_PROG "gsview" 
2223 wxPrintSetupData 
*wxThePrintSetupData 
= (wxPrintSetupData 
*) NULL
; 
2225 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC
, wxDC
) 
2226 IMPLEMENT_DYNAMIC_CLASS(wxPrintSetupData
, wxObject
) 
2228 // Redundant now I think 
2230 IMPLEMENT_CLASS(wxPostScriptPrintDialog
, wxDialog
) 
2232 wxPostScriptPrintDialog::wxPostScriptPrintDialog (wxWindow 
*parent
, const wxString
& title
, 
2233             const wxPoint
& pos
, const wxSize
& size
, wxCoord style
): 
2234    wxDialog(parent
, -1, title
, pos
, size
, style
) 
2236    wxBeginBusyCursor(); 
2241       *orientation 
= new wxString
[2], 
2242       *print_modes 
= new wxString
[3]; 
2244    wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
2245    double wx_printer_scale_x
, wx_printer_scale_y
; 
2247    orientation
[0] = _("Portrait"); 
2248    orientation
[1] = _("Landscape"); 
2250    print_modes
[0] = _("Send to Printer"); 
2251    print_modes
[1] = _("Print to File"); 
2252    print_modes
[2] = _("Preview Only"); 
2256    wxButton 
*okBut 
= new wxButton (this, wxID_OK
, _("OK"), wxPoint(5, 5)); 
2257    (void) new wxButton (this, wxID_CANCEL
, _("Cancel"), wxPoint(40, 5)); 
2258    okBut
->SetDefault(); 
2261 #if defined(__WXGTK__) || defined (__WXMOTIF__) 
2262    (void) new wxStaticText( this, -1, _("Printer Command: "), 
2264    (void) new wxTextCtrl( this, wxID_PRINTER_COMMAND
, wxThePrintSetupData
->GetPrinterCommand(), 
2265                           wxPoint(100, yPos
), wxSize(100, -1) ); 
2267    (void) new wxStaticText( this, -1, _("Printer Options: "), 
2268                             wxPoint(210, yPos
) ); 
2269    (void) new wxTextCtrl( this, wxID_PRINTER_OPTIONS
, wxThePrintSetupData
->GetPrinterOptions(), 
2270                           wxPoint(305, yPos
), wxSize(150, -1) ); 
2276    wxRadioBox 
*radio0 
= new wxRadioBox(this, wxID_PRINTER_ORIENTATION
, "Orientation: ", wxPoint(5, yPos
), wxSize(-1,-1), 
2277                                        2,orientation
,2,wxRA_SPECIFY_ROWS
); 
2278    radio0
->SetSelection((int)wxThePrintSetupData
->GetPrinterOrientation() - 1); 
2280   // @@@ Configuration hook 
2281    if ( !wxThePrintSetupData
->GetPrintPreviewCommand() ) 
2282       wxThePrintSetupData
->SetPrintPreviewCommand(PS_VIEWER_PROG
); 
2284    //   wxGetResource ("wxWindows", "PSView", &wxThePrintSetupData->m_previewCommand); 
2286    features 
= (wxThePrintSetupData
->GetPrintPreviewCommand() && 
2287                *wxThePrintSetupData
->GetPrintPreviewCommand()) ? 3 : 2; 
2289    wxRadioBox 
*radio1 
= new wxRadioBox(this, wxID_PRINTER_MODES
, _("PostScript:"), 
2291                                        wxSize(-1,-1), features
, 
2292                                        print_modes
, features
, wxRA_SPECIFY_ROWS
); 
2295    radio1
->Enable(0, FALSE
); 
2296    if (wxThePrintSetupData
->GetPrintPreviewCommand() && *wxThePrintSetupData
->GetPrintPreviewCommand()) 
2297       radio1
->Enable(2, FALSE
); 
2300    radio1
->SetSelection((int)wxThePrintSetupData
->GetPrinterMode()); 
2301    wxThePrintSetupData
->GetPrinterTranslation(&wx_printer_translate_x
, &wx_printer_translate_y
); 
2302    wxThePrintSetupData
->GetPrinterScaling(&wx_printer_scale_x
, &wx_printer_scale_y
); 
2304    sprintf (buf
, "%.2f", wx_printer_scale_x
); 
2307    (void) new wxStaticText(this, -1, _("X Scaling"), wxPoint(5, yPos
)); 
2308    /* wxTextCtrl *text1 = */ (void) new wxTextCtrl(this, wxID_PRINTER_X_SCALE
, buf
, wxPoint(100, yPos
), wxSize(100, -1)); 
2310    sprintf (buf
, "%.2f", wx_printer_scale_y
); 
2311    (void) new wxStaticText(this, -1, _("Y Scaling"), wxPoint(220, yPos
)); 
2312    /* wxTextCtrl *text2 = */ (void) new wxTextCtrl(this, wxID_PRINTER_Y_SCALE
, buf
, wxPoint(320, yPos
), wxSize(100, -1)); 
2316    (void) new wxStaticText(this, -1, _("X Translation"), wxPoint(5, yPos
)); 
2317    sprintf (buf
, "%.2d", wx_printer_translate_x
); 
2318    /* wxTextCtrl *text3 = */ (void) new wxTextCtrl(this, wxID_PRINTER_X_TRANS
, buf
, wxPoint(100, yPos
), wxSize(100, -1)); 
2320    (void) new wxStaticText(this, -1, _("Y Translation"), wxPoint(220, yPos
)); 
2321    sprintf (buf
, "%.2d", wx_printer_translate_y
); 
2322    /* wxTextCtrl *text4 = */ (void) new wxTextCtrl(this, wxID_PRINTER_Y_TRANS
, buf
, wxPoint(320, yPos
), wxSize(100, -1)); 
2326    delete[] orientation
; 
2327    delete[] print_modes
; 
2332 int wxPostScriptPrintDialog::ShowModal () 
2334   if ( wxDialog::ShowModal() == wxID_OK 
) 
2336 //    wxTextCtrl *text0 = (wxTextCtrl *)FindWindow(wxID_PRINTER_OPTIONS); 
2337       wxTextCtrl 
*text1 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_X_SCALE
); 
2338       wxTextCtrl 
*text2 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_Y_SCALE
); 
2339       wxTextCtrl 
*text3 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_X_TRANS
); 
2340       wxTextCtrl 
*text4 
= (wxTextCtrl 
*)FindWindow(wxID_PRINTER_Y_TRANS
); 
2341 //    wxTextCtrl *text_prt = (wxTextCtrl *)FindWindow(wxID_PRINTER_COMMAND); 
2342       wxRadioBox 
*radio0 
= (wxRadioBox 
*)FindWindow(wxID_PRINTER_ORIENTATION
); 
2343       wxRadioBox 
*radio1 
= (wxRadioBox 
*)FindWindow(wxID_PRINTER_MODES
); 
2345       StringToDouble (WXSTRINGCAST text1
->GetValue (), &wxThePrintSetupData
->m_printerScaleX
); 
2346       StringToDouble (WXSTRINGCAST text2
->GetValue (), &wxThePrintSetupData
->m_printerScaleY
); 
2349       StringToLong (WXSTRINGCAST text3
->GetValue (), &dummy
); 
2350       wxThePrintSetupData
->m_printerTranslateX 
= (wxCoord
)dummy
; 
2351       StringToLong (WXSTRINGCAST text4
->GetValue (), &dummy
); 
2352       wxThePrintSetupData
->m_printerTranslateY 
= (wxCoord
)dummy
; 
2355       //      wxThePrintSetupData->SetPrinterOptions(WXSTRINGCAST text0->GetValue ()); 
2356       //      wxThePrintSetupData->SetPrinterCommand(WXSTRINGCAST text_prt->GetValue ()); 
2359       wxThePrintSetupData
->SetPrinterOrientation((radio0
->GetSelection() == 1 ? wxLANDSCAPE 
: wxPORTRAIT
)); 
2362       switch ( radio1
->GetSelection() ) { 
2363         case 0: wxThePrintSetupData
->SetPrinterMode(PS_PRINTER
); break; 
2364         case 1:  wxThePrintSetupData
->SetPrinterMode(PS_FILE
); break; 
2365         case 2: wxThePrintSetupData
->SetPrinterMode(PS_PREVIEW
); break; 
2374 // PostScript printer settings 
2375 // RETAINED FOR BACKWARD COMPATIBILITY 
2376 void wxSetPrinterCommand(const wxString
& cmd
) 
2378   wxThePrintSetupData
->SetPrinterCommand(cmd
); 
2381 void wxSetPrintPreviewCommand(const wxString
& cmd
) 
2383   wxThePrintSetupData
->SetPrintPreviewCommand(cmd
); 
2386 void wxSetPrinterOptions(const wxString
& flags
) 
2388   wxThePrintSetupData
->SetPrinterOptions(flags
); 
2391 void wxSetPrinterFile(const wxString
& f
) 
2393   wxThePrintSetupData
->SetPrinterFile(f
); 
2396 void wxSetPrinterOrientation(int orient
) 
2398   wxThePrintSetupData
->SetPrinterOrientation(orient
); 
2401 void wxSetPrinterScaling(double x
, double y
) 
2403   wxThePrintSetupData
->SetPrinterScaling(x
, y
); 
2406 void wxSetPrinterTranslation(wxCoord x
, wxCoord y
) 
2408   wxThePrintSetupData
->SetPrinterTranslation(x
, y
); 
2411 // 1 = Preview, 2 = print to file, 3 = send to printer 
2412 void wxSetPrinterMode(int mode
) 
2414   wxThePrintSetupData
->SetPrinterMode(mode
); 
2417 void wxSetAFMPath(const wxString
& f
) 
2419   wxThePrintSetupData
->SetAFMPath(f
); 
2422 // Get current values 
2423 wxString 
wxGetPrinterCommand() 
2425   return wxThePrintSetupData
->GetPrinterCommand(); 
2428 wxString 
wxGetPrintPreviewCommand() 
2430   return wxThePrintSetupData
->GetPrintPreviewCommand(); 
2433 wxString 
wxGetPrinterOptions() 
2435   return wxThePrintSetupData
->GetPrinterOptions(); 
2438 wxString 
wxGetPrinterFile() 
2440   return wxThePrintSetupData
->GetPrinterFile(); 
2443 int wxGetPrinterOrientation() 
2445   return wxThePrintSetupData
->GetPrinterOrientation(); 
2448 void wxGetPrinterScaling(double* x
, double* y
) 
2450   wxThePrintSetupData
->GetPrinterScaling(x
, y
); 
2453 void wxGetPrinterTranslation(wxCoord 
*x
, wxCoord 
*y
) 
2455   wxThePrintSetupData
->GetPrinterTranslation(x
, y
); 
2458 int wxGetPrinterMode() 
2460   return wxThePrintSetupData
->GetPrinterMode(); 
2463 wxString 
wxGetAFMPath() 
2465   return wxThePrintSetupData
->GetAFMPath(); 
2472 wxPrintSetupData::wxPrintSetupData() 
2474   m_printerOrient 
= wxPORTRAIT
; 
2475   m_printerScaleX 
= (double)1.0; 
2476   m_printerScaleY 
= (double)1.0; 
2477   m_printerTranslateX 
= 0; 
2478   m_printerTranslateY 
= 0; 
2479   m_printerMode 
= wxPRINT_MODE_FILE
; 
2480   m_printColour 
= TRUE
; 
2483 wxPrintSetupData::~wxPrintSetupData() 
2487 void wxPrintSetupData::operator=(wxPrintSetupData
& data
) 
2489   SetPrinterCommand(data
.GetPrinterCommand()); 
2490   SetPrintPreviewCommand(data
.GetPrintPreviewCommand()); 
2491   SetPrinterOptions(data
.GetPrinterOptions()); 
2493   data
.GetPrinterTranslation(&x
, &y
); 
2494   SetPrinterTranslation(x
, y
); 
2497   data
.GetPrinterScaling(&x1
, &y1
); 
2498   SetPrinterScaling(x1
, y1
); 
2500   SetPrinterOrientation(data
.GetPrinterOrientation()); 
2501   SetPrinterMode(data
.GetPrinterMode()); 
2502   SetAFMPath(data
.GetAFMPath()); 
2503   SetPaperName(data
.GetPaperName()); 
2504   SetColour(data
.GetColour()); 
2507 // Initialize from a wxPrintData object (wxPrintData should now be used instead of wxPrintSetupData). 
2508 void wxPrintSetupData::operator=(const wxPrintData
& data
) 
2510     SetPrinterCommand(data
.GetPrinterCommand()); 
2511     SetPrintPreviewCommand(data
.GetPreviewCommand()); 
2512     SetPrinterOptions(data
.GetPrinterOptions()); 
2513     SetPrinterTranslation(data
.GetPrinterTranslateX(), data
.GetPrinterTranslateY()); 
2514     SetPrinterScaling(data
.GetPrinterScaleX(), data
.GetPrinterScaleY()); 
2515     SetPrinterOrientation(data
.GetOrientation()); 
2516     SetPrinterMode((int) data
.GetPrintMode()); 
2517     SetAFMPath(data
.GetFontMetricPath()); 
2518     SetPaperName(wxThePrintPaperDatabase
->ConvertIdToName(data
.GetPaperId())); 
2519     SetColour(data
.GetColour()); 
2520     SetPrinterFile(data
.GetFilename()); 
2523 void wxInitializePrintSetupData(bool init
) 
2527     wxThePrintSetupData 
= new wxPrintSetupData
; 
2529     wxThePrintSetupData
->SetPrintPreviewCommand(PS_VIEWER_PROG
); 
2530     wxThePrintSetupData
->SetPrinterOrientation(wxPORTRAIT
); 
2531     wxThePrintSetupData
->SetPrinterMode(wxPRINT_MODE_PREVIEW
); 
2532     wxThePrintSetupData
->SetPaperName(_("A4 sheet, 210 x 297 mm")); 
2534     // Could have a .ini file to read in some defaults 
2535     // - and/or use environment variables, e.g. WXWIN 
2537     wxThePrintSetupData
->SetPrinterCommand("print"); 
2538     wxThePrintSetupData
->SetPrinterOptions("/nonotify/queue=psqueue"); 
2539     wxThePrintSetupData
->SetAFMPath("sys$ps_font_metrics:"); 
2542     wxThePrintSetupData
->SetPrinterCommand("print"); 
2543     wxThePrintSetupData
->SetAFMPath("c:\\windows\\system\\"); 
2544     wxThePrintSetupData
->SetPrinterOptions(""); 
2546 #if !defined(__VMS__) && !defined(__WXMSW__) 
2547     wxThePrintSetupData
->SetPrinterCommand("lpr"); 
2548     wxThePrintSetupData
->SetPrinterOptions(""); 
2549     wxThePrintSetupData
->SetAFMPath(""); 
2554     if (wxThePrintSetupData
) 
2555       delete wxThePrintSetupData
; 
2556      wxThePrintSetupData 
= (wxPrintSetupData 
*) NULL
; 
2560 // A module to allow initialization/cleanup of PostScript-related 
2561 // things without calling these functions from app.cpp. 
2563 class WXDLLEXPORT wxPostScriptModule
: public wxModule
 
2565 DECLARE_DYNAMIC_CLASS(wxPostScriptModule
) 
2567     wxPostScriptModule() {} 
2572 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptModule
, wxModule
) 
2575  * Initialization/cleanup module 
2578 bool wxPostScriptModule::OnInit() 
2580     wxInitializePrintSetupData(); 
2585 void wxPostScriptModule::OnExit() 
2587     wxInitializePrintSetupData(FALSE
); 
2594   // wxUSE_PRINTING_ARCHITECTURE