Implement clipping in wxSVGFileDC.

Support setting the clipping region and add update the documentation and the
sample accordingly.

Closes #14462.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72762 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2012-10-24 23:40:41 +00:00
parent c84c7347ba
commit 614e38dbb2
5 changed files with 179 additions and 18 deletions

View File

@@ -579,6 +579,7 @@ All (GUI):
- Add missing styles support to wxWindow XRC hanlder (Steffen Olszewski).
- Allow specifying all wxFlexGridSizer parameters in XRC (Steffen Olszewski).
- Close wxLogWindow automatically if it's the last remaining top level window.
- Implement clipping for wxSVGFileDC (Steve Benbow).
wxGTK:

View File

@@ -54,10 +54,7 @@ public:
wxFAIL_MSG(wxT("wxSVGFILEDC::Clear() Call not implemented \nNot sensible for an output file?"));
}
virtual void DestroyClippingRegion()
{
wxFAIL_MSG(wxT("wxSVGFILEDC::void Call not yet implemented"));
}
virtual void DestroyClippingRegion();
virtual wxCoord GetCharHeight() const;
virtual wxCoord GetCharWidth() const;
@@ -175,10 +172,7 @@ private:
wxFAIL_MSG(wxT("wxSVGFILEDC::DoSetDeviceClippingRegion not yet implemented"));
}
virtual void DoSetClippingRegion( int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
{
wxFAIL_MSG(wxT("wxSVGFILEDC::DoSetClippingRegion not yet implemented"));
}
virtual void DoSetClippingRegion(int x, int y, int width, int height);
virtual void DoGetSizeMM( int *width, int *height ) const;
@@ -193,6 +187,10 @@ private:
// new one for the last pen/brush change.
void NewGraphicsIfNeeded();
// Open a new graphics group setting up all the attributes according to
// their current values in wxDC.
void DoStartNewGraphics();
wxFileOutputStream *m_outfile;
wxString m_filename;
int m_sub_images; // number of png format images we have
@@ -201,7 +199,14 @@ private:
int m_width, m_height;
double m_dpi;
private:
// The clipping nesting level is incremented by every call to
// SetClippingRegion() and reset when DestroyClippingRegion() is called.
size_t m_clipNestingLevel;
// Unique ID for every clipping graphics group: this is simply always
// incremented in each SetClippingRegion() call.
size_t m_clipUniqueId;
DECLARE_ABSTRACT_CLASS(wxSVGFileDCImpl)
};

View File

@@ -67,21 +67,52 @@ public:
*/
void SetLogicalFunction(wxRasterOperationMode function);
/**
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
set clipping region.
Clipping is implemented in the SVG output using SVG group elements (<g>), with
nested group elements being used to represent clipping region intersections when
two or more calls are made to SetClippingRegion().
*/
void SetClippingRegion(wxCoord x, wxCoord y, wxCoord width,
wxCoord height);
/**
This is an overloaded member function, provided for convenience. It differs from the
above function only in what argument(s) it accepts.
*/
void SetClippingRegion(const wxPoint& pt, const wxSize& sz);
/**
This is an overloaded member function, provided for convenience. It differs from the
above function only in what argument(s) it accepts.
*/
void SetClippingRegion(const wxRect& rect);
/**
This function is not implemented in this DC class.
It could be implemented in future if a GetPoints() function were made available on wxRegion.
*/
void SetClippingRegion(const wxRegion& region);
/**
Destroys the current clipping region so that none of the DC is clipped.
Since intersections arising from sequential calls to SetClippingRegion are represented
with nested SVG group elements (<g>), all such groups are closed when
DestroyClippingRegion is called.
*/
void DestroyClippingRegion();
//@{
/**
Functions not implemented in this DC class.
*/
void CrossHair(wxCoord x, wxCoord y);
void DestroyClippingRegion();
bool FloodFill(wxCoord x, wxCoord y, const wxColour& colour,
wxFloodFillStyle style = wxFLOOD_SURFACE);
void GetClippingBox(wxCoord *x, wxCoord *y, wxCoord *width, wxCoord *height) const;
bool GetPixel(wxCoord x, wxCoord y, wxColour* colour) const;
void SetClippingRegion(wxCoord x, wxCoord y, wxCoord width,
wxCoord height);
void SetClippingRegion(const wxPoint& pt, const wxSize& sz);
void SetClippingRegion(const wxRect& rect);
void SetClippingRegion(const wxRegion& region);
void SetPalette(const wxPalette& palette);
bool StartDoc(const wxString& message);
//@}

