[ooo-build-commit] patches/test

Thorsten Behrens thorsten at kemper.freedesktop.org
Wed Sep 30 13:29:38 PDT 2009


 patches/test/clipstate.diff    |  805 +++++++++++++++++++++++++++++++++--------
 patches/test/wmf-clipperf.diff |  439 ++++++++++++++++++++++
 2 files changed, 1105 insertions(+), 139 deletions(-)

New commits:
commit 49fb422bcf33f80c89a7b800009e17dcd4941aec
Author: Thorsten Behrens <tbehrens at novell.com>
Date:   Wed Sep 30 22:23:00 2009 +0200

    Updated B2DClipState; made us of it in wmf import
    
    * patches/test/clipstate.diff:
    * patches/test/wmf-clipperf.diff:

diff --git a/patches/test/clipstate.diff b/patches/test/clipstate.diff
index e1dd123..08c2ad9 100644
--- a/patches/test/clipstate.diff
+++ b/patches/test/clipstate.diff
@@ -5,29 +5,50 @@ From: Thorsten Behrens <thb at openoffice.org>
 
 ---
 
- basegfx/inc/basegfx/tools/b2dclipstate.hxx |  111 +++++++
- basegfx/prj/d.lst                          |    2 
+ basegfx/inc/basegfx/range/b2dpolyrange.hxx |    6 
+ basegfx/inc/basegfx/tools/b2dclipstate.hxx |  119 +++++
+ basegfx/prj/d.lst                          |    3 
  basegfx/qa/mkpolygons.pl                   |    0 
- basegfx/source/tools/b2dclipstate.cxx      |  431 ++++++++++++++++++++++++++++
+ basegfx/source/range/b2dpolyrange.cxx      |   40 ++
+ basegfx/source/tools/b2dclipstate.cxx      |  662 ++++++++++++++++++++++++++++
  basegfx/source/tools/makefile.mk           |    3 
  basegfx/test/basegfx2d.cxx                 |    6 
- basegfx/test/genericclipper.cxx            |  168 +++++++++++
- basegfx/test/makefile.mk                   |    1 
- slideshow/source/engine/slide/layer.cxx    |   11 -
+ basegfx/test/clipstate.cxx                 |  187 ++++++++
+ basegfx/test/genericclipper.cxx            |  168 +++++++
+ basegfx/test/makefile.mk                   |    8 
+ slideshow/source/engine/slide/layer.cxx    |   11 
  slideshow/source/engine/slide/layer.hxx    |    6 
- 10 files changed, 729 insertions(+), 10 deletions(-)
+ 13 files changed, 1206 insertions(+), 13 deletions(-)
  create mode 100644 basegfx/inc/basegfx/tools/b2dclipstate.hxx
  mode change 100644 => 100755 basegfx/qa/mkpolygons.pl
  create mode 100644 basegfx/source/tools/b2dclipstate.cxx
+ create mode 100644 basegfx/test/clipstate.cxx
  create mode 100644 basegfx/test/genericclipper.cxx
 
 
+diff --git basegfx/inc/basegfx/range/b2dpolyrange.hxx basegfx/inc/basegfx/range/b2dpolyrange.hxx
+index 0c07dc2..ad53552 100644
+--- basegfx/inc/basegfx/range/b2dpolyrange.hxx
++++ basegfx/inc/basegfx/range/b2dpolyrange.hxx
+@@ -131,6 +131,12 @@ namespace basegfx
+          */
+         B2DPolyPolygon solveCrossovers() const;
+ 
++        // element iterators
++        const B2DRange* begin() const;
++        const B2DRange* end() const;
++        B2DRange* begin();
++        B2DRange* end();
++
+     private:
+         o3tl::cow_wrapper< ImplB2DPolyRange > mpImpl;
+     };
 diff --git basegfx/inc/basegfx/tools/b2dclipstate.hxx basegfx/inc/basegfx/tools/b2dclipstate.hxx
 new file mode 100644
-index 0000000..4ea041b
+index 0000000..92b1578
 --- /dev/null
 +++ basegfx/inc/basegfx/tools/b2dclipstate.hxx
-@@ -0,0 +1,111 @@
+@@ -0,0 +1,119 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -96,6 +117,7 @@ index 0000000..4ea041b
 +            ImplType mpImpl;
 +
 +        public:
++            /// Init clip, in 'cleared' state - everything is visible
 +            B2DClipState();
 +            ~B2DClipState();
 +            B2DClipState( const B2DClipState& );
@@ -107,7 +129,15 @@ index 0000000..4ea041b
 +            /// unshare this poly-range with all internally shared instances
 +            void makeUnique();
 +            
-+            void clear();
++            /// Set clip to 'null' - nothing is visible
++            void makeNull();
++            /// returns true when clip is 'null' - nothing is visible
++            bool isNull() const;
++
++            /// Set clip 'cleared' - everything is visible
++            void makeClear();
++            /// returns true when clip is 'cleared' - everything is visible
++            bool isCleared() const;
 +
 +            bool operator==(const B2DClipState&) const;
 +            bool operator!=(const B2DClipState&) const;
@@ -133,14 +163,13 @@ index 0000000..4ea041b
 +            void xorClipState(const B2DClipState& );
 +
 +            B2DPolyPolygon getClipPoly() const;
-+            B2DPolyRange   getClipRanges() const;
 +        };
 +    }
 +}
 +
 +#endif // _BGFX_TOOLS_CLIPSTATE_HXX
 diff --git basegfx/prj/d.lst basegfx/prj/d.lst
-index 9dd6085..b9d3a10 100644
+index 9dd6085..9c54511 100644
 --- basegfx/prj/d.lst
 +++ basegfx/prj/d.lst
 @@ -27,7 +27,7 @@ mkdir: %_DEST%\inc%_EXT%\basegfx\range
@@ -152,15 +181,81 @@ index 9dd6085..b9d3a10 100644
  ..\inc\basegfx\range\b2drange.hxx %_DEST%\inc%_EXT%\basegfx\range\b2drange.hxx
  ..\inc\basegfx\range\b2drectangle.hxx %_DEST%\inc%_EXT%\basegfx\range\b2drectangle.hxx
  ..\inc\basegfx\range\b2dconnectedranges.hxx %_DEST%\inc%_EXT%\basegfx\range\b2dconnectedranges.hxx
+@@ -90,6 +90,7 @@ mkdir: %_DEST%\inc%_EXT%\basegfx\tuple
+ mkdir: %_DEST%\inc%_EXT%\basegfx\tools
+ ..\inc\basegfx\tools\canvastools.hxx %_DEST%\inc%_EXT%\basegfx\tools\canvastools.hxx
+ ..\inc\basegfx\tools\unopolypolygon.hxx %_DEST%\inc%_EXT%\basegfx\tools\unopolypolygon.hxx
++..\inc\basegfx\tools\b2dclipstate.hxx %_DEST%\inc%_EXT%\basegfx\tools\b2dclipstate.hxx
+ ..\inc\basegfx\tools\rectcliptools.hxx %_DEST%\inc%_EXT%\basegfx\tools\rectcliptools.hxx
+ ..\inc\basegfx\tools\tools.hxx %_DEST%\inc%_EXT%\basegfx\tools\tools.hxx
+ ..\inc\basegfx\tools\gradienttools.hxx %_DEST%\inc%_EXT%\basegfx\tools\gradienttools.hxx
 diff --git basegfx/qa/mkpolygons.pl basegfx/qa/mkpolygons.pl
 old mode 100644
 new mode 100755
