~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/wxWidgets3/src/generic/dcpsg.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

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