/////////////////////////////////////////////////////////////////////////////
-// Name: svg.cpp
+// Name: src/common/svg.cpp
// Purpose: SVG sample
// Author: Chris Elliott
// Modified by:
-// RCS-ID: $Id$
-// Licence: wxWindows license
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#pragma hdrstop
#endif
+#if wxUSE_SVG
+
#ifndef WX_PRECOMP
-#include "wx/wx.h"
+ #include "wx/dcmemory.h"
+ #include "wx/dcscreen.h"
+ #include "wx/icon.h"
+ #include "wx/image.h"
#endif
-#include "wx/svg/dcsvg.h"
+#include "wx/dcsvg.h"
+#include "wx/wfstream.h"
+#include "wx/filename.h"
-#include "wx/image.h"
+// ----------------------------------------------------------
+// Global utilities
+// ----------------------------------------------------------
-#define wxSVG_DEBUG FALSE
-// or TRUE to see the calls being executed
-#define newline wxString(wxT("\n"))
-#define space wxString(wxT(" "))
-#define semicolon wxString(wxT(";"))
-#define wx_round(a) (int)((a)+.5)
+namespace
+{
-#ifdef __BORLANDC__
-#pragma warn -rch
-#pragma warn -ccc
-#endif
+inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
-static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } ;
+// This function returns a string representation of a floating point number in
+// C locale (i.e. always using "." for the decimal separator) and with the
+// fixed precision (which is 2 for some unknown reason but this is what it was
+// in this code originally).
+inline wxString NumStr(double f)
+{
+ return wxString::FromCDouble(f, 2);
+}
-wxString wxColStr ( wxColour c )
+// Return the colour representation as HTML-like "#rrggbb" string and also
+// returns its alpha as opacity number in 0..1 range.
+wxString Col2SVG(wxColour c, float *opacity)
{
- unsigned char r, g, b ;
- r = c.Red ();
- g = c.Green ();
- b = c. Blue ();
+ if ( c.Alpha() != wxALPHA_OPAQUE )
+ {
+ *opacity = c.Alpha()/255.;
- // possible Unicode bug here
- wxString s = wxDecToHex(r) + wxDecToHex(g) + wxDecToHex(b) ;
- return s ;
-}
+ // Remove the alpha before using GetAsString(wxC2S_HTML_SYNTAX) as it
+ // doesn't support colours with alpha channel.
+ c = wxColour(c.GetRGB());
+ }
+ else // No alpha.
+ {
+ *opacity = 1.;
+ }
+ return c.GetAsString(wxC2S_HTML_SYNTAX);
+}
-wxString wxBrushString ( wxColour c, int style )
+wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
{
- wxString s = wxT("fill:#") + wxColStr (c) + semicolon + space ;
+ float opacity;
+ wxString s = wxT("stroke:") + Col2SVG(c, &opacity) + wxT("; ");
+
switch ( style )
{
- case wxSOLID :
- s = s + wxT("fill-opacity:1.0; ");
- break ;
- case wxTRANSPARENT:
- s = s + wxT("fill-opacity:0.0; ");
- break ;
-
+ case wxPENSTYLE_SOLID:
+ s += wxString::Format(wxT("stroke-opacity:%s; "), NumStr(opacity));
+ break;
+ case wxPENSTYLE_TRANSPARENT:
+ s += wxT("stroke-opacity:0.0; ");
+ break;
default :
- wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::Requested Brush Style not available")) ;
+ wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Pen Style not available"));
+ }
+
+ return s;
+}
+wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
+{
+ float opacity;
+ wxString s = wxT("fill:") + Col2SVG(c, &opacity) + wxT("; ");
+
+ switch ( style )
+ {
+ case wxBRUSHSTYLE_SOLID:
+ s += wxString::Format(wxT("fill-opacity:%s; "), NumStr(opacity));
+ break;
+ case wxBRUSHSTYLE_TRANSPARENT:
+ s += wxT("fill-opacity:0.0; ");
+ break;
+ default :
+ wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
}
- s = s + newline ;
- return s ;
+
+ return s;
}
+} // anonymous namespace
-void wxSVGFileDC::Init (wxString f, int Width, int Height, float dpi)
+// ----------------------------------------------------------
+// wxSVGFileDCImpl
+// ----------------------------------------------------------
-{
- //set up things first wxDCBase does all this?
- m_width = Width ;
- m_height = Height ;
+IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC)
- m_clipping = FALSE;
- m_OK = TRUE;
+wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC *owner, const wxString &filename,
+ int width, int height, double dpi ) :
+ wxDCImpl( owner )
+ {
+ Init( filename, width, height, dpi );
+ }
- m_mm_to_pix_x = dpi/25.4;
- m_mm_to_pix_y = dpi/25.4;
+void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, double dpi)
+{
+ m_width = Width;
+ m_height = Height;
- m_signX = m_signY = 1;
+ m_dpi = dpi;
- m_userScaleX = m_userScaleY =
- m_deviceOriginX = m_deviceOriginY = 0;
+ m_OK = true;
- m_OriginX = m_OriginY = 0;
- m_logicalOriginX = m_logicalOriginY = 0;
- m_logicalScaleX = m_logicalScaleY = 0 ;
- m_scaleX = m_scaleY = 1.0 ;
+ m_clipUniqueId = 0;
+ m_clipNestingLevel = 0;
- m_logicalFunction = wxCOPY;
- m_backgroundMode = wxTRANSPARENT;
- m_mappingMode = wxMM_TEXT;
+ m_mm_to_pix_x = dpi/25.4;
+ m_mm_to_pix_y = dpi/25.4;
m_backgroundBrush = *wxTRANSPARENT_BRUSH;
m_textForegroundColour = *wxBLACK;
m_font = *wxNORMAL_FONT;
m_brush = *wxWHITE_BRUSH;
- m_graphics_changed = TRUE ;
+ m_graphics_changed = true;
////////////////////code here
- m_outfile = new wxFileOutputStream(f) ;
- m_OK = m_outfile->Ok ();
+ m_outfile = new wxFileOutputStream(filename);
+ m_OK = m_outfile->IsOk();
if (m_OK)
{
- m_filename = f ;
- m_sub_images = 0 ;
- wxString s ;
- s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") ; s = s + newline ;
+ m_filename = filename;
+ m_sub_images = 0;
+ wxString s;
+ s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>\n");
write(s);
- s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + newline ;
+ s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
write(s);
- s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ")+ newline ;
+ s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
write(s);
- s.Printf ( wxT("<svg width=\"%.2gcm\" height=\"%.2gcm\" viewBox=\"0 0 %d %d \"> \n"), float(Width)/dpi*2.54, float(Height)/dpi*2.54, Width, Height );
+ s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
write(s);
- s = wxT("<title>SVG Picture created as ") + wxFileNameFromPath(f) + wxT(" </title>") + newline ;
+ s.Printf( wxT(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d \">\n"), NumStr(float(Width)/dpi*2.54), NumStr(float(Height)/dpi*2.54), Width, Height );
write(s);
- s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ newline ;
+ s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>\n");
write(s);
- s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + newline ;
+ s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>\n");
+ write(s);
+ s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">\n");
write(s);
-
}
}
-
-// constructors
-wxSVGFileDC::wxSVGFileDC (wxString f)
+wxSVGFileDCImpl::~wxSVGFileDCImpl()
{
- // quarter 640x480 screen display at 72 dpi
- Init (f,320,240,72.0);
-};
+ wxString s = wxT("</g> \n</svg> \n");
+ write(s);
+ delete m_outfile;
+}
-wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height)
+void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
{
- Init (f,Width,Height,72.0);
-};
+ if (width)
+ *width = wxRound( (double)m_width / m_mm_to_pix_x );
-wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height, float dpi)
-{
- Init (f,Width,Height,dpi);
-};
+ if (height)
+ *height = wxRound( (double)m_height / m_mm_to_pix_y );
+}
-wxSVGFileDC::~wxSVGFileDC()
+wxSize wxSVGFileDCImpl::GetPPI() const
{
- wxString s = wxT("</g> \n</svg> \n") ;
- write(s);
- delete m_outfile ;
+ return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-void wxSVGFileDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
+void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
{
- if (m_graphics_changed) NewGraphics ();
- wxString s ;
+ NewGraphicsIfNeeded();
+ wxString s;
s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
if (m_OK)
{
write(s);
}
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawLine Call executed")) ;
- CalcBoundingBox(x1, y1) ;
- CalcBoundingBox(x2, y2) ;
- return;
-};
+ CalcBoundingBox(x1, y1);
+ CalcBoundingBox(x2, y2);
+}
-void wxSVGFileDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
+void wxSVGFileDCImpl::DoDrawLines(int n, const wxPoint points[], wxCoord xoffset , wxCoord yoffset )
{
- for ( int i = 1; i < n ; i++ )
+ for ( int i = 1; i < n; i++ )
{
DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
- points [ i ].x + xoffset, points [ i ].y + yoffset ) ;
+ points [ i ].x + xoffset, points [ i ].y + yoffset );
}
}
-
-void wxSVGFileDC::DoDrawPoint (wxCoord x1, wxCoord y1)
+void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
{
wxString s;
- if (m_graphics_changed) NewGraphics ();
- s = wxT("<g style = \"stroke-linecap:round;\" > ") + newline ;
+ NewGraphicsIfNeeded();
+ s = wxT("<g style = \"stroke-linecap:round;\" > \n");
write(s);
- DrawLine ( x1,y1,x1,y1 );
+ DoDrawLine ( x1,y1,x1,y1 );
s = wxT("</g>");
write(s);
}
-
-void wxSVGFileDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
+void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
{
- wxDCBase::DoDrawCheckMark (x1,y1,width,height) ;
+ wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
}
-
-void wxSVGFileDC::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
+void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
{
DoDrawRotatedText(text, x1,y1,0.0);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawText Call executed")) ;
}
-
-void wxSVGFileDC::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
+void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
{
//known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
- if (m_graphics_changed) NewGraphics ();
+ NewGraphicsIfNeeded();
wxString s, sTmp;
// calculate bounding box
- wxCoord w, h, desc ;
+ wxCoord w, h, desc;
DoGetTextExtent(sText, &w, &h, &desc);
double rad = DegToRad(angle);
CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
// wxT("bottom left") and wxT("bottom right")
- x += (wxCoord)(h*sin(rad));
- y += (wxCoord)(h*cos(rad));
- CalcBoundingBox(x, y);
CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
+ CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad)));
- if (m_backgroundMode == wxSOLID)
+ if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
{
// draw background first
// just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background")) ;
- sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x,y+desc-h, w, h );
- s = sTmp + wxT("style=\"fill:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
- s = s + wxT("stroke-width:1; stroke:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
- sTmp.Printf ( wxT("\" transform=\"rotate( %.2g %d %d ) \">"), -angle, x,y ) ;
- s = s + sTmp + newline ;
+ sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h );
+ s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
+ s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
+ sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
+ s += sTmp + wxT("\n");
write(s);
}
+
+ // convert x,y to SVG text x,y (the coordinates of the text baseline)
+ x = (wxCoord)(x + (h-desc)*sin(rad));
+ y = (wxCoord)(y + (h-desc)*cos(rad));
+
//now do the text itself
s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
- sTmp = m_font.GetFaceName () ;
- if (sTmp.Len () > 0) s = s + wxT("style=\"font-family:") + sTmp + wxT("; ");
- else s = s + wxT("style=\" ") ;
+ sTmp = m_font.GetFaceName();
+ if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
+ else s += wxT("style=\" ");
wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
- s = s + wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + semicolon + space;
+ s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
- s = s + wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + semicolon + space;
-
- sTmp.Printf (wxT("font-size:%dpt; fill:#"), m_font.GetPointSize () );
- s = s + sTmp ;
- s = s + wxColStr (m_textForegroundColour) + wxT("; stroke:#") + wxColStr (m_textForegroundColour) + wxT("; ") ;
- sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %.2g %d %d ) \" >"), -angle, x,y ) ;
- s = s + sTmp + sText + wxT("</text> ") + newline ;
+ s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
+
+ sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
+ s += sTmp;
+ //text will be solid, unless alpha value isn't opaque in the foreground colour
+ s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
+ sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
+ s += sTmp + sText + wxT("</text> ") + wxT("\n");
if (m_OK)
{
write(s);
}
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawRotatedText Call executed")) ;
-
}
-
-void wxSVGFileDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
+void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
- DoDrawRoundedRectangle(x, y, width, height, 0) ;
+ DoDrawRoundedRectangle(x, y, width, height, 0);
}
-
-void wxSVGFileDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
+void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
{
- if (m_graphics_changed) NewGraphics ();
- wxString s ;
+ NewGraphicsIfNeeded();
+ wxString s;
- s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%.2g\" "),
- x, y, width, height, radius );
+ s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
+ x, y, width, height, NumStr(radius) );
- s = s + wxT(" /> ") + newline ;
+ s += wxT(" /> \n");
write(s);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed")) ;
- CalcBoundingBox(x, y) ;
- CalcBoundingBox(x + width, y + height) ;
-
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x + width, y + height);
}
-
-void wxSVGFileDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
+void wxSVGFileDCImpl::DoDrawPolygon(int n, const wxPoint points[],
+ wxCoord xoffset, wxCoord yoffset,
+ wxPolygonFillMode fillStyle)
{
- if (m_graphics_changed) NewGraphics ();
- wxString s, sTmp ;
- s = wxT("<polygon style=\"") ;
+ NewGraphicsIfNeeded();
+ wxString s, sTmp;
+ s = wxT("<polygon style=\"");
if ( fillStyle == wxODDEVEN_RULE )
- s = s + wxT("fill-rule:evenodd; ");
+ s += wxT("fill-rule:evenodd; ");
else
- s = s + wxT("fill-rule:nonzero; ");
+ s += wxT("fill-rule:nonzero; ");
- s = s + wxT("\" \npoints=\"") ;
+ s += wxT("\" \npoints=\"");
for (int i = 0; i < n; i++)
{
sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
- s = s + sTmp + newline ;
+ s += sTmp + wxT("\n");
CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
}
- s = s + wxT("\" /> ") ;
- s = s + newline ;
+ s += wxT("\" /> \n");
write(s);
-
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawPolygon Call executed")) ;
}
-
-void wxSVGFileDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
+void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
- if (m_graphics_changed) NewGraphics ();
+ NewGraphicsIfNeeded();
- int rh = height /2 ;
- int rw = width /2 ;
+ int rh = height /2;
+ int rw = width /2;
wxString s;
s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
- s = s + wxT(" /> ") + newline ;
+ s += wxT(" /> \n");
write(s);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipse Call executed")) ;
- CalcBoundingBox(x, y) ;
- CalcBoundingBox(x + width, y + height) ;
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x + width, y + height);
}
-
-void wxSVGFileDC::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
+void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
{
/* Draws an arc of a circle, centred on (xc, yc), with starting point
(x1, y1) and ending at (x2, y2). The current pen is used for the outline
Might be better described as Pie drawing */
- if (m_graphics_changed) NewGraphics ();
- wxString s ;
+ NewGraphicsIfNeeded();
+ wxString s;
// we need the radius of the circle which has two estimates
double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
- wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle")) ;
+ wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
if ( fabs ( r2-r1 ) > 3 ) //pixels
{
- s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n") ;
+ s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
write(s);
}
if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
- if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2 ;
+ if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
- int fArc ; // flag for large or small arc 0 means less than 180 degrees
- if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0 ;
+ int fArc; // flag for large or small arc 0 means less than 180 degrees
+ if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0;
- int fSweep = 0 ; // flag for sweep always 0
+ int fSweep = 0; // flag for sweep always 0
- s.Printf ( wxT("<path d=\"M%d %d A%.2g %.2g 0.0 %d %d %d %d L%d %d z "),
- x1,y1, r1, r2, fArc, fSweep, x2, y2, xc, yc );
+ s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
+ x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
// the z means close the path and fill
- s = s + wxT(" \" /> ") + newline ;
+ s += wxT(" \" /> \n");
if (m_OK)
{
write(s);
}
-
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawArc Call executed")) ;
}
-
-void wxSVGFileDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
+void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
{
/*
Draws an arc of an ellipse. The current pen is used for drawing the arc
//known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
- if (m_graphics_changed) NewGraphics ();
+ NewGraphicsIfNeeded();
- wxString s ;
+ wxString s;
//radius
- double rx = w / 2 ;
- double ry = h / 2 ;
+ double rx = w / 2;
+ double ry = h / 2;
// center
- double xc = x + rx ;
- double yc = y + ry ;
+ double xc = x + rx;
+ double yc = y + ry;
- double xs, ys, xe, ye ;
- xs = xc + rx * cos (DegToRad(sa)) ;
- xe = xc + rx * cos (DegToRad(ea)) ;
- ys = yc - ry * sin (DegToRad(sa)) ;
- ye = yc - ry * sin (DegToRad(ea)) ;
+ double xs, ys, xe, ye;
+ xs = xc + rx * cos (DegToRad(sa));
+ xe = xc + rx * cos (DegToRad(ea));
+ ys = yc - ry * sin (DegToRad(sa));
+ ye = yc - ry * sin (DegToRad(ea));
///now same as circle arc...
double theta1 = atan2(ys-yc, xs-xc);
double theta2 = atan2(ye-yc, xe-xc);
- int fArc ; // flag for large or small arc 0 means less than 180 degrees
- if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0 ;
+ int fArc; // flag for large or small arc 0 means less than 180 degrees
+ if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
- int fSweep ;
- if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0 ;
+ int fSweep;
+ if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
int(xs), int(ys), int(rx), int(ry),
fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
-
- s = s + wxT(" \" /> ") + newline ;
+ s += wxT(" \" /> \n");
if (m_OK)
{
write(s);
}
+}
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed")) ;
+void wxSVGFileDCImpl::DoSetClippingRegion( int x, int y, int width, int height )
+{
+ wxString svg;
+
+ // End current graphics group to ensure proper xml nesting (e.g. so that
+ // graphics can be subsequently changed inside the clipping region)
+ svg << "</g>\n"
+ "<defs>\n"
+ "<clipPath id=\"clip" << m_clipNestingLevel << "\">\n"
+ "<rect id=\"cliprect" << m_clipNestingLevel << "\" "
+ "x=\"" << x << "\" "
+ "y=\"" << y << "\" "
+ "width=\"" << width << "\" "
+ "height=\"" << height << "\" "
+ "style=\"stroke: gray; fill: none;\"/>\n"
+ "</clipPath>\n"
+ "</defs>\n"
+ "<g style=\"clip-path: url(#clip" << m_clipNestingLevel << ");\">\n";
+
+ write(svg);
+
+ // Re-apply current graphics to ensure proper xml nesting
+ DoStartNewGraphics();
+
+ m_clipUniqueId++;
+ m_clipNestingLevel++;
}
+void wxSVGFileDCImpl::DestroyClippingRegion()
+{
+ wxString svg;
+
+ // End current graphics element to ensure proper xml nesting (e.g. graphics
+ // might have been changed inside the clipping region)
+ svg << "</g>\n";
+
+ // Close clipping group elements
+ for ( size_t i = 0; i < m_clipUniqueId; i++ )
+ {
+ svg << "</g>";
+ }
+ svg << "\n";
+
+ write(svg);
+
+ // Re-apply current graphics (e.g. brush may have been changed inside one
+ // of the clipped regions - that change will have been lost after xml
+ // elements for the clipped region have been closed).
+ DoStartNewGraphics();
-void wxSVGFileDC::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , wxFont *font) const
+ m_clipUniqueId = 0;
+}
+
+void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
{
- wxScreenDC sDC ;
+ wxScreenDC sDC;
sDC.SetFont (m_font);
if ( font != NULL ) sDC.SetFont ( *font );
sDC.GetTextExtent(string, w, h, descent, externalLeading );
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetTextExtent Call executed")) ;
}
-
-wxCoord wxSVGFileDC::GetCharHeight() const
-
+wxCoord wxSVGFileDCImpl::GetCharHeight() const
{
- wxScreenDC sDC ;
+ wxScreenDC sDC;
sDC.SetFont (m_font);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharHeight Call executing")) ;
- return ( sDC.GetCharHeight() );
+ return sDC.GetCharHeight();
}
-
-wxCoord wxSVGFileDC::GetCharWidth() const
+wxCoord wxSVGFileDCImpl::GetCharWidth() const
{
- wxScreenDC sDC ;
+ wxScreenDC sDC;
sDC.SetFont (m_font);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharWidth Call executing")) ;
- return ( sDC.GetCharWidth() ) ;
-
+ return sDC.GetCharWidth();
}
-/// Set Functions /////////////////////////////////////////////////////////////////
-void wxSVGFileDC::SetBackground( const wxBrush &brush )
-{
+// ----------------------------------------------------------
+// wxSVGFileDCImpl - set functions
+// ----------------------------------------------------------
+void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
+{
m_backgroundBrush = brush;
- return;
}
-void wxSVGFileDC::SetBackgroundMode( int mode )
+void wxSVGFileDCImpl::SetBackgroundMode( int mode )
{
m_backgroundMode = mode;
- return;
}
-void wxSVGFileDC::SetBrush(const wxBrush& brush)
-
+void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
{
- m_brush = brush ;
+ m_brush = brush;
- m_graphics_changed = TRUE ;
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetBrush Call executed")) ;
+ m_graphics_changed = true;
}
-void wxSVGFileDC::SetPen(const wxPen& pen)
+void wxSVGFileDCImpl::SetPen(const wxPen& pen)
{
// width, color, ends, joins : currently implemented
// dashes, stipple : not implemented
- m_pen = pen ;
+ m_pen = pen;
- m_graphics_changed = TRUE ;
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetPen Call executed")) ;
+ m_graphics_changed = true;
}
-void wxSVGFileDC::NewGraphics ()
+void wxSVGFileDCImpl::NewGraphicsIfNeeded()
{
+ if ( !m_graphics_changed )
+ return;
- int w = m_pen.GetWidth ();
- wxColour c = m_pen.GetColour () ;
+ m_graphics_changed = false;
+
+ write(wxS("</g>\n"));
+
+ DoStartNewGraphics();
+}
- wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
+void wxSVGFileDCImpl::DoStartNewGraphics()
+{
+ wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast;
- sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour (), m_brush.GetStyle () )
- + wxT(" stroke:#") + wxColStr (c) + wxT("; ") ;
+ sBrush = wxS("<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
+ + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
- switch ( m_pen.GetCap () )
+ switch ( m_pen.GetCap() )
{
case wxCAP_PROJECTING :
- sPenCap = wxT("stroke-linecap:square; ") ;
- break ;
+ sPenCap = wxT("stroke-linecap:square; ");
+ break;
case wxCAP_BUTT :
- sPenCap = wxT("stroke-linecap:butt; ") ;
- break ;
+ sPenCap = wxT("stroke-linecap:butt; ");
+ break;
case wxCAP_ROUND :
default :
- sPenCap = wxT("stroke-linecap:round; ") ;
- };
- switch ( m_pen.GetJoin () )
+ sPenCap = wxT("stroke-linecap:round; ");
+ }
+
+ switch ( m_pen.GetJoin() )
{
case wxJOIN_BEVEL :
- sPenJoin = wxT("stroke-linejoin:bevel; ") ;
- break ;
+ sPenJoin = wxT("stroke-linejoin:bevel; ");
+ break;
case wxJOIN_MITER :
- sPenJoin = wxT("stroke-linejoin:miter; ") ;
- break ;
+ sPenJoin = wxT("stroke-linejoin:miter; ");
+ break;
case wxJOIN_ROUND :
default :
- sPenJoin = wxT("stroke-linejoin:round; ") ;
- };
-
- switch ( m_pen.GetStyle () )
- {
- case wxSOLID :
- sPenStyle = wxT("stroke-opacity:1.0; stroke-opacity:1.0; ") ;
- break ;
- case wxTRANSPARENT :
- sPenStyle = wxT("stroke-opacity:0.0; stroke-opacity:0.0; ") ;
- break ;
- default :
- wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::SetPen Call called to set a Style which is not available")) ;
- sWarn = sWarn + wxT("<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n") ;
+ sPenJoin = wxT("stroke-linejoin:round; ");
}
- sLast.Printf ( wxT("stroke-width:%d\" \n transform=\"translate(%.2g %.2g) scale(%.2g %.2g)\">"),
- w, m_OriginX, m_OriginY, m_scaleX, m_scaleY );
+ sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
+ m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
- s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + newline + sWarn;
+ s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n");
write(s);
- m_graphics_changed = FALSE ;
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::NewGraphics Call executed")) ;
}
-void wxSVGFileDC::SetFont(const wxFont& font)
+void wxSVGFileDCImpl::SetFont(const wxFont& font)
{
- m_font = font ;
-
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetFont Call executed")) ;
+ m_font = font;
}
-
-void wxSVGFileDC::ComputeScaleAndOrigin()
-{
- m_scaleX = m_logicalScaleX * m_userScaleX;
- m_scaleY = m_logicalScaleY * m_userScaleY;
- m_OriginX = m_logicalOriginX * m_logicalScaleX + m_deviceOriginX ;
- m_OriginY = m_logicalOriginY * m_logicalScaleY + m_deviceOriginY ;
- m_graphics_changed = TRUE;
-}
-
-
-int wxSVGFileDC::GetMapMode()
-{
- return m_mappingMode ;
-}
-
-
-void wxSVGFileDC::SetMapMode( int mode )
-{
- switch (mode)
- {
- case wxMM_TWIPS:
- SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
- break;
- case wxMM_POINTS:
- SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
- break;
- case wxMM_METRIC:
- SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
- break;
- case wxMM_LOMETRIC:
- SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
- break;
- default:
- case wxMM_TEXT:
- SetLogicalScale( 1.0, 1.0 );
- break;
- }
- m_mappingMode = mode;
-
- /* we don't do this mega optimisation
- if (mode != wxMM_TEXT)
- {
- m_needComputeScaleX = TRUE;
- m_needComputeScaleY = TRUE;
- }
- */
-}
-
-
-void wxSVGFileDC::GetUserScale(double *x, double *y) const
-{
- *x = m_userScaleX ;
- *y = m_userScaleY ;
-}
-
-
-void wxSVGFileDC::SetUserScale( double x, double y )
-{
- // allow negative ? -> no
- m_userScaleX = x;
- m_userScaleY = y;
- ComputeScaleAndOrigin();
-}
-
-
-void wxSVGFileDC::SetLogicalScale( double x, double y )
-{
- // allow negative ?
- m_logicalScaleX = x;
- m_logicalScaleY = y;
- ComputeScaleAndOrigin();
-}
-
-
-void wxSVGFileDC::SetLogicalOrigin( wxCoord x, wxCoord y )
-{
- // is this still correct ?
- m_logicalOriginX = x * m_signX;
- m_logicalOriginY = y * m_signY;
- ComputeScaleAndOrigin();
-}
-
-
-void wxSVGFileDC::SetDeviceOrigin( wxCoord x, wxCoord y )
-{
- // only wxPostScripDC has m_signX = -1,
- m_deviceOriginX = x;
- m_deviceOriginY = y;
- ComputeScaleAndOrigin();
-}
-
-
-void wxSVGFileDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
-{
- // only wxPostScripDC has m_signX = -1,
- m_signX = (xLeftRight ? 1 : -1);
- m_signY = (yBottomUp ? -1 : 1);
- ComputeScaleAndOrigin();
-}
-
-
// export a bitmap as a raster image in png
-bool wxSVGFileDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
- wxDC* source, wxCoord xsrc, wxCoord ysrc,
- int logicalFunc /*= wxCOPY*/, bool useMask /*= FALSE*/,
- wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
+bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
+ wxDC* source, wxCoord xsrc, wxCoord ysrc,
+ wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
+ wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
{
if (logicalFunc != wxCOPY)
{
- wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible")) ;
- return FALSE ;
+ wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
+ return false;
}
- if (useMask != FALSE)
+ if (useMask != false)
{
- wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested False mask ; this is not possible")) ;
- return FALSE ;
+ wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
+ return false;
}
- wxBitmap myBitmap (width, height) ;
+ wxBitmap myBitmap (width, height);
wxMemoryDC memDC;
memDC.SelectObject( myBitmap );
memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
memDC.SelectObject( wxNullBitmap );
DoDrawBitmap(myBitmap, xdest, ydest);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoBlit Call executed")) ;
- return FALSE ;
+ return false;
}
-
-void wxSVGFileDC::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
+void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
{
- wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() ) ;
+ wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
wxMemoryDC memDC;
memDC.SelectObject( myBitmap );
memDC.DrawIcon(myIcon,0,0);
memDC.SelectObject( wxNullBitmap );
DoDrawBitmap(myBitmap, x, y);
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawIcon Call executed")) ;
- return ;
}
-
-
-void wxSVGFileDC::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
+void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
{
- if (m_graphics_changed) NewGraphics ();
+ NewGraphicsIfNeeded();
- wxString sTmp, s, sPNG ;
- wxImage::AddHandler(new wxPNGHandler);
+ wxString sTmp, s, sPNG;
+ if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
+ wxImage::AddHandler(new wxPNGHandler);
// create suitable file name
sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
while (wxFile::Exists(sPNG) )
{
- m_sub_images ++ ;
+ m_sub_images ++;
sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
}
//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
- wxBitmap myBitmap = bmp ;
+ wxBitmap myBitmap = bmp;
//save it
bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
-// refrence the bitmap from the SVG doc
+// reference the bitmap from the SVG doc
+// only use filename & ext
+ sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
+
+// reference the bitmap from the SVG doc
int w = myBitmap.GetWidth();
int h = myBitmap.GetHeight();
sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
- s = s + sTmp ;
+ s += sTmp;
sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
- s = s + sTmp + wxT("<title>Image from wxSVG</title> </image>") + newline;
+ s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
if (m_OK && bPNG_OK)
{
write(s);
}
- m_OK = m_outfile->Ok () && bPNG_OK;
- wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawBitmap Call executed")) ;
-
- return ;
-}
-
-
-// ---------------------------------------------------------------------------
-// coordinates transformations
-// ---------------------------------------------------------------------------
-
-wxCoord wxSVGFileDC::DeviceToLogicalX(wxCoord x) const
-{
- return XDEV2LOG(x);
-}
-
-
-wxCoord wxSVGFileDC::DeviceToLogicalY(wxCoord y) const
-{
- return YDEV2LOG(y);
-}
-
-
-wxCoord wxSVGFileDC::DeviceToLogicalXRel(wxCoord x) const
-{
- return XDEV2LOGREL(x);
-}
-
-
-wxCoord wxSVGFileDC::DeviceToLogicalYRel(wxCoord y) const
-{
- return YDEV2LOGREL(y);
-}
-
-
-wxCoord wxSVGFileDC::LogicalToDeviceX(wxCoord x) const
-{
- return XLOG2DEV(x);
-}
-
-
-wxCoord wxSVGFileDC::LogicalToDeviceY(wxCoord y) const
-{
- return YLOG2DEV(y);
-}
-
-
-wxCoord wxSVGFileDC::LogicalToDeviceXRel(wxCoord x) const
-{
- return XLOG2DEVREL(x);
-}
-
-
-wxCoord wxSVGFileDC::LogicalToDeviceYRel(wxCoord y) const
-{
- return YLOG2DEVREL(y);
+ m_OK = m_outfile->IsOk() && bPNG_OK;
}
-void wxSVGFileDC::write(const wxString &s)
+void wxSVGFileDCImpl::write(const wxString &s)
{
- const wxWX2MBbuf buf = s.mb_str(wxConvUTF8);
+ const wxCharBuffer buf = s.utf8_str();
m_outfile->Write(buf, strlen((const char *)buf));
- m_OK = m_outfile->Ok();
+ m_OK = m_outfile->IsOk();
}
+
#ifdef __BORLANDC__
#pragma warn .rch
#pragma warn .ccc
#endif
+
+#endif // wxUSE_SVG
+