+diff --git basegfx/source/range/b2dpolyrange.cxx basegfx/source/range/b2dpolyrange.cxx
+index ae94f14..a69cd5b 100644
+--- basegfx/source/range/b2dpolyrange.cxx
++++ basegfx/source/range/b2dpolyrange.cxx
+@@ -227,6 +227,26 @@ namespace basegfx
+             return tools::solveCrossovers(maRanges,maOrient);
+         }
+ 
++        const B2DRange* begin() const
++        {
++            return &maRanges.front();
++        }
++
++        const B2DRange* end() const
++        {
++            return &maRanges[maRanges.size()];
++        }
++
++        B2DRange* begin()
++        {
++            return &maRanges.front();
++        }
++
++        B2DRange* end()
++        {
++            return &maRanges[maRanges.size()];
++        }
++
+     private:
+         B2DRange						 maBounds;
+         std::vector<B2DRange>			 maRanges;
+@@ -366,6 +386,26 @@ namespace basegfx
+         return mpImpl->solveCrossovers();
+     }
+ 
++    const B2DRange* B2DPolyRange::begin() const
++    {
++        return mpImpl->begin();
++    }
++
++    const B2DRange* B2DPolyRange::end() const
++    {
++        return mpImpl->end();
++    }
++
++    B2DRange* B2DPolyRange::begin()
++    {
++        return mpImpl->begin();
++    }
++
++    B2DRange* B2DPolyRange::end()
++    {
++        return mpImpl->end();
++    }
++
+ } // end of namespace basegfx
+ 
+ // eof
 diff --git basegfx/source/tools/b2dclipstate.cxx basegfx/source/tools/b2dclipstate.cxx
 new file mode 100644
-index 0000000..76e2aaf
+index 0000000..f203d4f
 --- /dev/null
 +++ basegfx/source/tools/b2dclipstate.cxx
-@@ -0,0 +1,431 @@
+@@ -0,0 +1,662 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -197,6 +292,7 @@ index 0000000..76e2aaf
 +
 +#include <basegfx/range/b2drange.hxx>
 +#include <basegfx/range/b2dpolyrange.hxx>
++#include <basegfx/range/b2drangeclipper.hxx>
 +#include <basegfx/polygon/b2dpolygon.hxx>
 +#include <basegfx/polygon/b2dpolygontools.hxx>
 +#include <basegfx/polygon/b2dpolypolygon.hxx>
