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" 
  26     #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 
 276 wxPostScriptDC::wxPostScriptDC (const wxPrintData
& printData
) 
 278     m_pstream 
= (FILE*) NULL
; 
 288     m_underlinePosition 
= 0.0; 
 289     m_underlineThickness 
= 0.0; 
 291     m_signX 
=  1;  // default x-axis left to right 
 292     m_signY 
= -1;  // default y-axis bottom up -> top down 
 294     m_printData 
= printData
; 
 298     SetDeviceLocalOrigin( 0, h 
); 
 303 wxPostScriptDC::~wxPostScriptDC () 
 308         m_pstream 
= (FILE*) NULL
; 
 312 bool wxPostScriptDC::IsOk() const 
 317 void wxPostScriptDC::DoSetClippingRegion (wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 319     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 321     if (m_clipping
) DestroyClippingRegion(); 
 323     wxDC::DoSetClippingRegion(x
, y
, w
, h
); 
 327     PsPrintf( wxT("gsave\n newpath\n") 
 328               wxT("%d %d moveto\n") 
 329               wxT("%d %d lineto\n") 
 330               wxT("%d %d lineto\n") 
 331               wxT("%d %d lineto\n") 
 332               wxT("closepath clip newpath\n"), 
 333             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 334             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
), 
 335             LogicalToDeviceX(x
+w
), LogicalToDeviceY(y
+h
), 
 336             LogicalToDeviceX(x
),   LogicalToDeviceY(y
+h
) ); 
 340 void wxPostScriptDC::DestroyClippingRegion() 
 342     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
 347         PsPrint( "grestore\n" ); 
 350     wxDC::DestroyClippingRegion(); 
 353 void wxPostScriptDC::Clear() 
 355     // This should fail silently to avoid unnecessary 
 357     //    wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); 
 360 bool wxPostScriptDC::DoFloodFill (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
)) 
 362     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); 
 366 bool wxPostScriptDC::DoGetPixel (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxColour 
* WXUNUSED(col
)) const 
 368     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); 
 372 void wxPostScriptDC::DoCrossHair (wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) 
 374     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); 
 377 void wxPostScriptDC::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 379     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 381     if  (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 385     PsPrintf( wxT("newpath\n") 
 386               wxT("%d %d moveto\n") 
 387               wxT("%d %d lineto\n") 
 389             LogicalToDeviceX(x1
), LogicalToDeviceY(y1
), 
 390             LogicalToDeviceX(x2
), LogicalToDeviceY (y2
) ); 
 392     CalcBoundingBox( x1
, y1 
); 
 393     CalcBoundingBox( x2
, y2 
); 
 396 #define RAD2DEG 57.29577951308 
 398 void wxPostScriptDC::DoDrawArc (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 400     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 402     wxCoord dx 
= x1 
- xc
; 
 403     wxCoord dy 
= y1 
- yc
; 
 404     wxCoord radius 
= (wxCoord
) sqrt( (double)(dx
*dx
+dy
*dy
) ); 
 405     double alpha1
, alpha2
; 
 407     if (x1 
== x2 
&& y1 
== y2
) 
 412     else if ( wxIsNullDouble(radius
) ) 
 419         alpha1 
= (x1 
- xc 
== 0) ? 
 420             (y1 
- yc 
< 0) ? 90.0 : -90.0 : 
 421                 -atan2(double(y1
-yc
), double(x1
-xc
)) * RAD2DEG
; 
 422         alpha2 
= (x2 
- xc 
== 0) ? 
 423             (y2 
- yc 
< 0) ? 90.0 : -90.0 : 
 424                 -atan2(double(y2
-yc
), double(x2
-xc
)) * RAD2DEG
; 
 426     while (alpha1 
<= 0)   alpha1 
+= 360; 
 427     while (alpha2 
<= 0)   alpha2 
+= 360; // adjust angles to be between 
 428     while (alpha1 
> 360)  alpha1 
-= 360; // 0 and 360 degree 
 429     while (alpha2 
> 360)  alpha2 
-= 360; 
 431     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 435         PsPrintf( wxT("newpath\n") 
 436                   wxT("%d %d %d %d %d %d ellipse\n") 
 437                   wxT("%d %d lineto\n") 
 440                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 441                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 443         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 444         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 447     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 451         PsPrintf( wxT("newpath\n") 
 452                   wxT("%d %d %d %d %d %d ellipse\n") 
 453                   wxT("%d %d lineto\n") 
 456                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
), LogicalToDeviceXRel(radius
), LogicalToDeviceYRel(radius
), (wxCoord
)alpha1
, (wxCoord
) alpha2
, 
 457                 LogicalToDeviceX(xc
), LogicalToDeviceY(yc
) ); 
 459         CalcBoundingBox( xc
-radius
, yc
-radius 
); 
 460         CalcBoundingBox( xc
+radius
, yc
+radius 
); 
 464 void wxPostScriptDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 466     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 468     if ( sa 
>= 360 || sa 
<= -360 ) 
 469         sa 
-= int(sa
/360)*360; 
 470     if ( ea 
>= 360 || ea 
<=- 360 ) 
 471         ea 
-= int(ea
/360)*360; 
 477     if ( wxIsSameDouble(sa
, ea
) ) 
 479         DrawEllipse(x
,y
,w
,h
); 
 483     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 487         PsPrintf( wxT("newpath\n") 
 488                   wxT("%d %d %d %d %d %d true ellipticarc\n"), 
 489                   LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 490                   LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 491                   (wxCoord
)sa
, (wxCoord
)ea 
); 
 493         CalcBoundingBox( x 
,y 
); 
 494         CalcBoundingBox( x
+w
, y
+h 
); 
 497     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 501         PsPrintf( wxT("newpath\n") 
 502                   wxT("%d %d %d %d %d %d false ellipticarc\n"), 
 503                 LogicalToDeviceX(x
+w
/2), LogicalToDeviceY(y
+h
/2), 
 504                 LogicalToDeviceXRel(w
/2), LogicalToDeviceYRel(h
/2), 
 505                 (wxCoord
)sa
, (wxCoord
)ea 
); 
 507         CalcBoundingBox( x 
,y 
); 
 508         CalcBoundingBox( x
+w
, y
+h 
); 
 512 void wxPostScriptDC::DoDrawPoint (wxCoord x
, wxCoord y
) 
 514     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 516     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 520     PsPrintf( wxT("newpath\n") 
 521               wxT("%d %d moveto\n") 
 522               wxT("%d %d lineto\n") 
 524             LogicalToDeviceX(x
),   LogicalToDeviceY(y
), 
 525             LogicalToDeviceX(x
+1), LogicalToDeviceY(y
) ); 
 527     CalcBoundingBox( x
, y 
); 
 530 void wxPostScriptDC::DoDrawPolygon (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 532     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 536     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 540         PsPrint( "newpath\n" ); 
 542         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 543         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 545         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 547         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 549         for (int i 
= 1; i 
< n
; i
++) 
 551             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 552             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 554             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 556             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 559         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 562     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 566         PsPrint( "newpath\n" ); 
 568         wxCoord xx 
= LogicalToDeviceX(points
[0].x 
+ xoffset
); 
 569         wxCoord yy 
= LogicalToDeviceY(points
[0].y 
+ yoffset
); 
 571         PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 573         CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 575         for (int i 
= 1; i 
< n
; i
++) 
 577             xx 
= LogicalToDeviceX(points
[i
].x 
+ xoffset
); 
 578             yy 
= LogicalToDeviceY(points
[i
].y 
+ yoffset
); 
 580             PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 582             CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset
); 
 585         PsPrint( "closepath\n" ); 
 586         PsPrint( "stroke\n" ); 
 590 void wxPostScriptDC::DoDrawPolyPolygon (int n
, int count
[], wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int fillStyle
) 
 592     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 596     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 600         PsPrint( "newpath\n" ); 
 603         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 605             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 606             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 608             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 610             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 612             for (int j 
= 1; j 
< count
[i
]; j
++) 
 614                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 615                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 617                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 619                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 622         PsPrint( (fillStyle 
== wxODDEVEN_RULE 
? "eofill\n" : "fill\n") ); 
 625     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 629         PsPrint( "newpath\n" ); 
 632         for (int i 
= 0; i 
< n
; ofs 
+= count
[i
++]) 
 634             wxCoord xx 
= LogicalToDeviceX(points
[ofs
].x 
+ xoffset
); 
 635             wxCoord yy 
= LogicalToDeviceY(points
[ofs
].y 
+ yoffset
); 
 637             PsPrintf( wxT("%d %d moveto\n"), xx
, yy 
); 
 639             CalcBoundingBox( points
[ofs
].x 
+ xoffset
, points
[ofs
].y 
+ yoffset 
); 
 641             for (int j 
= 1; j 
< count
[i
]; j
++) 
 643                 xx 
= LogicalToDeviceX(points
[ofs
+j
].x 
+ xoffset
); 
 644                 yy 
= LogicalToDeviceY(points
[ofs
+j
].y 
+ yoffset
); 
 646                 PsPrintf( wxT("%d %d lineto\n"), xx
, yy 
); 
 648                 CalcBoundingBox( points
[ofs
+j
].x 
+ xoffset
, points
[ofs
+j
].y 
+ yoffset
); 
 651         PsPrint( "closepath\n" ); 
 652         PsPrint( "stroke\n" ); 
 656 void wxPostScriptDC::DoDrawLines (int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 658     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 660     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 667     for ( i 
=0; i
<n 
; i
++ ) 
 669         CalcBoundingBox( LogicalToDeviceX(points
[i
].x
+xoffset
), LogicalToDeviceY(points
[i
].y
+yoffset
)); 
 672     PsPrintf( wxT("newpath\n") 
 673               wxT("%d %d moveto\n"), 
 674               LogicalToDeviceX(points
[0].x
+xoffset
), 
 675               LogicalToDeviceY(points
[0].y
+yoffset
) ); 
 677     for (i 
= 1; i 
< n
; i
++) 
 679         PsPrintf( wxT("%d %d lineto\n"), 
 680                   LogicalToDeviceX(points
[i
].x
+xoffset
), 
 681                   LogicalToDeviceY(points
[i
].y
+yoffset
) ); 
 684     PsPrint( "stroke\n" ); 
 687 void wxPostScriptDC::DoDrawRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 689     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 691     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 695         PsPrintf( wxT("newpath\n") 
 696                   wxT("%d %d moveto\n") 
 697                   wxT("%d %d lineto\n") 
 698                   wxT("%d %d lineto\n") 
 699                   wxT("%d %d lineto\n") 
 702                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 703                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 704                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 705                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 707         CalcBoundingBox( x
, y 
); 
 708         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 711     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 715         PsPrintf( wxT("newpath\n") 
 716                   wxT("%d %d moveto\n") 
 717                   wxT("%d %d lineto\n") 
 718                   wxT("%d %d lineto\n") 
 719                   wxT("%d %d lineto\n") 
 722                 LogicalToDeviceX(x
),         LogicalToDeviceY(y
), 
 723                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y
), 
 724                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ height
), 
 725                 LogicalToDeviceX(x
),         LogicalToDeviceY(y 
+ height
) ); 
 727         CalcBoundingBox( x
, y 
); 
 728         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 732 void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 734     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 738         // Now, a negative radius is interpreted to mean 
 739         // 'the proportion of the smallest X or Y dimension' 
 740         double smallest 
= width 
< height 
? width 
: height
; 
 741         radius 
=  (-radius 
* smallest
); 
 744     wxCoord rad 
= (wxCoord
) radius
; 
 746     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 750         /* Draw rectangle anticlockwise */ 
 751         PsPrintf( wxT("newpath\n") 
 752                   wxT("%d %d %d 90 180 arc\n") 
 753                   wxT("%d %d lineto\n") 
 754                   wxT("%d %d %d 180 270 arc\n") 
 755                   wxT("%d %d lineto\n") 
 756                   wxT("%d %d %d 270 0 arc\n") 
 757                   wxT("%d %d lineto\n") 
 758                   wxT("%d %d %d 0 90 arc\n") 
 759                   wxT("%d %d lineto\n") 
 762                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 763                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 764                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 765                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 766                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 767                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 768                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 769                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 771         CalcBoundingBox( x
, y 
); 
 772         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 775     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 779         /* Draw rectangle anticlockwise */ 
 780         PsPrintf( wxT("newpath\n") 
 781                   wxT("%d %d %d 90 180 arc\n") 
 782                   wxT("%d %d lineto\n") 
 783                   wxT("%d %d %d 180 270 arc\n") 
 784                   wxT("%d %d lineto\n") 
 785                   wxT("%d %d %d 270 0 arc\n") 
 786                   wxT("%d %d lineto\n") 
 787                   wxT("%d %d %d 0 90 arc\n") 
 788                   wxT("%d %d lineto\n") 
 791                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 792                 LogicalToDeviceX(x
), LogicalToDeviceY(y 
+ height 
- rad
), 
 793                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 794                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height
), 
 795                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ height 
- rad
), LogicalToDeviceXRel(rad
), 
 796                 LogicalToDeviceX(x 
+ width
), LogicalToDeviceY(y 
+ rad
), 
 797                 LogicalToDeviceX(x 
+ width 
- rad
), LogicalToDeviceY(y 
+ rad
), LogicalToDeviceXRel(rad
), 
 798                 LogicalToDeviceX(x 
+ rad
), LogicalToDeviceY(y
) ); 
 800         CalcBoundingBox( x
, y 
); 
 801         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 805 void wxPostScriptDC::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 807     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 809     if (m_brush
.GetStyle () != wxTRANSPARENT
) 
 813         PsPrintf( wxT("newpath\n") 
 814                   wxT("%d %d %d %d 0 360 ellipse\n") 
 816                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 817                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 819         CalcBoundingBox( x 
- width
, y 
- height 
); 
 820         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 823     if (m_pen
.GetStyle () != wxTRANSPARENT
) 
 827         PsPrintf( wxT("newpath\n") 
 828                   wxT("%d %d %d %d 0 360 ellipse\n") 
 830                 LogicalToDeviceX(x 
+ width 
/ 2), LogicalToDeviceY(y 
+ height 
/ 2), 
 831                 LogicalToDeviceXRel(width 
/ 2), LogicalToDeviceYRel(height 
/ 2) ); 
 833         CalcBoundingBox( x 
- width
, y 
- height 
); 
 834         CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 838 void wxPostScriptDC::DoDrawIcon( const wxIcon
& icon
, wxCoord x
, wxCoord y 
) 
 840     DrawBitmap( icon
, x
, y
, true ); 
 843 /* this has to be char, not wxChar */ 
 844 static char hexArray
[] = "0123456789ABCDEF"; 
 846 void wxPostScriptDC::DoDrawBitmap( const wxBitmap
& bitmap
, wxCoord x
, wxCoord y
, bool WXUNUSED(useMask
) ) 
 848     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 850     if (!bitmap
.Ok()) return; 
 852     wxImage image 
= bitmap
.ConvertToImage(); 
 854     if (!image
.Ok()) return; 
 856     wxCoord w 
= image
.GetWidth(); 
 857     wxCoord h 
= image
.GetHeight(); 
 859     wxCoord ww 
= LogicalToDeviceXRel(image
.GetWidth()); 
 860     wxCoord hh 
= LogicalToDeviceYRel(image
.GetHeight()); 
 862     wxCoord xx 
= LogicalToDeviceX(x
); 
 863     wxCoord yy 
= LogicalToDeviceY(y 
+ bitmap
.GetHeight()); 
 865     PsPrintf( wxT("/origstate save def\n") 
 866               wxT("20 dict begin\n") 
 867               wxT("/pix %d string def\n") 
 868               wxT("/grays %d string def\n") 
 869               wxT("/npixels 0 def\n") 
 870               wxT("/rgbindx 0 def\n") 
 871               wxT("%d %d translate\n") 
 874               wxT("[%d 0 0 %d 0 %d]\n") 
 875               wxT("{currentfile pix readhexstring pop}\n") 
 876               wxT("false 3 colorimage\n"), 
 877             w
, w
, xx
, yy
, ww
, hh
, w
, h
, w
, -h
, h 
); 
 879     unsigned char* data 
= image
.GetData(); 
 881     // size of the buffer = width*rgb(3)*hexa(2)+'\n' 
 882     wxCharBuffer 
buffer(w
*6 + 1); 
 883     int firstDigit
, secondDigit
; 
 886     for (int j 
= 0; j 
< h
; j
++) 
 888         char* bufferindex 
= buffer
.data(); 
 891         for (int i 
= 0; i 
< w
*3; i
++) 
 893             firstDigit 
= (int)(*data
/16.0); 
 894             secondDigit 
= (int)(*data 
- (firstDigit
*16.0)); 
 895             *(bufferindex
++) = hexArray
[firstDigit
]; 
 896             *(bufferindex
++) = hexArray
[secondDigit
]; 
 900         *(bufferindex
++) = '\n'; 
 906     PsPrint( "origstate restore\n" ); 
 909 void wxPostScriptDC::SetFont( const wxFont
& font 
) 
 911     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
 913     if (!font
.Ok())  return; 
 917     int Style 
= m_font
.GetStyle(); 
 918     int Weight 
= m_font
.GetWeight(); 
 921     switch (m_font
.GetFamily()) 
 926             if (Style 
== wxITALIC
) 
 928                 if (Weight 
== wxBOLD
) 
 929                     name 
= "/Courier-BoldOblique"; 
 931                     name 
= "/Courier-Oblique"; 
 935                 if (Weight 
== wxBOLD
) 
 936                     name 
= "/Courier-Bold"; 
 944             if (Style 
== wxITALIC
) 
 946                 if (Weight 
== wxBOLD
) 
 947                     name 
= "/Times-BoldItalic"; 
 949                     name 
= "/Times-Italic"; 
 953                 if (Weight 
== wxBOLD
) 
 954                     name 
= "/Times-Bold"; 
 956                     name 
= "/Times-Roman"; 
 962             name 
= "/ZapfChancery-MediumItalic"; 
 968             if (Style 
== wxITALIC
) 
 970                 if (Weight 
== wxBOLD
) 
 971                     name 
= "/Helvetica-BoldOblique"; 
 973                     name 
= "/Helvetica-Oblique"; 
 977                 if (Weight 
== wxBOLD
) 
 978                     name 
= "/Helvetica-Bold"; 
 986     // We may legitimately call SetFont before BeginDoc 
 991     PsPrint( " reencodeISO def\n" ); 
 993     PsPrint( " findfont\n" ); 
 996     sprintf( buffer
, "%f scalefont setfont\n", LogicalToDeviceYRel(m_font
.GetPointSize() * 1000) / 1000.0F
); 
 997     // this is a hack - we must scale font size (in pts) according to m_scaleY but 
 998     // LogicalToDeviceYRel works with wxCoord type (int or longint). Se we first convert font size 
 999     // to 1/1000th of pt and then back. 
1000     for (int i 
= 0; i 
< 100; i
++) 
1001         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1005 void wxPostScriptDC::SetPen( const wxPen
& pen 
) 
1007     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1009     if (!pen
.Ok()) return; 
1011     int oldStyle 
= m_pen
.GetStyle(); 
1016     sprintf( buffer
, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen
.GetWidth()) / 1000.0f 
); 
1017     for (int i 
= 0; i 
< 100; i
++) 
1018         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1022      Line style - WRONG: 2nd arg is OFFSET 
1024      Here, I'm afraid you do not conceive meaning of parameters of 'setdash' 
1025      operator correctly. You should look-up this in the Red Book: the 2nd parame- 
1026      ter is not number of values in the array of the first one, but an offset 
1027      into this description of the pattern. I mean a real *offset* not index 
1028      into array. I.e. If the command is [3 4] 1 setdash   is used, then there 
1029      will be first black line *2* units wxCoord, then space 4 units, then the 
1030      pattern of *3* units black, 4 units space will be repeated. 
1033     static const char *dotted 
= "[2 5] 2"; 
1034     static const char *short_dashed 
= "[4 4] 2"; 
1035     static const char *wxCoord_dashed 
= "[4 8] 2"; 
1036     static const char *dotted_dashed 
= "[6 6 2 6] 4"; 
1040     switch (m_pen
.GetStyle()) 
1042         case wxDOT
:           psdash 
= dotted
;         break; 
1043         case wxSHORT_DASH
:    psdash 
= short_dashed
;   break; 
1044         case wxLONG_DASH
:     psdash 
= wxCoord_dashed
; break; 
1045         case wxDOT_DASH
:      psdash 
= dotted_dashed
;  break; 
1049             int nDashes 
= m_pen
.GetDashes (&dashes
); 
1051             for (int i 
= 0; i 
< nDashes
; ++i
) 
1053                 sprintf( buffer
, "%d ", dashes 
[i
] ); 
1056             PsPrint ("] 0 setdash\n"); 
1062         default:              psdash 
= "[] 0";         break; 
1065     if ( psdash 
&& (oldStyle 
!= m_pen
.GetStyle()) ) 
1068         PsPrint( " setdash\n" ); 
1072     unsigned char red 
= m_pen
.GetColour().Red(); 
1073     unsigned char blue 
= m_pen
.GetColour().Blue(); 
1074     unsigned char green 
= m_pen
.GetColour().Green(); 
1078         // Anything not white is black 
1079         if (! (red 
== (unsigned char) 255 && 
1080                blue 
== (unsigned char) 255 && 
1081                green 
== (unsigned char) 255) ) 
1083             red 
= (unsigned char) 0; 
1084             green 
= (unsigned char) 0; 
1085             blue 
= (unsigned char) 0; 
1090     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1092         double redPS 
= (double)(red
) / 255.0; 
1093         double bluePS 
= (double)(blue
) / 255.0; 
1094         double greenPS 
= (double)(green
) / 255.0; 
1097             "%.8f %.8f %.8f setrgbcolor\n", 
1098             redPS
, greenPS
, bluePS 
); 
1099         for (int i 
= 0; i 
< 100; i
++) 
1100             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1105         m_currentBlue 
= blue
; 
1106         m_currentGreen 
= green
; 
1110 void wxPostScriptDC::SetBrush( const wxBrush
& brush 
) 
1112     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1114     if (!brush
.Ok()) return; 
1119     unsigned char red 
= m_brush
.GetColour().Red(); 
1120     unsigned char blue 
= m_brush
.GetColour().Blue(); 
1121     unsigned char green 
= m_brush
.GetColour().Green(); 
1125         // Anything not white is black 
1126         if (! (red 
== (unsigned char) 255 && 
1127                blue 
== (unsigned char) 255 && 
1128                green 
== (unsigned char) 255) ) 
1130             red 
= (unsigned char) 0; 
1131             green 
= (unsigned char) 0; 
1132             blue 
= (unsigned char) 0; 
1137     if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1139         double redPS 
= (double)(red
) / 255.0; 
1140         double bluePS 
= (double)(blue
) / 255.0; 
1141         double greenPS 
= (double)(green
) / 255.0; 
1145                 "%.8f %.8f %.8f setrgbcolor\n", 
1146                 redPS
, greenPS
, bluePS 
); 
1147         for (int i 
= 0; i 
< 100; i
++) 
1148             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1153         m_currentBlue 
= blue
; 
1154         m_currentGreen 
= green
; 
1158 void wxPostScriptDC::DoDrawText( const wxString
& text
, wxCoord x
, wxCoord y 
) 
1160     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1162     if (m_textForegroundColour
.Ok()) 
1164         unsigned char red 
= m_textForegroundColour
.Red(); 
1165         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1166         unsigned char green 
= m_textForegroundColour
.Green(); 
1170             // Anything not white is black 
1171             if (! (red 
== (unsigned char) 255 && 
1172                         blue 
== (unsigned char) 255 && 
1173                         green 
== (unsigned char) 255)) 
1175                 red 
= (unsigned char) 0; 
1176                 green 
= (unsigned char) 0; 
1177                 blue 
= (unsigned char) 0; 
1181         // maybe setgray here ? 
1182         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1184             double redPS 
= (double)(red
) / 255.0; 
1185             double bluePS 
= (double)(blue
) / 255.0; 
1186             double greenPS 
= (double)(green
) / 255.0; 
1190                 "%.8f %.8f %.8f setrgbcolor\n", 
1191                 redPS
, greenPS
, bluePS 
); 
1192             for (size_t i 
= 0; i 
< strlen(buffer
); i
++) 
1193                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1197             m_currentBlue 
= blue
; 
1198             m_currentGreen 
= green
; 
1202     wxCoord text_w
, text_h
, text_descent
; 
1204     GetTextExtent(text
, &text_w
, &text_h
, &text_descent
); 
1206     // VZ: this seems to be unnecessary, so taking it out for now, if it 
1207     //     doesn't create any problems, remove this comment entirely 
1208     //SetFont( m_font ); 
1211     int size 
= m_font
.GetPointSize(); 
1213 //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline 
1214 //    commented by V. Slavik and replaced by accurate version 
1215 //        - note that there is still rounding error in text_descent! 
1216     wxCoord by 
= y 
+ size 
- text_descent
; // baseline 
1218     PsPrintf( wxT("%d %d moveto\n"), LogicalToDeviceX(x
), LogicalToDeviceY(by
) ); 
1221     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1222     size_t len 
= strlen(textbuf
); 
1224     for (i 
= 0; i 
< len
; i
++) 
1226         int c 
= (unsigned char) textbuf
[i
]; 
1227         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1229             /* Cope with special characters */ 
1233         else if ( c 
>= 128 ) 
1235             /* Cope with character codes > 127 */ 
1236             PsPrintf( wxT("\\%o"), c
); 
1244     PsPrint( ") show\n" ); 
1246     if (m_font
.GetUnderlined()) 
1248         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1258                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1259                 m_underlineThickness
, 
1260                 LogicalToDeviceX(x 
+ text_w
), LogicalToDeviceY(uy
) ); 
1261         for (i 
= 0; i 
< 100; i
++) 
1262             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1266     CalcBoundingBox( x
, y 
); 
1267     CalcBoundingBox( x 
+ size 
* text
.length() * 2/3 , y 
); 
1270 void wxPostScriptDC::DoDrawRotatedText( const wxString
& text
, wxCoord x
, wxCoord y
, double angle 
) 
1272     if ( wxIsNullDouble(angle
) ) 
1274         DoDrawText(text
, x
, y
); 
1278     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1282     if (m_textForegroundColour
.Ok()) 
1284         unsigned char red 
= m_textForegroundColour
.Red(); 
1285         unsigned char blue 
= m_textForegroundColour
.Blue(); 
1286         unsigned char green 
= m_textForegroundColour
.Green(); 
1290             // Anything not white is black 
1291             if (! (red 
== (unsigned char) 255 && 
1292                    blue 
== (unsigned char) 255 && 
1293                    green 
== (unsigned char) 255)) 
1295                 red 
= (unsigned char) 0; 
1296                 green 
= (unsigned char) 0; 
1297                 blue 
= (unsigned char) 0; 
1301         // maybe setgray here ? 
1302         if (!(red 
== m_currentRed 
&& green 
== m_currentGreen 
&& blue 
== m_currentBlue
)) 
1304             double redPS 
= (double)(red
) / 255.0; 
1305             double bluePS 
= (double)(blue
) / 255.0; 
1306             double greenPS 
= (double)(green
) / 255.0; 
1310                 "%.8f %.8f %.8f setrgbcolor\n", 
1311                 redPS
, greenPS
, bluePS 
); 
1312             for (int i 
= 0; i 
< 100; i
++) 
1313                 if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1317             m_currentBlue 
= blue
; 
1318             m_currentGreen 
= green
; 
1322     int size 
= m_font
.GetPointSize(); 
1324     PsPrintf( wxT("%d %d moveto\n"), 
1325             LogicalToDeviceX(x
), LogicalToDeviceY(y
)); 
1328     sprintf(buffer
, "%.8f rotate\n", angle
); 
1330     for (i 
= 0; i 
< 100; i
++) 
1332         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1337     const wxWX2MBbuf textbuf 
= text
.mb_str(); 
1338     size_t len 
= strlen(textbuf
); 
1339     for (i 
= 0; i 
< len
; i
++) 
1341         int c 
= (unsigned char) textbuf
[i
]; 
1342         if (c 
== ')' || c 
== '(' || c 
== '\\') 
1344             /* Cope with special characters */ 
1348         else if ( c 
>= 128 ) 
1350             /* Cope with character codes > 127 */ 
1351             PsPrintf( wxT("\\%o"), c
); 
1359     PsPrint( ") show\n" ); 
1361     sprintf( buffer
, "%.8f rotate\n", -angle 
); 
1362     for (i 
= 0; i 
< 100; i
++) 
1364         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1368     if (m_font
.GetUnderlined()) 
1370         wxCoord uy 
= (wxCoord
)(y 
+ size 
- m_underlinePosition
); 
1372         GetTextExtent(text
, &w
, &h
); 
1381                 LogicalToDeviceX(x
), LogicalToDeviceY(uy
), 
1382                 m_underlineThickness
, 
1383                 LogicalToDeviceX(x 
+ w
), LogicalToDeviceY(uy
) ); 
1384         for (i 
= 0; i 
< 100; i
++) 
1386             if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1391     CalcBoundingBox( x
, y 
); 
1392     CalcBoundingBox( x 
+ size 
* text
.length() * 2/3 , y 
); 
1395 void wxPostScriptDC::SetBackground (const wxBrush
& brush
) 
1397     m_backgroundBrush 
= brush
; 
1400 void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function
)) 
1402     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); 
1406 void wxPostScriptDC::DoDrawSpline( wxList 
*points 
) 
1408     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1412     // a and b are not used 
1414     double c
, d
, x1
, y1
, x2
, y2
, x3
, y3
; 
1417     wxList::compatibility_iterator node 
= points
->GetFirst(); 
1418     p 
= (wxPoint 
*)node
->GetData(); 
1422     node 
= node
->GetNext(); 
1423     p 
= (wxPoint 
*)node
->GetData(); 
1430          (double)(x1 
+ c
) / 2; 
1435          (double)(y1 
+ d
) / 2; 
1437     PsPrintf( wxT("newpath\n") 
1438               wxT("%d %d moveto\n") 
1439               wxT("%d %d lineto\n"), 
1440             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1441             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1443     CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1444     CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1446     node 
= node
->GetNext(); 
1449         q 
= (wxPoint 
*)node
->GetData(); 
1457         x3 
= (double)(x2 
+ c
) / 2; 
1458         y3 
= (double)(y2 
+ d
) / 2; 
1460         PsPrintf( wxT("%d %d %d %d %d %d DrawSplineSection\n"), 
1461             LogicalToDeviceX((wxCoord
)x1
), LogicalToDeviceY((wxCoord
)y1
), 
1462             LogicalToDeviceX((wxCoord
)x2
), LogicalToDeviceY((wxCoord
)y2
), 
1463             LogicalToDeviceX((wxCoord
)x3
), LogicalToDeviceY((wxCoord
)y3
) ); 
1465         CalcBoundingBox( (wxCoord
)x1
, (wxCoord
)y1 
); 
1466         CalcBoundingBox( (wxCoord
)x3
, (wxCoord
)y3 
); 
1468         node 
= node
->GetNext(); 
1472        At this point, (x2,y2) and (c,d) are the position of the 
1473        next-to-last and last point respectively, in the point list 
1476     PsPrintf( wxT("%d %d lineto\n") 
1478             LogicalToDeviceX((wxCoord
)c
), LogicalToDeviceY((wxCoord
)d
) ); 
1480 #endif // wxUSE_SPLINES 
1482 wxCoord 
wxPostScriptDC::GetCharWidth() const 
1484     // Chris Breeze: reasonable approximation using wxMODERN/Courier 
1485     return (wxCoord
) (GetCharHeight() * 72.0 / 120.0); 
1488 void wxPostScriptDC::SetPrintData(const wxPrintData
& data
) 
1493     GetSize( NULL
, &h 
); 
1494     SetDeviceLocalOrigin( 0, h 
); 
1497 void wxPostScriptDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp 
) 
1499     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1501     m_signX 
= (xLeftRight 
? 1 : -1); 
1502     m_signY 
= (yBottomUp  
? 1 : -1); 
1504     ComputeScaleAndOrigin(); 
1507 void wxPostScriptDC::SetMapMode(int mode
) 
1509     wxDCBase::SetMapMode(mode
); 
1512 void wxPostScriptDC::SetUserScale(double x
, double y
) 
1514     wxDCBase::SetUserScale(x
,y
); 
1517 void wxPostScriptDC::SetLogicalScale(double x
, double y
) 
1519     wxDCBase::SetLogicalScale(x
,y
); 
1522 void wxPostScriptDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1524     wxDCBase::SetLogicalOrigin(x
,y
); 
1527 void wxPostScriptDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1529     wxDCBase::SetDeviceOrigin(x
,y
); 
1532 void wxPostScriptDC::DoGetSize(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
->GetSizeDeviceUnits().x
; 
1545         h 
= paper
->GetSizeDeviceUnits().y
; 
1548     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1555     if (width
) *width 
= (int)(w 
* ms_PSScaleFactor
); 
1556     if (height
) *height 
= (int)(h 
* ms_PSScaleFactor
); 
1559 void wxPostScriptDC::DoGetSizeMM(int *width
, int *height
) const 
1561     wxPaperSize id 
= m_printData
.GetPaperId(); 
1563     wxPrintPaperType 
*paper 
= wxThePrintPaperDatabase
->FindPaperType(id
); 
1565     if (!paper
) paper 
= wxThePrintPaperDatabase
->FindPaperType(wxPAPER_A4
); 
1571         w 
= paper
->GetWidth() / 10; 
1572         h 
= paper
->GetHeight() / 10; 
1575     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1582     if (width
) *width 
= w
; 
1583     if (height
) *height 
= h
; 
1586 // Resolution in pixels per logical inch 
1587 wxSize 
wxPostScriptDC::GetPPI(void) const 
1589     return wxSize((int)(72 * ms_PSScaleFactor
), 
1590                   (int)(72 * ms_PSScaleFactor
)); 
1594 bool wxPostScriptDC::StartDoc( const wxString
& message 
) 
1596     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1598     if (m_printData
.GetPrintMode() != wxPRINT_MODE_STREAM 
) 
1600         if (m_printData
.GetFilename() == wxEmptyString
) 
1602             wxString filename 
= wxGetTempFileName( wxT("ps") ); 
1603             m_printData
.SetFilename(filename
); 
1606         m_pstream 
= wxFopen( m_printData
.GetFilename(), wxT("w+") ); 
1610             wxLogError( _("Cannot open file for PostScript printing!")); 
1619     PsPrint( "%!PS-Adobe-2.0\n" ); 
1620     PsPrintf( wxT("%%%%Title: %s\n"), m_title
.c_str() ); 
1621     PsPrint( "%%Creator: wxWidgets PostScript renderer\n" ); 
1622     PsPrintf( wxT("%%%%CreationDate: %s\n"), wxNow().c_str() ); 
1623     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1624         PsPrint( "%%Orientation: Landscape\n" ); 
1626         PsPrint( "%%Orientation: Portrait\n" ); 
1628     // PsPrintf( wxT("%%%%Pages: %d\n"), (wxPageNumber - 1) ); 
1630     const wxChar 
*paper
; 
1631     switch (m_printData
.GetPaperId()) 
1633        case wxPAPER_LETTER
: paper 
= wxT("Letter"); break;       // Letter: paper ""; 8 1/2 by 11 inches 
1634        case wxPAPER_LEGAL
: paper 
= wxT("Legal"); break;         // Legal, 8 1/2 by 14 inches 
1635        case wxPAPER_A4
: paper 
= wxT("A4"); break;               // A4 Sheet, 210 by 297 millimeters 
1636        case wxPAPER_TABLOID
: paper 
= wxT("Tabloid"); break;     // Tabloid, 11 by 17 inches 
1637        case wxPAPER_LEDGER
: paper 
= wxT("Ledger"); break;       // Ledger, 17 by 11 inches 
1638        case wxPAPER_STATEMENT
: paper 
= wxT("Statement"); break; // Statement, 5 1/2 by 8 1/2 inches 
1639        case wxPAPER_EXECUTIVE
: paper 
= wxT("Executive"); break; // Executive, 7 1/4 by 10 1/2 inches 
1640        case wxPAPER_A3
: paper 
= wxT("A3"); break;               // A3 sheet, 297 by 420 millimeters 
1641        case wxPAPER_A5
: paper 
= wxT("A5"); break;               // A5 sheet, 148 by 210 millimeters 
1642        case wxPAPER_B4
: paper 
= wxT("B4"); break;               // B4 sheet, 250 by 354 millimeters 
1643        case wxPAPER_B5
: paper 
= wxT("B5"); break;               // B5 sheet, 182-by-257-millimeter paper 
1644        case wxPAPER_FOLIO
: paper 
= wxT("Folio"); break;         // Folio, 8-1/2-by-13-inch paper 
1645        case wxPAPER_QUARTO
: paper 
= wxT("Quaro"); break;        // Quarto, 215-by-275-millimeter paper 
1646        case wxPAPER_10X14
: paper 
= wxT("10x14"); break;         // 10-by-14-inch sheet 
1647        default: paper 
= wxT("A4"); 
1649     PsPrintf( wxT("%%%%DocumentPaperSizes: %s\n"), paper 
); 
1650     PsPrint( "%%EndComments\n\n" ); 
1652     PsPrint( "%%BeginProlog\n" ); 
1653     PsPrint( wxPostScriptHeaderConicTo 
); 
1654     PsPrint( wxPostScriptHeaderEllipse 
); 
1655     PsPrint( wxPostScriptHeaderEllipticArc 
); 
1656     PsPrint( wxPostScriptHeaderColourImage 
); 
1657     PsPrint( wxPostScriptHeaderReencodeISO1 
); 
1658     PsPrint( wxPostScriptHeaderReencodeISO2 
); 
1659     if (wxPostScriptHeaderSpline
) 
1660         PsPrint( wxPostScriptHeaderSpline 
); 
1661     PsPrint( "%%EndProlog\n" ); 
1663     SetBrush( *wxBLACK_BRUSH 
); 
1664     SetPen( *wxBLACK_PEN 
); 
1665     SetBackground( *wxWHITE_BRUSH 
); 
1666     SetTextForeground( *wxBLACK 
); 
1668     // set origin according to paper size 
1669     SetDeviceOrigin( 0,0 ); 
1676 void wxPostScriptDC::EndDoc () 
1678     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1683         PsPrint( "grestore\n" ); 
1687         fclose( m_pstream 
); 
1688         m_pstream 
= (FILE *) NULL
; 
1692     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com> 
1693     wxCoord wx_printer_translate_x
, wx_printer_translate_y
; 
1694     double wx_printer_scale_x
, wx_printer_scale_y
; 
1696     wx_printer_translate_x 
= (wxCoord
)m_printData
.GetPrinterTranslateX(); 
1697     wx_printer_translate_y 
= (wxCoord
)m_printData
.GetPrinterTranslateY(); 
1699     wx_printer_scale_x 
= m_printData
.GetPrinterScaleX(); 
1700     wx_printer_scale_y 
= m_printData
.GetPrinterScaleY(); 
1702     // Compute the bounding box.  Note that it is in the default user 
1703     // coordinate system, thus we have to convert the values. 
1704     wxCoord minX 
= (wxCoord
) LogicalToDeviceX(m_minX
); 
1705     wxCoord minY 
= (wxCoord
) LogicalToDeviceY(m_minY
); 
1706     wxCoord maxX 
= (wxCoord
) LogicalToDeviceX(m_maxX
); 
1707     wxCoord maxY 
= (wxCoord
) LogicalToDeviceY(m_maxY
); 
1709     // LOG2DEV may have changed the minimum to maximum vice versa 
1710     if ( minX 
> maxX 
) { wxCoord tmp 
= minX
; minX 
= maxX
; maxX 
= tmp
; } 
1711     if ( minY 
> maxY 
) { wxCoord tmp 
= minY
; minY 
= maxY
; maxY 
= tmp
; } 
1713     // account for used scaling (boundingbox is before scaling in ps-file) 
1714     double scale_x 
= m_printData
.GetPrinterScaleX() / ms_PSScaleFactor
; 
1715     double scale_y 
= m_printData
.GetPrinterScaleY() / ms_PSScaleFactor
; 
1717     wxCoord llx
, lly
, urx
, ury
; 
1718     llx 
= (wxCoord
) ((minX
+wx_printer_translate_x
)*scale_x
); 
1719     lly 
= (wxCoord
) ((minY
+wx_printer_translate_y
)*scale_y
); 
1720     urx 
= (wxCoord
) ((maxX
+wx_printer_translate_x
)*scale_x
); 
1721     ury 
= (wxCoord
) ((maxY
+wx_printer_translate_y
)*scale_y
); 
1722     // (end of bounding box computation) 
1725     // If we're landscape, our sense of "x" and "y" is reversed. 
1726     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1729         tmp 
= llx
; llx 
= lly
; lly 
= tmp
; 
1730         tmp 
= urx
; urx 
= ury
; ury 
= tmp
; 
1732         // We need either the two lines that follow, or we need to subtract 
1733         // min_x from real_translate_y, which is commented out below. 
1734         llx 
= llx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1735         urx 
= urx 
- (wxCoord
)(m_minX
*wx_printer_scale_y
); 
1738     // The Adobe specifications call for integers; we round as to make 
1739     // the bounding larger. 
1740     PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"), 
1741             (wxCoord
)floor((double)llx
), (wxCoord
)floor((double)lly
), 
1742             (wxCoord
)ceil((double)urx
), (wxCoord
)ceil((double)ury
) ); 
1744     // To check the correctness of the bounding box, postscript commands 
1745     // to draw a box corresponding to the bounding box are generated below. 
1746     // But since we typically don't want to print such a box, the postscript 
1747     // commands are generated within comments.  These lines appear before any 
1748     // adjustment of scale, rotation, or translation, and hence are in the 
1749     // default user coordinates. 
1750     PsPrint( "% newpath\n" ); 
1751     PsPrintf( wxT("%% %d %d moveto\n"), llx
, lly 
); 
1752     PsPrintf( wxT("%% %d %d lineto\n"), urx
, lly 
); 
1753     PsPrintf( wxT("%% %d %d lineto\n"), urx
, ury 
); 
1754     PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx
, ury 
); 
1758     wxPostScriptPrintNativeData 
*data 
= 
1759         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1761     if (m_ok 
&& (m_printData
.GetPrintMode() == wxPRINT_MODE_PRINTER
)) 
1764         command 
+= data
->GetPrinterCommand(); 
1765         command 
+= wxT(" "); 
1766         command 
+= data
->GetPrinterOptions(); 
1767         command 
+= wxT(" "); 
1768         command 
+= m_printData
.GetFilename(); 
1770         wxExecute( command
, true ); 
1771         wxRemoveFile( m_printData
.GetFilename() ); 
1776 void wxPostScriptDC::StartPage() 
1778     wxCHECK_RET( m_ok
, wxT("invalid postscript dc") ); 
1780     PsPrintf( wxT("%%%%Page: %d\n"), wxPageNumber
++ ); 
1782     //  What is this one supposed to do? RR. 
1783 //  *m_pstream << "matrix currentmatrix\n"; 
1785     // Added by Chris Breeze 
1787     // Each page starts with an "initgraphics" which resets the 
1788     // transformation and so we need to reset the origin 
1789     // (and rotate the page for landscape printing) 
1792     wxCoord translate_x
, translate_y
; 
1793     double scale_x
, scale_y
; 
1795     wxPostScriptPrintNativeData 
*data 
= 
1796         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
1798     translate_x 
= (wxCoord
)data
->GetPrinterTranslateX(); 
1799     translate_y 
= (wxCoord
)data
->GetPrinterTranslateY(); 
1801     scale_x 
= data
->GetPrinterScaleX(); 
1802     scale_y 
= data
->GetPrinterScaleY(); 
1804     if (m_printData
.GetOrientation() == wxLANDSCAPE
) 
1807         GetSize( (int*) NULL
, &h 
); 
1809         PsPrint( "90 rotate\n" ); 
1810         // I copied this one from a PostScript tutorial, but to no avail. RR. 
1811         // PsPrint( "90 rotate llx neg ury nef translate\n" ); 
1815     sprintf( buffer
, "%.8f %.8f scale\n", scale_x 
/ ms_PSScaleFactor
, 
1816             scale_y 
/ ms_PSScaleFactor
); 
1817     for (int i 
= 0; i 
< 100; i
++) 
1818         if (buffer
[i
] == ',') buffer
[i
] = '.'; 
1821     PsPrintf( wxT("%d %d translate\n"), translate_x
, translate_y 
); 
1824 void wxPostScriptDC::EndPage () 
1826     wxCHECK_RET( m_ok 
, wxT("invalid postscript dc") ); 
1828     PsPrint( "showpage\n" ); 
1831 bool wxPostScriptDC::DoBlit( wxCoord xdest
, wxCoord ydest
, 
1832                            wxCoord fwidth
, wxCoord fheight
, 
1834                            wxCoord xsrc
, wxCoord ysrc
, 
1835                            int rop
, bool WXUNUSED(useMask
), wxCoord 
WXUNUSED(xsrcMask
), wxCoord 
WXUNUSED(ysrcMask
) ) 
1837     wxCHECK_MSG( m_ok
, false, wxT("invalid postscript dc") ); 
1839     wxCHECK_MSG( source
, false, wxT("invalid source dc") ); 
1841     /* blit into a bitmap */ 
1842     wxBitmap 
bitmap( (int)fwidth
, (int)fheight 
); 
1844     memDC
.SelectObject(bitmap
); 
1845     memDC
.Blit(0, 0, fwidth
, fheight
, source
, xsrc
, ysrc
, rop
); /* TODO: Blit transparently? */ 
1846     memDC
.SelectObject(wxNullBitmap
); 
1848     /* draw bitmap. scaling and positioning is done there */ 
1849     DrawBitmap( bitmap
, xdest
, ydest 
); 
1854 wxCoord 
wxPostScriptDC::GetCharHeight() const 
1857         return m_font
.GetPointSize(); 
1862 void wxPostScriptDC::DoGetTextExtent(const wxString
& string
, 
1863                                      wxCoord 
*x
, wxCoord 
*y
, 
1864                                      wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1865                                      const wxFont 
*theFont 
) const 
1867     const wxFont 
*fontToUse 
= theFont
; 
1869     if (!fontToUse
) fontToUse 
= &m_font
; 
1871     wxCHECK_RET( fontToUse
, wxT("GetTextExtent: no font defined") ); 
1877         if (descent
) (*descent
) = 0; 
1878         if (externalLeading
) (*externalLeading
) = 0; 
1884     const wxWX2MBbuf strbuf 
= string
.mb_str(); 
1886 #if !wxUSE_AFM_FOR_POSTSCRIPT 
1887     /* Provide a VERY rough estimate (avoid using it). 
1888      * Produces accurate results for mono-spaced font 
1889      * such as Courier (aka wxMODERN) */ 
1894         height 
= fontToUse
->GetPointSize(); 
1897         *x 
= strlen (strbuf
) * height 
* 72 / 120; 
1899         *y 
= (wxCoord
) (height 
* 1.32);    /* allow for descender */ 
1900     if (descent
) *descent 
= 0; 
1901     if (externalLeading
) *externalLeading 
= 0; 
1904     /* method for calculating string widths in postscript: 
1905     /  read in the AFM (adobe font metrics) file for the 
1906     /  actual font, parse it and extract the character widths 
1907     /  and also the descender. this may be improved, but for now 
1908     /  it works well. the AFM file is only read in if the 
1909     /  font is changed. this may be chached in the future. 
1910     /  calls to GetTextExtent with the font unchanged are rather 
1913     /  for each font and style used there is an AFM file necessary. 
1914     /  currently i have only files for the roman font family. 
1915     /  I try to get files for the other ones! 
1917     /  CAVE: the size of the string is currently always calculated 
1918     /        in 'points' (1/72 of an inch). this should later on be 
1919     /        changed to depend on the mapping mode. 
1920     /  CAVE: the path to the AFM files must be set before calling this 
1921     /        function. this is usually done by a call like the following: 
1922     /        wxSetAFMPath("d:\\wxw161\\afm\\"); 
1926     /    wxPostScriptDC dc(NULL, true); 
1928     /      wxSetAFMPath("d:\\wxw161\\afm\\"); 
1929     /      dc.StartDoc("Test"); 
1932     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); 
1933     /      dc.GetTextExtent("Hallo",&w,&h); 
1938     /  by steve (stefan.hammes@urz.uni-heidelberg.de) 
1940     /  updated: 14.05.95 */ 
1942     /* these static vars are for storing the state between calls */ 
1943     static int lastFamily
= INT_MIN
; 
1944     static int lastSize
= INT_MIN
; 
1945     static int lastStyle
= INT_MIN
; 
1946     static int lastWeight
= INT_MIN
; 
1947     static int lastDescender 
= INT_MIN
; 
1948     static int lastWidths
[256]; /* widths of the characters */ 
1950     double UnderlinePosition 
= 0.0; 
1951     double UnderlineThickness 
= 0.0; 
1953     // Get actual parameters 
1954     int Family 
= fontToUse
->GetFamily(); 
1955     int Size 
=   fontToUse
->GetPointSize(); 
1956     int Style 
=  fontToUse
->GetStyle(); 
1957     int Weight 
= fontToUse
->GetWeight(); 
1959     // If we have another font, read the font-metrics 
1960     if (Family
!=lastFamily 
|| Size
!=lastSize 
|| Style
!=lastStyle 
|| Weight
!=lastWeight
) 
1962         // Store actual values 
1963         lastFamily 
= Family
; 
1966         lastWeight 
= Weight
; 
1975                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBoO.afm"); 
1976                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("CourBo.afm"); 
1977                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("CourO.afm"); 
1978                 else name 
= wxT("Cour.afm"); 
1983                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBoO.afm"); 
1984                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("TimesBo.afm"); 
1985                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("TimesO.afm"); 
1986                 else name 
= wxT("TimesRo.afm"); 
1991                 name 
= wxT("Zapf.afm"); 
1997                 if ((Style 
== wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBoO.afm"); 
1998                 else if ((Style 
!= wxITALIC
) && (Weight 
== wxBOLD
)) name 
= wxT("HelvBo.afm"); 
1999                 else if ((Style 
== wxITALIC
) && (Weight 
!= wxBOLD
)) name 
= wxT("HelvO.afm"); 
2000                 else name 
= wxT("Helv.afm"); 
2005         FILE *afmFile 
= NULL
; 
2007         // Get the directory of the AFM files 
2010         // VZ: I don't know if the cast always works under Unix but it clearly 
2011         //     never does under Windows where the pointer is 
2012         //     wxWindowsPrintNativeData and so calling GetFontMetricPath() on 
2015         wxPostScriptPrintNativeData 
*data 
= 
2016             wxDynamicCast(m_printData
.GetNativeData(), wxPostScriptPrintNativeData
); 
2018         if (data 
&& !data
->GetFontMetricPath().empty()) 
2020             afmName 
= data
->GetFontMetricPath(); 
2021             afmName 
<< wxFILE_SEP_PATH 
<< name
; 
2025         if ( !afmName
.empty() ) 
2026             afmFile 
= wxFopen(afmName
, wxT("r")); 
2030 #if defined(__UNIX__) && !defined(__VMS__) 
2031            afmName 
= wxGetDataDir(); 
2033            afmName 
= wxStandardPaths::Get().GetDataDir(); 
2034 #endif // __UNIX__/!__UNIX__ 
2036            afmName 
<<  wxFILE_SEP_PATH
 
2037 #if defined(__LINUX__) || defined(__FREEBSD__) 
2038                    << wxT("gs_afm") << wxFILE_SEP_PATH
 
2040                    << wxT("afm") << wxFILE_SEP_PATH
 
2043            afmFile 
= wxFopen(afmName
,wxT("r")); 
2046         /* 2. open and process the file 
2047            /  a short explanation of the AFM format: 
2048            /  we have for each character a line, which gives its size 
2051            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; 
2053            /  that means, we have a character with ascii code 63, and width 
2054            /  (444/1000 * fontSize) points. 
2055            /  the other data is ignored for now! 
2057            /  when the font has changed, we read in the right AFM file and store the 
2058            /  character widths in an array, which is processed below (see point 3.). */ 
2061             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName
.c_str() ); 
2062             wxLogDebug( wxT("               using approximate values")); 
2063             for (int i
=0; i
<256; i
++) lastWidths
[i
] = 500; /* an approximate value */ 
2064             lastDescender 
= -150; /* dito. */ 
2068             /* init the widths array */ 
2069             for(int i
=0; i
<256; i
++) lastWidths
[i
] = INT_MIN
; 
2070             /* some variables for holding parts of a line */ 
2071             char cString
[10], semiString
[10], WXString
[10]; 
2072             char descString
[20]; 
2073             char upString
[30], utString
[30]; 
2077             /* read in the file and parse it */ 
2078             while(fgets(line
,sizeof(line
),afmFile
)!=NULL
) 
2080                 /* A.) check for descender definition */ 
2081                 if (strncmp(line
,"Descender",9)==0) 
2083                     if ((sscanf(line
,"%s%d",descString
,&lastDescender
)!=2) || 
2084                             (strcmp(descString
,"Descender")!=0)) 
2086                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName
.c_str(),line 
); 
2089                 /* JC 1.) check for UnderlinePosition */ 
2090                 else if(strncmp(line
,"UnderlinePosition",17)==0) 
2092                     if ((sscanf(line
,"%s%lf",upString
,&UnderlinePosition
)!=2) || 
2093                             (strcmp(upString
,"UnderlinePosition")!=0)) 
2095                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName
.c_str(), line 
); 
2098                 /* JC 2.) check for UnderlineThickness */ 
2099                 else if(strncmp(line
,"UnderlineThickness",18)==0) 
2101                     if ((sscanf(line
,"%s%lf",utString
,&UnderlineThickness
)!=2) || 
2102                             (strcmp(utString
,"UnderlineThickness")!=0)) 
2104                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName
.c_str(), line 
); 
2107                 /* JC 3.) check for EncodingScheme */ 
2108                 else if(strncmp(line
,"EncodingScheme",14)==0) 
2110                     if ((sscanf(line
,"%s%s",utString
,encString
)!=2) || 
2111                             (strcmp(utString
,"EncodingScheme")!=0)) 
2113                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName
.c_str(), line 
); 
2115                     else if (strncmp(encString
, "AdobeStandardEncoding", 21)) 
2117                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"), 
2118                                 afmName
.c_str(),line
, encString
); 
2121                 /* B.) check for char-width */ 
2122                 else if(strncmp(line
,"C ",2)==0) 
2124                     if (sscanf(line
,"%s%d%s%s%d",cString
,&ascii
,semiString
,WXString
,&cWidth
)!=5) 
2126                         wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName
.c_str(),line
); 
2128                     if(strcmp(cString
,"C")!=0 || strcmp(semiString
,";")!=0 || strcmp(WXString
,"WX")!=0) 
2130                         wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName
.c_str(),line
); 
2132                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ 
2133                     if (ascii
>=0 && ascii
<256) 
2135                         lastWidths
[ascii
] = cWidth
; /* store width */ 
2139                         /* MATTHEW: this happens a lot; don't print an error */ 
2140                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ 
2143                 /* C.) ignore other entries. */ 
2147         /* hack to compute correct values for german 'Umlaute' 
2148            /  the correct way would be to map the character names 
2149            /  like 'adieresis' to corresp. positions of ISOEnc and read 
2150            /  these values from AFM files, too. Maybe later ... */ 
2152         // NB: casts to int are needed to suppress gcc 3.3 warnings 
2153         lastWidths
[196] = lastWidths
[(int)'A'];  // Ä 
2154         lastWidths
[228] = lastWidths
[(int)'a'];  // ä 
2155         lastWidths
[214] = lastWidths
[(int)'O'];  // Ö 
2156         lastWidths
[246] = lastWidths
[(int)'o'];  // ö 
2157         lastWidths
[220] = lastWidths
[(int)'U'];  // Ü 
2158         lastWidths
[252] = lastWidths
[(int)'u'];  // ü 
2159         lastWidths
[223] = lastWidths
[(int)251];  // ß 
2161         /* JC: calculate UnderlineThickness/UnderlinePosition */ 
2163         // VS: dirty, but is there any better solution? 
2165         pt 
= (double*) &m_underlinePosition
; 
2166         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlinePosition 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2167         pt 
= (double*) &m_underlineThickness
; 
2168         *pt 
= LogicalToDeviceYRel((wxCoord
)(UnderlineThickness 
* fontToUse
->GetPointSize())) / 1000.0f
; 
2173     /* 3. now the font metrics are read in, calc size this 
2174        /  is done by adding the widths of the characters in the 
2175        /  string. they are given in 1/1000 of the size! */ 
2178     wxCoord height
=Size
; /* by default */ 
2180     for(p
=(unsigned char *)wxMBSTRINGCAST strbuf
; *p
; p
++) 
2182         if(lastWidths
[*p
]== INT_MIN
) 
2184             wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p
,*p
); 
2185             sum 
+= lastWidths
[(unsigned char)' ']; /* assume space */ 
2189             sum 
+= lastWidths
[*p
]; 
2193     double widthSum 
= sum
; 
2195     widthSum 
/= 1000.0F
; 
2197     /* add descender to height (it is usually a negative value) */ 
2198     //if (lastDescender != INT_MIN) 
2200     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ 
2202     // - commented by V. Slavik - height already contains descender in it 
2203     //   (judging from few experiments) 
2205     /* return size values */ 
2207         *x 
= (wxCoord
)widthSum
; 
2211     /* return other parameters */ 
2214         if(lastDescender
!=INT_MIN
) 
2216             *descent 
= (wxCoord
)(((-lastDescender
)/1000.0F
) * Size
); /* MATTHEW: forgot scale */ 
2224     /* currently no idea how to calculate this! */ 
2225     if (externalLeading
) *externalLeading 
= 0; 
2230 // print postscript datas via required method (file, stream) 
2231 #if !wxUSE_UTF8_LOCALE_ONLY 
2232 void wxPostScriptDC::DoPsPrintfFormatWchar(const wxChar 
*fmt
, ...) 
2235     va_start(argptr
, fmt
); 
2237     PsPrint( wxString::FormatV( fmt
, argptr 
) ); 
2239 #endif // !wxUSE_UTF8_LOCALE_ONLY 
2241 #if wxUSE_UNICODE_UTF8 
2242 void wxPostScriptDC::DoPsPrintfFormatUtf8(const char *fmt
, ...) 
2245     va_start(argptr
, fmt
); 
2247     PsPrint( wxString::FormatV( fmt
, argptr 
) ); 
2249 #endif // wxUSE_UNICODE_UTF8 
2251 void wxPostScriptDC::PsPrint( const wxString
& str 
) 
2253     const wxWX2MBbuf 
psdata(str
.mb_str(wxConvUTF8
)); 
2255     wxPostScriptPrintNativeData 
*data 
= 
2256         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2258     switch (m_printData
.GetPrintMode()) 
2261         // append to output stream 
2262         case wxPRINT_MODE_STREAM
: 
2264                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2265                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2266                 outputstream
->Write( psdata
, strlen( psdata 
) ); 
2269 #endif // wxUSE_STREAMS 
2271         // save data into file 
2273             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2274             fwrite( psdata
, 1, strlen( psdata 
), m_pstream 
); 
2278 void wxPostScriptDC::PsPrint( int ch 
) 
2280     wxPostScriptPrintNativeData 
*data 
= 
2281         (wxPostScriptPrintNativeData 
*) m_printData
.GetNativeData(); 
2283     switch (m_printData
.GetPrintMode()) 
2286         // append to output stream 
2287         case wxPRINT_MODE_STREAM
: 
2289                 wxOutputStream
* outputstream 
= data
->GetOutputStream(); 
2290                 wxCHECK_RET( outputstream
, wxT("invalid outputstream") ); 
2291                 outputstream
->PutC( (char)ch 
); 
2294 #endif // wxUSE_STREAMS 
2296         // save data into file 
2298             wxCHECK_RET( m_pstream
, wxT("invalid postscript dc") ); 
2299             fputc( ch
, m_pstream 
); 
2303 #endif // wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT