]> git.saurik.com Git - wxWidgets.git/blame - src/generic/dcpsg.cpp
compilation fixes after applying DECLARE_NO_COPY_CLASS() patch
[wxWidgets.git] / src / generic / dcpsg.cpp
CommitLineData
ed880dd4 1/////////////////////////////////////////////////////////////////////////////
bf38cbff
JS
2// Name: dcpsg.cpp
3// Purpose: Generic wxPostScriptDC implementation
ed880dd4
RR
4// Author: Julian Smart, Robert Roebling, Markus Holzhem
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
9a6be59a 9// Licence: wxWindows licence
ed880dd4
RR
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
1aedb1dd 13#pragma implementation "dcpsg.h"
ed880dd4
RR
14#endif
15
9a6be59a
VZ
16#include "wx/wxprec.h"
17
18#ifdef __BORLANDC__
19 #pragma hdrstop
20#endif
21
22#ifndef WX_PRECOMP
9a6be59a 23#endif // WX_PRECOMP
06cfab17 24
ce4169a4
RR
25#if wxUSE_PRINTING_ARCHITECTURE
26
06cfab17
RR
27#if wxUSE_POSTSCRIPT
28
401eb3de
RR
29#include "wx/setup.h"
30
e6f1ad22 31#include "wx/window.h"
f04371f0 32#include "wx/dcmemory.h"
ed880dd4 33#include "wx/utils.h"
f04371f0 34#include "wx/intl.h"
ed880dd4 35#include "wx/filedlg.h"
ed880dd4 36#include "wx/app.h"
f04371f0 37#include "wx/msgdlg.h"
ef539066 38#include "wx/image.h"
3069ac4e 39#include "wx/log.h"
bf38cbff 40#include "wx/generic/dcpsg.h"
b403ab00 41#include "wx/printdlg.h"
bf38cbff
JS
42#include "wx/button.h"
43#include "wx/stattext.h"
44#include "wx/radiobox.h"
45#include "wx/textctrl.h"
9a05fd8d 46#include "wx/prntbase.h"
7bcb11d3 47#include "wx/paper.h"
d361e74e 48#include "wx/filefn.h"
ed880dd4 49
57c208c5
JS
50#include <math.h>
51
bf38cbff
JS
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
ed880dd4
RR
72//-----------------------------------------------------------------------------
73// start and end of document/page
74//-----------------------------------------------------------------------------
75
c31c771b
RR
76static 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\
c31c771b
RR
91";
92
ed880dd4
RR
93static const char *wxPostScriptHeaderEllipse = "\
94/ellipsedict 8 dict def\n\
95ellipsedict /mtrx matrix put\n\
96/ellipse {\n\
9a6be59a
VZ
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\
ed880dd4
RR
111";
112
113static const char *wxPostScriptHeaderEllipticArc= "\
114/ellipticarcdict 8 dict def\n\
115ellipticarcdict /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
135static const char *wxPostScriptHeaderSpline = "\
136/DrawSplineSection {\n\
9a6be59a
VZ
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\
ed880dd4
RR
150";
151
152static const char *wxPostScriptHeaderColourImage = "\
d7657f75
RR
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\
ed880dd4
RR
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\
d7657f75
RR
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\
ed880dd4
RR
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\
d7657f75
RR
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\
ed880dd4 179\n\
d7657f75 180 /mergeprocs { %% def\n\
ed880dd4
RR
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\
d7657f75
RR
199 /colorimage { %% def\n\
200 pop pop %% remove 'false 3' operands\n\
ed880dd4
RR
201 {colortogray} mergeprocs\n\
202 image\n\
203 } bind def\n\
d7657f75 204 } ifelse %% end of 'false' case\n\
ed880dd4
RR
205";
206
2b5f62a0
VZ
207#if wxUSE_PANGO
208#else
ed880dd4
RR
209static 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
233static 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";
c31c771b 249#endif
ed880dd4 250
ed880dd4
RR
251//-------------------------------------------------------------------------------
252// wxPostScriptDC
253//-------------------------------------------------------------------------------
254
eba33006
RR
255IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC, wxDC)
256
b64de916
VS
257float wxPostScriptDC::ms_PSScaleFactor = 10.0;
258
259void wxPostScriptDC::SetResolution(int ppi)
260{
261 ms_PSScaleFactor = (float)ppi / 72.0;
262}
263
264int wxPostScriptDC::GetResolution()
265{
266 return (int)(ms_PSScaleFactor * 72.0);
267}
48c31b28 268
eba33006 269//-------------------------------------------------------------------------------
b64de916 270
ed880dd4
RR
271wxPostScriptDC::wxPostScriptDC ()
272{
d7657f75 273 m_pstream = (FILE*) NULL;
afce4c03 274
ed880dd4
RR
275 m_currentRed = 0;
276 m_currentGreen = 0;
277 m_currentBlue = 0;
afce4c03 278
ed880dd4 279 m_pageNumber = 0;
afce4c03 280
ed880dd4 281 m_clipping = FALSE;
afce4c03 282
ed880dd4
RR
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
ed880dd4
RR
288}
289
7bcb11d3
JS
290wxPostScriptDC::wxPostScriptDC (const wxPrintData& printData)
291{
d7657f75 292 m_pstream = (FILE*) NULL;
7bcb11d3
JS
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;
75737d05
JS
309
310 m_ok = TRUE;
7bcb11d3
JS
311}
312
ed880dd4
RR
313wxPostScriptDC::~wxPostScriptDC ()
314{
d7657f75
RR
315 if (m_pstream)
316 {
317 fclose( m_pstream );
72cdf4c9 318 m_pstream = (FILE*) NULL;
d7657f75 319 }
ed880dd4
RR
320}
321
009a0665
RR
322#if WXWIN_COMPATIBILITY_2_2
323bool 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
4bc67cc5
RR
347bool wxPostScriptDC::Ok() const
348{
ef539066 349 return m_ok;
4bc67cc5 350}
afce4c03 351
72cdf4c9 352void wxPostScriptDC::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h)
ed880dd4 353{
223d09f6 354 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 355
7087444f 356 if (m_clipping) DestroyClippingRegion();
ed880dd4 357
7087444f 358 wxDC::DoSetClippingRegion(x, y, w, h);
afce4c03 359
ed880dd4 360 m_clipping = TRUE;
72cdf4c9 361 fprintf( m_pstream,
d7657f75 362 "gsave\n newpath\n"
72cdf4c9
VZ
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",
6a7b1d6e
RD
368 LogicalToDeviceX(x), LogicalToDeviceY(y),
369 LogicalToDeviceX(x+w), LogicalToDeviceY(y),
370 LogicalToDeviceX(x+w), LogicalToDeviceY(y+h),
371 LogicalToDeviceX(x), LogicalToDeviceY(y+h) );
ed880dd4
RR
372}
373
ed880dd4
RR
374
375void wxPostScriptDC::DestroyClippingRegion()
376{
223d09f6 377 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 378
ed880dd4
RR
379 if (m_clipping)
380 {
381 m_clipping = FALSE;
72cdf4c9 382 fprintf( m_pstream, "grestore\n" );
ed880dd4 383 }
004fd0c8 384
7087444f 385 wxDC::DestroyClippingRegion();
ed880dd4
RR
386}
387
388void wxPostScriptDC::Clear()
389{
223d09f6 390 wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") );
ed880dd4
RR
391}
392
387ebd3e 393bool wxPostScriptDC::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style))
ed880dd4 394{
223d09f6 395 wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") );
387ebd3e 396 return FALSE;
ed880dd4
RR
397}
398
72cdf4c9 399bool wxPostScriptDC::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const
ed880dd4 400{
223d09f6 401 wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") );
ed880dd4
RR
402 return FALSE;
403}
404
72cdf4c9 405void wxPostScriptDC::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
ed880dd4 406{
223d09f6 407 wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") );
ed880dd4
RR
408}
409
72cdf4c9 410void wxPostScriptDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
ed880dd4 411{
223d09f6 412 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 413
ed880dd4 414 if (m_pen.GetStyle() == wxTRANSPARENT) return;
afce4c03 415
ed880dd4 416 SetPen( m_pen );
afce4c03 417
d7657f75
RR
418 fprintf( m_pstream,
419 "newpath\n"
72cdf4c9
VZ
420 "%d %d moveto\n"
421 "%d %d lineto\n"
422 "stroke\n",
6a7b1d6e
RD
423 LogicalToDeviceX(x1), LogicalToDeviceY(y1),
424 LogicalToDeviceX(x2), LogicalToDeviceY (y2) );
afce4c03 425
ed880dd4
RR
426 CalcBoundingBox( x1, y1 );
427 CalcBoundingBox( x2, y2 );
428}
429
430#define RAD2DEG 57.29577951308
431
72cdf4c9 432void wxPostScriptDC::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
ed880dd4 433{
223d09f6 434 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 435
72cdf4c9
VZ
436 wxCoord dx = x1 - xc;
437 wxCoord dy = y1 - yc;
438 wxCoord radius = (wxCoord) sqrt( (double)(dx*dx+dy*dy) );
ed880dd4
RR
439 double alpha1, alpha2;
440
afce4c03 441 if (x1 == x2 && y1 == y2)
ed880dd4 442 {
d7657f75
RR
443 alpha1 = 0.0;
444 alpha2 = 360.0;
72cdf4c9 445 }
d7657f75 446 else if (radius == 0.0)
ed880dd4 447 {
d7657f75 448 alpha1 = alpha2 = 0.0;
72cdf4c9 449 }
d7657f75 450 else
ed880dd4 451 {
d7657f75
RR
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;
ed880dd4
RR
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
afce4c03 464 if (m_brush.GetStyle() != wxTRANSPARENT)
ed880dd4 465 {
d7657f75 466 SetBrush( m_brush );
72cdf4c9
VZ
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",
6a7b1d6e
RD
474 LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2,
475 LogicalToDeviceX(xc), LogicalToDeviceY(yc) );
d7657f75
RR
476
477 CalcBoundingBox( xc-radius, yc-radius );
478 CalcBoundingBox( xc+radius, yc+radius );
ed880dd4 479 }
afce4c03
VZ
480
481 if (m_pen.GetStyle() != wxTRANSPARENT)
ed880dd4 482 {
d7657f75 483 SetPen( m_pen );
72cdf4c9
VZ
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",
6a7b1d6e
RD
491 LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2,
492 LogicalToDeviceX(xc), LogicalToDeviceY(yc) );
d7657f75
RR
493
494 CalcBoundingBox( xc-radius, yc-radius );
495 CalcBoundingBox( xc+radius, yc+radius );
ed880dd4 496 }
ed880dd4
RR
497}
498
72cdf4c9 499void wxPostScriptDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
ed880dd4 500{
223d09f6 501 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 502
ed880dd4
RR
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;
afce4c03 507
ed880dd4
RR
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 );
72cdf4c9
VZ
517
518 fprintf( m_pstream,
519 "newpath\n"
520 "%d %d %d %d %d %d true ellipticarc\n",
6a7b1d6e 521 LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), (wxCoord)sa, (wxCoord)ea );
72cdf4c9 522
ed880dd4
RR
523 CalcBoundingBox( x ,y );
524 CalcBoundingBox( x+w, y+h );
72cdf4c9
VZ
525 }
526
ed880dd4
RR
527 if (m_pen.GetStyle () != wxTRANSPARENT)
528 {
529 SetPen( m_pen );
530
72cdf4c9
VZ
531 fprintf(m_pstream,
532 "newpath\n"
533 "%d %d %d %d %d %d false ellipticarc\n",
6a7b1d6e 534 LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), (wxCoord)sa, (wxCoord)ea );
72cdf4c9 535
d7657f75 536 CalcBoundingBox( x ,y );
ed880dd4
RR
537 CalcBoundingBox( x+w, y+h );
538 }
539}
540
72cdf4c9 541void wxPostScriptDC::DoDrawPoint (wxCoord x, wxCoord y)
ed880dd4 542{
223d09f6 543 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 544
ed880dd4 545 if (m_pen.GetStyle() == wxTRANSPARENT) return;
afce4c03 546
ed880dd4 547 SetPen (m_pen);
afce4c03 548
d7657f75
RR
549 fprintf( m_pstream,
550 "newpath\n"
72cdf4c9
VZ
551 "%d %d moveto\n"
552 "%d %d lineto\n"
553 "stroke\n",
6a7b1d6e
RD
554 LogicalToDeviceX(x), LogicalToDeviceY(y),
555 LogicalToDeviceX(x+1), LogicalToDeviceY(y) );
afce4c03 556
ed880dd4
RR
557 CalcBoundingBox( x, y );
558}
559
72cdf4c9 560void wxPostScriptDC::DoDrawPolygon (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle))
ed880dd4 561{
223d09f6 562 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 563
ed880dd4 564 if (n <= 0) return;
afce4c03 565
ed880dd4
RR
566 if (m_brush.GetStyle () != wxTRANSPARENT)
567 {
d7657f75
RR
568 SetBrush( m_brush );
569
570 fprintf( m_pstream, "newpath\n" );
afce4c03 571
6a7b1d6e
RD
572 wxCoord xx = LogicalToDeviceX(points[0].x + xoffset);
573 wxCoord yy = LogicalToDeviceY(points[0].y + yoffset);
72cdf4c9
VZ
574
575 fprintf( m_pstream, "%d %d moveto\n", xx, yy );
576
d7657f75 577 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
ed880dd4 578
d7657f75
RR
579 for (int i = 1; i < n; i++)
580 {
6a7b1d6e
RD
581 xx = LogicalToDeviceX(points[i].x + xoffset);
582 yy = LogicalToDeviceY(points[i].y + yoffset);
72cdf4c9
VZ
583
584 fprintf( m_pstream, "%d %d lineto\n", xx, yy );
ed880dd4 585
d7657f75
RR
586 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
587 }
72cdf4c9
VZ
588
589 fprintf( m_pstream, "fill\n" );
ed880dd4
RR
590 }
591
592 if (m_pen.GetStyle () != wxTRANSPARENT)
593 {
d7657f75 594 SetPen( m_pen );
72cdf4c9 595
d7657f75 596 fprintf( m_pstream, "newpath\n" );
ed880dd4 597
6a7b1d6e
RD
598 wxCoord xx = LogicalToDeviceX(points[0].x + xoffset);
599 wxCoord yy = LogicalToDeviceY(points[0].y + yoffset);
72cdf4c9
VZ
600
601 fprintf( m_pstream, "%d %d moveto\n", xx, yy );
602
d7657f75 603 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
ed880dd4 604
d7657f75
RR
605 for (int i = 1; i < n; i++)
606 {
6a7b1d6e
RD
607 xx = LogicalToDeviceX(points[i].x + xoffset);
608 yy = LogicalToDeviceY(points[i].y + yoffset);
72cdf4c9
VZ
609
610 fprintf( m_pstream, "%d %d lineto\n", xx, yy );
611
d7657f75
RR
612 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
613 }
ed880dd4 614
733b25e1 615 fprintf( m_pstream, "closepath\n" );
ceae98ef 616 fprintf( m_pstream, "stroke\n" );
ed880dd4
RR
617 }
618}
619
72cdf4c9 620void wxPostScriptDC::DoDrawLines (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
ed880dd4 621{
223d09f6 622 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 623
d7657f75 624 if (m_pen.GetStyle() == wxTRANSPARENT) return;
72cdf4c9 625
d7657f75 626 if (n <= 0) return;
afce4c03 627
ed880dd4 628 SetPen (m_pen);
afce4c03 629
9a6be59a
VZ
630 int i;
631 for ( i =0; i<n ; i++ )
ed880dd4 632 {
6a7b1d6e 633 CalcBoundingBox( LogicalToDeviceX(points[i].x+xoffset), LogicalToDeviceY(points[i].y+yoffset));
ed880dd4
RR
634 }
635
d7657f75
RR
636 fprintf( m_pstream,
637 "newpath\n"
72cdf4c9 638 "%d %d moveto\n",
6a7b1d6e 639 LogicalToDeviceX(points[0].x+xoffset), LogicalToDeviceY(points[0].y+yoffset) );
afce4c03
VZ
640
641 for (i = 1; i < n; i++)
ed880dd4 642 {
d7657f75 643 fprintf( m_pstream,
72cdf4c9 644 "%d %d lineto\n",
6a7b1d6e 645 LogicalToDeviceX(points[i].x+xoffset), LogicalToDeviceY(points[i].y+yoffset) );
ed880dd4 646 }
afce4c03 647
d7657f75 648 fprintf( m_pstream, "stroke\n" );
ed880dd4
RR
649}
650
72cdf4c9 651void wxPostScriptDC::DoDrawRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
ed880dd4 652{
223d09f6 653 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 654
ed880dd4
RR
655 if (m_brush.GetStyle () != wxTRANSPARENT)
656 {
657 SetBrush( m_brush );
72cdf4c9
VZ
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"
d7657f75
RR
665 "closepath\n"
666 "fill\n",
6a7b1d6e
RD
667 LogicalToDeviceX(x), LogicalToDeviceY(y),
668 LogicalToDeviceX(x + width), LogicalToDeviceY(y),
669 LogicalToDeviceX(x + width), LogicalToDeviceY(y + height),
670 LogicalToDeviceX(x), LogicalToDeviceY(y + height) );
ed880dd4
RR
671
672 CalcBoundingBox( x, y );
673 CalcBoundingBox( x + width, y + height );
674 }
afce4c03 675
ed880dd4
RR
676 if (m_pen.GetStyle () != wxTRANSPARENT)
677 {
678 SetPen (m_pen);
679
72cdf4c9
VZ
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"
d7657f75
RR
686 "closepath\n"
687 "stroke\n",
6a7b1d6e
RD
688 LogicalToDeviceX(x), LogicalToDeviceY(y),
689 LogicalToDeviceX(x + width), LogicalToDeviceY(y),
690 LogicalToDeviceX(x + width), LogicalToDeviceY(y + height),
691 LogicalToDeviceX(x), LogicalToDeviceY(y + height) );
72cdf4c9 692
ed880dd4
RR
693 CalcBoundingBox( x, y );
694 CalcBoundingBox( x + width, y + height );
695 }
696}
697
72cdf4c9 698void wxPostScriptDC::DoDrawRoundedRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
ed880dd4 699{
223d09f6 700 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 701
ed880dd4
RR
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)
9a6be59a 708 smallest = width;
ed880dd4 709 else
9a6be59a 710 smallest = height;
ed880dd4
RR
711 radius = (-radius * smallest);
712 }
afce4c03 713
72cdf4c9 714 wxCoord rad = (wxCoord) radius;
ed880dd4
RR
715
716 if (m_brush.GetStyle () != wxTRANSPARENT)
717 {
718 SetBrush( m_brush );
afce4c03 719
d7657f75 720 /* Draw rectangle anticlockwise */
72cdf4c9
VZ
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"
d7657f75
RR
731 "closepath\n"
732 "fill\n",
6a7b1d6e
RD
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) );
ed880dd4
RR
741
742 CalcBoundingBox( x, y );
743 CalcBoundingBox( x + width, y + height );
744 }
afce4c03 745
ed880dd4
RR
746 if (m_pen.GetStyle () != wxTRANSPARENT)
747 {
748 SetPen (m_pen);
afce4c03 749
d7657f75 750 /* Draw rectangle anticlockwise */
72cdf4c9
VZ
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"
d7657f75
RR
761 "closepath\n"
762 "stroke\n",
6a7b1d6e
RD
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) );
ed880dd4
RR
771
772 CalcBoundingBox( x, y );
773 CalcBoundingBox( x + width, y + height );
774 }
775}
776
72cdf4c9 777void wxPostScriptDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
ed880dd4 778{
223d09f6 779 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 780
ed880dd4
RR
781 if (m_brush.GetStyle () != wxTRANSPARENT)
782 {
783 SetBrush (m_brush);
784
72cdf4c9
VZ
785 fprintf( m_pstream,
786 "newpath\n"
787 "%d %d %d %d 0 360 ellipse\n"
788 "fill\n",
6a7b1d6e
RD
789 LogicalToDeviceX(x + width / 2), LogicalToDeviceY(y + height / 2),
790 LogicalToDeviceXRel(width / 2), LogicalToDeviceYRel(height / 2) );
ed880dd4
RR
791
792 CalcBoundingBox( x - width, y - height );
793 CalcBoundingBox( x + width, y + height );
794 }
afce4c03 795
d7657f75 796 if (m_pen.GetStyle () != wxTRANSPARENT)
ed880dd4
RR
797 {
798 SetPen (m_pen);
799
72cdf4c9
VZ
800 fprintf( m_pstream,
801 "newpath\n"
802 "%d %d %d %d 0 360 ellipse\n"
803 "stroke\n",
6a7b1d6e
RD
804 LogicalToDeviceX(x + width / 2), LogicalToDeviceY(y + height / 2),
805 LogicalToDeviceXRel(width / 2), LogicalToDeviceYRel(height / 2) );
ed880dd4
RR
806
807 CalcBoundingBox( x - width, y - height );
808 CalcBoundingBox( x + width, y + height );
809 }
810}
811
72cdf4c9 812void wxPostScriptDC::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y )
ed880dd4 813{
ef539066 814 DrawBitmap( icon, x, y, TRUE );
ed880dd4
RR
815}
816
d7657f75
RR
817/* this has to be char, not wxChar */
818static char hexArray[] = "0123456789ABCDEF";
819static 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
72cdf4c9 828void wxPostScriptDC::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
ed880dd4 829{
223d09f6 830 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
ef539066
RR
831
832 if (!bitmap.Ok()) return;
afce4c03 833
368d59f0 834 wxImage image = bitmap.ConvertToImage();
afce4c03 835
ef539066 836 if (!image.Ok()) return;
afce4c03 837
b64de916
VS
838 wxCoord w = image.GetWidth();
839 wxCoord h = image.GetHeight();
840
6a7b1d6e
RD
841 wxCoord ww = LogicalToDeviceXRel(image.GetWidth());
842 wxCoord hh = LogicalToDeviceYRel(image.GetHeight());
afce4c03 843
6a7b1d6e
RD
844 wxCoord xx = LogicalToDeviceX(x);
845 wxCoord yy = LogicalToDeviceY(y + bitmap.GetHeight());
d7657f75
RR
846
847 fprintf( m_pstream,
848 "/origstate save def\n"
72cdf4c9
VZ
849 "20 dict begin\n"
850 "/pix %d string def\n"
851 "/grays %d string def\n"
d7657f75
RR
852 "/npixels 0 def\n"
853 "/rgbindx 0 def\n"
72cdf4c9
VZ
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",
b64de916
VS
860 w, w, xx, yy, ww, hh, w, h, w, -h, h );
861
afce4c03 862
b64de916 863 for (int j = 0; j < h; j++)
ef539066 864 {
b64de916 865 for (int i = 0; i < w; i++)
ef539066 866 {
d7657f75
RR
867 char buffer[5];
868 LocalDecToHex( image.GetRed(i,j), buffer );
72cdf4c9 869 fprintf( m_pstream, buffer );
d7657f75 870 LocalDecToHex( image.GetGreen(i,j), buffer );
72cdf4c9
VZ
871 fprintf( m_pstream, buffer );
872 LocalDecToHex( image.GetBlue(i,j), buffer );
873 fprintf( m_pstream, buffer );
d7657f75
RR
874 }
875 fprintf( m_pstream, "\n" );
ef539066
RR
876 }
877
d7657f75
RR
878 fprintf( m_pstream, "end\n" );
879 fprintf( m_pstream, "origstate restore\n" );
ed880dd4
RR
880}
881
36b3b54a 882void wxPostScriptDC::SetFont( const wxFont& font )
ed880dd4 883{
223d09f6 884 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 885
ed880dd4 886 if (!font.Ok()) return;
afce4c03 887
ed880dd4 888 m_font = font;
57c208c5 889
2b5f62a0
VZ
890#if wxUSE_PANGO
891#else
36b3b54a
RR
892 int Style = m_font.GetStyle();
893 int Weight = m_font.GetWeight();
894
733b25e1 895 const char *name;
d7657f75 896 switch (m_font.GetFamily())
36b3b54a
RR
897 {
898 case wxTELETYPE:
899 case wxMODERN:
733b25e1
RR
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 }
36b3b54a 915 break;
733b25e1 916 }
36b3b54a 917 case wxROMAN:
733b25e1
RR
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 }
36b3b54a 933 break;
733b25e1 934 }
36b3b54a 935 case wxSCRIPT:
733b25e1
RR
936 {
937 name = "/ZapfChancery-MediumItalic";
36b3b54a
RR
938 Style = wxNORMAL;
939 Weight = wxNORMAL;
940 break;
733b25e1
RR
941 }
942 case wxSWISS:
36b3b54a 943 default:
733b25e1
RR
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 }
36b3b54a 961 }
57c208c5 962
733b25e1 963 fprintf( m_pstream, name );
d7657f75 964 fprintf( m_pstream, " reencodeISO def\n" );
733b25e1 965 fprintf( m_pstream, name );
d7657f75 966 fprintf( m_pstream, " findfont\n" );
ce7f10f2 967
733b25e1 968 char buffer[100];
6a7b1d6e 969 sprintf( buffer, "%f scalefont setfont\n", LogicalToDeviceYRel(m_font.GetPointSize() * 1000) / 1000.0F);
ce7f10f2 970 // this is a hack - we must scale font size (in pts) according to m_scaleY but
6a7b1d6e 971 // LogicalToDeviceYRel works with wxCoord type (int or longint). Se we first convert font size
479cd5de 972 // to 1/1000th of pt and then back.
b64de916
VS
973 for (int i = 0; i < 100; i++)
974 if (buffer[i] == ',') buffer[i] = '.';
975 fprintf( m_pstream, buffer );
c31c771b 976#endif
ed880dd4
RR
977}
978
979void wxPostScriptDC::SetPen( const wxPen& pen )
980{
223d09f6 981 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 982
ed880dd4 983 if (!pen.Ok()) return;
afce4c03 984
ed880dd4
RR
985 int oldStyle = m_pen.GetStyle();
986
987 m_pen = pen;
988
f6bcfd97
BP
989 {
990 char buffer[100];
991 #ifdef __WXMSW__
6a7b1d6e 992 sprintf( buffer, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen.GetWidth()) / 1000.0f );
f6bcfd97 993 #else
6a7b1d6e 994 sprintf( buffer, "%f setlinewidth\n", LogicalToDeviceXRel(1000 * m_pen.GetWidth()) / 1000.0f );
f6bcfd97
BP
995 #endif
996 for (int i = 0; i < 100; i++)
3ca6a5f0 997 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97
BP
998 fprintf( m_pstream, buffer );
999 }
1000
ed880dd4
RR
1001/*
1002 Line style - WRONG: 2nd arg is OFFSET
afce4c03 1003
ed880dd4
RR
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
72cdf4c9 1009 will be first black line *2* units wxCoord, then space 4 units, then the
ed880dd4
RR
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";
72cdf4c9 1015 static const char *wxCoord_dashed = "[4 8] 2";
ed880dd4
RR
1016 static const char *dotted_dashed = "[6 6 2 6] 4";
1017
1018 const char *psdash = (char *) NULL;
d7657f75 1019 switch (m_pen.GetStyle())
ed880dd4
RR
1020 {
1021 case wxDOT: psdash = dotted; break;
1022 case wxSHORT_DASH: psdash = short_dashed; break;
72cdf4c9 1023 case wxLONG_DASH: psdash = wxCoord_dashed; break;
ed880dd4
RR
1024 case wxDOT_DASH: psdash = dotted_dashed; break;
1025 case wxSOLID:
1026 case wxTRANSPARENT:
1027 default: psdash = "[] 0"; break;
1028 }
afce4c03 1029
ed880dd4
RR
1030 if (oldStyle != m_pen.GetStyle())
1031 {
d7657f75 1032 fprintf( m_pstream, psdash );
72cdf4c9 1033 fprintf( m_pstream," setdash\n" );
ed880dd4
RR
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
72cdf4c9
VZ
1044 if (! (red == (unsigned char) 255 &&
1045 blue == (unsigned char) 255 &&
d7657f75
RR
1046 green == (unsigned char) 255) )
1047 {
1048 red = (unsigned char) 0;
1049 green = (unsigned char) 0;
1050 blue = (unsigned char) 0;
72cdf4c9 1051 }
d7657f75 1052 // setgray here ?
ed880dd4
RR
1053 }
1054
1055 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1056 {
d7657f75
RR
1057 double redPS = (double)(red) / 255.0;
1058 double bluePS = (double)(blue) / 255.0;
1059 double greenPS = (double)(green) / 255.0;
3ca6a5f0 1060
f6bcfd97
BP
1061 char buffer[100];
1062 sprintf( buffer,
72cdf4c9
VZ
1063 "%.8f %.8f %.8f setrgbcolor\n",
1064 redPS, greenPS, bluePS );
f6bcfd97 1065 for (int i = 0; i < 100; i++)
3ca6a5f0 1066 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1067 fprintf( m_pstream, buffer );
72cdf4c9 1068
d7657f75
RR
1069 m_currentRed = red;
1070 m_currentBlue = blue;
1071 m_currentGreen = green;
ed880dd4
RR
1072 }
1073}
1074
1075void wxPostScriptDC::SetBrush( const wxBrush& brush )
1076{
223d09f6 1077 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1078
ed880dd4 1079 if (!brush.Ok()) return;
afce4c03 1080
ed880dd4
RR
1081 m_brush = brush;
1082
1083 // Brush colour
3c1b65a4
RR
1084 unsigned char red = m_brush.GetColour().Red();
1085 unsigned char blue = m_brush.GetColour().Blue();
1086 unsigned char green = m_brush.GetColour().Green();
ed880dd4
RR
1087
1088 if (!m_colour)
1089 {
d7657f75 1090 // Anything not white is black
72cdf4c9
VZ
1091 if (! (red == (unsigned char) 255 &&
1092 blue == (unsigned char) 255 &&
d7657f75
RR
1093 green == (unsigned char) 255) )
1094 {
1095 red = (unsigned char) 0;
1096 green = (unsigned char) 0;
1097 blue = (unsigned char) 0;
72cdf4c9 1098 }
d7657f75 1099 // setgray here ?
ed880dd4 1100 }
72cdf4c9 1101
ed880dd4
RR
1102 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1103 {
d7657f75
RR
1104 double redPS = (double)(red) / 255.0;
1105 double bluePS = (double)(blue) / 255.0;
1106 double greenPS = (double)(green) / 255.0;
72cdf4c9 1107
f6bcfd97
BP
1108 char buffer[100];
1109 sprintf( buffer,
72cdf4c9
VZ
1110 "%.8f %.8f %.8f setrgbcolor\n",
1111 redPS, greenPS, bluePS );
f6bcfd97 1112 for (int i = 0; i < 100; i++)
3ca6a5f0 1113 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1114 fprintf( m_pstream, buffer );
72cdf4c9 1115
d7657f75
RR
1116 m_currentRed = red;
1117 m_currentBlue = blue;
1118 m_currentGreen = green;
ed880dd4
RR
1119 }
1120}
1121
2b5f62a0 1122#if wxUSE_PANGO
46eed000 1123
eba33006
RR
1124#define PANGO_ENABLE_ENGINE
1125
2b5f62a0 1126#ifdef __WXGTK20__
46eed000 1127#include "wx/gtk/private.h"
46eed000 1128#include "gtk/gtk.h"
2b5f62a0
VZ
1129#else
1130#include "wx/x11/private.h"
1131#endif
1132
1133#include "wx/fontutil.h"
46eed000 1134#include <pango/pangoft2.h>
c31c771b
RR
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
1144typedef struct _OutlineInfo OutlineInfo;
1145struct _OutlineInfo {
bdaac0eb 1146 FILE *file;
c31c771b
RR
1147};
1148
1149static int paps_move_to( FT_Vector* to,
1150 void *user_data)
1151{
1152 OutlineInfo *outline_info = (OutlineInfo*)user_data;
bdaac0eb 1153 fprintf(outline_info->file, "%d %d moveto\n",
c31c771b
RR
1154 (int)to->x ,
1155 (int)to->y );
1156 return 0;
1157}
1158
1159static int paps_line_to( FT_Vector* to,
1160 void *user_data)
1161{
1162 OutlineInfo *outline_info = (OutlineInfo*)user_data;
bdaac0eb 1163 fprintf(outline_info->file, "%d %d lineto\n",
c31c771b
RR
1164 (int)to->x ,
1165 (int)to->y );
1166 return 0;
1167}
1168
1169static int paps_conic_to( FT_Vector* control,
1170 FT_Vector* to,
1171 void *user_data)
1172{
1173 OutlineInfo *outline_info = (OutlineInfo*)user_data;
bdaac0eb 1174 fprintf(outline_info->file, "%d %d %d %d conicto\n",
c31c771b
RR
1175 (int)control->x ,
1176 (int)control->y ,
1177 (int)to->x ,
1178 (int)to->y );
1179 return 0;
1180}
1181
1182static 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;
bdaac0eb 1188 fprintf(outline_info->file,
c31c771b
RR
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
bdaac0eb 1199void draw_bezier_outline(FILE *file,
c31c771b
RR
1200 FT_Face face,
1201 FT_UInt glyph_index,
bdaac0eb
RR
1202 int pos_x,
1203 int pos_y,
1204 int scale_x,
1205 int scale_y )
c31c771b 1206{
bdaac0eb 1207 FT_Int load_flags = FT_LOAD_NO_BITMAP;
c31c771b
RR
1208 FT_Glyph glyph;
1209
c31c771b
RR
1210 FT_Outline_Funcs outlinefunc =
1211 {
1212 paps_move_to,
1213 paps_line_to,
1214 paps_conic_to,
1215 paps_cubic_to
1216 };
bdaac0eb 1217
c31c771b 1218 OutlineInfo outline_info;
bdaac0eb 1219 outline_info.file = file;
c31c771b 1220
bdaac0eb
RR
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");
c31c771b
RR
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);
bdaac0eb 1232 fprintf(file, "closepath fill grestore \n");
c31c771b
RR
1233
1234 FT_Done_Glyph (glyph);
1235}
1236
46eed000
RR
1237#endif
1238
72cdf4c9 1239void wxPostScriptDC::DoDrawText( const wxString& text, wxCoord x, wxCoord y )
ed880dd4 1240{
223d09f6 1241 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
479cd5de 1242
2b5f62a0 1243#if wxUSE_PANGO
eba33006 1244 int dpi = GetResolution();
bdaac0eb 1245 dpi = 300;
c31c771b 1246 PangoContext *context = pango_ft2_get_context ( dpi, dpi );
46eed000 1247
46eed000
RR
1248 pango_context_set_language (context, pango_language_from_string ("en_US"));
1249 pango_context_set_base_dir (context, PANGO_DIRECTION_LTR );
1250
46eed000
RR
1251 pango_context_set_font_description (context, m_font.GetNativeFontInfo()->description );
1252
eba33006 1253 PangoLayout *layout = pango_layout_new (context);
46eed000
RR
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) );
c31c771b 1260
bdaac0eb
RR
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 );
eba33006 1269
c31c771b
RR
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;
eba33006
RR
1291 int pos_x = xx + geometry.x_offset;
1292 int pos_y = yy - geometry.y_offset;
1293 xx += geometry.width;
1294
bdaac0eb 1295 draw_bezier_outline( m_pstream, ft_face,
c31c771b 1296 (FT_UInt)(glyphs->glyphs[glyph_idx].glyph),
bdaac0eb
RR
1297 LogicalToDeviceX( pos_x / PANGO_SCALE ),
1298 LogicalToDeviceY( pos_y / PANGO_SCALE ),
1299 scale_x, scale_y );
c31c771b
RR
1300 }
1301 runs_list = runs_list->next;
1302 }
1303 }
46eed000 1304
3fc306e9 1305 g_object_unref( G_OBJECT( layout ) );
46eed000 1306#else
6c3d9ced 1307 wxCoord text_w, text_h, text_descent;
479cd5de 1308
6c3d9ced 1309 GetTextExtent(text, &text_w, &text_h, &text_descent);
afce4c03 1310
080b749f
VZ
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 );
ed880dd4 1314
d7657f75 1315 if (m_textForegroundColour.Ok())
ed880dd4 1316 {
d7657f75
RR
1317 unsigned char red = m_textForegroundColour.Red();
1318 unsigned char blue = m_textForegroundColour.Blue();
1319 unsigned char green = m_textForegroundColour.Green();
ed880dd4
RR
1320
1321 if (!m_colour)
9a6be59a 1322 {
d7657f75 1323 // Anything not white is black
72cdf4c9
VZ
1324 if (! (red == (unsigned char) 255 &&
1325 blue == (unsigned char) 255 &&
1326 green == (unsigned char) 255))
d7657f75
RR
1327 {
1328 red = (unsigned char) 0;
1329 green = (unsigned char) 0;
1330 blue = (unsigned char) 0;
1331 }
9a6be59a 1332 }
afce4c03 1333
d7657f75 1334 // maybe setgray here ?
ed880dd4
RR
1335 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1336 {
d7657f75
RR
1337 double redPS = (double)(red) / 255.0;
1338 double bluePS = (double)(blue) / 255.0;
1339 double greenPS = (double)(green) / 255.0;
72cdf4c9 1340
f6bcfd97
BP
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++)
3ca6a5f0 1346 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1347 fprintf( m_pstream, buffer );
72cdf4c9 1348
ed880dd4
RR
1349 m_currentRed = red;
1350 m_currentBlue = blue;
1351 m_currentGreen = green;
1352 }
1353 }
1354
1355 int size = m_font.GetPointSize();
1356
6c3d9ced
VS
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
6a7b1d6e 1361 fprintf( m_pstream, "%d %d moveto\n", LogicalToDeviceX(x), LogicalToDeviceY(by) );
afce4c03 1362
d7657f75 1363 fprintf( m_pstream, "(" );
9626e0bf 1364 const wxWX2MBbuf textbuf = text.mb_str();
b2abc293
VS
1365 size_t len = strlen(textbuf);
1366 size_t i;
ed880dd4
RR
1367 for (i = 0; i < len; i++)
1368 {
87138c52 1369 int c = (unsigned char) textbuf[i];
d7657f75 1370 if (c == ')' || c == '(' || c == '\\')
ed880dd4 1371 {
d7657f75 1372 /* Cope with special characters */
72cdf4c9 1373 fprintf( m_pstream, "\\" );
2d5e89e1 1374 fputc(c, m_pstream);
ed880dd4
RR
1375 }
1376 else if ( c >= 128 )
1377 {
d7657f75 1378 /* Cope with character codes > 127 */
72cdf4c9 1379 fprintf(m_pstream, "\\%o", c);
ed880dd4
RR
1380 }
1381 else
72cdf4c9 1382 {
2d5e89e1 1383 fputc(c, m_pstream);
72cdf4c9 1384 }
ed880dd4 1385 }
72cdf4c9 1386
d7657f75 1387 fprintf( m_pstream, ") show\n" );
ed880dd4
RR
1388
1389 if (m_font.GetUnderlined())
1390 {
72cdf4c9 1391 wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
f6bcfd97 1392 char buffer[100];
afce4c03 1393
f6bcfd97 1394 sprintf( buffer,
72cdf4c9
VZ
1395 "gsave\n"
1396 "%d %d moveto\n"
f6bcfd97 1397 "%f setlinewidth\n"
72cdf4c9
VZ
1398 "%d %d lineto\n"
1399 "stroke\n"
1400 "grestore\n",
6a7b1d6e 1401 LogicalToDeviceX(x), LogicalToDeviceY(uy),
f6bcfd97 1402 m_underlineThickness,
6a7b1d6e 1403 LogicalToDeviceX(x + text_w), LogicalToDeviceY(uy) );
f6bcfd97 1404 for (i = 0; i < 100; i++)
3ca6a5f0 1405 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1406 fprintf( m_pstream, buffer );
ed880dd4 1407 }
afce4c03 1408
ed880dd4
RR
1409 CalcBoundingBox( x, y );
1410 CalcBoundingBox( x + size * text.Length() * 2/3 , y );
46eed000 1411#endif
ed880dd4
RR
1412}
1413
95724b1a
VZ
1414void 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
479cd5de
VZ
1435 if (! (red == (unsigned char) 255 &&
1436 blue == (unsigned char) 255 &&
1437 green == (unsigned char) 255))
95724b1a
VZ
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;
479cd5de 1451
f6bcfd97
BP
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++)
3ca6a5f0 1457 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1458 fprintf( m_pstream, buffer );
479cd5de 1459
95724b1a
VZ
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
70846f0a 1470 // FIXME only correct for 90 degrees
06b466c7 1471 fprintf(m_pstream, "%d %d moveto\n",
6a7b1d6e 1472 LogicalToDeviceX((wxCoord)(x + size)), LogicalToDeviceY((wxCoord)by) );
3ca6a5f0 1473
f6bcfd97
BP
1474 char buffer[100];
1475 sprintf(buffer, "%.8f rotate\n", angle);
b2abc293 1476 size_t i;
f6bcfd97 1477 for (i = 0; i < 100; i++)
3ca6a5f0 1478 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1479 fprintf(m_pstream, buffer);
95724b1a 1480
95724b1a
VZ
1481 fprintf( m_pstream, "(" );
1482 const wxWX2MBbuf textbuf = text.mb_str();
b2abc293 1483 size_t len = strlen(textbuf);
95724b1a
VZ
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 */
479cd5de 1490 fprintf( m_pstream, "\\" );
2d5e89e1 1491 fputc(c, m_pstream);
95724b1a
VZ
1492 }
1493 else if ( c >= 128 )
1494 {
1495 /* Cope with character codes > 127 */
479cd5de 1496 fprintf(m_pstream, "\\%o", c);
95724b1a
VZ
1497 }
1498 else
479cd5de 1499 {
2d5e89e1 1500 fputc(c, m_pstream);
479cd5de 1501 }
95724b1a 1502 }
479cd5de 1503
95724b1a 1504 fprintf( m_pstream, ") show\n" );
3ca6a5f0 1505
f6bcfd97
BP
1506 sprintf( buffer, "%.8f rotate\n", -angle );
1507 for (i = 0; i < 100; i++)
3ca6a5f0 1508 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1509 fprintf( m_pstream, buffer );
95724b1a
VZ
1510
1511 if (m_font.GetUnderlined())
1512 {
06b466c7
VZ
1513 wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
1514 wxCoord w, h;
f6bcfd97 1515 char buffer[100];
95724b1a
VZ
1516 GetTextExtent(text, &w, &h);
1517
f6bcfd97 1518 sprintf( buffer,
70846f0a 1519 "gsave\n"
479cd5de 1520 "%d %d moveto\n"
f6bcfd97 1521 "%f setlinewidth\n"
70846f0a
VZ
1522 "%d %d lineto\n"
1523 "stroke\n"
479cd5de 1524 "grestore\n",
6a7b1d6e 1525 LogicalToDeviceX(x), LogicalToDeviceY(uy),
f6bcfd97 1526 m_underlineThickness,
6a7b1d6e 1527 LogicalToDeviceX(x + w), LogicalToDeviceY(uy) );
f6bcfd97 1528 for (i = 0; i < 100; i++)
3ca6a5f0 1529 if (buffer[i] == ',') buffer[i] = '.';
f6bcfd97 1530 fprintf( m_pstream, buffer );
95724b1a
VZ
1531 }
1532
1533 CalcBoundingBox( x, y );
1534 CalcBoundingBox( x + size * text.Length() * 2/3 , y );
1535}
ed880dd4
RR
1536
1537void wxPostScriptDC::SetBackground (const wxBrush& brush)
1538{
1539 m_backgroundBrush = brush;
1540}
1541
1542void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function))
1543{
223d09f6 1544 wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") );
ed880dd4
RR
1545}
1546
64698f9a 1547void wxPostScriptDC::DoDrawSpline( wxList *points )
ed880dd4 1548{
223d09f6 1549 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1550
ed880dd4
RR
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();
afce4c03 1558 x1 = p->x;
ed880dd4
RR
1559 y1 = p->y;
1560
1561 node = node->Next();
1562 p = (wxPoint *)node->Data();
afce4c03 1563 c = p->x;
ed880dd4
RR
1564 d = p->y;
1565 x3 = a = (double)(x1 + c) / 2;
1566 y3 = b = (double)(y1 + d) / 2;
1567
72cdf4c9 1568 fprintf( m_pstream,
d7657f75 1569 "newpath\n"
72cdf4c9
VZ
1570 "%d %d moveto\n"
1571 "%d %d lineto\n",
6a7b1d6e
RD
1572 LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1),
1573 LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
afce4c03 1574
72cdf4c9
VZ
1575 CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1576 CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
ed880dd4
RR
1577
1578 while ((node = node->Next()) != NULL)
1579 {
1580 q = (wxPoint *)node->Data();
1581
d7657f75
RR
1582 x1 = x3;
1583 y1 = y3;
1584 x2 = c;
1585 y2 = d;
1586 c = q->x;
1587 d = q->y;
ed880dd4
RR
1588 x3 = (double)(x2 + c) / 2;
1589 y3 = (double)(y2 + d) / 2;
72cdf4c9
VZ
1590
1591 fprintf( m_pstream,
1592 "%d %d %d %d %d %d DrawSplineSection\n",
6a7b1d6e
RD
1593 LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1),
1594 LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2),
1595 LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
72cdf4c9
VZ
1596
1597 CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1598 CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
ed880dd4 1599 }
afce4c03 1600
72cdf4c9
VZ
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 */
ed880dd4 1605
d7657f75 1606 fprintf( m_pstream,
72cdf4c9
VZ
1607 "%d %d lineto\n"
1608 "stroke\n",
6a7b1d6e 1609 LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) );
ed880dd4
RR
1610}
1611
72cdf4c9 1612wxCoord wxPostScriptDC::GetCharWidth() const
ed880dd4
RR
1613{
1614 // Chris Breeze: reasonable approximation using wxMODERN/Courier
72cdf4c9 1615 return (wxCoord) (GetCharHeight() * 72.0 / 120.0);
ed880dd4
RR
1616}
1617
1618
1619void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1620{
223d09f6 1621 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1622
ed880dd4
RR
1623 m_signX = (xLeftRight ? 1 : -1);
1624 m_signY = (yBottomUp ? 1 : -1);
afce4c03 1625
004fd0c8
DW
1626 // FIXME there is no such function in MSW nor in OS2/PM
1627#if !defined(__WXMSW__) && !defined(__WXPM__)
ed880dd4 1628 ComputeScaleAndOrigin();
9a6be59a 1629#endif
ed880dd4
RR
1630}
1631
72cdf4c9 1632void wxPostScriptDC::SetDeviceOrigin( wxCoord x, wxCoord y )
ed880dd4 1633{
223d09f6 1634 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1635
4bc67cc5
RR
1636 int h = 0;
1637 int w = 0;
1638 GetSize( &w, &h );
afce4c03 1639
4bc67cc5 1640 wxDC::SetDeviceOrigin( x, h-y );
ed880dd4
RR
1641}
1642
4e4ea166 1643void wxPostScriptDC::DoGetSize(int* width, int* height) const
ed880dd4 1644{
7bcb11d3 1645 wxPaperSize id = m_printData.GetPaperId();
ed880dd4 1646
7bcb11d3 1647 wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
afce4c03 1648
7bcb11d3 1649 if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
afce4c03 1650
ac2def68
RR
1651 int w = 595;
1652 int h = 842;
ed880dd4
RR
1653 if (paper)
1654 {
ac2def68
RR
1655 w = paper->GetSizeDeviceUnits().x;
1656 h = paper->GetSizeDeviceUnits().y;
ed880dd4 1657 }
72cdf4c9 1658
ac2def68 1659 if (m_printData.GetOrientation() == wxLANDSCAPE)
ed880dd4 1660 {
ac2def68 1661 int tmp = w;
72cdf4c9
VZ
1662 w = h;
1663 h = tmp;
ed880dd4 1664 }
72cdf4c9 1665
b64de916
VS
1666 if (width) *width = (int)(w * ms_PSScaleFactor);
1667 if (height) *height = (int)(h * ms_PSScaleFactor);
ed880dd4
RR
1668}
1669
4e4ea166 1670void wxPostScriptDC::DoGetSizeMM(int *width, int *height) const
ed880dd4 1671{
7bcb11d3
JS
1672 wxPaperSize id = m_printData.GetPaperId();
1673
1674 wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
afce4c03 1675
7bcb11d3
JS
1676 if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
1677
ac2def68
RR
1678 int w = 210;
1679 int h = 297;
7bcb11d3 1680 if (paper)
ed880dd4 1681 {
ac2def68
RR
1682 w = paper->GetWidth() / 10;
1683 h = paper->GetHeight() / 10;
ed880dd4 1684 }
72cdf4c9 1685
ac2def68 1686 if (m_printData.GetOrientation() == wxLANDSCAPE)
ed880dd4 1687 {
ac2def68 1688 int tmp = w;
72cdf4c9
VZ
1689 w = h;
1690 h = tmp;
ed880dd4 1691 }
72cdf4c9 1692
ac2def68
RR
1693 if (width) *width = w;
1694 if (height) *height = h;
7bcb11d3
JS
1695}
1696
1697// Resolution in pixels per logical inch
1698wxSize wxPostScriptDC::GetPPI(void) const
1699{
48c31b28 1700 return wxSize((int)(72 * ms_PSScaleFactor),
b64de916 1701 (int)(72 * ms_PSScaleFactor));
7bcb11d3 1702}
ed880dd4 1703
7bcb11d3 1704
d7657f75 1705bool wxPostScriptDC::StartDoc( const wxString& message )
7bcb11d3 1706{
223d09f6 1707 wxCHECK_MSG( m_ok, FALSE, wxT("invalid postscript dc") );
7bcb11d3 1708
2b5f62a0 1709 if (m_printData.GetFilename() == wxT(""))
7bcb11d3 1710 {
2b5f62a0 1711 wxString filename = wxGetTempFileName( wxT("ps") );
7bcb11d3 1712 m_printData.SetFilename(filename);
7bcb11d3 1713 }
72cdf4c9 1714
401eb3de 1715 m_pstream = wxFopen( m_printData.GetFilename().c_str(), wxT("w+") ); // FIXME: use fn_str() here under Unicode?
7bcb11d3 1716
d7657f75 1717 if (!m_pstream)
ed880dd4 1718 {
f6bcfd97 1719 wxLogError( _("Cannot open file for PostScript printing!"));
7bcb11d3
JS
1720 m_ok = FALSE;
1721 return FALSE;
ed880dd4 1722 }
afce4c03 1723
ed880dd4
RR
1724 m_ok = TRUE;
1725
eba33006
RR
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
09c9194a
RR
1735 // fprintf( m_pstream, "%%%%Pages: %d\n", (wxPageNumber - 1) );
1736
3fc306e9
RR
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 );
eba33006
RR
1757 fprintf( m_pstream, "%%%%EndComments\n\n" );
1758
d7657f75 1759 fprintf( m_pstream, "%%%%BeginProlog\n" );
c31c771b 1760 fprintf( m_pstream, wxPostScriptHeaderConicTo );
d7657f75
RR
1761 fprintf( m_pstream, wxPostScriptHeaderEllipse );
1762 fprintf( m_pstream, wxPostScriptHeaderEllipticArc );
1763 fprintf( m_pstream, wxPostScriptHeaderColourImage );
2b5f62a0
VZ
1764#if wxUSE_PANGO
1765#else
d7657f75
RR
1766 fprintf( m_pstream, wxPostScriptHeaderReencodeISO1 );
1767 fprintf( m_pstream, wxPostScriptHeaderReencodeISO2 );
c31c771b 1768#endif
d7657f75
RR
1769 if (wxPostScriptHeaderSpline)
1770 fprintf( m_pstream, wxPostScriptHeaderSpline );
1771 fprintf( m_pstream, "%%%%EndProlog\n" );
1772
ed880dd4
RR
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 );
afce4c03 1780
ed880dd4
RR
1781 wxPageNumber = 1;
1782 m_pageNumber = 1;
1783 m_title = message;
1784 return TRUE;
1785}
1786
1787void wxPostScriptDC::EndDoc ()
1788{
223d09f6 1789 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1790
ed880dd4
RR
1791 if (m_clipping)
1792 {
1793 m_clipping = FALSE;
72cdf4c9 1794 fprintf( m_pstream, "grestore\n" );
ed880dd4
RR
1795 }
1796
d7657f75
RR
1797 fclose( m_pstream );
1798 m_pstream = (FILE *) NULL;
ed880dd4 1799
eba33006 1800#if 0
ed880dd4 1801 // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com>
72cdf4c9 1802 wxCoord wx_printer_translate_x, wx_printer_translate_y;
ed880dd4 1803 double wx_printer_scale_x, wx_printer_scale_y;
ed880dd4 1804
479cd5de
VZ
1805 wx_printer_translate_x = (wxCoord)m_printData.GetPrinterTranslateX();
1806 wx_printer_translate_y = (wxCoord)m_printData.GetPrinterTranslateY();
7bcb11d3
JS
1807
1808 wx_printer_scale_x = m_printData.GetPrinterScaleX();
1809 wx_printer_scale_y = m_printData.GetPrinterScaleY();
1810
ed880dd4
RR
1811 // Compute the bounding box. Note that it is in the default user
1812 // coordinate system, thus we have to convert the values.
6a7b1d6e
RD
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);
48c31b28 1817
a30f8da8
VS
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; }
48c31b28 1821
a30f8da8
VS
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;
48c31b28
VZ
1825
1826 wxCoord llx, lly, urx, ury;
a30f8da8
VS
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
ed880dd4
RR
1833
1834 // If we're landscape, our sense of "x" and "y" is reversed.
7bcb11d3 1835 if (m_printData.GetOrientation() == wxLANDSCAPE)
ed880dd4 1836 {
72cdf4c9 1837 wxCoord tmp;
ed880dd4
RR
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.
72cdf4c9
VZ
1843 llx = llx - (wxCoord)(m_minX*wx_printer_scale_y);
1844 urx = urx - (wxCoord)(m_minX*wx_printer_scale_y);
ed880dd4
RR
1845 }
1846
1847 // The Adobe specifications call for integers; we round as to make
1848 // the bounding larger.
72cdf4c9
VZ
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) );
ed880dd4
RR
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.
d7657f75 1860 fprintf( m_pstream, "%% newpath\n" );
72cdf4c9
VZ
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 );
09c9194a 1865#endif
ed880dd4 1866
ed880dd4 1867#if defined(__X__) || defined(__WXGTK__)
3fc306e9 1868 if (m_ok && (m_printData.GetPrintMode() == wxPRINT_MODE_PRINTER))
ed880dd4 1869 {
09c9194a
RR
1870 wxString command;
1871 command += m_printData.GetPrinterCommand();
1872 command += wxT(" ");
1873 command += m_printData.GetFilename();
ed880dd4 1874
09c9194a
RR
1875 wxExecute( command, TRUE );
1876 wxRemoveFile( m_printData.GetFilename() );
ed880dd4
RR
1877 }
1878#endif
1879}
1880
d7657f75 1881void wxPostScriptDC::StartPage()
ed880dd4 1882{
223d09f6 1883 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1884
d7657f75 1885 fprintf( m_pstream, "%%%%Page: %d\n", wxPageNumber++ );
afce4c03 1886
ac2def68 1887 // What is this one supposed to do? RR.
ed880dd4
RR
1888// *m_pstream << "matrix currentmatrix\n";
1889
1890 // Added by Chris Breeze
1891
9a6be59a
VZ
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)
afce4c03 1895
afce4c03 1896 // Output scaling
72cdf4c9 1897 wxCoord translate_x, translate_y;
afce4c03 1898 double scale_x, scale_y;
afce4c03 1899
479cd5de
VZ
1900 translate_x = (wxCoord)m_printData.GetPrinterTranslateX();
1901 translate_y = (wxCoord)m_printData.GetPrinterTranslateY();
7bcb11d3
JS
1902
1903 scale_x = m_printData.GetPrinterScaleX();
1904 scale_y = m_printData.GetPrinterScaleY();
1905
1906 if (m_printData.GetOrientation() == wxLANDSCAPE)
afce4c03 1907 {
ac2def68
RR
1908 int h;
1909 GetSize( (int*) NULL, &h );
1910 translate_y -= h;
1911 fprintf( m_pstream, "90 rotate\n" );
72cdf4c9 1912
ac2def68 1913 // I copied this one from a PostScript tutorial, but to no avail. RR.
72cdf4c9 1914 // fprintf( m_pstream, "90 rotate llx neg ury nef translate\n" );
afce4c03
VZ
1915 }
1916
f6bcfd97 1917 char buffer[100];
48c31b28 1918 sprintf( buffer, "%.8f %.8f scale\n", scale_x / ms_PSScaleFactor,
b64de916 1919 scale_y / ms_PSScaleFactor);
f6bcfd97
BP
1920 for (int i = 0; i < 100; i++)
1921 if (buffer[i] == ',') buffer[i] = '.';
1922 fprintf( m_pstream, buffer );
3ca6a5f0 1923
72cdf4c9 1924 fprintf( m_pstream, "%d %d translate\n", translate_x, translate_y );
ed880dd4
RR
1925}
1926
1927void wxPostScriptDC::EndPage ()
1928{
223d09f6 1929 wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
afce4c03 1930
d7657f75 1931 fprintf( m_pstream, "showpage\n" );
ed880dd4
RR
1932}
1933
72cdf4c9
VZ
1934bool wxPostScriptDC::DoBlit( wxCoord xdest, wxCoord ydest,
1935 wxCoord fwidth, wxCoord fheight,
afce4c03 1936 wxDC *source,
72cdf4c9 1937 wxCoord xsrc, wxCoord ysrc,
f0a6b1cd 1938 int rop, bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) )
ed880dd4 1939{
223d09f6 1940 wxCHECK_MSG( m_ok && m_pstream, FALSE, wxT("invalid postscript dc") );
afce4c03 1941
223d09f6 1942 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
afce4c03 1943
342b6a2f 1944 /* blit into a bitmap */
afce4c03 1945 wxBitmap bitmap( (int)fwidth, (int)fheight );
45b776d4
JS
1946 wxMemoryDC memDC;
1947 memDC.SelectObject(bitmap);
342b6a2f 1948 memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */
45b776d4 1949 memDC.SelectObject(wxNullBitmap);
ea6f44b5
RR
1950
1951 /* draw bitmap. scaling and positioning is done there */
ea6f44b5 1952 DrawBitmap( bitmap, xdest, ydest );
afce4c03 1953
ed880dd4
RR
1954 return TRUE;
1955}
1956
72cdf4c9 1957wxCoord wxPostScriptDC::GetCharHeight() const
ed880dd4
RR
1958{
1959 if (m_font.Ok())
b64de916 1960 return m_font.GetPointSize();
ed880dd4
RR
1961 else
1962 return 12;
1963}
1964
72cdf4c9
VZ
1965void wxPostScriptDC::DoGetTextExtent(const wxString& string,
1966 wxCoord *x, wxCoord *y,
1967 wxCoord *descent, wxCoord *externalLeading,
1968 wxFont *theFont ) const
ed880dd4 1969{
36b3b54a 1970 wxFont *fontToUse = theFont;
afce4c03 1971
36b3b54a
RR
1972 if (!fontToUse) fontToUse = (wxFont*) &m_font;
1973
223d09f6 1974 wxCHECK_RET( fontToUse, wxT("GetTextExtent: no font defined") );
87138c52 1975
3fc306e9
RR
1976 if (string.IsEmpty())
1977 {
1978 if (x) (*x) = 0;
1979 if (y) (*y) = 0;
1980 return;
1981 }
1982
2b5f62a0 1983#if wxUSE_PANGO
3fc306e9 1984 int dpi = GetResolution();
3fc306e9
RR
1985 PangoContext *context = pango_ft2_get_context ( dpi, dpi );
1986
3fc306e9
RR
1987 pango_context_set_language (context, pango_language_from_string ("en_US"));
1988 pango_context_set_base_dir (context, PANGO_DIRECTION_LTR );
1989
3fc306e9
RR
1990 PangoLayout *layout = pango_layout_new (context);
1991
3fc306e9
RR
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
bdaac0eb
RR
2007 if (x) (*x) = (wxCoord) ( m_scaleX * rect.width / PANGO_SCALE );
2008 if (y) (*y) = (wxCoord) ( m_scaleY * rect.height / PANGO_SCALE );
3fc306e9
RR
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
9626e0bf 2020 const wxWX2MBbuf strbuf = string.mb_str();
ed880dd4 2021
f036b31c 2022#if !wxUSE_AFM_FOR_POSTSCRIPT
36b3b54a
RR
2023 /* Provide a VERY rough estimate (avoid using it).
2024 * Produces accurate results for mono-spaced font
2025 * such as Courier (aka wxMODERN) */
afce4c03 2026
9a6be59a
VZ
2027 int height = 12;
2028 if (fontToUse)
2029 {
afce4c03 2030 height = fontToUse->GetPointSize();
9a6be59a 2031 }
72cdf4c9
VZ
2032 if ( x )
2033 *x = strlen (strbuf) * height * 72 / 120;
2034 if ( y )
2035 *y = (wxCoord) (height * 1.32); /* allow for descender */
36b3b54a
RR
2036 if (descent) *descent = 0;
2037 if (externalLeading) *externalLeading = 0;
ed880dd4 2038#else
ed880dd4 2039
afce4c03
VZ
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();
72cdf4c9 2067 / wxCoord w,h;
afce4c03
VZ
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 */
36b3b54a
RR
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 */
72cdf4c9 2085
a439ecef
VS
2086 double UnderlinePosition = 0.0;
2087 double UnderlineThickness = 0.0;
36b3b54a 2088
eba33006 2089 // Get actual parameters
733b25e1
RR
2090 int Family = fontToUse->GetFamily();
2091 int Size = fontToUse->GetPointSize();
2092 int Style = fontToUse->GetStyle();
2093 int Weight = fontToUse->GetWeight();
36b3b54a 2094
eba33006 2095 // If we have another font, read the font-metrics
36b3b54a
RR
2096 if (Family!=lastFamily || Size!=lastSize || Style!=lastStyle || Weight!=lastWeight)
2097 {
eba33006 2098 // Store actual values
36b3b54a
RR
2099 lastFamily = Family;
2100 lastSize = Size;
2101 lastStyle = Style;
2102 lastWeight = Weight;
2103
2b5f62a0 2104 const wxChar *name = NULL;
36b3b54a
RR
2105
2106 switch (Family)
afce4c03
VZ
2107 {
2108 case wxMODERN:
733b25e1
RR
2109 case wxTELETYPE:
2110 {
2b5f62a0
VZ
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");
afce4c03 2115 break;
733b25e1 2116 }
afce4c03 2117 case wxROMAN:
733b25e1 2118 {
2b5f62a0
VZ
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");
afce4c03 2123 break;
733b25e1
RR
2124 }
2125 case wxSCRIPT:
2126 {
2b5f62a0 2127 name = wxT("Zapf.afm");
733b25e1
RR
2128 Style = wxNORMAL;
2129 Weight = wxNORMAL;
2130 }
2131 case wxSWISS:
afce4c03 2132 default:
733b25e1 2133 {
2b5f62a0
VZ
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");
afce4c03 2138 break;
733b25e1 2139 }
afce4c03 2140 }
36b3b54a 2141
eba33006
RR
2142 FILE *afmFile = NULL;
2143
2144 // Get the directory of the AFM files
2145 wxString afmName;
72cdf4c9
VZ
2146 if (!m_printData.GetFontMetricPath().IsEmpty())
2147 {
021e0f21 2148 afmName = m_printData.GetFontMetricPath();
eba33006
RR
2149 afmName << wxFILE_SEP_PATH << name;
2150 afmFile = wxFopen(afmName,wxT("r"));
d361e74e 2151 }
72cdf4c9 2152
733b25e1 2153#if defined(__UNIX__) && !defined(__VMS__)
eba33006 2154 if (afmFile==NULL)
3e469ea3 2155 {
2c18f21d 2156 afmName = wxGetDataDir();
3e469ea3 2157 afmName << wxFILE_SEP_PATH
733b25e1
RR
2158#if defined(__LINUX__) || defined(__FREEBSD__)
2159 << wxT("gs_afm") << wxFILE_SEP_PATH
2160#else
021e0f21 2161 << wxT("afm") << wxFILE_SEP_PATH
733b25e1
RR
2162#endif
2163 << name;
021e0f21 2164 afmFile = wxFopen(afmName,wxT("r"));
3e469ea3 2165 }
3e469ea3 2166#endif
479cd5de 2167
eba33006
RR
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.). */
385bcb35 2181 if (afmFile==NULL)
36b3b54a 2182 {
ccbfa8ec 2183 wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() );
48c31b28 2184 wxLogDebug( wxT(" using approximate values"));
36b3b54a
RR
2185 for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
2186 lastDescender = -150; /* dito. */
ed880dd4 2187 }
afce4c03
VZ
2188 else
2189 {
36b3b54a
RR
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)
afce4c03 2199 {
36b3b54a 2200 /* A.) check for descender definition */
021e0f21 2201 if (strncmp(line,"Descender",9)==0)
afce4c03 2202 {
36b3b54a 2203 if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
021e0f21 2204 (strcmp(descString,"Descender")!=0))
afce4c03 2205 {
ccbfa8ec 2206 wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line );
36b3b54a
RR
2207 }
2208 }
2209 /* JC 1.) check for UnderlinePosition */
021e0f21 2210 else if(strncmp(line,"UnderlinePosition",17)==0)
afce4c03 2211 {
36b3b54a 2212 if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
021e0f21 2213 (strcmp(upString,"UnderlinePosition")!=0))
afce4c03 2214 {
ccbfa8ec 2215 wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line );
36b3b54a
RR
2216 }
2217 }
afce4c03 2218 /* JC 2.) check for UnderlineThickness */
021e0f21 2219 else if(strncmp(line,"UnderlineThickness",18)==0)
afce4c03 2220 {
36b3b54a 2221 if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
021e0f21 2222 (strcmp(utString,"UnderlineThickness")!=0))
afce4c03 2223 {
ccbfa8ec 2224 wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line );
36b3b54a
RR
2225 }
2226 }
afce4c03 2227 /* JC 3.) check for EncodingScheme */
021e0f21 2228 else if(strncmp(line,"EncodingScheme",14)==0)
afce4c03 2229 {
36b3b54a 2230 if ((sscanf(line,"%s%s",utString,encString)!=2) ||
021e0f21 2231 (strcmp(utString,"EncodingScheme")!=0))
afce4c03 2232 {
ccbfa8ec 2233 wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line );
36b3b54a 2234 }
021e0f21 2235 else if (strncmp(encString, "AdobeStandardEncoding", 21))
36b3b54a 2236 {
ccbfa8ec 2237 wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"),
3e469ea3 2238 afmName.c_str(),line, encString);
36b3b54a
RR
2239 }
2240 }
2241 /* B.) check for char-width */
021e0f21 2242 else if(strncmp(line,"C ",2)==0)
afce4c03 2243 {
36b3b54a 2244 if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
afce4c03 2245 {
ccbfa8ec 2246 wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line);
36b3b54a 2247 }
021e0f21 2248 if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
afce4c03 2249 {
ccbfa8ec 2250 wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line);
36b3b54a
RR
2251 }
2252 /* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
2253 if (ascii>=0 && ascii<256)
afce4c03 2254 {
36b3b54a
RR
2255 lastWidths[ascii] = cWidth; /* store width */
2256 }
afce4c03
VZ
2257 else
2258 {
2259 /* MATTHEW: this happens a lot; don't print an error */
48c31b28 2260 /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */
36b3b54a
RR
2261 }
2262 }
2263 /* C.) ignore other entries. */
2264 }
2265 fclose(afmFile);
ed880dd4 2266 }
36b3b54a 2267 /* hack to compute correct values for german 'Umlaute'
afce4c03
VZ
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 ... */
36b3b54a
RR
2271