]> git.saurik.com Git - wxWidgets.git/commitdiff
Implement clipping in wxSVGFileDC.
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 24 Oct 2012 23:40:41 +0000 (23:40 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 24 Oct 2012 23:40:41 +0000 (23:40 +0000)
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

docs/changes.txt
include/wx/dcsvg.h
interface/wx/dcsvg.h
samples/svg/svgtest.cpp
src/common/dcsvg.cpp

index 812427cf1a0cc1ae267eae81e38d8264d9b7d87f..88dbc74e335563450c7da3cf987d18d78f2e8b59 100644 (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:
 
index dc541ae799f30304aee316772dbeeabe82f034fd..d1b26c1e202e594c57f665824cb1688c6021e1b2 100644 (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)
 };
 
index 5138aead6b169b9d57fae915ef50c0efdc04aa3b..d0a593b46b4123383678b342bcd17cb4d23b2a6b 100644 (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);
     //@}
index ba6561bd06fdd2493545ba2f87f22387f8b97862..bcd3339105e46434f9523c89913141a2c1bb0c2b 100644 (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);
index dcba36482771392140b8bcfa7049cee640bac7e7..85105f91f292f4bbb56c8e596073368228b5970a 100644 (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() )