diff options
author | Thorsten Behrens <tbehrens@novell.com> | 2011-06-21 09:11:29 +0200 |
---|---|---|
committer | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2011-06-22 12:54:14 +0200 |
commit | 246168e94709a5ea7f34914d8e246af0985a9c81 (patch) | |
tree | 10ee751a84b95986ca5c06255a24215e51a9535b | |
parent | 56888909e7fa263501bc41eb3c13ca63c4b62fcb (diff) |
Teach LibreOffice proper svg:d support
-rw-r--r-- | basegfx/inc/basegfx/tools/unotools.hxx | 55 | ||||
-rw-r--r-- | basegfx/prj/d.lst | 1 | ||||
-rwxr-xr-x | basegfx/source/tools/makefile.mk | 3 | ||||
-rw-r--r-- | basegfx/source/tools/unotools.cxx | 264 |
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 0000000000..e7bcc27fb5 --- /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 dd4a2d8aed..06888a8e5e 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 0a0977f730..6023a327a6 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 0000000000..710568b8d7 --- /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); + } + } + +} +} |