@@ -210,238 +306,458 @@ index 0000000..76e2aaf
 +    struct ImplB2DClipState
 +    {
 +    public:
-+        enum Operation {UNION, INTERSECT, XOR};
++        enum Operation {UNION, INTERSECT, XOR, SUBTRACT};
 +
 +        ImplB2DClipState() :
-+            maPending(),
++            maPendingPolygons(),
++            maPendingRanges(),
 +            maClipPoly(),
 +            mePendingOps(UNION)
 +        {}
 +
 +        explicit ImplB2DClipState( const B2DRange& rRange ) :
-+            maPending(),
++            maPendingPolygons(),
++            maPendingRanges(),
 +            maClipPoly(
 +                tools::createPolygonFromRect(rRange)),
 +            mePendingOps(UNION)
 +        {}
 +
 +        explicit ImplB2DClipState( const B2DPolygon& rPoly ) :
-+            maPending(),
++            maPendingPolygons(),
++            maPendingRanges(),
 +            maClipPoly(rPoly),
 +            mePendingOps(UNION)
 +        {}
 +
 +        explicit ImplB2DClipState( const B2DPolyPolygon& rPoly ) :
-+            maPending(),
++            maPendingPolygons(),
++            maPendingRanges(),
 +            maClipPoly(rPoly),
 +            mePendingOps(UNION)
 +        {}
 +
-+        void clear()
++        bool isCleared() const
++        {
++            return !maClipPoly.count()
++                && !maPendingPolygons.count() 
++                && !maPendingRanges.count();
++        }
++
++        void makeClear()
++        {
++            maPendingPolygons.clear();
++            maPendingRanges.clear();
++            maClipPoly.clear();
++            mePendingOps = UNION;
++        }
++
++        bool isNullClipPoly() const
++        {
++            return maClipPoly.count() == 1
++                && !maClipPoly.getB2DPolygon(0).count();
++        }
++
++        bool isNull() const
++        {
++            return !maPendingPolygons.count() 
++                && !maPendingRanges.count()
++                && isNullClipPoly();
++        }
++
++        void makeNull()
 +        {
-+            maPending.clear();
++            maPendingPolygons.clear();
++            maPendingRanges.clear();
 +            maClipPoly.clear();
++            maClipPoly.append(B2DPolygon());
 +            mePendingOps = UNION;
 +        }
 +
 +        bool operator==(const ImplB2DClipState& rRHS) const
 +        {
-+            return maPending == rRHS.maPending 
++            return maPendingPolygons == rRHS.maPendingPolygons 
++                && maPendingRanges == rRHS.maPendingRanges
 +                && maClipPoly == rRHS.maClipPoly 
 +                && mePendingOps == rRHS.mePendingOps;
 +        }
 +
-+        void unionRange(const B2DRange& rRange)
++        void addRange(const B2DRange& rRange, Operation eOp)
 +        {
 +            if( rRange.isEmpty() )
 +                return;
 +
-+            if( maPending.count() && mePendingOps != UNION )
-+                commitToPolygon();
++            commitPendingPolygons();
++            if( mePendingOps != eOp )
++                commitPendingRanges();
 +
-+            mePendingOps = UNION;
-+            maPending.append(
-+                tools::createPolygonFromRect(rRange));
++            mePendingOps = eOp;
++            maPendingRanges.appendElement(
++                rRange,
++                ORIENTATION_POSITIVE);
++        }
++
++        void addPolygon(B2DPolygon aPoly, Operation eOp)
++        {
++            commitPendingRanges();
++            if( mePendingOps != eOp )
++                commitPendingPolygons();
++
++            mePendingOps = eOp;
++            maPendingPolygons.append(aPoly);
++        }
++
++        void addPolyPolygon(B2DPolyPolygon aPoly, Operation eOp)
++        {
++            commitPendingRanges();
++            if( mePendingOps != eOp )
++                commitPendingPolygons();
++
++            mePendingOps = eOp;
++            maPendingPolygons.append(aPoly);
++        }
++
++        void addClipState(const ImplB2DClipState& rOther, Operation eOp)
++        {
++            if( rOther.mePendingOps == mePendingOps
++                && !rOther.maClipPoly.count()
++                && !rOther.maPendingPolygons.count() )
++            {
++                maPendingRanges.appendPolyRange( rOther.maPendingRanges );
++            }
++            else
++            {
++                commitPendingRanges();
++                commitPendingPolygons();
++                rOther.commitPendingRanges();
++                rOther.commitPendingPolygons();
++
++                maPendingPolygons = rOther.maClipPoly;
++                mePendingOps = eOp;
++            }
++        }
++
++        void unionRange(const B2DRange& rRange)
++        {
++            if( isCleared() )
++                return;
++
++            addRange(rRange,UNION);
 +        }
 +
 +        void unionPolygon(const B2DPolygon& rPoly)
 +        {
-+            if( maPending.count() && mePendingOps != UNION )
-+                commitToPolygon();
++            if( isCleared() )
++                return;
 +
-+            mePendingOps = UNION;
-+            maPending.append(
-+                tools::prepareForPolygonOperation(rPoly));
++            addPolygon(rPoly,UNION);
 +        }
 +
 +        void unionPolyPolygon(const B2DPolyPolygon& rPolyPoly)
 +        {
-+            if( maPending.count() && mePendingOps != UNION )
-+                commitToPolygon();
++            if( isCleared() )
++                return;
 +
-+            mePendingOps = UNION;
-+            maPending.append(
-+                tools::prepareForPolygonOperation(rPolyPoly));
++            addPolyPolygon(rPolyPoly,UNION);
 +        }
 +
-+        void unionClipState(const B2DClipState&)
-+        {}
++        void unionClipState(const ImplB2DClipState& rOther)
++        {
++            if( isCleared() )
++                return;
++            
++            addClipState(rOther, UNION);
++        }
 +        
 +        void intersectRange(const B2DRange& rRange)
 +        {
-+            if( rRange.isEmpty() )
++            if( isNull() )
 +                return;
 +
-+            if( maPending.count() && mePendingOps != INTERSECT )
-+                commitToPolygon();
-+
-+            mePendingOps = INTERSECT;
-+            maPending.append(
-+                tools::createPolygonFromRect(rRange));
++            addRange(rRange,INTERSECT);
 +        }
 +
 +        void intersectPolygon(const B2DPolygon& rPoly)
 +        {
-+            if( maPending.count() && mePendingOps != INTERSECT )
-+                commitToPolygon();
++            if( isNull() )
++                return;
 +
-+            mePendingOps = INTERSECT;
-+            maPending.append(rPoly);
++            addPolygon(rPoly,INTERSECT);
 +        }
 +
 +        void intersectPolyPolygon(const B2DPolyPolygon& rPolyPoly)
 +        {
-+            if( maPending.count() && mePendingOps != INTERSECT )
-+                commitToPolygon();
++            if( isNull() )
++                return;
 +
-+            mePendingOps = INTERSECT;
-+            maPending.append(rPolyPoly);
++            addPolyPolygon(rPolyPoly,INTERSECT);
 +        }
 +
-+        void intersectClipState(const tools::B2DClipState& )
-+        {}
++        void intersectClipState(const ImplB2DClipState& rOther)
++        {
++            if( isNull() )
++                return;
++            
++            addClipState(rOther, INTERSECT);
++        }
 +        
 +        void subtractRange(const B2DRange& rRange )
 +        {
-+            if( rRange.isEmpty() )
++            if( isNull() )
 +                return;
 +
-+            // how unfortunate. subtract is not associative, cannot
-+            // lump together
-+            commitToPolygon();
-+
-+            maClipPoly = tools::solvePolygonOperationDiff(
-+                maClipPoly,
-+                B2DPolyPolygon(
-+                    tools::createPolygonFromRect(rRange)));
++            addRange(rRange,SUBTRACT);
 +        }
 +
 +        void subtractPolygon(const B2DPolygon& rPoly)
 +        {
-+            // how unfortunate. subtract is not associative, cannot
-+            // lump together
-+            commitToPolygon();
++            if( isNull() )
++                return;
 +
-+            maClipPoly = tools::solvePolygonOperationDiff(
-+                maClipPoly, 
-+                prepareForPolygonOperation(rPoly));
++            addPolygon(rPoly,SUBTRACT);
 +        }
 +
-+        void subtractPolyPolygon(const B2DPolyPolygon& rPoly)
++        void subtractPolyPolygon(const B2DPolyPolygon& rPolyPoly)
 +        {
-+            // how unfortunate. subtract is not associative, cannot
-+            // lump together
-+            commitToPolygon();
++            if( isNull() )
++                return;
 +
-+            maClipPoly = tools::solvePolygonOperationDiff(
-+                maClipPoly, 
-+                prepareForPolygonOperation(rPoly));
++            addPolyPolygon(rPolyPoly,SUBTRACT);
 +        }
 +        
-+        void subtractClipState(const B2DClipState& )
-+        {}
-+        
-+        void xorRange(const B2DRange& rRange)
++        void subtractClipState(const ImplB2DClipState& rOther)
 +        {
-+            if( rRange.isEmpty() )
++            if( isNull() )
 +                return;
 +
-+            if( maPending.count() && mePendingOps != XOR )
-+                commitToPolygon();
-+
-+            mePendingOps = XOR;
-+            maPending.append(
-+                tools::createPolygonFromRect(rRange));
++            addClipState(rOther, SUBTRACT);
++        }
++        
++        void xorRange(const B2DRange& rRange)
++        {
++            addRange(rRange,XOR);
 +        }
 +
 +        void xorPolygon(const B2DPolygon& rPoly)
 +        {
-+            if( maPending.count() && mePendingOps != XOR )
-+                commitToPolygon();
-+
-+            mePendingOps = XOR;
-+            maPending.append(rPoly);
++            addPolygon(rPoly,XOR);
 +        }
 +
 +        void xorPolyPolygon(const B2DPolyPolygon& rPolyPoly)
 +        {
-+            if( maPending.count() && mePendingOps != XOR )
-+                commitToPolygon();
-+
-+            mePendingOps = XOR;
-+            maPending.append(rPolyPoly);
++            addPolyPolygon(rPolyPoly,XOR);
 +        }
 +
-+        void xorClipState(const B2DClipState& )
-+        {}
++        void xorClipState(const ImplB2DClipState& rOther)
++        {
++            addClipState(rOther, XOR);
++        }
 +        
 +        B2DPolyPolygon getClipPoly() const
 +        {
-+            commitToPolygon();
-+            return maClipPoly;
-+        }
++            commitPendingRanges();
++            commitPendingPolygons();
 +
-+        B2DPolyRange getClipRanges() const
-+        {
-+            return B2DPolyRange();
++            return maClipPoly;
 +        }
 +
 +    private:
-+        void commitToPolygon() const
++        void commitPendingPolygons() const
 +        {
-+            if( !maPending.count() )
++            if( !maPendingPolygons.count() )
 +                return;
 +
 +            // assumption: maClipPoly has kept polygons prepared for
 +            // clipping; i.e. no neutral polygons & correct
 +            // orientation
-+            maPending = tools::prepareForPolygonOperation(maPending);
++            maPendingPolygons = tools::prepareForPolygonOperation(maPendingPolygons);
++            const bool bIsEmpty=isNullClipPoly();
++            const bool bIsCleared=!maClipPoly.count();
 +            switch(mePendingOps)
 +            {
 +                case UNION:
-+                    maClipPoly = tools::solvePolygonOperationOr(
-+                        maClipPoly,
-+                        maPending);
++                    OSL_ASSERT( !bIsCleared );
++
++                    if( bIsEmpty )
++                        maClipPoly = maPendingPolygons;
++                    else
++                        maClipPoly = tools::solvePolygonOperationOr(
++                            maClipPoly,
++                            maPendingPolygons);
 +                    break;
 +                case INTERSECT:
-+                    maClipPoly = tools::solvePolygonOperationAnd(
-+                        maClipPoly,
-+                        maPending);
++                    OSL_ASSERT( !bIsEmpty );
++
++                    if( bIsCleared )
++                        maClipPoly = maPendingPolygons;
++                    else
++                        maClipPoly = tools::solvePolygonOperationAnd(
++                            maClipPoly,
++                            maPendingPolygons);
 +                    break;
 +                case XOR:
-+                    maClipPoly = tools::solvePolygonOperationXor(
-+                        maClipPoly,
-+                        maPending);
++                    if( bIsEmpty )
++                        maClipPoly = maPendingPolygons;
++                    else if( bIsCleared )
++                    {
++                        // not representable, strictly speaking,
++                        // using polygons with the common even/odd
++                        // or nonzero winding number fill rule. If
++                        // we'd want to represent it, fill rule
++                        // would need to be "non-negative winding
++                        // number" (and we then would return
++                        // 'holes' here)
++
++                        // going for an ugly hack meanwhile
++                        maClipPoly = tools::solvePolygonOperationXor(
++                            B2DPolyPolygon(
++                                tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
++                            maPendingPolygons);
++                    }
++                    else
++                        maClipPoly = tools::solvePolygonOperationXor(
++                            maClipPoly,
++                            maPendingPolygons);
++                    break;
++                case SUBTRACT:
++                    OSL_ASSERT( !bIsEmpty );
++
++                    // first union all pending ones, subtract en bloc then
++                    maPendingPolygons = solveCrossovers(maPendingPolygons);
++                    maPendingPolygons = stripNeutralPolygons(maPendingPolygons);
++                    maPendingPolygons = stripDispensablePolygons(maPendingPolygons, false);
++                        
++                    if( bIsCleared )
++                    {
++                        // not representable, strictly speaking,
++                        // using polygons with the common even/odd
++                        // or nonzero winding number fill rule. If
++                        // we'd want to represent it, fill rule
++                        // would need to be "non-negative winding
++                        // number" (and we then would return
++                        // 'holes' here)
++
++                        // going for an ugly hack meanwhile
++                        maClipPoly = tools::solvePolygonOperationDiff(
++                            B2DPolyPolygon(
++                                tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
++                            maPendingPolygons);
++                    }
++                    else
++                        maClipPoly = tools::solvePolygonOperationDiff(
++                            maClipPoly,
++                            maPendingPolygons);
 +                    break;
-+                default:
-+                    OSL_ASSERT(false);
 +            }
 +
-+            maPending.clear();
++            maPendingPolygons.clear();
++            mePendingOps = UNION;
++        }
++
++        void commitPendingRanges() const
++        {
++            if( !maPendingRanges.count() )
++                return;
++
++            // use the specialized range clipper for the win
++            B2DPolyPolygon aCollectedRanges; 
++            const bool bIsEmpty=isNullClipPoly();
++            const bool bIsCleared=!maClipPoly.count();
++            switch(mePendingOps)
++            {
++                case UNION:
++                    OSL_ASSERT( !bIsCleared );
++
++                    aCollectedRanges = maPendingRanges.solveCrossovers();
++                    aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
++                    aCollectedRanges = stripDispensablePolygons(aCollectedRanges, false);
++                    if( bIsEmpty )
++                        maClipPoly = aCollectedRanges;
++                    else
++                        maClipPoly = tools::solvePolygonOperationOr(
++                            maClipPoly,
++                            aCollectedRanges);
++                    break;
++                case INTERSECT:
++                    OSL_ASSERT( !bIsEmpty );
++
++                    aCollectedRanges = maPendingRanges.solveCrossovers();
++                    aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
++                    if( maPendingRanges.count() > 1 )
++                        aCollectedRanges = stripDispensablePolygons(aCollectedRanges, true);
++
++                    if( bIsCleared )
++                        maClipPoly = aCollectedRanges;
++                    else
++                        maClipPoly = tools::solvePolygonOperationAnd(
++                            maClipPoly,
++                            aCollectedRanges);
++                    break;
++                case XOR:
++                    aCollectedRanges = maPendingRanges.solveCrossovers();
++                    aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
++                    aCollectedRanges = correctOrientations(aCollectedRanges);
++
++                    if( bIsEmpty )
++                        maClipPoly = aCollectedRanges;
++                    else if( bIsCleared )
++                    {
++                        // not representable, strictly speaking,
++                        // using polygons with the common even/odd
++                        // or nonzero winding number fill rule. If
++                        // we'd want to represent it, fill rule
++                        // would need to be "non-negative winding
++                        // number" (and we then would return
++                        // 'holes' here)
++
++                        // going for an ugly hack meanwhile
++                        maClipPoly = tools::solvePolygonOperationXor(
++                            B2DPolyPolygon(
++                                tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
++                            aCollectedRanges);
++                    }
++                    else
++                        maClipPoly = tools::solvePolygonOperationXor(
++                            maClipPoly,
++                            aCollectedRanges);
++                    break;
++                case SUBTRACT:
++                    OSL_ASSERT( !bIsEmpty );
++
++                    // first union all pending ranges, subtract en bloc then
++                    aCollectedRanges = maPendingRanges.solveCrossovers();
++                    aCollectedRanges = stripNeutralPolygons(aCollectedRanges);
++                    aCollectedRanges = stripDispensablePolygons(aCollectedRanges, false);
++                        
++                    if( bIsCleared )
++                    {
++                        // not representable, strictly speaking,
++                        // using polygons with the common even/odd
++                        // or nonzero winding number fill rule. If
++                        // we'd want to represent it, fill rule
++                        // would need to be "non-negative winding
++                        // number" (and we then would return
++                        // 'holes' here)
++
++                        // going for an ugly hack meanwhile
++                        maClipPoly = tools::solvePolygonOperationDiff(
++                            B2DPolyPolygon(
++                                tools::createPolygonFromRect(B2DRange(-1E20,-1E20,1E20,1E20))),
++                            aCollectedRanges);
++                    }
++                    else
++                        maClipPoly = tools::solvePolygonOperationDiff(
++                            maClipPoly,
++                            aCollectedRanges);
++                    break;
++            }
++
++            maPendingRanges.clear();
 +            mePendingOps = UNION;
 +        }
 +        
-+        mutable B2DPolyPolygon maPending;
++        mutable B2DPolyPolygon maPendingPolygons;
++        mutable B2DPolyRange   maPendingRanges;
 +        mutable B2DPolyPolygon maClipPoly;
 +        mutable Operation      mePendingOps;
 +    };
@@ -480,9 +796,24 @@ index 0000000..76e2aaf
 +        mpImpl.make_unique();
 +    }
 +    
-+    void B2DClipState::clear()
++    void B2DClipState::makeNull()
++    {
++        mpImpl->makeNull();
++    }
++
++    bool B2DClipState::isNull() const
++    {
++        return mpImpl->isNull();
++    }
++
++    void B2DClipState::makeClear()
++    {
++        mpImpl->makeClear();
++    }
++
++    bool B2DClipState::isCleared() const
 +    {
-+        mpImpl->clear();
++        return mpImpl->isCleared();
 +    }
 +
 +    bool B2DClipState::operator==(const B2DClipState& rRHS) const
@@ -515,7 +846,7 @@ index 0000000..76e2aaf
 +
 +    void B2DClipState::unionClipState(const B2DClipState& rState)
 +    {
-+        mpImpl->unionClipState(rState);
++        mpImpl->unionClipState(*rState.mpImpl);
 +    }
 +
 +    void B2DClipState::intersectRange(const B2DRange& rRange)
@@ -535,7 +866,7 @@ index 0000000..76e2aaf
 +
 +    void B2DClipState::intersectClipState(const B2DClipState& rState)
 +    {
-+        mpImpl->intersectClipState(rState);
++        mpImpl->intersectClipState(*rState.mpImpl);
 +    }
 +
 +    void B2DClipState::subtractRange(const B2DRange& rRange)
@@ -555,7 +886,7 @@ index 0000000..76e2aaf
 +
 +    void B2DClipState::subtractClipState(const B2DClipState& rState)
 +    {
-+        mpImpl->subtractClipState(rState);
++        mpImpl->subtractClipState(*rState.mpImpl);
 +    }
 +    
 +    void B2DClipState::xorRange(const B2DRange& rRange)
@@ -575,7 +906,7 @@ index 0000000..76e2aaf
 +
 +    void B2DClipState::xorClipState(const B2DClipState& rState)
 +    {
-+        mpImpl->xorClipState(rState);
++        mpImpl->xorClipState(*rState.mpImpl);
 +    }
 +
 +    B2DPolyPolygon B2DClipState::getClipPoly() const
@@ -583,11 +914,6 @@ index 0000000..76e2aaf
 +        return mpImpl->getClipPoly();
 +    }
 +
-+    B2DPolyRange B2DClipState::getClipRanges() const
-+    {
-+        return mpImpl->getClipRanges();
-+    }
-+
 +} // end of namespace tools
 +} // end of namespace basegfx
 +
