home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / generic / dcpsg.cpp < prev    next >
C/C++ Source or Header  |  2002-08-27  |  76KB  |  2,323 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        dcpsg.cpp
  3. // Purpose:     Generic wxPostScriptDC implementation
  4. // Author:      Julian Smart, Robert Roebling, Markus Holzhem
  5. // Modified by:
  6. // Created:     04/01/98
  7. // RCS-ID:      $Id: dcpsg.cpp,v 1.85 2002/08/25 18:41:59 RR Exp $
  8. // Copyright:   (c) Julian Smart and Markus Holzem
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "dcpsg.h"
  14. #endif
  15.  
  16. #include "wx/wxprec.h"
  17.  
  18. #ifdef __BORLANDC__
  19.     #pragma hdrstop
  20. #endif
  21.  
  22. #ifndef WX_PRECOMP
  23. #endif // WX_PRECOMP
  24.  
  25. #if wxUSE_PRINTING_ARCHITECTURE
  26.  
  27. #if wxUSE_POSTSCRIPT
  28.  
  29. #include "wx/setup.h"
  30.  
  31. #include "wx/window.h"
  32. #include "wx/dcmemory.h"
  33. #include "wx/utils.h"
  34. #include "wx/intl.h"
  35. #include "wx/filedlg.h"
  36. #include "wx/app.h"
  37. #include "wx/msgdlg.h"
  38. #include "wx/image.h"
  39. #include "wx/log.h"
  40. #include "wx/generic/dcpsg.h"
  41. #include "wx/printdlg.h"
  42. #include "wx/button.h"
  43. #include "wx/stattext.h"
  44. #include "wx/radiobox.h"
  45. #include "wx/textctrl.h"
  46. #include "wx/prntbase.h"
  47. #include "wx/paper.h"
  48. #include "wx/filefn.h"
  49.  
  50. #include <math.h>
  51.  
  52. #ifdef __WXMSW__
  53.  
  54. #ifdef DrawText
  55. #undef DrawText
  56. #endif
  57.  
  58. #ifdef StartDoc
  59. #undef StartDoc
  60. #endif
  61.  
  62. #ifdef GetCharWidth
  63. #undef GetCharWidth
  64. #endif
  65.  
  66. #ifdef FindWindow
  67. #undef FindWindow
  68. #endif
  69.  
  70. #endif
  71.  
  72. //-----------------------------------------------------------------------------
  73. // start and end of document/page
  74. //-----------------------------------------------------------------------------
  75.  
  76. static const char *wxPostScriptHeaderConicTo = "\
  77. /conicto {\n\
  78.     /to_y exch def\n\
  79.     /to_x exch def\n\
  80.     /conic_cntrl_y exch def\n\
  81.     /conic_cntrl_x exch def\n\
  82.     currentpoint\n\
  83.     /p0_y exch def\n\
  84.     /p0_x exch def\n\
  85.     /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\
  86.     /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\
  87.     /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\
  88.     /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\
  89.     p1_x p1_y p2_x p2_y to_x to_y curveto\n\
  90. }  bind def\n\
  91. ";
  92.       
  93. static const char *wxPostScriptHeaderEllipse = "\
  94. /ellipsedict 8 dict def\n\
  95. ellipsedict /mtrx matrix put\n\
  96. /ellipse {\n\
  97.     ellipsedict begin\n\
  98.     /endangle exch def\n\
  99.     /startangle exch def\n\
  100.     /yrad exch def\n\
  101.     /xrad exch def\n\
  102.     /y exch def\n\
  103.     /x exch def\n\
  104.     /savematrix mtrx currentmatrix def\n\
  105.     x y translate\n\
  106.     xrad yrad scale\n\
  107.     0 0 1 startangle endangle arc\n\
  108.     savematrix setmatrix\n\
  109.     end\n\
  110.     } def\n\
  111. ";
  112.  
  113. static const char *wxPostScriptHeaderEllipticArc= "\
  114. /ellipticarcdict 8 dict def\n\
  115. ellipticarcdict /mtrx matrix put\n\
  116. /ellipticarc\n\
  117. { ellipticarcdict begin\n\
  118.   /do_fill exch def\n\
  119.   /endangle exch def\n\
  120.   /startangle exch def\n\
  121.   /yrad exch def\n\
  122.   /xrad exch def \n\
  123.   /y exch def\n\
  124.   /x exch def\n\
  125.   /savematrix mtrx currentmatrix def\n\
  126.   x y translate\n\
  127.   xrad yrad scale\n\
  128.   do_fill { 0 0 moveto } if\n\
  129.   0 0 1 startangle endangle arc\n\
  130.   savematrix setmatrix\n\
  131.   do_fill { fill }{ stroke } ifelse\n\
  132.   end\n\
  133. } def\n";
  134.  
  135. static const char *wxPostScriptHeaderSpline = "\
  136. /DrawSplineSection {\n\
  137.     /y3 exch def\n\
  138.     /x3 exch def\n\
  139.     /y2 exch def\n\
  140.     /x2 exch def\n\
  141.     /y1 exch def\n\
  142.     /x1 exch def\n\
  143.     /xa x1 x2 x1 sub 0.666667 mul add def\n\
  144.     /ya y1 y2 y1 sub 0.666667 mul add def\n\
  145.     /xb x3 x2 x3 sub 0.666667 mul add def\n\
  146.     /yb y3 y2 y3 sub 0.666667 mul add def\n\
  147.     x1 y1 lineto\n\
  148.     xa ya xb yb x3 y3 curveto\n\
  149.     } def\n\
  150. ";
  151.  
  152. static const char *wxPostScriptHeaderColourImage = "\
  153. %% define 'colorimage' if it isn't defined\n\
  154. %%   ('colortogray' and 'mergeprocs' come from xwd2ps\n\
  155. %%     via xgrab)\n\
  156. /colorimage where   %% do we know about 'colorimage'?\n\
  157.   { pop }           %% yes: pop off the 'dict' returned\n\
  158.   {                 %% no:  define one\n\
  159.     /colortogray {  %% define an RGB->I function\n\
  160.       /rgbdata exch store    %% call input 'rgbdata'\n\
  161.       rgbdata length 3 idiv\n\
  162.       /npixls exch store\n\
  163.       /rgbindx 0 store\n\
  164.       0 1 npixls 1 sub {\n\
  165.         grays exch\n\
  166.         rgbdata rgbindx       get 20 mul    %% Red\n\
  167.         rgbdata rgbindx 1 add get 32 mul    %% Green\n\
  168.         rgbdata rgbindx 2 add get 12 mul    %% Blue\n\
  169.         add add 64 idiv      %% I = .5G + .31R + .18B\n\
  170.         put\n\
  171.         /rgbindx rgbindx 3 add store\n\
  172.       } for\n\
  173.       grays 0 npixls getinterval\n\
  174.     } bind def\n\
  175. \n\
  176.     %% Utility procedure for colorimage operator.\n\
  177.     %% This procedure takes two procedures off the\n\
  178.     %% stack and merges them into a single procedure.\n\
  179. \n\
  180.     /mergeprocs { %% def\n\
  181.       dup length\n\
  182.       3 -1 roll\n\
  183.       dup\n\
  184.       length\n\
  185.       dup\n\
  186.       5 1 roll\n\
  187.       3 -1 roll\n\
  188.       add\n\
  189.       array cvx\n\
  190.       dup\n\
  191.       3 -1 roll\n\
  192.       0 exch\n\
  193.       putinterval\n\
  194.       dup\n\
  195.       4 2 roll\n\
  196.       putinterval\n\
  197.     } bind def\n\
  198. \n\
  199.     /colorimage { %% def\n\
  200.       pop pop     %% remove 'false 3' operands\n\
  201.       {colortogray} mergeprocs\n\
  202.       image\n\
  203.     } bind def\n\
  204.   } ifelse          %% end of 'false' case\n\
  205. ";
  206.  
  207. #ifndef __WXGTK20__
  208. static char wxPostScriptHeaderReencodeISO1[] =
  209.     "\n/reencodeISO {\n"
  210. "dup dup findfont dup length dict begin\n"
  211. "{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n"
  212. "/Encoding ISOLatin1Encoding def\n"
  213. "currentdict end definefont\n"
  214. "} def\n"
  215. "/ISOLatin1Encoding [\n"
  216. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  217. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  218. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  219. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  220. "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n"
  221. "/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n"
  222. "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n"
  223. "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n"
  224. "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n"
  225. "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n"
  226. "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n"
  227. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  228. "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
  229. "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n"
  230. "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n";
  231.  
  232. static char wxPostScriptHeaderReencodeISO2[] =
  233. "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n"
  234. "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n"
  235. "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n"
  236. "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n"
  237. "/guillemotright/onequarter/onehalf/threequarters/questiondown\n"
  238. "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n"
  239. "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n"
  240. "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n"
  241. "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n"
  242. "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n"
  243. "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n"
  244. "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n"
  245. "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n"
  246. "/yacute/thorn/ydieresis\n"
  247.         "] def\n\n";
  248. #endif
  249.  
  250. //-------------------------------------------------------------------------------
  251. // wxPostScriptDC
  252. //-------------------------------------------------------------------------------
  253.  
  254. IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC, wxDC)
  255.  
  256. float wxPostScriptDC::ms_PSScaleFactor = 10.0;
  257.  
  258. void wxPostScriptDC::SetResolution(int ppi)
  259. {
  260.     ms_PSScaleFactor = (float)ppi / 72.0;
  261. }
  262.  
  263. int wxPostScriptDC::GetResolution()
  264. {
  265.     return (int)(ms_PSScaleFactor * 72.0);
  266. }
  267.  
  268. //-------------------------------------------------------------------------------
  269.  
  270. wxPostScriptDC::wxPostScriptDC ()
  271. {
  272.     m_pstream = (FILE*) NULL;
  273.  
  274.     m_currentRed = 0;
  275.     m_currentGreen = 0;
  276.     m_currentBlue = 0;
  277.  
  278.     m_pageNumber = 0;
  279.  
  280.     m_clipping = FALSE;
  281.  
  282.     m_underlinePosition = 0.0;
  283.     m_underlineThickness = 0.0;
  284.  
  285.     m_signX =  1;  // default x-axis left to right
  286.     m_signY = -1;  // default y-axis bottom up -> top down
  287. }
  288.  
  289. wxPostScriptDC::wxPostScriptDC (const wxPrintData& printData)
  290. {
  291.     m_pstream = (FILE*) NULL;
  292.  
  293.     m_currentRed = 0;
  294.     m_currentGreen = 0;
  295.     m_currentBlue = 0;
  296.  
  297.     m_pageNumber = 0;
  298.  
  299.     m_clipping = FALSE;
  300.  
  301.     m_underlinePosition = 0.0;
  302.     m_underlineThickness = 0.0;
  303.  
  304.     m_signX =  1;  // default x-axis left to right
  305.     m_signY = -1;  // default y-axis bottom up -> top down
  306.  
  307.     m_printData = printData;
  308.  
  309.     m_ok = TRUE;
  310. }
  311.  
  312. wxPostScriptDC::~wxPostScriptDC ()
  313. {
  314.     if (m_pstream)
  315.     {
  316.         fclose( m_pstream );
  317.         m_pstream = (FILE*) NULL;
  318.     }
  319. }
  320.  
  321. bool wxPostScriptDC::Ok() const
  322. {
  323.   return m_ok;
  324. }
  325.  
  326. void wxPostScriptDC::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h)
  327. {
  328.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  329.  
  330.     if (m_clipping) DestroyClippingRegion();
  331.  
  332.     wxDC::DoSetClippingRegion(x, y, w, h);
  333.  
  334.     m_clipping = TRUE;
  335.     fprintf( m_pstream,
  336.             "gsave\n newpath\n"
  337.             "%d %d moveto\n"
  338.             "%d %d lineto\n"
  339.             "%d %d lineto\n"
  340.             "%d %d lineto\n"
  341.             "closepath clip newpath\n",
  342.             LogicalToDeviceX(x),   LogicalToDeviceY(y),
  343.             LogicalToDeviceX(x+w), LogicalToDeviceY(y),
  344.             LogicalToDeviceX(x+w), LogicalToDeviceY(y+h),
  345.             LogicalToDeviceX(x),   LogicalToDeviceY(y+h) );
  346. }
  347.  
  348.  
  349. void wxPostScriptDC::DestroyClippingRegion()
  350. {
  351.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  352.  
  353.     if (m_clipping)
  354.     {
  355.         m_clipping = FALSE;
  356.         fprintf( m_pstream, "grestore\n" );
  357.     }
  358.  
  359.     wxDC::DestroyClippingRegion();
  360. }
  361.  
  362. void wxPostScriptDC::Clear()
  363. {
  364.     wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") );
  365. }
  366.  
  367. bool wxPostScriptDC::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style))
  368. {
  369.     wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") );
  370.     return FALSE;
  371. }
  372.  
  373. bool wxPostScriptDC::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const
  374. {
  375.     wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") );
  376.     return FALSE;
  377. }
  378.  
  379. void wxPostScriptDC::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
  380. {
  381.     wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") );
  382. }
  383.  
  384. void wxPostScriptDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
  385. {
  386.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  387.  
  388.     if  (m_pen.GetStyle() == wxTRANSPARENT) return;
  389.  
  390.     SetPen( m_pen );
  391.  
  392.     fprintf( m_pstream,
  393.             "newpath\n"
  394.             "%d %d moveto\n"
  395.             "%d %d lineto\n"
  396.             "stroke\n",
  397.             LogicalToDeviceX(x1), LogicalToDeviceY(y1),
  398.             LogicalToDeviceX(x2), LogicalToDeviceY (y2) );
  399.  
  400.     CalcBoundingBox( x1, y1 );
  401.     CalcBoundingBox( x2, y2 );
  402. }
  403.  
  404. #define RAD2DEG 57.29577951308
  405.  
  406. void wxPostScriptDC::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
  407. {
  408.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  409.  
  410.     wxCoord dx = x1 - xc;
  411.     wxCoord dy = y1 - yc;
  412.     wxCoord radius = (wxCoord) sqrt( (double)(dx*dx+dy*dy) );
  413.     double alpha1, alpha2;
  414.  
  415.     if (x1 == x2 && y1 == y2)
  416.     {
  417.         alpha1 = 0.0;
  418.         alpha2 = 360.0;
  419.     }
  420.     else if (radius == 0.0)
  421.     {
  422.         alpha1 = alpha2 = 0.0;
  423.     }
  424.     else
  425.     {
  426.         alpha1 = (x1 - xc == 0) ?
  427.             (y1 - yc < 0) ? 90.0 : -90.0 :
  428.                 -atan2(double(y1-yc), double(x1-xc)) * RAD2DEG;
  429.         alpha2 = (x2 - xc == 0) ?
  430.             (y2 - yc < 0) ? 90.0 : -90.0 :
  431.                 -atan2(double(y2-yc), double(x2-xc)) * RAD2DEG;
  432.     }
  433.     while (alpha1 <= 0)   alpha1 += 360;
  434.     while (alpha2 <= 0)   alpha2 += 360; // adjust angles to be between
  435.     while (alpha1 > 360)  alpha1 -= 360; // 0 and 360 degree
  436.     while (alpha2 > 360)  alpha2 -= 360;
  437.  
  438.     if (m_brush.GetStyle() != wxTRANSPARENT)
  439.     {
  440.         SetBrush( m_brush );
  441.  
  442.         fprintf( m_pstream,
  443.                 "newpath\n"
  444.                 "%d %d %d %d %d %d ellipse\n"
  445.                 "%d %d lineto\n"
  446.                 "closepath\n"
  447.                 "fill\n",
  448.                 LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2,
  449.                 LogicalToDeviceX(xc), LogicalToDeviceY(yc) );
  450.  
  451.         CalcBoundingBox( xc-radius, yc-radius );
  452.         CalcBoundingBox( xc+radius, yc+radius );
  453.     }
  454.  
  455.     if (m_pen.GetStyle() != wxTRANSPARENT)
  456.     {
  457.         SetPen( m_pen );
  458.  
  459.         fprintf( m_pstream,
  460.                 "newpath\n"
  461.                 "%d %d %d %d %d %d ellipse\n"
  462.                 "%d %d lineto\n"
  463.                 "stroke\n"
  464.                 "fill\n",
  465.                 LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2,
  466.                 LogicalToDeviceX(xc), LogicalToDeviceY(yc) );
  467.  
  468.         CalcBoundingBox( xc-radius, yc-radius );
  469.         CalcBoundingBox( xc+radius, yc+radius );
  470.     }
  471. }
  472.  
  473. void wxPostScriptDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
  474. {
  475.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  476.  
  477.     if (sa>=360 || sa<=-360) sa=sa-int(sa/360)*360;
  478.     if (ea>=360 || ea<=-360) ea=ea-int(ea/360)*360;
  479.     if (sa<0) sa+=360;
  480.     if (ea<0) ea+=360;
  481.  
  482.     if (sa==ea)
  483.     {
  484.         DrawEllipse(x,y,w,h);
  485.         return;
  486.     }
  487.  
  488.     if (m_brush.GetStyle () != wxTRANSPARENT)
  489.     {
  490.         SetBrush( m_brush );
  491.  
  492.         fprintf( m_pstream,
  493.                 "newpath\n"
  494.                 "%d %d %d %d %d %d true ellipticarc\n",
  495.                 LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), (wxCoord)sa, (wxCoord)ea );
  496.  
  497.         CalcBoundingBox( x ,y );
  498.         CalcBoundingBox( x+w, y+h );
  499.     }
  500.  
  501.     if (m_pen.GetStyle () != wxTRANSPARENT)
  502.     {
  503.         SetPen( m_pen );
  504.  
  505.         fprintf(m_pstream,
  506.                 "newpath\n"
  507.                 "%d %d %d %d %d %d false ellipticarc\n",
  508.                 LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), (wxCoord)sa, (wxCoord)ea );
  509.  
  510.         CalcBoundingBox( x ,y );
  511.         CalcBoundingBox( x+w, y+h );
  512.     }
  513. }
  514.  
  515. void wxPostScriptDC::DoDrawPoint (wxCoord x, wxCoord y)
  516. {
  517.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  518.  
  519.     if (m_pen.GetStyle() == wxTRANSPARENT) return;
  520.  
  521.     SetPen (m_pen);
  522.  
  523.     fprintf( m_pstream,
  524.             "newpath\n"
  525.             "%d %d moveto\n"
  526.             "%d %d lineto\n"
  527.             "stroke\n",
  528.             LogicalToDeviceX(x),   LogicalToDeviceY(y),
  529.             LogicalToDeviceX(x+1), LogicalToDeviceY(y) );
  530.  
  531.     CalcBoundingBox( x, y );
  532. }
  533.  
  534. void wxPostScriptDC::DoDrawPolygon (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle))
  535. {
  536.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  537.  
  538.     if (n <= 0) return;
  539.  
  540.     if (m_brush.GetStyle () != wxTRANSPARENT)
  541.     {
  542.         SetBrush( m_brush );
  543.  
  544.         fprintf( m_pstream, "newpath\n" );
  545.  
  546.         wxCoord xx = LogicalToDeviceX(points[0].x + xoffset);
  547.         wxCoord yy = LogicalToDeviceY(points[0].y + yoffset);
  548.  
  549.         fprintf( m_pstream, "%d %d moveto\n", xx, yy );
  550.  
  551.         CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
  552.  
  553.         for (int i = 1; i < n; i++)
  554.         {
  555.             xx = LogicalToDeviceX(points[i].x + xoffset);
  556.             yy = LogicalToDeviceY(points[i].y + yoffset);
  557.  
  558.             fprintf( m_pstream, "%d %d lineto\n", xx, yy );
  559.  
  560.             CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
  561.         }
  562.  
  563.         fprintf( m_pstream, "fill\n" );
  564.     }
  565.  
  566.     if (m_pen.GetStyle () != wxTRANSPARENT)
  567.     {
  568.         SetPen( m_pen );
  569.  
  570.         fprintf( m_pstream, "newpath\n" );
  571.  
  572.         wxCoord xx = LogicalToDeviceX(points[0].x + xoffset);
  573.         wxCoord yy = LogicalToDeviceY(points[0].y + yoffset);
  574.  
  575.         fprintf( m_pstream, "%d %d moveto\n", xx, yy );
  576.  
  577.         CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
  578.  
  579.         for (int i = 1; i < n; i++)
  580.         {
  581.             xx = LogicalToDeviceX(points[i].x + xoffset);
  582.             yy = LogicalToDeviceY(points[i].y + yoffset);
  583.  
  584.             fprintf( m_pstream, "%d %d lineto\n", xx, yy );
  585.  
  586.             CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
  587.         }
  588.  
  589.         fprintf( m_pstream, "closepath\n" );
  590.         fprintf( m_pstream, "stroke\n" );
  591.     }
  592. }
  593.  
  594. void wxPostScriptDC::DoDrawLines (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
  595. {
  596.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  597.  
  598.     if (m_pen.GetStyle() == wxTRANSPARENT) return;
  599.  
  600.     if (n <= 0) return;
  601.  
  602.     SetPen (m_pen);
  603.  
  604.     int i;
  605.     for ( i =0; i<n ; i++ )
  606.     {
  607.         CalcBoundingBox( LogicalToDeviceX(points[i].x+xoffset), LogicalToDeviceY(points[i].y+yoffset));
  608.     }
  609.  
  610.     fprintf( m_pstream,
  611.             "newpath\n"
  612.             "%d %d moveto\n",
  613.             LogicalToDeviceX(points[0].x+xoffset), LogicalToDeviceY(points[0].y+yoffset) );
  614.  
  615.     for (i = 1; i < n; i++)
  616.     {
  617.         fprintf( m_pstream,
  618.                 "%d %d lineto\n",
  619.                 LogicalToDeviceX(points[i].x+xoffset), LogicalToDeviceY(points[i].y+yoffset) );
  620.     }
  621.  
  622.     fprintf( m_pstream, "stroke\n" );
  623. }
  624.  
  625. void wxPostScriptDC::DoDrawRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
  626. {
  627.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  628.  
  629.     if (m_brush.GetStyle () != wxTRANSPARENT)
  630.     {
  631.         SetBrush( m_brush );
  632.  
  633.         fprintf( m_pstream,
  634.                 "newpath\n"
  635.                 "%d %d moveto\n"
  636.                 "%d %d lineto\n"
  637.                 "%d %d lineto\n"
  638.                 "%d %d lineto\n"
  639.                 "closepath\n"
  640.                 "fill\n",
  641.                 LogicalToDeviceX(x),         LogicalToDeviceY(y),
  642.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y),
  643.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y + height),
  644.                 LogicalToDeviceX(x),         LogicalToDeviceY(y + height) );
  645.  
  646.         CalcBoundingBox( x, y );
  647.         CalcBoundingBox( x + width, y + height );
  648.     }
  649.  
  650.     if (m_pen.GetStyle () != wxTRANSPARENT)
  651.     {
  652.         SetPen (m_pen);
  653.  
  654.         fprintf( m_pstream,
  655.                 "newpath\n"
  656.                 "%d %d moveto\n"
  657.                 "%d %d lineto\n"
  658.                 "%d %d lineto\n"
  659.                 "%d %d lineto\n"
  660.                 "closepath\n"
  661.                 "stroke\n",
  662.                 LogicalToDeviceX(x),         LogicalToDeviceY(y),
  663.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y),
  664.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y + height),
  665.                 LogicalToDeviceX(x),         LogicalToDeviceY(y + height) );
  666.  
  667.         CalcBoundingBox( x, y );
  668.         CalcBoundingBox( x + width, y + height );
  669.     }
  670. }
  671.  
  672. void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
  673. {
  674.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  675.  
  676.     if (radius < 0.0)
  677.     {
  678.         // Now, a negative radius is interpreted to mean
  679.         // 'the proportion of the smallest X or Y dimension'
  680.         double smallest = 0.0;
  681.         if (width < height)
  682.         smallest = width;
  683.         else
  684.         smallest = height;
  685.         radius =  (-radius * smallest);
  686.     }
  687.  
  688.     wxCoord rad = (wxCoord) radius;
  689.  
  690.     if (m_brush.GetStyle () != wxTRANSPARENT)
  691.     {
  692.         SetBrush( m_brush );
  693.  
  694.         /* Draw rectangle anticlockwise */
  695.         fprintf( m_pstream,
  696.                 "newpath\n"
  697.                 "%d %d %d 90 180 arc\n"
  698.                 "%d %d moveto\n"
  699.                 "%d %d %d 180 270 arc\n"
  700.                 "%d %d lineto\n"
  701.                 "%d %d %d 270 0 arc\n"
  702.                 "%d %d lineto\n"
  703.                 "%d %d %d 0 90 arc\n"
  704.                 "%d %d lineto\n"
  705.                 "closepath\n"
  706.                 "fill\n",
  707.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y + rad), LogicalToDeviceXRel(rad),
  708.                 LogicalToDeviceX(x), LogicalToDeviceY(y + rad),
  709.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y + height - rad), LogicalToDeviceXRel(rad),
  710.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + height),
  711.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + height - rad), LogicalToDeviceXRel(rad),
  712.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y + rad),
  713.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + rad), LogicalToDeviceXRel(rad),
  714.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y) );
  715.  
  716.         CalcBoundingBox( x, y );
  717.         CalcBoundingBox( x + width, y + height );
  718.     }
  719.  
  720.     if (m_pen.GetStyle () != wxTRANSPARENT)
  721.     {
  722.         SetPen (m_pen);
  723.  
  724.         /* Draw rectangle anticlockwise */
  725.         fprintf( m_pstream,
  726.                 "newpath\n"
  727.                 "%d %d %d 90 180 arc\n"
  728.                 "%d %d moveto\n"
  729.                 "%d %d %d 180 270 arc\n"
  730.                 "%d %d lineto\n"
  731.                 "%d %d %d 270 0 arc\n"
  732.                 "%d %d lineto\n"
  733.                 "%d %d %d 0 90 arc\n"
  734.                 "%d %d lineto\n"
  735.                 "closepath\n"
  736.                 "stroke\n",
  737.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y + rad), LogicalToDeviceXRel(rad),
  738.                 LogicalToDeviceX(x), LogicalToDeviceY(y + rad),
  739.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y + height - rad), LogicalToDeviceXRel(rad),
  740.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + height),
  741.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + height - rad), LogicalToDeviceXRel(rad),
  742.                 LogicalToDeviceX(x + width), LogicalToDeviceY(y + rad),
  743.                 LogicalToDeviceX(x + width - rad), LogicalToDeviceY(y + rad), LogicalToDeviceXRel(rad),
  744.                 LogicalToDeviceX(x + rad), LogicalToDeviceY(y) );
  745.  
  746.         CalcBoundingBox( x, y );
  747.         CalcBoundingBox( x + width, y + height );
  748.     }
  749. }
  750.  
  751. void wxPostScriptDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
  752. {
  753.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  754.  
  755.     if (m_brush.GetStyle () != wxTRANSPARENT)
  756.     {
  757.         SetBrush (m_brush);
  758.  
  759.         fprintf( m_pstream,
  760.                 "newpath\n"
  761.                 "%d %d %d %d 0 360 ellipse\n"
  762.                 "fill\n",
  763.                 LogicalToDeviceX(x + width / 2), LogicalToDeviceY(y + height / 2),
  764.                 LogicalToDeviceXRel(width / 2), LogicalToDeviceYRel(height / 2) );
  765.  
  766.         CalcBoundingBox( x - width, y - height );
  767.         CalcBoundingBox( x + width, y + height );
  768.     }
  769.  
  770.     if (m_pen.GetStyle () != wxTRANSPARENT)
  771.     {
  772.         SetPen (m_pen);
  773.  
  774.         fprintf( m_pstream,
  775.                 "newpath\n"
  776.                 "%d %d %d %d 0 360 ellipse\n"
  777.                 "stroke\n",
  778.                 LogicalToDeviceX(x + width / 2), LogicalToDeviceY(y + height / 2),
  779.                 LogicalToDeviceXRel(width / 2), LogicalToDeviceYRel(height / 2) );
  780.  
  781.         CalcBoundingBox( x - width, y - height );
  782.         CalcBoundingBox( x + width, y + height );
  783.     }
  784. }
  785.  
  786. void wxPostScriptDC::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y )
  787. {
  788.     DrawBitmap( icon, x, y, TRUE );
  789. }
  790.  
  791. /* this has to be char, not wxChar */
  792. static char hexArray[] = "0123456789ABCDEF";
  793. static void LocalDecToHex( int dec, char *buf )
  794. {
  795.     int firstDigit = (int)(dec/16.0);
  796.     int secondDigit = (int)(dec - (firstDigit*16.0));
  797.     buf[0] = hexArray[firstDigit];
  798.     buf[1] = hexArray[secondDigit];
  799.     buf[2] = 0;
  800. }
  801.  
  802. void wxPostScriptDC::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
  803. {
  804.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  805.  
  806.     if (!bitmap.Ok()) return;
  807.  
  808.     wxImage image = bitmap.ConvertToImage();
  809.  
  810.     if (!image.Ok()) return;
  811.  
  812.     wxCoord w = image.GetWidth();
  813.     wxCoord h = image.GetHeight();
  814.  
  815.     wxCoord ww = LogicalToDeviceXRel(image.GetWidth());
  816.     wxCoord hh = LogicalToDeviceYRel(image.GetHeight());
  817.  
  818.     wxCoord xx = LogicalToDeviceX(x);
  819.     wxCoord yy = LogicalToDeviceY(y + bitmap.GetHeight());
  820.  
  821.     fprintf( m_pstream,
  822.             "/origstate save def\n"
  823.             "20 dict begin\n"
  824.             "/pix %d string def\n"
  825.             "/grays %d string def\n"
  826.             "/npixels 0 def\n"
  827.             "/rgbindx 0 def\n"
  828.             "%d %d translate\n"
  829.             "%d %d scale\n"
  830.             "%d %d 8\n"
  831.             "[%d 0 0 %d 0 %d]\n"
  832.             "{currentfile pix readhexstring pop}\n"
  833.             "false 3 colorimage\n",
  834.             w, w, xx, yy, ww, hh, w, h, w, -h, h );
  835.  
  836.  
  837.     for (int j = 0; j < h; j++)
  838.     {
  839.         for (int i = 0; i < w; i++)
  840.         {
  841.             char buffer[5];
  842.             LocalDecToHex( image.GetRed(i,j), buffer );
  843.             fprintf( m_pstream, buffer );
  844.             LocalDecToHex( image.GetGreen(i,j), buffer );
  845.             fprintf( m_pstream, buffer );
  846.             LocalDecToHex( image.GetBlue(i,j), buffer );
  847.             fprintf( m_pstream, buffer );
  848.         }
  849.         fprintf( m_pstream, "\n" );
  850.     }
  851.  
  852.     fprintf( m_pstream, "end\n" );
  853.     fprintf( m_pstream, "origstate restore\n" );
  854. }
  855.  
  856. void wxPostScriptDC::SetFont( const wxFont& font )
  857. {
  858.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  859.  
  860.     if (!font.Ok())  return;
  861.  
  862.     m_font = font;
  863.  
  864. #ifndef __WXGTK20__
  865.     int Style = m_font.GetStyle();
  866.     int Weight = m_font.GetWeight();
  867.  
  868.     const char *name;
  869.     switch (m_font.GetFamily())
  870.     {
  871.         case wxTELETYPE:
  872.         case wxMODERN:
  873.         {
  874.             if (Style == wxITALIC)
  875.             {
  876.                 if (Weight == wxBOLD)
  877.                     name = "/Courier-BoldOblique";
  878.                 else
  879.                     name = "/Courier-Oblique";
  880.             }
  881.             else
  882.             {
  883.                 if (Weight == wxBOLD)
  884.                     name = "/Courier-Bold";
  885.                 else
  886.                     name = "/Courier";
  887.             }
  888.             break;
  889.         }
  890.         case wxROMAN:
  891.         {
  892.             if (Style == wxITALIC)
  893.             {
  894.                 if (Weight == wxBOLD)
  895.                     name = "/Times-BoldItalic";
  896.                 else
  897.                     name = "/Times-Italic";
  898.             }
  899.             else
  900.             {
  901.                 if (Weight == wxBOLD)
  902.                     name = "/Times-Bold";
  903.                 else
  904.                     name = "/Times-Roman";
  905.             }
  906.             break;
  907.         }
  908.         case wxSCRIPT:
  909.         {
  910.             name = "/ZapfChancery-MediumItalic";
  911.             Style  = wxNORMAL;
  912.             Weight = wxNORMAL;
  913.             break;
  914.         }
  915.         case wxSWISS:
  916.         default:
  917.         {
  918.             if (Style == wxITALIC)
  919.             {
  920.                 if (Weight == wxBOLD)
  921.                     name = "/Helvetica-BoldOblique";
  922.                 else
  923.                     name = "/Helvetica-Oblique";
  924.             }
  925.             else
  926.             {
  927.                 if (Weight == wxBOLD)
  928.                     name = "/Helvetica-Bold";
  929.                 else
  930.                     name = "/Helvetica";
  931.             }
  932.             break;
  933.         }
  934.     }
  935.  
  936.     fprintf( m_pstream, name );
  937.     fprintf( m_pstream, " reencodeISO def\n" );
  938.     fprintf( m_pstream, name );
  939.     fprintf( m_pstream, " findfont\n" );
  940.  
  941.     char buffer[100];
  942.     sprintf( buffer, "%f scalefont setfont\n", LogicalToDeviceYRel(m_font.GetPointSize() * 1000) / 1000.0F);
  943.                 // this is a hack - we must scale font size (in pts) according to m_scaleY but
  944.                 // LogicalToDeviceYRel works with wxCoord type (int or longint). Se we first convert font size
  945.                 // to 1/1000th of pt and then back.
  946.     for (int i = 0; i < 100; i++)
  947.         if (buffer[i] == ',') buffer[i] = '.';
  948.     fprintf( m_pstream, buffer );
  949. #endif
  950. }
  951.  
  952. void wxPostScriptDC::SetPen( const wxPen& pen )
  953. {
  954.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  955.  
  956.     if (!pen.Ok()) return;
  957.  
  958.     int oldStyle = m_pen.GetStyle();
  959.  
  960.     m_pen = pen;
  961.  
  962.     {
  963.         char buffer[100];
  964.         #ifdef __WXMSW__
  965.         sprintf( buffer, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen.GetWidth()) / 1000.0f );
  966.         #else
  967.         sprintf( buffer, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen.GetWidth()) / 1000.0f );
  968.         #endif
  969.         for (int i = 0; i < 100; i++)
  970.             if (buffer[i] == ',') buffer[i] = '.';
  971.         fprintf( m_pstream, buffer );
  972.     }
  973.  
  974. /*
  975.      Line style - WRONG: 2nd arg is OFFSET
  976.  
  977.      Here, I'm afraid you do not conceive meaning of parameters of 'setdash'
  978.      operator correctly. You should look-up this in the Red Book: the 2nd parame-
  979.      ter is not number of values in the array of the first one, but an offset
  980.      into this description of the pattern. I mean a real *offset* not index
  981.      into array. I.e. If the command is [3 4] 1 setdash   is used, then there
  982.      will be first black line *2* units wxCoord, then space 4 units, then the
  983.      pattern of *3* units black, 4 units space will be repeated.
  984. */
  985.  
  986.     static const char *dotted = "[2 5] 2";
  987.     static const char *short_dashed = "[4 4] 2";
  988.     static const char *wxCoord_dashed = "[4 8] 2";
  989.     static const char *dotted_dashed = "[6 6 2 6] 4";
  990.  
  991.     const char *psdash = (char *) NULL;
  992.     switch (m_pen.GetStyle())
  993.     {
  994.         case wxDOT:           psdash = dotted;         break;
  995.         case wxSHORT_DASH:    psdash = short_dashed;   break;
  996.         case wxLONG_DASH:     psdash = wxCoord_dashed;    break;
  997.         case wxDOT_DASH:      psdash = dotted_dashed;  break;
  998.         case wxSOLID:
  999.         case wxTRANSPARENT:
  1000.         default:              psdash = "[] 0";         break;
  1001.     }
  1002.  
  1003.     if (oldStyle != m_pen.GetStyle())
  1004.     {
  1005.         fprintf( m_pstream, psdash );
  1006.         fprintf( m_pstream," setdash\n" );
  1007.     }
  1008.  
  1009.     // Line colour
  1010.     unsigned char red = m_pen.GetColour().Red();
  1011.     unsigned char blue = m_pen.GetColour().Blue();
  1012.     unsigned char green = m_pen.GetColour().Green();
  1013.  
  1014.     if (!m_colour)
  1015.     {
  1016.         // Anything not white is black
  1017.         if (! (red == (unsigned char) 255 &&
  1018.                blue == (unsigned char) 255 &&
  1019.                green == (unsigned char) 255) )
  1020.         {
  1021.             red = (unsigned char) 0;
  1022.             green = (unsigned char) 0;
  1023.             blue = (unsigned char) 0;
  1024.         }
  1025.         // setgray here ?
  1026.     }
  1027.  
  1028.     if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
  1029.     {
  1030.         double redPS = (double)(red) / 255.0;
  1031.         double bluePS = (double)(blue) / 255.0;
  1032.         double greenPS = (double)(green) / 255.0;
  1033.  
  1034.         char buffer[100];
  1035.         sprintf( buffer,
  1036.                 "%.8f %.8f %.8f setrgbcolor\n",
  1037.                 redPS, greenPS, bluePS );
  1038.         for (int i = 0; i < 100; i++)
  1039.             if (buffer[i] == ',') buffer[i] = '.';
  1040.         fprintf( m_pstream, buffer );
  1041.  
  1042.         m_currentRed = red;
  1043.         m_currentBlue = blue;
  1044.         m_currentGreen = green;
  1045.     }
  1046. }
  1047.  
  1048. void wxPostScriptDC::SetBrush( const wxBrush& brush )
  1049. {
  1050.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1051.  
  1052.     if (!brush.Ok()) return;
  1053.  
  1054.     m_brush = brush;
  1055.  
  1056.     // Brush colour
  1057.     unsigned char red = m_brush.GetColour().Red();
  1058.     unsigned char blue = m_brush.GetColour().Blue();
  1059.     unsigned char green = m_brush.GetColour().Green();
  1060.  
  1061.     if (!m_colour)
  1062.     {
  1063.         // Anything not white is black
  1064.         if (! (red == (unsigned char) 255 &&
  1065.                blue == (unsigned char) 255 &&
  1066.                green == (unsigned char) 255) )
  1067.         {
  1068.             red = (unsigned char) 0;
  1069.             green = (unsigned char) 0;
  1070.             blue = (unsigned char) 0;
  1071.         }
  1072.         // setgray here ?
  1073.     }
  1074.  
  1075.     if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
  1076.     {
  1077.         double redPS = (double)(red) / 255.0;
  1078.         double bluePS = (double)(blue) / 255.0;
  1079.         double greenPS = (double)(green) / 255.0;
  1080.  
  1081.         char buffer[100];
  1082.         sprintf( buffer,
  1083.                 "%.8f %.8f %.8f setrgbcolor\n",
  1084.                 redPS, greenPS, bluePS );
  1085.         for (int i = 0; i < 100; i++)
  1086.             if (buffer[i] == ',') buffer[i] = '.';
  1087.         fprintf( m_pstream, buffer );
  1088.  
  1089.         m_currentRed = red;
  1090.         m_currentBlue = blue;
  1091.         m_currentGreen = green;
  1092.     }
  1093. }
  1094.  
  1095. #ifdef __WXGTK20__
  1096.  
  1097. #define PANGO_ENABLE_ENGINE
  1098.  
  1099. #include "wx/gtk/private.h"
  1100. #include "wx/fontutil.h"
  1101. #include "gtk/gtk.h"
  1102. #include <pango/pangoft2.h>
  1103. #include <freetype/ftglyph.h>
  1104.  
  1105. #ifndef FT_Outline_Decompose
  1106.   FT_EXPORT( FT_Error )  FT_Outline_Decompose(
  1107.                            FT_Outline*              outline,
  1108.                            const FT_Outline_Funcs*  interface,
  1109.                            void*                    user );
  1110. #endif
  1111.  
  1112. typedef struct _OutlineInfo OutlineInfo;
  1113. struct _OutlineInfo {
  1114.   FILE *file;
  1115. };
  1116.  
  1117. static int paps_move_to( FT_Vector* to,
  1118.              void *user_data)
  1119. {
  1120.   OutlineInfo *outline_info = (OutlineInfo*)user_data;
  1121.   fprintf(outline_info->file, "%d %d moveto\n",
  1122.       (int)to->x ,
  1123.       (int)to->y );
  1124.   return 0;
  1125. }
  1126.  
  1127. static int paps_line_to( FT_Vector*  to,
  1128.              void *user_data)
  1129. {
  1130.   OutlineInfo *outline_info = (OutlineInfo*)user_data;
  1131.   fprintf(outline_info->file, "%d %d lineto\n",
  1132.       (int)to->x ,
  1133.       (int)to->y );
  1134.   return 0;
  1135. }
  1136.  
  1137. static int paps_conic_to( FT_Vector*  control,
  1138.               FT_Vector*  to,
  1139.               void *user_data)
  1140. {
  1141.   OutlineInfo *outline_info = (OutlineInfo*)user_data;
  1142.   fprintf(outline_info->file, "%d %d %d %d conicto\n",
  1143.       (int)control->x  ,
  1144.       (int)control->y  ,
  1145.       (int)to->x   ,
  1146.       (int)to->y  );
  1147.   return 0;
  1148. }
  1149.  
  1150. static int paps_cubic_to( FT_Vector*  control1,
  1151.               FT_Vector*  control2,
  1152.               FT_Vector*  to,
  1153.               void *user_data)
  1154. {
  1155.   OutlineInfo *outline_info = (OutlineInfo*)user_data;
  1156.   fprintf(outline_info->file,
  1157.       "%d %d %d %d %d %d curveto\n",
  1158.       (int)control1->x , 
  1159.       (int)control1->y ,
  1160.       (int)control2->x ,
  1161.       (int)control2->y ,
  1162.       (int)to->x ,
  1163.       (int)to->y );
  1164.   return 0;
  1165. }
  1166.  
  1167. void draw_bezier_outline(FILE *file,
  1168.              FT_Face face,
  1169.              FT_UInt glyph_index,
  1170.              int pos_x,
  1171.              int pos_y,
  1172.              int scale_x,
  1173.              int scale_y )
  1174. {
  1175.   FT_Int load_flags = FT_LOAD_NO_BITMAP;
  1176.   FT_Glyph glyph;
  1177.  
  1178.   FT_Outline_Funcs outlinefunc = 
  1179.   {
  1180.     paps_move_to,
  1181.     paps_line_to,
  1182.     paps_conic_to,
  1183.     paps_cubic_to
  1184.   };
  1185.   
  1186.   OutlineInfo outline_info;
  1187.   outline_info.file = file;
  1188.  
  1189.   fprintf(file, "gsave\n");
  1190.   fprintf(file, "%d %d translate\n", pos_x, pos_y );
  1191.   // FT2 scales outlines to 26.6 pixels so the code below
  1192.   // should read 26600 instead of the 60000.
  1193.   fprintf(file, "%d 60000 div %d 60000 div scale\n", scale_x, scale_y );
  1194.   fprintf(file, "0 0 0 setrgbcolor\n");
  1195.  
  1196.   FT_Load_Glyph(face, glyph_index, load_flags);
  1197.   FT_Get_Glyph (face->glyph, &glyph);
  1198.   FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline),
  1199.                         &outlinefunc, &outline_info);
  1200.   fprintf(file, "closepath fill grestore \n");
  1201.   
  1202.   FT_Done_Glyph (glyph);
  1203. }
  1204.  
  1205. #endif
  1206.  
  1207. void wxPostScriptDC::DoDrawText( const wxString& text, wxCoord x, wxCoord y )
  1208. {
  1209.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1210.  
  1211. #ifdef __WXGTK20__
  1212.     int dpi = GetResolution();
  1213.     dpi = 300;
  1214.     PangoContext *context = pango_ft2_get_context ( dpi, dpi );
  1215.  
  1216.     pango_context_set_language (context, pango_language_from_string ("en_US"));
  1217.     pango_context_set_base_dir (context, PANGO_DIRECTION_LTR );
  1218.  
  1219.     pango_context_set_font_description (context, m_font.GetNativeFontInfo()->description );
  1220.  
  1221.     PangoLayout *layout = pango_layout_new (context);
  1222. #if wxUSE_UNICODE
  1223.     wxCharBuffer buffer = wxConvUTF8.cWC2MB( text );
  1224. #else
  1225.     wxCharBuffer buffer = wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( text ) );
  1226. #endif
  1227.     pango_layout_set_text( layout, (const char*) buffer, strlen(buffer) );
  1228.  
  1229.     PangoRectangle rect;
  1230.     pango_layout_get_extents(layout, NULL, &rect);
  1231.     
  1232.     int xx = x * PANGO_SCALE;
  1233.     int yy = y * PANGO_SCALE + (rect.height*2/3);
  1234.     
  1235.     int scale_x = LogicalToDeviceXRel( 1000 );
  1236.     int scale_y = LogicalToDeviceYRel( 1000 );
  1237.     
  1238.     // Loop over lines in layout
  1239.     int num_lines = pango_layout_get_line_count( layout );
  1240.     for (int i = 0; i < num_lines; i++)
  1241.     {
  1242.         PangoLayoutLine *line = pango_layout_get_line( layout, i );
  1243.         
  1244.         // Loop over runs in line
  1245.         GSList *runs_list = line->runs;
  1246.         while (runs_list)
  1247.         {
  1248.             PangoLayoutRun *run = (PangoLayoutRun*) runs_list->data;
  1249.             PangoItem *item = run->item;
  1250.             PangoGlyphString *glyphs = run->glyphs;
  1251.             PangoAnalysis *analysis = &item->analysis;
  1252.             PangoFont *font = analysis->font;
  1253.             FT_Face ft_face = pango_ft2_font_get_face(font);
  1254.             
  1255.             int num_glyphs = glyphs->num_glyphs;
  1256.             for (int glyph_idx = 0; glyph_idx < num_glyphs; glyph_idx++)
  1257.             {
  1258.                 PangoGlyphGeometry geometry = glyphs->glyphs[glyph_idx].geometry;
  1259.                 int pos_x = xx + geometry.x_offset;
  1260.                 int pos_y = yy - geometry.y_offset;
  1261.                 xx += geometry.width;
  1262.                 
  1263.                 draw_bezier_outline( m_pstream, ft_face,
  1264.                   (FT_UInt)(glyphs->glyphs[glyph_idx].glyph),
  1265.                   LogicalToDeviceX( pos_x / PANGO_SCALE ), 
  1266.                   LogicalToDeviceY( pos_y / PANGO_SCALE ),
  1267.                   scale_x, scale_y );
  1268.             }
  1269.             runs_list = runs_list->next;
  1270.         }
  1271.     }
  1272.  
  1273.     g_object_unref( G_OBJECT( layout ) );
  1274. #else
  1275.     wxCoord text_w, text_h, text_descent;
  1276.  
  1277.     GetTextExtent(text, &text_w, &text_h, &text_descent);
  1278.  
  1279.     // VZ: this seems to be unnecessary, so taking it out for now, if it
  1280.     //     doesn't create any problems, remove this comment entirely
  1281.     //SetFont( m_font );
  1282.  
  1283.     if (m_textForegroundColour.Ok())
  1284.     {
  1285.         unsigned char red = m_textForegroundColour.Red();
  1286.         unsigned char blue = m_textForegroundColour.Blue();
  1287.         unsigned char green = m_textForegroundColour.Green();
  1288.  
  1289.         if (!m_colour)
  1290.         {
  1291.             // Anything not white is black
  1292.             if (! (red == (unsigned char) 255 &&
  1293.                         blue == (unsigned char) 255 &&
  1294.                         green == (unsigned char) 255))
  1295.             {
  1296.                 red = (unsigned char) 0;
  1297.                 green = (unsigned char) 0;
  1298.                 blue = (unsigned char) 0;
  1299.             }
  1300.         }
  1301.  
  1302.         // maybe setgray here ?
  1303.         if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
  1304.         {
  1305.             double redPS = (double)(red) / 255.0;
  1306.             double bluePS = (double)(blue) / 255.0;
  1307.             double greenPS = (double)(green) / 255.0;
  1308.  
  1309.             char buffer[100];
  1310.             sprintf( buffer,
  1311.                 "%.8f %.8f %.8f setrgbcolor\n",
  1312.                 redPS, greenPS, bluePS );
  1313.             for (int i = 0; i < 100; i++)
  1314.                 if (buffer[i] == ',') buffer[i] = '.';
  1315.             fprintf( m_pstream, buffer );
  1316.  
  1317.             m_currentRed = red;
  1318.             m_currentBlue = blue;
  1319.             m_currentGreen = green;
  1320.         }
  1321.     }
  1322.  
  1323.     int size = m_font.GetPointSize();
  1324.  
  1325. //    wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline
  1326. //    commented by V. Slavik and replaced by accurate version
  1327. //        - note that there is still rounding error in text_descent!
  1328.     wxCoord by = y + size - text_descent; // baseline
  1329.     fprintf( m_pstream, "%d %d moveto\n", LogicalToDeviceX(x), LogicalToDeviceY(by) );
  1330.  
  1331.     fprintf( m_pstream, "(" );
  1332.     const wxWX2MBbuf textbuf = text.mb_str();
  1333.     size_t len = strlen(textbuf);
  1334.     size_t i;
  1335.     for (i = 0; i < len; i++)
  1336.     {
  1337.         int c = (unsigned char) textbuf[i];
  1338.         if (c == ')' || c == '(' || c == '\\')
  1339.         {
  1340.             /* Cope with special characters */
  1341.             fprintf( m_pstream, "\\" );
  1342.             fputc(c, m_pstream);
  1343.         }
  1344.         else if ( c >= 128 )
  1345.         {
  1346.             /* Cope with character codes > 127 */
  1347.             fprintf(m_pstream, "\\%o", c);
  1348.         }
  1349.         else
  1350.         {
  1351.             fputc(c, m_pstream);
  1352.         }
  1353.     }
  1354.  
  1355.     fprintf( m_pstream, ") show\n" );
  1356.  
  1357.     if (m_font.GetUnderlined())
  1358.     {
  1359.         wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
  1360.         char buffer[100];
  1361.  
  1362.         sprintf( buffer,
  1363.                 "gsave\n"
  1364.                 "%d %d moveto\n"
  1365.                 "%f setlinewidth\n"
  1366.                 "%d %d lineto\n"
  1367.                 "stroke\n"
  1368.                 "grestore\n",
  1369.                 LogicalToDeviceX(x), LogicalToDeviceY(uy),
  1370.                 m_underlineThickness,
  1371.                 LogicalToDeviceX(x + text_w), LogicalToDeviceY(uy) );
  1372.         for (i = 0; i < 100; i++)
  1373.             if (buffer[i] == ',') buffer[i] = '.';
  1374.         fprintf( m_pstream, buffer );
  1375.     }
  1376.  
  1377.     CalcBoundingBox( x, y );
  1378.     CalcBoundingBox( x + size * text.Length() * 2/3 , y );
  1379. #endif
  1380. }
  1381.  
  1382. void wxPostScriptDC::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle )
  1383. {
  1384.     if (angle == 0.0)
  1385.     {
  1386.         DoDrawText(text, x, y);
  1387.         return;
  1388.     }
  1389.  
  1390.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1391.  
  1392.     SetFont( m_font );
  1393.  
  1394.     if (m_textForegroundColour.Ok())
  1395.     {
  1396.         unsigned char red = m_textForegroundColour.Red();
  1397.         unsigned char blue = m_textForegroundColour.Blue();
  1398.         unsigned char green = m_textForegroundColour.Green();
  1399.  
  1400.         if (!m_colour)
  1401.         {
  1402.             // Anything not white is black
  1403.             if (! (red == (unsigned char) 255 &&
  1404.                    blue == (unsigned char) 255 &&
  1405.                    green == (unsigned char) 255))
  1406.             {
  1407.                 red = (unsigned char) 0;
  1408.                 green = (unsigned char) 0;
  1409.                 blue = (unsigned char) 0;
  1410.             }
  1411.         }
  1412.  
  1413.         // maybe setgray here ?
  1414.         if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
  1415.         {
  1416.             double redPS = (double)(red) / 255.0;
  1417.             double bluePS = (double)(blue) / 255.0;
  1418.             double greenPS = (double)(green) / 255.0;
  1419.  
  1420.             char buffer[100];
  1421.             sprintf( buffer,
  1422.                 "%.8f %.8f %.8f setrgbcolor\n",
  1423.                 redPS, greenPS, bluePS );
  1424.             for (int i = 0; i < 100; i++)
  1425.                 if (buffer[i] == ',') buffer[i] = '.';
  1426.             fprintf( m_pstream, buffer );
  1427.  
  1428.             m_currentRed = red;
  1429.             m_currentBlue = blue;
  1430.             m_currentGreen = green;
  1431.         }
  1432.     }
  1433.  
  1434.     int size = m_font.GetPointSize();
  1435.  
  1436.     long by = y + (long)floor( double(size) * 2.0 / 3.0 ); // approximate baseline
  1437.  
  1438.     // FIXME only correct for 90 degrees
  1439.     fprintf(m_pstream, "%d %d moveto\n",
  1440.             LogicalToDeviceX((wxCoord)(x + size)), LogicalToDeviceY((wxCoord)by) );
  1441.  
  1442.     char buffer[100];
  1443.     sprintf(buffer, "%.8f rotate\n", angle);
  1444.     size_t i;
  1445.     for (i = 0; i < 100; i++)
  1446.         if (buffer[i] == ',') buffer[i] = '.';
  1447.     fprintf(m_pstream, buffer);
  1448.  
  1449.     fprintf( m_pstream, "(" );
  1450.     const wxWX2MBbuf textbuf = text.mb_str();
  1451.     size_t len = strlen(textbuf);
  1452.     for (i = 0; i < len; i++)
  1453.     {
  1454.         int c = (unsigned char) textbuf[i];
  1455.         if (c == ')' || c == '(' || c == '\\')
  1456.         {
  1457.             /* Cope with special characters */
  1458.             fprintf( m_pstream, "\\" );
  1459.             fputc(c, m_pstream);
  1460.         }
  1461.         else if ( c >= 128 )
  1462.         {
  1463.             /* Cope with character codes > 127 */
  1464.             fprintf(m_pstream, "\\%o", c);
  1465.         }
  1466.         else
  1467.         {
  1468.             fputc(c, m_pstream);
  1469.         }
  1470.     }
  1471.  
  1472.     fprintf( m_pstream, ") show\n" );
  1473.  
  1474.     sprintf( buffer, "%.8f rotate\n", -angle );
  1475.     for (i = 0; i < 100; i++)
  1476.         if (buffer[i] == ',') buffer[i] = '.';
  1477.     fprintf( m_pstream, buffer );
  1478.  
  1479.     if (m_font.GetUnderlined())
  1480.     {
  1481.         wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
  1482.         wxCoord w, h;
  1483.         char buffer[100];
  1484.         GetTextExtent(text, &w, &h);
  1485.  
  1486.         sprintf( buffer,
  1487.                  "gsave\n"
  1488.                  "%d %d moveto\n"
  1489.                  "%f setlinewidth\n"
  1490.                  "%d %d lineto\n"
  1491.                  "stroke\n"
  1492.                  "grestore\n",
  1493.                  LogicalToDeviceX(x), LogicalToDeviceY(uy),
  1494.                  m_underlineThickness,
  1495.                  LogicalToDeviceX(x + w), LogicalToDeviceY(uy) );
  1496.         for (i = 0; i < 100; i++)
  1497.             if (buffer[i] == ',') buffer[i] = '.';
  1498.         fprintf( m_pstream, buffer );
  1499.     }
  1500.  
  1501.     CalcBoundingBox( x, y );
  1502.     CalcBoundingBox( x + size * text.Length() * 2/3 , y );
  1503. }
  1504.  
  1505. void wxPostScriptDC::SetBackground (const wxBrush& brush)
  1506. {
  1507.     m_backgroundBrush = brush;
  1508. }
  1509.  
  1510. void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function))
  1511. {
  1512.     wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") );
  1513. }
  1514.  
  1515. void wxPostScriptDC::DoDrawSpline( wxList *points )
  1516. {
  1517.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1518.  
  1519.     SetPen( m_pen );
  1520.  
  1521.     double a, b, c, d, x1, y1, x2, y2, x3, y3;
  1522.     wxPoint *p, *q;
  1523.  
  1524.     wxNode *node = points->First();
  1525.     p = (wxPoint *)node->Data();
  1526.     x1 = p->x;
  1527.     y1 = p->y;
  1528.  
  1529.     node = node->Next();
  1530.     p = (wxPoint *)node->Data();
  1531.     c = p->x;
  1532.     d = p->y;
  1533.     x3 = a = (double)(x1 + c) / 2;
  1534.     y3 = b = (double)(y1 + d) / 2;
  1535.  
  1536.     fprintf( m_pstream,
  1537.             "newpath\n"
  1538.             "%d %d moveto\n"
  1539.             "%d %d lineto\n",
  1540.             LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1),
  1541.             LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
  1542.  
  1543.     CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
  1544.     CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
  1545.  
  1546.     while ((node = node->Next()) != NULL)
  1547.     {
  1548.         q = (wxPoint *)node->Data();
  1549.  
  1550.         x1 = x3;
  1551.         y1 = y3;
  1552.         x2 = c;
  1553.         y2 = d;
  1554.         c = q->x;
  1555.         d = q->y;
  1556.         x3 = (double)(x2 + c) / 2;
  1557.         y3 = (double)(y2 + d) / 2;
  1558.  
  1559.         fprintf( m_pstream,
  1560.                 "%d %d %d %d %d %d DrawSplineSection\n",
  1561.                 LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1),
  1562.                 LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2),
  1563.                 LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
  1564.  
  1565.         CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
  1566.         CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
  1567.     }
  1568.  
  1569.     /*
  1570.        At this point, (x2,y2) and (c,d) are the position of the
  1571.        next-to-last and last point respectively, in the point list
  1572.      */
  1573.  
  1574.     fprintf( m_pstream,
  1575.             "%d %d lineto\n"
  1576.             "stroke\n",
  1577.             LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) );
  1578. }
  1579.  
  1580. wxCoord wxPostScriptDC::GetCharWidth() const
  1581. {
  1582.     // Chris Breeze: reasonable approximation using wxMODERN/Courier
  1583.     return (wxCoord) (GetCharHeight() * 72.0 / 120.0);
  1584. }
  1585.  
  1586.  
  1587. void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
  1588. {
  1589.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1590.  
  1591.     m_signX = (xLeftRight ? 1 : -1);
  1592.     m_signY = (yBottomUp  ? 1 : -1);
  1593.  
  1594.     // FIXME there is no such function in MSW nor in OS2/PM
  1595. #if !defined(__WXMSW__) && !defined(__WXPM__)
  1596.     ComputeScaleAndOrigin();
  1597. #endif
  1598. }
  1599.  
  1600. void wxPostScriptDC::SetDeviceOrigin( wxCoord x, wxCoord y )
  1601. {
  1602.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1603.  
  1604.     int h = 0;
  1605.     int w = 0;
  1606.     GetSize( &w, &h );
  1607.  
  1608.     wxDC::SetDeviceOrigin( x, h-y );
  1609. }
  1610.  
  1611. void wxPostScriptDC::DoGetSize(int* width, int* height) const
  1612. {
  1613.     wxPaperSize id = m_printData.GetPaperId();
  1614.  
  1615.     wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
  1616.  
  1617.     if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
  1618.  
  1619.     int w = 595;
  1620.     int h = 842;
  1621.     if (paper)
  1622.     {
  1623.         w = paper->GetSizeDeviceUnits().x;
  1624.         h = paper->GetSizeDeviceUnits().y;
  1625.     }
  1626.  
  1627.     if (m_printData.GetOrientation() == wxLANDSCAPE)
  1628.     {
  1629.         int tmp = w;
  1630.         w = h;
  1631.         h = tmp;
  1632.     }
  1633.  
  1634.     if (width) *width = (int)(w * ms_PSScaleFactor);
  1635.     if (height) *height = (int)(h * ms_PSScaleFactor);
  1636. }
  1637.  
  1638. void wxPostScriptDC::DoGetSizeMM(int *width, int *height) const
  1639. {
  1640.     wxPaperSize id = m_printData.GetPaperId();
  1641.  
  1642.     wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
  1643.  
  1644.     if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
  1645.  
  1646.     int w = 210;
  1647.     int h = 297;
  1648.     if (paper)
  1649.     {
  1650.         w = paper->GetWidth() / 10;
  1651.         h = paper->GetHeight() / 10;
  1652.     }
  1653.  
  1654.     if (m_printData.GetOrientation() == wxLANDSCAPE)
  1655.     {
  1656.         int tmp = w;
  1657.         w = h;
  1658.         h = tmp;
  1659.     }
  1660.  
  1661.     if (width) *width = w;
  1662.     if (height) *height = h;
  1663. }
  1664.  
  1665. // Resolution in pixels per logical inch
  1666. wxSize wxPostScriptDC::GetPPI(void) const
  1667. {
  1668.     return wxSize((int)(72 * ms_PSScaleFactor),
  1669.                   (int)(72 * ms_PSScaleFactor));
  1670. }
  1671.  
  1672.  
  1673. bool wxPostScriptDC::StartDoc( const wxString& message )
  1674. {
  1675.     wxCHECK_MSG( m_ok, FALSE, wxT("invalid postscript dc") );
  1676.  
  1677.     if (m_printData.GetFilename() == "")
  1678.     {
  1679.         wxString filename = wxGetTempFileName("ps");
  1680.         m_printData.SetFilename(filename);
  1681.     }
  1682.  
  1683.     m_pstream = wxFopen( m_printData.GetFilename().c_str(), wxT("w+") );  // FIXME: use fn_str() here under Unicode?
  1684.  
  1685.     if (!m_pstream)
  1686.     {
  1687.         wxLogError( _("Cannot open file for PostScript printing!"));
  1688.         m_ok = FALSE;
  1689.         return FALSE;
  1690.     }
  1691.  
  1692.     m_ok = TRUE;
  1693.  
  1694.     fprintf( m_pstream, "%%!PS-Adobe-2.0\n" );
  1695.     fprintf( m_pstream, "%%%%Title: %s\n", (const char *) m_title.ToAscii() );
  1696.     fprintf( m_pstream, "%%%%Creator: wxWindows PostScript renderer\n" );
  1697.     fprintf( m_pstream, "%%%%CreationDate: %s\n", (const char *) wxNow().ToAscii() );
  1698.     if (m_printData.GetOrientation() == wxLANDSCAPE)
  1699.         fprintf( m_pstream, "%%%%Orientation: Landscape\n" );
  1700.     else
  1701.         fprintf( m_pstream, "%%%%Orientation: Portrait\n" );
  1702.     
  1703.     // fprintf( m_pstream, "%%%%Pages: %d\n", (wxPageNumber - 1) );
  1704.     
  1705.     char *paper = "A4";
  1706.     switch (m_printData.GetPaperId())
  1707.     {
  1708.        case wxPAPER_LETTER: paper = "Letter"; break;             // Letter: paper ""; 8 1/2 by 11 inches
  1709.        case wxPAPER_LEGAL: paper = "Legal"; break;              // Legal, 8 1/2 by 14 inches
  1710.        case wxPAPER_A4: paper = "A4"; break;          // A4 Sheet, 210 by 297 millimeters
  1711.        case wxPAPER_TABLOID: paper = "Tabloid"; break;     // Tabloid, 11 by 17 inches
  1712.        case wxPAPER_LEDGER: paper = "Ledger"; break;      // Ledger, 17 by 11 inches
  1713.        case wxPAPER_STATEMENT: paper = "Statement"; break;   // Statement, 5 1/2 by 8 1/2 inches
  1714.        case wxPAPER_EXECUTIVE: paper = "Executive"; break;   // Executive, 7 1/4 by 10 1/2 inches
  1715.        case wxPAPER_A3: paper = "A3"; break;          // A3 sheet, 297 by 420 millimeters
  1716.        case wxPAPER_A5: paper = "A5"; break;          // A5 sheet, 148 by 210 millimeters
  1717.        case wxPAPER_B4: paper = "B4"; break;          // B4 sheet, 250 by 354 millimeters
  1718.        case wxPAPER_B5: paper = "B5"; break;          // B5 sheet, 182-by-257-millimeter paper
  1719.        case wxPAPER_FOLIO: paper = "Folio"; break;       // Folio, 8-1/2-by-13-inch paper
  1720.        case wxPAPER_QUARTO: paper = "Quaro"; break;      // Quarto, 215-by-275-millimeter paper
  1721.        case wxPAPER_10X14: paper = "10x14"; break;       // 10-by-14-inch sheet
  1722.        default: paper = "A4";
  1723.     }
  1724.     fprintf( m_pstream, "%%%%DocumentPaperSizes: %s\n", paper );
  1725.     fprintf( m_pstream, "%%%%EndComments\n\n" );
  1726.  
  1727.     fprintf( m_pstream, "%%%%BeginProlog\n" );
  1728.     fprintf( m_pstream, wxPostScriptHeaderConicTo );
  1729.     fprintf( m_pstream, wxPostScriptHeaderEllipse );
  1730.     fprintf( m_pstream, wxPostScriptHeaderEllipticArc );
  1731.     fprintf( m_pstream, wxPostScriptHeaderColourImage );
  1732. #ifndef __WXGTK20__
  1733.     fprintf( m_pstream, wxPostScriptHeaderReencodeISO1 );
  1734.     fprintf( m_pstream, wxPostScriptHeaderReencodeISO2 );
  1735. #endif
  1736.     if (wxPostScriptHeaderSpline)
  1737.         fprintf( m_pstream, wxPostScriptHeaderSpline );
  1738.     fprintf( m_pstream, "%%%%EndProlog\n" );
  1739.  
  1740.     SetBrush( *wxBLACK_BRUSH );
  1741.     SetPen( *wxBLACK_PEN );
  1742.     SetBackground( *wxWHITE_BRUSH );
  1743.     SetTextForeground( *wxBLACK );
  1744.  
  1745.     // set origin according to paper size
  1746.     SetDeviceOrigin( 0,0 );
  1747.  
  1748.     wxPageNumber = 1;
  1749.     m_pageNumber = 1;
  1750.     m_title = message;
  1751.     return TRUE;
  1752. }
  1753.  
  1754. void wxPostScriptDC::EndDoc ()
  1755. {
  1756.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1757.  
  1758.     if (m_clipping)
  1759.     {
  1760.         m_clipping = FALSE;
  1761.         fprintf( m_pstream, "grestore\n" );
  1762.     }
  1763.  
  1764.     fclose( m_pstream );
  1765.     m_pstream = (FILE *) NULL;
  1766.  
  1767. #if 0    
  1768.     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com>
  1769.     wxCoord wx_printer_translate_x, wx_printer_translate_y;
  1770.     double wx_printer_scale_x, wx_printer_scale_y;
  1771.  
  1772.     wx_printer_translate_x = (wxCoord)m_printData.GetPrinterTranslateX();
  1773.     wx_printer_translate_y = (wxCoord)m_printData.GetPrinterTranslateY();
  1774.  
  1775.     wx_printer_scale_x = m_printData.GetPrinterScaleX();
  1776.     wx_printer_scale_y = m_printData.GetPrinterScaleY();
  1777.  
  1778.     // Compute the bounding box.  Note that it is in the default user
  1779.     // coordinate system, thus we have to convert the values.
  1780.     wxCoord minX = (wxCoord) LogicalToDeviceX(m_minX);
  1781.     wxCoord minY = (wxCoord) LogicalToDeviceY(m_minY);
  1782.     wxCoord maxX = (wxCoord) LogicalToDeviceX(m_maxX);
  1783.     wxCoord maxY = (wxCoord) LogicalToDeviceY(m_maxY);
  1784.  
  1785.     // LOG2DEV may have changed the minimum to maximum vice versa
  1786.     if ( minX > maxX ) { wxCoord tmp = minX; minX = maxX; maxX = tmp; }
  1787.     if ( minY > maxY ) { wxCoord tmp = minY; minY = maxY; maxY = tmp; }
  1788.  
  1789.     // account for used scaling (boundingbox is before scaling in ps-file)
  1790.     double scale_x = m_printData.GetPrinterScaleX() / ms_PSScaleFactor;
  1791.     double scale_y = m_printData.GetPrinterScaleY() / ms_PSScaleFactor;
  1792.  
  1793.     wxCoord llx, lly, urx, ury;
  1794.     llx = (wxCoord) ((minX+wx_printer_translate_x)*scale_x);
  1795.     lly = (wxCoord) ((minY+wx_printer_translate_y)*scale_y);
  1796.     urx = (wxCoord) ((maxX+wx_printer_translate_x)*scale_x);
  1797.     ury = (wxCoord) ((maxY+wx_printer_translate_y)*scale_y);
  1798.     // (end of bounding box computation)
  1799.  
  1800.  
  1801.     // If we're landscape, our sense of "x" and "y" is reversed.
  1802.     if (m_printData.GetOrientation() == wxLANDSCAPE)
  1803.     {
  1804.         wxCoord tmp;
  1805.         tmp = llx; llx = lly; lly = tmp;
  1806.         tmp = urx; urx = ury; ury = tmp;
  1807.  
  1808.         // We need either the two lines that follow, or we need to subtract
  1809.         // min_x from real_translate_y, which is commented out below.
  1810.         llx = llx - (wxCoord)(m_minX*wx_printer_scale_y);
  1811.         urx = urx - (wxCoord)(m_minX*wx_printer_scale_y);
  1812.     }
  1813.  
  1814.     // The Adobe specifications call for integers; we round as to make
  1815.     // the bounding larger.
  1816.     fprintf( m_pstream,
  1817.             "%%%%BoundingBox: %d %d %d %d\n",
  1818.             (wxCoord)floor((double)llx), (wxCoord)floor((double)lly),
  1819.             (wxCoord)ceil((double)urx), (wxCoord)ceil((double)ury) );
  1820.  
  1821.     // To check the correctness of the bounding box, postscript commands
  1822.     // to draw a box corresponding to the bounding box are generated below.
  1823.     // But since we typically don't want to print such a box, the postscript
  1824.     // commands are generated within comments.  These lines appear before any
  1825.     // adjustment of scale, rotation, or translation, and hence are in the
  1826.     // default user coordinates.
  1827.     fprintf( m_pstream, "%% newpath\n" );
  1828.     fprintf( m_pstream, "%% %d %d moveto\n", llx, lly );
  1829.     fprintf( m_pstream, "%% %d %d lineto\n", urx, lly );
  1830.     fprintf( m_pstream, "%% %d %d lineto\n", urx, ury );
  1831.     fprintf( m_pstream, "%% %d %d lineto closepath stroke\n", llx, ury );
  1832. #endif
  1833.  
  1834. #if defined(__X__) || defined(__WXGTK__)
  1835.     if (m_ok && (m_printData.GetPrintMode() == wxPRINT_MODE_PRINTER))    
  1836.     {
  1837.         wxString command;
  1838.         command += m_printData.GetPrinterCommand();
  1839.         command += wxT(" ");
  1840.         command += m_printData.GetFilename();
  1841.  
  1842.         wxExecute( command, TRUE );
  1843.         wxRemoveFile( m_printData.GetFilename() );
  1844.     }
  1845. #endif
  1846. }
  1847.  
  1848. void wxPostScriptDC::StartPage()
  1849. {
  1850.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1851.  
  1852.     fprintf( m_pstream, "%%%%Page: %d\n", wxPageNumber++ );
  1853.  
  1854.     //  What is this one supposed to do? RR.
  1855. //  *m_pstream << "matrix currentmatrix\n";
  1856.  
  1857.     // Added by Chris Breeze
  1858.  
  1859.     // Each page starts with an "initgraphics" which resets the
  1860.     // transformation and so we need to reset the origin
  1861.     // (and rotate the page for landscape printing)
  1862.  
  1863.     // Output scaling
  1864.     wxCoord translate_x, translate_y;
  1865.     double scale_x, scale_y;
  1866.  
  1867.     translate_x = (wxCoord)m_printData.GetPrinterTranslateX();
  1868.     translate_y = (wxCoord)m_printData.GetPrinterTranslateY();
  1869.  
  1870.     scale_x = m_printData.GetPrinterScaleX();
  1871.     scale_y = m_printData.GetPrinterScaleY();
  1872.  
  1873.     if (m_printData.GetOrientation() == wxLANDSCAPE)
  1874.     {
  1875.         int h;
  1876.         GetSize( (int*) NULL, &h );
  1877.         translate_y -= h;
  1878.         fprintf( m_pstream, "90 rotate\n" );
  1879.  
  1880.         // I copied this one from a PostScript tutorial, but to no avail. RR.
  1881.         // fprintf( m_pstream, "90 rotate llx neg ury nef translate\n" );
  1882.     }
  1883.  
  1884.     char buffer[100];
  1885.     sprintf( buffer, "%.8f %.8f scale\n", scale_x / ms_PSScaleFactor,
  1886.                                           scale_y / ms_PSScaleFactor);
  1887.     for (int i = 0; i < 100; i++)
  1888.         if (buffer[i] == ',') buffer[i] = '.';
  1889.     fprintf( m_pstream, buffer );
  1890.  
  1891.     fprintf( m_pstream, "%d %d translate\n", translate_x, translate_y );
  1892. }
  1893.  
  1894. void wxPostScriptDC::EndPage ()
  1895. {
  1896.     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
  1897.  
  1898.     fprintf( m_pstream, "showpage\n" );
  1899. }
  1900.  
  1901. bool wxPostScriptDC::DoBlit( wxCoord xdest, wxCoord ydest,
  1902.                            wxCoord fwidth, wxCoord fheight,
  1903.                            wxDC *source,
  1904.                            wxCoord xsrc, wxCoord ysrc,
  1905.                            int rop, bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) )
  1906. {
  1907.     wxCHECK_MSG( m_ok && m_pstream, FALSE, wxT("invalid postscript dc") );
  1908.  
  1909.     wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
  1910.  
  1911.     /* blit into a bitmap */
  1912.     wxBitmap bitmap( (int)fwidth, (int)fheight );
  1913.     wxMemoryDC memDC;
  1914.     memDC.SelectObject(bitmap);
  1915.     memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */
  1916.     memDC.SelectObject(wxNullBitmap);
  1917.  
  1918.     /* draw bitmap. scaling and positioning is done there */
  1919.     DrawBitmap( bitmap, xdest, ydest );
  1920.  
  1921.     return TRUE;
  1922. }
  1923.  
  1924. wxCoord wxPostScriptDC::GetCharHeight() const
  1925. {
  1926.     if (m_font.Ok())
  1927.         return m_font.GetPointSize();
  1928.     else
  1929.         return 12;
  1930. }
  1931.  
  1932. void wxPostScriptDC::DoGetTextExtent(const wxString& string,
  1933.                                      wxCoord *x, wxCoord *y,
  1934.                                      wxCoord *descent, wxCoord *externalLeading,
  1935.                                      wxFont *theFont ) const
  1936. {
  1937.     wxFont *fontToUse = theFont;
  1938.  
  1939.     if (!fontToUse) fontToUse = (wxFont*) &m_font;
  1940.  
  1941.     wxCHECK_RET( fontToUse, wxT("GetTextExtent: no font defined") );
  1942.  
  1943.     if (string.IsEmpty())
  1944.     {
  1945.         if (x) (*x) = 0;
  1946.         if (y) (*y) = 0;
  1947.         return;
  1948.     }
  1949.     
  1950. #ifdef __WXGTK20__
  1951.     int dpi = GetResolution();
  1952.     PangoContext *context = pango_ft2_get_context ( dpi, dpi );
  1953.     
  1954.     pango_context_set_language (context, pango_language_from_string ("en_US"));
  1955.     pango_context_set_base_dir (context, PANGO_DIRECTION_LTR );
  1956.  
  1957.     PangoLayout *layout = pango_layout_new (context);
  1958.     
  1959.     PangoFontDescription *desc = fontToUse->GetNativeFontInfo()->description;
  1960.     pango_layout_set_font_description(layout, desc);
  1961. #if wxUSE_UNICODE
  1962.         const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
  1963.         pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
  1964. #else
  1965.         const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
  1966.         const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
  1967.         pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
  1968. #endif
  1969.     PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
  1970.  
  1971.     PangoRectangle rect;
  1972.     pango_layout_line_get_extents(line, NULL, &rect);
  1973.     
  1974.     if (x) (*x) = (wxCoord) ( m_scaleX * rect.width / PANGO_SCALE );
  1975.     if (y) (*y) = (wxCoord) ( m_scaleY * rect.height / PANGO_SCALE );
  1976.     if (descent)
  1977.     {
  1978.         // Do something about metrics here
  1979.         (*descent) = 0;
  1980.     }
  1981.     if (externalLeading) (*externalLeading) = 0;  // ??
  1982.     
  1983.     g_object_unref( G_OBJECT( layout ) );
  1984. #else
  1985.    // GTK 2.0
  1986.  
  1987.     const wxWX2MBbuf strbuf = string.mb_str();
  1988.  
  1989. #if !wxUSE_AFM_FOR_POSTSCRIPT
  1990.     /* Provide a VERY rough estimate (avoid using it).
  1991.      * Produces accurate results for mono-spaced font
  1992.      * such as Courier (aka wxMODERN) */
  1993.  
  1994.     int height = 12;
  1995.     if (fontToUse)
  1996.     {
  1997.         height = fontToUse->GetPointSize();
  1998.     }
  1999.     if ( x )
  2000.         *x = strlen (strbuf) * height * 72 / 120;
  2001.     if ( y )
  2002.         *y = (wxCoord) (height * 1.32);    /* allow for descender */
  2003.     if (descent) *descent = 0;
  2004.     if (externalLeading) *externalLeading = 0;
  2005. #else
  2006.  
  2007.     /* method for calculating string widths in postscript:
  2008.     /  read in the AFM (adobe font metrics) file for the
  2009.     /  actual font, parse it and extract the character widths
  2010.     /  and also the descender. this may be improved, but for now
  2011.     /  it works well. the AFM file is only read in if the
  2012.     /  font is changed. this may be chached in the future.
  2013.     /  calls to GetTextExtent with the font unchanged are rather
  2014.     /  efficient!!!
  2015.     /
  2016.     /  for each font and style used there is an AFM file necessary.
  2017.     /  currently i have only files for the roman font family.
  2018.     /  I try to get files for the other ones!
  2019.     /
  2020.     /  CAVE: the size of the string is currently always calculated
  2021.     /        in 'points' (1/72 of an inch). this should later on be
  2022.     /        changed to depend on the mapping mode.
  2023.     /  CAVE: the path to the AFM files must be set before calling this
  2024.     /        function. this is usually done by a call like the following:
  2025.     /        wxSetAFMPath("d:\\wxw161\\afm\\");
  2026.     /
  2027.     /  example:
  2028.     /
  2029.     /    wxPostScriptDC dc(NULL, TRUE);
  2030.     /    if (dc.Ok()){
  2031.     /      wxSetAFMPath("d:\\wxw161\\afm\\");
  2032.     /      dc.StartDoc("Test");
  2033.     /      dc.StartPage();
  2034.     /      wxCoord w,h;
  2035.     /      dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
  2036.     /      dc.GetTextExtent("Hallo",&w,&h);
  2037.     /      dc.EndPage();
  2038.     /      dc.EndDoc();
  2039.     /    }
  2040.     /
  2041.     /  by steve (stefan.hammes@urz.uni-heidelberg.de)
  2042.     /  created: 10.09.94
  2043.     /  updated: 14.05.95 */
  2044.  
  2045.     /* these static vars are for storing the state between calls */
  2046.     static int lastFamily= INT_MIN;
  2047.     static int lastSize= INT_MIN;
  2048.     static int lastStyle= INT_MIN;
  2049.     static int lastWeight= INT_MIN;
  2050.     static int lastDescender = INT_MIN;
  2051.     static int lastWidths[256]; /* widths of the characters */
  2052.  
  2053.     double UnderlinePosition = 0.0;
  2054.     double UnderlineThickness = 0.0;
  2055.  
  2056.     // Get actual parameters
  2057.     int Family = fontToUse->GetFamily();
  2058.     int Size =   fontToUse->GetPointSize();
  2059.     int Style =  fontToUse->GetStyle();
  2060.     int Weight = fontToUse->GetWeight();
  2061.  
  2062.     // If we have another font, read the font-metrics
  2063.     if (Family!=lastFamily || Size!=lastSize || Style!=lastStyle || Weight!=lastWeight)
  2064.     {
  2065.         // Store actual values
  2066.         lastFamily = Family;
  2067.         lastSize =   Size;
  2068.         lastStyle =  Style;
  2069.         lastWeight = Weight;
  2070.  
  2071.         const char *name = NULL;
  2072.  
  2073.         switch (Family)
  2074.         {
  2075.             case wxMODERN:
  2076.             case wxTELETYPE:
  2077.             {
  2078.                 if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "CourBoO.afm";
  2079.                 else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "CourBo.afm";
  2080.                 else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "CourO.afm";
  2081.                 else name = "Cour.afm";
  2082.                 break;
  2083.             }
  2084.             case wxROMAN:
  2085.             {
  2086.                 if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "TimesBoO.afm";
  2087.                 else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "TimesBo.afm";
  2088.                 else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "TimesO.afm";
  2089.                 else name = "TimesRo.afm";
  2090.                 break;
  2091.             }
  2092.             case wxSCRIPT:
  2093.             {
  2094.                 name = "Zapf.afm";
  2095.                 Style = wxNORMAL;
  2096.                 Weight = wxNORMAL;
  2097.             }
  2098.             case wxSWISS:
  2099.             default:
  2100.             {
  2101.                 if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "HelvBoO.afm";
  2102.                 else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "HelvBo.afm";
  2103.                 else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "HelvO.afm";
  2104.                 else name = "Helv.afm";
  2105.                 break;
  2106.             }
  2107.         }
  2108.  
  2109.         FILE *afmFile = NULL;
  2110.         
  2111.         // Get the directory of the AFM files
  2112.         wxString afmName;
  2113.         if (!m_printData.GetFontMetricPath().IsEmpty())
  2114.         {
  2115.             afmName = m_printData.GetFontMetricPath();
  2116.             afmName << wxFILE_SEP_PATH << name;
  2117.             afmFile = wxFopen(afmName,wxT("r"));
  2118.         }
  2119.  
  2120. #if defined(__UNIX__) && !defined(__VMS__)
  2121.         if (afmFile==NULL)
  2122.         {
  2123.            afmName = wxGetDataDir();
  2124.            afmName <<  wxFILE_SEP_PATH
  2125. #if defined(__LINUX__) || defined(__FREEBSD__)
  2126.                    << wxT("gs_afm") << wxFILE_SEP_PATH
  2127. #else
  2128.                    << wxT("afm") << wxFILE_SEP_PATH
  2129. #endif
  2130.                    << name;
  2131.            afmFile = wxFopen(afmName,wxT("r"));
  2132.         }
  2133. #endif
  2134.  
  2135.         /* 2. open and process the file
  2136.            /  a short explanation of the AFM format:
  2137.            /  we have for each character a line, which gives its size
  2138.            /  e.g.:
  2139.            /
  2140.            /    C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
  2141.            /
  2142.            /  that means, we have a character with ascii code 63, and width
  2143.            /  (444/1000 * fontSize) points.
  2144.            /  the other data is ignored for now!
  2145.            /
  2146.            /  when the font has changed, we read in the right AFM file and store the
  2147.            /  character widths in an array, which is processed below (see point 3.). */
  2148.         if (afmFile==NULL)
  2149.         {
  2150.             wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() );
  2151.             wxLogDebug( wxT("               using approximate values"));
  2152.             for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
  2153.             lastDescender = -150; /* dito. */
  2154.         }
  2155.         else
  2156.         {
  2157.             /* init the widths array */
  2158.             for(int i=0; i<256; i++) lastWidths[i] = INT_MIN;
  2159.             /* some variables for holding parts of a line */
  2160.             char cString[10],semiString[10],WXString[10],descString[20];
  2161.             char upString[30], utString[30], encString[50];
  2162.             char line[256];
  2163.             int ascii,cWidth;
  2164.             /* read in the file and parse it */
  2165.             while(fgets(line,sizeof(line),afmFile)!=NULL)
  2166.             {
  2167.                 /* A.) check for descender definition */
  2168.                 if (strncmp(line,"Descender",9)==0)
  2169.                 {
  2170.                     if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
  2171.                             (strcmp(descString,"Descender")!=0))
  2172.                     {
  2173.                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line );
  2174.                     }
  2175.                 }
  2176.                 /* JC 1.) check for UnderlinePosition */
  2177.                 else if(strncmp(line,"UnderlinePosition",17)==0)
  2178.                 {
  2179.                     if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
  2180.                             (strcmp(upString,"UnderlinePosition")!=0))
  2181.                     {
  2182.                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line );
  2183.                     }
  2184.                 }
  2185.                 /* JC 2.) check for UnderlineThickness */
  2186.                 else if(strncmp(line,"UnderlineThickness",18)==0)
  2187.                 {
  2188.                     if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
  2189.                             (strcmp(utString,"UnderlineThickness")!=0))
  2190.                     {
  2191.                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line );
  2192.                     }
  2193.                 }
  2194.                 /* JC 3.) check for EncodingScheme */
  2195.                 else if(strncmp(line,"EncodingScheme",14)==0)
  2196.                 {
  2197.                     if ((sscanf(line,"%s%s",utString,encString)!=2) ||
  2198.                             (strcmp(utString,"EncodingScheme")!=0))
  2199.                     {
  2200.                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line );
  2201.                     }
  2202.                     else if (strncmp(encString, "AdobeStandardEncoding", 21))
  2203.                     {
  2204.                         wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"),
  2205.                                 afmName.c_str(),line, encString);
  2206.                     }
  2207.                 }
  2208.                 /* B.) check for char-width */
  2209.                 else if(strncmp(line,"C ",2)==0)
  2210.                 {
  2211.                     if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
  2212.                     {
  2213.                         wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line);
  2214.                     }
  2215.                     if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
  2216.                     {
  2217.                         wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line);
  2218.                     }
  2219.                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
  2220.                     if (ascii>=0 && ascii<256)
  2221.                     {
  2222.                         lastWidths[ascii] = cWidth; /* store width */
  2223.                     }
  2224.                     else
  2225.                     {
  2226.                         /* MATTHEW: this happens a lot; don't print an error */
  2227.                         /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */
  2228.                     }
  2229.                 }
  2230.                 /* C.) ignore other entries. */
  2231.             }
  2232.             fclose(afmFile);
  2233.         }
  2234.         /* hack to compute correct values for german 'Umlaute'
  2235.            /  the correct way would be to map the character names
  2236.            /  like 'adieresis' to corresp. positions of ISOEnc and read
  2237.            /  these values from AFM files, too. Maybe later ... */
  2238.         lastWidths[196] = lastWidths['A'];  // ─
  2239.         lastWidths[228] = lastWidths['a'];  // Σ
  2240.         lastWidths[214] = lastWidths['O'];  // ╓
  2241.         lastWidths[246] = lastWidths['o'];  // ÷
  2242.         lastWidths[220] = lastWidths['U'];  // ▄
  2243.         lastWidths[252] = lastWidths['u'];  // ⁿ
  2244.         lastWidths[223] = lastWidths[251];  // ▀
  2245.  
  2246.         /* JC: calculate UnderlineThickness/UnderlinePosition */
  2247.  
  2248.         // VS: dirty, but is there any better solution?
  2249.         double *pt;
  2250.         pt = (double*) &m_underlinePosition;
  2251.         *pt = LogicalToDeviceYRel((wxCoord)(UnderlinePosition * fontToUse->GetPointSize())) / 1000.0f;
  2252.         pt = (double*) &m_underlineThickness;
  2253.         *pt = LogicalToDeviceYRel((wxCoord)(UnderlineThickness * fontToUse->GetPointSize())) / 1000.0f;
  2254.  
  2255.     }
  2256.  
  2257.  
  2258.     /* 3. now the font metrics are read in, calc size this
  2259.        /  is done by adding the widths of the characters in the
  2260.        /  string. they are given in 1/1000 of the size! */
  2261.  
  2262.     long sum=0;
  2263.     wxCoord height=Size; /* by default */
  2264.     unsigned char *p;
  2265.     for(p=(unsigned char *)wxMBSTRINGCAST strbuf; *p; p++)
  2266.     {
  2267.         if(lastWidths[*p]== INT_MIN)
  2268.         {
  2269.             wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p,*p);
  2270.             sum += lastWidths[' ']; /* assume space */
  2271.         }
  2272.         else
  2273.         {
  2274.             sum += lastWidths[*p];
  2275.         }
  2276.     }
  2277.  
  2278.     double widthSum = sum;
  2279.     widthSum *= Size;
  2280.     widthSum /= 1000.0F;
  2281.  
  2282.     /* add descender to height (it is usually a negative value) */
  2283.     //if (lastDescender != INT_MIN)
  2284.     //{
  2285.     //    height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
  2286.     //}
  2287.     // - commented by V. Slavik - height already contains descender in it
  2288.     //   (judging from few experiments)
  2289.  
  2290.     /* return size values */
  2291.     if ( x )
  2292.         *x = (wxCoord)widthSum;
  2293.     if ( y )
  2294.         *y = height;
  2295.  
  2296.     /* return other parameters */
  2297.     if (descent)
  2298.     {
  2299.         if(lastDescender!=INT_MIN)
  2300.         {
  2301.             *descent = (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
  2302.         }
  2303.         else
  2304.         {
  2305.             *descent = 0;
  2306.         }
  2307.     }
  2308.  
  2309.     /* currently no idea how to calculate this! */
  2310.     if (externalLeading) *externalLeading = 0;
  2311. #endif
  2312.     // Use AFM
  2313.  
  2314. #endif
  2315.     // GTK 2.0
  2316. }
  2317.  
  2318. #endif
  2319.   // wxUSE_POSTSCRIPT
  2320.  
  2321. #endif
  2322.   // wxUSE_PRINTING_ARCHITECTURE
  2323.