Miscellaneous improvements to wxSVGFileDC, notably add gradient fill
support and shape rendering mode.

See https://github.com/wxWidgets/wxWidgets/pull/1493
This commit is contained in:
Vadim Zeitlin
2019-08-22 17:19:30 +02:00
3 changed files with 463 additions and 215 deletions

View File

@@ -11,16 +11,25 @@
#ifndef _WX_DCSVG_H_ #ifndef _WX_DCSVG_H_
#define _WX_DCSVG_H_ #define _WX_DCSVG_H_
#if wxUSE_SVG
#include "wx/string.h" #include "wx/string.h"
#include "wx/filename.h" #include "wx/filename.h"
#include "wx/dc.h" #include "wx/dc.h"
#if wxUSE_SVG
#include "wx/scopedptr.h" #include "wx/scopedptr.h"
#define wxSVGVersion wxT("v0101") #define wxSVGVersion wxT("v0101")
enum wxSVGShapeRenderingMode
{
wxSVG_SHAPE_RENDERING_AUTO = 0,
wxSVG_SHAPE_RENDERING_OPTIMIZE_SPEED,
wxSVG_SHAPE_RENDERING_CRISP_EDGES,
wxSVG_SHAPE_RENDERING_GEOMETRIC_PRECISION,
wxSVG_SHAPE_RENDERING_OPTIMISE_SPEED = wxSVG_SHAPE_RENDERING_OPTIMIZE_SPEED
};
class WXDLLIMPEXP_FWD_BASE wxFileOutputStream; class WXDLLIMPEXP_FWD_BASE wxFileOutputStream;
class WXDLLIMPEXP_FWD_CORE wxSVGFileDC; class WXDLLIMPEXP_FWD_CORE wxSVGFileDC;
@@ -76,9 +85,9 @@ public:
class WXDLLIMPEXP_CORE wxSVGFileDCImpl : public wxDCImpl class WXDLLIMPEXP_CORE wxSVGFileDCImpl : public wxDCImpl
{ {
public: public:
wxSVGFileDCImpl(wxSVGFileDC *owner, const wxString &filename, wxSVGFileDCImpl(wxSVGFileDC* owner, const wxString& filename,
int width = 320, int height = 240, double dpi = 72.0, int width = 320, int height = 240, double dpi = 72.0,
const wxString &title = wxString()); const wxString& title = wxString());
virtual ~wxSVGFileDCImpl(); virtual ~wxSVGFileDCImpl();
@@ -101,7 +110,7 @@ public:
virtual wxCoord GetCharWidth() const wxOVERRIDE; virtual wxCoord GetCharWidth() const wxOVERRIDE;
#if wxUSE_PALETTE #if wxUSE_PALETTE
virtual void SetPalette(const wxPalette& WXUNUSED(palette)) wxOVERRIDE virtual void SetPalette(const wxPalette& WXUNUSED(palette)) wxOVERRIDE
{ {
wxFAIL_MSG(wxT("wxSVGFILEDC::SetPalette not implemented")); wxFAIL_MSG(wxT("wxSVGFILEDC::SetPalette not implemented"));
} }
@@ -136,7 +145,7 @@ public:
m_graphics_changed = true; m_graphics_changed = true;
} }
virtual void SetBackground(const wxBrush &brush) wxOVERRIDE; virtual void SetBackground(const wxBrush& brush) wxOVERRIDE;
virtual void SetBackgroundMode(int mode) wxOVERRIDE; virtual void SetBackgroundMode(int mode) wxOVERRIDE;
virtual void SetBrush(const wxBrush& brush) wxOVERRIDE; virtual void SetBrush(const wxBrush& brush) wxOVERRIDE;
virtual void SetFont(const wxFont& font) wxOVERRIDE; virtual void SetFont(const wxFont& font) wxOVERRIDE;
@@ -146,81 +155,102 @@ public:
void SetBitmapHandler(wxSVGBitmapHandler* handler); void SetBitmapHandler(wxSVGBitmapHandler* handler);
void SetShapeRenderingMode(wxSVGShapeRenderingMode renderingMode);
private: private:
virtual bool DoGetPixel(wxCoord, wxCoord, wxColour *) const wxOVERRIDE virtual bool DoGetPixel(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
wxColour* WXUNUSED(col)) const wxOVERRIDE
{ {
wxFAIL_MSG(wxT("wxSVGFILEDC::DoGetPixel Call not implemented")); wxFAIL_MSG(wxT("wxSVGFILEDC::DoGetPixel Call not implemented"));
return true; return true;
} }
virtual bool DoBlit(wxCoord, wxCoord, wxCoord, wxCoord, wxDC *, virtual bool DoBlit(wxCoord xdest, wxCoord ydest,
wxCoord, wxCoord, wxRasterOperationMode = wxCOPY, wxCoord width, wxCoord height,
bool = 0, int = -1, int = -1) wxOVERRIDE; wxDC* source,
wxCoord xsrc, wxCoord ysrc,
wxRasterOperationMode rop,
bool useMask = false,
wxCoord xsrcMask = wxDefaultCoord,
wxCoord ysrcMask = wxDefaultCoord) wxOVERRIDE;
virtual void DoCrossHair(wxCoord, wxCoord) wxOVERRIDE virtual void DoCrossHair(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) wxOVERRIDE
{ {
wxFAIL_MSG(wxT("wxSVGFILEDC::CrossHair Call not implemented")); wxFAIL_MSG(wxT("wxSVGFILEDC::CrossHair Call not implemented"));
} }
virtual void DoDrawArc(wxCoord, wxCoord, wxCoord, wxCoord, wxCoord, wxCoord) wxOVERRIDE; virtual void DoDrawArc(wxCoord x1, wxCoord y1,
wxCoord x2, wxCoord y2,
wxCoord xc, wxCoord yc) wxOVERRIDE;
virtual void DoDrawBitmap(const wxBitmap &, wxCoord, wxCoord, bool = false) wxOVERRIDE; virtual void DoDrawBitmap(const wxBitmap& bmp, wxCoord x, wxCoord y,
bool useMask = false) wxOVERRIDE;
virtual void DoDrawCheckMark(wxCoord x, wxCoord y, wxCoord w, wxCoord h) wxOVERRIDE; virtual void DoDrawEllipse(wxCoord x, wxCoord y,
wxCoord width, wxCoord height) wxOVERRIDE;
virtual void DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) wxOVERRIDE;
virtual void DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, virtual void DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
double sa, double ea) wxOVERRIDE; double sa, double ea) wxOVERRIDE;
virtual void DoDrawIcon(const wxIcon &, wxCoord, wxCoord) wxOVERRIDE; virtual void DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) wxOVERRIDE;
virtual void DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) wxOVERRIDE; virtual void DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) wxOVERRIDE;
virtual void DoDrawLines(int n, const wxPoint points[], virtual void DoDrawLines(int n, const wxPoint points[],
wxCoord xoffset = 0, wxCoord yoffset = 0) wxOVERRIDE; wxCoord xoffset, wxCoord yoffset) wxOVERRIDE;
virtual void DoDrawPoint(wxCoord, wxCoord) wxOVERRIDE; virtual void DoDrawPoint(wxCoord x, wxCoord y) wxOVERRIDE;
virtual void DoDrawPolygon(int n, const wxPoint points[], virtual void DoDrawPolygon(int n, const wxPoint points[],
wxCoord xoffset, wxCoord yoffset, wxCoord xoffset, wxCoord yoffset,
wxPolygonFillMode fillStyle) wxOVERRIDE; wxPolygonFillMode fillStyle = wxODDEVEN_RULE) wxOVERRIDE;
virtual void DoDrawPolyPolygon(int n, const int count[], const wxPoint points[], virtual void DoDrawPolyPolygon(int n, const int count[], const wxPoint points[],
wxCoord xoffset, wxCoord yoffset, wxCoord xoffset, wxCoord yoffset,
wxPolygonFillMode fillStyle) wxOVERRIDE; wxPolygonFillMode fillStyle) wxOVERRIDE;
virtual void DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) wxOVERRIDE; virtual void DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) wxOVERRIDE;
virtual void DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, virtual void DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y,
double angle) wxOVERRIDE; double angle) wxOVERRIDE;
virtual void DoDrawRoundedRectangle(wxCoord x, wxCoord y, virtual void DoDrawRoundedRectangle(wxCoord x, wxCoord y,
wxCoord w, wxCoord h, wxCoord width, wxCoord height,
double radius = 20) wxOVERRIDE; double radius) wxOVERRIDE;
virtual void DoDrawText(const wxString& text, wxCoord x, wxCoord y) wxOVERRIDE; virtual void DoDrawText(const wxString& text, wxCoord x, wxCoord y) wxOVERRIDE;
virtual bool DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), virtual bool DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
const wxColour& WXUNUSED(col), const wxColour& WXUNUSED(col),
wxFloodFillStyle WXUNUSED(style) = wxFLOOD_SURFACE) wxOVERRIDE wxFloodFillStyle WXUNUSED(style)) wxOVERRIDE
{ {
wxFAIL_MSG(wxT("wxSVGFILEDC::DoFloodFill Call not implemented")); wxFAIL_MSG(wxT("wxSVGFILEDC::DoFloodFill Call not implemented"));
return false; return false;
} }
virtual void DoGetSize(int * x, int *y) const wxOVERRIDE virtual void DoGradientFillLinear(const wxRect& rect,
const wxColour& initialColour,
const wxColour& destColour,
wxDirection nDirection) wxOVERRIDE;
virtual void DoGradientFillConcentric(const wxRect& rect,
const wxColour& initialColour,
const wxColour& destColour,
const wxPoint& circleCenter) wxOVERRIDE;
virtual void DoGetSize(int* width, int* height) const wxOVERRIDE
{ {
if ( x ) if ( width )
*x = m_width; *width = m_width;
if ( y ) if ( height )
*y = m_height; *height = m_height;
} }
virtual void DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, virtual void DoGetTextExtent(const wxString& string,
wxCoord *descent = NULL, wxCoord* x, wxCoord* y,
wxCoord *externalLeading = NULL, wxCoord* descent = NULL,
const wxFont *font = NULL) const wxOVERRIDE; wxCoord* externalLeading = NULL,
const wxFont* theFont = NULL) const wxOVERRIDE;
virtual void DoSetDeviceClippingRegion(const wxRegion& region) wxOVERRIDE virtual void DoSetDeviceClippingRegion(const wxRegion& region) wxOVERRIDE
{ {
@@ -228,16 +258,17 @@ private:
region.GetBox().width, region.GetBox().height); region.GetBox().width, region.GetBox().height);
} }
virtual void DoSetClippingRegion(int x, int y, int width, int height) wxOVERRIDE; virtual void DoSetClippingRegion(wxCoord x, wxCoord y,
wxCoord w, wxCoord h) wxOVERRIDE;
virtual void DoGetSizeMM(int *width, int *height) const wxOVERRIDE; virtual void DoGetSizeMM(int* width, int* height) const wxOVERRIDE;
virtual wxSize GetPPI() const wxOVERRIDE; virtual wxSize GetPPI() const wxOVERRIDE;
void Init(const wxString &filename, int width, int height, void Init(const wxString& filename, int width, int height,
double dpi, const wxString &title); double dpi, const wxString& title);
void write(const wxString &s); void write(const wxString& s);
private: private:
// If m_graphics_changed is true, close the current <g> element and start a // If m_graphics_changed is true, close the current <g> element and start a
@@ -255,6 +286,7 @@ private:
double m_dpi; double m_dpi;
wxScopedPtr<wxFileOutputStream> m_outfile; wxScopedPtr<wxFileOutputStream> m_outfile;
wxScopedPtr<wxSVGBitmapHandler> m_bmp_handler; // class to handle bitmaps wxScopedPtr<wxSVGBitmapHandler> m_bmp_handler; // class to handle bitmaps
wxSVGShapeRenderingMode m_renderingMode;
// The clipping nesting level is incremented by every call to // The clipping nesting level is incremented by every call to
// SetClippingRegion() and reset when DestroyClippingRegion() is called. // SetClippingRegion() and reset when DestroyClippingRegion() is called.
@@ -264,7 +296,11 @@ private:
// incremented in each SetClippingRegion() call. // incremented in each SetClippingRegion() call.
size_t m_clipUniqueId; size_t m_clipUniqueId;
// Unique ID for every gradient.
size_t m_gradientUniqueId;
wxDECLARE_ABSTRACT_CLASS(wxSVGFileDCImpl); wxDECLARE_ABSTRACT_CLASS(wxSVGFileDCImpl);
wxDECLARE_NO_COPY_CLASS(wxSVGFileDCImpl);
}; };
@@ -284,6 +320,16 @@ public:
// Use a custom bitmap handler: takes ownership of the handler. // Use a custom bitmap handler: takes ownership of the handler.
void SetBitmapHandler(wxSVGBitmapHandler* handler); void SetBitmapHandler(wxSVGBitmapHandler* handler);
void SetShapeRenderingMode(wxSVGShapeRenderingMode renderingMode);
private:
wxSVGFileDC()
: wxDC(new wxSVGFileDCImpl(this, wxString()))
{
}
wxDECLARE_DYNAMIC_CLASS(wxSVGFileDC);
}; };
#endif // wxUSE_SVG #endif // wxUSE_SVG

