1/////////////////////////////////////////////////////////////////////////////
2// Name:        svg.cpp
3// Purpose:     SVG sample
4// Author:      Chris Elliott
5// Modified by:
6// RCS-ID:      $Id: dcsvg.cpp 59238 2009-03-01 13:15:04Z CE $
7// Licence:     wxWindows license
8/////////////////////////////////////////////////////////////////////////////
9
10
11// For compilers that support precompilation, includes "wx/wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15#pragma hdrstop
16#endif
17
18#ifndef WX_PRECOMP
19#include "wx/wx.h"
20#endif
21
22#include "wx/svg/dcsvg.h"
23
24#include "wx/image.h"
25#include "wx/filename.h"
26
27#define wxSVG_DEBUG FALSE
28// or TRUE to see the calls being executed
29#define newline    wxString(wxT("\n"))
30#define space      wxString(wxT(" "))
31#define semicolon  wxString(wxT(";"))
32#define     wx_round(a)    (int)((a)+.5)
33
34#ifdef __BORLANDC__
35#pragma warn -rch
36#pragma warn -ccc
37#endif
38
39static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } ;
40
41wxString wxColStr ( wxColour c )
42{
43    unsigned char r, g, b ;
44    r = c.Red ();
45    g = c.Green ();
46    b = c. Blue ();
47
48    // possible Unicode bug here
49    wxString s = wxDecToHex(r) + wxDecToHex(g) + wxDecToHex(b) ;
50    return s ;
51}
52
53
54wxString wxBrushString ( wxColour c, int style )
55{
56    wxString s = wxT("fill:#") + wxColStr (c)  + semicolon + space ;
57    switch ( style )
58    {
59        case wxSOLID :
60            s = s + wxT("fill-opacity:1.0; ");
61            break ;
62        case wxTRANSPARENT:
63            s = s + wxT("fill-opacity:0.0; ");
64            break ;
65
66        default :
67            wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::Requested Brush Style not available")) ;
68
69    }
70    s = s + newline ;
71    return s ;
72}
73
74
75void wxSVGFileDC::Init (wxString f, int Width, int Height, float dpi)
76
77{
78    //set up things first  wxDCBase does all this?
79    m_width = Width ;
80    m_height = Height ;
81
82    m_clipping = FALSE;
83    m_OK = TRUE;
84
85    m_mm_to_pix_x = dpi/25.4;
86    m_mm_to_pix_y = dpi/25.4;
87
88    m_signX = m_signY = 1;
89
90    m_userScaleX = m_userScaleY = 1.0 ;
91        m_deviceOriginX = m_deviceOriginY = 0;
92
93    m_OriginX = m_OriginY = 0;
94    m_logicalOriginX = m_logicalOriginY = 0;
95    m_logicalScaleX = m_logicalScaleY = 1.0 ;
96    m_scaleX = m_scaleY = 1.0 ;
97
98    m_logicalFunction = wxCOPY;
99    m_backgroundMode = wxTRANSPARENT;
100    m_mappingMode = wxMM_TEXT;
101
102    m_backgroundBrush = *wxTRANSPARENT_BRUSH;
103    m_textForegroundColour = *wxBLACK;
104    m_textBackgroundColour = *wxWHITE;
105    m_colour = wxColourDisplay();
106
107    m_pen   = *wxBLACK_PEN;
108    m_font  = *wxNORMAL_FONT;
109    m_brush = *wxWHITE_BRUSH;
110
111    m_graphics_changed = TRUE ;
112
113    ////////////////////code here
114
115    m_outfile = new wxFileOutputStream(f) ;
116    m_OK = m_outfile->Ok ();
117    if (m_OK)
118    {
119        m_filename = f ;
120        m_sub_images = 0 ;
121        wxString s ;
122        s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") ; s = s + newline ;
123        write(s);
124        s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + newline ;
125        write(s);
126        s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + newline ;
127        write(s);
128        s =  wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + newline;
129        write(s);
130        s.Printf( wxT("    width=\"%.2gcm\" height=\"%.2gcm\" viewBox=\"0 0 %d %d \"> \n"), float(Width)/dpi*2.54, float(Height)/dpi*2.54, Width, Height );
131        write(s);
132        s = wxT("<title>SVG Picture created as ") + wxFileNameFromPath(f) + wxT(" </title>") + newline ;
133        write(s);
134        s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ newline ;
135        write(s);
136        s =  wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + newline ;
137        write(s);
138
139    }
140}
141
142
143// constructors
144wxSVGFileDC::wxSVGFileDC (wxString f)
145{
146    // quarter 640x480 screen display at 72 dpi
147    Init (f,320,240,72.0);
148};
149
150wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height)
151{
152    Init (f,Width,Height,72.0);
153};
154
155wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height, float dpi)
156{
157    Init (f,Width,Height,dpi);
158};
159
160wxSVGFileDC::~wxSVGFileDC()
161{
162    wxString s = wxT("</g> \n</svg> \n") ;
163    write(s);
164    delete m_outfile ;
165}
166
167
168//////////////////////////////////////////////////////////////////////////////////////////
169
170void wxSVGFileDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
171{
172    if (m_graphics_changed) NewGraphics ();
173    wxString s ;
174    s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
175    if (m_OK)
176    {
177        write(s);
178    }
179    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawLine Call executed")) ;
180    CalcBoundingBox(x1, y1) ;
181    CalcBoundingBox(x2, y2) ;
182    return;
183};
184
185void wxSVGFileDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
186{
187    for ( int i = 1; i < n ; i++ )
188    {
189        DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
190            points [ i ].x + xoffset, points [ i ].y + yoffset ) ;
191    }
192}
193
194
195void wxSVGFileDC::DoDrawPoint (wxCoord x1, wxCoord y1)
196{
197    wxString s;
198    if (m_graphics_changed) NewGraphics ();
199    s = wxT("<g style = \"stroke-linecap:round;\" > ") + newline ;
200    write(s);
201    DrawLine ( x1,y1,x1,y1 );
202    s = wxT("</g>");
203    write(s);
204}
205
206
207void wxSVGFileDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
208{
209    wxDCBase::DoDrawCheckMark (x1,y1,width,height) ;
210}
211
212
213void wxSVGFileDC::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
214{
215    DoDrawRotatedText(text, x1,y1,0.0);
216    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawText Call executed")) ;
217}
218
219
220void wxSVGFileDC::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
221{
222    //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
223    if (m_graphics_changed) NewGraphics ();
224    wxString s, sTmp;
225
226    // calculate bounding box
227    wxCoord w, h, desc ;
228    DoGetTextExtent(sText, &w, &h, &desc);
229
230    double rad = DegToRad(angle);
231
232    // wxT("upper left") and wxT("upper right")
233    CalcBoundingBox(x, y);
234    CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
235
236    // wxT("bottom left") and wxT("bottom right")
237    x += (wxCoord)(h*sin(rad));
238    y += (wxCoord)(h*cos(rad));
239    CalcBoundingBox(x, y);
240    CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
241
242    if (m_backgroundMode == wxSOLID)
243    {
244        // draw background first
245        // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
246
247        wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background")) ;
248        sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"  "), x,y+desc-h, w, h );
249        s = sTmp + wxT("style=\"fill:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
250        s = s + wxT("stroke-width:1; stroke:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
251        sTmp.Printf ( wxT("\" transform=\"rotate( %.2g %d %d )  \">"), -angle, x,y ) ;
252        s = s + sTmp + newline ;
253        write(s);
254    }
255    //now do the text itself
256    s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
257
258    sTmp = m_font.GetFaceName () ;
259    if (sTmp.Len () > 0)  s = s + wxT("style=\"font-family:") + sTmp + wxT("; ");
260    else s = s + wxT("style=\" ") ;
261
262    wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
263    s = s + wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + semicolon + space;
264
265    wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
266    s = s + wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + semicolon  + space;
267
268    sTmp.Printf (wxT("font-size:%dpt; fill:#"), m_font.GetPointSize () );
269    s = s + sTmp ;
270    s = s + wxColStr (m_textForegroundColour) + wxT("; stroke:#") + wxColStr (m_textForegroundColour) + wxT("; ") ;
271    sTmp.Printf ( wxT("stroke-width:0;\"  transform=\"rotate( %.2g %d %d )  \" >"),  -angle, x,y ) ;
272    s = s + sTmp + sText + wxT("</text> ") + newline ;
273    if (m_OK)
274    {
275        write(s);
276    }
277    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawRotatedText Call executed")) ;
278
279}
280
281
282void wxSVGFileDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
283{
284    DoDrawRoundedRectangle(x, y, width, height, 0)  ;
285}
286
287
288void wxSVGFileDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
289
290{
291    if (m_graphics_changed) NewGraphics ();
292    wxString s ;
293
294    s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%.2g\" "),
295               x, y, width, height, radius );
296
297    s = s + wxT(" /> ") + newline ;
298    write(s);
299
300    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed")) ;
301    CalcBoundingBox(x, y) ;
302    CalcBoundingBox(x + width, y + height) ;
303
304}
305
306
307void wxSVGFileDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
308{
309    if (m_graphics_changed) NewGraphics ();
310    wxString s, sTmp ;
311    s = wxT("<polygon style=\"") ;
312    if ( fillStyle == wxODDEVEN_RULE )
313        s = s + wxT("fill-rule:evenodd; ");
314    else
315        s = s + wxT("fill-rule:nonzero; ");
316
317    s = s  + wxT("\" \npoints=\"") ;
318
319    for (int i = 0; i < n;  i++)
320    {
321        sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
322        s = s + sTmp + newline ;
323        CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
324    }
325    s = s + wxT("\" /> ") ;
326    s = s + newline ;
327    write(s);
328
329    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawPolygon Call executed")) ;
330}
331
332
333void wxSVGFileDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
334
335{
336    if (m_graphics_changed) NewGraphics ();
337
338    int rh = height /2 ;
339    int rw = width  /2 ;
340
341    wxString s;
342    s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
343    s = s + wxT(" /> ") + newline ;
344
345    write(s);
346
347    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipse Call executed")) ;
348    CalcBoundingBox(x, y) ;
349    CalcBoundingBox(x + width, y + height) ;
350}
351
352
353void wxSVGFileDC::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
354{
355    /* Draws an arc of a circle, centred on (xc, yc), with starting point
356    (x1, y1) and ending at (x2, y2). The current pen is used for the outline
357    and the current brush for filling the shape.
358
359    The arc is drawn in an anticlockwise direction from the start point to
360    the end point.
361
362    Might be better described as Pie drawing */
363
364    if (m_graphics_changed) NewGraphics ();
365    wxString s ;
366
367    // we need the radius of the circle which has two estimates
368    double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
369    double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
370
371    wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle")) ;
372    if ( fabs ( r2-r1 ) > 3 )    //pixels
373    {
374        s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n") ;
375        write(s);
376    }
377
378    double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
379    if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
380    double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
381    if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
382    if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2 ;
383
384    int fArc  ;                  // flag for large or small arc 0 means less than 180 degrees
385    if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0 ;
386
387    int fSweep = 0 ;             // flag for sweep always 0
388
389    s.Printf ( wxT("<path d=\"M%d %d A%.2g %.2g 0.0 %d %d %d %d L%d %d z "),
390        x1,y1, r1, r2, fArc, fSweep, x2, y2, xc, yc );
391
392    // the z means close the path and fill
393    s = s + wxT(" \" /> ") + newline ;
394
395
396    if (m_OK)
397    {
398        write(s);
399    }
400
401    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawArc Call executed")) ;
402}
403
404
405void wxSVGFileDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
406{
407    /*
408    Draws an arc of an ellipse. The current pen is used for drawing the arc
409    and the current brush is used for drawing the pie. This function is
410    currently only available for X window and PostScript device contexts.
411
412    x and y specify the x and y coordinates of the upper-left corner of the
413    rectangle that contains the ellipse.
414
415    width and height specify the width and height of the rectangle that
416    contains the ellipse.
417
418    start and end specify the start and end of the arc relative to the
419    three-o'clock position from the center of the rectangle. Angles are
420    specified in degrees (360 is a complete circle). Positive values mean
421    counter-clockwise motion. If start is equal to end, a complete ellipse
422    will be drawn. */
423
424    //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
425
426    if (m_graphics_changed) NewGraphics ();
427
428    wxString s ;
429    //radius
430    double rx = w / 2 ;
431    double ry = h / 2 ;
432    // center
433    double xc = x + rx ;
434    double yc = y + ry ;
435
436    double xs, ys, xe, ye ;
437    xs = xc + rx * cos (DegToRad(sa)) ;
438    xe = xc + rx * cos (DegToRad(ea)) ;
439    ys = yc - ry * sin (DegToRad(sa)) ;
440    ye = yc - ry * sin (DegToRad(ea)) ;
441
442    ///now same as circle arc...
443
444    double theta1 = atan2(ys-yc, xs-xc);
445    double theta2 = atan2(ye-yc, xe-xc);
446
447    int fArc  ;                  // flag for large or small arc 0 means less than 180 degrees
448    if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0 ;
449
450    int fSweep ;
451    if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0 ;
452
453    s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d  %d %d L %d %d z "),
454        int(xs), int(ys), int(rx), int(ry),
455        fArc, fSweep, int(xe), int(ye), int(xc), int(yc)  );
456
457
458    s = s + wxT(" \" /> ") + newline ;
459
460    if (m_OK)
461    {
462        write(s);
463    }
464
465    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed")) ;
466}
467
468
469void wxSVGFileDC::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , wxFont *font) const
470
471{
472    wxScreenDC sDC ;
473
474    sDC.SetFont (m_font);
475    if ( font != NULL ) sDC.SetFont ( *font );
476    sDC.GetTextExtent(string, w,  h, descent, externalLeading );
477    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetTextExtent Call executed")) ;
478}
479
480
481wxCoord wxSVGFileDC::GetCharHeight() const
482
483{
484    wxScreenDC sDC ;
485    sDC.SetFont (m_font);
486
487    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharHeight Call executing")) ;
488    return ( sDC.GetCharHeight() );
489
490}
491
492
493wxCoord wxSVGFileDC::GetCharWidth() const
494{
495    wxScreenDC sDC ;
496    sDC.SetFont (m_font);
497
498    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharWidth Call executing")) ;
499    return ( sDC.GetCharWidth() ) ;
500
501}
502
503
504/// Set Functions /////////////////////////////////////////////////////////////////
505void wxSVGFileDC::SetBackground( const wxBrush &brush )
506{
507
508    m_backgroundBrush = brush;
509    return;
510}
511
512
513void wxSVGFileDC::SetBackgroundMode( int mode )
514{
515    m_backgroundMode = mode;
516    return;
517}
518
519
520void wxSVGFileDC::SetBrush(const wxBrush& brush)
521
522{
523    m_brush = brush ;
524
525    m_graphics_changed = TRUE ;
526    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetBrush Call executed")) ;
527}
528
529
530void wxSVGFileDC::SetPen(const wxPen& pen)
531{
532    // width, color, ends, joins : currently implemented
533    // dashes, stipple :  not implemented
534    m_pen = pen ;
535
536    m_graphics_changed = TRUE ;
537    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetPen Call executed")) ;
538}
539
540void wxSVGFileDC::NewGraphics ()
541{
542
543    int w = m_pen.GetWidth ();
544    wxColour c = m_pen.GetColour () ;
545
546    wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
547
548    sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour (), m_brush.GetStyle () )
549             + wxT("  stroke:#") + wxColStr (c) + wxT("; ") ;
550
551    switch ( m_pen.GetCap () )
552    {
553        case  wxCAP_PROJECTING :
554            sPenCap = wxT("stroke-linecap:square; ") ;
555            break ;
556        case  wxCAP_BUTT :
557            sPenCap = wxT("stroke-linecap:butt; ") ;
558            break ;
559        case    wxCAP_ROUND :
560        default :
561            sPenCap = wxT("stroke-linecap:round; ") ;
562    };
563    switch ( m_pen.GetJoin () )
564    {
565        case  wxJOIN_BEVEL :
566            sPenJoin = wxT("stroke-linejoin:bevel; ") ;
567            break ;
568        case  wxJOIN_MITER :
569            sPenJoin = wxT("stroke-linejoin:miter; ") ;
570            break ;
571        case    wxJOIN_ROUND :
572        default :
573            sPenJoin = wxT("stroke-linejoin:round; ") ;
574    };
575
576    switch ( m_pen.GetStyle () )
577    {
578        case  wxSOLID :
579            sPenStyle = wxT("stroke-opacity:1.0; stroke-opacity:1.0; ") ;
580            break ;
581        case  wxTRANSPARENT :
582            sPenStyle = wxT("stroke-opacity:0.0; stroke-opacity:0.0; ") ;
583            break ;
584        default :
585            wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::SetPen Call called to set a Style which is not available")) ;
586            sWarn = sWarn + wxT("<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n") ;
587    }
588
589    sLast.Printf (   wxT("stroke-width:%d\" \n   transform=\"translate(%.2g %.2g) scale(%.2g %.2g)\">"),
590                  w, m_OriginX, m_OriginY, m_scaleX, m_scaleY  );
591
592    s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + newline + sWarn;
593    write(s);
594    m_graphics_changed = FALSE ;
595    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::NewGraphics Call executed")) ;
596}
597
598#ifdef __WXMAC__
599void wxSVGFileDC::SetTextForeground ( const wxColour& textForegroundColour )
600{
601    m_textForegroundColour = textForegroundColour ;
602
603    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetSetTextForeground Call executed")) ;
604}
605
606void wxSVGFileDC::DoDrawSpline(wxList *points)
607{
608  wxDCBase::DoDrawSpline(points);
609}
610
611#endif
612
613void wxSVGFileDC::SetFont(const wxFont& font)
614
615{
616    m_font = font ;
617
618    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetFont Call executed")) ;
619}
620
621
622void wxSVGFileDC::ComputeScaleAndOrigin()
623{
624    m_scaleX = m_logicalScaleX * m_userScaleX;
625    m_scaleY = m_logicalScaleY * m_userScaleY;
626    m_OriginX = m_logicalOriginX * m_logicalScaleX + m_deviceOriginX ;
627    m_OriginY = m_logicalOriginY * m_logicalScaleY + m_deviceOriginY ;
628    m_graphics_changed = TRUE;
629}
630
631
632int wxSVGFileDC::GetMapMode()
633{
634    return m_mappingMode ;
635}
636
637
638void wxSVGFileDC::SetMapMode( int mode )
639{
640    switch (mode)
641    {
642        case wxMM_TWIPS:
643            SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
644            break;
645        case wxMM_POINTS:
646            SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
647            break;
648        case wxMM_METRIC:
649            SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
650            break;
651        case wxMM_LOMETRIC:
652            SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
653            break;
654        default:
655        case wxMM_TEXT:
656            SetLogicalScale( 1.0, 1.0 );
657            break;
658    }
659    m_mappingMode = mode;
660
661    /*  we don't do this mega optimisation
662        if (mode != wxMM_TEXT)
663        {
664            m_needComputeScaleX = TRUE;
665            m_needComputeScaleY = TRUE;
666        }
667    */
668}
669
670
671void wxSVGFileDC::GetUserScale(double *x, double *y) const
672{
673    *x = m_userScaleX ;
674    *y = m_userScaleY ;
675}
676
677
678void wxSVGFileDC::SetUserScale( double x, double y )
679{
680    // allow negative ? -> no
681    m_userScaleX = x;
682    m_userScaleY = y;
683    ComputeScaleAndOrigin();
684}
685
686
687void wxSVGFileDC::SetLogicalScale( double x, double y )
688{
689    // allow negative ?
690    m_logicalScaleX = x;
691    m_logicalScaleY = y;
692    ComputeScaleAndOrigin();
693}
694
695
696void wxSVGFileDC::SetLogicalOrigin( wxCoord x, wxCoord y )
697{
698    // is this still correct ?
699    m_logicalOriginX = x * m_signX;
700    m_logicalOriginY = y * m_signY;
701    ComputeScaleAndOrigin();
702}
703
704
705void wxSVGFileDC::SetDeviceOrigin( wxCoord x, wxCoord y )
706{
707    // only wxPostScripDC has m_signX = -1,
708    m_deviceOriginX = x;
709    m_deviceOriginY = y;
710    ComputeScaleAndOrigin();
711}
712
713
714void wxSVGFileDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
715{
716    // only wxPostScripDC has m_signX = -1,
717    m_signX = (xLeftRight ?  1 : -1);
718    m_signY = (yBottomUp  ? -1 :  1);
719    ComputeScaleAndOrigin();
720}
721
722
723// export a bitmap as a raster image in png
724bool wxSVGFileDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
725                         wxDC* source, wxCoord xsrc, wxCoord ysrc,
726                         int logicalFunc /*= wxCOPY*/, bool useMask /*= FALSE*/,
727                         wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
728{
729    if (logicalFunc != wxCOPY)
730    {
731        wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible")) ;
732        return FALSE ;
733    }
734    if (useMask != FALSE)
735    {
736        wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested False mask ; this is not possible")) ;
737        return FALSE ;
738    }
739    wxBitmap myBitmap (width, height) ;
740    wxMemoryDC memDC;
741    memDC.SelectObject( myBitmap );
742    memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
743    memDC.SelectObject( wxNullBitmap );
744    DoDrawBitmap(myBitmap, xdest, ydest);
745    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoBlit Call executed")) ;
746    return FALSE ;
747}
748
749
750void wxSVGFileDC::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
751{
752    wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() ) ;
753    wxMemoryDC memDC;
754    memDC.SelectObject( myBitmap );
755    memDC.DrawIcon(myIcon,0,0);
756    memDC.SelectObject( wxNullBitmap );
757    DoDrawBitmap(myBitmap, x, y);
758    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawIcon Call executed")) ;
759    return ;
760}
761
762
763
764void wxSVGFileDC::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool  WXUNUSED(bTransparent) /*=0*/ )
765{
766    if (m_graphics_changed) NewGraphics ();
767
768    wxString sTmp, s, sPNG ;
769    wxImage::AddHandler(new wxPNGHandler);
770
771// create suitable file name
772    sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
773    sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
774    while (wxFile::Exists(sPNG) )
775    {
776        m_sub_images ++ ;
777        sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
778        sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
779    }
780
781//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
782    wxBitmap myBitmap = bmp ;
783//save it
784    bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
785
786// reference the bitmap from the SVG doc
787// only use filename & ext
788    sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
789
790    int w = myBitmap.GetWidth();
791    int h = myBitmap.GetHeight();
792    sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
793    s = s + sTmp ;
794    sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
795    s = s + sTmp + wxT("<title>Image from wxSVG</title>  </image>") + newline;
796
797    if (m_OK && bPNG_OK)
798    {
799        write(s);
800    }
801    m_OK = m_outfile->Ok () && bPNG_OK;
802    wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawBitmap Call executed")) ;
803
804    return  ;
805}
806
807
808// ---------------------------------------------------------------------------
809// coordinates transformations
810// ---------------------------------------------------------------------------
811
812wxCoord wxSVGFileDC::DeviceToLogicalX(wxCoord x) const
813{
814    return XDEV2LOG(x);
815}
816
817
818wxCoord wxSVGFileDC::DeviceToLogicalY(wxCoord y) const
819{
820    return YDEV2LOG(y);
821}
822
823
824wxCoord wxSVGFileDC::DeviceToLogicalXRel(wxCoord x) const
825{
826    return XDEV2LOGREL(x);
827}
828
829
830wxCoord wxSVGFileDC::DeviceToLogicalYRel(wxCoord y) const
831{
832    return YDEV2LOGREL(y);
833}
834
835
836wxCoord wxSVGFileDC::LogicalToDeviceX(wxCoord x) const
837{
838    return XLOG2DEV(x);
839}
840
841
842wxCoord wxSVGFileDC::LogicalToDeviceY(wxCoord y) const
843{
844    return YLOG2DEV(y);
845}
846
847
848wxCoord wxSVGFileDC::LogicalToDeviceXRel(wxCoord x) const
849{
850    return XLOG2DEVREL(x);
851}
852
853
854wxCoord wxSVGFileDC::LogicalToDeviceYRel(wxCoord y) const
855{
856    return YLOG2DEVREL(y);
857}
858
859void wxSVGFileDC::write(const wxString &s)
860{
861    const wxWX2MBbuf buf = s.mb_str(wxConvUTF8);
862    m_outfile->Write(buf, strlen((const char *)buf));
863    m_OK = m_outfile->Ok();
864}
865
866#ifdef __BORLANDC__
867#pragma warn .rch
868#pragma warn .ccc
869#endif
870