View File

@@ -323,7 +323,7 @@ MyCanvas::MyCanvas(MyChild *parent, const wxPoint& pos, const wxSize& size)
SetBackgroundColour(wxColour(wxT("WHITE")));
m_child = parent;
m_index = m_child->GetFrame()->GetCountOfChildren() % 8;
m_index = m_child->GetFrame()->GetCountOfChildren() % 9;
}
// Define the repainting behaviour
@@ -496,6 +496,68 @@ void MyCanvas::OnDraw(wxDC& dc)
break;
case 7:
dc.SetTextForeground(wxT("RED"));
dc.DrawText(wxT("Red = Clipping Off"), 30, 5);
dc.SetTextForeground(wxT("GREEN"));
dc.DrawText(wxT("Green = Clipping On"), 30, 25);
dc.SetTextForeground(wxT("BLACK"));
dc.SetPen(*wxRED_PEN);
dc.SetBrush (wxBrush (wxT("SALMON"),wxBRUSHSTYLE_TRANSPARENT));
dc.DrawCheckMark ( 80,50,75,75);
dc.DrawRectangle ( 80,50,75,75);
dc.SetPen(*wxGREEN_PEN);
// Clipped checkmarks
dc.DrawRectangle(180,50,75,75);
dc.SetClippingRegion(180,50,75,75); // x,y,width,height version
dc.DrawCheckMark ( 180,50,75,75);
dc.DestroyClippingRegion();
dc.DrawRectangle(wxRect(80,150,75,75));
dc.SetClippingRegion(wxPoint(80,150),wxSize(75,75)); // pt,size version
dc.DrawCheckMark ( 80,150,75,75);
dc.DestroyClippingRegion();
dc.DrawRectangle(wxRect(180,150,75,75));
dc.SetClippingRegion(wxRect(180,150,75,75)); // rect version
dc.DrawCheckMark ( 180,150,75,75);
dc.DestroyClippingRegion();
dc.DrawRectangle(wxRect( 80,250,50,65));
dc.DrawRectangle(wxRect(105,260,50,65));
dc.SetClippingRegion(wxRect( 80,250,50,65)); // second call to SetClippingRegion
dc.SetClippingRegion(wxRect(105,260,50,65)); // forms intersection with previous
dc.DrawCheckMark(80,250,75,75);
dc.DestroyClippingRegion(); // only one call to destroy (there's no stack)
/*
** Clipping by wxRegion not implemented for SVG. Should be
** possible, but need to access points that define the wxRegion
** from inside DoSetDeviceClippingRegion() and wxRegion does not
** implement anything like getPoints().
points[0].x = 180; points[0].y = 250;
points[1].x = 255; points[1].y = 250;
points[2].x = 180; points[2].y = 325;
points[3].x = 255; points[3].y = 325;
points[4].x = 180; points[4].y = 250;
dc.DrawLines (5, points);
wxRegion reg = wxRegion(5,points);
dc.SetClippingRegion(reg);
dc.DrawCheckMark ( 180,250,75,75);
dc.DestroyClippingRegion();
*/
#if wxUSE_STATUSBAR
s = wxT("Clipping region");
#endif // wxUSE_STATUSBAR
break;
case 8:
wxString txtStr;
wxCoord txtX, txtY, txtW, txtH, txtDescent, txtEL;
wxCoord txtPad = 0;
@@ -538,7 +600,6 @@ void MyCanvas::OnDraw(wxDC& dc)
s = wxT("Text position test page");
#endif // wxUSE_STATUSBAR
break;
}
#if wxUSE_STATUSBAR
m_child->SetStatusText(s);

View File

@@ -130,6 +130,9 @@ void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, dou
m_OK = true;
m_clipUniqueId = 0;
m_clipNestingLevel = 0;
m_mm_to_pix_x = dpi/25.4;
m_mm_to_pix_y = dpi/25.4;
@@ -470,6 +473,59 @@ void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,
}
}
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();
m_clipUniqueId = 0;
}
void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
{
@@ -538,9 +594,16 @@ void wxSVGFileDCImpl::NewGraphicsIfNeeded()
m_graphics_changed = false;
write(wxS("</g>\n"));
DoStartNewGraphics();
}
void wxSVGFileDCImpl::DoStartNewGraphics()
{
wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast;
sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
sBrush = wxS("<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
+ wxPenString(m_pen.GetColour(), m_pen.GetStyle());
switch ( m_pen.GetCap() )