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" 
  21 #if wxUSE_PRINTING_ARCHITECTURE 
  25 #include "wx/dcmemory.h" 
  31 #include "wx/generic/dcpsg.h" 
  32 #include "wx/prntbase.h" 
  33 #include "wx/generic/prntdlgg.h" 
  35 #include "wx/filefn.h" 
  37 #include "wx/stdpaths.h" 
  59 //----------------------------------------------------------------------------- 
  60 // start and end of document/page 
  61 //----------------------------------------------------------------------------- 
  63 static const char *wxPostScriptHeaderConicTo 
= "\ 
  67     /conic_cntrl_y exch def\n\ 
  68     /conic_cntrl_x exch def\n\ 
  72     /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\ 
  73     /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\ 
  74     /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\ 
  75     /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\ 
  76     p1_x p1_y p2_x p2_y to_x to_y curveto\n\ 
  80 static const char *wxPostScriptHeaderEllipse 
= "\ 
  81 /ellipsedict 8 dict def\n\ 
  82 ellipsedict /mtrx matrix put\n\ 
  86     /startangle exch def\n\ 
  91     /savematrix mtrx currentmatrix def\n\ 
  94     0 0 1 startangle endangle arc\n\ 
  95     savematrix setmatrix\n\ 
 100 static const char *wxPostScriptHeaderEllipticArc