@@ -623,6 +949,199 @@ index 8b1d659..ef49c2e 100644
      }
  
      // Change the following lines only, if you add, remove or rename 
+diff --git basegfx/test/clipstate.cxx basegfx/test/clipstate.cxx
+new file mode 100644
+index 0000000..aeb7cfc
+--- /dev/null
++++ basegfx/test/clipstate.cxx
+@@ -0,0 +1,187 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: basegfx2d.cxx,v $
++ * $Revision: 1.14 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_basegfx.hxx"
++// autogenerated file with codegen.pl
++
++#include <cppunit/simpleheader.hxx>
++
++#include <basegfx/tools/b2dclipstate.hxx>
++#include <basegfx/range/b2dpolyrange.hxx>
++#include <basegfx/polygon/b2dpolygon.hxx>
++#include <basegfx/polygon/b2dpolygontools.hxx>
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <basegfx/polygon/b2dpolypolygon.hxx>
++#include <basegfx/numeric/ftools.hxx>
++
++#include <boost/bind.hpp>
++
++using namespace ::basegfx;
++
++
++namespace basegfx2d
++{
++
++class clipstate : public CppUnit::TestFixture
++{
++private:
++    tools::B2DClipState aUnion1; 
++    tools::B2DClipState aUnion2; 
++    tools::B2DClipState aIntersect; 
++    tools::B2DClipState aXor; 
++    tools::B2DClipState aSubtract; 
++
++public:
++    void setUp()
++    {
++        B2DRange aCenter(100, 100, -100, -100);
++        B2DRange aNorth(-10, -110, 10, -90);
++        B2DRange aWest(-110, -10, -90, 10);
++        B2DRange aSouth(-10, 110, 10, 90);
++        B2DRange aEast(110, -10, 90, 10);
++
++        aUnion1.unionRange(aCenter);
++        aUnion1.unionRange(aNorth);
++        aUnion1.unionRange(aWest);
++        aUnion1.unionRange(aSouth);
++        aUnion1.unionRange(aEast);
++
++        aUnion2.makeNull();
++        aUnion2.unionRange(aCenter);
++        aUnion2.unionRange(aNorth);
++        aUnion2.unionRange(aWest);
++        aUnion2.unionRange(aSouth);
++        aUnion2.unionRange(aEast);
++
++        aIntersect.intersectRange(aCenter);
++        aIntersect.intersectRange(aNorth);
++        aIntersect.intersectRange(aWest);
++        aIntersect.intersectRange(aSouth);
++        aIntersect.intersectRange(aEast);
++
++        aXor.makeNull();
++        aXor.xorRange(aCenter);
++        aXor.xorRange(aNorth);
++        aXor.xorRange(aWest);
++        aXor.xorRange(aSouth);
++        aXor.xorRange(aEast);
++
++        aSubtract.intersectRange(aCenter);
++        aSubtract.subtractRange(aNorth);
++        aSubtract.subtractRange(aWest);
++        aSubtract.subtractRange(aSouth);
++        aSubtract.subtractRange(aEast);
++    }
++
++    void tearDown()
++    {}
++
++    void verifyPoly(const char* sName, const char* sSvg, const tools::B2DClipState& toTest)
++    {
++#if defined(VERBOSE)
++        fprintf(stderr, "%s - svg:d=\"%s\"\n", 
++                sName, rtl::OUStringToOString(
++                    basegfx::tools::exportToSvgD(toTest.getClipPoly()),
++                    RTL_TEXTENCODING_UTF8).getStr() );
++#endif
++
++        B2DPolyPolygon aTmp1;
++        CPPUNIT_ASSERT_MESSAGE(sName, 
++                               tools::importFromSvgD(
++                                   aTmp1,
++                                   rtl::OUString::createFromAscii(sSvg)));
++
++        const rtl::OUString aSvg=
++            tools::exportToSvgD(toTest.getClipPoly());
++        B2DPolyPolygon aTmp2;
++        CPPUNIT_ASSERT_MESSAGE(sName,
++                               tools::importFromSvgD(
++                                   aTmp2,
++                                   aSvg));
++
++        CPPUNIT_ASSERT_MESSAGE(
++            sName,
++            aTmp2 == aTmp1);
++    }
++
++    void verifySimpleRange()
++    {
++        const char* unionSvg="m100 10v90h-90v10h-20v-10h-90v-90h-10v-20h10v-90h90v-10h20v10h90v90h10v20z";
++        const char* intersectSvg="m-100 10v-20h10v20zm80 90v-10h20v10zm-20-190v-10h20v10zm80 100v-20h10v20z";
++        const char* xorSvg="m-100 10h10v-20h-10zm90 110h20v-10h-20zm0-180h20v-10h-20zm100 110h10v-20h-10zm10 20v90h-90v10h-20v-10h-90v-90h-10v-20h10v-90h90v-10h20v10h90v90h10v20z";
++        const char* subtractSvg="m-90 10v-20h-10v-90h90v10h20v-10h90v90h-10v20h10v90h-90v-10h-20v10h-90v-90z";
++
++        CPPUNIT_ASSERT_MESSAGE("cleared clip stays empty under union operation",
++                               aUnion1.isCleared());
++        verifyPoly("union", unionSvg, aUnion2);
++        verifyPoly("intersect", intersectSvg, aIntersect);
++        verifyPoly("xor", xorSvg, aXor);
++        verifyPoly("subtract", subtractSvg, aSubtract);
++    }
++
++    void verifyMixedClips()
++    {
++        tools::B2DClipState aMixedClip; 
++
++        const char* unionSvg="m100 10v90h-90v10h-20v-10h-90v-90h-10v-20h10v-90h90v-10h20v10h90v90h10v20z";
++
++        B2DPolyPolygon aTmp1;
++        tools::importFromSvgD(
++            aTmp1,
++            rtl::OUString::createFromAscii(unionSvg));
++
++        aMixedClip.intersectPolyPolygon(aTmp1);
++        aMixedClip.subtractRange(B2DRange(-20,-150,20,0));
++        aMixedClip.subtractRange(B2DRange(-150,-20,0,20));
++        aMixedClip.xorRange(B2DRange(-150,-150,150,150));
++
++        const char* mixedClipSvg="m0 0v20h-100v80h90v10h20v-10h90v-90h10v-20h-10v-90h-80v100zm-40-20v-80h-80v80zm-50 170v-300h300v300z";
++        verifyPoly("mixed clip", mixedClipSvg, aMixedClip);
++    }
++
++    CPPUNIT_TEST_SUITE(clipstate);
++    CPPUNIT_TEST(verifySimpleRange);
++    CPPUNIT_TEST(verifyMixedClips);
++    CPPUNIT_TEST_SUITE_END();
++};
++
++// -----------------------------------------------------------------------------
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::clipstate, "clipstate");
++} // namespace basegfx2d
++
++
++// -----------------------------------------------------------------------------
++
++// this macro creates an empty function, which will called by the RegisterAllFunctions()
++// to let the user the possibility to also register some functions by hand.
++// NOADDITIONAL;
++
 diff --git basegfx/test/genericclipper.cxx basegfx/test/genericclipper.cxx
 new file mode 100644
 index 0000000..70455fd
