[ooo-build-commit] 2 commits - configure.in patches/test
Thorsten Behrens
thorsten at kemper.freedesktop.org
Thu Sep 10 07:19:38 PDT 2009
configure.in | 3
patches/test/boxclipping.diff | 2860 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 2860 insertions(+), 3 deletions(-)
New commits:
commit 95e4fd1ec476c7f2ee7e1bf8df9bcae4c9f3f9f2
Author: Thorsten Behrens <thb at openoffice.org>
Date: Fri Sep 11 09:41:51 2009 +0200
Removed warning that master is not buildable
* configure.in: now, master _should_ be buildable!
diff --git a/configure.in b/configure.in
index 88d3bd1..052062a 100644
--- a/configure.in
+++ b/configure.in
@@ -1580,9 +1580,6 @@ $warn_use_download make
ooo-build-3-1 branch for 3.1
ooo-build-3-1-1 branch for 3.1.1
opensuse-11-1 branch for 3.0 in openSUSE 11.1 and SLED11
-
-
- NOTE that 'master' currently is not necessarily buildable.
"
if test "$BUILD_WIN32" != "yes" -a "$ENABLE_ICECREAM" != "yes"; then
commit 9e619223eed2abe3cdad7965f5f676c74aa01f22
Author: Thorsten Behrens <thb at openoffice.org>
Date: Fri Sep 11 09:39:48 2009 +0200
First working version of a specialized box clipper
* patches/test/boxclipping.diff: adds a clipper specialized for
symbolically clipping boxes (=axis-aligned rectangles) against
each other
diff --git a/patches/test/boxclipping.diff b/patches/test/boxclipping.diff
new file mode 100644
index 0000000..a6dafdf
--- /dev/null
+++ b/patches/test/boxclipping.diff
@@ -0,0 +1,2860 @@
+Specialized boxclipping stuff
+
+From: Thorsten Behrens <thb at openoffice.org>
+
+
+---
+
+ basegfx/inc/basegfx/polygon/b2dpolygon.hxx | 10
+ basegfx/inc/basegfx/polygon/b2dpolypolygon.hxx | 6
+ basegfx/inc/basegfx/range/b2dmultirange.hxx | 7
+ basegfx/qa/mkpolygons.pl | 337 ++++++
+ basegfx/source/polygon/b2dpolygon.cxx | 102 +-
+ basegfx/source/polygon/b2dpolypolygon.cxx | 40 +
+ basegfx/source/range/b2dmultirange.cxx | 1394 ++++++++++++++++++++++--
+ basegfx/test/basegfx2d.cxx | 211 ----
+ basegfx/test/boxclipper.cxx | 418 +++++++
+ basegfx/test/makefile.mk | 5
+ 10 files changed, 2194 insertions(+), 336 deletions(-)
+ create mode 100644 basegfx/qa/mkpolygons.pl
+ create mode 100644 basegfx/test/boxclipper.cxx
+
+
+diff --git basegfx/inc/basegfx/polygon/b2dpolygon.hxx basegfx/inc/basegfx/polygon/b2dpolygon.hxx
+index 067680e..e7f60c1 100644
+--- basegfx/inc/basegfx/polygon/b2dpolygon.hxx
++++ basegfx/inc/basegfx/polygon/b2dpolygon.hxx
+@@ -83,7 +83,7 @@ namespace basegfx
+ sal_uInt32 count() const;
+
+ /// Coordinate interface
+- basegfx::B2DPoint getB2DPoint(sal_uInt32 nIndex) const;
++ const basegfx::B2DPoint& getB2DPoint(sal_uInt32 nIndex) const;
+ void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
+
+ /// Coordinate insert/append
+@@ -201,7 +201,7 @@ namespace basegfx
+ @return
+ The outer range of the bezier curve/polygon
+ */
+- B2DRange getB2DRange() const;
++ const B2DRange& getB2DRange() const;
+
+ /** insert other 2D polygons
+
+@@ -261,6 +261,12 @@ namespace basegfx
+
+ /// apply transformation given in matrix form
+ void transform(const basegfx::B2DHomMatrix& rMatrix);
++
++ // point iterators
++ const B2DPoint* begin() const;
++ const B2DPoint* end() const;
++ B2DPoint* begin();
++ B2DPoint* end();
+ };
+ } // end of namespace basegfx
+
+diff --git basegfx/inc/basegfx/polygon/b2dpolypolygon.hxx basegfx/inc/basegfx/polygon/b2dpolypolygon.hxx
+index 38048f8..1b8ba65 100644
+--- basegfx/inc/basegfx/polygon/b2dpolypolygon.hxx
++++ basegfx/inc/basegfx/polygon/b2dpolypolygon.hxx
+@@ -128,6 +128,12 @@ namespace basegfx
+
+ // apply transformation given in matrix form to the polygon
+ void transform(const basegfx::B2DHomMatrix& rMatrix);
++
++ // polygon iterators
++ const B2DPolygon* begin() const;
++ const B2DPolygon* end() const;
++ B2DPolygon* begin();
++ B2DPolygon* end();
+ };
+ } // end of namespace basegfx
+
+diff --git basegfx/inc/basegfx/range/b2dmultirange.hxx basegfx/inc/basegfx/range/b2dmultirange.hxx
+index 447b0bf..ee0d5df 100644
+--- basegfx/inc/basegfx/range/b2dmultirange.hxx
++++ basegfx/inc/basegfx/range/b2dmultirange.hxx
+@@ -32,8 +32,7 @@
+ #define _BGFX_RANGE_B2DMULTIRANGE_HXX
+
+ #include <o3tl/cow_wrapper.hxx>
+-#include <memory>
+-
++#include <vector>
+
+ namespace basegfx
+ {
+@@ -102,6 +101,10 @@ namespace basegfx
+ */
+ B2DRange getBounds() const;
+
++ /** Get vector of all current ranges
++ */
++ const std::vector<B2DRange>& getRanges() const;
++
+ /** Request poly-polygon representing the added ranges.
+
+ This method creates a poly-polygon, consisting exactly out
+diff --git basegfx/qa/mkpolygons.pl basegfx/qa/mkpolygons.pl
+new file mode 100644
+index 0000000..22056fb
+--- /dev/null
++++ basegfx/qa/mkpolygons.pl
+@@ -0,0 +1,337 @@
++:
++eval 'exec perl -wS $0 ${1+"$@"}'
++ if 0;
++
++
++use IO::File;
++use Cwd;
++use File::Spec;
++use File::Spec::Functions;
++use File::Temp;
++use File::Path;
++
++$TempDir = "";
++
++
++# all the XML package generation is a blatant rip from AF's
++# write-calc-doc.pl
++
++
++###############################################################################
++# Open a file with the given name.
++# First it is checked if the temporary directory, in which all files for
++# the document are gathered, is already present and create it if it is not.
++# Then create the path to the file inside the temporary directory.
++# Finally open the file and return a file handle to it.
++#
++sub open_file
++{
++ my $filename = pop @_;
++
++ # Create base directory of temporary directory tree if not alreay
++ # present.
++ if ($TempDir eq "")
++ {
++ $TempDir = File::Temp::tempdir (CLEANUP => 1);
++ }
++
++ # Create the path to the file.
++ my $fullname = File::Spec->catfile ($TempDir, $filename);
++ my ($volume,$directories,$file) = File::Spec->splitpath ($fullname);
++ mkpath (File::Spec->catpath ($volume,$directories,""));
++
++ # Open the file and return a file handle to it.
++ return new IO::File ($fullname, "w");
++}
++
++
++###############################################################################
++# Zip the files in the directory tree into the given file.
++#
++sub zip_dirtree
++{
++ my $filename = pop @_;
++
++ my $cwd = getcwd;
++ my $zip_name = $filename;
++
++ # We are about to change the directory.
++ # Therefore create an absolute pathname for the zip archive.
++
++ # First transfer the drive from $cwd to $zip_name. This is a
++ # workaround for a bug in file_name_is_absolute which thinks
++ # the the path \bla is an absolute path under DOS.
++ my ($volume,$directories,$file) = File::Spec->splitpath ($zip_name);
++ my ($volume_cwd,$directories_cwd,$file_cwd) = File::Spec->splitpath ($cwd);
++ $volume = $volume_cwd if ($volume eq "");
++ $zip_name = File::Spec->catpath ($volume,$directories,$file);
++
++ # Add the current working directory to a relative path.
++ if ( ! file_name_is_absolute ($zip_name))
++ {
++ $zip_name = File::Spec->catfile ($cwd, $zip_name);
++
++ # Try everything to clean up the name.
++ $zip_name = File::Spec->rel2abs ($filename);
++ $zip_name = File::Spec->canonpath ($zip_name);
++
++ # Remove .. directories from the middle of the path.
++ while ($zip_name =~ /\/[^\/][^\.\/][^\/]*\/\.\.\//)
++ {
++ $zip_name = $` . "/" . $';
++ }
++ }
++
++ # Just in case the zip program gets confused by an existing file with the
++ # same name as the one to be written that file is removed first.
++ if ( -e $filename)
++ {
++ if (unlink ($filename) == 0)
++ {
++ print "Existing file $filename could not be deleted.\n";
++ print "Please close the application that uses it, then try again.\n";
++ return;
++ }
++ }
++
++ # Finally create the zip file. First change into the temporary directory
++ # so that the resulting zip file contains only paths relative to it.
++ print "zipping [$ZipCmd $ZipFlags $zip_name *]\n";
++ chdir ($TempDir);
++ system ("$ZipCmd $ZipFlags $zip_name *");
++ chdir ($cwd);
++}
++
++
++sub writeHeader
++{
++ print $OUT qq~<?xml version="1.0" encoding="UTF-8"?>
++
++<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" office:version="1.0">
++ <office:scripts/>
++ <office:automatic-styles>
++ <style:style style:name="dp1" style:family="drawing-page">
++ <style:drawing-page-properties presentation:background-visible="true" presentation:background-objects-visible="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/>
++ </style:style>
++ <style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard">
++ <style:graphic-properties draw:textarea-horizontal-align="center" draw:fill="none" draw:stroke="none" draw:textarea-vertical-align="middle"/>
++ </style:style>
++ <style:style style:name="gr2" style:family="graphic" style:parent-style-name="standard">
++ <style:graphic-properties draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle"/>
++ </style:style>
++ <style:style style:name="pr1" style:family="presentation" style:parent-style-name="Default-title">
++ <style:graphic-properties draw:fill-color="#ffffff" draw:auto-grow-height="true" fo:min-height="3.508cm"/>
++ </style:style>
++ <style:style style:name="pr2" style:family="presentation" style:parent-style-name="Default-notes">
++ <style:graphic-properties draw:fill-color="#ffffff" draw:auto-grow-height="true" fo:min-height="13.367cm"/>
++ </style:style>
++ <style:style style:name="P1" style:family="paragraph">
++ <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm"/>
++ </style:style>
++ <style:style style:name="P2" style:family="paragraph">
++ <style:paragraph-properties fo:margin-left="0.6cm" fo:margin-right="0cm" fo:text-indent="-0.6cm"/>
++ </style:style>
++ <text:list-style style:name="L1">
++ <text:list-level-style-bullet text:level="1" text:bullet-char="â">
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="2" text:bullet-char="â">
++ <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="3" text:bullet-char="â">
++ <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="4" text:bullet-char="â">
++ <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="5" text:bullet-char="â">
++ <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="6" text:bullet-char="â">
++ <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="7" text:bullet-char="â">
++ <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="8" text:bullet-char="â">
++ <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ <text:list-level-style-bullet text:level="9" text:bullet-char="â">
++ <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/>
++ <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
++ </text:list-level-style-bullet>
++ </text:list-style>
++ </office:automatic-styles>
++ <office:body>
++ <office:presentation>
++~;
++
++}
++
++sub writeSlideHeader
++{
++ my $titleText = pop @_;
++ my $slideNum = pop @_;
++
++ print $OUT " <draw:page draw:name=\"page1\" draw:style-name=\"dp1\" draw:master-page-name=\"Default\">\n";
++ print $OUT " <office:forms form:automatic-focus=\"false\" form:apply-design-mode=\"false\"/>\n";
++ print $OUT " <draw:rect draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:id=\"id$slideNum\" draw:layer=\"layout\" svg:width=\"17.5cm\" svg:height=\"6cm\" svg:x=\"5cm\" svg:y=\"4cm\">\n";
++ print $OUT " <text:p text:style-name=\"P2\">Slide: $slideNum</text:p>\n";
++ print $OUT " <text:p text:style-name=\"P2\">Path: $titleText</text:p>\n";
++ print $OUT " </draw:rect>\n";
++}
++
++
++sub writeSlideFooter
++{
++ print $OUT " <presentation:notes draw:style-name=\"dp1\">\n";
++ print $OUT " <draw:page-thumbnail draw:style-name=\"gr1\" draw:layer=\"layout\" svg:width=\"14.851cm\" svg:height=\"11.138cm\" svg:x=\"3.068cm\" svg:y=\"2.257cm\" draw:page-number=\"1\" presentation:class=\"page\"/>\n";
++ print $OUT " <draw:frame presentation:style-name=\"pr3\" draw:layer=\"layout\" svg:width=\"16.79cm\" svg:height=\"13.116cm\" svg:x=\"2.098cm\" svg:y=\"14.109cm\" presentation:class=\"notes\" presentation:placeholder=\"true\">\n";
++ print $OUT " <draw:text-box/>\n";
++ print $OUT " </draw:frame>\n";
++ print $OUT " </presentation:notes>\n";
++ print $OUT " </draw:page>\n";
++}
++
++sub writeFooter
++{
++ print $OUT qq~ <presentation:settings presentation:full-screen="false"/>
++ </office:presentation>
++ </office:body>
++</office:document-content>
++~;
++
++}
++
++sub writePath
++{
++ my $pathAry = pop @_;
++ my $path = $pathAry->[1];
++ my $viewBox = $pathAry->[0];
++
++ print $OUT " <draw:path draw:style-name=\"gr2\" draw:text-style-name=\"P1\" draw:layer=\"layout\" svg:width=\"10cm\" svg:height=\"10cm\" svg:x=\"5cm\" svg:y=\"5cm\" svg:viewBox=\"";
++ print $OUT $viewBox;
++ print $OUT "\" svg:d=\"";
++ print $OUT $path;
++ print $OUT "\">\n";
++ print $OUT " <text:p/>\n";
++ print $OUT " </draw:path>\n";
++}
++
++sub writeManifest
++{
++ my $outFile = open_file("META-INF/manifest.xml");
++
++ print $outFile qq~<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE manifest:manifest PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
++<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
++ <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.presentation" manifest:full-path="/"/>
++ <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
++</manifest:manifest>
++~;
++
++ $outFile->close;
++}
++
++
++###############################################################################
++# Print usage information.
++#
++sub usage ()
++{
++ print <<END_OF_USAGE;
++usage: $0 <option>* [<SvgD-values>]
++
++output-file-name defaults to polygons.odp.
++
++ -h Print this usage information.
++ -o output-file-name
++END_OF_USAGE
++}
++
++###############################################################################
++# Process the command line.
++#
++sub process_command_line
++{
++ foreach (@ARGV)
++ {
++ if (/^-h/)
++ {
++ usage;
++ exit 0;
++ }
++ }
++
++ $global_output_name = "polygons.odp";
++ my $j = 0, $noMoreOptions = 0;
++ for (my $i=0; $i<$#ARGV; $i++)
++ {
++ if ( !$noMoreOptions and $ARGV[$i] eq "-o")
++ {
++ $i++;
++ $global_output_name = $ARGV[$i];
++ }
++ elsif ( !$noMoreOptions and $ARGV[$i] eq "--")
++ {
++ $noMoreOptions = 1;
++ }
++ elsif ( !$noMoreOptions and $ARGV[$i] =~ /^-/)
++ {
++ print "Unknown option $ARGV[$i]\n";
++ usage;
++ exit 1;
++ }
++ else
++ {
++ push(@paths, [$ARGV[$i],$ARGV[$i+1]]);
++ $i++;
++ }
++ }
++
++ print "output to $global_output_name\n";
++}
++
++###############################################################################
++# Main
++###############################################################################
++
++$ZipCmd = $ENV{LOG_FILE_ZIP_CMD};
++$ZipFlags = $ENV{LOG_FILE_ZIP_FLAGS};
++# Provide default values for the zip command and it's flags.
++if ( ! defined $ZipCmd)
++{
++ $ZipCmd = "zip" unless defined $ZipCmd;
++ $ZipFlags = "-r -q" unless defined $ZipFlags;
++}
++
++process_command_line();
++
++writeManifest();
++
++$OUT = open_file( "content.xml" );
++
++writeHeader();
++
++$pathNum=0;
++foreach $path (@paths)
++{
++ writeSlideHeader($pathNum, $path->[1]);
++ writePath($path);
++ writeSlideFooter();
++ $pathNum++;
++}
++
++writeFooter();
++
++$OUT->close;
++
++zip_dirtree ($global_output_name);
++
+diff --git basegfx/source/polygon/b2dpolygon.cxx basegfx/source/polygon/b2dpolygon.cxx
+index 02a25e6..c30d070 100644
+--- basegfx/source/polygon/b2dpolygon.cxx
++++ basegfx/source/polygon/b2dpolygon.cxx
+@@ -44,38 +44,24 @@
+
+ //////////////////////////////////////////////////////////////////////////////
+
+-class CoordinateData2D
++struct CoordinateData2D : public basegfx::B2DPoint
+ {
+- basegfx::B2DPoint maPoint;
+-
+ public:
+- CoordinateData2D()
+- : maPoint()
+- {}
+-
++ CoordinateData2D() {}
++
+ explicit CoordinateData2D(const basegfx::B2DPoint& rData)
+- : maPoint(rData)
++ : B2DPoint(rData)
+ {}
+
+- const basegfx::B2DPoint& getCoordinate() const
+- {
+- return maPoint;
++ CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
++ {
++ B2DPoint::operator=(rData);
++ return *this;
+ }
+
+- void setCoordinate(const basegfx::B2DPoint& rValue)
+- {
+- if(rValue != maPoint)
+- maPoint = rValue;
+- }
+-
+- bool operator==(const CoordinateData2D& rData ) const
+- {
+- return (maPoint == rData.getCoordinate());
+- }
+-
+ void transform(const basegfx::B2DHomMatrix& rMatrix)
+ {
+- maPoint *= rMatrix;
++ *this *= rMatrix;
+ }
+ };
+
+@@ -115,12 +101,12 @@ public:
+
+ const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
+ {
+- return maVector[nIndex].getCoordinate();
++ return maVector[nIndex];
+ }
+
+ void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
+ {
+- maVector[nIndex].setCoordinate(rValue);
++ maVector[nIndex] = rValue;
+ }
+
+ void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
+@@ -221,6 +207,26 @@ public:
+ aStart->transform(rMatrix);
+ }
+ }
++
++ const basegfx::B2DPoint* begin() const
++ {
++ return &maVector.front();
++ }
++
++ const basegfx::B2DPoint* end() const
++ {
++ return &maVector[maVector.size()];
++ }
++
++ basegfx::B2DPoint* begin()
++ {
++ return &maVector.front();
++ }
++
++ basegfx::B2DPoint* end()
++ {
++ return &maVector[maVector.size()];
++ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
+@@ -1113,6 +1119,28 @@ public:
+ maPoints.transform(rMatrix);
+ }
+ }
++
++ const basegfx::B2DPoint* begin() const
++ {
++ return maPoints.begin();
++ }
++
++ const basegfx::B2DPoint* end() const
++ {
++ return maPoints.end();
++ }
++
++ basegfx::B2DPoint* begin()
++ {
++ mpBufferedData.reset();
++ return maPoints.begin();
++ }
++
++ basegfx::B2DPoint* end()
++ {
++ mpBufferedData.reset();
++ return maPoints.end();
++ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
+@@ -1173,7 +1201,7 @@ namespace basegfx
+ return mpPolygon->count();
+ }
+
+- B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
++ const B2DPoint& B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
+
+@@ -1432,7 +1460,7 @@ namespace basegfx
+ return mpPolygon->getDefaultAdaptiveSubdivision(*this);
+ }
+
+- B2DRange B2DPolygon::getB2DRange() const
++ const B2DRange& B2DPolygon::getB2DRange() const
+ {
+ return mpPolygon->getB2DRange(*this);
+ }
+@@ -1540,6 +1568,26 @@ namespace basegfx
+ mpPolygon->transform(rMatrix);
+ }
+ }
++
++ const B2DPoint* B2DPolygon::begin() const
++ {
++ return mpPolygon->begin();
++ }
++
++ const B2DPoint* B2DPolygon::end() const
++ {
++ return mpPolygon->end();
++ }
++
++ B2DPoint* B2DPolygon::begin()
++ {
++ return mpPolygon->begin();
++ }
++
++ B2DPoint* B2DPolygon::end()
++ {
++ return mpPolygon->end();
++ }
+ } // end of namespace basegfx
+
+ //////////////////////////////////////////////////////////////////////////////
+diff --git basegfx/source/polygon/b2dpolypolygon.cxx basegfx/source/polygon/b2dpolypolygon.cxx
+index 67cd079..4be35f7 100644
+--- basegfx/source/polygon/b2dpolypolygon.cxx
++++ basegfx/source/polygon/b2dpolypolygon.cxx
+@@ -166,6 +166,26 @@ public:
+ maPolygons.end(),
+ std::mem_fun_ref( &basegfx::B2DPolygon::makeUnique ));
+ }
++
++ const basegfx::B2DPolygon* begin() const
++ {
++ return &maPolygons.front();
++ }
++
++ const basegfx::B2DPolygon* end() const
++ {
++ return &maPolygons[maPolygons.size()];
++ }
++
++ basegfx::B2DPolygon* begin()
++ {
++ return &maPolygons.front();
++ }
++
++ basegfx::B2DPolygon* end()
++ {
++ return &maPolygons[maPolygons.size()];
++ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
+@@ -378,6 +398,26 @@ namespace basegfx
+ mpPolyPolygon->transform(rMatrix);
+ }
+ }
++
++ const B2DPolygon* B2DPolyPolygon::begin() const
++ {
++ return mpPolyPolygon->begin();
++ }
++
++ const B2DPolygon* B2DPolyPolygon::end() const
++ {
++ return mpPolyPolygon->end();
++ }
++
++ B2DPolygon* B2DPolyPolygon::begin()
++ {
++ return mpPolyPolygon->begin();
++ }
++
++ B2DPolygon* B2DPolyPolygon::end()
++ {
++ return mpPolyPolygon->end();
++ }
+ } // end of namespace basegfx
+
+ // eof
+diff --git basegfx/source/range/b2dmultirange.cxx basegfx/source/range/b2dmultirange.cxx
+index 738c5d1..9eb9a08 100644
+--- basegfx/source/range/b2dmultirange.cxx
++++ basegfx/source/range/b2dmultirange.cxx
+@@ -30,61 +30,1266 @@
+
+ // MARKER(update_precomp.py): autogen include statement, do not remove
+ #include "precompiled_basegfx.hxx"
++
++#include <rtl/math.hxx>
++
+ #include <basegfx/range/b2drange.hxx>
+ #include <basegfx/tuple/b2dtuple.hxx>
+ #include <basegfx/polygon/b2dpolypolygon.hxx>
+ #include <basegfx/range/b2dmultirange.hxx>
+ #include <basegfx/polygon/b2dpolygontools.hxx>
+ #include <basegfx/polygon/b2dpolypolygontools.hxx>
+-#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
++
+ #include <boost/bind.hpp>
+ #include <boost/mem_fn.hpp>
++#include <boost/scoped_ptr.hpp>
++
+ #include <algorithm>
+ #include <vector>
++#include <deque>
++#include <list>
+
+
+ namespace basegfx
+ {
++ namespace
++ {
++ // Generating a poly-polygon from a bunch of rectangles
++ //
++ // Helper functionality for sweep-line algorithm
++ // ====================================================
++
++ typedef std::vector<B2DRange> VectorOfRanges;
++
++ class ImplPolygon;
++ typedef std::vector<ImplPolygon> VectorOfPolygons;
++
++
++ /** This class represents an active edge
++
++ As the sweep line traverses across the overall area,
++ rectangle edges parallel to it generate events, and
++ rectangle edges orthogonal to it generate active
++ edges. This class represents the latter.
++ */
++ class ActiveEdge
++ {
++ public:
++ /** The two possible active rectangle edges differ by one
++ coordinate value - the proximal edge has the lower, the
++ distal edge the higher value.
++ */
++ enum EdgeType {
++ /// edge with lower coordinate value
++ PROXIMAL=0,
++ /// edge with higher coordinate value
++ DISTAL=1
++ };
++
++ /** Create active edge
++
++ @param rRect
++ Rectangle this edge is part of
++
++ @param fInvariantCoord
++ The invariant ccordinate value of this edge
++
++ @param eEdgeType
++ Is fInvariantCoord the lower or the higher value, for
++ this rect?
++ */
++ ActiveEdge( const B2DRectangle& rRect,
++ const double& fInvariantCoord,
++ ImplPolygon& rPolygon,
++ EdgeType eEdgeType ) :
++ mfInvariantCoord(fInvariantCoord),
++ mpAssociatedRect( &rRect ),
++ mpPolygon( &rPolygon ),
++ meEdgeType( eEdgeType )
++ {}
++
++ double getInvariantCoord() const { return mfInvariantCoord; }
++ const B2DRectangle& getRect() const { return *mpAssociatedRect; }
++ ImplPolygon& getTargetPolygon() const { return *mpPolygon; }
++ void setTargetPolygon( ImplPolygon& rPolygon ) { mpPolygon = &rPolygon; }
++ EdgeType getEdgeType() const { return meEdgeType; }
++
++ /// For STL sort
++ bool operator<( const ActiveEdge& rRHS ) const { return mfInvariantCoord < rRHS.mfInvariantCoord; }
++
++ private:
++ /** The invariant coordinate value of this edge (e.g. the
++ common y value, for a horizontal edge)
++ */
++ double mfInvariantCoord;
++
++ /** Associated rectangle
++
++ This on the one hand saves some storage space (the
++ vector of rectangles is persistent, anyway), and on
++ the other hand provides an identifier to match active
++ edges and x events (see below)
++
++ Ptr because class needs to be assignable
++ */
++ const B2DRectangle* mpAssociatedRect;
++
++ /** Pointer to the polygon this edge is currently involved
++ with.
++
++ Note that this can change for some kinds of edge
++ intersection, as the algorithm tends to swap
++ associated polygons there.
++
++ Must never be NULL, pointer here to keep class
++ assignable
++ */
++ ImplPolygon* mpPolygon;
++
++ /// 'upper' or 'lower' edge of original rectangle.
++ EdgeType meEdgeType;
++ };
++
++ // Needs to be list - various places hold ptrs to elements
++ typedef std::list< ActiveEdge > ListOfEdges;
++
++
++ /** Element of the sweep line event list
++
++ As the sweep line traverses across the overall area,
++ rectangle edges parallel to it generate events, and
++ rectangle edges orthogonal to it generate active
++ edges. This class represents the former.
++
++ The class defines an element of the sweep line list. The
++ sweep line's position jumps in steps defined by the
++ coordinates of the sorted SweepLineEvent entries.
++ */
++ class SweepLineEvent
++ {
++ public:
++ /** The two possible sweep line rectangle edges differ by
++ one coordinate value - the proximal edge has the
++ lower, the distal edge the higher value.
++ */
++ enum EdgeType {
++ /// edge with lower coordinate value
++ PROXIMAL=0,
++ /// edge with higher coordinate value
++ DISTAL=1
++ };
++
++ /** Create sweep line event
++
++ @param fPos
++ Coordinate position of the event
++
++ @param rRect
++ Rectangle this event is generated for.
++
++ @param eEdgeType
++ Is fPos the lower or the higher value, for the
++ rectangle this event is generated for?
++ */
++ SweepLineEvent( double fPos,
++ const B2DRectangle& rRect,
++ EdgeType eEdgeType ) :
++ mfPos( fPos ),
++ mpAssociatedRect( &rRect ),
++ meEdgeType( eEdgeType )
++ {}
++
++ double getPos() const { return mfPos; }
++ const B2DRectangle& getRect() const { return *mpAssociatedRect; }
++ EdgeType getEdgeType() const { return meEdgeType; }
++
++ /// For STL sort
++ bool operator<( const SweepLineEvent& rRHS ) const { return mfPos < rRHS.mfPos; }
++
++ private:
++ /// position of the event, in the direction of the line sweep
++ double mfPos;
++
++ /** Rectangle this event is generated for
++
++ This on the one hand saves some storage space (the
++ vector of rectangles is persistent, anyway), and on
++ the other hand provides an identifier to match active
++ edges and events (see below)
++
++ Ptr because class needs to be assignable
++ */
++ const B2DRectangle* mpAssociatedRect;
++
++ /// 'upper' or 'lower' edge of original rectangle.
++ EdgeType meEdgeType;
++ };
++
++ typedef std::vector< SweepLineEvent > VectorOfEvents;
++
++
++ /** Smart point container for B2DMultiRange::getPolyPolygon()
++
++ This class provides methods needed only here, and is used
++ as a place to store some additional information per
++ polygon. Also, most of the intersection logic is
++ implemented here.
++ */
++ class ImplPolygon
++ {
++ public:
++ /** Create polygon
++ */
++ ImplPolygon() :
++ maPoints(),
++ mnContainmentCount( 0 ),
++ mpLeadingEdge( NULL ),
++ mpTrailingEdge( NULL ),
++ mbIsFinished( false )
++ {
++ // initially, no associated edges are known (will be
++ // added when we intersect one)
++ }
++
++ /** Perform the intersection of this polygon with an
++ active edge.
++
++ @rPolygonVector
++ Container to retrieve new polygons from
++
++ @param rEvent
++ The vertical line event that generated the
++ intersection
++
++ @param rActiveEdge
++ The active edge that generated the intersection
++
++ @return the new current polygon (that's the one
++ processing must proceed with, when going through the
++ list of distal active edges).
++ */
++ ImplPolygon& intersect( VectorOfPolygons& rPolygonVector,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rActiveEdge )
++ {
++ OSL_PRECOND( !isFinished(),
++ "ImplPolygon::intersect(): called on already finished polygon!" );
++
++ const B2DPoint aIntersectionPoint( rEvent.getPos(),
++ rActiveEdge.getInvariantCoord() );
++
++ // dispatch according to vert and horiz edge
++ // directions.
++ // -----------------------------------------
++
++ if( rActiveEdge.getEdgeType() == ActiveEdge::PROXIMAL )
++ {
++ if( rEvent.getEdgeType() == SweepLineEvent::PROXIMAL )
++ return intersectionUpperLeft( rPolygonVector,
++ rEvent,
++ rActiveEdge,
++ aIntersectionPoint );
++ else
++ return intersectionUpperRight( rPolygonVector,
++ rEvent,
++ rActiveEdge,
++ aIntersectionPoint );
++ }
++ else
++ {
++ if( rEvent.getEdgeType() == SweepLineEvent::PROXIMAL )
++ return intersectionLowerLeft( rPolygonVector,
++ rEvent,
++ rActiveEdge,
++ aIntersectionPoint );
++ else
++ return intersectionLowerRight( rPolygonVector,
++ rEvent,
++ rActiveEdge,
++ aIntersectionPoint );
++ }
++ }
++
++ /// Return finished state
++ bool isFinished() const
++ {
++ return mbIsFinished;
++ }
++
++ sal_Int32 getContainmentCount() const
++ {
++ return mnContainmentCount;
++ }
++
++ /// Retrieve B2DPolygon from this object
++ B2DPolygon getPolygon() const
++ {
++ B2DPolygon aRes;
++
++ std::for_each( maPoints.begin(),
++ maPoints.end(),
++ boost::bind(
++ &B2DPolygon::append,
++ boost::ref(aRes),
++ _1,
++ 1 ) );
++
++ if( isFinished() )
++ aRes.setClosed( true );
++
++ return aRes;
++ }
++
++
++ private:
++ std::size_t count() const
++ {
++ return maPoints.size();
++ }
++
++ /// Add point to the end of the existing points
++ void append( const B2DPoint& rPoint )
++ {
++ OSL_PRECOND( maPoints.empty() ||
++ maPoints.back().getX() == rPoint.getX() ||
++ maPoints.back().getY() == rPoint.getY(),
++ "ImplPolygon::append(): added point violates 90 degree line angle constraint!" );
++
++ if( maPoints.empty() ||
++ maPoints.back() != rPoint )
++ {
++ // avoid duplicate points
++ maPoints.push_back( rPoint );
++ }
++ }
++
++ /// Add point to the beginning of the existing points
++ void prepend( const B2DPoint& rPoint )
++ {
++ OSL_PRECOND( maPoints.empty() ||
++ maPoints.front().getX() == rPoint.getX() ||
++ maPoints.front().getY() == rPoint.getY(),
++ "ImplPolygon::prepend(): added point violates 90 degree line angle constraint!" );
++
++ if( maPoints.empty() ||
++ maPoints.front() != rPoint )
++ {
++ maPoints.push_front( rPoint );
++ }
++ }
++
++ /** Set finished state to true
++
++ A polygon is finished, if no further points will ever
++ be added to it.
++ */
++ void finish()
++ {
++ OSL_PRECOND( maPoints.empty() ||
++ maPoints.front().getX() == maPoints.back().getX() ||
++ maPoints.front().getY() == maPoints.back().getY(),
++ "ImplPolygon::finish(): first and last point violate 90 degree line angle constraint!" );
++
++ mbIsFinished = true;
++
++ // clear mutual edge references
++ mpLeadingEdge = NULL;
++ mpTrailingEdge = NULL;
++ }
++
++ /** Adapt containment count.
++
++ @param nNewValue
++ */
++ void setContainment( sal_Int32 nValue )
++ {
++ mnContainmentCount = nValue;
++ }
++
++ /// Swap edges with given polygon
++ void swapEdges( ImplPolygon& rPoly,
++ ActiveEdge*& rEdgeReference,
++ ActiveEdge*& rPolyEdgeReference )
++ {
++ // swap active edges
++ std::swap( rEdgeReference,
++ rPolyEdgeReference );
++
++ // swapped references to edges - also have to adapt
++ // reverse relationship, aka back references at the
++ // edges (note that rPoly.mpLowerActiveEdge now points
++ // to this->mpLowerActiveEdge and vice versa)
++ if( rPolyEdgeReference != NULL )
++ rPolyEdgeReference->setTargetPolygon( rPoly );
++ if( rEdgeReference != NULL )
++ rEdgeReference->setTargetPolygon( *this );
++ }
++
++ /// Swap leading edges with given polygon
++ void swapLeadingEdges( ImplPolygon& rPoly )
++ {
++ swapEdges( rPoly,
++ mpLeadingEdge,
++ rPoly.mpLeadingEdge );
++ }
++
++ /// Swap upper edges with given polygon
++ void swapTrailingEdges( ImplPolygon& rPoly )
++ {
++ swapEdges( rPoly,
++ mpTrailingEdge,
++ rPoly.mpTrailingEdge );
++ }
++
++ /// Clear all points
++ void clear()
++ {
++ maPoints.clear();
++ }
++
++ bool verifyMutualReferences() const
++ {
++ return ( (!mpLeadingEdge ||
++ &mpLeadingEdge->getTargetPolygon() == this ) &&
++ (!mpTrailingEdge ||
++ &mpTrailingEdge->getTargetPolygon() == this ) );
++ }
++
++ bool verifyEdgeReferences( const ActiveEdge& rEdge ) const
++ {
++ return ( (mpLeadingEdge == &rEdge ||
++ mpTrailingEdge == &rEdge) &&
++ mpLeadingEdge != mpTrailingEdge );
++ }
++
++ /** Perform an intersection of two polygons at the upper,
++ left corner of the associated rectangle
++
++ @param rPoly
++ The other polygon involved in this intersection
++
++ @param rIntersection
++ The intersection point
++
++ @return the new current polygon
++ */
++ ImplPolygon& intersectionUpperLeft( VectorOfPolygons& rPolygonVector,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rActiveEdge,
++ const B2DPoint& rIntersection )
++ {
++ OSL_PRECOND( rEvent.getEdgeType() == SweepLineEvent::PROXIMAL &&
++ rActiveEdge.getEdgeType() == ActiveEdge::PROXIMAL,
++ "ImplPolygon::intersectionUpperLeft(): don't call me!" );
++ OSL_PRECOND( mpLeadingEdge == NULL,
++ "ImplPolygon::intersectionUpperLeft(): leading edge != NULL!" );
++
++ ImplPolygon& rEdgeTargetPoly = rActiveEdge.getTargetPolygon();
++ if( &rActiveEdge.getRect() == &rEvent.getRect() )
++ {
++ // #1.1
++ OSL_ENSURE( count() == 0 &&
++ mpTrailingEdge == NULL,
++ "ImplPolygon::intersectionUpperLeft(): Virgin edge gets added to non-empty polygon!" );
++
++ append( rIntersection );
++
++ // init edge<->polygon mutual references
++ rActiveEdge.setTargetPolygon( *this );
++ mpTrailingEdge = &rActiveEdge;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionUpperLeft(): case #1" );
++
++ return *this;
++ }
++ else
++ {
++ OSL_ENSURE( rEdgeTargetPoly.mpTrailingEdge != NULL,
++ "ImplPolygon::intersectionUpperLeft(): Edge poly has empty trailing edge!" );
++ OSL_ENSURE( mpTrailingEdge != NULL,
++ "ImplPolygon::intersectionUpperLeft(): Trailing edge not set!" );
++
++ if( &rEdgeTargetPoly == this )
++ {
++ // #1.2
++
++ // closing 'hole' polygon
++ append( rIntersection );
++ finish();
++
++ // now, generate fresh polygon, and setup
++ rPolygonVector.push_back( ImplPolygon() );
++
++ ImplPolygon& rCurrPoly( rPolygonVector.back() );
++ rCurrPoly.append( rIntersection );
++ rCurrPoly.setContainment( mnContainmentCount + 1 );
++
++ // and setup mutual references on edge and polygon
++ rActiveEdge.setTargetPolygon( rCurrPoly );
++ rCurrPoly.mpTrailingEdge = &rActiveEdge;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ rCurrPoly.verifyMutualReferences() &&
++ rCurrPoly.verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionUpperLeft(): case #2" );
++
++ return rCurrPoly;
++ }
++ else
++ {
++ // #1.3
++
++ // interpose intersection point between our existing
++ // points and the to-be-appended ones
++ append( rIntersection );
++
++ std::for_each( rEdgeTargetPoly.maPoints.begin(),
++ rEdgeTargetPoly.maPoints.end(),
++ boost::bind(
++ &ImplPolygon::append,
++ this,
++ _1 ) );
++
++ rEdgeTargetPoly.clear();
++ rEdgeTargetPoly.append( rIntersection );
++ rEdgeTargetPoly.setContainment( rEdgeTargetPoly.mnContainmentCount + 1 );
++
++ // swap edges with rPoly
++ swapLeadingEdges( rEdgeTargetPoly );
++
++ OSL_POSTCOND( verifyMutualReferences(),
++ "ImplPolygon::intersectionUpperLeft(): case #3 verifyMutualReferences" );
++ OSL_POSTCOND( rEdgeTargetPoly.verifyMutualReferences(),
++ "ImplPolygon::intersectionUpperLeft(): case #3 target->verifyMutualReferences" );
++ OSL_POSTCOND( rEdgeTargetPoly.verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionUpperLeft(): case #3 target->verifyEdgeReferences" );
++
++ return rEdgeTargetPoly;
++ }
++ }
++ }
++
++ /** Perform an intersection of two polygons at the lower,
++ left corner of the associated rectangle
++
++ @param rPoly
++ The other polygon involved in this intersection
++
++ @param rIntersection
++ The intersection point
++
++ @return the new current polygon
++ */
++ ImplPolygon& intersectionLowerLeft( VectorOfPolygons& /*rPolygonVector*/,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rActiveEdge,
++ const B2DPoint& rIntersection )
++ {
++ OSL_PRECOND( rEvent.getEdgeType() == SweepLineEvent::PROXIMAL &&
++ rActiveEdge.getEdgeType() == ActiveEdge::DISTAL,
++ "ImplPolygon::intersectionLowerLeft(): don't call me!" );
++ OSL_PRECOND( mpLeadingEdge == NULL,
++ "ImplPolygon::intersectionLowerLeft(): leading edge != NULL!" );
++
++ ImplPolygon& rEdgeTargetPoly = rActiveEdge.getTargetPolygon();
++ if( &rActiveEdge.getRect() == &rEvent.getRect() )
++ {
++ // #3.1
++ OSL_ENSURE( count() != 0 &&
++ mpTrailingEdge != NULL,
++ "ImplPolygon::intersectionLowerLeft(): Virgin edge gets added to non-empty polygon!" );
++
++ append( rIntersection );
++
++ // init edge<->polygon mutual references
++ rActiveEdge.setTargetPolygon( *this );
++ mpLeadingEdge = &rActiveEdge;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionLowerLeft(): case #1" );
++
++ return *this;
++ }
++ else
++ {
++ // #3.2
++ OSL_ENSURE( rEdgeTargetPoly.mpLeadingEdge != NULL &&
++ rEdgeTargetPoly.mpTrailingEdge != NULL,
++ "ImplPolygon::intersectionLowerLeft(): Edge poly has one or more finished edges!" );
++ OSL_ENSURE( &rEdgeTargetPoly != this,
++ "ImplPolygon::intersectionLowerLeft(): intersection with myself!" );
++ OSL_ENSURE( mpTrailingEdge != NULL,
++ "ImplPolygon::intersectionLowerLeft(): Trailing edge not set!" );
++
++ // append intersection point to both polygons
++ append( rIntersection );
++ rEdgeTargetPoly.append( rIntersection );
++
++ // swap edges with rPoly
++ swapLeadingEdges( rEdgeTargetPoly );
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ rEdgeTargetPoly.verifyMutualReferences() &&
++ verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionLowerLeft(): case #2" );
++
++ return rEdgeTargetPoly;
++ }
++ }
++
++ /** Perform an intersection of two polygons at the upper,
++ right corner of the associated rectangle
++
++ @param rPoly
++ The other polygon involved in this intersection
++
++ @param rIntersection
++ The intersection point
++
++ @return the new current polygon
++ */
++ ImplPolygon& intersectionUpperRight( VectorOfPolygons& /*rPolygonVector*/,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rActiveEdge,
++ const B2DPoint& rIntersection )
++ {
++ (void)rEvent;
++ OSL_PRECOND( rEvent.getEdgeType() == SweepLineEvent::DISTAL &&
++ rActiveEdge.getEdgeType() == ActiveEdge::PROXIMAL,
++ "ImplPolygon::intersectionUpperRight(): don't call me!" );
++ OSL_PRECOND( count() != 0,
++ "ImplPolygon::intersectionUpperRight(): Upper edge is empty!" );
++
++ ImplPolygon& rEdgeTargetPoly = rActiveEdge.getTargetPolygon();
++ if( &rEdgeTargetPoly == this )
++ {
++ // #2.1
++
++ // first hit at all - the horizonal edge the
++ // vertical event is starting with
++
++ // this MUST be our own upper edge, then.
++ OSL_ENSURE( &rActiveEdge.getRect() == &rEvent.getRect() &&
++ mpTrailingEdge == &rActiveEdge,
++ "ImplPolygon::intersectionUpperRight(): Own upper edge is inconsistent!" );
++
++ prepend( rIntersection );
++
++ mpTrailingEdge = NULL;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ mpLeadingEdge != &rActiveEdge,
++ "ImplPolygon::intersectionUpperRight(): case #1" );
++
++ return *this;
++ }
++ else
++ {
++ // #2.2
++
++ OSL_ENSURE( mpTrailingEdge == NULL,
++ "ImplPolygon::intersectionUpperRight(): Trailing edge not NULL!" );
++
++ // insert intersection point to both polygons
++ prepend( rIntersection );
++ rEdgeTargetPoly.prepend( rIntersection );
++
++ // swap current edge to this polygon (vert edge will
++ // proceed with rPoly)
++ swapTrailingEdges( rEdgeTargetPoly );
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ rEdgeTargetPoly.verifyMutualReferences() &&
++ verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionUpperRight(): case #2" );
++
++ return rEdgeTargetPoly;
++ }
++ }
++
++ /** Perform an intersection of two polygons at the lower,
++ right corner of the associated rectangle
++
++ @param rPoly
++ The other polygon involved in this intersection
++
++ @param rIntersection
++ The intersection point
++
++ @return the new current polygon
++ */
++ ImplPolygon& intersectionLowerRight( VectorOfPolygons& rPolygonVector,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rActiveEdge,
++ const B2DPoint& rIntersection )
++ {
++ (void)rEvent;
++ OSL_PRECOND( rEvent.getEdgeType() == SweepLineEvent::DISTAL &&
++ rActiveEdge.getEdgeType() == ActiveEdge::DISTAL,
++ "ImplPolygon::intersectionLowerRight(): don't call me!" );
++ OSL_PRECOND( count() != 0,
++ "ImplPolygon::intersectionLowerRight(): Upper edge is empty!" );
++ OSL_ENSURE( mpTrailingEdge == NULL,
++ "ImplPolygon::intersectionLowerRight(): Trailing edge not NULL!" );
++
++ ImplPolygon& rEdgeTargetPoly = rActiveEdge.getTargetPolygon();
++ if( &rEdgeTargetPoly == this )
++ {
++ // #4.1
++
++ // finish current polygon, and create a new one
++ prepend( rIntersection );
++ finish();
++
++ // now, generate fresh polygon, and setup
++ rPolygonVector.push_back( ImplPolygon() );
++
++ ImplPolygon& rCurrPoly( rPolygonVector.back() );
++ rCurrPoly.append( rIntersection );
++ rCurrPoly.setContainment( mnContainmentCount - 1 );
++
++ // and setup mutual references on edge and polygon
++ rActiveEdge.setTargetPolygon( rCurrPoly );
++ rCurrPoly.mpLeadingEdge = &rActiveEdge;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ rCurrPoly.verifyMutualReferences() &&
++ rCurrPoly.verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionLowerRight(): case #1" );
++
++ return rCurrPoly;
++ }
++ else
++ {
++ // #4.2
++
++ // interpose intersection point between our existing
++ // points and the to-be-prepended ones
++ rEdgeTargetPoly.append( rIntersection );
++
++ // Subtlety: using reverse iterator on rPoly.maPoints
++ // here, to maintain correct ordering in polygon
++ std::for_each( maPoints.begin(),
++ maPoints.end(),
++ boost::bind(
++ &ImplPolygon::append,
++ &rEdgeTargetPoly,
++ _1 ) );
++
++ clear();
++ append( rIntersection );
++ setContainment( rEdgeTargetPoly.mnContainmentCount - 1 );
++
++ // swap edges with rPoly
++ rEdgeTargetPoly.mpLeadingEdge = mpLeadingEdge;
++ rEdgeTargetPoly.mpLeadingEdge->setTargetPolygon( rEdgeTargetPoly );
++ mpLeadingEdge = &rActiveEdge;
++ rActiveEdge.setTargetPolygon( *this );
++ mpTrailingEdge = NULL;
++
++ OSL_POSTCOND( verifyMutualReferences() &&
++ rEdgeTargetPoly.verifyMutualReferences() &&
++ verifyEdgeReferences( rActiveEdge ),
++ "ImplPolygon::intersectionLowerRight(): case #2" );
++
++ return *this;
++ }
++ }
++
++
++ /// Container for the actual polygon points
++ std::deque<B2DPoint> maPoints;
++
++ /** Number of polygons this one is contained within.
++
++ A polygon that is contained in no other polygon has a
++ 0 here. A polygon that is contained in another
++ polygon, but has reversed winding (a 'hole') has the
++ same containment count as its surrounding
++ polygon. Thus, when filtering for containment number,
++ holes will be selected along with their surrounding
++ polygons.
++ */
++ sal_Int32 mnContainmentCount;
++
++ /** Refers to the current leading edge element of this
++ polygon, or NULL. The leading edge denotes the 'front'
++ of the polygon vertex sequence, i.e. the coordinates
++ at the polygon's leading edge are returned from
++ maPoints.front()
++ */
++ ActiveEdge* mpLeadingEdge;
++
++ /** Refers to the current trailing edge element of this
++ polygon, or NULL. The trailing edge denotes the 'back'
++ of the polygon vertex sequence, i.e. the coordinates
++ at the polygon's trailing edge are returned from
++ maPoints.back()
++ */
++ ActiveEdge* mpTrailingEdge;
++
++ /// When true, this polygon is 'done', i.e. nothing must be added anymore.
++ bool mbIsFinished;
++ };
++
++
++ /** Prune given container from elements the 'filter' functor
++ yields true upon; exit from processing when 'pred'
++ predicate becomes true
++ */
++ template<typename Container, typename Filter, typename Predicate>
++ inline void prune_until( Container& container,
++ Filter filter,
++ Predicate pred )
++ {
++ typename Container::iterator first=container.begin();
++ const typename Container::iterator last=container.end();
++ while( first != last )
++ {
++ const bool bExit=pred(*first);
++ if( filter(*first) )
++ first = container.erase(first);
++ else
++ ++first;
++
++ if( bExit )
++ return;
++ }
++ }
++
++ /** Init sweep line event list
++
++ This method fills the event list with the sweep line
++ events generated from the input rectangles, and sorts them
++ with increasing x.
++ */
++ void setupSweepLineEventListFromRanges( VectorOfEvents& o_rEventVector,
++ const VectorOfRanges& rVectorOfRectangles )
++ {
++ // we need exactly 2*rectVec.size() events: one for the
++ // left, and one for the right edge of each rectangle
++ o_rEventVector.clear();
++ o_rEventVector.reserve( 2*rVectorOfRectangles.size() );
++
++ // generate events
++ // ===============
++
++ // first pass: add all left edges in increasing order
++ VectorOfRanges::const_iterator aCurrRect( rVectorOfRectangles.begin() );
++ const VectorOfRanges::const_iterator aEndRects( rVectorOfRectangles.end() );
++ for( ; aCurrRect != aEndRects; ++aCurrRect )
++ {
++ const B2DRectangle& rCurrRect( *aCurrRect );
++
++ o_rEventVector.push_back(
++ SweepLineEvent( rCurrRect.getMinX(),
++ rCurrRect,
++ SweepLineEvent::PROXIMAL ) );
++ }
++
++ // second pass: add all right edges in reversed order
++ VectorOfRanges::const_reverse_iterator aCurrRectRev( rVectorOfRectangles.rbegin() );
++ const VectorOfRanges::const_reverse_iterator aEndRectsRev( rVectorOfRectangles.rend() );
++ for( ; aCurrRectRev != aEndRectsRev; ++aCurrRectRev )
++ {
++ const B2DRectangle& rCurrRect( *aCurrRectRev );
++
++ o_rEventVector.push_back(
++ SweepLineEvent( rCurrRect.getMaxX(),
++ rCurrRect,
++ SweepLineEvent::DISTAL ) );
++ }
++
++ // sort events
++ // ===========
++
++ // since we use stable_sort, the order of events with the
++ // same x value will not change. The elaborate two-pass
++ // add above thus ensures, that for each two rectangles
++ // with similar left and right x coordinates, the
++ // rectangle whose left event comes first will have its
++ // right event come last. This is advantageous for the
++ // clip algorithm below, see handleRightEdgeCrossing().
++
++ // TODO(P3): Use radix sort (from
++ // b2dpolypolygonrasterconverter, or have your own
++ // templatized version).
++ std::stable_sort( o_rEventVector.begin(),
++ o_rEventVector.end() );
++ }
++
++ /** Insert two active edge segments for the given rectangle.
++
++ This method creates two active edge segments from the
++ given rect, and inserts them into the active edge list,
++ such that this stays sorted (if it was before).
++
++ @param io_rEdgeList
++ Active edge list to insert into
++
++ @param io_rPolygons
++ Vector of polygons. Each rectangle added creates one
++ tentative result polygon in this vector, and the edge list
++ entries holds a reference to that polygon (this _requires_
++ that the polygon vector does not reallocate, i.e. it must
++ have at least the maximal number of rectangles reserved)
++
++ @param o_CurrentPolygon
++ The then-current polygon when processing this sweep line
++ event
++
++ @param rCurrEvent
++ The actual event that caused this call
++ */
++ void createActiveEdgesFromEvent( ListOfEdges& io_rEdgeList,
++ VectorOfPolygons& io_rGeneratedPolygons,
++ ImplPolygon*& o_pCurrentPolygon,
++ SweepLineEvent& rCurrEvent )
++ {
++ ListOfEdges aNewEdges;
++ const B2DRectangle& rRect=rCurrEvent.getRect();
++
++ // init current polygon for vertical edge point output,
++ // we're just generating upper and lower edges for it
++ io_rGeneratedPolygons.push_back( ImplPolygon() );
++ o_pCurrentPolygon = &io_rGeneratedPolygons.back();
++
++ // the new active edges
++ aNewEdges.push_back(
++ ActiveEdge(
++ rRect,
++ rRect.getMinY(),
++ io_rGeneratedPolygons.back(),
++ ActiveEdge::PROXIMAL ) );
++ aNewEdges.push_back(
++ ActiveEdge(
++ rRect,
++ rRect.getMaxY(),
++ io_rGeneratedPolygons.back(),
++ ActiveEdge::DISTAL ) );
++
++ // furthermore, have to respect a special tie-breaking
++ // rule here, for edges which share the same y value:
++ // newly added upper edges must be inserted _before_ any
++ // other edge with the same y value, and newly added lower
++ // edges must be _after_ all other edges with the same
++ // y. This ensures that the left vertical edge processing
++ // below encounters the upper edge of the current rect
++ // first, and the lower edge last, which automatically
++ // starts and finishes this rect correctly (as only then,
++ // the polygon will have their associated active edges
++ // set).
++ const double nMinY( rRect.getMinY() );
++ const double nMaxY( rRect.getMaxY() );
++ ListOfEdges::iterator aCurr( io_rEdgeList.begin() );
++ const ListOfEdges::iterator aEnd ( io_rEdgeList.end() );
++ while( aCurr != aEnd )
++ {
++ const double nCurrY( aCurr->getInvariantCoord() );
++
++ if( nCurrY >= nMinY &&
++ aNewEdges.size() == 2 ) // only add, if not yet done.
++ {
++ // insert upper edge _before_ aCurr. Thus, it will
++ // be the first entry for a range of equal y
++ // values. Using splice here, since we hold
++ // references to the moved list element!
++ io_rEdgeList.splice( aCurr,
++ aNewEdges,
++ aNewEdges.begin() );
++ }
++
++ if( nCurrY > nMaxY )
++ {
++ // insert lower edge _before_ aCurr. Thus, it will
++ // be the last entry for a range of equal y values
++ // (aCurr is the first entry strictly larger than
++ // nMaxY). Using splice here, since we hold
++ // references to the moved list element!
++ io_rEdgeList.splice( aCurr,
++ aNewEdges,
++ aNewEdges.begin() );
++ // done with insertion, can early-exit here.
++ return;
++ }
++
++ ++aCurr;
++ }
++
++ // append remainder of aNewList (might still contain 2 or
++ // 1 elements, depending of the contents of io_rEdgeList).
++ io_rEdgeList.splice( aCurr,
++ aNewEdges );
++ }
++
++ /** Intersection predicate for active edge segments
++
++ The check is inclusive, i.e. if rEdge's y coordinate is
++ equal to one of the given vertical edge bounds, the
++ predicate still returns true.
++
++ @return true, if the given active edge is intersected
++ by the sweep line edge.
++ */
++ inline bool intersects( const ActiveEdge& rEdge,
++ const double fRectProximalValue,
++ const double fRectDistalValue )
++ {
++ const double nEdgeY( rEdge.getInvariantCoord() );
++
++ return (nEdgeY >= fRectProximalValue &&
++ nEdgeY <= fRectDistalValue );
++ }
++
++ /** Handle crossing of a right, vertical edge with horizontal
++ edges.
++
++ @param rPolygonVector
++ Vector of polygons, for which rCurrPoly is a member of.
++
++ @param pCurrPoly
++ Pointer to the polygon the current vertical edge currently
++ adds points to (or NULL, then the polygon will be taken
++ from the edge we're intersecting).
++
++ @param nX
++ X coordinate of the vertical edge
++
++ @param rEdge
++ Horizontal edge that is crossed.
++
++ @return the pointer to the new currently active polygon
++ for the vertical edge (might differ from rCurrPoly, if we
++ jumped to another branch because of the
++ intersection). Might even get NULL, if the current polygon
++ gets finished by the intersecting edge.
++ */
++ ImplPolygon& handleRightEdgeCrossing( VectorOfPolygons& rPolygonVector,
++ ImplPolygon* pCurrPoly,
++ const SweepLineEvent& rEvent,
++ ActiveEdge& rEdge )
++ {
++ ImplPolygon& rEdgePoly( rEdge.getTargetPolygon() );
++
++ OSL_ENSURE( rEdge.getRect().getMaxX() >= rEvent.getPos(),
++ "handleRightEdgeCrossing(): end point left of current X!" );
++
++ // set current polygon to edge polygon, if not yet
++ // setup. This happens for the very first horizontal line
++ // intersected for a given vertical line event (because
++ // there's no other natural initial polygon)
++ if( pCurrPoly==NULL )
++ pCurrPoly = &rEdgePoly;
++
++ OSL_ENSURE( !pCurrPoly->isFinished(),
++ "handleRightEdgeCrossing(): encountered already finished polygon!" );
++ OSL_ENSURE( !rEdgePoly.isFinished(),
++ "handleRightEdgeCrossing(): encountered already finished polygon!" );
++
++ return pCurrPoly->intersect( rPolygonVector,
++ rEvent,
++ rEdge );
++ }
++
++ inline void handleStartingEdge( ActiveEdge& rEdge,
++ const double nVertEdgeStartY,
++ const double nVertEdgeEndY,
++ ImplPolygon*& pCurrPolygon,
++ VectorOfPolygons& rGeneratedPolygons,
++ SweepLineEvent& rCurrEvent )
++ {
++ // fast-forward to our newly generated
++ // upper edge - which is guaranteed to be
++ // the first of all horizontal edges with
++ // the same value.
++ if( intersects( rEdge,
++ nVertEdgeStartY,
++ nVertEdgeEndY ) )
++ {
++ pCurrPolygon = &pCurrPolygon->intersect( rGeneratedPolygons,
++ rCurrEvent,
++ rEdge );
++ }
++ }
++
++ inline bool handleEndingEdge( ActiveEdge& rEdge,
++ const double nVertEdgeStartY,
++ const double nVertEdgeEndY,
++ ImplPolygon*& pCurrPolygon,
++ VectorOfPolygons& rGeneratedPolygons,
++ SweepLineEvent& rCurrEvent )
++ {
++ // true, if aCurrActiveEdge and aCurrEvent
++ // intersect
++ const bool bIntersection( intersects( rEdge,
++ nVertEdgeStartY,
++ nVertEdgeEndY ) );
++
++ // true, if aCurrActiveEdge is either upper
++ // or lower edge of aCurrEvent's
++ // associated rectangle or right
++ const bool bOwnEdge( &rEdge.getRect() == &rCurrEvent.getRect() );
++
++ // skip intersections, if we've not yet
++ // hit aCurrEvent's own horizontal
++ // edge. This is kind of a tie-break: the
++ // horizontal edge elements are sorted
++ // such that new rectangles will always
++ // start outside of other rectangles, that
++ // have the same y value. Thus, on the
++ // right edge, we of course must not
++ // intersect with edges above us, which we
++ // did not intersect with on the left edge
++ // (uh, a drawing would help here...).
++ if( bIntersection &&
++ (pCurrPolygon || bOwnEdge) )
++ {
++ // right vertical edge crossing
++ pCurrPolygon = &handleRightEdgeCrossing(
++ rGeneratedPolygons,
++ pCurrPolygon,
++ rCurrEvent,
++ rEdge );
++ }
++
++ return bOwnEdge;
++ }
++
++ inline bool isOwnDistalEdge( ActiveEdge& rEdge,
++ SweepLineEvent& rCurrEvent )
++ {
++ // true, if aCurrActiveEdge is either upper
++ // or lower edge of aCurrEvent's
++ // associated rectangle or right
++ const bool bOwnEdge( &rEdge.getRect() == &rCurrEvent.getRect() );
++ const bool bIsDistalEdge( rEdge.getEdgeType() == ActiveEdge::DISTAL );
++
++ return bOwnEdge && bIsDistalEdge;
++ }
++
++ void handleSweepLineEvent( SweepLineEvent& rCurrEvent,
++ ListOfEdges& rActiveEdgeList,
++ VectorOfPolygons& rGeneratedPolygons )
++ {
++ ImplPolygon* pCurrPolygon(NULL);
++
++ const double nVertEdgeStartY( rCurrEvent.getRect().getMinY() );
++ const double nVertEdgeEndY ( rCurrEvent.getRect().getMaxY() );
++ const bool bIsStartingEdge( rCurrEvent.getEdgeType() == SweepLineEvent::PROXIMAL );
++
++ // Add two new active edges, if this is the starting edge
++ // of a rectangle
++ if( bIsStartingEdge )
++ createActiveEdgesFromEvent( rActiveEdgeList,
++ rGeneratedPolygons,
++ pCurrPolygon,
++ rCurrEvent );
++
++ OSL_ENSURE( !rActiveEdgeList.empty(),
++ "B2DMultiRange::getPolyPolygon(): empty edge list, "
++ "with remaining events" );
++
++
++ // check current vertical line (defined by the
++ // current event) against intersection with all
++ // active horizontal edges
++ // ============================================
++
++ if( bIsStartingEdge )
++ {
++ std::for_each( rActiveEdgeList.begin(),
++ rActiveEdgeList.end(),
++ boost::bind(
++ &handleStartingEdge,
++ _1,
++ nVertEdgeStartY,
++ nVertEdgeEndY,
++ boost::ref(pCurrPolygon),
++ boost::ref(rGeneratedPolygons),
++ boost::ref(rCurrEvent)) );
++ }
++ else
++ {
++ // pick up curr poly from first horiz edge we're
++ // intersecting. If NULL, also serves as a flag, to
++ // skip all intersections until own edge is hit
++ pCurrPolygon = NULL;
++
++ // handle ending edge, prune list from expired edges
++ // until sweep line's associated rectangle's own
++ // distal edge is reached
++ prune_until( rActiveEdgeList,
++ boost::bind(
++ &handleEndingEdge,
++ _1,
++ nVertEdgeStartY,
++ nVertEdgeEndY,
++ boost::ref(pCurrPolygon),
++ boost::ref(rGeneratedPolygons),
++ boost::ref(rCurrEvent)),
++ boost::bind(
++ &isOwnDistalEdge,
++ _1,
++ boost::ref(rCurrEvent)) );
++ }
++ }
++ }
++
+ class ImplB2DMultiRange
+ {
+ public:
+ ImplB2DMultiRange() :
+ maBounds(),
+- maRanges()
++ maRanges(),
++ mpPolyPolygon()
+ {
+ }
+
++ ImplB2DMultiRange( const ImplB2DMultiRange& rOrig ) :
++ maBounds( rOrig.maBounds ),
++ maRanges( rOrig.maRanges ),
++ mpPolyPolygon()
++ {
++ if( rOrig.mpPolyPolygon )
++ mpPolyPolygon.reset( new B2DPolyPolygon(*rOrig.mpPolyPolygon) );
++ }
++
+ explicit ImplB2DMultiRange( const B2DRange& rRange ) :
+ maBounds(),
+- maRanges( 1, rRange )
++ maRanges( 1, rRange ),
++ mpPolyPolygon()
+ {
+ }
+
+- bool isEmpty() const
++ bool isEmpty() const
+ {
+ // no ranges at all, or all ranges empty
+ return maRanges.empty() ||
+- ::std::count_if( maRanges.begin(),
+- maRanges.end(),
+- ::boost::mem_fn( &B2DRange::isEmpty ) )
++ std::count_if( maRanges.begin(),
++ maRanges.end(),
++ boost::mem_fn( &B2DRange::isEmpty ) )
+ == static_cast<VectorOfRanges::difference_type>(maRanges.size());
+ }
+
+- void reset()
++ void reset()
+ {
+ // swap in empty vector
+ VectorOfRanges aTmp;
+ maRanges.swap( aTmp );
+
+ maBounds.reset();
++ mpPolyPolygon.reset();
+ }
+
+- template< typename ValueType > bool isInside( const ValueType& rValue ) const
++ template< typename ValueType > bool isInside( const ValueType& rValue ) const
+ {
+ if( !maBounds.isInside( rValue ) )
+ return false;
+
+- // cannot use ::boost::bind here, since isInside is overloaded.
++ // cannot use boost::bind here, since isInside is overloaded.
+ // It is currently not possible to resolve the overload
+ // by considering one of the other template arguments.
+ VectorOfRanges::const_iterator aCurr( maRanges.begin() );
+@@ -96,23 +1301,26 @@ namespace basegfx
+ return false;
+ }
+
+- bool overlaps( const B2DRange& rRange ) const
++ bool overlaps( const B2DRange& rRange ) const
+ {
+ if( !maBounds.overlaps( rRange ) )
+ return false;
+
+ const VectorOfRanges::const_iterator aEnd( maRanges.end() );
+- return ::std::find_if( maRanges.begin(),
+- aEnd,
+- ::boost::bind<bool>( ::boost::mem_fn( &B2DRange::overlaps ),
+- _1,
+- rRange ) ) != aEnd;
++ return std::find_if( maRanges.begin(),
++ aEnd,
++ boost::bind<bool>( boost::mem_fn( &B2DRange::overlaps ),
++ _1,
++ boost::cref(rRange) ) ) != aEnd;
+ }
+
+ void addRange( const B2DRange& rRange )
+ {
+ maRanges.push_back( rRange );
+ maBounds.expand( rRange );
++
++ // range changed, invalidate buffer
++ mpPolyPolygon.reset();
+ }
+
+ B2DRange getBounds() const
+@@ -120,91 +1328,79 @@ namespace basegfx
+ return maBounds;
+ }
+
++ const std::vector<B2DRange>& getRanges() const
++ {
++ return maRanges;
++ }
++
+ B2DPolyPolygon getPolyPolygon() const
+ {
+- B2DPolyPolygon aRes;
++ // use buffered copy, if any.
++ if( !mpPolyPolygon )
++ {
++ mpPolyPolygon.reset( new B2DPolyPolygon() );
+
+- // Make range vector unique ( have to avoid duplicate
+- // rectangles. The polygon clipper will return an empty
+- // result in this case).
+- VectorOfRanges aUniqueRanges;
+- aUniqueRanges.reserve( maRanges.size() );
++ // sweep-line algorithm to generate a poly-polygon
++ // from a bunch of rectangles
++ // ===============================================
++ //
++ // This algorithm uses the well-known sweep line
++ // concept, explained in every good text book about
++ // computational geometry.
++ //
++ // We start with creating two structures for every
++ // rectangle, one representing the left x coordinate,
++ // one representing the right x coordinate (and both
++ // referencing the original rect). These structs are
++ // sorted with increasing x coordinates.
++ //
++ // Then, we start processing the resulting list from
++ // the beginning. Every entry in the list defines a
++ // point in time of the line sweeping from left to
++ // right across all rectangles.
+
+- VectorOfRanges::const_iterator aCurr( maRanges.begin() );
+- const VectorOfRanges::const_iterator aEnd ( maRanges.end() );
+- while( aCurr != aEnd )
+- {
+- // TODO(F3): It's plain wasted resources to apply a
+- // general clipping algorithm to the problem at
+- // hand. Go for a dedicated, scan-line-based approach.
+- VectorOfRanges::const_iterator aCurrScan( aCurr+1 );
+- VectorOfRanges::const_iterator aFound( aEnd );
+- while( aCurrScan != aEnd )
+- {
+- if( aCurrScan->equal( *aCurr ) ||
+- aCurrScan->isInside( *aCurr ) )
+- {
+- // current probe is equal to aCurr, or
+- // completely contains aCurr. Thus, stop
+- // searching, because aCurr is definitely not
+- // a member of the unique rect list
+- aFound = aCurrScan;
+- break;
+- }
++ VectorOfEvents aSweepLineEvents;
++ setupSweepLineEventListFromRanges( aSweepLineEvents,
++ maRanges );
+
+- ++aCurrScan;
+- }
++ ListOfEdges aActiveEdgeList;
++ VectorOfPolygons aGeneratedPolygons;
+
+- if( aFound == aEnd )
+- {
+- // check whether aCurr is fully contained in one
+- // of the already added rects. If yes, we can skip
+- // it.
+- bool bUnique( true );
+- VectorOfRanges::const_iterator aCurrUnique( aUniqueRanges.begin() );
+- VectorOfRanges::const_iterator aEndUnique ( aUniqueRanges.end() );
+- while( aCurrUnique != aEndUnique )
+- {
+- if( aCurrUnique->isInside( *aCurr ) )
+- {
+- // fully contained, no need to add
+- bUnique = false;
+- break;
+- }
+-
+- ++aCurrUnique;
+- }
++ // Ensure that aGeneratedPolygons vector does *not* get
++ // resized *ever*. This is because we hold references
++ // into this vector, and thus must avoid memory
++ // reallocation. Each rectangle generates one polygon,
++ // thus, have to reserve that much space.
++ aGeneratedPolygons.reserve( maRanges.size()*maRanges.size() );
+
+- if( bUnique )
+- aUniqueRanges.push_back( *aCurr );
+- }
++ std::for_each( aSweepLineEvents.begin(),
++ aSweepLineEvents.end(),
++ boost::bind(
++ &handleSweepLineEvent,
++ _1,
++ boost::ref(aActiveEdgeList),
++ boost::ref(aGeneratedPolygons)) );
+
+- ++aCurr;
+- }
++ // TODO: TEMP TEMP TEMP
++ VectorOfPolygons::const_iterator aCurr( aGeneratedPolygons.begin() );
++ const VectorOfPolygons::const_iterator aEnd( aGeneratedPolygons.end() );
++ while( aCurr != aEnd )
++ {
++ if( aCurr->isFinished() )
++ mpPolyPolygon->append( aCurr->getPolygon() );
++ ++aCurr;
++ }
++ }
+
+- VectorOfRanges::const_iterator aCurrUnique( aUniqueRanges.begin() );
+- const VectorOfRanges::const_iterator aEndUnique ( aUniqueRanges.end() );
+- while( aCurrUnique != aEndUnique )
+- {
+- // simply merge all unique parts (OR)
+- aRes.append( tools::createPolygonFromRect( *aCurrUnique++ ) );
+- }
+-
+- // remove redundant intersections. Note: since all added
+- // rectangles are positively oriented, this method cannot
+- // generate any holes.
+- aRes = basegfx::tools::solveCrossovers(aRes);
+- aRes = basegfx::tools::stripNeutralPolygons(aRes);
+- aRes = basegfx::tools::stripDispensablePolygons(aRes, false);
+-
+- return aRes;
++ return *mpPolyPolygon;
+ }
+
+ private:
+- typedef ::std::vector< B2DRange > VectorOfRanges;
++ B2DRange maBounds;
++ VectorOfRanges maRanges;
+
+- B2DRange maBounds;
+- VectorOfRanges maRanges;
++ // buffered poly-polygon from getPolyPolygon() method
++ mutable boost::scoped_ptr< B2DPolyPolygon > mpPolyPolygon;
+ };
+
+
+@@ -220,21 +1416,22 @@ namespace basegfx
+ mpImpl( ImplB2DMultiRange( rRange ) )
+ {
+ }
+-
+- B2DMultiRange::~B2DMultiRange()
++
++ B2DMultiRange::B2DMultiRange( const B2DMultiRange& rRange ) :
++ mpImpl( rRange.mpImpl )
+ {
+- // otherwise, ImplB2DMultiRange would be an incomplete type
+ }
+
+- B2DMultiRange::B2DMultiRange( const B2DMultiRange& rSrc ) :
+- mpImpl( rSrc.mpImpl )
++ B2DMultiRange& B2DMultiRange::operator=( const B2DMultiRange& rRange )
+ {
++ mpImpl = rRange.mpImpl;
++ return *this;
+ }
+
+- B2DMultiRange& B2DMultiRange::operator=( const B2DMultiRange& rSrc )
++ B2DMultiRange::~B2DMultiRange()
+ {
+- mpImpl = rSrc.mpImpl;
+- return *this;
++ // to have ImplB2DMultiRange declaration available, when
++ // deleting the auto_ptr member
+ }
+
+ bool B2DMultiRange::isEmpty() const
+@@ -272,6 +1469,11 @@ namespace basegfx
+ return mpImpl->getBounds();
+ }
+
++ const std::vector<B2DRange>& B2DMultiRange::getRanges() const
++ {
++ return mpImpl->getRanges();
++ }
++
+ B2DPolyPolygon B2DMultiRange::getPolyPolygon() const
+ {
+ return mpImpl->getPolyPolygon();
+diff --git basegfx/test/basegfx2d.cxx basegfx/test/basegfx2d.cxx
+index 660a19d..c4d4069 100644
+--- basegfx/test/basegfx2d.cxx
++++ basegfx/test/basegfx2d.cxx
+@@ -41,6 +41,8 @@
+ #include <basegfx/curve/b2dcubicbezier.hxx>
+ #include <basegfx/curve/b2dbeziertools.hxx>
+ #include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <basegfx/polygon/b2dpolygonclipper.hxx>
++#include <basegfx/polygon/b2dpolypolygon.hxx>
+ #include <basegfx/range/b2dmultirange.hxx>
+ #include <basegfx/numeric/ftools.hxx>
+
+@@ -54,214 +56,6 @@ using namespace ::basegfx;
+
+ namespace basegfx2d
+ {
+-/// Gets a random ordinal [0,n)
+-inline double getRandomOrdinal( const ::std::size_t n )
+-{
+- return double(n) * rand() / (RAND_MAX + 1.0);
+-}
+-
+-class b2dmultirange : public CppUnit::TestFixture
+-{
+-private:
+- B2DMultiRange aDisjunctRanges;
+- B2DMultiRange aEqualRanges;
+- B2DMultiRange aIntersectionN;
+- B2DMultiRange aIntersectionE;
+- B2DMultiRange aIntersectionS;
+- B2DMultiRange aIntersectionW;
+- B2DMultiRange aIntersectionNE;
+- B2DMultiRange aIntersectionSE;
+- B2DMultiRange aIntersectionSW;
+- B2DMultiRange aIntersectionNW;
+- B2DMultiRange aRingIntersection;
+- B2DMultiRange aComplexIntersections;
+- B2DMultiRange aRandomIntersections;
+-
+-public:
+- // initialise your test code values here.
+- void setUp()
+- {
+- B2DRange aCenter(1.0, 1.0, -1.0, -1.0);
+- B2DRange aOffside(9.0, 9.0, 11.0, 11.0);
+- B2DRange aNorth(1.0, 0.0, -1.0, -2.0);
+- B2DRange aSouth(1.0, 2.0, -1.0, 0.0);
+- B2DRange aEast(0.0, 1.0, 2.0, -1.0);
+- B2DRange aWest(-2.0, 1.0, 0.0, -1.0);
+- B2DRange aNorthEast(0.0, 0.0, 2.0, -2.0);
+- B2DRange aSouthEast(0.0, 0.0, 2.0, 2.0);
+- B2DRange aSouthWest(0.0, 0.0, -2.0, 2.0);
+- B2DRange aNorthWest(0.0, 0.0, -2.0, -2.0);
+-
+- B2DRange aNorth2(-1.5, 0.5, 1.5, 3.5);
+- B2DRange aSouth2(-1.5, -0.5, 1.5, -3.5);
+- B2DRange aEast2 (0.5, -1.5, 3.5, 1.5);
+- B2DRange aWest2 (-0.5, -1.5,-3.5, 1.5);
+-
+- ::std::ofstream output("multirange_testcases.gnuplot");
+- DebugPlotter aPlotter( "multirange testcases",
+- output );
+-
+- aPlotter.plot( aCenter, "center" );
+- aPlotter.plot( aOffside, "offside" );
+- aPlotter.plot( aNorth, "north" );
+- aPlotter.plot( aSouth, "south" );
+- aPlotter.plot( aEast, "east" );
+- aPlotter.plot( aWest, "west" );
+- aPlotter.plot( aNorthEast, "northeast" );
+- aPlotter.plot( aSouthEast, "southeast" );
+- aPlotter.plot( aSouthWest, "southwest" );
+- aPlotter.plot( aNorthWest, "northwest" );
+-
+- aDisjunctRanges.addRange( aCenter );
+- aDisjunctRanges.addRange( aOffside );
+-
+- aEqualRanges.addRange( aCenter );
+- aEqualRanges.addRange( aCenter );
+-
+- aIntersectionN.addRange( aCenter );
+- aIntersectionN.addRange( aNorth );
+-
+- aIntersectionE.addRange( aCenter );
+- aIntersectionE.addRange( aEast );
+-
+- aIntersectionS.addRange( aCenter );
+- aIntersectionS.addRange( aSouth );
+-
+- aIntersectionW.addRange( aCenter );
+- aIntersectionW.addRange( aWest );
+-
+- aIntersectionNE.addRange( aCenter );
+- aIntersectionNE.addRange( aNorthEast );
+-
+- aIntersectionSE.addRange( aCenter );
+- aIntersectionSE.addRange( aSouthEast );
+-
+- aIntersectionSW.addRange( aCenter );
+- aIntersectionSW.addRange( aSouthWest );
+-
+- aIntersectionNW.addRange( aCenter );
+- aIntersectionNW.addRange( aNorthWest );
+-
+- aRingIntersection.addRange( aNorth2 );
+- aRingIntersection.addRange( aEast2 );
+- aRingIntersection.addRange( aSouth2 );
+- aRingIntersection.addRange( aWest2 );
+-
+- aComplexIntersections.addRange( aCenter );
+- aComplexIntersections.addRange( aOffside );
+- aComplexIntersections.addRange( aCenter );
+- aComplexIntersections.addRange( aNorth );
+- aComplexIntersections.addRange( aEast );
+- aComplexIntersections.addRange( aSouth );
+- aComplexIntersections.addRange( aWest );
+- aComplexIntersections.addRange( aNorthEast );
+- aComplexIntersections.addRange( aSouthEast );
+- aComplexIntersections.addRange( aSouthWest );
+- aComplexIntersections.addRange( aNorthWest );
+-
+-/*
+- for( int i=0; i<10; ++i )
+- {
+- B2DRange aRandomRange(
+- getRandomOrdinal( 10 ),
+- getRandomOrdinal( 10 ),
+- getRandomOrdinal( 10 ),
+- getRandomOrdinal( 10 ) );
+-
+- aRandomIntersections.addRange( aRandomRange );
+- }
+-*/
+- }
+-
+- void tearDown()
+- {
+- }
+-
+- ::basegfx::B2DPolyPolygon shiftPoly( int nCount,
+- const ::basegfx::B2DPolyPolygon& rPoly )
+- {
+- B2DHomMatrix aMatrix;
+- aMatrix.translate( nCount*4.0,
+- 10.0-nCount*2.0 );
+-
+- ::basegfx::B2DPolyPolygon aRes( rPoly );
+- aRes.transform( aMatrix );
+-
+- return aRes;
+- }
+-
+- void getPolyPolygon()
+- {
+- ::std::ofstream output("multirange_getpolypolygon.gnuplot");
+- DebugPlotter aPlotter( "multirange getPolyPolygon",
+- output );
+-
+- B2DPolyPolygon result;
+-
+- aPlotter.plot( shiftPoly(
+- 0,
+- aDisjunctRanges.getPolyPolygon() ),
+- "disjunct" );
+- aPlotter.plot( shiftPoly(
+- 1,
+- aEqualRanges.getPolyPolygon() ),
+- "equal" );
+- aPlotter.plot( shiftPoly(
+- 2,
+- aIntersectionN.getPolyPolygon() ),
+- "intersectionN" );
+- aPlotter.plot( shiftPoly(
+- 3,
+- aIntersectionE.getPolyPolygon() ),
+- "intersectionE" );
+- aPlotter.plot( shiftPoly(
+- 4,
+- aIntersectionS.getPolyPolygon() ),
+- "intersectionS" );
+- aPlotter.plot( shiftPoly(
+- 5,
+- aIntersectionW.getPolyPolygon() ),
+- "intersectionW" );
+- aPlotter.plot( shiftPoly(
+- 6,
+- aIntersectionNE.getPolyPolygon() ),
+- "intersectionNE" );
+- aPlotter.plot( shiftPoly(
+- 7,
+- aIntersectionSE.getPolyPolygon() ),
+- "intersectionSE" );
+- aPlotter.plot( shiftPoly(
+- 8,
+- aIntersectionSW.getPolyPolygon() ),
+- "intersectionSW" );
+- aPlotter.plot( shiftPoly(
+- 9,
+- aIntersectionNW.getPolyPolygon() ),
+- "intersectionNW" );
+- aPlotter.plot( shiftPoly(
+- 10,
+- aRingIntersection.getPolyPolygon() ),
+- "intersection ring" );
+- aPlotter.plot( shiftPoly(
+- 11,
+- aComplexIntersections.getPolyPolygon() ),
+- "intersection complex" );
+- aPlotter.plot( shiftPoly(
+- 12,
+- aRandomIntersections.getPolyPolygon() ),
+- "intersection random" );
+-
+- CPPUNIT_ASSERT_MESSAGE("getPolyPolygon", true );
+- }
+-
+- // Change the following lines only, if you add, remove or rename
+- // member functions of the current class,
+- // because these macros are need by auto register mechanism.
+-
+- CPPUNIT_TEST_SUITE(b2dmultirange);
+- CPPUNIT_TEST(getPolyPolygon);
+- CPPUNIT_TEST_SUITE_END();
+-}; // class b2dmultirange
+
+ class b2dsvgdimpex : public CppUnit::TestFixture
+ {
+@@ -1444,7 +1238,6 @@ public:
+ }; // class b2dvector
+
+ // -----------------------------------------------------------------------------
+-//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dmultirange, "basegfx2d");
+ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dsvgdimpex, "basegfx2d");
+ //CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dbeziertools, "basegfx2d");
+ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dcubicbezier, "basegfx2d");
+diff --git basegfx/test/boxclipper.cxx basegfx/test/boxclipper.cxx
+new file mode 100644
+index 0000000..cd7ed83
+--- /dev/null
++++ basegfx/test/boxclipper.cxx
+@@ -0,0 +1,418 @@
++/*************************************************************************
++ *
++ * 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/matrix/b2dhommatrix.hxx>
++#include <basegfx/polygon/b2dpolygon.hxx>
++#include <basegfx/polygon/b2dpolygontools.hxx>
++#include <basegfx/curve/b2dcubicbezier.hxx>
++#include <basegfx/curve/b2dbeziertools.hxx>
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
++#include <basegfx/polygon/b2dpolygonclipper.hxx>
++#include <basegfx/polygon/b2dpolypolygon.hxx>
++#include <basegfx/range/b2dmultirange.hxx>
++#include <basegfx/numeric/ftools.hxx>
++
++#include <boost/bind.hpp>
++
++using namespace ::basegfx;
++
++
++namespace basegfx2d
++{
++/// Gets a random ordinal [0,n)
++inline double getRandomOrdinal( const ::std::size_t n )
++{
++ // use this one when displaying polygons in OOo, which still sucks
++ // great rocks when trying to import non-integer svg:d attributes
++ // return sal_Int64(double(n) * rand() / (RAND_MAX + 1.0));
++ return double(n) * rand() / (RAND_MAX + 1.0);
++}
++
++inline bool compare(const B2DPoint& left, const B2DPoint& right)
++{
++ return left.getX()<right.getX()
++ || (left.getX()==right.getX() && left.getY()<right.getY());
++}
++
++
++class boxclipper : public CppUnit::TestFixture
++{
++private:
++ B2DMultiRange aDisjunctRanges;
++ B2DMultiRange aEqualRanges;
++ B2DMultiRange aIntersectionN;
++ B2DMultiRange aIntersectionE;
++ B2DMultiRange aIntersectionS;
++ B2DMultiRange aIntersectionW;
++ B2DMultiRange aIntersectionNE;
++ B2DMultiRange aIntersectionSE;
++ B2DMultiRange aIntersectionSW;
++ B2DMultiRange aIntersectionNW;
++ B2DMultiRange aRingIntersection;
++ B2DMultiRange aRingIntersection2;
++ B2DMultiRange aRingIntersectExtraStrip;
++ B2DMultiRange aComplexIntersections;
++ B2DMultiRange aRandomIntersections;
++
++public:
++ // initialise your test code values here.
++ void setUp()
++ {
++ B2DRange aCenter(100, 100, -100, -100);
++ B2DRange aOffside(800, 800, 1000, 1000);
++ B2DRange aNorth(100, 0, -100, -200);
++ B2DRange aSouth(100, 200, -100, 0);
++ B2DRange aEast(0, 100, 200, -100);
++ B2DRange aWest(-200, 100, 0, -100);
++ B2DRange aNorthEast(0, 0, 200, -200);
++ B2DRange aSouthEast(0, 0, 200, 200);
++ B2DRange aSouthWest(0, 0, -200, 200);
++ B2DRange aNorthWest(0, 0, -200, -200);
++
++ B2DRange aNorth2(-150, 50, 150, 350);
++ B2DRange aSouth2(-150, -50, 150, -350);
++ B2DRange aEast2 (50, -150, 350, 150);
++ B2DRange aWest2 (-50, -150,-350, 150);
++
++ aDisjunctRanges.addRange( aCenter );
++ aDisjunctRanges.addRange( aOffside );
++
++ aEqualRanges.addRange( aCenter );
++ aEqualRanges.addRange( aCenter );
++
++ aIntersectionN.addRange( aCenter );
++ aIntersectionN.addRange( aNorth );
++
++ aIntersectionE.addRange( aCenter );
++ aIntersectionE.addRange( aEast );
++
++ aIntersectionS.addRange( aCenter );
++ aIntersectionS.addRange( aSouth );
++
++ aIntersectionW.addRange( aCenter );
++ aIntersectionW.addRange( aWest );
++
++ aIntersectionNE.addRange( aCenter );
++ aIntersectionNE.addRange( aNorthEast );
++
++ aIntersectionSE.addRange( aCenter );
++ aIntersectionSE.addRange( aSouthEast );
++
++ aIntersectionSW.addRange( aCenter );
++ aIntersectionSW.addRange( aSouthWest );
++
++ aIntersectionNW.addRange( aCenter );
++ aIntersectionNW.addRange( aNorthWest );
++
++ aRingIntersection.addRange( aNorth2 );
++ aRingIntersection.addRange( aEast2 );
++ aRingIntersection.addRange( aSouth2 );
++
++ aRingIntersection2 = aRingIntersection;
++ aRingIntersection2.addRange( aWest2 );
++
++ aRingIntersectExtraStrip = aRingIntersection2;
++ aRingIntersectExtraStrip.addRange( B2DRange(0, -25, 200, 25) );
++
++ aComplexIntersections.addRange( aCenter );
++ aComplexIntersections.addRange( aOffside );
++ aComplexIntersections.addRange( aCenter );
++ aComplexIntersections.addRange( aNorth );
++ aComplexIntersections.addRange( aEast );
++ aComplexIntersections.addRange( aSouth );
++ aComplexIntersections.addRange( aWest );
++ aComplexIntersections.addRange( aNorthEast );
++ aComplexIntersections.addRange( aSouthEast );
++ aComplexIntersections.addRange( aSouthWest );
++ aComplexIntersections.addRange( aNorthWest );
++
++#if GENERATE_RANDOM
++ for( int i=0; i<800; ++i )
++ {
++ B2DRange aRandomRange(
++ getRandomOrdinal( 1000 ),
++ getRandomOrdinal( 1000 ),
++ getRandomOrdinal( 1000 ),
++ getRandomOrdinal( 1000 ) );
++
++ aRandomIntersections.addRange( aRandomRange );
++ }
++#else
++ const char* randomSvg="m394 783h404v57h-404zm-197-505h571v576h-571zm356-634h75v200h-75zm-40-113h403v588h-403zm93-811h111v494h-111zm-364-619h562v121h-562zm-134-8h292v27h-292zm110 356h621v486h-621zm78-386h228v25h-228zm475-345h201v201h-201zm-2-93h122v126h-122zm-417-243h567v524h-567zm-266-738h863v456h-863zm262-333h315v698h-315zm-328-826h43v393h-43zm830-219h120v664h-120zm-311-636h221v109h-221zm-500 137h628v19h-628zm681-94h211v493h-211zm-366-646h384v355h-384zm-189-199h715v247h-715zm165-459h563v601h-563zm258-479h98v606h-98zm270-517h65v218h-65zm-44-259h96v286h-96zm-599-202h705v468h-705zm216-803h450v494h-450zm-150-22h26v167h-26zm-55-599h50v260h-50zm190-278h490v387h-490zm-290-453h634v392h-634zm257 189h552v300h-552zm-151-690h136v455h-136zm12-597h488v432h-488zm501-459h48v39h-48zm-224-112h429v22h-429zm-281 102h492v621h-492zm519-158h208v17h-208zm-681-563h56v427h-56zm126-451h615v392h-615zm-47-410h598v522h-598zm-32 316h79v110h-79zm-71-129h18v127h-18zm126-993h743v589h-743zm211-430h428v750h-428zm61-554h100v220h-100zm-353-49h658v157h-658zm778-383h115v272h-115zm-249-541h119v712h-119zm203 86h94v40h-94z";
++ B2DPolyPolygon randomPoly;
++ tools::importFromSvgD(
++ randomPoly,
++ rtl::OUString::createFromAscii(randomSvg));
++ std::for_each(randomPoly.begin(),
++ randomPoly.end(),
++ boost::bind(
++ &B2DMultiRange::addRange,
++ boost::ref(aRandomIntersections),
++ boost::bind(
++ &B2DPolygon::getB2DRange,
++ _1)));
++#endif
++ }
++
++ void tearDown()
++ {
++ }
++
++ void verifyPoly(const char* sName, const char* sSvg, const B2DMultiRange& toTest)
++ {
++ B2DPolyPolygon aTmp1;
++ CPPUNIT_ASSERT_MESSAGE(sName,
++ tools::importFromSvgD(
++ aTmp1,
++ rtl::OUString::createFromAscii(sSvg)));
++
++ const rtl::OUString aSvg=
++ tools::exportToSvgD(toTest.getPolyPolygon());
++ B2DPolyPolygon aTmp2;
++ CPPUNIT_ASSERT_MESSAGE(sName,
++ tools::importFromSvgD(
++ aTmp2,
++ aSvg));
++
++ CPPUNIT_ASSERT_MESSAGE(sName,
++ aTmp2 == aTmp1);
++ }
++
++ void verifyPoly()
++ {
++ const char* disjunct="m100 100v-200h-200v200zm1100 900v-200h-200v200z";
++ const char* equal="m100 100v-200h-200v200zm200 0v-200h-200v200h200z";
++ const char* intersectionN="m100 0v-100h-200v100zm200 100v-200-100h-200v100 200z";
++ const char* intersectionE="m100 100v-200h-100v200zm200 0v-200h-200-100v200h100z";
++ const char* intersectionS="m100 100v-200h-200v200 100h200v-100zm0 0v-100h-200v100z";
++ const char* intersectionW="m0 100v-200h-100v200zm200 0v-200h-200-100v200h100z";
++ const char* intersectionNE="m100 0v-100h-100v100zm200 0v-200h-200v100h-100v200h200v-100z";
++ const char* intersectionSE="m200 200v-200h-100v-100h-200v200h100v100zm100-100v-100h-100v100z";
++ const char* intersectionSW="m0 100v-100h-100v100zm200 0v-200h-200v100h-100v200h200v-100z";
++ const char* intersectionNW="m100 100v-200h-100v-100h-200v200h100v100zm100-100v-100h-100v100z";
++ const char* ringIntersection="m150 150v-100h-100v100zm300 0v-300h-200v-200h-300v300h200v100h-200v300h300v-200zm0-200v-100h-100v100z";
++ const char* ringIntersection2="m-50-50v-100h-100v100zm100 200v-100h-100v100zm500 0v-300h-200v-200h-300v200h-200v300h200v200h300v-200zm-200-100v-100h100v100zm100-100v-100h-100v100zm100 200v-100h-100v100z";
++ const char* ringIntersectExtraStrip="m-50-50v-100h-100v100zm100 200v-100h-100v100zm500 0v-300h-200v-200h-300v200h-200v300h200v200h300v-200zm-200-100v-100h100v25h-50v50h50v25zm150-25v-50h-150v50zm100-75v-100h-100v100zm100 200v-100h-100v100z";
++ const char* complexIntersections="m100 0h-100v-100 100h-100 100v100-100zm0 0zm200 0h-100v-100h-100v-100 100h-100v100h-100 100v100h100v100-100h100v-100zm0 0h-100v-100 100h-100 100v100-100h100zm0 0v-100h-100-100v100 100h100 100v-100zm100 0v-100h-100v-100h-100-100v100h-100v100 100h100v100h100 100v-100h100v-100zm-200 0zm100 0v-100h-100-100v100 100h100 100v-100zm100 100v-200-100h-200-100-100v100 200 100h100 100 200v-100zm-200-100zm1000 1000v-200h-200v200z";
++ const char* randomIntersections="m63 457v-393h-43v393zm114 63v-8h-48v8zm-14 477v-127h-18v127zm693-923v-5h-119v5zm-260 457v-1h-14v1zm-220-375v-27h-8v27zm78 755v-22h-7v22zm203-774v-8h-158v8zm-108 375v-17h23v17zm813-19v-189h-21v-12h-26v-54h-17v-69h-25v-22h-62v-73h104v-5h-104-15v-17h-49v-1h-8v-16h-119v16h-386v18h-38-24v34h-23v26h-23v-26h-8v26h-18v27h18v339h8v-339h23v339h8v17h-8v13h8v5h-8v1h8v42h15v20h17v94h18 3v224h165v39h130v2h75v4h98v-4h153v-2h77v-20h4v-28h11v-218h-11v-27h3v-1h8v-17h-8v-63h8v-51h18v-32zm-581 32v-13h-14v13zm-78-78v-7h-32v7zm124 14v-21h-14v21zm595 32v-189h-26v-12h-4v-9h-13v-45h-13v-10h-12v-59h-62v-22h-26v-10h11v-63h15v-5h-15-49v-17h-8v-1h-119v1h-107v17h-279-38v34h-24v26h-23v27h23v284h-15v55h15v17h-15v13h15v5h-15v1h15v42h17v20h18v94h3 14v62h8v48h90v32h18v61h35v21h8v2h122v37h75v2h98v-2h153v-20h77v-28h4v-29h5v-40h-5v-149h-1v-27h1v-1h3v-17h-3v-46h3v-17-51h8v-32zm-563 2v-13h-14v13zm198 30v-13h-39v13zm204-43v-21h3v21zm-168-21v-21h-39v21zm306 0v-21h-5v21zm178 115v-272h-20v-12h-2v-54h-21v-164h1v-22h-27v-48h-743v47h-23v18h-71v24h-8v419h-39v19h60v156h66 32v202h-72v110h79v-88h11v39h3v48h621v-14h96v-82h35v-326zm-570-420v-4h-156v4zm63 481v-18h-11v18zm72 0v-25h-14v25zm465-112v-13h-5v13zm-46-43v-21h1v21zm-37-21v-21h-12v21zm-352 21v-21h23v21zm-23 30v-17h23v17zm-23 18v-5h23v5zm-23 82v-19h23v19zm272 75v-3h-35v3zm-76-192v-13h-39v13zm150 30v-13h-35v13zm-76 6v-1h-39v1zm11 106v-25h-11v25zm150 160v-14h-75v14zm318-304v-11h-13v-43h-2v-2h-10v-37h-4v37h-27v3h-31v-3-37h-5v37h-43v3h-2v21h2v21h-2v30h-1v-30h-8v-21h8v-21h-8v-3h-5v-62h5v-11h-5v-29h-8v-52h-15v-17-38h-15v-52h-89v16h-22v36h-175v55h-15v1h-25v51h-23v-41h-14v41h-2v105h-4v21h4v21h-4v13h4v17h-4-18v13h18v5h-18v1h18v42h4v11h2v9h14v-9h23v9h40v19h-40v25h40v2h82v2h75v43h-75v3h75 40v60h35v-60h23 34 12 15v-3h-15v-43h15v-48h10v-37h11v-31h1v1h45v30h5v-30h20v-1h11v1h8v30h19v20h3v-20h1v-30h10v-1h2v-32zm-146-329v-1h-2v1zm-117 211v-11 11zm-76 0v-11h-13v11zm13 65v-65h1v65zm-1 42v-21h1v16h35v5zm-36 30v-17h36v17zm-36 18v-5h36v5zm180-5v-13h-13v-17h5v-13h-5v-21h5v-21h-5v-3h-8v-62h8v-11h-8v-29h-9v-51h-6v-1-17h-15v-38h-54v-36h-35v36h-22v38h-67v17h-108v1h-15v51h-25v105h-23v-105h-14v105h-2v21h2v21h-2v13h2v17h-2-4v13h4v5h-4v1h4v42h2v11h14v-11h23v11h40v9h82v19h-82v25h82v2h75v2h40v43h-40v3h40 35 23v-3h-23v-43h23v-2h34v2h12v-2h6v-46h9v-20h8v-17h2v-26h-2v-5zm-127-64v-21 21zm89 51v-17h3v17zm-57-17v-13h-35v13zm58 61v-26h-19v-5h19v-13h-23v-17h23v-13h-23v-21h23v-21h-23v-65h23v-11h-23v-14h-35v-15 15h-22v14h-18v11h18v65h-18v21h18v16h22v5h-22v13h22v17h-22-18v13h18v5h-18v1h18v25h22v17h35v-17zm0-25v-1h-35v1zm-22-390v6h-175v5h-31v-15h228v4zm344 352v-189h-2v-12h-21v-54h-26v-164h26v-5h-26v-17h-119v-36h-562v35h-62v18h-23v34h-23v-10h-48v419h-8v8h8v5h71v5h-58v1h58v42h8v114h32 18v224h3v39h165v34h456v-32h77v-2h4v-20h11v-28h4v-218h-4v-28h36v-17h-36v-63h39v-83zm-50 0v-11h-1v-43h-3v-2h-6v-39h-4v-34h-13v-60h-12v-12h-31v72h-31v-72-9h-59v-17-38h-5v-59h-8v-5h8v-1h-8v-16h-2v16h-13v-11h-15v-5h-89v5h-22v11h-175v6h-15v7h-25v16h-43v36h-18v66h-54v-107h-32v107h-4v41h-8v105h-6v7h6v14h8v21h-8v13h8v17h-8-14v13h14v5h-14v1h14v42h8v20h90v19h-34v7h-15v68h26v-50h23v50h18 4v62h16v-62h15v110h8v10h3v22h119v11h75v50h75v-50h23v-11h34v11h48v-11h30v-22h21v-120h20v-3h11v3h30v-3h13-13v-27h13v-1h17v-17h-17v-46h17v-17h6v-51h3v-32zm-256-32v-21h-35v-65h35v-11h-35v-14 14h-22v11h22v65h-22v21h22v16-16zm89 69v-5h3v5zm-3 26v-26h-31v-5h31v-13h-31v-17h31v-13h-31v-21h31v-21h-31v-65h31v-11h-31v-14h-23v-15h-35v-51 51h-22v15h-18v14h-35v11h35v65h-35v21h35v16h18v5h-18v13h18v17h-18-36-39-61v13h61v5h-61v1h61v25h39v-25h36v25h18v17h22v11h35v-11h23v-17zm-19-25v-1h-4v-5h4v-13h-4-35-22v13h22v5h-22v1h22v25h35v-25zm23 252v-36h34v36zm-34-99v-43h34v43zm35-128v-26h-8v-5h8v-13h-8v-17h8v-13h-8v-21h8v-21h-8v-3h-9v-62h9v-11h-9v-29h-6v-51-1h-15v-17h-54v-38h-35v38h-22v11h-53v6h-14v1h-108v51h-15v105h-25v21h25v21h-25v13h25v17h-25-23-14-2v13h2v5h-2v1h2v42h14v-42h23v42h40v11h82v9h75v46h40v2h35v-2h23v-4h31v-42h3v46h12v-46h6v-20h9v-17zm-15-61v-13h-12v13zm12 30v-13h-12v13zm12 31v-26h-12v26zm12 131v-3h-12v3zm12 110v-14h-12v14zm27-241v-26h-9v-5h9v-13h-9v-17h9v-13h-9v-21h9v-21h-9v-3h-6v-62h6v-11h-6v-29-51h-15v-1h-54v-17h-35v11h-22v6h-53v1h-14v51h-108v105h-15v21h15v21h-15v13h15v17h-15-25v13h25v5h-25v1h25v25h15v17h21v6h61v5h75v9h18v42h22v4h35v-4h23v-42h31v-9h3v9h12v-9-11h6v-17zm0 0v-26h-6v-5h6v-13h-6v-17h6v-13h-6v-21h6v-21h-6v-3-62-11-29h-15v-51h-54v-1h-35v-6 6h-22v1h-53v51h-14v24h-87v81h-21v21h21v21h-21v13h21v17h-21-15v13h15v5h-15v1h15v25h21v17h61v6h39v-6h36v11h18v9h22v42h35v-42h23v-9h31v-11h3v11h12v-11-17zm0 0v-26-5-13-17-13-21-21-3h-12v3h-3v-65h15v-11h-15v-29h-54v-51h-35v-1 1h-22v51h-53v29h-1v-5h-13v5h-26v76h-61v21h61v21h-61v13h61v17h-61-21v13h21v5h-21v1h21v25h61v17h39v-17h36v17h18v11h22v9h35v-9h23v-11h31v-17h3v17h12v-17zm15-419v-12h-2v12zm186 356v-56h-8v-133h-4v-12h-13v-9h-13v-45h-12v-10h-62v-59-6h-26v-16h-33v-10h33v-12h-33v-22h-5v-29h49v-5h-49-8v-17h-119v17h-107-279v34h-38v26h-24v27h24v179h-7v105h-17v55h17v17h-17v13h17v5h-17v1h17v42h18v20h3v94h14 8v62h41v37h26v-37h23v48h18v32h35v61h8v21h122v2h75v37h98v-37h34v17h119v-57h11v29h66v-29h4v-40h-4v-26h3v-123h-3v-27h3v-1h1v-17h-1v-46h1v-17h3v-51-32zm0 0v-54h-4v-2h-3v-73h-10v-60h-13v-12h-12v-9h-31v9h-31v-9-55h-59v-59h-5v-5h5v-1h-5v-16h-8v-10h8v-12h-8v-22h-119v34h117v10h-28v-6h-89v6h-22v5h-175v11h-40v13h-147v11h-4v107h-8v41h-6v105h-22v21h28v21h-17v13h17v17h-14-3v13h3v5h-3v1h3v42h14v20h8v94h41 26 23 18v62h4v48h31v10h8v22h3v11h119v50h75v21h98v-71h34v71h48v-71h30v-11h21v-22h20v-120h11v120h43v-123h17-17v-27h17v-1h6v-17h-6v-46h6v-17h3v-51h1v-32zm-4 0v-11h-6v-43h-4v-2h-13v-39h-12v-34h-4v34h-27v2h-31v-2-34h-48v36h-2v37h-1v-73h-8v-29-52h-5v-17h-8v-38h-15v-59h-15v-6h-89v6h-22v7h-175v16h-15v36h-25v55h-39v11h-4v41h-18v105h-54v-105h-32v105h-4v7h4v14h86v21h-86v13h86v17h-86-4v13h4v5h-4v1h4v42h86v11h18v9h4v19h-4v25h4v50h16v-48h23v45h-8v3h8 122v96h-119v14h119v10h75v22h75v-22h23v-10h34v10h48v-24h-36v-36h15v-60h21v-3h-11v-43h2v15h9v-15h46v15h5v-15h20v-2h-20v-46h20v-37h11v37h8v46h-8v2h8v15h22v-15h1v-2h-1v-46h1v-17h12v-20h13v-31h4v-32zm-142 148v-2h-9v2zm9-2v-46h46v46zm-46 45v-28h46v28zm67-191v-11h-1v-42h-3v42h-19v11h19v32h3v-32zm-61 0v-11h-5v11zm96 0v-11h-4v-43h-13v-2h-2v-37h-10v-2h-4v2h-27v37h-31v-37-2h-5v2h-43v37h-2v3h-1v-3h-8v-62-11-29h-5v-52h-8v-17h-15v-38-52h-15v-7h-89v7h-22v16h-175v36h-15v55h-25v1h-37v10h-2v41h-4v105h-18v21h18v21h-18v13h18v17h-18-86v13h86v5h-86v1h86v42h18v11h4v9h2v19h-2v25h2v2h14v-2h23v2h40v2h82v43h-122v3h122 75v96h-75v14h75v10h75v-10h23v-14h-23v-36h23v-60h34v60h12v-60h15 10v-3h-10v-43h10v-48h11v-37h46v37h5v-37h20v-30h11v30h8v37h22v-17h1v-20h12v-31h13v-32zm-13 0v-11h-2v-43h-10v-2h-4v2h-19v1h-8v42h-31v-21-21-3h-5v3h-43v21h43v21h-43v11h43v19h-45v13h45v1h5v-1h20v-13h-20v-19h31v32h8v1h19v30h3v-30h1v-1h10v-32zm-72 148v-2h-5v2zm5 43h-5zm66-191v-11h-3v11zm-38 146v-46h11v46zm-11 45v-28h11v28zm-11 149v-4h11v4zm-11 40v-40h-8v40zm92-380v-54-2h-4v-133h-13v-12h-13v-9h-12v-45h-31v45h-31v-55-59h-59v-5h33v-1h-33v-16h-5v-10h5v-12h-5v-22h-8v-29h8v-5h-8-119-107v5h107v29h-386v26h-38v27h40v20h-4v11h-14v148h-22v105h-7v55h18v17h-18v13h18v5h-18v1h18v42h3v20h14v94h8 41v62h26v-62h23v62h18v48h4v10h31v22h8v61h122v21h75v2h98v-2h34v2h99v-84h20v-22h11v22h43v-22h23v-123h-6v-27h6v-1h3v-17h-3v-46h3v-17h1v-51h3v-32zm-43 148v-2h-22v2zm22 43h-30zm66 189v-40h-66v40zm41-380v-11h-10v-43h-4v1h-19v42h-8v11h8v32h19v1h3v-1h1v-32zm38 0v-11h-3v-43h-6v-2h-4v-39h-13v-34h-12v-60h-4v60h-27v34h-31v-34-72h-48v72h-3v-29h-8v-52-17h-5v-38h-8v-59h-15v-6h-15v-11h-89v11h-22v6h-175v7h-15v16h-25v36h-43v66h-18v41h-54v-41h-32v41h-4v105h-8v7h8v14h4v21h-4v13h4v17h-4-8v13h8v5h-8v1h8v42h4v11h86v9h18v19h-18v25h18v50h4 16 15 8v110h3v10h119v22h75v11h75v-11h23v-22h34v22h48v-22h30v-24h-30v-96h51v-3h20-20v-28h20v-15h11v15h8v1h22v-1h13v-17h-12v-46h12v-17h17v-51h6v-32z";
++
++ verifyPoly("disjunct", disjunct, aDisjunctRanges);
++ verifyPoly("equal", equal, aEqualRanges);
++ verifyPoly("intersectionN", intersectionN, aIntersectionN);
++ verifyPoly("intersectionE", intersectionE, aIntersectionE);
++ verifyPoly("intersectionS", intersectionS, aIntersectionS);
++ verifyPoly("intersectionW", intersectionW, aIntersectionW);
++ verifyPoly("intersectionNE", intersectionNE, aIntersectionNE);
++ verifyPoly("intersectionSE", intersectionSE, aIntersectionSE);
++ verifyPoly("intersectionSW", intersectionSW, aIntersectionSW);
++ verifyPoly("intersectionNW", intersectionNW, aIntersectionNW);
++ verifyPoly("ringIntersection", ringIntersection, aRingIntersection);
++ verifyPoly("ringIntersection2", ringIntersection2, aRingIntersection2);
++ verifyPoly("ringIntersectExtraStrip", ringIntersectExtraStrip, aRingIntersectExtraStrip);
++ verifyPoly("complexIntersections", complexIntersections, aComplexIntersections);
++ verifyPoly("randomIntersections", randomIntersections, aRandomIntersections);
++ }
++
++ void dumpSvg(const char* pName,
++ const ::basegfx::B2DPolyPolygon& rPoly)
++ {
++ (void)pName; (void)rPoly;
++#if defined(VERBOSE)
++ fprintf(stderr, "%s - svg:d=\"%s\"\n",
++ pName, rtl::OUStringToOString(
++ basegfx::tools::exportToSvgD(rPoly),
++ RTL_TEXTENCODING_UTF8).getStr() );
++#endif
++ }
++
++ void getPolyPolygon()
++ {
++ dumpSvg("disjunct",aDisjunctRanges.getPolyPolygon());
++ dumpSvg("equal",aEqualRanges.getPolyPolygon());
++ dumpSvg("intersectionN",aIntersectionN.getPolyPolygon());
++ dumpSvg("intersectionE",aIntersectionE.getPolyPolygon());
++ dumpSvg("intersectionS",aIntersectionS.getPolyPolygon());
++ dumpSvg("intersectionW",aIntersectionW.getPolyPolygon());
++ dumpSvg("intersectionNE",aIntersectionNE.getPolyPolygon());
++ dumpSvg("intersectionSE",aIntersectionSE.getPolyPolygon());
++ dumpSvg("intersectionSW",aIntersectionSW.getPolyPolygon());
++ dumpSvg("intersectionNW",aIntersectionNW.getPolyPolygon());
++ dumpSvg("ringIntersection",aRingIntersection.getPolyPolygon());
++ dumpSvg("ringIntersection2",aRingIntersection2.getPolyPolygon());
++ dumpSvg("aRingIntersectExtraStrip",aRingIntersectExtraStrip.getPolyPolygon());
++ dumpSvg("complexIntersections",aComplexIntersections.getPolyPolygon());
++ dumpSvg("randomIntersections",aRandomIntersections.getPolyPolygon());
++
++ CPPUNIT_ASSERT_MESSAGE("getPolyPolygon", true );
++ }
++
++ B2DPolyPolygon normalizePoly( const B2DPolyPolygon& rPoly )
++ {
++ B2DPolyPolygon aRes;
++ for( sal_uInt32 i=0; i<rPoly.count(); ++i )
++ {
++ B2DPolygon aTmp=rPoly.getB2DPolygon(i);
++ if( ORIENTATION_NEGATIVE == tools::getOrientation(aTmp) )
++ aTmp.flip();
++
++ aTmp=tools::removeNeutralPoints(aTmp);
++
++ B2DPoint* pSmallest=0;
++ for(B2DPoint* pCurr=aTmp.begin(); pCurr!=aTmp.end(); ++pCurr)
++ {
++ if( ! pSmallest || compare(*pCurr, *pSmallest) )
++ {
++ pSmallest=pCurr;
++ }
++ }
++
++ if( pSmallest )
++ std::rotate(aTmp.begin(),pSmallest,aTmp.end());
++
++ aRes.append(aTmp);
++ }
++
++ // boxclipper & generic clipper disagree slightly on area-less
++ // polygons (one or two points only)
++ aRes = tools::stripNeutralPolygons(aRes);
++
++ // now, sort all polygons with increasing 0th point
++ std::sort(aRes.begin(),
++ aRes.end(),
++ boost::bind(
++ &compare,
++ boost::bind(
++ &B2DPolygon::getB2DPoint,
++ _1,0),
++ boost::bind(
++ &B2DPolygon::getB2DPoint,
++ _2,0)));
++
++ return aRes;
++ }
++
++ void validatePoly( const char* pName, const B2DMultiRange& rRange )
++ {
++ B2DPolyPolygon genericClip;
++ std::for_each(rRange.getRanges().begin(),
++ rRange.getRanges().end(),
++ boost::bind(
++ &B2DPolyPolygon::append,
++ boost::ref(genericClip),
++ boost::bind(
++ &tools::createPolygonFromRect,_1),
++ 1));
++
++#if defined(VERBOSE)
++ fprintf(stderr, "%s input - svg:d=\"%s\"\n",
++ pName, rtl::OUStringToOString(
++ basegfx::tools::exportToSvgD(
++ genericClip),
++ RTL_TEXTENCODING_UTF8).getStr() );
++#endif
++
++ const B2DPolyPolygon boxClipResult=rRange.getPolyPolygon();
++ const rtl::OUString boxClipSvg(
++ basegfx::tools::exportToSvgD(
++ normalizePoly(
++ boxClipResult)));
++#if defined(VERBOSE)
++ fprintf(stderr, "%s boxclipper - svg:d=\"%s\"\n",
++ pName, rtl::OUStringToOString(
++ boxClipSvg,
++ RTL_TEXTENCODING_UTF8).getStr() );
++#endif
++
++ genericClip = tools::solveCrossovers(genericClip);
++ const rtl::OUString genericClipSvg(
++ basegfx::tools::exportToSvgD(
++ normalizePoly(
++ genericClip)));
++#if defined(VERBOSE)
++ fprintf(stderr, "%s genclipper - svg:d=\"%s\"\n",
++ pName, rtl::OUStringToOString(
++ genericClipSvg,
++ RTL_TEXTENCODING_UTF8).getStr() );
++#endif
++
++ CPPUNIT_ASSERT_MESSAGE(pName,
++ genericClipSvg == boxClipSvg);
++ }
++
++ void validatePoly()
++ {
++ validatePoly("disjunct", aDisjunctRanges);
++ validatePoly("equal", aEqualRanges);
++ validatePoly("intersectionN", aIntersectionN);
++ validatePoly("intersectionE", aIntersectionE);
++ validatePoly("intersectionS", aIntersectionS);
++ validatePoly("intersectionW", aIntersectionW);
++ validatePoly("intersectionNE", aIntersectionNE);
++ validatePoly("intersectionSE", aIntersectionSE);
++ validatePoly("intersectionSW", aIntersectionSW);
++ validatePoly("intersectionNW", aIntersectionNW);
++ validatePoly("ringIntersection", aRingIntersection);
++ validatePoly("ringIntersection2", aRingIntersection2);
++ validatePoly("ringIntersectExtraStrip", aRingIntersectExtraStrip);
++ // generic clipper buggy here, likely
++ //validatePoly("complexIntersections", aComplexIntersections);
++ //validatePoly("randomIntersections", aRandomIntersections);
++ }
++
++ // Change the following lines only, if you add, remove or rename
++ // member functions of the current class,
++ // because these macros are need by auto register mechanism.
++
++ CPPUNIT_TEST_SUITE(boxclipper);
++ CPPUNIT_TEST(validatePoly);
++ CPPUNIT_TEST(verifyPoly);
++ CPPUNIT_TEST(getPolyPolygon);
++ CPPUNIT_TEST_SUITE_END();
++};
++
++// -----------------------------------------------------------------------------
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::boxclipper, "boxclipper");
++} // 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/makefile.mk basegfx/test/makefile.mk
+index 5bf0d8a..320bd0c 100644
+--- basegfx/test/makefile.mk
++++ basegfx/test/makefile.mk
+@@ -46,6 +46,7 @@ SHL1OBJS= \
+ $(SLO)$/basegfx1d.obj \
+ $(SLO)$/basegfx2d.obj \
+ $(SLO)$/basegfx3d.obj \
++ $(SLO)$/boxclipper.obj \
+ $(SLO)$/testtools.obj
+
+ # linking statically against basegfx parts
+@@ -83,6 +84,10 @@ SLOFILES=$(SHL1OBJS)
+ .INCLUDE : target.mk
+ .INCLUDE : _cppunit.mk
+
++.IF "$(verbose)"!="" || "$(VERBOSE)"!=""
++CDEFS+= -DVERBOSE
++.ENDIF
++
+ # --- Enable testshl2 execution in normal build ------------------------
+
+ $(MISC)$/unittest_succeeded : $(SHL1TARGETN)
More information about the ooo-build-commit
mailing list