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