From de8b6ad8ff15b3e31aa057436113ef37cf24ea09 Mon Sep 17 00:00:00 2001 From: Thorsten Behrens Date: Tue, 21 Jun 2011 09:11:29 +0200 Subject: Teach LibreOffice proper svg:d support --- basegfx/inc/basegfx/tools/unotools.hxx | 55 +++++++ basegfx/prj/d.lst | 1 + basegfx/source/tools/makefile.mk | 3 +- basegfx/source/tools/unotools.cxx | 264 +++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 basegfx/inc/basegfx/tools/unotools.hxx create mode 100644 basegfx/source/tools/unotools.cxx (limited to 'basegfx') 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 + * 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 +#include +#include +#include +#include +#include +#include + + +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 + * + * 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basegfx.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +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 aPoints; aPoints.reserve(nLoopCount); + std::vector aFlags; aFlags.reserve(nLoopCount); + + // prepare insert index and current point + basegfx::B2DCubicBezier aBezier; + aBezier.setStartPoint(rPoly.getB2DPoint(0)); + + for(sal_uInt32 b(0L); b