View File

@@ -5,6 +5,23 @@
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/**
SVG shape rendering mode.
These options represent the values defined in the SVG specification:
https://svgwg.org/svg2-draft/painting.html#ShapeRenderingProperty
*/
enum wxSVGShapeRenderingMode
{
wxSVG_SHAPE_RENDERING_AUTO = 0,
wxSVG_SHAPE_RENDERING_OPTIMIZE_SPEED,
wxSVG_SHAPE_RENDERING_CRISP_EDGES,
wxSVG_SHAPE_RENDERING_GEOMETRIC_PRECISION,
wxSVG_SHAPE_RENDERING_OPTIMISE_SPEED = wxSVG_SHAPE_RENDERING_OPTIMIZE_SPEED
};
/** /**
@class wxSVGFileDC @class wxSVGFileDC
@@ -74,6 +91,17 @@ public:
*/ */
void SetBitmapHandler(wxSVGBitmapHandler* handler); void SetBitmapHandler(wxSVGBitmapHandler* handler);
/**
Set the shape rendering mode of the generated SVG.
All subsequent drawing calls will have this rendering mode set in the
SVG file.
The default mode is wxSVG_SHAPE_RENDERING_AUTO.
@since 3.1.3
*/
void SetShapeRenderingMode(wxSVGShapeRenderingMode renderingMode);
/** /**
Sets the clipping region for this device context to the intersection of Sets the clipping region for this device context to the intersection of
the given region described by the parameters of this method and the previously the given region described by the parameters of this method and the previously

View File

@@ -48,16 +48,23 @@ namespace
// in this code originally). // in this code originally).
inline wxString NumStr(double f) inline wxString NumStr(double f)
{ {
// Handle this case specially to avoid generating "-0.00" in the output.
if ( f == 0 )
{
return wxS("0.00");
}
return wxString::FromCDouble(f, 2); return wxString::FromCDouble(f, 2);
} }
// Return the colour representation as HTML-like "#rrggbb" string and also // Return the colour representation as HTML-like "#rrggbb" string and also
// returns its alpha as opacity number in 0..1 range. // returns its alpha as opacity number in 0..1 range.
wxString Col2SVG(wxColour c, float *opacity) wxString Col2SVG(wxColour c, float* opacity = NULL)
{ {
if ( c.Alpha() != wxALPHA_OPAQUE ) if ( c.Alpha() != wxALPHA_OPAQUE )
{ {
*opacity = c.Alpha() / 255.0f; if ( opacity )
*opacity = c.Alpha() / 255.0f;
// Remove the alpha before using GetAsString(wxC2S_HTML_SYNTAX) as it // Remove the alpha before using GetAsString(wxC2S_HTML_SYNTAX) as it
// doesn't support colours with alpha channel. // doesn't support colours with alpha channel.
@@ -65,16 +72,17 @@ wxString Col2SVG(wxColour c, float *opacity)
} }
else // No alpha. else // No alpha.
{ {
*opacity = 1.; if ( opacity )
*opacity = 1.0f;
} }
return c.GetAsString(wxC2S_HTML_SYNTAX); return c.GetAsString(wxC2S_HTML_SYNTAX);
} }
wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID) wxString GetPenStroke(const wxColour& c, int style = wxPENSTYLE_SOLID)
{ {
float opacity; float opacity;
wxString s = wxS("stroke:") + Col2SVG(c, &opacity) + wxS("; "); wxString s = wxS("stroke:") + Col2SVG(c, &opacity) + wxS(";");
switch ( style ) switch ( style )
{ {
@@ -84,45 +92,47 @@ wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
case wxPENSTYLE_LONG_DASH: case wxPENSTYLE_LONG_DASH:
case wxPENSTYLE_DOT_DASH: case wxPENSTYLE_DOT_DASH:
case wxPENSTYLE_USER_DASH: case wxPENSTYLE_USER_DASH:
s += wxString::Format(wxS("stroke-opacity:%s; "), NumStr(opacity)); s += wxString::Format(wxS(" stroke-opacity:%s;"), NumStr(opacity));
break; break;
case wxPENSTYLE_TRANSPARENT: case wxPENSTYLE_TRANSPARENT:
s += wxS("stroke-opacity:0.0; "); s += wxS(" stroke-opacity:0.0;");
break; break;
default: default:
wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Pen Style not available")); wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Pen Style not available"));
break;
} }
return s; return s;
} }
wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID) wxString GetBrushFill(const wxColour& c, int style = wxBRUSHSTYLE_SOLID)
{ {
float opacity; float opacity;
wxString s = wxS("fill:") + Col2SVG(c, &opacity) + wxS("; "); wxString s = wxS("fill:") + Col2SVG(c, &opacity) + wxS(";");
switch ( style ) switch ( style )
{ {
case wxBRUSHSTYLE_SOLID: case wxBRUSHSTYLE_SOLID:
case wxBRUSHSTYLE_BDIAGONAL_HATCH:
case wxBRUSHSTYLE_FDIAGONAL_HATCH: case wxBRUSHSTYLE_FDIAGONAL_HATCH:
case wxBRUSHSTYLE_CROSSDIAG_HATCH: case wxBRUSHSTYLE_CROSSDIAG_HATCH:
case wxBRUSHSTYLE_CROSS_HATCH: case wxBRUSHSTYLE_CROSS_HATCH:
case wxBRUSHSTYLE_VERTICAL_HATCH: case wxBRUSHSTYLE_VERTICAL_HATCH:
case wxBRUSHSTYLE_HORIZONTAL_HATCH: case wxBRUSHSTYLE_HORIZONTAL_HATCH:
s += wxString::Format(wxS("fill-opacity:%s; "), NumStr(opacity)); s += wxString::Format(wxS(" fill-opacity:%s;"), NumStr(opacity));
break; break;
case wxBRUSHSTYLE_TRANSPARENT: case wxBRUSHSTYLE_TRANSPARENT:
s += wxS("fill-opacity:0.0; "); s += wxS(" fill-opacity:0.0;");
break; break;
default: default:
wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Brush Style not available")); wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Brush Style not available"));
break;
} }
return s; return s;
} }
static wxString GetPenPattern(const wxPen& pen)
wxString wxGetPenPattern(wxPen& pen)
{ {
wxString s; wxString s;
@@ -139,21 +149,21 @@ wxString wxGetPenPattern(wxPen& pen)
switch (pen.GetStyle()) switch (pen.GetStyle())
{ {
case wxPENSTYLE_DOT: case wxPENSTYLE_DOT:
s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\" "), w * 2, w * 5); s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\""), w * 2, w * 5);
break; break;
case wxPENSTYLE_SHORT_DASH: case wxPENSTYLE_SHORT_DASH:
s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\" "), w * 10, w * 8); s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\""), w * 10, w * 8);
break; break;
case wxPENSTYLE_LONG_DASH: case wxPENSTYLE_LONG_DASH:
s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\" "), w * 15, w * 8); s = wxString::Format(wxS("stroke-dasharray=\"%f,%f\""), w * 15, w * 8);
break; break;
case wxPENSTYLE_DOT_DASH: case wxPENSTYLE_DOT_DASH:
s = wxString::Format(wxS("stroke-dasharray=\"%f,%f,%f,%f\" "), w * 8, w * 8, w * 2, w * 8); s = wxString::Format(wxS("stroke-dasharray=\"%f,%f,%f,%f\""), w * 8, w * 8, w * 2, w * 8);
break; break;
case wxPENSTYLE_USER_DASH: case wxPENSTYLE_USER_DASH:
{ {
s = wxS("stroke-dasharray=\""); s = wxS("stroke-dasharray=\"");
wxDash *dashes; wxDash* dashes;
int count = pen.GetDashes(&dashes); int count = pen.GetDashes(&dashes);
if ((dashes != NULL) && (count > 0)) if ((dashes != NULL) && (count > 0))
{ {
@@ -164,7 +174,7 @@ wxString wxGetPenPattern(wxPen& pen)
s << ","; s << ",";
} }
} }
s += wxS("\" "); s += wxS("\"");
break; break;
} }
case wxPENSTYLE_STIPPLE_MASK_OPAQUE: case wxPENSTYLE_STIPPLE_MASK_OPAQUE:
@@ -187,12 +197,52 @@ wxString wxGetPenPattern(wxPen& pen)
return s; return s;
} }
wxString wxGetBrushStyleName(wxBrush& brush) wxString GetPenStyle(const wxPen& pen)
{
wxString penStyle;
penStyle += wxString::Format(wxS("stroke-width:%d;"), pen.GetWidth());
switch (pen.GetCap())
{
case wxCAP_PROJECTING:
penStyle += wxS(" stroke-linecap:square;");
break;
case wxCAP_BUTT:
penStyle += wxS(" stroke-linecap:butt;");
break;
case wxCAP_ROUND:
default:
penStyle += wxS(" stroke-linecap:round;");
break;
}
switch (pen.GetJoin())
{
case wxJOIN_BEVEL:
penStyle += wxS(" stroke-linejoin:bevel;");
break;
case wxJOIN_MITER:
penStyle += wxS(" stroke-linejoin:miter;");
break;
case wxJOIN_ROUND:
default:
penStyle += wxS(" stroke-linejoin:round;");
break;
}
return penStyle;
}
wxString GetBrushStyleName(const wxBrush& brush)
{ {
wxString brushStyle; wxString brushStyle;
switch (brush.GetStyle()) switch (brush.GetStyle())
{ {
case wxBRUSHSTYLE_BDIAGONAL_HATCH:
brushStyle = wxS("BdiagonalHatch");
break;
case wxBRUSHSTYLE_FDIAGONAL_HATCH: case wxBRUSHSTYLE_FDIAGONAL_HATCH:
brushStyle = wxS("FdiagonalHatch"); brushStyle = wxS("FdiagonalHatch");
break; break;
@@ -211,7 +261,6 @@ wxString wxGetBrushStyleName(wxBrush& brush)
case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE: case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE:
case wxBRUSHSTYLE_STIPPLE_MASK: case wxBRUSHSTYLE_STIPPLE_MASK:
case wxBRUSHSTYLE_STIPPLE: case wxBRUSHSTYLE_STIPPLE:
case wxBRUSHSTYLE_BDIAGONAL_HATCH:
wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Brush Fill not available")); wxASSERT_MSG(false, wxS("wxSVGFileDC::Requested Brush Fill not available"));
break; break;
case wxBRUSHSTYLE_SOLID: case wxBRUSHSTYLE_SOLID:
@@ -224,56 +273,85 @@ wxString wxGetBrushStyleName(wxBrush& brush)
return brushStyle; return brushStyle;
} }
wxString wxGetBrushFill(wxBrush& brush) wxString GetBrushPattern(const wxBrush& brush)
{ {
wxString s; wxString s;
wxString brushStyle = wxGetBrushStyleName(brush); wxString brushStyle = GetBrushStyleName(brush);
if (!brushStyle.IsEmpty()) if (!brushStyle.empty())
s = wxS(" fill=\"url(#") + brushStyle + brush.GetColour().GetAsString(wxC2S_HTML_SYNTAX).substr(1) + wxS(")\""); s = wxS("fill=\"url(#") + brushStyle + Col2SVG(brush.GetColour()).substr(1) + wxS(")\"");
return s; return s;
} }
wxString wxCreateBrushFill(wxBrush& brush) wxString GetRenderMode(const wxSVGShapeRenderingMode style)
{
wxString mode;
switch (style)
{
case wxSVG_SHAPE_RENDERING_OPTIMIZE_SPEED:
mode = wxS("optimizeSpeed");
break;
case wxSVG_SHAPE_RENDERING_CRISP_EDGES:
mode = wxS("crispEdges");
break;
case wxSVG_SHAPE_RENDERING_GEOMETRIC_PRECISION:
mode = wxS("geometricPrecision");
break;
case wxSVG_SHAPE_RENDERING_AUTO:
mode = wxS("auto");
break;
}
wxString s = wxString::Format(wxS("shape-rendering=\"%s\""), mode);
return s;
}
wxString CreateBrushFill(const wxBrush& brush, wxSVGShapeRenderingMode mode)
{ {
wxString s; wxString s;
wxString patternName = wxGetBrushStyleName(brush); wxString patternName = GetBrushStyleName(brush);
if (!patternName.IsEmpty()) if (!patternName.empty())
{ {
patternName += brush.GetColour().GetAsString(wxC2S_HTML_SYNTAX).substr(1); wxString pattern;
s = wxS("<pattern id=\"") + patternName + wxS("\" patternUnits=\"userSpaceOnUse\" width=\"8\" height=\"8\">\n");
s += wxS(" <path style=\"stroke:") + brush.GetColour().GetAsString(wxC2S_HTML_SYNTAX) + wxS(";\" ");
switch (brush.GetStyle()) switch (brush.GetStyle())
{ {
case wxBRUSHSTYLE_BDIAGONAL_HATCH:
pattern = wxS("d=\"M-1,1 l2,-2 M0,8 l8,-8 M7,9 l2,-2\"");
break;
case wxBRUSHSTYLE_FDIAGONAL_HATCH: case wxBRUSHSTYLE_FDIAGONAL_HATCH:
s += wxS("d=\"M7,-1 l2,2 M0,0 l8,8 M-1,7 l2,2\""); pattern = wxS("d=\"M7,-1 l2,2 M0,0 l8,8 M-1,7 l2,2\"");
break; break;
case wxBRUSHSTYLE_CROSSDIAG_HATCH: case wxBRUSHSTYLE_CROSSDIAG_HATCH:
s += wxS("d=\"M7,-1 l2,2 M0,0 l8,8 M-1,7 l2,2 M-1,1 l2,-2 M0,8 l8,-8 M7,9 l2,-2\""); pattern = wxS("d=\"M7,-1 l2,2 M0,0 l8,8 M-1,7 l2,2 M-1,1 l2,-2 M0,8 l8,-8 M7,9 l2,-2\"");
break; break;
case wxBRUSHSTYLE_CROSS_HATCH: case wxBRUSHSTYLE_CROSS_HATCH:
s += wxS("d=\"M4,0 l0,8 M0,4 l8,0\""); pattern = wxS("d=\"M4,0 l0,8 M0,4 l8,0\"");
break; break;
case wxBRUSHSTYLE_VERTICAL_HATCH: case wxBRUSHSTYLE_VERTICAL_HATCH:
s += wxS("d=\"M4,0 l0,8\""); pattern = wxS("d=\"M4,0 l0,8\"");
break; break;
case wxBRUSHSTYLE_HORIZONTAL_HATCH: case wxBRUSHSTYLE_HORIZONTAL_HATCH:
s += wxS("d=\"M0,4 l8,0\""); pattern = wxS("d=\"M0,4 l8,0\"");
break; break;
default: default:
break; break;
} }
s += wxS("/>\n</pattern>\n"); wxString brushColourStr = Col2SVG(brush.GetColour());
s += wxString::Format(wxS(" <pattern id=\"%s%s\" patternUnits=\"userSpaceOnUse\" width=\"8\" height=\"8\">\n"),
patternName, brushColourStr.substr(1));
s += wxString::Format(wxS(" <path style=\"stroke:%s;\" %s %s/>\n"),
brushColourStr, pattern, GetRenderMode(mode));
s += wxS(" </pattern>\n");
} }
return s; return s;
} }
void wxSetScaledScreenDCFont(wxScreenDC& sDC, const wxFont& font) void SetScaledScreenDCFont(wxScreenDC& sDC, const wxFont& font)
{ {
const double scale = sDC.GetContentScaleFactor(); const double scale = sDC.GetContentScaleFactor();
if ( scale > 1 ) if ( scale > 1 )
@@ -337,7 +415,7 @@ wxSVGBitmapEmbedHandler::ProcessBitmap(const wxBitmap& bmp,
// write to the SVG file // write to the SVG file
const wxCharBuffer buf = s.utf8_str(); const wxCharBuffer buf = s.utf8_str();
stream.Write(buf, strlen((const char *)buf)); stream.Write(buf, strlen((const char*)buf));
return stream.IsOk(); return stream.IsOk();
} }
@@ -362,7 +440,7 @@ wxSVGBitmapFileHandler::ProcessBitmap(const wxBitmap& bmp,
{ {
sPNG.SetFullName(wxString::Format("%s%simage%d.png", sPNG.SetFullName(wxString::Format("%s%simage%d.png",
sPNG.GetName(), sPNG.GetName(),
sPNG.GetName().IsEmpty() ? "" : "_", sPNG.GetName().empty() ? "" : "_",
sub_images++)); sub_images++));
} }
while ( sPNG.FileExists() ); while ( sPNG.FileExists() );
@@ -387,29 +465,36 @@ wxSVGBitmapFileHandler::ProcessBitmap(const wxBitmap& bmp,
// wxSVGFileDC (specialisations) // wxSVGFileDC (specialisations)
// ---------------------------------------------------------- // ----------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxSVGFileDC, wxDC);
void wxSVGFileDC::SetBitmapHandler(wxSVGBitmapHandler* handler) void wxSVGFileDC::SetBitmapHandler(wxSVGBitmapHandler* handler)
{ {
((wxSVGFileDCImpl*)GetImpl())->SetBitmapHandler(handler); ((wxSVGFileDCImpl*)GetImpl())->SetBitmapHandler(handler);
} }
void wxSVGFileDC::SetShapeRenderingMode(wxSVGShapeRenderingMode renderingMode)
{
((wxSVGFileDCImpl*)GetImpl())->SetShapeRenderingMode(renderingMode);
}
// ---------------------------------------------------------- // ----------------------------------------------------------
// wxSVGFileDCImpl // wxSVGFileDCImpl
// ---------------------------------------------------------- // ----------------------------------------------------------
wxIMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC); wxIMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDCImpl);
wxSVGFileDCImpl::wxSVGFileDCImpl(wxSVGFileDC *owner, const wxString &filename, wxSVGFileDCImpl::wxSVGFileDCImpl(wxSVGFileDC* owner, const wxString& filename,
int width, int height, double dpi, const wxString &title) int width, int height, double dpi, const wxString& title)
: wxDCImpl(owner) : wxDCImpl(owner)
{ {
Init(filename, width, height, dpi, title); Init(filename, width, height, dpi, title);
} }
void wxSVGFileDCImpl::Init(const wxString &filename, int Width, int Height, void wxSVGFileDCImpl::Init(const wxString& filename, int width, int height,
double dpi, const wxString &title) double dpi, const wxString& title)
{ {
m_width = Width; m_width = width;
m_height = Height; m_height = height;
m_dpi = dpi; m_dpi = dpi;
@@ -418,6 +503,8 @@ void wxSVGFileDCImpl::Init(const wxString &filename, int Width, int Height,
m_clipUniqueId = 0; m_clipUniqueId = 0;
m_clipNestingLevel = 0; m_clipNestingLevel = 0;
m_gradientUniqueId = 0;
m_mm_to_pix_x = dpi / 25.4; m_mm_to_pix_x = dpi / 25.4;
m_mm_to_pix_y = dpi / 25.4; m_mm_to_pix_y = dpi / 25.4;
@@ -432,16 +519,22 @@ void wxSVGFileDCImpl::Init(const wxString &filename, int Width, int Height,
m_filename = filename; m_filename = filename;
m_graphics_changed = true; m_graphics_changed = true;
m_renderingMode = wxSVG_SHAPE_RENDERING_AUTO;
////////////////////code here ////////////////////code here
m_bmp_handler.reset(); m_bmp_handler.reset();
m_outfile.reset(new wxFileOutputStream(m_filename));
if ( m_filename.empty() )
m_outfile.reset();
else
m_outfile.reset(new wxFileOutputStream(m_filename));
wxString s; wxString s;
s += wxS("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); s += wxS("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
s += wxS("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n\n"); s += wxS("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n\n");
s += wxS("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\""); s += wxS("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
s += wxString::Format(wxS(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d\">\n"), NumStr(float(Width) / dpi * 2.54), NumStr(float(Height) / dpi * 2.54), Width, Height); s += wxString::Format(wxS(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d\">\n"), NumStr(float(m_width) / dpi * 2.54), NumStr(float(m_height) / dpi * 2.54), m_width, m_height);
s += wxString::Format(wxS("<title>%s</title>\n"), title); s += wxString::Format(wxS("<title>%s</title>\n"), title);
s += wxString(wxS("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxS("</desc>\n\n"); s += wxString(wxS("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxS("</desc>\n\n");
s += wxS("<g style=\"fill:black; stroke:black; stroke-width:1\">\n"); s += wxS("<g style=\"fill:black; stroke:black; stroke-width:1\">\n");
@@ -460,7 +553,7 @@ wxSVGFileDCImpl::~wxSVGFileDCImpl()
write(s); write(s);
} }
void wxSVGFileDCImpl::DoGetSizeMM(int *width, int *height) const void wxSVGFileDCImpl::DoGetSizeMM(int* width, int* height) const
{ {
if (width) if (width)
*width = wxRound( (double)m_width / GetMMToPXx() ); *width = wxRound( (double)m_width / GetMMToPXx() );
@@ -490,7 +583,8 @@ void wxSVGFileDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString s; wxString s;
s = wxString::Format(wxS(" <path %sd=\"M%d %d L%d %d\"/>\n"), wxGetPenPattern(m_pen), x1, y1, x2, y2); s = wxString::Format(wxS(" <path d=\"M%d %d L%d %d\" %s %s/>\n"),
x1, y1, x2, y2, GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
write(s); write(s);
@@ -505,8 +599,9 @@ void wxSVGFileDCImpl::DoDrawLines(int n, const wxPoint points[], wxCoord xoffset
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString s; wxString s;
s = wxS(" <path ") + wxGetPenPattern(m_pen); s = wxString::Format(wxS(" <path d=\"M%d %d"),
s += wxString::Format(wxS("d=\"M%d %d"), (points[0].x + xoffset), (points[0].y + yoffset)); (points[0].x + xoffset), (points[0].y + yoffset));
CalcBoundingBox(points[0].x + xoffset, points[0].y + yoffset); CalcBoundingBox(points[0].x + xoffset, points[0].y + yoffset);
for (int i = 1; i < n; ++i) for (int i = 1; i < n; ++i)
@@ -515,31 +610,31 @@ void wxSVGFileDCImpl::DoDrawLines(int n, const wxPoint points[], wxCoord xoffset
CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
} }
s += wxS("\" style=\"fill:none\"/>\n"); s += wxString::Format(wxS("\" style=\"fill:none\" %s %s/>\n"),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
write(s); write(s);
} }
} }
void wxSVGFileDCImpl::DoDrawPoint(wxCoord x1, wxCoord y1) void wxSVGFileDCImpl::DoDrawPoint(wxCoord x, wxCoord y)
{ {
wxString s;
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
s = wxS("<g style=\"stroke-linecap:round;\">\n");
wxString s;
s = wxS(" <g style=\"stroke-width:1; stroke-linecap:round;\">\n ");
write(s); write(s);
DoDrawLine(x1, y1, x1, y1);
s = wxS("</g>\n"); DoDrawLine(x, y, x, y);
s = wxS(" </g>\n");
write(s); write(s);
} }
void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height) void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
{ {
wxDCImpl::DoDrawCheckMark(x1, y1, width, height); DoDrawRotatedText(text, x, y, 0.0);
}
void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
{
DoDrawRotatedText(text, x1, y1, 0.0);
} }
void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle) void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
@@ -586,7 +681,7 @@ void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoor
textDecoration += wxS(" underline"); textDecoration += wxS(" underline");
if (m_font.GetStrikethrough()) if (m_font.GetStrikethrough())
textDecoration += wxS(" line-through"); textDecoration += wxS(" line-through");
if (textDecoration.IsEmpty()) if (textDecoration.empty())
textDecoration = wxS(" none"); textDecoration = wxS(" none");
wxString style = wxS("style=\""); wxString style = wxS("style=\"");
@@ -596,8 +691,8 @@ void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoor
style += wxString::Format(wxS("font-size:%spt; "), NumStr(m_font.GetFractionalPointSize())); style += wxString::Format(wxS("font-size:%spt; "), NumStr(m_font.GetFractionalPointSize()));
style += wxString::Format(wxS("text-decoration:%s; "), textDecoration); style += wxString::Format(wxS("text-decoration:%s; "), textDecoration);
style += wxString::Format(wxS("%s %s stroke-width:0; "), style += wxString::Format(wxS("%s %s stroke-width:0; "),
wxBrushString(m_textForegroundColour), GetBrushFill(m_textForegroundColour),
wxPenString(m_textForegroundColour)); GetPenStroke(m_textForegroundColour));
style += wxS("white-space: pre;"); style += wxS("white-space: pre;");
style += wxS("\""); style += wxS("\"");
@@ -609,42 +704,43 @@ void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoor
const wxArrayString lines = wxSplit(sText, '\n', '\0'); const wxArrayString lines = wxSplit(sText, '\n', '\0');
for (size_t lineNum = 0; lineNum < lines.size(); lineNum++) for (size_t lineNum = 0; lineNum < lines.size(); lineNum++)
{ {
const int xRect = x + wxRound(lineNum * dx); const double xRect = x + lineNum * dx;
const int yRect = y + wxRound(lineNum * dy); const double yRect = y + lineNum * dy;
// convert x,y to SVG text x,y (the coordinates of the text baseline) // convert x,y to SVG text x,y (the coordinates of the text baseline)
wxCoord ww, hh, desc; wxCoord ww, hh, desc;
wxString const& line = lines[lineNum]; wxString const& line = lines[lineNum];
DoGetTextExtent(line, &ww, &hh, &desc); DoGetTextExtent(line, &ww, &hh, &desc);
const int xText = xRect + (hh - desc) * sin(rad); const double xText = xRect + (hh - desc) * sin(rad);
const int yText = yRect + (hh - desc) * cos(rad); const double yText = yRect + (hh - desc) * cos(rad);
if (m_backgroundMode == wxBRUSHSTYLE_SOLID) if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
{ {
// draw text background // draw text background
const wxString rectStyle = wxString::Format( const wxString rectStyle = wxString::Format(
wxS("style=\"%s %s stroke-width:1;\""), wxS("style=\"%s %s stroke-width:1;\""),
wxBrushString(m_textBackgroundColour), GetBrushFill(m_textBackgroundColour),
wxPenString(m_textBackgroundColour)); GetPenStroke(m_textBackgroundColour));
const wxString rectTransform = wxString::Format( const wxString rectTransform = wxString::Format(
wxS("transform=\"rotate(%s %d %d)\""), wxS("transform=\"rotate(%s %s %s)\""),
NumStr(-angle), xRect, yRect); NumStr(-angle), NumStr(xRect), NumStr(yRect));
s = wxString::Format( s = wxString::Format(
wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" %s %s/>\n"), wxS(" <rect x=\"%s\" y=\"%s\" width=\"%d\" height=\"%d\" %s %s %s/>\n"),
xRect, yRect, ww, hh, rectStyle, rectTransform); NumStr(xRect), NumStr(yRect), ww, hh,
GetRenderMode(m_renderingMode), rectStyle, rectTransform);
write(s); write(s);
} }
const wxString transform = wxString::Format( const wxString transform = wxString::Format(
wxS("transform=\"rotate(%s %d %d)\""), wxS("transform=\"rotate(%s %s %s)\""),
NumStr(-angle), xText, yText); NumStr(-angle), NumStr(xText), NumStr(yText));
s = wxString::Format( s = wxString::Format(
wxS(" <text x=\"%d\" y=\"%d\" textLength=\"%d\" %s %s>%s</text>\n"), wxS(" <text x=\"%s\" y=\"%s\" textLength=\"%d\" %s %s>%s</text>\n"),
xText, yText, ww, style, transform, NumStr(xText), NumStr(yText), ww, style, transform,
#if wxUSE_MARKUP #if wxUSE_MARKUP
wxMarkupParser::Quote(line) wxMarkupParser::Quote(line)
#else #else
@@ -658,7 +754,7 @@ void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoor
void wxSVGFileDCImpl::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.0);
} }
void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius) void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
@@ -666,10 +762,10 @@ void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString s; wxString s;
s = wxString::Format(wxS(" <rect %sx=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\"%s"), s = wxString::Format(wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" %s %s %s/>\n"),
wxGetPenPattern(m_pen), x, y, width, height, NumStr(radius), wxGetBrushFill(m_brush)); x, y, width, height, NumStr(radius),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen), GetBrushPattern(m_brush));
s += wxS("/>\n");
write(s); write(s);
CalcBoundingBox(x, y); CalcBoundingBox(x, y);
@@ -681,22 +777,21 @@ void wxSVGFileDCImpl::DoDrawPolygon(int n, const wxPoint points[],
wxPolygonFillMode fillStyle) wxPolygonFillMode fillStyle)
{ {
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString s; wxString s;
s = wxS(" <polygon style=\""); s = wxS(" <polygon points=\"");
if (fillStyle == wxODDEVEN_RULE)
s += wxS("fill-rule:evenodd;");
else
s += wxS("fill-rule:nonzero;");
s += wxS("\" ") + wxGetPenPattern(m_pen) + wxGetBrushFill(m_brush) + wxS(" points=\"");
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {
s += wxString::Format(wxS("%d %d "), points[i].x + xoffset, points[i].y + yoffset); s += wxString::Format(wxS("%d %d "), points[i].x + xoffset, points[i].y + yoffset);
CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
} }
s += wxS("\"/>\n");
s += wxString::Format(wxS("\" %s %s %s style=\"fill-rule:%s;\"/>\n"),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen), GetBrushPattern(m_brush),
fillStyle == wxODDEVEN_RULE ? wxS("evenodd") : wxS("nonzero"));
write(s); write(s);
} }
@@ -746,12 +841,13 @@ void wxSVGFileDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord
{ {
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
int rh = height / 2; const double rh = height / 2.0;
int rw = width / 2; const double rw = width / 2.0;
wxString s; wxString s;
s = wxString::Format(wxS(" <ellipse %scx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\""), s = wxString::Format(wxS(" <ellipse cx=\"%s\" cy=\"%s\" rx=\"%s\" ry=\"%s\" %s %s"),
wxGetPenPattern(m_pen), x + rw, y + rh, rw, rh); NumStr(x + rw), NumStr(y + rh), NumStr(rw), NumStr(rh),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
s += wxS("/>\n"); s += wxS("/>\n");
write(s); write(s);
@@ -803,8 +899,8 @@ void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
if (x1 == x2 && y1 == y2) if (x1 == x2 && y1 == y2)
{ {
// drawing full circle fails with default arc. Draw two half arcs instead. // drawing full circle fails with default arc. Draw two half arcs instead.
s = wxString::Format(wxS(" <path %sd=\"M%d %d a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"), s = wxString::Format(wxS(" <path d=\"M%d %d a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"),
wxGetPenPattern(m_pen), x1, y1, x1, y1,
NumStr(r1), NumStr(r2), fArc, fSweep, NumStr( r1 * 2), NumStr(0), NumStr(r1), NumStr(r2), fArc, fSweep, NumStr( r1 * 2), NumStr(0),
NumStr(r1), NumStr(r2), fArc, fSweep, NumStr(-r1 * 2), NumStr(0)); NumStr(r1), NumStr(r2), fArc, fSweep, NumStr(-r1 * 2), NumStr(0));
} }
@@ -815,12 +911,12 @@ void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
if (GetBrush().GetStyle() != wxBRUSHSTYLE_TRANSPARENT) if (GetBrush().GetStyle() != wxBRUSHSTYLE_TRANSPARENT)
line = wxString::Format(wxS("L%d %d z"), xc, yc); line = wxString::Format(wxS("L%d %d z"), xc, yc);
s = wxString::Format(wxS(" <path %sd=\"M%d %d A%s %s 0 %d %d %d %d %s"), s = wxString::Format(wxS(" <path d=\"M%d %d A%s %s 0 %d %d %d %d %s"),
wxGetPenPattern(m_pen), x1, y1, x1, y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, line);
NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, line);
} }
s += wxS("\"/>\n"); s += wxString::Format(wxS("\" %s %s/>\n"),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
write(s); write(s);
} }
@@ -883,15 +979,15 @@ void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord
{ {
// Drawing full circle fails with default arc. Draw two half arcs instead. // Drawing full circle fails with default arc. Draw two half arcs instead.
fArc = 1; fArc = 1;
arcPath = wxString::Format(wxS(" <path %sd=\"M%s %s a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"), arcPath = wxString::Format(wxS(" <path d=\"M%s %s a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"),
wxGetPenPattern(m_pen), NumStr(x), NumStr(y + ry), NumStr(x), NumStr(y + ry),
NumStr(rx), NumStr(ry), fArc, fSweep, NumStr( rx * 2), NumStr(0), NumStr(rx), NumStr(ry), fArc, fSweep, NumStr( rx * 2), NumStr(0),
NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(-rx * 2), NumStr(0)); NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(-rx * 2), NumStr(0));
} }
else else
{ {
arcPath = wxString::Format(wxS(" <path %sd=\"M%s %s A%s %s 0 %d %d %s %s"), arcPath = wxString::Format(wxS(" <path d=\"M%s %s A%s %s 0 %d %d %s %s"),
wxGetPenPattern(m_pen), NumStr(xs), NumStr(ys), NumStr(xs), NumStr(ys),
NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(xe), NumStr(ye)); NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(xe), NumStr(ye));
} }
@@ -905,19 +1001,101 @@ void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString arcFill = arcPath; wxString arcFill = arcPath;
arcFill += wxString::Format(wxS(" L%s %s z"), NumStr(xc), NumStr(yc)); arcFill += wxString::Format(wxS(" L%s %s z\" %s %s/>\n"),
arcFill += wxS("\"/>\n"); NumStr(xc), NumStr(yc),
GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
write(arcFill); write(arcFill);
} }
wxDCBrushChanger setTransp(*GetOwner(), *wxTRANSPARENT_BRUSH); wxDCBrushChanger setTransp(*GetOwner(), *wxTRANSPARENT_BRUSH);
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
wxString arcLine = arcPath + wxS("\"/>\n"); wxString arcLine = wxString::Format(wxS("%s\" %s %s/>\n"),
arcPath, GetRenderMode(m_renderingMode), GetPenPattern(m_pen));
write(arcLine); write(arcLine);
} }
void wxSVGFileDCImpl::DoSetClippingRegion(int x, int y, int width, int height) void wxSVGFileDCImpl::DoGradientFillLinear(const wxRect& rect,
const wxColour& initialColour,
const wxColour& destColour,
wxDirection nDirection)
{
NewGraphicsIfNeeded();
float initOpacity;
float destOpacity;
wxString initCol = Col2SVG(initialColour, &initOpacity);
wxString destCol = Col2SVG(destColour, &destOpacity);
const int x1 = ((nDirection & wxLEFT) > 0) ? 100 : 0;
const int y1 = ((nDirection & wxUP) > 0) ? 100 : 0;
const int x2 = ((nDirection & wxRIGHT) > 0) ? 100 : 0;
const int y2 = ((nDirection & wxDOWN) > 0) ? 100 : 0;
wxString s;
s += wxS(" <defs>\n");
s += wxString::Format(wxS(" <linearGradient id=\"gradient%zu\" x1=\"%d%%\" y1=\"%d%%\" x2=\"%d%%\" y2=\"%d%%\">\n"),
m_gradientUniqueId, x1, y1, x2, y2);
s += wxString::Format(wxS(" <stop offset=\"0%%\" style=\"stop-color:%s; stop-opacity:%s\"/>\n"),
initCol, NumStr(initOpacity));
s += wxString::Format(wxS(" <stop offset=\"100%%\" style=\"stop-color:%s; stop-opacity:%s\"/>\n"),
destCol, NumStr(destOpacity));
s += wxS(" </linearGradient>\n");
s += wxS(" </defs>\n");
s += wxString::Format(wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" fill=\"url(#gradient%zu)\" %s %s %s/>\n"),
rect.x, rect.y, rect.width, rect.height, m_gradientUniqueId,
GetRenderMode(m_renderingMode), GetPenPattern(m_pen), GetBrushPattern(m_brush));
m_gradientUniqueId++;
write(s);
CalcBoundingBox(rect.x, rect.y);
CalcBoundingBox(rect.x + rect.width, rect.y + rect.height);
}
void wxSVGFileDCImpl::DoGradientFillConcentric(const wxRect& rect,
const wxColour& initialColour,
const wxColour& destColour,
const wxPoint& circleCenter)
{
NewGraphicsIfNeeded();
float initOpacity;
float destOpacity;
wxString initCol = Col2SVG(initialColour, &initOpacity);
wxString destCol = Col2SVG(destColour, &destOpacity);
const double cx = circleCenter.x * 100.0 / rect.GetWidth();
const double cy = circleCenter.y * 100.0 / rect.GetHeight();
const double fx = cx;
const double fd = cy;
wxString s;
s += wxS(" <defs>\n");
s += wxString::Format(wxS(" <radialGradient id=\"gradient%zu\" cx=\"%s%%\" cy=\"%s%%\" fx=\"%s%%\" fy=\"%s%%\">\n"),
m_gradientUniqueId, NumStr(cx), NumStr(cy), NumStr(fx), NumStr(fd));
s += wxString::Format(wxS(" <stop offset=\"0%%\" style=\"stop-color:%s; stop-opacity:%s\" />\n"),
initCol, NumStr(initOpacity));
s += wxString::Format(wxS(" <stop offset=\"100%%\" style=\"stop-color:%s; stop-opacity:%s\" />\n"),
destCol, NumStr(destOpacity));
s += wxS(" </radialGradient>\n");
s += wxS(" </defs>\n");
s += wxString::Format(wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" fill=\"url(#gradient%zu)\" %s %s %s/>\n"),
rect.x, rect.y, rect.width, rect.height, m_gradientUniqueId,
GetRenderMode(m_renderingMode), GetPenPattern(m_pen), GetBrushPattern(m_brush));
m_gradientUniqueId++;
write(s);
CalcBoundingBox(rect.x, rect.y);
CalcBoundingBox(rect.x + rect.width, rect.y + rect.height);
}
void wxSVGFileDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{ {
wxString svg; wxString svg;
@@ -975,18 +1153,23 @@ void wxSVGFileDCImpl::DestroyClippingRegion()
wxDCImpl::DestroyClippingRegion(); wxDCImpl::DestroyClippingRegion();
} }
void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent, wxCoord *externalLeading, const wxFont *font) const void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string,
wxCoord* x,
wxCoord* y,
wxCoord* descent,
wxCoord* externalLeading,
const wxFont* theFont) const
{ {
wxScreenDC sDC; wxScreenDC sDC;
wxSetScaledScreenDCFont(sDC, font ? *font : m_font); SetScaledScreenDCFont(sDC, theFont ? *theFont : m_font);
sDC.GetTextExtent(string, w, h, descent, externalLeading); sDC.GetTextExtent(string, x, y, descent, externalLeading);
} }
wxCoord wxSVGFileDCImpl::GetCharHeight() const wxCoord wxSVGFileDCImpl::GetCharHeight() const
{ {
wxScreenDC sDC; wxScreenDC sDC;
wxSetScaledScreenDCFont(sDC, m_font); SetScaledScreenDCFont(sDC, m_font);
return sDC.GetCharHeight(); return sDC.GetCharHeight();
@@ -995,7 +1178,7 @@ wxCoord wxSVGFileDCImpl::GetCharHeight() const
wxCoord wxSVGFileDCImpl::GetCharWidth() const wxCoord wxSVGFileDCImpl::GetCharWidth() const
{ {
wxScreenDC sDC; wxScreenDC sDC;
wxSetScaledScreenDCFont(sDC, m_font); SetScaledScreenDCFont(sDC, m_font);
return sDC.GetCharWidth(); return sDC.GetCharWidth();
} }
@@ -1005,7 +1188,7 @@ wxCoord wxSVGFileDCImpl::GetCharWidth() const
// wxSVGFileDCImpl - set functions // wxSVGFileDCImpl - set functions
// ---------------------------------------------------------- // ----------------------------------------------------------
void wxSVGFileDCImpl::SetBackground(const wxBrush &brush) void wxSVGFileDCImpl::SetBackground(const wxBrush& brush)
{ {
m_backgroundBrush = brush; m_backgroundBrush = brush;
} }
@@ -1020,14 +1203,24 @@ void wxSVGFileDCImpl::SetBitmapHandler(wxSVGBitmapHandler* handler)
m_bmp_handler.reset(handler); m_bmp_handler.reset(handler);
} }
void wxSVGFileDCImpl::SetShapeRenderingMode(wxSVGShapeRenderingMode renderingMode)
{
m_renderingMode = renderingMode;
}
void wxSVGFileDCImpl::SetBrush(const wxBrush& brush) void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
{ {
m_brush = brush; m_brush = brush;
m_graphics_changed = true; m_graphics_changed = true;
wxString pattern = wxCreateBrushFill(m_brush); wxString pattern = CreateBrushFill(m_brush, m_renderingMode);
write(pattern); if ( !pattern.empty() )
{
NewGraphicsIfNeeded();
write(pattern);
}
} }
void wxSVGFileDCImpl::SetPen(const wxPen& pen) void wxSVGFileDCImpl::SetPen(const wxPen& pen)
@@ -1051,45 +1244,17 @@ void wxSVGFileDCImpl::NewGraphicsIfNeeded()
void wxSVGFileDCImpl::DoStartNewGraphics() void wxSVGFileDCImpl::DoStartNewGraphics()
{ {
wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast; wxString s;
sBrush = wxS("<g style=\"") + wxBrushString(m_brush.GetColour(), m_brush.GetStyle()) s = wxString::Format(wxS("<g style=\"%s %s %s\" transform=\"translate(%s %s) scale(%s %s)\">\n"),
+ wxPenString(m_pen.GetColour(), m_pen.GetStyle()); GetPenStyle(m_pen),
GetBrushFill(m_brush.GetColour(), m_brush.GetStyle()),
GetPenStroke(m_pen.GetColour(), m_pen.GetStyle()),
NumStr((m_deviceOriginX - m_logicalOriginX) * m_signX),
NumStr((m_deviceOriginY - m_logicalOriginY) * m_signY),
NumStr(m_scaleX * m_signX),
NumStr(m_scaleY * m_signY));
switch ( m_pen.GetCap() )
{
case wxCAP_PROJECTING:
sPenCap = wxS("stroke-linecap:square; ");
break;
case wxCAP_BUTT:
sPenCap = wxS("stroke-linecap:butt; ");
break;
case wxCAP_ROUND:
default:
sPenCap = wxS("stroke-linecap:round; ");
}
switch (m_pen.GetJoin())
{
case wxJOIN_BEVEL:
sPenJoin = wxS("stroke-linejoin:bevel; ");
break;
case wxJOIN_MITER:
sPenJoin = wxS("stroke-linejoin:miter; ");
break;
case wxJOIN_ROUND:
default:
sPenJoin = wxS("stroke-linejoin:round; ");
}
sLast = wxString::Format(wxS("stroke-width:%d\" transform=\"translate(%s %s) scale(%s %s)\">"),
m_pen.GetWidth(),
NumStr((m_deviceOriginX - m_logicalOriginX)* m_signX),
NumStr((m_deviceOriginY - m_logicalOriginY)* m_signY),
NumStr(m_scaleX * m_signX),
NumStr(m_scaleY * m_signY));
s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxS("\n");
write(s); write(s);
} }
@@ -1098,13 +1263,15 @@ void wxSVGFileDCImpl::SetFont(const wxFont& font)
m_font = font; m_font = font;
} }
// export a bitmap as a raster image in png bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest,
bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxCoord width, wxCoord height,
wxDC* source, wxCoord xsrc, wxCoord ysrc, wxDC* source,
wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/, wxCoord xsrc, wxCoord ysrc,
wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/) wxRasterOperationMode rop,
bool useMask,
wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask))
{ {
if (logicalFunc != wxCOPY) if (rop != wxCOPY)
{ {
wxASSERT_MSG(false, wxS("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible")); wxASSERT_MSG(false, wxS("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
return false; return false;
@@ -1123,17 +1290,18 @@ bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoor
return false; return false;
} }
void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y) void wxSVGFileDCImpl::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
{ {
wxBitmap myBitmap(myIcon.GetWidth(), myIcon.GetHeight()); wxBitmap myBitmap(icon.GetWidth(), icon.GetHeight());
wxMemoryDC memDC; wxMemoryDC memDC;
memDC.SelectObject(myBitmap); memDC.SelectObject(myBitmap);
memDC.DrawIcon(myIcon, 0, 0); memDC.DrawIcon(icon, 0, 0);
memDC.SelectObject(wxNullBitmap); memDC.SelectObject(wxNullBitmap);
DoDrawBitmap(myBitmap, x, y); DoDrawBitmap(myBitmap, x, y);
} }
void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y, bool WXUNUSED(bTransparent) /*=0*/) void wxSVGFileDCImpl::DoDrawBitmap(const wxBitmap& bmp, wxCoord x, wxCoord y,
bool WXUNUSED(useMask))
{ {
NewGraphicsIfNeeded(); NewGraphicsIfNeeded();
@@ -1141,16 +1309,22 @@ void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoor
if ( !m_bmp_handler ) if ( !m_bmp_handler )
m_bmp_handler.reset(new wxSVGBitmapFileHandler(m_filename)); m_bmp_handler.reset(new wxSVGBitmapFileHandler(m_filename));
m_bmp_handler->ProcessBitmap(bmp, x, y, *m_outfile); m_OK = m_outfile && m_outfile->IsOk();
}
void wxSVGFileDCImpl::write(const wxString &s)
{
m_OK = m_outfile->IsOk();
if (!m_OK) if (!m_OK)
return; return;
m_bmp_handler->ProcessBitmap(bmp, x, y, *m_outfile);
m_OK = m_outfile->IsOk();
}
void wxSVGFileDCImpl::write(const wxString& s)
{
m_OK = m_outfile && m_outfile->IsOk();
if (!m_OK)
return;
const wxCharBuffer buf = s.utf8_str(); const wxCharBuffer buf = s.utf8_str();
m_outfile->Write(buf, strlen((const char *)buf)); m_outfile->Write(buf, strlen((const char*)buf));
m_OK = m_outfile->IsOk(); m_OK = m_outfile->IsOk();
} }