summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorThorsten Behrens <tbehrens@novell.com>2011-06-21 09:11:29 +0200
committerFridrich Štrba <fridrich.strba@bluewin.ch>2011-06-22 12:54:14 +0200
commitde8b6ad8ff15b3e31aa057436113ef37cf24ea09 (patch)
tree00bcc474fcda15e1b72177516f9d5c45580afd39 /basegfx
parentfb18147a63061e719c35f32d5adf7699bc021972 (diff)
Teach LibreOffice proper svg:d support
Diffstat (limited to 'basegfx')
-rw-r--r--basegfx/inc/basegfx/tools/unotools.hxx55
-rw-r--r--basegfx/prj/d.lst1
-rwxr-xr-xbasegfx/source/tools/makefile.mk3
-rw-r--r--basegfx/source/tools/unotools.cxx264
4 files changed, 322 insertions, 1 deletions
diff --git a/basegfx/inc/basegfx/tools/unotools.hxx b/basegfx/inc/basegfx/tools/unotools.hxx
new file mode 100644
index 000000000000..e7bcc27fb561
--- /dev/null
+++ b/basegfx/inc/basegfx/tools/unotools.hxx
@@ -0,0 +1,55 @@
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ * Thorsten Behrens <tbehrens@novell.com>
+ * Portions created by the Initial Developer are Copyright (C) 2011 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#ifndef INCLUDED_BASEGFX_UNOTOOLS_HXX
+#define INCLUDED_BASEGFX_UNOTOOLS_HXX
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase3.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/rendering/FillRule.hpp>
+#include <com/sun/star/rendering/XLinePolyPolygon2D.hpp>
+#include <com/sun/star/rendering/XBezierPolyPolygon2D.hpp>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+namespace basegfx
+{
+class B2DPolyPolygon;
+
+namespace unotools
+{
+
+ B2DPolyPolygon polyPolygonBezierToB2DPolyPolygon(const ::com::sun::star::drawing::PolyPolygonBezierCoords& rSourcePolyPolygon)
+ throw( ::com::sun::star::lang::IllegalArgumentException );
+
+ void b2DPolyPolygonToPolyPolygonBezier( const B2DPolyPolygon& rPolyPoly,
+ ::com::sun::star::drawing::PolyPolygonBezierCoords& rRetval );
+}
+}
+
+#endif /* INCLUDED_BASEGFX_UNOTOOLS_HXX */
diff --git a/basegfx/prj/d.lst b/basegfx/prj/d.lst
index dd4a2d8aedd6..06888a8e5e99 100644
--- a/basegfx/prj/d.lst
+++ b/basegfx/prj/d.lst
@@ -93,6 +93,7 @@ mkdir: %_DEST%\inc\basegfx\tools
..\inc\basegfx\tools\keystoplerp.hxx %_DEST%\inc\basegfx\tools\keystoplerp.hxx
..\inc\basegfx\tools\lerp.hxx %_DEST%\inc\basegfx\tools\lerp.hxx
..\inc\basegfx\tools\unopolypolygon.hxx %_DEST%\inc\basegfx\tools\unopolypolygon.hxx
+..\inc\basegfx\tools\unotools.hxx %_DEST%\inc%_EXT%\basegfx\tools\unotools.hxx
..\inc\basegfx\tools\b2dclipstate.hxx %_DEST%\inc\basegfx\tools\b2dclipstate.hxx
..\inc\basegfx\tools\rectcliptools.hxx %_DEST%\inc\basegfx\tools\rectcliptools.hxx
..\inc\basegfx\tools\tools.hxx %_DEST%\inc\basegfx\tools\tools.hxx
diff --git a/basegfx/source/tools/makefile.mk b/basegfx/source/tools/makefile.mk
index 0a0977f7305d..6023a327a66f 100755
--- a/basegfx/source/tools/makefile.mk
+++ b/basegfx/source/tools/makefile.mk
@@ -44,7 +44,8 @@ SLOFILES= $(SLO)$/b2dclipstate.obj \
$(SLO)$/keystoplerp.obj \
$(SLO)$/liangbarsky.obj \
$(SLO)$/tools.obj \
- $(SLO)$/unopolypolygon.obj
+ $(SLO)$/unopolypolygon.obj\
+ $(SLO)$/unotools.obj
# --- Targets ----------------------------------
diff --git a/basegfx/source/tools/unotools.cxx b/basegfx/source/tools/unotools.cxx
new file mode 100644
index 000000000000..710568b8d737
--- /dev/null
+++ b/basegfx/source/tools/unotools.cxx
@@ -0,0 +1,264 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * Portions Copright 2011 Thorsten Behrens <tbehrens@novell.com>
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * 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"
+
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/drawing/FlagSequence.hpp>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+
+#include <basegfx/tools/unotools.hxx>
+#include <comphelper/sequence.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace basegfx
+{
+namespace unotools
+{
+
+ B2DPolyPolygon polyPolygonBezierToB2DPolyPolygon(const drawing::PolyPolygonBezierCoords& rSourcePolyPolygon)
+ throw( lang::IllegalArgumentException )
+ {
+ const sal_Int32 nOuterSequenceCount(rSourcePolyPolygon.Coordinates.getLength());
+ B2DPolyPolygon aNewPolyPolygon;
+
+ if(rSourcePolyPolygon.Flags.getLength() != nOuterSequenceCount)
+ throw lang::IllegalArgumentException();
+
+ // get pointers to inner sequence
+ const drawing::PointSequence* pInnerSequence = rSourcePolyPolygon.Coordinates.getConstArray();
+ const drawing::FlagSequence* pInnerSequenceFlags = rSourcePolyPolygon.Flags.getConstArray();
+
+ for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
+ {
+ const sal_Int32 nInnerSequenceCount(pInnerSequence->getLength());
+
+ if(pInnerSequenceFlags->getLength() != nInnerSequenceCount)
+ throw lang::IllegalArgumentException();
+
+ // prepare new polygon
+ basegfx::B2DPolygon aNewPolygon;
+ const awt::Point* pArray = pInnerSequence->getConstArray();
+ const drawing::PolygonFlags* pArrayFlags = pInnerSequenceFlags->getConstArray();
+
+ // get first point and flag
+ basegfx::B2DPoint aNewCoordinatePair(pArray->X, pArray->Y); pArray++;
+ drawing::PolygonFlags ePolyFlag(*pArrayFlags); pArrayFlags++;
+ basegfx::B2DPoint aControlA;
+ basegfx::B2DPoint aControlB;
+
+ // first point is not allowed to be a control point
+ if(drawing::PolygonFlags_CONTROL == ePolyFlag)
+ throw lang::IllegalArgumentException();
+
+ // add first point as start point
+ aNewPolygon.append(aNewCoordinatePair);
+ for(sal_Int32 b(1); b < nInnerSequenceCount;)
+ {
+ // prepare loop
+ bool bControlA(false);
+ bool bControlB(false);
+
+ // get next point and flag
+ aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
+ ePolyFlag = *pArrayFlags;
+ pArray++; pArrayFlags++; b++;
+
+ if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag)
+ {
+ aControlA = aNewCoordinatePair;
+ bControlA = true;
+
+ // get next point and flag
+ aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
+ ePolyFlag = *pArrayFlags;
+ pArray++; pArrayFlags++; b++;
+ }
+
+ if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag)
+ {
+ aControlB = aNewCoordinatePair;
+ bControlB = true;
+
+ // get next point and flag
+ aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
+ ePolyFlag = *pArrayFlags;
+ pArray++; pArrayFlags++; b++;
+ }
+
+ // two or no control points are consumed, another one would be an error.
+ // It's also an error if only one control point was read
+ if(drawing::PolygonFlags_CONTROL == ePolyFlag || bControlA != bControlB)
+ throw lang::IllegalArgumentException();
+
+ // the previous writes used the B2DPolyPoygon -> PolyPolygon converter
+ // which did not create minimal PolyPolygons, but created all control points
+ // as null vectors (identical points). Because of the former P(CA)(CB)-norm of
+ // B2DPolygon and it's unused sign of being the zero-vector and CA and CB being
+ // relative to P, an empty edge was exported as P == CA == CB. Luckily, the new
+ // export format can be read without errors by the old OOo-versions, so we need only
+ // to correct here at read and do not need to export a wrong but compatible version
+ // for the future.
+ if(bControlA
+ && aControlA.equal(aControlB)
+ && aControlA.equal(aNewPolygon.getB2DPoint(aNewPolygon.count() - 1)))
+ {
+ bControlA = bControlB = false;
+ }
+
+ if(bControlA)
+ {
+ // add bezier edge
+ aNewPolygon.appendBezierSegment(aControlA, aControlB, aNewCoordinatePair);
+ }
+ else
+ {
+ // add edge
+ aNewPolygon.append(aNewCoordinatePair);
+ }
+ }
+
+ // next sequence
+ pInnerSequence++;
+ pInnerSequenceFlags++;
+
+ // #i72807# API import uses old line start/end-equal definition for closed,
+ // so we need to correct this to closed state here
+ basegfx::tools::checkClosed(aNewPolygon);
+
+ // add new subpolygon
+ aNewPolyPolygon.append(aNewPolygon);
+ }
+
+ return aNewPolyPolygon;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+
+ void b2DPolyPolygonToPolyPolygonBezier( const basegfx::B2DPolyPolygon& rPolyPoly,
+ drawing::PolyPolygonBezierCoords& rRetval )
+ {
+ rRetval.Coordinates.realloc(rPolyPoly.count());
+ rRetval.Flags.realloc(rPolyPoly.count());
+
+ drawing::PointSequence* pOuterSequence = rRetval.Coordinates.getArray();
+ drawing::FlagSequence* pOuterFlags = rRetval.Flags.getArray();
+
+ for(sal_uInt32 a=0;a<rPolyPoly.count();a++)
+ {
+ const B2DPolygon& rPoly = rPolyPoly.getB2DPolygon(a);
+ sal_uInt32 nCount(rPoly.count());
+ const bool bClosed(rPoly.isClosed());
+
+ // calculate input vertex count
+ const sal_uInt32 nLoopCount(bClosed ? nCount : (nCount ? nCount - 1L : 0L ));
+
+ std::vector<awt::Point> aPoints; aPoints.reserve(nLoopCount);
+ std::vector<drawing::PolygonFlags> aFlags; aFlags.reserve(nLoopCount);
+
+ // prepare insert index and current point
+ basegfx::B2DCubicBezier aBezier;
+ aBezier.setStartPoint(rPoly.getB2DPoint(0));
+
+ for(sal_uInt32 b(0L); b<nLoopCount; b++)
+ {
+ // add current point (always) and remember StartPointIndex for evtl. later corrections
+ const awt::Point aStartPoint(fround(aBezier.getStartPoint().getX()),
+ fround(aBezier.getStartPoint().getY()));
+ const sal_uInt32 nStartPointIndex(aPoints.size());
+ aPoints.push_back(aStartPoint);
+ aFlags.push_back(drawing::PolygonFlags_NORMAL);
+
+ // prepare next segment
+ const sal_uInt32 nNextIndex((b + 1) % nCount);
+ aBezier.setEndPoint(rPoly.getB2DPoint(nNextIndex));
+ aBezier.setControlPointA(rPoly.getNextControlPoint(b));
+ aBezier.setControlPointB(rPoly.getPrevControlPoint(nNextIndex));
+
+ if(aBezier.isBezier())
+ {
+ // if one is used, add always two control points due to the old schema
+ aPoints.push_back( awt::Point(fround(aBezier.getControlPointA().getX()),
+ fround(aBezier.getControlPointA().getY())) );
+ aFlags.push_back(drawing::PolygonFlags_CONTROL);
+
+ aPoints.push_back( awt::Point(fround(aBezier.getControlPointB().getX()),
+ fround(aBezier.getControlPointB().getY())) );
+ aFlags.push_back(drawing::PolygonFlags_CONTROL);
+ }
+
+ // test continuity with previous control point to set flag value
+ if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || b))
+ {
+ const basegfx::B2VectorContinuity eCont(rPoly.getContinuityInPoint(b));
+
+ if(basegfx::CONTINUITY_C1 == eCont)
+ {
+ aFlags[nStartPointIndex] = drawing::PolygonFlags_SMOOTH;
+ }
+ else if(basegfx::CONTINUITY_C2 == eCont)
+ {
+ aFlags[nStartPointIndex] = drawing::PolygonFlags_SYMMETRIC;
+ }
+ }
+
+ // prepare next polygon step
+ aBezier.setStartPoint(aBezier.getEndPoint());
+ }
+
+ if(bClosed)
+ {
+ // add first point again as closing point due to old definition
+ aPoints.push_back( aPoints[0] );
+ aFlags.push_back(drawing::PolygonFlags_NORMAL);
+ }
+ else
+ {
+ // add last point as closing point
+ const basegfx::B2DPoint aClosingPoint(rPoly.getB2DPoint(nCount - 1L));
+ const awt::Point aEnd(fround(aClosingPoint.getX()),
+ fround(aClosingPoint.getY()));
+ aPoints.push_back(aEnd);
+ aFlags.push_back(drawing::PolygonFlags_NORMAL);
+ }
+
+ *pOuterSequence++ = comphelper::containerToSequence(aPoints);
+ *pOuterFlags++ = comphelper::containerToSequence(aFlags);
+ }
+ }
+
+}
+}