= "\ 
 101 /ellipticarcdict 8 dict def\n\ 
 102 ellipticarcdict /mtrx matrix put\n\ 
 104 { ellipticarcdict begin\n\ 
 106   /endangle exch def\n\ 
 107   /startangle exch def\n\ 
 112   /savematrix mtrx currentmatrix def\n\ 
 115   do_fill { 0 0 moveto } if\n\ 
 116   0 0 1 startangle endangle arc\n\ 
 117   savematrix setmatrix\n\ 
 118   do_fill { fill }{ stroke } ifelse\n\ 
 122 static const char *wxPostScriptHeaderSpline 
= "\ 
 123 /DrawSplineSection {\n\ 
 130     /xa x1 x2 x1 sub 0.666667 mul add def\n\ 
 131     /ya y1 y2 y1 sub 0.666667 mul add def\n\ 
 132     /xb x3 x2 x3 sub 0.666667 mul add def\n\ 
 133     /yb y3 y2 y3 sub 0.666667 mul add def\n\ 
 135     xa ya xb yb x3 y3 curveto\n\ 
 139 static const char *wxPostScriptHeaderColourImage 
= "\ 
 140 % define 'colorimage' if it isn't defined\n\ 
 141 %   ('colortogray' and 'mergeprocs' come from xwd2ps\n\ 
 143 /colorimage where   % do we know about 'colorimage'?\n\ 
 144   { pop }           % yes: pop off the 'dict' returned\n\ 
 145   {                 % no:  define one\n\ 
 146     /colortogray {  % define an RGB->I function\n\ 
 147       /rgbdata exch store    % call input 'rgbdata'\n\ 
 148       rgbdata length 3 idiv\n\ 
 149       /npixls exch store\n\ 
 151       0 1 npixls 1 sub {\n\ 
 153         rgbdata rgbindx       get 20 mul    % Red\n\ 
 154         rgbdata rgbindx 1 add get 32 mul    % Green\n\ 
 155         rgbdata rgbindx 2 add get 12 mul    % Blue\n\ 
 156         add add 64 idiv      % I = .5G + .31R + .18B\n\ 
 158         /rgbindx rgbindx 3 add store\n\ 
 160       grays 0 npixls getinterval\n\ 
 163     % Utility procedure for colorimage operator.\n\ 
 164     % This procedure takes two procedures off the\n\ 
 165     % stack and merges them into a single procedure.\n\ 
 167     /mergeprocs { % def\n\ 
 186     /colorimage { % def\n\ 
 187       pop pop     % remove 'false 3' operands\n\ 
 188       {colortogray} mergeprocs\n\ 
 191   } ifelse          % end of 'false' case\n\ 
 194 static char wxPostScriptHeaderReencodeISO1
[] = 
 196 "dup dup findfont dup length dict begin\n" 
 197 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" 
 198 "/Encoding ISOLatin1Encoding def\n" 
 199 "currentdict end definefont\n" 
 201 "/ISOLatin1Encoding [\n" 
 202 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\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 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" 
 207 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" 
 208 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" 
 209 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" 
 210 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" 
 211 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" 
 212 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" 
 213 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 214 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" 
 215 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" 
 216 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; 
 218 static char wxPostScriptHeaderReencodeISO2
[] = 
 219 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" 
 220 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" 
 221 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" 
 222 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" 
 223 "/guillemotright/onequarter/onehalf/threequarters/questiondown\n" 
 224 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" 
 225 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" 
 226 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" 
 227 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" 
 228 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" 
 229 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" 
 230 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" 
 231 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" 
 232 "/yacute/thorn/ydieresis\n" 
 235 //------------------------------------------------------------------------------- 
 237 //------------------------------------------------------------------------------- 
 239 IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC
, wxDC
) 
 241 float wxPostScriptDC::ms_PSScaleFactor 
= 1.0; 
 243 void wxPostScriptDC::SetResolution(int ppi
) 
 245     ms_PSScaleFactor 
= (float)ppi 
/ 72.0; 
 248 int wxPostScriptDC::GetResolution() 
 250     return (int)(ms_PSScaleFactor 
* 72.0); 
 253 //------------------------------------------------------------------------------- 
 255 wxPostScriptDC::wxPostScriptDC () 
 257     m_pstream 
= (FILE*) NULL
; 
 267     m_underlinePosition 
= 0.0; 
 268     m_underlineThickness 
= 0.0; 
 270     m_signX 
=  1;  // default x-axis left to right 
 271     m_signY 
= -1;  // default y-axis bottom up -> top down 
 274 wxPostScriptDC::wxPostScriptDC (const wxPrintData
& printData
) 
 276     m_pstream 
= (FILE*) NULL
; 
 286     m_underlinePosition 
= 0.0; 
 287     m_underlineThickness 
= 0.0; 
 289     m_signX 
=  1;  // default x-axis left to right 
 290     m_signY 
= -1;  // default y-axis bottom up -> top down 
 292     m_printData 
= printData
; 
 297 wxPostScriptDC::~wxPostScriptDC () 
 302         m_pstream 
= (FILE*) NULL
; 
 306 bool wxPostScriptDC::Ok() const 
 311 void wxPostScriptDC::DoSetClippingRegion (wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 313     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 315     if (m_clipping
) DestroyClippingRegion(); 
 317     wxDC::DoSetClippingRegion(x
, y
, w
, h
); 
 321     PsPrintf( wxT("gsave\n newpath\n") 
 322               wxT("%d %d moveto\n") 
 323               wxT("%d %d lineto\n") 
 324               wxT("%d %d lineto\n") 
 325               wxT("%d %d lineto\n") 
 326               wxT("closepath clip newpath\n"), 
 327             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 328             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
), 
 329             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
+h
), 
 330             LogicalToDeviceX(x
),   LogicalToDeviceY(y
+h
) ); 
 334 void wxPostScriptDC::DestroyClippingRegion() 
 336     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 341         PsPrint( "grestore\n" ); 
 344     wxDC::DestroyClippingRegion(); 
 347 void wxPostScriptDC::Clear() 
 349     // This should fail silently to avoid unnecessary 
 351     //    wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); 
 354 bool wxPostScriptDC::DoFloodFill (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
)) 
 356     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); 
 360 bool wxPostScriptDC::DoGetPixel (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxColour 
* WXUNUSED(col
)) const 
 362     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); 
 366 void wxPostScriptDC::DoCrossHair (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) 
 368     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); 
 371 void wxPostScriptDC::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 373     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 375     if  (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 379     PsPrintf( wxT("newpath\n") 
 380               wxT("%d %d moveto\n") 
 381               wxT("%d %d lineto\n") 
 383             LogicalToDeviceX(x1
), LogicalToDeviceY(y1
), 
 384             LogicalToDeviceX(x2
), LogicalToDeviceY (y2
) ); 
 386     CalcBoundingBox( x1
, y1 
); 
 387     CalcBoundingBox( x2
, y2 
); 
 390 #define RAD2DEG 57.29577951308 
 392 void wxPostScriptDC::DoDrawArc (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 394     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 396     wxCoord dx 
= x1 
- xc
; 
 397     wxCoord dy 
= y1 
- yc
; 
 398     wxCoord radius 
= (wxCoord
) sqrt( (double)(dx
*dx
+dy
*dy
) ); 
 399     double alpha1
, alpha2
; 
 401     if (x1 
== x2 
&& y1 
== y2
) 
 406     else if ( wxIsNullDouble(radius
) ) 
 413         alpha1 
= (x1 
- xc 
== 0) ? 
 414             (y1 
- yc 
< 0) ? 90.0 : -90.0 : 
 415                 -atan2(double(y1
-yc
), double(x1
-xc
)) * RAD2DEG
; 
 416         alpha2 
= (x2 
- xc 
== 0) ? 
 417             (y2 
- yc 
< 0) ? 90.0 : -90.0 : 
 418                 -atan2(double(y2
-yc
), double(x2
-xc
)) * RAD2DEG
; 
 420     while (alpha1 
<= 0)   alpha1 
+= 360; 
 421     while (alpha2 
<= 0)   alpha2 
+= 360; // adjust angles to be between 
 422     while (alpha1 
> 360)  alpha1 
-= 360; // 0 and 360 degree 
 423     while (alpha2 
> 360)  alpha2 
-= 360; 
 425     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 429         PsPrintf( wxT("newpath\n") 
 430                   wxT("%d %d %d %d %d %d ellipse\n") 
 431                   wxT("%d %d lineto\n") 
 434                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 435                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 437         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 438         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 441     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 445         PsPrintf( wxT("newpath\n") 
 446                   wxT("%d %d %d %d %d %d ellipse\n") 
 447                   wxT("%d %d lineto\n") 
 450                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 451                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 453         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 454         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 458 void wxPostScriptDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 460     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 462     if ( sa 
>= 360 || sa 
<= -360 ) 
 463         sa 
-= int(sa
/360)*360; 
 464     if ( ea 
>= 360 || ea 
<=- 360 ) 
 465         ea 
-= int(ea
/360)*360; 
 471     if ( wxIsSameDouble(sa
, ea
) ) 
 473         DrawEllipse(x
,y
,w
,h
); 
 477     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 481         PsPrintf( wxT("newpath\n") 
 482                   wxT("%d %d %d %d %d %d true ellipticarc\n"), 
 483                   LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 484                   LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 485                   (wxCoord
)sa
, (wxCoord
)ea 
); 
 487         CalcBoundingBox( x 
,y 
); 
 488         CalcBoundingBox( x
+w
, y
+h 
); 
 491     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 495         PsPrintf( wxT("newpath\n") 
 496                   wxT("%d %d %d %d %d %d false ellipticarc\n"), 
 497                 LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 498                 LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 499                 (wxCoord
)sa
, (wxCoord
)ea 
); 
 501         CalcBoundingBox( x 
,y 
); 
 502         CalcBoundingBox( x
+w
, y
+h 
); 
 506 void wxPostScriptDC::DoDrawPoint (wxCoord x
, wxCoord y
) 
 508     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 510     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 514     PsPrintf( wxT("newpath\n") 
 515               wxT("%d %d moveto\n") 
 516               wxT("%d %d lineto\n") 
 518             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 519             LogicalToDeviceX(x
+1), LogicalToDeviceY(y
) ); 
 521     CalcBoundingBox( x
, y 
); 
 524 void wxPostScriptDC::DoDrawPolygon (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 526     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 530     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 534         PsPrint( "newpath\n" ); 
 536         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 537         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 539         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 541         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 543         for (int i 
= 1; i 
< n
; i
++) 
 545             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 546             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 548             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 550             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 553         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 556     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 560         PsPrint( "newpath\n" ); 
 562         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 563         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 565         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 567         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 569         for (int i 
= 1; i 
< n
; i
++) 
 571             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 572             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 574             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 576             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 579         PsPrint( "closepath\n" ); 
 580         PsPrint( "stroke\n" ); 
 584 void wxPostScriptDC::DoDrawPolyPolygon (int n
, int count
[], wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 586     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 590     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 594         PsPrint( "newpath\n" ); 
 597         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 599             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 600             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 602             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 604             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 606             for (int j 
= 1; j 
< count
[i
]; j
++) 
 608                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 609                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 611                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 613                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 616         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 619     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 623         PsPrint( "newpath\n" ); 
 626         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 628             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 629             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 631             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 633             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 635             for (int j 
= 1; j 
< count
[i
]; j
++) 
 637                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 638                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 640                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 642                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 645         PsPrint( "closepath\n" ); 
 646         PsPrint( "stroke\n" ); 
 650 void wxPostScriptDC::DoDrawLines (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 652     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 654     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 661     for ( i 
=0; i
<n 
; i
++ ) 
 663         CalcBoundingBox( LogicalToDeviceX(points
[i
].x
+xoffset
), LogicalToDeviceY(points
[i
].y
+yoffset
)); 
 666     PsPrintf( wxT("newpath\n") 
 667               wxT("%d %d moveto\n"), 
 668               LogicalToDeviceX(points
[0].x
+xoffset
), 
 669               LogicalToDeviceY(points
[0].y
+yoffset
) ); 
 671     for (i 
= 1; i 
< n
; i
++) 
 673         PsPrintf( wxT("%d %d lineto\n"), 
 674                   LogicalToDeviceX(points
[i
].x
+xoffset
), 
 675                   LogicalToDeviceY(points
[i
].y
+yoffset
) ); 
 678     PsPrint( "stroke\n" ); 
 681 void wxPostScriptDC::DoDrawRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 683     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 685     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 689         PsPrintf( wxT("newpath\n") 
 690                   wxT("%d %d moveto\n") 
 691                   wxT("%d %d lineto\n") 
 692                   wxT("%d %d lineto\n") 
 693                   wxT("%d %d lineto\n") 
 696                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 697                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 698                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 699                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 701         CalcBoundingBox( x
, y 
); 
 702         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 705     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 709         PsPrintf( wxT("newpath\n") 
 710                   wxT("%d %d moveto\n") 
 711                   wxT("%d %d lineto\n") 
 712                   wxT("%d %d lineto\n") 
 713                   wxT("%d %d lineto\n") 
 716                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 717                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 718                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 719                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 721         CalcBoundingBox( x
, y 
); 
 722         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 726 void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 728     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 732         // Now, a negative radius is interpreted to mean 
 733         // 'the proportion of the smallest X or Y dimension' 
 734         double smallest 
= width 
< height 
? width 
: height
; 
 735         radius 
=  (-radius 
* smallest
); 
 738     wxCoord rad 
= (wxCoord
) radius
; 
 740     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 744         /* Draw rectangle anticlockwise */ 
 745         PsPrintf( wxT("newpath\n") 
 746                   wxT("%d %d %d 90 180 arc\n") 
 747                   wxT("%d %d lineto\n") 
 748                   wxT("%d %d %d 180 270 arc\n") 
 749                   wxT("%d %d lineto\n") 
 750                   wxT("%d %d %d 270 0 arc\n") 
 751                   wxT("%d %d lineto\n") 
 752                   wxT("%d %d %d 0 90 arc\n") 
 753                   wxT("%d %d lineto\n") 
 756                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 757                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 758                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 759                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 760                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 761                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 762                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 763                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 765         CalcBoundingBox( x
, y 
); 
 766         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 769     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 773         /* Draw rectangle anticlockwise */ 
 774         PsPrintf( wxT("newpath\n") 
 775                   wxT("%d %d %d 90 180 arc\n") 
 776                   wxT("%d %d lineto\n") 
 777                   wxT("%d %d %d 180 270 arc\n") 
 778                   wxT("%d %d lineto\n") 
 779                   wxT("%d %d %d 270 0 arc\n") 
 780                   wxT("%d %d lineto\n") 
 781                   wxT("%d %d %d 0 90 arc\n") 
 782                   wxT("%d %d lineto\n") 
 785                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 786                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 787                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 788                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 789                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 790                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 791                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 792                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 794         CalcBoundingBox( x
, y 
); 
 795         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 799 void wxPostScriptDC::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 801     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 803     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 807         PsPrintf( wxT("newpath\n") 
 808                   wxT("%d %d %d %d 0 360 ellipse\n") 
 810                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 811                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 813         CalcBoundingBox( x 
- width
, y 
- height 
); 
 814         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 817     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 821         PsPrintf( wxT("newpath\n") 
 822                   wxT("%d %d %d %d 0 360 ellipse\n") 
 824                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 825                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 827         CalcBoundingBox( x 
- width
, y 
- height 
); 
 828         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 832 void wxPostScriptDC::DoDrawIcon( const wxIcon
& icon
, wxCoord x
, wxCoord y 
) 
 834     DrawBitmap( icon
, x
, y
, true ); 
 837 /* this has to be char, not wxChar */ 
 838 static char hexArray
[] = "0123456789ABCDEF"; 
 840 void wxPostScriptDC::DoDrawBitmap( const wxBitmap
& bitmap
, wxCoord x
, wxCoord y
, bool WXUNUSED(useMask
) ) 
 842     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 844     if (!bitmap
.Ok()) return; 
 846     wxImage image 
= bitmap
.ConvertToImage(); 
 848     if (!image
.Ok()) return; 
 850     wxCoord w 
= image
.GetWidth(); 
 851     wxCoord h 
= image
.GetHeight(); 
 853     wxCoord ww 
= LogicalToDeviceXRel(image
.GetWidth()); 
 854     wxCoord hh 
= LogicalToDeviceYRel(image
.GetHeight()); 
 856     wxCoord xx 
= LogicalToDeviceX(x
); 
 857     wxCoord yy 
= LogicalToDeviceY(y 
+ bitmap
.GetHeight()); 
 859     PsPrintf( wxT("/origstate save def\n") 
 860               wxT("20 dict begin\n") 
 861               wxT("/pix %d string def\n") 
 862               wxT("/grays %d string def\n") 
 863               wxT("/npixels 0 def\n") 
 864               wxT("/rgbindx 0 def\n") 
 865               wxT("%d %d translate\n") 
 868               wxT("[%d 0 0 %d 0 %d]\n") 
 869               wxT("{currentfile pix readhexstring pop}\n") 
 870               wxT("false 3 colorimage\n"), 
 871             w
, w
, xx
, yy
, ww
, hh
, w
, h
, w
, -h
, h 
); 
 873     unsigned char* data 
= image
.GetData(); 
 875     // size of the buffer = width*rgb(3)*hexa(2)+'\n' 
 876     wxCharBuffer 
buffer(w
*6 + 1); 
 877     int firstDigit
, secondDigit
; 
 880     for (int j 
= 0; j 
< h
; j
++) 
 882         char* bufferindex 
= buffer
.data(); 
 885         for (int i 
= 0; i 
< w
*3; i
++) 
 887             firstDigit 
= (int)(*data
/16.0); 
 888             secondDigit 
= (int)(*data 
- (firstDigit
*16.0)); 
 889             *(bufferindex
++) = hexArray
[firstDigit
]; 
 890             *(bufferindex
++) = hexArray
[secondDigit
]; 
 894         *(bufferindex
++) = '\n'; 
 900     PsPrint( "origstate restore\n" ); 
 903 void wxPostScriptDC::SetFont( const wxFont
& font 
) 
 905     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 907     if (!font
.Ok())  return; 
 911     int Style 
= m_font
.GetStyle(); 
 912     int Weight 
= m_font
.GetWeight(); 
 915     switch (m_font
.GetFamily()) 
 920             if (Style 
== wxITALIC
) 
 922                 if (Weight 
== wxBOLD
) 
 923                     name 
= "/Courier-BoldOblique"; 
 925                     name 
= "/Courier-Oblique"; 
 929                 if (Weight 
== wxBOLD
) 
 930                     name 
= "/Courier-Bold"; 
 938             if (Style 
== wxITALIC
) 
 940                 if (Weight 
== wxBOLD
) 
 941                     name 
= "/Times-BoldItalic"; 
 943                     name 
= "/Times-Italic"; 
 947                 if (Weight 
== wxBOLD
) 
 948                     name 
= "/Times-Bold"; 
 950                     name 
= "/Times-Roman"; 
 956             name 
= "/ZapfChancery-MediumItalic"; 
 962             if (Style 
== wxITALIC
) 
 964                 if (Weight 
== wxBOLD
) 
 965                     name 
= "/Helvetica-BoldOblique"; 
 967                     name 
= "/Helvetica-Oblique"; 
 971                 if (Weight 
== wxBOLD
) 
 972                     name 
= "/Helvetica-Bold"; 
 980     // We may legitimately call SetFont before BeginDoc 
 985     PsPrint( " reencodeISO def\n" ); 
 987     PsPrint( " findfont\n" ); 
 990     sprintf( buffer
, "%f scalefont setfont\n", LogicalToDeviceYRel(m_font
.GetPointSize() * 1000) / 1000.0F
); 
 991     // this is a hack - we must scale font size (in pts) according to m_scaleY but 
 992     // LogicalToDeviceYRel works with wxCoord type (int or longint). Se we first convert font size 
 993     // to 1/1000th of pt and then back. 
 994     for (int i 
= 0; i 
< 100; i
++) 
 995         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
 999 void wxPostScriptDC::SetPen( const wxPen
& pen 
) 
1001     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1003     if (!pen
.Ok()) return; 
1005     int oldStyle 
= m_pen
.GetStyle(); 
1010     sprintf( buffer
, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1011     for (int i 
= 0; i 
< 100; i
++) 
1012         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1016      Line style - WRONG: 2nd arg is OFFSET 
1018      Here, I'm afraid you do not conceive meaning of parameters of 'setdash' 
1019      operator correctly. You should look-up this in the Red Book: the 2nd parame- 
1020      ter is not number of values in the array of the first one, but an offset 
1021      into this description of the pattern. I mean a real *offset* not index 
1022      into array. I.e. If the command is [3 4] 1 setdash   is used, then there 
1023      will be first black line *2* units wxCoord, then space 4 units, then the 
1024      pattern of *3* units black, 4 units space will be repeated. 
1027     static const char *dotted 
= "[2 5] 2"; 
1028     static const char *short_dashed 
= "[4 4] 2"; 
1029     static const char *wxCoord_dashed 
= "[4 8] 2"; 
1030     static const char *dotted_dashed 
= "[6 6 2 6] 4"; 
1034     switch (m_pen
.GetStyle()) 
1036         case wxDOT
:           psdash 
= dotted
;         break; 
1037         case wxSHORT_DASH
:    psdash 
= short_dashed
;   break; 
1038         case wxLONG_DASH
:     psdash 
= wxCoord_dashed
; break; 
1039         case wxDOT_DASH
:      psdash 
= dotted_dashed
;  break; 
1043             int nDashes 
= m_pen
.GetDashes (&dashes
); 
1045             for (int i 
= 0; i 
< nDashes
; ++i
) 
1047                 sprintf( buffer
, "%d ", dashes 
[i
] ); 
1050             PsPrint ("] 0 setdash\n"); 
1056         default:              psdash 
= "[] 0";         break; 
1059     if ( psdash 
&& (oldStyle 
!= m_pen
.GetStyle()) ) 
1062         PsPrint( " setdash\n" ); 
1066     unsigned char red 
= m_pen
.GetColour().Red(); 
1067     unsigned char blue 
= m_pen
.GetColour().Blue(); 
1068     unsigned char green 
= m_pen
.GetColour().Green(); 
1072         // Anything not white is black 
1073         if (! (red 
== (unsigned char) 255 && 
1074                blue 
== (unsigned char) 255 && 
1075                green 
== (unsigned char) 255) ) 
1077             red 
= (unsigned char) 0; 
1078             green 
= (unsigned char) 0; 
1079             blue 
= (unsigned char) 0; 
1084     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1086         double redPS 
= (double)(red
) / 255.0; 
1087         double bluePS 
= (double)(blue
) / 255.0; 
1088         double greenPS 
= (double)(green
) / 255.0; 
1091             "%.8f %.8f %.8f setrgbcolor\n", 
1092             redPS
, greenPS
, bluePS 
); 
1093         for (int i 
= 0; i 
< 100; i
++) 
1094             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1099         m_currentBlue 
= blue
; 
1100         m_currentGreen 
= green
; 
1104 void wxPostScriptDC::SetBrush( const wxBrush
& brush 
) 
1106     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1108     if (!brush
.Ok()) return; 
1113     unsigned char red 
= m_brush
.GetColour().Red(); 
1114     unsigned char blue 
= m_brush
.GetColour().Blue(); 
1115     unsigned char green 
= m_brush
.GetColour().Green(); 
1119         // Anything not white is black 
1120         if (! (red 
== (unsigned char) 255 && 
1121                blue 
== (unsigned char) 255 && 
1122                green 
== (unsigned char) 255) ) 
1124             red 
= (unsigned char) 0; 
1125             green 
= (unsigned char) 0; 
1126             blue 
= (unsigned char) 0; 
1131     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1133         double redPS 
= (double)(red
) / 255.0; 
1134         double bluePS 
= (double)(blue
) / 255.0; 
1135         double greenPS 
= (double)(green
) / 255.0; 
1139                 "%.8f %.8f %.8f setrgbcolor\n", 
1140                 redPS
, greenPS
, bluePS 
); 
1141         for (int i 
= 0; i 
< 100; i
++) 
1142             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1147         m_currentBlue 
= blue
; 
1148         m_currentGreen 
= green
; 
1152 void wxPostScriptDC::DoDrawText( const wxString
& text
, wxCoord x
, wxCoord y 
) 
1154     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1156     if (m_textForegroundColour
.Ok()) 
1158         unsigned char red 
= m_textForegroundColour
.Red(); 
1159         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1160         unsigned char green 
= m_textForegroundColour
.Green(); 
1164             // Anything not white is black 
1165             if (! (red 
== (unsigned char) 255 && 
1166                         blue 
== (unsigned char) 255 && 
1167                         green 
== (unsigned char) 255)) 
1169                 red 
= (unsigned char) 0; 
1170                 green 
= (unsigned char) 0; 
1171                 blue 
= (unsigned char) 0; 
1175         // maybe setgray here ? 
1176         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1178             double redPS 
= (double)(red
) / 255.0; 
1179             double bluePS 
= (double)(blue
) / 255.0; 
1180             double greenPS 
= (double)(green
) / 255.0; 
1184                 "%.8f %.8f %.8f setrgbcolor\n", 
1185                 redPS
, greenPS
, bluePS 
); 
1186             for (size_t i 
= 0; i 
< strlen(buffer
); i
++) 
1187                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1191             m_currentBlue 
= blue
; 
1192             m_currentGreen 
= green
; 
1196     wxCoord text_w
, text_h
, text_descent
; 
1198     GetTextExtent(text
, &text_w
, &text_h
, &text_descent
); 
1200     // VZ: this seems to be unnecessary, so taking it out for now, if it 
1201     //     doesn't create any problems, remove this comment entirely 
1202     //SetFont( m_font ); 
1205     int size 
= m_font
.GetPointSize(); 
1207 //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline 
1208 //    commented by V. Slavik and replaced by accurate version 
1209 //        - note that there is still rounding error in text_descent! 
1210     wxCoord by 
= y 
+ size 
- text_descent
; // baseline 
1212     PsPrintf( wxT("%d %d moveto\n"), LogicalToDeviceX(x
), LogicalToDeviceY(by
) ); 
1215     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1216     size_t len 
= strlen(textbuf
); 
1218     for (i 
= 0; i 
< len
; i
++) 
1220         int c 
= (unsigned char) textbuf
[i
]; 
1221         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1223             /* Cope with special characters */ 
1227         else if ( c 
>= 128 ) 
1229             /* Cope with character codes > 127 */ 
1230             PsPrintf( wxT("\\%o"), c
); 
1238     PsPrint( ") show\n" ); 
1240     if (m_font
.GetUnderlined()) 
1242         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1252                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1253                 m_underlineThickness
, 
1254                 LogicalToDeviceX(x 
+ text_w
), LogicalToDeviceY(uy
) ); 
1255         for (i 
= 0; i 
< 100; i
++) 
1256             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1260     CalcBoundingBox( x
, y 
); 
1261     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1264 void wxPostScriptDC::DoDrawRotatedText( const wxString
& text
, wxCoord x
, wxCoord y
, double angle 
) 
1266     if ( wxIsNullDouble(angle
) ) 
1268         DoDrawText(text
, x
, y
); 
1272     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1276     if (m_textForegroundColour
.Ok()) 
1278         unsigned char red 
= m_textForegroundColour
.Red(); 
1279         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1280         unsigned char green 
= m_textForegroundColour
.Green(); 
1284             // Anything not white is black 
1285             if (! (red 
== (unsigned char) 255 && 
1286                    blue 
== (unsigned char) 255 && 
1287                    green 
== (unsigned char) 255)) 
1289                 red 
= (unsigned char) 0; 
1290                 green 
= (unsigned char) 0; 
1291                 blue 
= (unsigned char) 0; 
1295         // maybe setgray here ? 
1296         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1298             double redPS 
= (double)(red
) / 255.0; 
1299             double bluePS 
= (double)(blue
) / 255.0; 
1300             double greenPS 
= (double)(green
) / 255.0; 
1304                 "%.8f %.8f %.8f setrgbcolor\n", 
1305                 redPS
, greenPS
, bluePS 
); 
1306             for (int i 
= 0; i 
< 100; i
++) 
1307                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1311             m_currentBlue 
= blue
; 
1312             m_currentGreen 
= green
; 
1316     int size 
= m_font
.GetPointSize(); 
1318     PsPrintf( wxT("%d %d moveto\n"), 
1319             LogicalToDeviceX(x
), LogicalToDeviceY(y
)); 
1322     sprintf(buffer
, "%.8f rotate\n", angle
); 
1324     for (i 
= 0; i 
< 100; i
++) 
1326         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1331     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1332     size_t len 
= strlen(textbuf
); 
1333     for (i 
= 0; i 
< len
; i
++) 
1335         int c 
= (unsigned char) textbuf
[i
]; 
1336         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1338             /* Cope with special characters */ 
1342         else if ( c 
>= 128 ) 
1344             /* Cope with character codes > 127 */ 
1345             PsPrintf( wxT("\\%o"), c
); 
1353     PsPrint( ") show\n" ); 
1355     sprintf( buffer
, "%.8f rotate\n", -angle 
); 
1356     for (i 
= 0; i 
< 100; i
++) 
1358         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1362     if (m_font
.GetUnderlined()) 
1364         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1366         GetTextExtent(text
, &w
, &h
); 
1375                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1376                 m_underlineThickness
, 
1377                 LogicalToDeviceX(x 
+ w
), LogicalToDeviceY(uy
) ); 
1378         for (i 
= 0; i 
< 100; i
++) 
1380             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1385     CalcBoundingBox( x
, y 
); 
1386     CalcBoundingBox( x 
+ size 
* text
.Length() * 2/3 , y 
); 
1389 void wxPostScriptDC::SetBackground (const wxBrush
& brush
) 
1391     m_backgroundBrush 
= brush
; 
1394 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function
)) 
1396     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); 
1400 void wxPostScriptDC::DoDrawSpline( wxList 
*points 
) 
1402     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1406     // a and b are not used 
1408     double c
, d
, x1
, y1
, x2
, y2
, x3
, y3
; 
1411     wxList::compatibility_iterator node 
= points
->GetFirst(); 
1412     p 
= (wxPoint 
*)node
->GetData(); 
1416     node 
= node
->GetNext(); 
1417     p 
= (wxPoint 
*)node
->GetData(); 
1424          (double)(x1 
+ c
) / 2; 
1429          (double)(y1 
+ d
) / 2; 
1431     PsPrintf( wxT("newpath\n") 
1432               wxT("%d %d moveto\n") 
1433               wxT("%d %d lineto\n"), 
1434             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1435             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1437     CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1438     CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1440     node 
= node
->GetNext(); 
1443         q 
= (wxPoint 
*)node
->GetData(); 
1451         x3 
= (double)(x2 
+ c
) / 2; 
1452         y3 
= (double)(y2 
+ d
) / 2; 
1454         PsPrintf( wxT("%d %d %d %d %d %d DrawSplineSection\n"), 
1455             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1456             LogicalToDeviceX((wxCoord
)x2
), LogicalToDeviceY((wxCoord
)y2
), 
1457             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1459         CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1460         CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1462         node 
= node
->GetNext(); 
1466        At this point, (x2,y2) and (c,d) are the position of the 
1467        next-to-last and last point respectively, in the point list 
1470     PsPrintf( wxT("%d %d lineto\n") 
1472             LogicalToDeviceX((wxCoord
)c
), LogicalToDeviceY((wxCoord
)d
) ); 
1474 #endif // wxUSE_SPLINES 
1476 wxCoord 
wxPostScriptDC::GetCharWidth() const 
1478     // Chris Breeze: reasonable approximation using wxMODERN/Courier 
1479     return (wxCoord
) (GetCharHeight() * 72.0 / 120.0); 
1483 void wxPostScriptDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
1485     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1487     m_signX 
= (xLeftRight 
? 1 : -1); 
1488     m_signY 
= (yBottomUp  
? 1 : -1); 
1490     ComputeScaleAndOrigin(); 
1493 void wxPostScriptDC::SetDeviceOrigin( wxCoord x
, wxCoord y 
) 
1495     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1501     wxDC::SetDeviceOrigin( x
, h
-y 
); 
1504 void wxPostScriptDC::DoGetSize(int* width
, int* height
) const 
1506     wxPaperSize id 
= m_printData
.GetPaperId(); 
1508     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1510     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1516         w 
= paper
->GetSizeDeviceUnits().x
; 
1517         h 
= paper
->GetSizeDeviceUnits().y
; 
1520     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1527     if (width
) *width 
= (int)(w 
* ms_PSScaleFactor
); 
1528     if (height
) *height 
= (int)(h 
* ms_PSScaleFactor
); 
1531 void wxPostScriptDC::DoGetSizeMM(int *width
, int *height
) const 
1533     wxPaperSize id 
= m_printData
.GetPaperId(); 
1535     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1537     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1543         w 
= paper
->GetWidth() / 10; 
1544         h 
= paper
->GetHeight() / 10; 
1547     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1554     if (width
) *width 
= w
; 
1555     if (height
) *height 
= h
; 
1558 // Resolution in pixels per logical inch 
1559 wxSize 
wxPostScriptDC::GetPPI(void) const 
1561     return wxSize((int)(72 * ms_PSScaleFactor
), 
1562                   (int)(72 * ms_PSScaleFactor
)); 
1566 bool wxPostScriptDC::StartDoc( const wxString
& message 
) 
1568     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1570     if (m_printData
.GetPrintMode() != wxPRINT_MODE_STREAM 
) 
1572         if (m_printData
.GetFilename() == wxEmptyString
) 
1574             wxString filename 
= wxGetTempFileName( wxT("ps") ); 
1575             m_printData
.SetFilename(filename
); 
1578         m_pstream 
= wxFopen( m_printData
.GetFilename(), wxT("w+") ); 
1582             wxLogError( _("Cannot open file for PostScript printing!")); 
1591     PsPrint( "%!PS-Adobe-2.0\n" ); 
1592     PsPrintf( wxT("%%%%Title: %s\n"), m_title
.c_str() ); 
1593     PsPrint( "%%Creator: wxWidgets PostScript renderer\n" ); 
1594     PsPrintf( wxT("%%%%CreationDate: %s\n"), wxNow().c_str() ); 
1595     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1596         PsPrint( "%%Orientation: Landscape\n" ); 
1598         PsPrint( "%%Orientation: Portrait\n" ); 
1600     // PsPrintf( wxT("%%%%Pages: %d\n"), (wxPageNumber - 1) ); 
1602     const wxChar 
*paper
; 
1603     switch (m_printData
.GetPaperId()) 
1605        case wxPAPER_LETTER
: paper 
= wxT("Letter"); break;             // Letter: paper ""; 8 1/2 by 11 inches 
1606        case wxPAPER_LEGAL
: paper 
= wxT("Legal"); break;              // Legal, 8 1/2 by 14 inches 
1607        case wxPAPER_A4
: paper 
= wxT("A4"); break;          // A4 Sheet, 210 by 297 millimeters 
1608        case wxPAPER_TABLOID
: paper 
= wxT("Tabloid"); break;     // Tabloid, 11 by 17 inches 
1609        case wxPAPER_LEDGER
: paper 
= wxT("Ledger"); break;      // Ledger, 17 by 11 inches 
1610        case wxPAPER_STATEMENT
: paper 
= wxT("Statement"); break;   // Statement, 5 1/2 by 8 1/2 inches 
1611        case wxPAPER_EXECUTIVE
: paper 
= wxT("Executive"); break;   // Executive, 7 1/4 by 10 1/2 inches 
1612        case wxPAPER_A3
: paper 
= wxT("A3"); break;          // A3 sheet, 297 by 420 millimeters 
1613        case wxPAPER_A5
: paper 
= wxT("A5"); break;          // A5 sheet, 148 by 210 millimeters 
1614        case wxPAPER_B4
: paper 
= wxT("B4"); break;          // B4 sheet, 250 by 354 millimeters 
1615        case wxPAPER_B5
: paper 
= wxT("B5"); break;          // B5 sheet, 182-by-257-millimeter paper 
1616        case wxPAPER_FOLIO
: paper 
= wxT("Folio"); break;       // Folio, 8-1/2-by-13-inch paper 
1617        case wxPAPER_QUARTO
: paper 
= wxT("Quaro"); break;      // Quarto, 215-by-275-millimeter paper 
1618        case wxPAPER_10X14
: paper 
= wxT("10x14"); break;       // 10-by-14-inch sheet 
1619        default: paper 
= wxT("A4"); 
1621     PsPrintf( wxT("%%%%DocumentPaperSizes: %s\n"), paper 
); 
1622     PsPrint( "%%EndComments\n\n" ); 
1624     PsPrint( "%%BeginProlog\n" ); 
1625     PsPrint( wxPostScriptHeaderConicTo 
); 
1626     PsPrint( wxPostScriptHeaderEllipse 
); 
1627     PsPrint( wxPostScriptHeaderEllipticArc 
); 
1628     PsPrint( wxPostScriptHeaderColourImage 
); 
1629     PsPrint( wxPostScriptHeaderReencodeISO1 
); 
1630     PsPrint( wxPostScriptHeaderReencodeISO2 
); 
1631     if (wxPostScriptHeaderSpline
) 
1632         PsPrint( wxPostScriptHeaderSpline 
); 
1633     PsPrint( "%%EndProlog\n" ); 
1635     SetBrush( *wxBLACK_BRUSH 
); 
1636     SetPen( *wxBLACK_PEN 
); 
1637     SetBackground( *wxWHITE_BRUSH 
); 
1638     SetTextForeground( *wxBLACK 
); 
1640     // set origin according to paper size 
1641     SetDeviceOrigin( 0,0 ); 
1648 void wxPostScriptDC::EndDoc () 
1650     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1655         PsPrint( "grestore\n" ); 
1659         fclose( m_pstream 
); 
1660         m_pstream 
= (FILE *) NULL
; 
1664     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com> 
1665     wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
1666     double wx_printer_scale_x
, wx_printer_scale_y
; 
1668     wx_printer_translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1669     wx_printer_translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1671     wx_printer_scale_x 
= m_printData
.GetPrinterScaleX(); 
1672     wx_printer_scale_y 
= m_printData
.GetPrinterScaleY(); 
1674     // Compute the bounding box.  Note that it is in the default user 
1675     // coordinate system, thus we have to convert the values. 
1676     wxCoord minX 
= (wxCoord
) LogicalToDeviceX(m_minX
); 
1677     wxCoord minY 
= (wxCoord
) LogicalToDeviceY(m_minY
); 
1678     wxCoord maxX 
= (wxCoord
) LogicalToDeviceX(m_maxX
); 
1679     wxCoord maxY 
= (wxCoord
) LogicalToDeviceY(m_maxY
); 
1681     // LOG2DEV may have changed the minimum to maximum vice versa 
1682     if ( minX 
> maxX 
) { wxCoord tmp 
= minX
; minX 
= maxX
; maxX 
= tmp
; } 
1683     if ( minY 
> maxY 
) { wxCoord tmp 
= minY
; minY 
= maxY
; maxY 
= tmp
; } 
1685     // account for used scaling (boundingbox is before scaling in ps-file) 
1686     double scale_x 
= m_printData
.GetPrinterScaleX() / ms_PSScaleFactor
; 
1687     double scale_y 
= m_printData
.GetPrinterScaleY() / ms_PSScaleFactor
; 
1689     wxCoord llx
, lly
, urx
, ury
; 
1690     llx 
= (wxCoord
) ((minX
+wx_printer_translate_x
)*scale_x
); 
1691     lly 
= (wxCoord
) ((minY
+wx_printer_translate_y
)*scale_y
); 
1692     urx 
= (wxCoord
) ((maxX
+wx_printer_translate_x
)*scale_x
); 
1693     ury 
= (wxCoord
) ((maxY
+wx_printer_translate_y
)*scale_y
); 
1694     // (end of bounding box computation) 
1697     // If we're landscape, our sense of "x" and "y" is reversed. 
1698     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1701         tmp 
= llx
; llx 
= lly
; lly 
= tmp
; 
1702         tmp 
= urx
; urx 
= ury
; ury 
= tmp
; 
1704         // We need either the two lines that follow, or we need to subtract 
1705         // min_x from real_translate_y, which is commented out below. 
1706         llx 
= llx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1707         urx 
= urx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1710     // The Adobe specifications call for integers; we round as to make 
1711     // the bounding larger. 
1712     PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"), 
1713             (wxCoord
)floor((double)llx
), (wxCoord
)floor((double)lly
), 
1714             (wxCoord
)ceil((double)urx
), (wxCoord
)ceil((double)ury
) ); 
1716     // To check the correctness of the bounding box, postscript commands 
1717     // to draw a box corresponding to the bounding box are generated below. 
1718     // But since we typically don't want to print such a box, the postscript 
1719     // commands are generated within comments.  These lines appear before any 
1720     // adjustment of scale, rotation, or translation, and hence are in the 
1721     // default user coordinates. 
1722     PsPrint( "% newpath\n" ); 
1723     PsPrintf( wxT("%% %d %d moveto\n"), llx
, lly 
); 
1724     PsPrintf( wxT("%% %d %d lineto\n"), urx
, lly 
); 
1725     PsPrintf( wxT("%% %d %d lineto\n"), urx
, ury 
); 
1726     PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx
, ury 
); 
1730     wxPostScriptPrintNativeData 
*data 
= 
1731         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1733     if (m_ok 
&& (m_printData
.GetPrintMode() == wxPRINT_MODE_PRINTER
)) 
1736         command 
+= data
->GetPrinterCommand(); 
1737         command 
+= wxT(" "); 
1738         command 
+= data
->GetPrinterOptions(); 
1739         command 
+= wxT(" "); 
1740         command 
+= m_printData
.GetFilename(); 
1742         wxExecute( command
, true ); 
1743         wxRemoveFile( m_printData
.GetFilename() ); 
1748 void wxPostScriptDC::StartPage() 
1750     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1752     PsPrintf( wxT("%%%%Page: %d\n"), wxPageNumber
++ ); 
1754     //  What is this one supposed to do? RR. 
1755 //  *m_pstream << "matrix currentmatrix\n"; 
1757     // Added by Chris Breeze 
1759     // Each page starts with an "initgraphics" which resets the 
1760     // transformation and so we need to reset the origin 
1761     // (and rotate the page for landscape printing) 
1764     wxCoord translate_x
, translate_y
; 
1765     double scale_x
, scale_y
; 
1767     wxPostScriptPrintNativeData 
*data 
= 
1768         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1770     translate_x 
= (wxCoord
)data
->GetPrinterTranslateX(); 
1771     translate_y 
= (wxCoord
)data
->GetPrinterTranslateY(); 
1773     scale_x 
= data
->GetPrinterScaleX(); 
1774     scale_y 
= data
->GetPrinterScaleY(); 
1776     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1779         GetSize( (int*) NULL
, &h 
); 
1781         PsPrint( "90 rotate\n" ); 
1782         // I copied this one from a PostScript tutorial, but to no avail. RR. 
1783         // PsPrint( "90 rotate llx neg ury nef translate\n" ); 
1787     sprintf( buffer
, "%.8f %.8f scale\n", scale_x 
/ ms_PSScaleFactor
, 
1788             scale_y 
/ ms_PSScaleFactor
); 
1789     for (int i 
= 0; i 
< 100; i
++) 
1790         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1793     PsPrintf( wxT("%d %d translate\n"), translate_x
, translate_y 
); 
1796 void wxPostScriptDC::EndPage () 
1798     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
1800     PsPrint( "showpage\n" ); 
1803 bool wxPostScriptDC::DoBlit( wxCoord xdest
, wxCoord ydest
, 
1804                            wxCoord fwidth
, wxCoord fheight
, 
1806                            wxCoord xsrc
, wxCoord ysrc
, 
1807                            int rop
, bool WXUNUSED(useMask
), wxCoord 
WXUNUSED(xsrcMask
), wxCoord 
WXUNUSED(ysrcMask
) ) 
1809     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1811     wxCHECK_MSG( source
, false, wxT("invalid source dc") ); 
1813     /* blit into a bitmap */ 
1814     wxBitmap 
bitmap( (int)fwidth
, (int)fheight 
); 
1816     memDC
.SelectObject(bitmap
); 
1817     memDC
.Blit(0, 0, fwidth
, fheight
, source
, xsrc
, ysrc
, rop
); /* TODO: Blit transparently? */ 
1818     memDC
.SelectObject(wxNullBitmap
); 
1820     /* draw bitmap. scaling and positioning is done there */ 
1821     DrawBitmap( bitmap
, xdest
, ydest 
); 
1826 wxCoord 
wxPostScriptDC::GetCharHeight() const 
1829         return m_font
.GetPointSize(); 
1834 void wxPostScriptDC::DoGetTextExtent(const wxString
& string
, 
1835                                      wxCoord 
*x
, wxCoord 
*y
, 
1836                                      wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1837                                      wxFont 
*theFont 
) const 
1839     wxFont 
*fontToUse 
= theFont
; 
1841     if (!fontToUse
) fontToUse 
= (wxFont
*) &m_font
; 
1843     wxCHECK_RET( fontToUse
, wxT("GetTextExtent: no font defined") ); 
1849         if (descent
) (*descent
) = 0; 
1850         if (externalLeading
) (*externalLeading
) = 0; 
1856     const wxWX2MBbuf strbuf 
= string
.mb_str(); 
1858 #if !wxUSE_AFM_FOR_POSTSCRIPT 
1859     /* Provide a VERY rough estimate (avoid using it). 
1860      * Produces accurate results for mono-spaced font 
1861      * such as Courier (aka wxMODERN) */ 
1866         height 
= fontToUse
->GetPointSize(); 
1869         *x 
= strlen (strbuf
) * height 
* 72 / 120; 
1871         *y 
= (wxCoord
) (height 
* 1.32);    /* allow for descender */ 
1872     if (descent
) *descent 
= 0; 
1873     if (externalLeading
) *externalLeading 
= 0; 
1876     /* method for calculating string widths in postscript: 
1877     /  read in the AFM (adobe font metrics) file for the 
1878     /  actual font, parse it and extract the character widths 
1879     /  and also the descender. this may be improved, but for now 
1880     /  it works well. the AFM file is only read in if the 
1881     /  font is changed. this may be chached in the future. 
1882     /  calls to GetTextExtent with the font unchanged are rather 
1885     /  for each font and style used there is an AFM file necessary. 
1886     /  currently i have only files for the roman font family. 
1887     /  I try to get files for the other ones! 
1889     /  CAVE: the size of the string is currently always calculated 
1890     /        in 'points' (1/72 of an inch). this should later on be 
1891     /        changed to depend on the mapping mode. 
1892     /  CAVE: the path to the AFM files must be set before calling this 
1893     /        function. this is usually done by a call like the following: 
1894     /        wxSetAFMPath("d:\\wxw161\\afm\\"); 
1898     /    wxPostScriptDC dc(NULL, true); 
1900     /      wxSetAFMPath("d:\\wxw161\\afm\\"); 
1901     /      dc.StartDoc("Test"); 
1904     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); 
1905     /      dc.GetTextExtent("Hallo",&w,&h); 
1910     /  by steve (stefan.hammes@urz.uni-heidelberg.de) 
1912     /  updated: 14.05.95 */ 
1914     /* these static vars are for storing the state between calls */ 
1915     static int lastFamily
= INT_MIN
; 
1916     static int lastSize
= INT_MIN
; 
1917     static int lastStyle
= INT_MIN
; 
1918     static int lastWeight
= INT_MIN
; 
1919     static int lastDescender 
= INT_MIN
; 
1920     static int lastWidths
[256]; /* widths of the characters */ 
1922     double UnderlinePosition 
= 0.0; 
1923     double UnderlineThickness 
= 0.0; 
1925     // Get actual parameters 
1926     int Family 
= fontToUse
->GetFamily(); 
1927     int Size 
=   fontToUse
->GetPointSize(); 
1928     int Style 
=  fontToUse
->GetStyle(); 
1929     int Weight 
= fontToUse
->GetWeight(); 
1931     // If we have another font, read the font-metrics 
1932     if (Family
!=lastFamily 
|| Size
!=lastSize 
|| Style
!=lastStyle 
|| Weight
!=lastWeight
) 
1934         // Store actual values 
1935         lastFamily 
= Family
; 
1938         lastWeight 
= Weight
; 
1947                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBoO.afm"); 
1948                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBo.afm"); 
1949                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("CourO.afm"); 
1950                 else name 
= wxT("Cour.afm"); 
1955                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBoO.afm"); 
1956                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBo.afm"); 
1957                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("TimesO.afm"); 
1958                 else name 
= wxT("TimesRo.afm"); 
1963                 name 
= wxT("Zapf.afm"); 
1969                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBoO.afm"); 
1970                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBo.afm"); 
1971                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("HelvO.afm"); 
1972                 else name 
= wxT("Helv.afm"); 
1977         FILE *afmFile 
= NULL
; 
1979         // Get the directory of the AFM files 
1982         // VZ: I don't know if the cast always works under Unix but it clearly 
1983         //     never does under Windows where the pointer is 
1984         //     wxWindowsPrintNativeData and so calling GetFontMetricPath() on 
1987         wxPostScriptPrintNativeData 
*data 
= 
1988             wxDynamicCast(m_printData
.GetNativeData(), wxPostScriptPrintNativeData
); 
1990         if (data 
&& !data
->GetFontMetricPath().empty()) 
1992             afmName 
= data
->GetFontMetricPath(); 
1993             afmName 
<< wxFILE_SEP_PATH 
<< name
; 
1997         if ( !afmName
.empty() ) 
1998             afmFile 
= wxFopen(afmName
, wxT("r")); 
2002 #if defined(__UNIX__) && !defined(__VMS__) 
2003            afmName 
= wxGetDataDir(); 
2005            afmName 
= wxStandardPaths::Get().GetDataDir(); 
2006 #endif // __UNIX__/!__UNIX__ 
2008            afmName 
<<  wxFILE_SEP_PATH
 
2009 #if defined(__LINUX__) || defined(__FREEBSD__) 
2010                    << wxT("gs_afm") << wxFILE_SEP_PATH
 
2012                    << wxT("afm") << wxFILE_SEP_PATH
 
2015            afmFile 
= wxFopen(afmName
,wxT("r")); 
2018         /* 2. open and process the file 
2019            /  a short explanation of the AFM format: 
2020            /  we have for each character a line, which gives its size 
2023            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; 
2025            /  that means, we have a character with ascii code 63, and width 
2026            /  (444/1000 * fontSize) points. 
2027            /  the other data is ignored for now! 
2029            /  when the font has changed, we read in the right AFM file and store the 
2030            /  character widths in an array, which is processed below (see point 3.). */ 
2033             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName
.c_str() ); 
2034             wxLogDebug( wxT("               using approximate values")); 
2035             for (int i
=0; i
<256; i
++) lastWidths
[i
] = 500; /* an approximate value */ 
2036             lastDescender 
= -150; /* dito. */ 
2040             /* init the widths array */ 
2041             for(int i
=0; i
<256; i
++) lastWidths
[i
] = INT_MIN
; 
2042             /* some variables for holding parts of a line */ 
2043             char cString
[10], semiString
[10], WXString
[10]; 
2044             char descString
[20]; 
2045             char upString
[30], utString
[30]; 
2049             /* read in the file and parse it */ 
2050             while(fgets(line
,sizeof(line
),afmFile
)!=NULL
) 
2052                 /* A.) check for descender definition */ 
2053                 if (strncmp(line
,"Descender",9)==0) 
2055                     if ((sscanf(line
,"%s%d",descString
,&lastDescender
)!=2) || 
2056                             (strcmp(descString
,"Descender")!=0)) 
2058                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName
.c_str(),line 
); 
2061                 /* JC 1.) check for UnderlinePosition */ 
2062                 else if(strncmp(line
,"UnderlinePosition",17)==0) 
2064                     if ((sscanf(line
,"%s%lf",upString
,&UnderlinePosition
)!=2) || 
2065                             (strcmp(upString
,"UnderlinePosition")!=0)) 
2067                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName
.c_str(), line 
); 
2070                 /* JC 2.) check for UnderlineThickness */ 
2071                 else if(strncmp(line
,"UnderlineThickness",18)==0) 
2073                     if ((sscanf(line
,"%s%lf",utString
,&UnderlineThickness
)!=2) || 
2074                             (strcmp(utString
,"UnderlineThickness")!=0)) 
2076                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName
.c_str(), line 
); 
2079                 /* JC 3.) check for EncodingScheme */ 
2080                 else if(strncmp(line
,"EncodingScheme",14)==0) 
2082                     if ((sscanf(line
,"%s%s",utString
,encString
)!=2) || 
2083                             (strcmp(utString
,"EncodingScheme")!=0)) 
2085                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName
.c_str(), line 
); 
2087                     else if (strncmp(encString
, "AdobeStandardEncoding", 21)) 
2089                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"), 
2090                                 afmName
.c_str(),line
, encString
); 
2093                 /* B.) check for char-width */ 
2094                 else if(strncmp(line
,"C ",2)==0) 
2096                     if (sscanf(line
,"%s%d%s%s%d",cString
,&ascii
,semiString
,WXString
,&cWidth
)!=5) 
2098                         wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName
.c_str(),line
); 
2100                     if(strcmp(cString
,"C")!=0 || strcmp(semiString
,";")!=0 || strcmp(WXString
,"WX")!=0) 
2102                         wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName
.c_str(),line
); 
2104                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ 
2105                     if (ascii
>=0 && ascii
<256) 
2107                         lastWidths
[ascii
] = cWidth
; /* store width */ 
2111                         /* MATTHEW: this happens a lot; don't print an error */ 
2112                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ 
2115                 /* C.) ignore other entries. */ 
2119         /* hack to compute correct values for german 'Umlaute' 
2120            /  the correct way would be to map the character names 
2121            /  like 'adieresis' to corresp. positions of ISOEnc and read 
2122            /  these values from AFM files, too. Maybe later ... */ 
2124         // NB: casts to int are needed to suppress gcc 3.3 warnings 
2125         lastWidths
[196] = lastWidths
[(int)'A'];  // Ä 
2126         lastWidths
[228] = lastWidths
[(int)'a'];  // ä 
2127         lastWidths
[214] = lastWidths
[(int)'O'];  // Ö 
2128         lastWidths
[246] = lastWidths
[(int)'o'];  // ö 
2129         lastWidths
[220] = lastWidths
[(int)'U'];  // Ü 
2130         lastWidths
[252] = lastWidths
[(int)'u'];  // ü 
2131         lastWidths
[223] = lastWidths
[(int)251];  // ß 
2133         /* JC: calculate UnderlineThickness/UnderlinePosition */ 
2135         // VS: dirty, but is there any better solution? 
2137         pt 
= (double*) &m_underlinePosition
; 
2138         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlinePosition 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2139         pt 
= (double*) &m_underlineThickness
; 
2140         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlineThickness 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2145     /* 3. now the font metrics are read in, calc size this 
2146        /  is done by adding the widths of the characters in the 
2147        /  string. they are given in 1/1000 of the size! */ 
2150     wxCoord height
=Size
; /* by default */ 
2152     for(p
=(unsigned char *)wxMBSTRINGCAST strbuf
; *p
; p
++) 
2154         if(lastWidths
[*p
]== INT_MIN
) 
2156             wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p
,*p
); 
2157             sum 
+= lastWidths
[(unsigned char)' ']; /* assume space */ 
2161             sum 
+= lastWidths
[*p
]; 
2165     double widthSum 
= sum
; 
2167     widthSum 
/= 1000.0F
; 
2169     /* add descender to height (it is usually a negative value) */ 
2170     //if (lastDescender != INT_MIN) 
2172     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ 
2174     // - commented by V. Slavik - height already contains descender in it 
2175     //   (judging from few experiments) 
2177     /* return size values */ 
2179         *x 
= (wxCoord
)widthSum
; 
2183     /* return other parameters */ 
2186         if(lastDescender
!=INT_MIN
) 
2188             *descent 
= (wxCoord
)(((-lastDescender
)/1000.0F
) * Size
); /* MATTHEW: forgot scale */ 
2196     /* currently no idea how to calculate this! */ 
2197     if (externalLeading
) *externalLeading 
= 0; 
2202 // print postscript datas via required method (file, stream) 
2203 void wxPostScriptDC::PsPrintf( const wxChar
* fmt
, ... ) 
2206     va_start(argptr
, fmt
); 
2208     PsPrint( wxString::FormatV( fmt
, argptr 
).c_str() ); 
2211 void wxPostScriptDC::PsPrint( const char* psdata 
) 
2213     wxPostScriptPrintNativeData 
*data 
= 
2214         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2216     switch (m_printData
.GetPrintMode()) 
2219         // append to output stream 
2220         case wxPRINT_MODE_STREAM
: 
2222                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2223                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2224                 outputstream
->Write( psdata
, strlen( psdata 
) ); 
2227 #endif // wxUSE_STREAMS 
2229         // save data into file 
2231             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2232             fwrite( psdata
, 1, strlen( psdata 
), m_pstream 
); 
2236 void wxPostScriptDC::PsPrint( int ch 
) 
2238     wxPostScriptPrintNativeData 
*data 
= 
2239         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2241     switch (m_printData
.GetPrintMode()) 
2244         // append to output stream 
2245         case wxPRINT_MODE_STREAM
: 
2247                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2248                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2249                 outputstream
->PutC( (char)ch 
); 
2252 #endif // wxUSE_STREAMS 
2254         // save data into file 
2256             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2257             fputc( ch
, m_pstream 
); 
2265   // wxUSE_PRINTING_ARCHITECTURE