1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/dcpsg.cpp 
   3 // Purpose:     Generic wxPostScriptDC implementation 
   4 // Author:      Julian Smart, Robert Roebling, Markus Holzhem 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  18 #if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT 
  20 #include "wx/generic/dcpsg.h" 
  27     #include "wx/dcmemory.h" 
  32 #include "wx/prntbase.h" 
  33 #include "wx/generic/prntdlgg.h" 
  35 #include "wx/filefn.h" 
  36 #include "wx/stdpaths.h" 
  38 WXDLLIMPEXP_DATA_CORE(int) wxPageNumber
; 
  60 //----------------------------------------------------------------------------- 
  61 // start and end of document/page 
  62 //----------------------------------------------------------------------------- 
  64 static const char *wxPostScriptHeaderConicTo 
= "\ 
  68     /conic_cntrl_y exch def\n\ 
  69     /conic_cntrl_x exch def\n\ 
  73     /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\ 
  74     /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\ 
  75     /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\ 
  76     /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\ 
  77     p1_x p1_y p2_x p2_y to_x to_y curveto\n\ 
  81 static const char *wxPostScriptHeaderEllipse 
= "\ 
  82 /ellipsedict 8 dict def\n\ 
  83 ellipsedict /mtrx matrix put\n\ 
  87     /startangle exch def\n\ 
  92     /savematrix mtrx currentmatrix def\n\ 
  95     0 0 1 startangle endangle arc\n\ 
  96     savematrix setmatrix\n\ 
 101 static const char *wxPostScriptHeaderEllipticArc