@@ -798,13 +1317,21 @@ index 0000000..70455fd
 +// NOADDITIONAL;
 +
 diff --git basegfx/test/makefile.mk basegfx/test/makefile.mk
-index 320bd0c..4ca75c1 100644
+index 320bd0c..31ea7f8 100644
 --- basegfx/test/makefile.mk
 +++ basegfx/test/makefile.mk
-@@ -47,6 +47,7 @@ SHL1OBJS=  \
-     $(SLO)$/basegfx2d.obj \
-     $(SLO)$/basegfx3d.obj \
+@@ -43,10 +43,12 @@ ENABLE_EXCEPTIONS=TRUE
+ # --- Common ----------------------------------------------------------
+ 
+ SHL1OBJS=  \
+-    $(SLO)$/basegfx1d.obj \
+-    $(SLO)$/basegfx2d.obj \
+-    $(SLO)$/basegfx3d.obj \
++    $(SLO)$/basegfx1d.obj  \
++    $(SLO)$/basegfx2d.obj  \
++    $(SLO)$/basegfx3d.obj  \
      $(SLO)$/boxclipper.obj \
++    $(SLO)$/clipstate.obj  \
 +    $(SLO)$/genericclipper.obj \
      $(SLO)$/testtools.obj	
  
diff --git a/patches/test/wmf-clipperf.diff b/patches/test/wmf-clipperf.diff
new file mode 100644
index 0000000..71e3cce
--- /dev/null
+++ b/patches/test/wmf-clipperf.diff
@@ -0,0 +1,439 @@
+Use the new B2DClipState to improve wmf clip performance
+
+From: Thorsten Behrens <thb at openoffice.org>
+
+
+---
+
+ svtools/source/filter.vcl/wmf/winmtf.cxx |  178 ++++++++++++------------------
+ svtools/source/filter.vcl/wmf/winmtf.hxx |   54 +++++----
+ svtools/util/makefile.mk                 |    1 
+ 3 files changed, 97 insertions(+), 136 deletions(-)
+
+
+diff --git svtools/source/filter.vcl/wmf/winmtf.cxx svtools/source/filter.vcl/wmf/winmtf.cxx
+index 666b0a0..026d024 100644
+--- svtools/source/filter.vcl/wmf/winmtf.cxx
++++ svtools/source/filter.vcl/wmf/winmtf.cxx
+@@ -33,8 +33,11 @@
+ 
+ 
+ #include "winmtf.hxx"
++#include <basegfx/matrix/b2dhommatrix.hxx>
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
+ #include <vcl/metaact.hxx>
+ #include <vcl/graphictools.hxx>
++#include <vcl/canvastools.hxx>
+ #include <vcl/metric.hxx>
+ #include <rtl/tencinfo.h>
+ 
+@@ -45,99 +48,56 @@
+ 
+ #define WIN_MTF_MAX_POLYPOLYCOUNT	16
+ 
+-void WinMtfClipPath::ImpUpdateType()
++void WinMtfClipPath::intersectClipRect( const Rectangle& rRect )
+ {
+-    if ( !aPolyPoly.Count() )
+-        eType = EMPTY;
+-    else if ( aPolyPoly.IsRect() )
+-        eType = RECTANGLE;
+-    else
+-        eType = COMPLEX;
+-
+-    bNeedsUpdate = sal_True;
+-}
+-
+-void WinMtfClipPath::IntersectClipRect( const Rectangle& rRect )
+-{
+-    if ( !aPolyPoly.Count() )
+-        aPolyPoly = Polygon( rRect );
+-    else if ( aPolyPoly.Count() < WIN_MTF_MAX_POLYPOLYCOUNT )
+-    {
+-        Polygon aPolygon( rRect );
+-        PolyPolygon aIntersection;
+-        PolyPolygon aPolyPolyRect( aPolygon );
+-        aPolyPoly.GetIntersection( aPolyPolyRect, aIntersection );
+-        aPolyPoly = aIntersection;
+-    }
+-    ImpUpdateType();
++    maClip.intersectRange(
++        vcl::unotools::b2DRectangleFromRectangle(rRect));
+ }
+ 
+-void WinMtfClipPath::ExcludeClipRect( const Rectangle& rRect )
++void WinMtfClipPath::excludeClipRect( const Rectangle& rRect )
+ {
+-    if ( aPolyPoly.Count() && ( aPolyPoly.Count() < WIN_MTF_MAX_POLYPOLYCOUNT ) )
+-    {
+-        Polygon aPolygon( rRect );
+-        PolyPolygon aPolyPolyRect( aPolygon );
+-        PolyPolygon aDifference;
+-        aPolyPoly.GetDifference( aPolyPolyRect, aDifference );
+-        aPolyPoly = aDifference;
+-    }
+-    ImpUpdateType();
++    maClip.subtractRange(
++        vcl::unotools::b2DRectangleFromRectangle(rRect));
+ }
+ 
+-void WinMtfClipPath::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode )
++void WinMtfClipPath::setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode )
+ {
+-    if ( !rPolyPolygon.Count() )
+-        aPolyPoly = rPolyPolygon;
+-    else if ( rPolyPolygon.Count() < WIN_MTF_MAX_POLYPOLYCOUNT )
++    const basegfx::B2DPolyPolygon& rB2DPoly=rPolyPolygon.getB2DPolyPolygon();
++    switch ( nClippingMode )
+     {
+-        PolyPolygon aNewClipPath;
+-
+-        // #115345# Watch out for empty aPolyPoly here - conceptually,
+-        // an empty clip path is a rectangle of infinite size, but it
+-        // is represented by an empty aPolyPoly. When intersecting
+-        // rPolyPolygon with this _empty_ aPolyPoly, set algebra
+-        // guarantees wrong results.
+-        switch ( nClippingMode )
+-        {
+-            case RGN_OR :
+-                // #115345# clip stays empty, when ORing an arbitrary
+-                // rPolyPolygon. Thus, we can save us the unnecessary
+-                // clipper call.
+-                if( aPolyPoly.Count() )
+-                    aPolyPoly.GetUnion( rPolyPolygon, aNewClipPath );
++        case RGN_OR :
++            maClip.unionPolyPolygon(rB2DPoly);
+             break;
+-            case RGN_XOR :
+-                // TODO:
+-                // #115345# Cannot handle this case, for the time being
+-                aPolyPoly.GetXOR( rPolyPolygon, aNewClipPath );
++        case RGN_XOR :
++            maClip.xorPolyPolygon(rB2DPoly);
+             break;
+-            case RGN_DIFF :
+-                // TODO:
+-                // #115345# Cannot handle this case, for the time being
+-                aPolyPoly.GetDifference( rPolyPolygon, aNewClipPath );
++        case RGN_DIFF :
++            maClip.subtractPolyPolygon(rB2DPoly);
+             break;
+-            case RGN_AND :
+-                // #115345# Clip becomes rPolyPolygon, when ANDing
+-                // with an arbitrary rPolyPolygon
+-                if( aPolyPoly.Count() )
+-                    aPolyPoly.GetIntersection( rPolyPolygon, aNewClipPath );
+-                else
+-                    aNewClipPath = rPolyPolygon;
++        case RGN_AND :
++            maClip.intersectPolyPolygon(rB2DPoly);
+             break;
+-            case RGN_COPY :
+-                aNewClipPath = rPolyPolygon;
++        case RGN_COPY :
++            maClip = basegfx::tools::B2DClipState(rB2DPoly);
+             break;
+-        }
+-        aPolyPoly = aNewClipPath;
+     }
+-    ImpUpdateType();
+ }
+ 
+-void WinMtfClipPath::MoveClipRegion( const Size& rSize )
++void WinMtfClipPath::moveClipRegion( const Size& rSize )
++{
++    // what a weird concept. emulate, don't want this in B2DClipState
++    // API
++    basegfx::B2DPolyPolygon aCurrClip=maClip.getClipPoly();
++    basegfx::B2DHomMatrix aTranslate;
++    aTranslate.translate(rSize.Width(), rSize.Height());
++
++    aCurrClip.transform(aTranslate);
++    maClip = basegfx::tools::B2DClipState( aCurrClip );
++}
++
++basegfx::B2DPolyPolygon WinMtfClipPath::getClipPath() const
+ {
+-    aPolyPoly.Move( rSize.Width(), rSize.Height() );
+-    bNeedsUpdate = sal_True;
++    return maClip.getClipPoly();
+ }
+ 
+ // ------------------------------------------------------------------------
+@@ -882,31 +842,35 @@ void WinMtfOutput::DeleteObject( sal_Int32 nIndex )
+ 
+ void WinMtfOutput::IntersectClipRect( const Rectangle& rRect )
+ {
+-    aClipPath.IntersectClipRect( ImplMap( rRect ) );
++    mbClipNeedsUpdate=true;
++    aClipPath.intersectClipRect( ImplMap( rRect ) );
+ }
+ 
+ //-----------------------------------------------------------------------------------
+ 
+ void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect )
+ {
+-    aClipPath.ExcludeClipRect( ImplMap( rRect ) );
++    mbClipNeedsUpdate=true;
++    aClipPath.excludeClipRect( ImplMap( rRect ) );
+ }
+ 
+ //-----------------------------------------------------------------------------------
+ 
+ void WinMtfOutput::MoveClipRegion( const Size& rSize )
+ {
+-    aClipPath.MoveClipRegion( ImplMap( rSize ) );
++    mbClipNeedsUpdate=true;
++    aClipPath.moveClipRegion( ImplMap( rSize ) );
+ }
+ 
+ void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped )
+ {
++    mbClipNeedsUpdate=true;
+     if ( bIsMapped )
+-        aClipPath.SetClipPath( rPolyPolygon, nClippingMode );
++        aClipPath.setClipPath( rPolyPolygon, nClippingMode );
+     else
+     {
+         PolyPolygon aPP( rPolyPolygon );
+-        aClipPath.SetClipPath( ImplMap( aPP ), nClippingMode );
++        aClipPath.setClipPath( ImplMap( aPP ), nClippingMode );
+     }
+ }
+ 
+@@ -928,6 +892,8 @@ WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
+     maActPos			( Point() ),
+     mbNopMode			( sal_False ),
+     mbFillStyleSelected	( sal_False ),
++    mbClipNeedsUpdate   ( true ),
++    mbComplexClip       ( false ),
+     mnGfxMode			( GM_COMPATIBLE ),
+     mnMapMode           ( MM_TEXT ),
+     mnDevOrgX			( 0 ),
+@@ -979,31 +945,25 @@ WinMtfOutput::~WinMtfOutput()
+ 
+ void WinMtfOutput::UpdateClipRegion()
+ {
+-    if ( aClipPath.bNeedsUpdate )
++    if ( mbClipNeedsUpdate )
+     {
+-        aClipPath.bNeedsUpdate = sal_False;
++        mbClipNeedsUpdate = false;
++        mbComplexClip = false;
+ 
+         mpGDIMetaFile->AddAction( new MetaPopAction() );                    // taking the orignal clipregion
+         mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );  // 
+ 
+-        switch ( aClipPath.GetType() )
++        // skip for 'no clipping at all' case
++        if( !aClipPath.isEmpty() )
+         {
+-            case RECTANGLE :
+-            case COMPLEX :
+-            {
+-//				we will not generate a RegionClipRegion Action, because this action
+-//				cannot be saved to the wmf format - saving to wmf always happens
+-//				if the placeholder graphic for ole objects is generated. (SJ)
+-
+-//				Region aClipRegion( aClipPath.GetClipPath() );
+-//				mpGDIMetaFile->AddAction( new MetaISectRegionClipRegionAction( aClipRegion ) );
+-
+-                Rectangle aClipRect( aClipPath.GetClipPath().GetBoundRect() );
+-                mpGDIMetaFile->AddAction( new MetaISectRectClipRegionAction( aClipRect ) );
+-            }
+-            break;
+-            case EMPTY:
+-            break;  // -Wall not handled.
++            const basegfx::B2DPolyPolygon& rClipPoly( aClipPath.getClipPath() );
++            mpGDIMetaFile->AddAction( 
++                new MetaISectRectClipRegionAction( 
++                    vcl::unotools::rectangleFromB2DRectangle(
++                        rClipPoly.getB2DRange())));
++
++            mbComplexClip = rClipPoly.count() > 1 
++                || !basegfx::tools::isRectangle(rClipPoly);
+         }
+     }
+ }
+@@ -1182,12 +1142,12 @@ void WinMtfOutput::DrawRect( const Rectangle& rRect, BOOL bEdge )
+     UpdateClipRegion();
+     UpdateFillStyle();
+ 
+-    if ( aClipPath.GetType() == COMPLEX )
++    if ( mbComplexClip )
+     {
+         Polygon aPoly( ImplMap( rRect ) );
+         PolyPolygon aPolyPolyRect( aPoly );
+         PolyPolygon aDest;
+-        aClipPath.GetClipPath().GetIntersection( aPolyPolyRect, aDest );
++        PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPolyRect, aDest );
+         ImplDrawClippedPolyPolygon( aDest );
+     }
+     else
+@@ -1342,11 +1302,11 @@ void WinMtfOutput::DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath )
+     {
+         UpdateFillStyle();
+ 
+-        if ( aClipPath.GetType() == COMPLEX )
++        if ( mbComplexClip )
+         {
+             PolyPolygon aPolyPoly( rPolygon );
+             PolyPolygon aDest;
+-            aClipPath.GetClipPath().GetIntersection( aPolyPoly, aDest );
++            PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest );
+             ImplDrawClippedPolyPolygon( aDest );
+         }
+         else
+@@ -1418,10 +1378,10 @@ void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordP
+     {
+         UpdateFillStyle();
+ 
+-        if ( aClipPath.GetType() == COMPLEX )
++        if ( mbComplexClip )
+         {
+             PolyPolygon aDest;
+-            aClipPath.GetClipPath().GetIntersection( rPolyPolygon, aDest );	
++            PolyPolygon(aClipPath.getClipPath()).GetIntersection( rPolyPolygon, aDest );	
+             ImplDrawClippedPolyPolygon( aDest );
+         }
+         else
+@@ -1656,7 +1616,7 @@ void WinMtfOutput::DrawText( Point& rPosition, String& rText, sal_Int32* pDXArry
+ void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap )
+ {
+     BitmapEx aBmpEx( rBitmap );
+-    if ( aClipPath.GetType() == COMPLEX )
++    if ( mbComplexClip )
+     {
+         VirtualDevice aVDev;
+         MapMode aMapMode( MAP_100TH_MM );
+@@ -1671,7 +1631,7 @@ void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const B
+         aVDev.SetMapMode( aMapMode );
+         aVDev.SetOutputSizePixel( aSizePixel );
+         aVDev.SetFillColor( Color( COL_BLACK ) );
+-        const PolyPolygon aClip( aClipPath.GetClipPath() );
++        const PolyPolygon aClip( aClipPath.getClipPath() );
+         aVDev.DrawPolyPolygon( aClip );
+         const Point aEmptyPoint;
+ 
+@@ -2220,7 +2180,7 @@ void WinMtfOutput::Pop()
+         if ( ! ( aClipPath == pSave->aClipPath ) )
+         {
+             aClipPath = pSave->aClipPath;
+-            aClipPath.bNeedsUpdate = sal_True;
++            mbClipNeedsUpdate = true;
+         }
+         if ( meLatestRasterOp != meRasterOp )
+             mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
+diff --git svtools/source/filter.vcl/wmf/winmtf.hxx svtools/source/filter.vcl/wmf/winmtf.hxx
+index 19e2a06..9286953 100644
+--- svtools/source/filter.vcl/wmf/winmtf.hxx
++++ svtools/source/filter.vcl/wmf/winmtf.hxx
+@@ -48,6 +48,7 @@
+ #include <vcl/graph.hxx>
+ #include <vcl/virdev.hxx>
+ #include <tools/poly.hxx>
++#include <basegfx/tools/b2dclipstate.hxx>
+ #include <vcl/font.hxx>
+ #include <vcl/bmpacc.hxx>
+ #include <vcl/lineinfo.hxx>
+@@ -311,34 +312,26 @@ struct LOGFONTW
+ void WinMtfAssertHandler( const sal_Char*, sal_uInt32 nFlags = WIN_MTF_ASSERT_MIFE );
+ #endif 
+ 
+-enum WinMtfClipPathType{ EMPTY, RECTANGLE, COMPLEX };
+-
+ class WinMtfClipPath
+ {
+-        PolyPolygon			aPolyPoly;
+-        WinMtfClipPathType	eType;
+-
+-        void		ImpUpdateType();
+-
+-    public :
+-
+-        sal_Bool	bNeedsUpdate;
+-
+-                    WinMtfClipPath(): eType(EMPTY), bNeedsUpdate( sal_False ){};
++    basegfx::tools::B2DClipState maClip;
+ 
+-        void		SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode );
+-        void		IntersectClipRect( const Rectangle& rRect );
+-        void		ExcludeClipRect( const Rectangle& rRect );
+-        void		MoveClipRegion( const Size& rSize );
++public :
++    WinMtfClipPath(): maClip() {};
+ 
+-        WinMtfClipPathType GetType() const { return eType; };
+-        const PolyPolygon& GetClipPath() const { return aPolyPoly; };
++    void		setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode );
++    void		intersectClipRect( const Rectangle& rRect );
++    void		excludeClipRect( const Rectangle& rRect );
++    void		moveClipRegion( const Size& rSize );
+ 
+-        sal_Bool operator==( const WinMtfClipPath& rPath )
+-        {
+-            return  ( rPath.eType == eType ) &&
+-                    ( rPath.aPolyPoly == aPolyPoly );
+-        };
++    bool isEmpty() const { return maClip.isCleared(); }
++    
++    basegfx::B2DPolyPolygon getClipPath() const;
++    
++    bool operator==( const WinMtfClipPath& rPath ) const
++    {
++        return maClip == rPath.maClip;
++    };
+ };
+ 
+ class WinMtfPathObj : public PolyPolygon
+@@ -380,20 +373,25 @@ struct WinMtfFillStyle
+ 
+     WinMtfFillStyle() :
+         aFillColor	( Color( COL_BLACK ) ),
+-        bTransparent( FALSE )
++        bTransparent( FALSE ),
++        aType(),
++        aBmp()
+     {
+     };
+ 
+     WinMtfFillStyle( const Color& rColor, BOOL bTrans = FALSE ) :
+         aFillColor	( rColor ),
+ 		bTransparent( bTrans ),
+-        aType       ( FillStyleSolid )
++        aType       ( FillStyleSolid ),
++        aBmp()
+ 	{
+ 	};
+ 
+ 	WinMtfFillStyle( Bitmap& rBmp ) :
+-		aBmp ( rBmp ),
+-        aType( FillStylePattern )
++        aFillColor	(),
++        bTransparent( FALSE ),
++        aType( FillStylePattern ),
++		aBmp ( rBmp )
+     {
+     };
+ 
+@@ -584,6 +582,8 @@ class WinMtfOutput
+         sal_uInt32          mnRop;
+         sal_Bool            mbNopMode;
+         sal_Bool			mbFillStyleSelected;
++        sal_Bool            mbClipNeedsUpdate;
++        sal_Bool            mbComplexClip;
+ 
+         std::vector< SaveStructPtr > vSaveStack;
+ 
+diff --git svtools/util/makefile.mk svtools/util/makefile.mk
+index d401956..2f869a2 100644
+--- svtools/util/makefile.mk
++++ svtools/util/makefile.mk
+@@ -139,6 +139,7 @@ SHL1STDLIBS+= \
+         $(VCLLIB)			\
+         $(SVLLIB)			\
+         $(SOTLIB)			\
++        $(BASEGFXLIB)		\
+         $(UNOTOOLSLIB)		\
+         $(TOOLSLIB)			\
+         $(I18NISOLANGLIB)   \


More information about the ooo-build-commit mailing list