= "\ 
 102 /ellipticarcdict 8 dict def\n\ 
 103 ellipticarcdict /mtrx matrix put\n\ 
 105 { ellipticarcdict begin\n\ 
 107   /endangle exch def\n\ 
 108   /startangle exch def\n\ 
 113   /savematrix mtrx currentmatrix def\n\ 
 116   do_fill { 0 0 moveto } if\n\ 
 117   0 0 1 startangle endangle arc\n\ 
 118   savematrix setmatrix\n\ 
 119   do_fill { fill }{ stroke } ifelse\n\ 
 123 static const char *wxPostScriptHeaderSpline 
= "\ 
 124 /DrawSplineSection {\n\ 
 131     /xa x1 x2 x1 sub 0.666667 mul add def\n\ 
 132     /ya y1 y2 y1 sub 0.666667 mul add def\n\ 
 133     /xb x3 x2 x3 sub 0.666667 mul add def\n\ 
 134     /yb y3 y2 y3 sub 0.666667 mul add def\n\ 
 136     xa ya xb yb x3 y3 curveto\n\ 
 140 static const char *wxPostScriptHeaderColourImage 
= "\ 
 141 % define 'colorimage' if it isn't defined\n\ 
 142 %   ('colortogray' and 'mergeprocs' come from xwd2ps\n\ 
 144 /colorimage where   % do we know about 'colorimage'?\n\ 
 145   { pop }           % yes: pop off the 'dict' returned\n\ 
 146   {                 % no:  define one\n\ 
 147     /colortogray {  % define an RGB->I function\n\ 
 148       /rgbdata exch store    % call input 'rgbdata'\n\ 
 149       rgbdata length 3 idiv\n\ 
 150       /npixls exch store\n\ 
 152       0 1 npixls 1 sub {\n\ 
 154         rgbdata rgbindx       get 20 mul    % Red\n\ 
 155         rgbdata rgbindx 1 add get 32 mul    % Green\n\ 
 156         rgbdata rgbindx 2 add get 12 mul    % Blue\n\ 
 157         add add 64 idiv      % I = .5G + .31R + .18B\n\ 
 159         /rgbindx rgbindx 3 add store\n\ 
 161       grays 0 npixls getinterval\n\ 
 164     % Utility procedure for colorimage operator.\n\ 
 165     % This procedure takes two procedures off the\n\ 
 166     % stack and merges them into a single procedure.\n\ 
 168     /mergeprocs { % def\n\ 
 187     /colorimage { % def\n\ 
 188       pop pop     % remove 'false 3' operands\n\ 
 189       {colortogray} mergeprocs\n\ 
 192   } ifelse          % end of 'false' case\n\ 
 195 static char wxPostScriptHeaderReencodeISO1
[] = 
 197 "dup dup findfont dup length dict begin\n" 
 198 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" 
 199 "/Encoding ISOLatin1Encoding def\n" 
 200 "currentdict end definefont\n" 
 202 "/ISOLatin1Encoding [\n" 
 203 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 204 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 205 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 206 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 207 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" 
 208 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" 
 209 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" 
 210 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" 
 211 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" 
 212 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" 
 213 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" 
 214 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 215 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 216 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" 
 217 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; 
 219 static char wxPostScriptHeaderReencodeISO2
[] = 
 220 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" 
 221 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" 
 222 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" 
 223 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" 
 224 "/guillemotright/onequarter/onehalf/threequarters/questiondown\n" 
 225 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" 
 226 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" 
 227 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" 
 228 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" 
 229 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" 
 230 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" 
 231 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" 
 232 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" 
 233 "/yacute/thorn/ydieresis\n" 
 236 //------------------------------------------------------------------------------- 
 238 //------------------------------------------------------------------------------- 
 240 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC
, wxDC
) 
 242 float wxPostScriptDC::ms_PSScaleFactor 
= 1.0; 
 244 void wxPostScriptDC::SetResolution(int ppi
) 
 246     ms_PSScaleFactor 
= (float)ppi 
/ 72.0; 
 249 int wxPostScriptDC::GetResolution() 
 251     return (int)(ms_PSScaleFactor 
* 72.0); 
 254 //------------------------------------------------------------------------------- 
 256 wxPostScriptDC::wxPostScriptDC () 
 258     m_pstream 
= (FILE*) NULL
; 
 268     m_underlinePosition 
= 0.0; 
 269     m_underlineThickness 
= 0.0; 
 271     m_signX 
=  1;  // default x-axis left to right 
 272     m_signY 
= -1;  // default y-axis bottom up -> top down 
 275 wxPostScriptDC::wxPostScriptDC (const wxPrintData
& printData
) 
 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     m_printData 
= printData
; 
 298 wxPostScriptDC::~wxPostScriptDC () 
 303         m_pstream 
= (FILE*) NULL
; 
 307 bool wxPostScriptDC::Ok() const 
 312 void wxPostScriptDC::DoSetClippingRegion (wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 314     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 316     if (m_clipping
) DestroyClippingRegion(); 
 318     wxDC::DoSetClippingRegion(x
, y
, w
, h
); 
 322     PsPrintf( wxT("gsave\n newpath\n") 
 323               wxT("%d %d moveto\n") 
 324               wxT("%d %d lineto\n") 
 325               wxT("%d %d lineto\n") 
 326               wxT("%d %d lineto\n") 
 327               wxT("closepath clip newpath\n"), 
 328             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 329             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
), 
 330             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
+h
), 
 331             LogicalToDeviceX(x
),   LogicalToDeviceY(y
+h
) ); 
 335 void wxPostScriptDC::DestroyClippingRegion() 
 337     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 342         PsPrint( "grestore\n" ); 
 345     wxDC::DestroyClippingRegion(); 
 348 void wxPostScriptDC::Clear() 
 350     // This should fail silently to avoid unnecessary 
 352     //    wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); 
 355 bool wxPostScriptDC::DoFloodFill (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
)) 
 357     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); 
 361 bool wxPostScriptDC::DoGetPixel (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxColour 
* WXUNUSED(col
)) const 
 363     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); 
 367 void wxPostScriptDC::DoCrossHair (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) 
 369     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); 
 372 void wxPostScriptDC::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 374     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 376     if  (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 380     PsPrintf( wxT("newpath\n") 
 381               wxT("%d %d moveto\n") 
 382               wxT("%d %d lineto\n") 
 384             LogicalToDeviceX(x1
), LogicalToDeviceY(y1
), 
 385             LogicalToDeviceX(x2
), LogicalToDeviceY (y2
) ); 
 387     CalcBoundingBox( x1
, y1 
); 
 388     CalcBoundingBox( x2
, y2 
); 
 391 #define RAD2DEG 57.29577951308 
 393 void wxPostScriptDC::DoDrawArc (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 395     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 397     wxCoord dx 
= x1 
- xc
; 
 398     wxCoord dy 
= y1 
- yc
; 
 399     wxCoord radius 
= (wxCoord
) sqrt( (double)(dx
*dx
+dy
*dy
) ); 
 400     double alpha1
, alpha2
; 
 402     if (x1 
== x2 
&& y1 
== y2
) 
 407     else if ( wxIsNullDouble(radius
) ) 
 414         alpha1 
= (x1 
- xc 
== 0) ? 
 415             (y1 
- yc 
< 0) ? 90.0 : -90.0 : 
 416                 -atan2(double(y1
-yc
), double(x1
-xc
)) * RAD2DEG
; 
 417         alpha2 
= (x2 
- xc 
== 0) ? 
 418             (y2 
- yc 
< 0) ? 90.0 : -90.0 : 
 419                 -atan2(double(y2
-yc
), double(x2
-xc
)) * RAD2DEG
; 
 421     while (alpha1 
<= 0)   alpha1 
+= 360; 
 422     while (alpha2 
<= 0)   alpha2 
+= 360; // adjust angles to be between 
 423     while (alpha1 
> 360)  alpha1 
-= 360; // 0 and 360 degree 
 424     while (alpha2 
> 360)  alpha2 
-= 360; 
 426     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 430         PsPrintf( wxT("newpath\n") 
 431                   wxT("%d %d %d %d %d %d ellipse\n") 
 432                   wxT("%d %d lineto\n") 
 435                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 436                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 438         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 439         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 442     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 446         PsPrintf( wxT("newpath\n") 
 447                   wxT("%d %d %d %d %d %d ellipse\n") 
 448                   wxT("%d %d lineto\n") 
 451                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 452                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 454         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 455         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 459 void wxPostScriptDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 461     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 463     if ( sa 
>= 360 || sa 
<= -360 ) 
 464         sa 
-= int(sa
/360)*360; 
 465     if ( ea 
>= 360 || ea 
<=- 360 ) 
 466         ea 
-= int(ea
/360)*360; 
 472     if ( wxIsSameDouble(sa
, ea
) ) 
 474         DrawEllipse(x
,y
,w
,h
); 
 478     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 482         PsPrintf( wxT("newpath\n") 
 483                   wxT("%d %d %d %d %d %d true ellipticarc\n"), 
 484                   LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 485                   LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 486                   (wxCoord
)sa
, (wxCoord
)ea 
); 
 488         CalcBoundingBox( x 
,y 
); 
 489         CalcBoundingBox( x
+w
, y
+h 
); 
 492     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 496         PsPrintf( wxT("newpath\n") 
 497                   wxT("%d %d %d %d %d %d false ellipticarc\n"), 
 498                 LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 499                 LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 500                 (wxCoord
)sa
, (wxCoord
)ea 
); 
 502         CalcBoundingBox( x 
,y 
); 
 503         CalcBoundingBox( x
+w
, y
+h 
); 
 507 void wxPostScriptDC::DoDrawPoint (wxCoord x
, wxCoord y
) 
 509     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 511     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 515     PsPrintf( wxT("newpath\n") 
 516               wxT("%d %d moveto\n") 
 517               wxT("%d %d lineto\n") 
 519             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 520             LogicalToDeviceX(x
+1), LogicalToDeviceY(y
) ); 
 522     CalcBoundingBox( x
, y 
); 
 525 void wxPostScriptDC::DoDrawPolygon (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 527     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 531     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 535         PsPrint( "newpath\n" ); 
 537         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 538         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 540         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 542         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 544         for (int i 
= 1; i 
< n
; i
++) 
 546             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 547             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 549             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 551             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 554         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 557     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 561         PsPrint( "newpath\n" ); 
 563         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 564         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 566         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 568         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 570         for (int i 
= 1; i 
< n
; i
++) 
 572             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 573             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 575             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 577             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 580         PsPrint( "closepath\n" ); 
 581         PsPrint( "stroke\n" ); 
 585 void wxPostScriptDC::DoDrawPolyPolygon (int n
, int count
[], wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 587     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 591     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 595         PsPrint( "newpath\n" ); 
 598         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 600             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 601             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 603             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 605             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 607             for (int j 
= 1; j 
< count
[i
]; j
++) 
 609                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 610                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 612                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 614                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 617         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 620     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 624         PsPrint( "newpath\n" ); 
 627         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 629             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 630             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 632             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 634             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 636             for (int j 
= 1; j 
< count
[i
]; j
++) 
 638                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 639                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 641                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 643                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 646         PsPrint( "closepath\n" ); 
 647         PsPrint( "stroke\n" ); 
 651 void wxPostScriptDC::DoDrawLines (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 653     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 655     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 662     for ( i 
=0; i
<n 
; i
++ ) 
 664         CalcBoundingBox( LogicalToDeviceX(points
[i
].x
+xoffset
), LogicalToDeviceY(points
[i
].y
+yoffset
)); 
 667     PsPrintf( wxT("newpath\n") 
 668               wxT("%d %d moveto\n"), 
 669               LogicalToDeviceX(points
[0].x
+xoffset
), 
 670               LogicalToDeviceY(points
[0].y
+yoffset
) ); 
 672     for (i 
= 1; i 
< n
; i
++) 
 674         PsPrintf( wxT("%d %d lineto\n"), 
 675                   LogicalToDeviceX(points
[i
].x
+xoffset
), 
 676                   LogicalToDeviceY(points
[i
].y
+yoffset
) ); 
 679     PsPrint( "stroke\n" ); 
 682 void wxPostScriptDC::DoDrawRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 684     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 686     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 690         PsPrintf( wxT("newpath\n") 
 691                   wxT("%d %d moveto\n") 
 692                   wxT("%d %d lineto\n") 
 693                   wxT("%d %d lineto\n") 
 694                   wxT("%d %d lineto\n") 
 697                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 698                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 699                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 700                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 702         CalcBoundingBox( x
, y 
); 
 703         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 706     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 710         PsPrintf( wxT("newpath\n") 
 711                   wxT("%d %d moveto\n") 
 712                   wxT("%d %d lineto\n") 
 713                   wxT("%d %d lineto\n") 
 714                   wxT("%d %d lineto\n") 
 717                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 718                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 719                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 720                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 722         CalcBoundingBox( x
, y 
); 
 723         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 727 void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 729     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 733         // Now, a negative radius is interpreted to mean 
 734         // 'the proportion of the smallest X or Y dimension' 
 735         double smallest 
= width 
< height 
? width 
: height
; 
 736         radius 
=  (-radius 
* smallest
); 
 739     wxCoord rad 
= (wxCoord
) radius
; 
 741     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 745         /* Draw rectangle anticlockwise */ 
 746         PsPrintf( wxT("newpath\n") 
 747                   wxT("%d %d %d 90 180 arc\n") 
 748                   wxT("%d %d lineto\n") 
 749                   wxT("%d %d %d 180 270 arc\n") 
 750                   wxT("%d %d lineto\n") 
 751                   wxT("%d %d %d 270 0 arc\n") 
 752                   wxT("%d %d lineto\n") 
 753                   wxT("%d %d %d 0 90 arc\n") 
 754                   wxT("%d %d lineto\n") 
 757                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 758                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 759                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 760                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 761                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 762                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 763                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 764                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 766         CalcBoundingBox( x
, y 
); 
 767         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 770     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 774         /* Draw rectangle anticlockwise */ 
 775         PsPrintf( wxT("newpath\n") 
 776                   wxT("%d %d %d 90 180 arc\n") 
 777                   wxT("%d %d lineto\n") 
 778                   wxT("%d %d %d 180 270 arc\n") 
 779                   wxT("%d %d lineto\n") 
 780                   wxT("%d %d %d 270 0 arc\n") 
 781                   wxT("%d %d lineto\n") 
 782                   wxT("%d %d %d 0 90 arc\n") 
 783                   wxT("%d %d lineto\n") 
 786                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 787                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 788                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 789                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 790                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 791                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 792                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 793                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 795         CalcBoundingBox( x
, y 
); 
 796         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 800 void wxPostScriptDC::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 802     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 804     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 808         PsPrintf( wxT("newpath\n") 
 809                   wxT("%d %d %d %d 0 360 ellipse\n") 
 811                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 812                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 814         CalcBoundingBox( x 
- width
, y 
- height 
); 
 815         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 818     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 822         PsPrintf( wxT("newpath\n") 
 823                   wxT("%d %d %d %d 0 360 ellipse\n") 
 825                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 826                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 828         CalcBoundingBox( x 
- width
, y 
- height 
); 
 829         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 833 void wxPostScriptDC::DoDrawIcon( const wxIcon
& icon
, wxCoord x
, wxCoord y 
) 
 835     DrawBitmap( icon
, x
, y
, true ); 
 838 /* this has to be char, not wxChar */ 
 839 static char hexArray
[] = "0123456789ABCDEF"; 
 841 void wxPostScriptDC::DoDrawBitmap( const wxBitmap
& bitmap
, wxCoord x
, wxCoord y
, bool WXUNUSED(useMask
) ) 
 843     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 845     if (!bitmap
.Ok()) return; 
 847     wxImage image 
= bitmap
.ConvertToImage(); 
 849     if (!image
.Ok()) return; 
 851     wxCoord w 
= image
.GetWidth(); 
 852     wxCoord h 
= image
.GetHeight(); 
 854     wxCoord ww 
= LogicalToDeviceXRel(image
.GetWidth()); 
 855     wxCoord hh 
= LogicalToDeviceYRel(image
.GetHeight()); 
 857     wxCoord xx 
= LogicalToDeviceX(x
); 
 858     wxCoord yy 
= LogicalToDeviceY(y 
+ bitmap
.GetHeight()); 
 860     PsPrintf( wxT("/origstate save def\n") 
 861               wxT("20 dict begin\n") 
 862               wxT("/pix %d string def\n") 
 863               wxT("/grays %d string def\n") 
 864               wxT("/npixels 0 def\n") 
 865               wxT("/rgbindx 0 def\n") 
 866               wxT("%d %d translate\n") 
 869               wxT("[%d 0 0 %d 0 %d]\n") 
 870               wxT("{currentfile pix readhexstring pop}\n") 
 871               wxT("false 3 colorimage\n"), 
 872             w
, w
, xx
, yy
, ww
, hh
, w
, h
, w
, -h
, h 
); 
 874     unsigned char* data 
= image
.GetData(); 
 876     // size of the buffer = width*rgb(3)*hexa(2)+'\n' 
 877     wxCharBuffer 
buffer(w
*6 + 1); 
 878     int firstDigit
, secondDigit
; 
 881     for (int j 
= 0; j 
< h
; j
++) 
 883         char* bufferindex 
= buffer
.data(); 
 886         for (int i 
= 0; i 
< w
*3; i
++) 
 888             firstDigit 
= (int)(*data
/16.0); 
 889             secondDigit 
= (int)(*data 
- (firstDigit
*16.0)); 
 890             *(bufferindex
++) = hexArray
[firstDigit
]; 
 891             *(bufferindex
++) = hexArray
[secondDigit
]; 
 895         *(bufferindex
++) = '\n'; 
 901     PsPrint( "origstate restore\n" ); 
 904 void wxPostScriptDC::SetFont( const wxFont
& font 
) 
 906     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 908     if (!font
.Ok())  return; 
 912     int Style 
= m_font
.GetStyle(); 
 913     int Weight 
= m_font
.GetWeight(); 
 916     switch (m_font
.GetFamily()) 
 921             if (Style 
== wxITALIC
) 
 923                 if (Weight 
== wxBOLD
) 
 924                     name 
= "/Courier-BoldOblique"; 
 926                     name 
= "/Courier-Oblique"; 
 930                 if (Weight 
== wxBOLD
) 
 931                     name 
= "/Courier-Bold"; 
 939             if (Style 
== wxITALIC
) 
 941                 if (Weight 
== wxBOLD
) 
 942                     name 
= "/Times-BoldItalic"; 
 944                     name 
= "/Times-Italic"; 
 948                 if (Weight 
== wxBOLD
) 
 949                     name 
= "/Times-Bold"; 
 951                     name 
= "/Times-Roman"; 
 957             name 
= "/ZapfChancery-MediumItalic"; 
 963             if (Style 
== wxITALIC
) 
 965                 if (Weight 
== wxBOLD
) 
 966                     name 
= "/Helvetica-BoldOblique"; 
 968                     name 
= "/Helvetica-Oblique"; 
 972                 if (Weight 
== wxBOLD
) 
 973                     name 
= "/Helvetica-Bold"; 
 981     // We may legitimately call SetFont before BeginDoc 
 986     PsPrint( " reencodeISO def\n" ); 
 988     PsPrint( " findfont\n" ); 
 991     sprintf( buffer
, "%f scalefont setfont\n", LogicalToDeviceYRel(m_font
.GetPointSize() * 1000) / 1000.0F
); 
 992     // this is a hack - we must scale font size (in pts) according to m_scaleY but 
 993     // LogicalToDeviceYRel works with wxCoord type (int or longint). Se we first convert font size 
 994     // to 1/1000th of pt and then back. 
 995     for (int i 
= 0; i 
< 100; i
++) 
 996         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1000 void wxPostScriptDC::SetPen( const wxPen
& pen 
) 
1002     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1004     if (!pen
.Ok()) return; 
1006     int oldStyle 
= m_pen
.GetStyle(); 
1011     sprintf( buffer
, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1012     for (int i 
= 0; i 
< 100; i
++) 
1013         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1017      Line style - WRONG: 2nd arg is OFFSET 
1019      Here, I'm afraid you do not conceive meaning of parameters of 'setdash' 
1020      operator correctly. You should look-up this in the Red Book: the 2nd parame- 
1021      ter is not number of values in the array of the first one, but an offset 
1022      into this description of the pattern. I mean a real *offset* not index 
1023      into array. I.e. If the command is [3 4] 1 setdash   is used, then there 
1024      will be first black line *2* units wxCoord, then space 4 units, then the 
1025      pattern of *3* units black, 4 units space will be repeated. 
1028     static const char *dotted 
= "[2 5] 2"; 
1029     static const char *short_dashed 
= "[4 4] 2"; 
1030     static const char *wxCoord_dashed 
= "[4 8] 2"; 
1031     static const char *dotted_dashed 
= "[6 6 2 6] 4"; 
1035     switch (m_pen
.GetStyle()) 
1037         case wxDOT
:           psdash 
= dotted
;         break; 
1038         case wxSHORT_DASH
:    psdash 
= short_dashed
;   break; 
1039         case wxLONG_DASH
:     psdash 
= wxCoord_dashed
; break; 
1040         case wxDOT_DASH
:      psdash 
= dotted_dashed
;  break; 
1044             int nDashes 
= m_pen
.GetDashes (&dashes
); 
1046             for (int i 
= 0; i 
< nDashes
; ++i
) 
1048                 sprintf( buffer
, "%d ", dashes 
[i
] ); 
1051             PsPrint ("] 0 setdash\n"); 
1057         default:              psdash 
= "[] 0";         break; 
1060     if ( psdash 
&& (oldStyle 
!= m_pen
.GetStyle()) ) 
1063         PsPrint( " setdash\n" ); 
1067     unsigned char red 
= m_pen
.GetColour().Red(); 
1068     unsigned char blue 
= m_pen
.GetColour().Blue(); 
1069     unsigned char green 
= m_pen
.GetColour().Green(); 
1073         // Anything not white is black 
1074         if (! (red 
== (unsigned char) 255 && 
1075                blue 
== (unsigned char) 255 && 
1076                green 
== (unsigned char) 255) ) 
1078             red 
= (unsigned char) 0; 
1079             green 
= (unsigned char) 0; 
1080             blue 
= (unsigned char) 0; 
1085     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1087         double redPS 
= (double)(red
) / 255.0; 
1088         double bluePS 
= (double)(blue
) / 255.0; 
1089         double greenPS 
= (double)(green
) / 255.0; 
1092             "%.8f %.8f %.8f setrgbcolor\n", 
1093             redPS
, greenPS
, bluePS 
); 
1094         for (int i 
= 0; i 
< 100; i
++) 
1095             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1100         m_currentBlue 
= blue
; 
1101         m_currentGreen 
= green
; 
1105 void wxPostScriptDC::SetBrush( const wxBrush
& brush 
) 
1107     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1109     if (!brush
.Ok()) return; 
1114     unsigned char red 
= m_brush
.GetColour().Red(); 
1115     unsigned char blue 
= m_brush
.GetColour().Blue(); 
1116     unsigned char green 
= m_brush
.GetColour().Green(); 
1120         // Anything not white is black 
1121         if (! (red 
== (unsigned char) 255 && 
1122                blue 
== (unsigned char) 255 && 
1123                green 
== (unsigned char) 255) ) 
1125             red 
= (unsigned char) 0; 
1126             green 
= (unsigned char) 0; 
1127             blue 
= (unsigned char) 0; 
1132     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1134         double redPS 
= (double)(red
) / 255.0; 
1135         double bluePS 
= (double)(blue
) / 255.0; 
1136         double greenPS 
= (double)(green
) / 255.0; 
1140                 "%.8f %.8f %.8f setrgbcolor\n", 
1141                 redPS
, greenPS
, bluePS 
); 
1142         for (int i 
= 0; i 
< 100; i
++) 
1143             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1148         m_currentBlue 
= blue
; 
1149         m_currentGreen 
= green
; 
1153 void wxPostScriptDC::DoDrawText( const wxString
& text
, wxCoord x
, wxCoord y 
) 
1155     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1157     if (m_textForegroundColour
.Ok()) 
1159         unsigned char red 
= m_textForegroundColour
.Red(); 
1160         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1161         unsigned char green 
= m_textForegroundColour
.Green(); 
1165             // Anything not white is black 
1166             if (! (red 
== (unsigned char) 255 && 
1167                         blue 
== (unsigned char) 255 && 
1168                         green 
== (unsigned char) 255)) 
1170                 red 
= (unsigned char) 0; 
1171                 green 
= (unsigned char) 0; 
1172                 blue 
= (unsigned char) 0; 
1176         // maybe setgray here ? 
1177         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1179             double redPS 
= (double)(red
) / 255.0; 
1180             double bluePS 
= (double)(blue
) / 255.0; 
1181             double greenPS 
= (double)(green
) / 255.0; 
1185                 "%.8f %.8f %.8f setrgbcolor\n", 
1186                 redPS
, greenPS
, bluePS 
); 
1187             for (size_t i 
= 0; i 
< strlen(buffer
); i
++) 
1188                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1192             m_currentBlue 
= blue
; 
1193             m_currentGreen 
= green
; 
1197     wxCoord text_w
, text_h
, text_descent
; 
1199     GetTextExtent(text
, &text_w
, &text_h
, &text_descent
); 
1201     // VZ: this seems to be unnecessary, so taking it out for now, if it 
1202     //     doesn't create any problems, remove this comment entirely 
1203     //SetFont( m_font ); 
1206     int size 
= m_font
.GetPointSize(); 
1208 //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline 
1209 //    commented by V. Slavik and replaced by accurate version 
1210 //        - note that there is still rounding error in text_descent! 
1211     wxCoord by 
= y 
+ size 
- text_descent
; // baseline 
1213     PsPrintf( wxT("%d %d moveto\n"), LogicalToDeviceX(x
), LogicalToDeviceY(by
) ); 
1216     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1217     size_t len 
= strlen(textbuf
); 
1219     for (i 
= 0; i 
< len
; i
++) 
1221         int c 
= (unsigned char) textbuf
[i
]; 
1222         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1224             /* Cope with special characters */ 
1228         else if ( c 
>= 128 ) 
1230             /* Cope with character codes > 127 */ 
1231             PsPrintf( wxT("\\%o"), c
); 
1239     PsPrint( ") show\n" ); 
1241     if (m_font
.GetUnderlined()) 
1243         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1253                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1254                 m_underlineThickness
, 
1255                 LogicalToDeviceX(x 
+ text_w
), LogicalToDeviceY(uy
) ); 
1256         for (i 
= 0; i 
< 100; i
++) 
1257             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1261     CalcBoundingBox( x
, y 
); 
1262     CalcBoundingBox( x 
+ size 
* text
.length() * 2/3 , y 
); 
1265 void wxPostScriptDC::DoDrawRotatedText( const wxString
& text
, wxCoord x
, wxCoord y
, double angle 
) 
1267     if ( wxIsNullDouble(angle
) ) 
1269         DoDrawText(text
, x
, y
); 
1273     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1277     if (m_textForegroundColour
.Ok()) 
1279         unsigned char red 
= m_textForegroundColour
.Red(); 
1280         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1281         unsigned char green 
= m_textForegroundColour
.Green(); 
1285             // Anything not white is black 
1286             if (! (red 
== (unsigned char) 255 && 
1287                    blue 
== (unsigned char) 255 && 
1288                    green 
== (unsigned char) 255)) 
1290                 red 
= (unsigned char) 0; 
1291                 green 
= (unsigned char) 0; 
1292                 blue 
= (unsigned char) 0; 
1296         // maybe setgray here ? 
1297         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1299             double redPS 
= (double)(red
) / 255.0; 
1300             double bluePS 
= (double)(blue
) / 255.0; 
1301             double greenPS 
= (double)(green
) / 255.0; 
1305                 "%.8f %.8f %.8f setrgbcolor\n", 
1306                 redPS
, greenPS
, bluePS 
); 
1307             for (int i 
= 0; i 
< 100; i
++) 
1308                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1312             m_currentBlue 
= blue
; 
1313             m_currentGreen 
= green
; 
1317     int size 
= m_font
.GetPointSize(); 
1319     PsPrintf( wxT("%d %d moveto\n"), 
1320             LogicalToDeviceX(x
), LogicalToDeviceY(y
)); 
1323     sprintf(buffer
, "%.8f rotate\n", angle
); 
1325     for (i 
= 0; i 
< 100; i
++) 
1327         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1332     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1333     size_t len 
= strlen(textbuf
); 
1334     for (i 
= 0; i 
< len
; i
++) 
1336         int c 
= (unsigned char) textbuf
[i
]; 
1337         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1339             /* Cope with special characters */ 
1343         else if ( c 
>= 128 ) 
1345             /* Cope with character codes > 127 */ 
1346             PsPrintf( wxT("\\%o"), c
); 
1354     PsPrint( ") show\n" ); 
1356     sprintf( buffer
, "%.8f rotate\n", -angle 
); 
1357     for (i 
= 0; i 
< 100; i
++) 
1359         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1363     if (m_font
.GetUnderlined()) 
1365         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1367         GetTextExtent(text
, &w
, &h
); 
1376                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1377                 m_underlineThickness
, 
1378                 LogicalToDeviceX(x 
+ w
), LogicalToDeviceY(uy
) ); 
1379         for (i 
= 0; i 
< 100; i
++) 
1381             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1386     CalcBoundingBox( x
, y 
); 
1387     CalcBoundingBox( x 
+ size 
* text
.length() * 2/3 , y 
); 
1390 void wxPostScriptDC::SetBackground (const wxBrush
& brush
) 
1392     m_backgroundBrush 
= brush
; 
1395 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function
)) 
1397     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); 
1401 void wxPostScriptDC::DoDrawSpline( wxList 
*points 
) 
1403     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1407     // a and b are not used 
1409     double c
, d
, x1
, y1
, x2
, y2
, x3
, y3
; 
1412     wxList::compatibility_iterator node 
= points
->GetFirst(); 
1413     p 
= (wxPoint 
*)node
->GetData(); 
1417     node 
= node
->GetNext(); 
1418     p 
= (wxPoint 
*)node
->GetData(); 
1425          (double)(x1 
+ c
) / 2; 
1430          (double)(y1 
+ d
) / 2; 
1432     PsPrintf( wxT("newpath\n") 
1433               wxT("%d %d moveto\n") 
1434               wxT("%d %d lineto\n"), 
1435             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1436             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1438     CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1439     CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1441     node 
= node
->GetNext(); 
1444         q 
= (wxPoint 
*)node
->GetData(); 
1452         x3 
= (double)(x2 
+ c
) / 2; 
1453         y3 
= (double)(y2 
+ d
) / 2; 
1455         PsPrintf( wxT("%d %d %d %d %d %d DrawSplineSection\n"), 
1456             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1457             LogicalToDeviceX((wxCoord
)x2
), LogicalToDeviceY((wxCoord
)y2
), 
1458             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1460         CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1461         CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1463         node 
= node
->GetNext(); 
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 
1471     PsPrintf( wxT("%d %d lineto\n") 
1473             LogicalToDeviceX((wxCoord
)c
), LogicalToDeviceY((wxCoord
)d
) ); 
1475 #endif // wxUSE_SPLINES 
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
, wxT("invalid postscript dc") ); 
1488     m_signX 
= (xLeftRight 
? 1 : -1); 
1489     m_signY 
= (yBottomUp  
? 1 : -1); 
1491     ComputeScaleAndOrigin(); 
1494 void wxPostScriptDC::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
1496     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1502     wxDC::SetDeviceOrigin( x
, h
-y 
); 
1505 void wxPostScriptDC::DoGetSize(int* width
, int* height
) const 
1507     wxPaperSize id 
= m_printData
.GetPaperId(); 
1509     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1511     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1517         w 
= paper
->GetSizeDeviceUnits().x
; 
1518         h 
= paper
->GetSizeDeviceUnits().y
; 
1521     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1528     if (width
) *width 
= (int)(w 
* ms_PSScaleFactor
); 
1529     if (height
) *height 
= (int)(h 
* ms_PSScaleFactor
); 
1532 void wxPostScriptDC::DoGetSizeMM(int *width
, int *height
) const 
1534     wxPaperSize id 
= m_printData
.GetPaperId(); 
1536     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1538     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1544         w 
= paper
->GetWidth() / 10; 
1545         h 
= paper
->GetHeight() / 10; 
1548     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1555     if (width
) *width 
= w
; 
1556     if (height
) *height 
= h
; 
1559 // Resolution in pixels per logical inch 
1560 wxSize 
wxPostScriptDC::GetPPI(void) const 
1562     return wxSize((int)(72 * ms_PSScaleFactor
), 
1563                   (int)(72 * ms_PSScaleFactor
)); 
1567 bool wxPostScriptDC::StartDoc( const wxString
& message 
) 
1569     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1571     if (m_printData
.GetPrintMode() != wxPRINT_MODE_STREAM 
) 
1573         if (m_printData
.GetFilename() == wxEmptyString
) 
1575             wxString filename 
= wxGetTempFileName( wxT("ps") ); 
1576             m_printData
.SetFilename(filename
); 
1579         m_pstream 
= wxFopen( m_printData
.GetFilename(), wxT("w+") ); 
1583             wxLogError( _("Cannot open file for PostScript printing!")); 
1592     PsPrint( "%!PS-Adobe-2.0\n" ); 
1593     PsPrintf( wxT("%%%%Title: %s\n"), m_title
.c_str() ); 
1594     PsPrint( "%%Creator: wxWidgets PostScript renderer\n" ); 
1595     PsPrintf( wxT("%%%%CreationDate: %s\n"), wxNow().c_str() ); 
1596     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1597         PsPrint( "%%Orientation: Landscape\n" ); 
1599         PsPrint( "%%Orientation: Portrait\n" ); 
1601     // PsPrintf( wxT("%%%%Pages: %d\n"), (wxPageNumber - 1) ); 
1603     const wxChar 
*paper
; 
1604     switch (m_printData
.GetPaperId()) 
1606        case wxPAPER_LETTER
: paper 
= wxT("Letter"); break;       // Letter: paper ""; 8 1/2 by 11 inches 
1607        case wxPAPER_LEGAL
: paper 
= wxT("Legal"); break;         // Legal, 8 1/2 by 14 inches 
1608        case wxPAPER_A4
: paper 
= wxT("A4"); break;               // A4 Sheet, 210 by 297 millimeters 
1609        case wxPAPER_TABLOID
: paper 
= wxT("Tabloid"); break;     // Tabloid, 11 by 17 inches 
1610        case wxPAPER_LEDGER
: paper 
= wxT("Ledger"); break;       // Ledger, 17 by 11 inches 
1611        case wxPAPER_STATEMENT
: paper 
= wxT("Statement"); break; // Statement, 5 1/2 by 8 1/2 inches 
1612        case wxPAPER_EXECUTIVE
: paper 
= wxT("Executive"); break; // Executive, 7 1/4 by 10 1/2 inches 
1613        case wxPAPER_A3
: paper 
= wxT("A3"); break;               // A3 sheet, 297 by 420 millimeters 
1614        case wxPAPER_A5
: paper 
= wxT("A5"); break;               // A5 sheet, 148 by 210 millimeters 
1615        case wxPAPER_B4
: paper 
= wxT("B4"); break;               // B4 sheet, 250 by 354 millimeters 
1616        case wxPAPER_B5
: paper 
= wxT("B5"); break;               // B5 sheet, 182-by-257-millimeter paper 
1617        case wxPAPER_FOLIO
: paper 
= wxT("Folio"); break;         // Folio, 8-1/2-by-13-inch paper 
1618        case wxPAPER_QUARTO
: paper 
= wxT("Quaro"); break;        // Quarto, 215-by-275-millimeter paper 
1619        case wxPAPER_10X14
: paper 
= wxT("10x14"); break;         // 10-by-14-inch sheet 
1620        default: paper 
= wxT("A4"); 
1622     PsPrintf( wxT("%%%%DocumentPaperSizes: %s\n"), paper 
); 
1623     PsPrint( "%%EndComments\n\n" ); 
1625     PsPrint( "%%BeginProlog\n" ); 
1626     PsPrint( wxPostScriptHeaderConicTo 
); 
1627     PsPrint( wxPostScriptHeaderEllipse 
); 
1628     PsPrint( wxPostScriptHeaderEllipticArc 
); 
1629     PsPrint( wxPostScriptHeaderColourImage 
); 
1630     PsPrint( wxPostScriptHeaderReencodeISO1 
); 
1631     PsPrint( wxPostScriptHeaderReencodeISO2 
); 
1632     if (wxPostScriptHeaderSpline
) 
1633         PsPrint( wxPostScriptHeaderSpline 
); 
1634     PsPrint( "%%EndProlog\n" ); 
1636     SetBrush( *wxBLACK_BRUSH 
); 
1637     SetPen( *wxBLACK_PEN 
); 
1638     SetBackground( *wxWHITE_BRUSH 
); 
1639     SetTextForeground( *wxBLACK 
); 
1641     // set origin according to paper size 
1642     SetDeviceOrigin( 0,0 ); 
1649 void wxPostScriptDC::EndDoc () 
1651     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1656         PsPrint( "grestore\n" ); 
1660         fclose( m_pstream 
); 
1661         m_pstream 
= (FILE *) NULL
; 
1665     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com> 
1666     wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
1667     double wx_printer_scale_x
, wx_printer_scale_y
; 
1669     wx_printer_translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1670     wx_printer_translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1672     wx_printer_scale_x 
= m_printData
.GetPrinterScaleX(); 
1673     wx_printer_scale_y 
= m_printData
.GetPrinterScaleY(); 
1675     // Compute the bounding box.  Note that it is in the default user 
1676     // coordinate system, thus we have to convert the values. 
1677     wxCoord minX 
= (wxCoord
) LogicalToDeviceX(m_minX
); 
1678     wxCoord minY 
= (wxCoord
) LogicalToDeviceY(m_minY
); 
1679     wxCoord maxX 
= (wxCoord
) LogicalToDeviceX(m_maxX
); 
1680     wxCoord maxY 
= (wxCoord
) LogicalToDeviceY(m_maxY
); 
1682     // LOG2DEV may have changed the minimum to maximum vice versa 
1683     if ( minX 
> maxX 
) { wxCoord tmp 
= minX
; minX 
= maxX
; maxX 
= tmp
; } 
1684     if ( minY 
> maxY 
) { wxCoord tmp 
= minY
; minY 
= maxY
; maxY 
= tmp
; } 
1686     // account for used scaling (boundingbox is before scaling in ps-file) 
1687     double scale_x 
= m_printData
.GetPrinterScaleX() / ms_PSScaleFactor
; 
1688     double scale_y 
= m_printData
.GetPrinterScaleY() / ms_PSScaleFactor
; 
1690     wxCoord llx
, lly
, urx
, ury
; 
1691     llx 
= (wxCoord
) ((minX
+wx_printer_translate_x
)*scale_x
); 
1692     lly 
= (wxCoord
) ((minY
+wx_printer_translate_y
)*scale_y
); 
1693     urx 
= (wxCoord
) ((maxX
+wx_printer_translate_x
)*scale_x
); 
1694     ury 
= (wxCoord
) ((maxY
+wx_printer_translate_y
)*scale_y
); 
1695     // (end of bounding box computation) 
1698     // If we're landscape, our sense of "x" and "y" is reversed. 
1699     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1702         tmp 
= llx
; llx 
= lly
; lly 
= tmp
; 
1703         tmp 
= urx
; urx 
= ury
; ury 
= tmp
; 
1705         // We need either the two lines that follow, or we need to subtract 
1706         // min_x from real_translate_y, which is commented out below. 
1707         llx 
= llx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1708         urx 
= urx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1711     // The Adobe specifications call for integers; we round as to make 
1712     // the bounding larger. 
1713     PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"), 
1714             (wxCoord
)floor((double)llx
), (wxCoord
)floor((double)lly
), 
1715             (wxCoord
)ceil((double)urx
), (wxCoord
)ceil((double)ury
) ); 
1717     // To check the correctness of the bounding box, postscript commands 
1718     // to draw a box corresponding to the bounding box are generated below. 
1719     // But since we typically don't want to print such a box, the postscript 
1720     // commands are generated within comments.  These lines appear before any 
1721     // adjustment of scale, rotation, or translation, and hence are in the 
1722     // default user coordinates. 
1723     PsPrint( "% newpath\n" ); 
1724     PsPrintf( wxT("%% %d %d moveto\n"), llx
, lly 
); 
1725     PsPrintf( wxT("%% %d %d lineto\n"), urx
, lly 
); 
1726     PsPrintf( wxT("%% %d %d lineto\n"), urx
, ury 
); 
1727     PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx
, ury 
); 
1731     wxPostScriptPrintNativeData 
*data 
= 
1732         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1734     if (m_ok 
&& (m_printData
.GetPrintMode() == wxPRINT_MODE_PRINTER
)) 
1737         command 
+= data
->GetPrinterCommand(); 
1738         command 
+= wxT(" "); 
1739         command 
+= data
->GetPrinterOptions(); 
1740         command 
+= wxT(" "); 
1741         command 
+= m_printData
.GetFilename(); 
1743         wxExecute( command
, true ); 
1744         wxRemoveFile( m_printData
.GetFilename() ); 
1749 void wxPostScriptDC::StartPage() 
1751     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1753     PsPrintf( wxT("%%%%Page: %d\n"), wxPageNumber
++ ); 
1755     //  What is this one supposed to do? RR. 
1756 //  *m_pstream << "matrix currentmatrix\n"; 
1758     // Added by Chris Breeze 
1760     // Each page starts with an "initgraphics" which resets the 
1761     // transformation and so we need to reset the origin 
1762     // (and rotate the page for landscape printing) 
1765     wxCoord translate_x
, translate_y
; 
1766     double scale_x
, scale_y
; 
1768     wxPostScriptPrintNativeData 
*data 
= 
1769         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1771     translate_x 
= (wxCoord
)data
->GetPrinterTranslateX(); 
1772     translate_y 
= (wxCoord
)data
->GetPrinterTranslateY(); 
1774     scale_x 
= data
->GetPrinterScaleX(); 
1775     scale_y 
= data
->GetPrinterScaleY(); 
1777     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1780         GetSize( (int*) NULL
, &h 
); 
1782         PsPrint( "90 rotate\n" ); 
1783         // I copied this one from a PostScript tutorial, but to no avail. RR. 
1784         // PsPrint( "90 rotate llx neg ury nef translate\n" ); 
1788     sprintf( buffer
, "%.8f %.8f scale\n", scale_x 
/ ms_PSScaleFactor
, 
1789             scale_y 
/ ms_PSScaleFactor
); 
1790     for (int i 
= 0; i 
< 100; i
++) 
1791         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1794     PsPrintf( wxT("%d %d translate\n"), translate_x
, translate_y 
); 
1797 void wxPostScriptDC::EndPage () 
1799     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
1801     PsPrint( "showpage\n" ); 
1804 bool wxPostScriptDC::DoBlit( wxCoord xdest
, wxCoord ydest
, 
1805                            wxCoord fwidth
, wxCoord fheight
, 
1807                            wxCoord xsrc
, wxCoord ysrc
, 
1808                            int rop
, bool WXUNUSED(useMask
), wxCoord 
WXUNUSED(xsrcMask
), wxCoord 
WXUNUSED(ysrcMask
) ) 
1810     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1812     wxCHECK_MSG( source
, false, wxT("invalid source dc") ); 
1814     /* blit into a bitmap */ 
1815     wxBitmap 
bitmap( (int)fwidth
, (int)fheight 
); 
1817     memDC
.SelectObject(bitmap
); 
1818     memDC
.Blit(0, 0, fwidth
, fheight
, source
, xsrc
, ysrc
, rop
); /* TODO: Blit transparently? */ 
1819     memDC
.SelectObject(wxNullBitmap
); 
1821     /* draw bitmap. scaling and positioning is done there */ 
1822     DrawBitmap( bitmap
, xdest
, ydest 
); 
1827 wxCoord 
wxPostScriptDC::GetCharHeight() const 
1830         return m_font
.GetPointSize(); 
1835 void wxPostScriptDC::DoGetTextExtent(const wxString
& string
, 
1836                                      wxCoord 
*x
, wxCoord 
*y
, 
1837                                      wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1838                                      wxFont 
*theFont 
) const 
1840     wxFont 
*fontToUse 
= theFont
; 
1842     if (!fontToUse
) fontToUse 
= (wxFont
*) &m_font
; 
1844     wxCHECK_RET( fontToUse
, wxT("GetTextExtent: no font defined") ); 
1850         if (descent
) (*descent
) = 0; 
1851         if (externalLeading
) (*externalLeading
) = 0; 
1857     const wxWX2MBbuf strbuf 
= string
.mb_str(); 
1859 #if !wxUSE_AFM_FOR_POSTSCRIPT 
1860     /* Provide a VERY rough estimate (avoid using it). 
1861      * Produces accurate results for mono-spaced font 
1862      * such as Courier (aka wxMODERN) */ 
1867         height 
= fontToUse
->GetPointSize(); 
1870         *x 
= strlen (strbuf
) * height 
* 72 / 120; 
1872         *y 
= (wxCoord
) (height 
* 1.32);    /* allow for descender */ 
1873     if (descent
) *descent 
= 0; 
1874     if (externalLeading
) *externalLeading 
= 0; 
1877     /* method for calculating string widths in postscript: 
1878     /  read in the AFM (adobe font metrics) file for the 
1879     /  actual font, parse it and extract the character widths 
1880     /  and also the descender. this may be improved, but for now 
1881     /  it works well. the AFM file is only read in if the 
1882     /  font is changed. this may be chached in the future. 
1883     /  calls to GetTextExtent with the font unchanged are rather 
1886     /  for each font and style used there is an AFM file necessary. 
1887     /  currently i have only files for the roman font family. 
1888     /  I try to get files for the other ones! 
1890     /  CAVE: the size of the string is currently always calculated 
1891     /        in 'points' (1/72 of an inch). this should later on be 
1892     /        changed to depend on the mapping mode. 
1893     /  CAVE: the path to the AFM files must be set before calling this 
1894     /        function. this is usually done by a call like the following: 
1895     /        wxSetAFMPath("d:\\wxw161\\afm\\"); 
1899     /    wxPostScriptDC dc(NULL, true); 
1901     /      wxSetAFMPath("d:\\wxw161\\afm\\"); 
1902     /      dc.StartDoc("Test"); 
1905     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); 
1906     /      dc.GetTextExtent("Hallo",&w,&h); 
1911     /  by steve (stefan.hammes@urz.uni-heidelberg.de) 
1913     /  updated: 14.05.95 */ 
1915     /* these static vars are for storing the state between calls */ 
1916     static int lastFamily
= INT_MIN
; 
1917     static int lastSize
= INT_MIN
; 
1918     static int lastStyle
= INT_MIN
; 
1919     static int lastWeight
= INT_MIN
; 
1920     static int lastDescender 
= INT_MIN
; 
1921     static int lastWidths
[256]; /* widths of the characters */ 
1923     double UnderlinePosition 
= 0.0; 
1924     double UnderlineThickness 
= 0.0; 
1926     // Get actual parameters 
1927     int Family 
= fontToUse
->GetFamily(); 
1928     int Size 
=   fontToUse
->GetPointSize(); 
1929     int Style 
=  fontToUse
->GetStyle(); 
1930     int Weight 
= fontToUse
->GetWeight(); 
1932     // If we have another font, read the font-metrics 
1933     if (Family
!=lastFamily 
|| Size
!=lastSize 
|| Style
!=lastStyle 
|| Weight
!=lastWeight
) 
1935         // Store actual values 
1936         lastFamily 
= Family
; 
1939         lastWeight 
= Weight
; 
1948                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBoO.afm"); 
1949                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBo.afm"); 
1950                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("CourO.afm"); 
1951                 else name 
= wxT("Cour.afm"); 
1956                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBoO.afm"); 
1957                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBo.afm"); 
1958                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("TimesO.afm"); 
1959                 else name 
= wxT("TimesRo.afm"); 
1964                 name 
= wxT("Zapf.afm"); 
1970                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBoO.afm"); 
1971                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBo.afm"); 
1972                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("HelvO.afm"); 
1973                 else name 
= wxT("Helv.afm"); 
1978         FILE *afmFile 
= NULL
; 
1980         // Get the directory of the AFM files 
1983         // VZ: I don't know if the cast always works under Unix but it clearly 
1984         //     never does under Windows where the pointer is 
1985         //     wxWindowsPrintNativeData and so calling GetFontMetricPath() on 
1988         wxPostScriptPrintNativeData 
*data 
= 
1989             wxDynamicCast(m_printData
.GetNativeData(), wxPostScriptPrintNativeData
); 
1991         if (data 
&& !data
->GetFontMetricPath().empty()) 
1993             afmName 
= data
->GetFontMetricPath(); 
1994             afmName 
<< wxFILE_SEP_PATH 
<< name
; 
1998         if ( !afmName
.empty() ) 
1999             afmFile 
= wxFopen(afmName
, wxT("r")); 
2003 #if defined(__UNIX__) && !defined(__VMS__) 
2004            afmName 
= wxGetDataDir(); 
2006            afmName 
= wxStandardPaths::Get().GetDataDir(); 
2007 #endif // __UNIX__/!__UNIX__ 
2009            afmName 
<<  wxFILE_SEP_PATH
 
2010 #if defined(__LINUX__) || defined(__FREEBSD__) 
2011                    << wxT("gs_afm") << wxFILE_SEP_PATH
 
2013                    << wxT("afm") << wxFILE_SEP_PATH
 
2016            afmFile 
= wxFopen(afmName
,wxT("r")); 
2019         /* 2. open and process the file 
2020            /  a short explanation of the AFM format: 
2021            /  we have for each character a line, which gives its size 
2024            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; 
2026            /  that means, we have a character with ascii code 63, and width 
2027            /  (444/1000 * fontSize) points. 
2028            /  the other data is ignored for now! 
2030            /  when the font has changed, we read in the right AFM file and store the 
2031            /  character widths in an array, which is processed below (see point 3.). */ 
2034             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName
.c_str() ); 
2035             wxLogDebug( wxT("               using approximate values")); 
2036             for (int i
=0; i
<256; i
++) lastWidths
[i
] = 500; /* an approximate value */ 
2037             lastDescender 
= -150; /* dito. */ 
2041             /* init the widths array */ 
2042             for(int i
=0; i
<256; i
++) lastWidths
[i
] = INT_MIN
; 
2043             /* some variables for holding parts of a line */ 
2044             char cString
[10], semiString
[10], WXString
[10]; 
2045             char descString
[20]; 
2046             char upString
[30], utString
[30]; 
2050             /* read in the file and parse it */ 
2051             while(fgets(line
,sizeof(line
),afmFile
)!=NULL
) 
2053                 /* A.) check for descender definition */ 
2054                 if (strncmp(line
,"Descender",9)==0) 
2056                     if ((sscanf(line
,"%s%d",descString
,&lastDescender
)!=2) || 
2057                             (strcmp(descString
,"Descender")!=0)) 
2059                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName
.c_str(),line 
); 
2062                 /* JC 1.) check for UnderlinePosition */ 
2063                 else if(strncmp(line
,"UnderlinePosition",17)==0) 
2065                     if ((sscanf(line
,"%s%lf",upString
,&UnderlinePosition
)!=2) || 
2066                             (strcmp(upString
,"UnderlinePosition")!=0)) 
2068                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName
.c_str(), line 
); 
2071                 /* JC 2.) check for UnderlineThickness */ 
2072                 else if(strncmp(line
,"UnderlineThickness",18)==0) 
2074                     if ((sscanf(line
,"%s%lf",utString
,&UnderlineThickness
)!=2) || 
2075                             (strcmp(utString
,"UnderlineThickness")!=0)) 
2077                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName
.c_str(), line 
); 
2080                 /* JC 3.) check for EncodingScheme */ 
2081                 else if(strncmp(line
,"EncodingScheme",14)==0) 
2083                     if ((sscanf(line
,"%s%s",utString
,encString
)!=2) || 
2084                             (strcmp(utString
,"EncodingScheme")!=0)) 
2086                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName
.c_str(), line 
); 
2088                     else if (strncmp(encString
, "AdobeStandardEncoding", 21)) 
2090                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"), 
2091                                 afmName
.c_str(),line
, encString
); 
2094                 /* B.) check for char-width */ 
2095                 else if(strncmp(line
,"C ",2)==0) 
2097                     if (sscanf(line
,"%s%d%s%s%d",cString
,&ascii
,semiString
,WXString
,&cWidth
)!=5) 
2099                         wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName
.c_str(),line
); 
2101                     if(strcmp(cString
,"C")!=0 || strcmp(semiString
,";")!=0 || strcmp(WXString
,"WX")!=0) 
2103                         wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName
.c_str(),line
); 
2105                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ 
2106                     if (ascii
>=0 && ascii
<256) 
2108                         lastWidths
[ascii
] = cWidth
; /* store width */ 
2112                         /* MATTHEW: this happens a lot; don't print an error */ 
2113                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ 
2116                 /* C.) ignore other entries. */ 
2120         /* hack to compute correct values for german 'Umlaute' 
2121            /  the correct way would be to map the character names 
2122            /  like 'adieresis' to corresp. positions of ISOEnc and read 
2123            /  these values from AFM files, too. Maybe later ... */ 
2125         // NB: casts to int are needed to suppress gcc 3.3 warnings 
2126         lastWidths
[196] = lastWidths
[(int)'A'];  // Ä 
2127         lastWidths
[228] = lastWidths
[(int)'a'];  // ä 
2128         lastWidths
[214] = lastWidths
[(int)'O'];  // Ö 
2129         lastWidths
[246] = lastWidths
[(int)'o'];  // ö 
2130         lastWidths
[220] = lastWidths
[(int)'U'];  // Ü 
2131         lastWidths
[252] = lastWidths
[(int)'u'];  // ü 
2132         lastWidths
[223] = lastWidths
[(int)251];  // ß 
2134         /* JC: calculate UnderlineThickness/UnderlinePosition */ 
2136         // VS: dirty, but is there any better solution? 
2138         pt 
= (double*) &m_underlinePosition
; 
2139         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlinePosition 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2140         pt 
= (double*) &m_underlineThickness
; 
2141         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlineThickness 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2146     /* 3. now the font metrics are read in, calc size this 
2147        /  is done by adding the widths of the characters in the 
2148        /  string. they are given in 1/1000 of the size! */ 
2151     wxCoord height
=Size
; /* by default */ 
2153     for(p
=(unsigned char *)wxMBSTRINGCAST strbuf
; *p
; p
++) 
2155         if(lastWidths
[*p
]== INT_MIN
) 
2157             wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p
,*p
); 
2158             sum 
+= lastWidths
[(unsigned char)' ']; /* assume space */ 
2162             sum 
+= lastWidths
[*p
]; 
2166     double widthSum 
= sum
; 
2168     widthSum 
/= 1000.0F
; 
2170     /* add descender to height (it is usually a negative value) */ 
2171     //if (lastDescender != INT_MIN) 
2173     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ 
2175     // - commented by V. Slavik - height already contains descender in it 
2176     //   (judging from few experiments) 
2178     /* return size values */ 
2180         *x 
= (wxCoord
)widthSum
; 
2184     /* return other parameters */ 
2187         if(lastDescender
!=INT_MIN
) 
2189             *descent 
= (wxCoord
)(((-lastDescender
)/1000.0F
) * Size
); /* MATTHEW: forgot scale */ 
2197     /* currently no idea how to calculate this! */ 
2198     if (externalLeading
) *externalLeading 
= 0; 
2203 // print postscript datas via required method (file, stream) 
2204 void wxPostScriptDC::PsPrintf( const wxChar
* fmt
, ... ) 
2207     va_start(argptr
, fmt
); 
2209     PsPrint( wxString::FormatV( fmt
, argptr 
).c_str() ); 
2212 void wxPostScriptDC::PsPrint( const char* psdata 
) 
2214     wxPostScriptPrintNativeData 
*data 
= 
2215         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2217     switch (m_printData
.GetPrintMode()) 
2220         // append to output stream 
2221         case wxPRINT_MODE_STREAM
: 
2223                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2224                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2225                 outputstream
->Write( psdata
, strlen( psdata 
) ); 
2228 #endif // wxUSE_STREAMS 
2230         // save data into file 
2232             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2233             fwrite( psdata
, 1, strlen( psdata 
), m_pstream 
); 
2237 void wxPostScriptDC::PsPrint( int ch 
) 
2239     wxPostScriptPrintNativeData 
*data 
= 
2240         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2242     switch (m_printData
.GetPrintMode()) 
2245         // append to output stream 
2246         case wxPRINT_MODE_STREAM
: 
2248                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2249                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2250                 outputstream
->PutC( (char)ch 
); 
2253 #endif // wxUSE_STREAMS 
2255         // save data into file 
2257             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2258             fputc( ch
, m_pstream 
); 
2262 #endif // wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT