diff options
author | Armin Le Grand <alg@apache.org> | 2013-10-29 14:11:45 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2013-10-31 15:56:14 +0000 |
commit | 223f6b631c1b087754c0f9051fb55f029f2503ce (patch) | |
tree | 14582be2894a88d16c6b0debbc8491350f9a5cce | |
parent | 9069e26d1fe1fbbe7bceab0bae8a186d8cdb47cc (diff) |
Resolves: #i123433# Detect pseudo-vertices at svg import...
unify svg:d handling, correct svg:d import for relative sub-polygons in svg
import; changed default for moveto writes for svg:d in ODF to absolute
(cherry picked from commit f15874d8f976f3874bdbcb53429eeefa65c28841)
Conflicts:
basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
basegfx/inc/basegfx/polygon/b3dpolypolygontools.hxx
basegfx/source/polygon/b2dpolypolygontools.cxx
basegfx/source/polygon/b2dsvgpolypolygon.cxx
basegfx/source/polygon/b3dpolypolygontools.cxx
basegfx/source/tools/makefile.mk
basegfx/test/boxclipper.cxx
basegfx/test/clipstate.cxx
basegfx/test/genericclipper.cxx
canvas/source/tools/surfaceproxy.cxx
sdext/source/pdfimport/tree/drawtreevisiting.cxx
sdext/source/pdfimport/tree/writertreevisiting.cxx
xmloff/inc/xexptran.hxx
xmloff/source/draw/XMLImageMapContext.cxx
xmloff/source/draw/XMLImageMapExport.cxx
xmloff/source/draw/shapeexport2.cxx
xmloff/source/draw/shapeexport3.cxx
xmloff/source/draw/xexptran.cxx
xmloff/source/draw/ximp3dobject.cxx
xmloff/source/draw/ximpshap.cxx
xmloff/source/style/MarkerStyle.cxx
xmloff/source/text/XMLTextFrameContext.cxx
xmloff/source/text/txtparae.cxx
Change-Id: I5171b4a3559ea116bea45152e1f2685666463635
47 files changed, 1799 insertions, 1963 deletions
diff --git a/basebmp/CppunitTest_basebmp.mk b/basebmp/CppunitTest_basebmp.mk index 67113ff0d874..c2ffb5f7d5b6 100644 --- a/basebmp/CppunitTest_basebmp.mk +++ b/basebmp/CppunitTest_basebmp.mk @@ -9,6 +9,8 @@ $(eval $(call gb_CppunitTest_CppunitTest,basebmp_cpputest)) +$(eval $(call gb_CppunitTest_use_sdk_api,basebmp_cpputest)) + $(eval $(call gb_CppunitTest_use_external,basebmp_cpputest,boost_headers)) $(eval $(call gb_CppunitTest_use_libraries,basebmp_cpputest,\ diff --git a/basebmp/test/bmpmasktest.cxx b/basebmp/test/bmpmasktest.cxx index d98fb6209606..a0209dfabfd6 100644 --- a/basebmp/test/bmpmasktest.cxx +++ b/basebmp/test/bmpmasktest.cxx @@ -112,7 +112,7 @@ public: OUString aSvg( "m 0 0h5v10h5v-5h-10z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); const Color aColWhite(0xFFFFFFFF); const Color aColBlack(0); mpBmp1bpp->fillPolyPolygon( @@ -127,7 +127,7 @@ public: aSvg = "m 0 0 h6 v10 h-6z" ; aPoly.clear(); - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); mpMaskBmp1bpp->clear(aColWhite); mpMaskBmp1bpp->fillPolyPolygon( aPoly, diff --git a/basebmp/test/bmptest.cxx b/basebmp/test/bmptest.cxx index 59adac5feeae..e364804a391e 100644 --- a/basebmp/test/bmptest.cxx +++ b/basebmp/test/bmptest.cxx @@ -165,7 +165,7 @@ public: OUString aSvg( "m 0 0h5v10h5v-5h-10z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); const Color aCol(0xFFFFFFFF); mpBmp1bpp->fillPolyPolygon( aPoly, diff --git a/basebmp/test/cliptest.cxx b/basebmp/test/cliptest.cxx index cc1dbb0ce384..bcde756adeee 100644 --- a/basebmp/test/cliptest.cxx +++ b/basebmp/test/cliptest.cxx @@ -161,7 +161,7 @@ private: OUString aSvg( "m 0 0h5v10h5v-5h-10z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); const basebmp::Color aCol(0xFF); pBmp->clear( basebmp::Color(0) ); pBmp->fillPolyPolygon( @@ -200,7 +200,7 @@ public: OUString aSvg( "m 0 0 h5 l5 5 v5 h-5 l-5-5 z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); mpClipMask->clear(Color(0)); mpClipMask->drawPolygon( aPoly.getB2DPolygon(0), diff --git a/basebmp/test/filltest.cxx b/basebmp/test/filltest.cxx index 6c0079583cd5..3adf26a0a97c 100644 --- a/basebmp/test/filltest.cxx +++ b/basebmp/test/filltest.cxx @@ -149,7 +149,7 @@ private: OUString aSvg( "m 0 0l7 7h-1z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, diff --git a/basebmp/test/masktest.cxx b/basebmp/test/masktest.cxx index bdc870d28193..1662c81f9b98 100644 --- a/basebmp/test/masktest.cxx +++ b/basebmp/test/masktest.cxx @@ -116,7 +116,7 @@ public: OUString aSvg( "m 0 0h5v10h5v-5h-10z" ); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( aPoly, aSvg ); + basegfx::tools::importFromSvgD( aPoly, aSvg, false, NULL ); const Color aCol(0xFF); mpMask->fillPolyPolygon( aPoly, diff --git a/basebmp/test/polytest.cxx b/basebmp/test/polytest.cxx index a32d099c3834..3ed416b1dfef 100644 --- a/basebmp/test/polytest.cxx +++ b/basebmp/test/polytest.cxx @@ -54,7 +54,7 @@ private: basegfx::tools::importFromSvgD( aPoly, - OUString( "M2 2 l7 7 z" ) ); + OUString( "M2 2 l7 7 z" ), false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, @@ -68,7 +68,7 @@ private: aPoly.clear(); basegfx::tools::importFromSvgD( aPoly, - OUString( "M7 2 l-6 6 z" ) ); + OUString( "M7 2 l-6 6 z" ), false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, @@ -86,7 +86,7 @@ private: basegfx::tools::importFromSvgD( aPoly, - OUString( "M2 2 h1 l7 7 h-1 z" ) ); + OUString( "M2 2 h1 l7 7 h-1 z" ), false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, @@ -100,7 +100,7 @@ private: aPoly.clear(); basegfx::tools::importFromSvgD( aPoly, - OUString( "M7 2 h-1 l-6 6 h1 z" ) ); + OUString( "M7 2 h-1 l-6 6 h1 z" ), false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, @@ -114,7 +114,7 @@ private: aPoly.clear(); basegfx::tools::importFromSvgD( aPoly, - OUString( "M0 0 l7 7 h-1 l-5-7 z" ) ); + OUString( "M0 0 l7 7 h-1 l-5-7 z" ), false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, @@ -131,7 +131,8 @@ private: basegfx::B2DPolyPolygon aPoly; basegfx::tools::importFromSvgD( aPoly, - OUString( "M0 0 h7 v7 h-7 z M2 2 v3 h3 v-3 z" ) ); + OUString( "M0 0 h7 v7 h-7 z M2 2 v3 h3 v-3 z" ), + false, NULL ); rDevice->fillPolyPolygon( aPoly, @@ -149,7 +150,8 @@ private: basegfx::B2DPolyPolygon aPoly; basegfx::tools::importFromSvgD( aPoly, - OUString( "M0 0 h7 v7 h-7 z M2 2 v3 h3 v-3 z" ) ); + OUString( "M0 0 h7 v7 h-7 z M2 2 v3 h3 v-3 z" ), + false, NULL ); basegfx::B2DHomMatrix aMat; aMat.translate(-3,-3); aMat.rotate( 1.7 ); @@ -249,7 +251,8 @@ private: // *all* of the four two-pixel lines in that polygon do *not* // generate a single pixel, due to the rasterization effect. basegfx::tools::importFromSvgD( aPoly, - OUString( "M2 3 l1 -1 M4 2 l1 1 M2 8 l1 1 M5 8 l-1 1 M2 5 h4 M3 0 v10" ) ); + OUString( "M2 3 l1 -1 M4 2 l1 1 M2 8 l1 1 M5 8 l-1 1 M2 5 h4 M3 0 v10" ), + false, NULL ); BitmapDeviceSharedPtr pClippedDevice=( subsetBitmapDevice( rDevice, basegfx::B2IBox(3,3,5,9) )); @@ -276,7 +279,8 @@ private: "M10 6 v-2 l-10 2 v2 z" "M1 0 h1 v10 h-1 z" "M4 0 h1 v10 h-1 z" - "M8 0 h1 v10 h-1 z" ) ); + "M8 0 h1 v10 h-1 z" ), + false, NULL ); rDevice->fillPolyPolygon( aPoly, aCol, diff --git a/basegfx/Library_basegfx.mk b/basegfx/Library_basegfx.mk index 5956d6ee18e2..f121f69cae78 100644 --- a/basegfx/Library_basegfx.mk +++ b/basegfx/Library_basegfx.mk @@ -70,6 +70,7 @@ $(eval $(call gb_Library_add_exception_objects,basegfx,\ basegfx/source/tools/gradienttools \ basegfx/source/tools/keystoplerp \ basegfx/source/tools/numbertools \ + basegfx/source/tools/stringconversiontools \ basegfx/source/tools/tools \ basegfx/source/tools/unopolypolygon \ basegfx/source/tools/unotools \ diff --git a/basegfx/source/inc/stringconversiontools.hxx b/basegfx/source/inc/stringconversiontools.hxx new file mode 100644 index 000000000000..96692dcf2bb4 --- /dev/null +++ b/basegfx/source/inc/stringconversiontools.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef _STRINGCONVERSIONTOOLS_HXX +#define _STRINGCONVERSIONTOOLS_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> + +namespace basegfx +{ + namespace internal + { + void lcl_skipSpaces(sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen); + + void lcl_skipSpacesAndCommas(sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen); + + inline bool lcl_isOnNumberChar(const sal_Unicode aChar, bool bSignAllowed = true) + { + const bool bPredicate( (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) + || (bSignAllowed && sal_Unicode('+') == aChar) + || (bSignAllowed && sal_Unicode('-') == aChar) ); + + return bPredicate; + } + + inline bool lcl_isOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true) + { + return lcl_isOnNumberChar(rStr[nPos], + bSignAllowed); + } + + bool lcl_getDoubleChar(double& o_fRetval, + sal_Int32& io_rPos, + const OUString& rStr); + + bool lcl_importDoubleAndSpaces( double& o_fRetval, + sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen ); + + bool lcl_importFlagAndSpaces(sal_Int32& o_nRetval, + sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen); + + void lcl_skipNumber(sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen); + + void lcl_skipDouble(sal_Int32& io_rPos, + const OUString& rStr); + + inline void lcl_putNumberChar( OUStringBuffer& rStr, + double fValue ) + { + rStr.append( fValue ); + } + + void lcl_putNumberCharWithSpace( OUStringBuffer& rStr, + double fValue, + double fOldValue, + bool bUseRelativeCoordinates ); + + inline sal_Unicode lcl_getCommand( sal_Char cUpperCaseCommand, + sal_Char cLowerCaseCommand, + bool bUseRelativeCoordinates ) + { + return bUseRelativeCoordinates ? cLowerCaseCommand : cUpperCaseCommand; + } + } // namespace internal +} // namespace basegfx + +#endif /* _STRINGCONVERSIONTOOLS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index f9fec004e15c..535e8cd6acda 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -3352,6 +3352,349 @@ namespace basegfx return aRetval; } + ////////////////////////////////////////////////////////////////////////////// + // converters for com::sun::star::drawing::PointSequence + + B2DPolygon UnoPointSequenceToB2DPolygon( + const com::sun::star::drawing::PointSequence& rPointSequenceSource, + bool bCheckClosed) + { + B2DPolygon aRetval; + const sal_uInt32 nLength(rPointSequenceSource.getLength()); + + if(nLength) + { + aRetval.reserve(nLength); + const com::sun::star::awt::Point* pArray = rPointSequenceSource.getConstArray(); + const com::sun::star::awt::Point* pArrayEnd = pArray + rPointSequenceSource.getLength(); + + for(;pArray != pArrayEnd; pArray++) + { + aRetval.append(B2DPoint(pArray->X, pArray->Y)); + } + + if(bCheckClosed) + { + // check for closed state flag + tools::checkClosed(aRetval); + } + } + + return aRetval; + } + + void B2DPolygonToUnoPointSequence( + const B2DPolygon& rPolygon, + com::sun::star::drawing::PointSequence& rPointSequenceRetval) + { + B2DPolygon aPolygon(rPolygon); + + if(aPolygon.areControlPointsUsed()) + { + OSL_ENSURE(false, "B2DPolygonToUnoPointSequence: Source contains bezier segments, wrong UNO API data type may be used (!)"); + aPolygon = aPolygon.getDefaultAdaptiveSubdivision(); + } + + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + // Take closed state into account, the API polygon still uses the old closed definition + // with last/first point are identical (cannot hold information about open polygons with identical + // first and last point, though) + const bool bIsClosed(aPolygon.isClosed()); + + rPointSequenceRetval.realloc(bIsClosed ? nPointCount + 1 : nPointCount); + com::sun::star::awt::Point* pSequence = rPointSequenceRetval.getArray(); + + for(sal_uInt32 b(0); b < nPointCount; b++) + { + const B2DPoint aPoint(aPolygon.getB2DPoint(b)); + const com::sun::star::awt::Point aAPIPoint(fround(aPoint.getX()), fround(aPoint.getY())); + + *pSequence = aAPIPoint; + pSequence++; + } + + // copy first point if closed + if(bIsClosed) + { + *pSequence = *rPointSequenceRetval.getArray(); + } + } + else + { + rPointSequenceRetval.realloc(0); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // converters for com::sun::star::drawing::PointSequence and + // com::sun::star::drawing::FlagSequence to B2DPolygon (curved polygons) + + B2DPolygon UnoPolygonBezierCoordsToB2DPolygon( + const com::sun::star::drawing::PointSequence& rPointSequenceSource, + const com::sun::star::drawing::FlagSequence& rFlagSequenceSource, + bool bCheckClosed) + { + const sal_uInt32 nCount((sal_uInt32)rPointSequenceSource.getLength()); + OSL_ENSURE(nCount == (sal_uInt32)rFlagSequenceSource.getLength(), + "UnoPolygonBezierCoordsToB2DPolygon: Unequal count of Points and Flags (!)"); + + // prepare new polygon + B2DPolygon aRetval; + const com::sun::star::awt::Point* pPointSequence = rPointSequenceSource.getConstArray(); + const com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceSource.getConstArray(); + + // get first point and flag + B2DPoint aNewCoordinatePair(pPointSequence->X, pPointSequence->Y); pPointSequence++; + com::sun::star::drawing::PolygonFlags ePolygonFlag(*pFlagSequence); pFlagSequence++; + B2DPoint aControlA; + B2DPoint aControlB; + + // first point is not allowed to be a control point + OSL_ENSURE(com::sun::star::drawing::PolygonFlags_CONTROL != ePolygonFlag, + "UnoPolygonBezierCoordsToB2DPolygon: Start point is a control point, illegal input polygon (!)"); + + // add first point as start point + aRetval.append(aNewCoordinatePair); + + for(sal_uInt32 b(1); b < nCount;) + { + // prepare loop + bool bControlA(false); + bool bControlB(false); + + // get next point and flag + aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y); + ePolygonFlag = *pFlagSequence; + pPointSequence++; pFlagSequence++; b++; + + if(b < nCount && com::sun::star::drawing::PolygonFlags_CONTROL == ePolygonFlag) + { + aControlA = aNewCoordinatePair; + bControlA = true; + + // get next point and flag + aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y); + ePolygonFlag = *pFlagSequence; + pPointSequence++; pFlagSequence++; b++; + } + + if(b < nCount && com::sun::star::drawing::PolygonFlags_CONTROL == ePolygonFlag) + { + aControlB = aNewCoordinatePair; + bControlB = true; + + // get next point and flag + aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y); + ePolygonFlag = *pFlagSequence; + pPointSequence++; pFlagSequence++; 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 + OSL_ENSURE(com::sun::star::drawing::PolygonFlags_CONTROL != ePolygonFlag && bControlA == bControlB, + "UnoPolygonBezierCoordsToB2DPolygon: Illegal source polygon (!)"); + + // 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(aRetval.getB2DPoint(aRetval.count() - 1))) + { + bControlA = bControlB = false; + } + + if(bControlA) + { + // add bezier edge + aRetval.appendBezierSegment(aControlA, aControlB, aNewCoordinatePair); + } + else + { + // add edge + aRetval.append(aNewCoordinatePair); + } + } + + // #i72807# API import uses old line start/end-equal definition for closed, + // so we need to correct this to closed state here + if(bCheckClosed) + { + checkClosed(aRetval); + } + + return aRetval; + } + + void B2DPolygonToUnoPolygonBezierCoords( + const B2DPolygon& rPolygon, + com::sun::star::drawing::PointSequence& rPointSequenceRetval, + com::sun::star::drawing::FlagSequence& rFlagSequenceRetval) + { + const sal_uInt32 nPointCount(rPolygon.count()); + + if(nPointCount) + { + const bool bCurve(rPolygon.areControlPointsUsed()); + const bool bClosed(rPolygon.isClosed()); + + if(nPointCount) + { + if(bCurve) + { + // calculate target point count + const sal_uInt32 nLoopCount(bClosed ? nPointCount : (nPointCount ? nPointCount - 1 : 0)); + + if(nLoopCount) + { + // prepare target data. The real needed number of target points (and flags) + // could only be calculated by using two loops, so use dynamic memory + std::vector< com::sun::star::awt::Point > aCollectPoints; + std::vector< com::sun::star::drawing::PolygonFlags > aCollectFlags; + + // reserve maximum creatable points + const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1); + aCollectPoints.reserve(nMaxTargetCount); + aCollectFlags.reserve(nMaxTargetCount); + + // prepare current bezier segment by setting start point + B2DCubicBezier aBezierSegment; + aBezierSegment.setStartPoint(rPolygon.getB2DPoint(0)); + + for(sal_uInt32 a(0); a < nLoopCount; a++) + { + // add current point (always) and remember StartPointIndex for evtl. later corrections + const sal_uInt32 nStartPointIndex(aCollectPoints.size()); + aCollectPoints.push_back( + com::sun::star::awt::Point( + fround(aBezierSegment.getStartPoint().getX()), + fround(aBezierSegment.getStartPoint().getY()))); + aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL); + + // prepare next segment + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + aBezierSegment.setEndPoint(rPolygon.getB2DPoint(nNextIndex)); + aBezierSegment.setControlPointA(rPolygon.getNextControlPoint(a)); + aBezierSegment.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex)); + + if(aBezierSegment.isBezier()) + { + // if bezier is used, add always two control points due to the old schema + aCollectPoints.push_back( + com::sun::star::awt::Point( + fround(aBezierSegment.getControlPointA().getX()), + fround(aBezierSegment.getControlPointA().getY()))); + aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_CONTROL); + + aCollectPoints.push_back( + com::sun::star::awt::Point( + fround(aBezierSegment.getControlPointB().getX()), + fround(aBezierSegment.getControlPointB().getY()))); + aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_CONTROL); + } + + // test continuity with previous control point to set flag value + if(aBezierSegment.getControlPointA() != aBezierSegment.getStartPoint() && (bClosed || a)) + { + const B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a)); + + if(CONTINUITY_C1 == eCont) + { + aCollectFlags[nStartPointIndex] = com::sun::star::drawing::PolygonFlags_SMOOTH; + } + else if(CONTINUITY_C2 == eCont) + { + aCollectFlags[nStartPointIndex] = com::sun::star::drawing::PolygonFlags_SYMMETRIC; + } + } + + // prepare next loop + aBezierSegment.setStartPoint(aBezierSegment.getEndPoint()); + } + + if(bClosed) + { + // add first point again as closing point due to old definition + aCollectPoints.push_back(aCollectPoints[0]); + aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL); + } + else + { + // add last point as closing point + const B2DPoint aClosingPoint(rPolygon.getB2DPoint(nPointCount - 1L)); + aCollectPoints.push_back( + com::sun::star::awt::Point( + fround(aClosingPoint.getX()), + fround(aClosingPoint.getY()))); + aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL); + } + + // copy collected data to target arrays + const sal_uInt32 nTargetCount(aCollectPoints.size()); + OSL_ENSURE(nTargetCount == aCollectFlags.size(), "Unequal Point and Flag count (!)"); + + rPointSequenceRetval.realloc((sal_Int32)nTargetCount); + rFlagSequenceRetval.realloc((sal_Int32)nTargetCount); + com::sun::star::awt::Point* pPointSequence = rPointSequenceRetval.getArray(); + com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceRetval.getArray(); + + for(sal_uInt32 a(0); a < nTargetCount; a++) + { + *pPointSequence = aCollectPoints[a]; + *pFlagSequence = aCollectFlags[a]; + pPointSequence++; + pFlagSequence++; + } + } + } + else + { + // straightforward point list creation + const sal_uInt32 nTargetCount(nPointCount + (bClosed ? 1 : 0)); + + rPointSequenceRetval.realloc((sal_Int32)nTargetCount); + rFlagSequenceRetval.realloc((sal_Int32)nTargetCount); + + com::sun::star::awt::Point* pPointSequence = rPointSequenceRetval.getArray(); + com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceRetval.getArray(); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const B2DPoint aB2DPoint(rPolygon.getB2DPoint(a)); + const com::sun::star::awt::Point aAPIPoint( + fround(aB2DPoint.getX()), + fround(aB2DPoint.getY())); + + *pPointSequence = aAPIPoint; + *pFlagSequence = com::sun::star::drawing::PolygonFlags_NORMAL; + pPointSequence++; + pFlagSequence++; + } + + if(bClosed) + { + // add first point as closing point + *pPointSequence = *rPointSequenceRetval.getConstArray(); + *pFlagSequence = com::sun::star::drawing::PolygonFlags_NORMAL; + } + } + } + } + else + { + rPointSequenceRetval.realloc(0); + rFlagSequenceRetval.realloc(0); + } + } + } // end of namespace tools } // end of namespace basegfx diff --git a/basegfx/source/polygon/b2dpolypolygontools.cxx b/basegfx/source/polygon/b2dpolypolygontools.cxx index 11a3e8a29615..f1ba12b67663 100644 --- a/basegfx/source/polygon/b2dpolypolygontools.cxx +++ b/basegfx/source/polygon/b2dpolypolygontools.cxx @@ -24,7 +24,6 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/numeric/ftools.hxx> #include <basegfx/polygon/b2dpolypolygoncutter.hxx> - #include <numeric> ////////////////////////////////////////////////////////////////////////////// @@ -648,6 +647,119 @@ namespace basegfx return aRes; } + ////////////////////////////////////////////////////////////////////////////// + // converters for com::sun::star::drawing::PointSequence + + B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon( + const com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceSource, + bool bCheckClosed) + { + B2DPolyPolygon aRetval; + const com::sun::star::drawing::PointSequence* pPointSequence = rPointSequenceSequenceSource.getConstArray(); + const com::sun::star::drawing::PointSequence* pPointSeqEnd = pPointSequence + rPointSequenceSequenceSource.getLength(); + + for(;pPointSequence != pPointSeqEnd; pPointSequence++) + { + const B2DPolygon aNewPolygon = UnoPointSequenceToB2DPolygon(*pPointSequence, bCheckClosed); + aRetval.append(aNewPolygon); + } + + return aRetval; + } + + void B2DPolyPolygonToUnoPointSequenceSequence( + const B2DPolyPolygon& rPolyPolygon, + com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceRetval) + { + const sal_uInt32 nCount(rPolyPolygon.count()); + + if(nCount) + { + rPointSequenceSequenceRetval.realloc(nCount); + com::sun::star::drawing::PointSequence* pPointSequence = rPointSequenceSequenceRetval.getArray(); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(a)); + + B2DPolygonToUnoPointSequence(aPolygon, *pPointSequence); + pPointSequence++; + } + } + else + { + rPointSequenceSequenceRetval.realloc(0); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // converters for com::sun::star::drawing::PolyPolygonBezierCoords (curved polygons) + + B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + const com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource, + bool bCheckClosed) + { + B2DPolyPolygon aRetval; + const sal_uInt32 nSequenceCount((sal_uInt32)rPolyPolygonBezierCoordsSource.Coordinates.getLength()); + + if(nSequenceCount) + { + OSL_ENSURE(nSequenceCount == (sal_uInt32)rPolyPolygonBezierCoordsSource.Flags.getLength(), + "UnoPolyPolygonBezierCoordsToB2DPolyPolygon: unequal number of Points and Flags (!)"); + const com::sun::star::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsSource.Coordinates.getConstArray(); + const com::sun::star::drawing::FlagSequence* pFlagSequence = rPolyPolygonBezierCoordsSource.Flags.getConstArray(); + + for(sal_uInt32 a(0); a < nSequenceCount; a++) + { + const B2DPolygon aNewPolygon(UnoPolygonBezierCoordsToB2DPolygon( + *pPointSequence, + *pFlagSequence, + bCheckClosed)); + + pPointSequence++; + pFlagSequence++; + aRetval.append(aNewPolygon); + } + } + + return aRetval; + } + + void B2DPolyPolygonToUnoPolyPolygonBezierCoords( + const B2DPolyPolygon& rPolyPolygon, + com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval) + { + const sal_uInt32 nCount(rPolyPolygon.count()); + + if(nCount) + { + // prepare return value memory + rPolyPolygonBezierCoordsRetval.Coordinates.realloc((sal_Int32)nCount); + rPolyPolygonBezierCoordsRetval.Flags.realloc((sal_Int32)nCount); + + // get pointers to arrays + com::sun::star::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsRetval.Coordinates.getArray(); + com::sun::star::drawing::FlagSequence* pFlagSequence = rPolyPolygonBezierCoordsRetval.Flags.getArray(); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const B2DPolygon aSource(rPolyPolygon.getB2DPolygon(a)); + + B2DPolygonToUnoPolygonBezierCoords( + aSource, + *pPointSequence, + *pFlagSequence); + pPointSequence++; + pFlagSequence++; + } + } + else + { + rPolyPolygonBezierCoordsRetval.Coordinates.realloc(0); + rPolyPolygonBezierCoordsRetval.Flags.realloc(0); + } + } + } // end of namespace tools } // end of namespace basegfx diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx index 6a1dffa4e3a5..46675643ae81 100644 --- a/basegfx/source/polygon/b2dsvgpolypolygon.cxx +++ b/basegfx/source/polygon/b2dsvgpolypolygon.cxx @@ -24,227 +24,91 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <rtl/ustring.hxx> #include <rtl/math.hxx> +#include <stringconversiontools.hxx> namespace basegfx { namespace tools { - namespace + bool PointIndex::operator<(const PointIndex& rComp) const { - void lcl_skipSpaces(sal_Int32& io_rPos, - const OUString& rStr, - const sal_Int32 nLen) + if(rComp.getPolygonIndex() == getPolygonIndex()) { - while( io_rPos < nLen && - sal_Unicode(' ') == rStr[io_rPos] ) - { - ++io_rPos; - } - } - - void lcl_skipSpacesAndCommas(sal_Int32& io_rPos, - const OUString& rStr, - const sal_Int32 nLen) - { - while(io_rPos < nLen - && (sal_Unicode(' ') == rStr[io_rPos] || sal_Unicode(',') == rStr[io_rPos])) - { - ++io_rPos; - } - } - - inline bool lcl_isOnNumberChar(const sal_Unicode aChar, bool bSignAllowed = true) - { - const bool bPredicate( (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) - || (bSignAllowed && sal_Unicode('+') == aChar) - || (bSignAllowed && sal_Unicode('-') == aChar) - || (sal_Unicode('.') == aChar) ); - - return bPredicate; - } - - inline bool lcl_isOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true) - { - return lcl_isOnNumberChar(rStr[nPos], - bSignAllowed); - } - - bool lcl_getDoubleChar(double& o_fRetval, - sal_Int32& io_rPos, - const OUString& rStr) - { - sal_Unicode aChar( rStr[io_rPos] ); - OUStringBuffer sNumberString; - bool separator_seen=false; - - if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar) - { - sNumberString.append(rStr[io_rPos]); - aChar = rStr[++io_rPos]; - } - - while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) - || (!separator_seen && sal_Unicode('.') == aChar)) - { - if (sal_Unicode('.') == aChar) separator_seen = true; - sNumberString.append(rStr[io_rPos]); - io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; - } - - if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar) - { - sNumberString.append(rStr[io_rPos]); - io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; - - if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar) - { - sNumberString.append(rStr[io_rPos]); - io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; - } - - while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) - { - sNumberString.append(rStr[io_rPos]); - io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; - } - } - - if(!sNumberString.isEmpty()) - { - rtl_math_ConversionStatus eStatus; - o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(), - (sal_Unicode)('.'), - (sal_Unicode)(','), - &eStatus, - NULL ); - return ( eStatus == rtl_math_ConversionStatus_Ok ); - } - - return false; - } - - bool lcl_importDoubleAndSpaces( double& o_fRetval, - sal_Int32& io_rPos, - const OUString& rStr, - const sal_Int32 nLen ) - { - if( !lcl_getDoubleChar(o_fRetval, io_rPos, rStr) ) - return false; - - lcl_skipSpacesAndCommas(io_rPos, rStr, nLen); - - return true; - } - - bool lcl_importFlagAndSpaces(sal_Int32& o_nRetval, - sal_Int32& io_rPos, - const OUString& rStr, - const sal_Int32 nLen) - { - sal_Unicode aChar( rStr[io_rPos] ); - - if(sal_Unicode('0') == aChar) - { - o_nRetval = 0; - ++io_rPos; - } - else if (sal_Unicode('1') == aChar) - { - o_nRetval = 1; - ++io_rPos; - } - else - return false; - - lcl_skipSpacesAndCommas(io_rPos, rStr, nLen); - - return true; - } - - void lcl_putNumberChar( OUStringBuffer& rStr, - double fValue ) - { - rStr.append( fValue ); - } - - void lcl_putNumberCharWithSpace( OUStringBuffer& rStr, - double fValue, - double fOldValue, - bool bUseRelativeCoordinates ) - { - if( bUseRelativeCoordinates ) - fValue -= fOldValue; - - const sal_Int32 aLen( rStr.getLength() ); - if(aLen > 0) - { - if( lcl_isOnNumberChar(rStr[aLen - 1], false) && - fValue >= 0.0 ) - { - rStr.append( sal_Unicode(' ') ); - } - } - - lcl_putNumberChar(rStr, fValue); + return rComp.getPointIndex() < getPointIndex(); } - inline sal_Unicode lcl_getCommand( sal_Char cUpperCaseCommand, - sal_Char cLowerCaseCommand, - bool bUseRelativeCoordinates ) - { - return bUseRelativeCoordinates ? cLowerCaseCommand : cUpperCaseCommand; - } + return rComp.getPolygonIndex() < getPolygonIndex(); } - bool importFromSvgD(B2DPolyPolygon& o_rPolyPolygon, const OUString& rSvgDStatement, bool bWrongPositionAfterZ) + bool importFromSvgD( + B2DPolyPolygon& o_rPolyPolygon, + const OUString& rSvgDStatement, + bool bHandleRelativeNextPointCompatible, + PointIndexSet* pHelpPointIndexSet) { o_rPolyPolygon.clear(); const sal_Int32 nLen(rSvgDStatement.getLength()); sal_Int32 nPos(0); - bool bIsClosed(false); double nLastX( 0.0 ); double nLastY( 0.0 ); B2DPolygon aCurrPoly; // skip initial whitespace - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); while(nPos < nLen) { bool bRelative(false); - bool bMoveTo(false); const sal_Unicode aCurrChar(rSvgDStatement[nPos]); + if(o_rPolyPolygon.count() && !aCurrPoly.count() && !('m' == aCurrChar || 'M' == aCurrChar)) + { + // we have a new sub-polygon starting, but without a 'moveto' command. + // this requires to add the current point as start point to the polygon + // (see SVG1.1 8.3.3 The "closepath" command) + aCurrPoly.append(B2DPoint(nLastX, nLastY)); + } + switch(aCurrChar) { case 'z' : case 'Z' : { + // consume CurrChar and whitespace nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - // remember closed state of current polygon - bIsClosed = true; - - // update current point - we're back at the start - if( aCurrPoly.count() && !bWrongPositionAfterZ) + // create closed polygon and reset import values + if(aCurrPoly.count()) { - const B2DPoint aFirst( aCurrPoly.getB2DPoint(0) ); - nLastX = aFirst.getX(); - nLastY = aFirst.getY(); + if(!bHandleRelativeNextPointCompatible) + { + // SVG defines that "the next subpath starts at the + // same initial point as the current subpath", so set the + // current point if we do not need to be compatible + nLastX = aCurrPoly.getB2DPoint(0).getX(); + nLastY = aCurrPoly.getB2DPoint(0).getY(); + } + + aCurrPoly.setClosed(true); + o_rPolyPolygon.append(aCurrPoly); + aCurrPoly.clear(); } + break; } case 'm' : case 'M' : { - bMoveTo = true; - // FALLTHROUGH intended + // create non-closed polygon and reset import values + if(aCurrPoly.count()) + { + o_rPolyPolygon.append(aCurrPoly); + aCurrPoly.clear(); + } + + // FALLTHROUGH intended to add coordinate data as 1st point of new polygon } case 'l' : case 'L' : @@ -254,37 +118,16 @@ namespace basegfx bRelative = true; } - if(bMoveTo) - { - // new polygon start, finish old one - if(aCurrPoly.count()) - { - // add current polygon - if(bIsClosed) - { - // #i123465# no need to do the old closeWithGeometryChange - // corerection on SVG polygons; this even may lead to wrong - // results e.g. for marker processing - aCurrPoly.setClosed(true); - } - - o_rPolyPolygon.append(aCurrPoly); - - // reset import values - bIsClosed = false; - aCurrPoly.clear(); - } - } - + // consume CurrChar and whitespace nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -310,13 +153,13 @@ namespace basegfx case 'H' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY(nLastY); - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -340,13 +183,13 @@ namespace basegfx case 'V' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX(nLastX), nY; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -370,17 +213,17 @@ namespace basegfx case 'S' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; double nX2, nY2; - if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -429,20 +272,20 @@ namespace basegfx case 'C' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; double nX1, nY1; double nX2, nY2; - if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -479,17 +322,17 @@ namespace basegfx case 'Q' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; double nX1, nY1; - if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -530,14 +373,14 @@ namespace basegfx case 'T' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -604,21 +447,21 @@ namespace basegfx case 'A' : { nPos++; - lcl_skipSpaces(nPos, rSvgDStatement, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgDStatement, nLen); - while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos)) + while(nPos < nLen && ::basegfx::internal::lcl_isOnNumberChar(rSvgDStatement, nPos)) { double nX, nY; double fRX, fRY, fPhi; sal_Int32 bLargeArcFlag, bSweepFlag; - if(!lcl_importDoubleAndSpaces(fRX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(fRY, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(fPhi, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importFlagAndSpaces(bLargeArcFlag, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importFlagAndSpaces(bSweepFlag, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(fRX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(fRY, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(fPhi, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importFlagAndSpaces(bLargeArcFlag, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importFlagAndSpaces(bSweepFlag, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false; if(bRelative) { @@ -749,7 +592,22 @@ namespace basegfx // if we swapped angles above if( !bSweepFlag ) aSegment.flip(); + + // remember PointIndex of evtl. added pure helper points + sal_uInt32 nPointIndex(aCurrPoly.count() + 1); aCurrPoly.append(aSegment); + + // if asked for, mark pure helper points by adding them to the index list of + // helper points + if(pHelpPointIndexSet && aCurrPoly.count() > 1) + { + const sal_uInt32 nPolyIndex(o_rPolyPolygon.count()); + + for(;nPointIndex + 1 < aCurrPoly.count(); nPointIndex++) + { + pHelpPointIndexSet->insert(PointIndex(nPolyIndex, nPointIndex)); + } + } } // set last position @@ -769,17 +627,9 @@ namespace basegfx } } + // if there is polygon data, create non-closed polygon if(aCurrPoly.count()) { - // end-process last poly - if(bIsClosed) - { - // #i123465# no need to do the old closeWithGeometryChange - // corerection on SVG polygons; this even may lead to wrong - // results e.g. for marker processing - aCurrPoly.setClosed(true); - } - o_rPolyPolygon.append(aCurrPoly); } @@ -795,27 +645,51 @@ namespace basegfx double nX, nY; // skip initial whitespace - lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen); while(nPos < nLen) { - if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgPointsAttribute, nLen)) return false; - if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgPointsAttribute, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nX, nPos, rSvgPointsAttribute, nLen)) return false; + if(!::basegfx::internal::lcl_importDoubleAndSpaces(nY, nPos, rSvgPointsAttribute, nLen)) return false; // add point o_rPoly.append(B2DPoint(nX, nY)); // skip to next number, or finish - lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen); + ::basegfx::internal::lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen); } return true; } + OUString exportToSvgPoints( const B2DPolygon& rPoly ) + { + OSL_ENSURE(!rPoly.areControlPointsUsed(), "exportToSvgPoints: Only non-bezier polygons allowed (!)"); + const sal_uInt32 nPointCount(rPoly.count()); + OUStringBuffer aResult; + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const basegfx::B2DPoint aPoint(rPoly.getB2DPoint(a)); + + if(a) + { + aResult.append(sal_Unicode(' ')); + } + + ::basegfx::internal::lcl_putNumberChar(aResult, aPoint.getX()); + aResult.append(sal_Unicode(',')); + ::basegfx::internal::lcl_putNumberChar(aResult, aPoint.getY()); + } + + return aResult.makeStringAndClear(); + } + OUString exportToSvgD( const B2DPolyPolygon& rPolyPolygon, bool bUseRelativeCoordinates, - bool bDetectQuadraticBeziers) + bool bDetectQuadraticBeziers, + bool bHandleRelativeNextPointCompatible) { const sal_uInt32 nCount(rPolyPolygon.count()); OUStringBuffer aResult; @@ -835,10 +709,21 @@ namespace basegfx // handle polygon start point B2DPoint aEdgeStart(aPolygon.getB2DPoint(0)); - aResult.append(lcl_getCommand('M', 'm', bUseRelativeCoordinates)); - lcl_putNumberCharWithSpace(aResult, aEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); - aLastSVGCommand = lcl_getCommand('L', 'l', bUseRelativeCoordinates); + bool bUseRelativeCoordinatesForFirstPoint(bUseRelativeCoordinates); + + if(bHandleRelativeNextPointCompatible) + { + // To get around the error that the start point for the next polygon is the + // start point of the current one (and not the last as it was handled up to now) + // do force to write an absolute 'M' command as start for the next polygon + bUseRelativeCoordinatesForFirstPoint = false; + } + + // Write 'moveto' and the 1st coordinates, set aLastSVGCommand to 'lineto' + aResult.append(::basegfx::internal::lcl_getCommand('M', 'm', bUseRelativeCoordinatesForFirstPoint)); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinatesForFirstPoint); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinatesForFirstPoint); + aLastSVGCommand = ::basegfx::internal::lcl_getCommand('L', 'l', bUseRelativeCoordinatesForFirstPoint); aCurrentSVGPosition = aEdgeStart; for(sal_uInt32 nIndex(0); nIndex < nEdgeCount; nIndex++) @@ -892,7 +777,7 @@ namespace basegfx // approximately equal, export as quadratic bezier if(bSymmetricAtEdgeStart) { - const sal_Unicode aCommand(lcl_getCommand('T', 't', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('T', 't', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -900,14 +785,14 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aLastSVGCommand = aCommand; aCurrentSVGPosition = aEdgeEnd; } else { - const sal_Unicode aCommand(lcl_getCommand('Q', 'q', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('Q', 'q', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -915,10 +800,10 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aLeft.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aLeft.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aLeft.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aLeft.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aLastSVGCommand = aCommand; aCurrentSVGPosition = aEdgeEnd; } @@ -928,7 +813,7 @@ namespace basegfx // export as cubic bezier if(bSymmetricAtEdgeStart) { - const sal_Unicode aCommand(lcl_getCommand('S', 's', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('S', 's', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -936,16 +821,16 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aLastSVGCommand = aCommand; aCurrentSVGPosition = aEdgeEnd; } else { - const sal_Unicode aCommand(lcl_getCommand('C', 'c', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('C', 'c', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -953,12 +838,12 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aLastSVGCommand = aCommand; aCurrentSVGPosition = aEdgeEnd; } @@ -984,7 +869,7 @@ namespace basegfx else if(bXEqual) { // export as vertical line - const sal_Unicode aCommand(lcl_getCommand('V', 'v', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('V', 'v', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -992,13 +877,13 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aCurrentSVGPosition = aEdgeEnd; } else if(bYEqual) { // export as horizontal line - const sal_Unicode aCommand(lcl_getCommand('H', 'h', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('H', 'h', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -1006,13 +891,13 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); aCurrentSVGPosition = aEdgeEnd; } else { // export as line - const sal_Unicode aCommand(lcl_getCommand('L', 'l', bUseRelativeCoordinates)); + const sal_Unicode aCommand(::basegfx::internal::lcl_getCommand('L', 'l', bUseRelativeCoordinates)); if(aLastSVGCommand != aCommand) { @@ -1020,8 +905,8 @@ namespace basegfx aLastSVGCommand = aCommand; } - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); - lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates); + ::basegfx::internal::lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates); aCurrentSVGPosition = aEdgeEnd; } } @@ -1034,8 +919,13 @@ namespace basegfx // close path if closed poly (Z and z are equivalent here, but looks nicer when case is matched) if(aPolygon.isClosed()) { - aResult.append(lcl_getCommand('Z', 'z', bUseRelativeCoordinates)); - // return to first point + aResult.append(::basegfx::internal::lcl_getCommand('Z', 'z', bUseRelativeCoordinates)); + } + + if(!bHandleRelativeNextPointCompatible) + { + // SVG defines that "the next subpath starts at the same initial point as the current subpath", + // so set aCurrentSVGPosition to the 1st point of the current, now ended and written path aCurrentSVGPosition = aPolygon.getB2DPoint(0); } } diff --git a/basegfx/source/polygon/b3dpolypolygontools.cxx b/basegfx/source/polygon/b3dpolypolygontools.cxx index dd7fa412235e..83241d8bfa87 100644 --- a/basegfx/source/polygon/b3dpolypolygontools.cxx +++ b/basegfx/source/polygon/b3dpolypolygontools.cxx @@ -26,6 +26,7 @@ #include <numeric> #include <basegfx/matrix/b3dhommatrix.hxx> #include <basegfx/numeric/ftools.hxx> +#include <com/sun/star/drawing/DoubleSequence.hpp> ////////////////////////////////////////////////////////////////////////////// // predefines @@ -483,6 +484,158 @@ namespace basegfx } } + ////////////////////////////////////////////////////////////////////// + // comparators with tolerance for 3D PolyPolygons + + bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB, const double& rfSmallValue) + { + const sal_uInt32 nPolygonCount(rCandidateA.count()); + + if(nPolygonCount != rCandidateB.count()) + return false; + + for(sal_uInt32 a(0); a < nPolygonCount; a++) + { + const B3DPolygon aCandidate(rCandidateA.getB3DPolygon(a)); + + if(!equal(aCandidate, rCandidateB.getB3DPolygon(a), rfSmallValue)) + return false; + } + + return true; + } + + bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB) + { + const double fSmallValue(fTools::getSmallValue()); + + return equal(rCandidateA, rCandidateB, fSmallValue); + } + +/// converters for com::sun::star::drawing::PolyPolygonShape3D + B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon( + const com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource, + bool bCheckClosed) + { + B3DPolyPolygon aRetval; + const sal_Int32 nOuterSequenceCount(rPolyPolygonShape3DSource.SequenceX.getLength()); + + if(nOuterSequenceCount) + { + OSL_ENSURE(nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceY.getLength() + && nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceZ.getLength(), + "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)"); + + const com::sun::star::drawing::DoubleSequence* pInnerSequenceX = rPolyPolygonShape3DSource.SequenceX.getConstArray(); + const com::sun::star::drawing::DoubleSequence* pInnerSequenceY = rPolyPolygonShape3DSource.SequenceY.getConstArray(); + const com::sun::star::drawing::DoubleSequence* pInnerSequenceZ = rPolyPolygonShape3DSource.SequenceZ.getConstArray(); + + for(sal_Int32 a(0); a < nOuterSequenceCount; a++) + { + basegfx::B3DPolygon aNewPolygon; + const sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength()); + OSL_ENSURE(nInnerSequenceCount == pInnerSequenceY->getLength() + && nInnerSequenceCount == pInnerSequenceZ->getLength(), + "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)"); + + const double* pArrayX = pInnerSequenceX->getConstArray(); + const double* pArrayY = pInnerSequenceY->getConstArray(); + const double* pArrayZ = pInnerSequenceZ->getConstArray(); + + for(sal_Int32 b(0); b < nInnerSequenceCount; b++) + { + aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++)); + } + + pInnerSequenceX++; + pInnerSequenceY++; + pInnerSequenceZ++; + + // #i101520# correction is needed for imported polygons of old format, + // see callers + if(bCheckClosed) + { + basegfx::tools::checkClosed(aNewPolygon); + } + + aRetval.append(aNewPolygon); + } + } + + return aRetval; + } + + void B3DPolyPolygonToUnoPolyPolygonShape3D( + const B3DPolyPolygon& rPolyPolygonSource, + com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval) + { + const sal_uInt32 nPolygonCount(rPolyPolygonSource.count()); + + if(nPolygonCount) + { + rPolyPolygonShape3DRetval.SequenceX.realloc(nPolygonCount); + rPolyPolygonShape3DRetval.SequenceY.realloc(nPolygonCount); + rPolyPolygonShape3DRetval.SequenceZ.realloc(nPolygonCount); + + com::sun::star::drawing::DoubleSequence* pOuterSequenceX = rPolyPolygonShape3DRetval.SequenceX.getArray(); + com::sun::star::drawing::DoubleSequence* pOuterSequenceY = rPolyPolygonShape3DRetval.SequenceY.getArray(); + com::sun::star::drawing::DoubleSequence* pOuterSequenceZ = rPolyPolygonShape3DRetval.SequenceZ.getArray(); + + for(sal_uInt32 a(0); a < nPolygonCount; a++) + { + const basegfx::B3DPolygon aPoly(rPolyPolygonSource.getB3DPolygon(a)); + const sal_uInt32 nPointCount(aPoly.count()); + + if(nPointCount) + { + const bool bIsClosed(aPoly.isClosed()); + const sal_uInt32 nTargetCount(bIsClosed ? nPointCount + 1 : nPointCount); + pOuterSequenceX->realloc(nTargetCount); + pOuterSequenceY->realloc(nTargetCount); + pOuterSequenceZ->realloc(nTargetCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_uInt32 b(0); b < nPointCount; b++) + { + const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b)); + + *pInnerSequenceX++ = aPoint.getX(); + *pInnerSequenceY++ = aPoint.getY(); + *pInnerSequenceZ++ = aPoint.getZ(); + } + + if(bIsClosed) + { + const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0)); + + *pInnerSequenceX++ = aPoint.getX(); + *pInnerSequenceY++ = aPoint.getY(); + *pInnerSequenceZ++ = aPoint.getZ(); + } + } + else + { + pOuterSequenceX->realloc(0); + pOuterSequenceY->realloc(0); + pOuterSequenceZ->realloc(0); + } + + pOuterSequenceX++; + pOuterSequenceY++; + pOuterSequenceZ++; + } + } + else + { + rPolyPolygonShape3DRetval.SequenceX.realloc(0); + rPolyPolygonShape3DRetval.SequenceY.realloc(0); + rPolyPolygonShape3DRetval.SequenceZ.realloc(0); + } + } + } // end of namespace tools } // end of namespace basegfx diff --git a/basegfx/source/tools/stringconversiontools.cxx b/basegfx/source/tools/stringconversiontools.cxx new file mode 100644 index 000000000000..bc5cfb240745 --- /dev/null +++ b/basegfx/source/tools/stringconversiontools.cxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stringconversiontools.hxx> +#include <rtl/math.hxx> + +namespace basegfx +{ + namespace internal + { + void lcl_skipSpaces(sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen) + { + while( io_rPos < nLen && + sal_Unicode(' ') == rStr[io_rPos] ) + { + ++io_rPos; + } + } + + void lcl_skipSpacesAndCommas(sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen) + { + while(io_rPos < nLen + && (sal_Unicode(' ') == rStr[io_rPos] || sal_Unicode(',') == rStr[io_rPos])) + { + ++io_rPos; + } + } + + bool lcl_getDoubleChar(double& o_fRetval, + sal_Int32& io_rPos, + const OUString& rStr) + { + sal_Unicode aChar( rStr[io_rPos] ); + OUStringBuffer sNumberString; + bool separator_seen=false; + + if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar) + { + sNumberString.append(rStr[io_rPos]); + aChar = rStr[++io_rPos]; + } + + while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) + || (!separator_seen && sal_Unicode('.') == aChar)) + { + if (sal_Unicode('.') == aChar) separator_seen = true; + sNumberString.append(rStr[io_rPos]); + io_rPos++; + aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + } + + if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar) + { + sNumberString.append(rStr[io_rPos]); + io_rPos++; + aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + + if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar) + { + sNumberString.append(rStr[io_rPos]); + io_rPos++; + aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + } + + while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) + { + sNumberString.append(rStr[io_rPos]); + io_rPos++; + aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + } + } + + if(sNumberString.getLength()) + { + rtl_math_ConversionStatus eStatus; + o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(), + (sal_Unicode)('.'), + (sal_Unicode)(','), + &eStatus, + NULL ); + return ( eStatus == rtl_math_ConversionStatus_Ok ); + } + + return false; + } + + bool lcl_importDoubleAndSpaces( double& o_fRetval, + sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen ) + { + if( !lcl_getDoubleChar(o_fRetval, io_rPos, rStr) ) + return false; + + lcl_skipSpacesAndCommas(io_rPos, rStr, nLen); + + return true; + } + + bool lcl_importFlagAndSpaces(sal_Int32& o_nRetval, + sal_Int32& io_rPos, + const OUString& rStr, + const sal_Int32 nLen) + { + sal_Unicode aChar( rStr[io_rPos] ); + + if(sal_Unicode('0') == aChar) + { + o_nRetval = 0; + ++io_rPos; + } + else if (sal_Unicode('1') == aChar) + { + o_nRetval = 1; + ++io_rPos; + } + else + return false; + + lcl_skipSpacesAndCommas(io_rPos, rStr, nLen); + + return true; + } + + void lcl_putNumberCharWithSpace( OUStringBuffer& rStr, + double fValue, + double fOldValue, + bool bUseRelativeCoordinates ) + { + if( bUseRelativeCoordinates ) + fValue -= fOldValue; + + const sal_Int32 aLen( rStr.getLength() ); + if(aLen) + { + if( lcl_isOnNumberChar(rStr[aLen - 1], false) && + fValue >= 0.0 ) + { + rStr.append( sal_Unicode(' ') ); + } + } + + lcl_putNumberChar(rStr, fValue); + } + + } // namespace internal +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/test/basegfx2d.cxx b/basegfx/test/basegfx2d.cxx index 67ecb3e32d0b..15446780d6d6 100644 --- a/basegfx/test/basegfx2d.cxx +++ b/basegfx/test/basegfx2d.cxx @@ -142,23 +142,20 @@ public: OUString aExport; CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D", - tools::importFromSvgD( aPoly, - aPath0 )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aPath0, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); const char* sExportString = "m10 10h-20v-20h20z"; CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D", !aExport.compareToAscii(sExportString) ); CPPUNIT_ASSERT_MESSAGE("importing simple rectangle from SVG-D (round-trip", - tools::importFromSvgD( aPoly, - aExport )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aExport, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); CPPUNIT_ASSERT_MESSAGE("exporting rectangle to SVG-D (round-trip)", !aExport.compareToAscii(sExportString)); CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D", - tools::importFromSvgD( aPoly, - aPath1 )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aPath1, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); // Adaptions for B2DPolygon bezier change (see #i77162#): // @@ -185,11 +182,11 @@ public: // a 2nd good test is that re-importing of aExport has to create the same // B2DPolPolygon again: B2DPolyPolygon aReImport; - CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D", tools::importFromSvgD( aReImport, aExport)); + CPPUNIT_ASSERT_MESSAGE("importing simple bezier polygon from SVG-D", tools::importFromSvgD( aReImport, aExport, false, 0)); CPPUNIT_ASSERT_MESSAGE("re-imported polygon needs to be identical", aReImport == aPoly); - CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D", tools::importFromSvgD( aPoly, aPath2 )); - aExport = tools::exportToSvgD( aPoly ); + CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D", tools::importFromSvgD( aPoly, aPath2, false, NULL)); + aExport = tools::exportToSvgD( aPoly, true, true, false ); // Adaptions for B2DPolygon bezier change (see #i77162#): // @@ -205,22 +202,20 @@ public: "8 752-224 1128-21 101-31 183-31 245 0 39 9 70 26 93 17 24 39 36 67 36 145 0 279-80 400-240s182-365 182-615c0-2" "88-107-533-322-734s-487-301-816-301c-395 0-715 124-960 373s-368 569-368 958q0 577.5 357 900c237 216 557 324 95" "8 325 189-1 389-27 600-77 211-52 378-110 503-174q40.5 105 81 210z"; - CPPUNIT_ASSERT_MESSAGE("re-importing '@' from SVG-D", tools::importFromSvgD( aReImport, aExport)); + CPPUNIT_ASSERT_MESSAGE("re-importing '@' from SVG-D", tools::importFromSvgD( aReImport, aExport, false, 0)); CPPUNIT_ASSERT_MESSAGE("re-imported '@' needs to be identical", aReImport == aPoly); CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D", !aExport.compareToAscii(sExportString1)); CPPUNIT_ASSERT_MESSAGE("importing '@' from SVG-D (round-trip", - tools::importFromSvgD( aPoly, - aExport )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aExport, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); CPPUNIT_ASSERT_MESSAGE("exporting '@' to SVG-D (round-trip)", !aExport.compareToAscii(sExportString1)); CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D", - tools::importFromSvgD( aPoly, - aPath3 )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aPath3, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); const char* sExportString2 = "m1598 125h306v2334h-306v-1105h-1293v1105h-305v-2334h305v973h1293" "zm2159 1015 78-44 85 235-91 47-91 40-90 34-90 29-89 21-88 16-88 10-88 3-102-4-97" @@ -245,15 +240,14 @@ public: CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D", !aExport.compareToAscii(sExportString2)); CPPUNIT_ASSERT_MESSAGE("importing complex polygon from SVG-D (round-trip", - tools::importFromSvgD( aPoly, - aExport )); - aExport = tools::exportToSvgD( aPoly ); + tools::importFromSvgD( aPoly, aExport, false, 0 )); + aExport = tools::exportToSvgD( aPoly, true, true, false ); CPPUNIT_ASSERT_MESSAGE("exporting complex polygon to SVG-D (round-trip)", !aExport.compareToAscii(sExportString2)); const B2DPolygon aRect( tools::createPolygonFromRect( B2DRange(0.0,0.0,4000.0,4000.0) )); - aExport = tools::exportToSvgD( B2DPolyPolygon(aRect), false, false); + aExport = tools::exportToSvgD( B2DPolyPolygon(aRect), false, false, false ); const char* sExportStringRect = "M0 0H4000V4000H0Z"; CPPUNIT_ASSERT_MESSAGE("exporting to rectangle svg-d string", diff --git a/basegfx/test/boxclipper.cxx b/basegfx/test/boxclipper.cxx index a296871d7fe9..bb02dc521d48 100644 --- a/basegfx/test/boxclipper.cxx +++ b/basegfx/test/boxclipper.cxx @@ -165,7 +165,7 @@ public: B2DPolyPolygon randomPoly; tools::importFromSvgD( randomPoly, - OUString::createFromAscii(randomSvg)); + OUString::createFromAscii(randomSvg), false, 0); std::for_each(randomPoly.begin(), randomPoly.end(), boost::bind( @@ -240,16 +240,15 @@ public: B2DPolyPolygon aTmp1; CPPUNIT_ASSERT_MESSAGE(sName, tools::importFromSvgD( - aTmp1, - OUString::createFromAscii(sSvg))); + aTmp1, OUString::createFromAscii(sSvg), false, 0)); const OUString aSvg= - tools::exportToSvgD(toTest.solveCrossovers()); + tools::exportToSvgD(toTest.solveCrossovers(), true, true, false); B2DPolyPolygon aTmp2; CPPUNIT_ASSERT_MESSAGE(sName, tools::importFromSvgD( - aTmp2, - aSvg)); + aTmp2, aSvg, false, 0)); + CPPUNIT_ASSERT_MESSAGE( sName, normalizePoly(aTmp2) == normalizePoly(aTmp1)); @@ -321,7 +320,7 @@ public: #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "%s - svg:d=\"%s\"\n", pName, OUStringToOString( - basegfx::tools::exportToSvgD(rPoly), + basegfx::tools::exportToSvgD(rPoly, , true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); #endif } @@ -365,15 +364,14 @@ public: fprintf(stderr, "%s input - svg:d=\"%s\"\n", pName, OUStringToOString( basegfx::tools::exportToSvgD( - genericClip), + genericClip, , true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); #endif const B2DPolyPolygon boxClipResult=rRange.solveCrossovers(); const OUString boxClipSvg( basegfx::tools::exportToSvgD( - normalizePoly( - boxClipResult))); + normalizePoly(boxClipResult), true, true, false)); #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "%s boxclipper - svg:d=\"%s\"\n", pName, OUStringToOString( @@ -384,8 +382,7 @@ public: genericClip = tools::solveCrossovers(genericClip); const OUString genericClipSvg( basegfx::tools::exportToSvgD( - normalizePoly( - genericClip))); + normalizePoly(genericClip), true, true, false)); #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "%s genclipper - svg:d=\"%s\"\n", pName, OUStringToOString( diff --git a/basegfx/test/clipstate.cxx b/basegfx/test/clipstate.cxx index f2b0ef0e94b7..ffdc35397fb8 100644 --- a/basegfx/test/clipstate.cxx +++ b/basegfx/test/clipstate.cxx @@ -95,23 +95,21 @@ public: #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "%s - svg:d=\"%s\"\n", sName, OUStringToOString( - basegfx::tools::exportToSvgD(toTest.getClipPoly()), + basegfx::tools::exportToSvgD(toTest.getClipPoly(), true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); #endif B2DPolyPolygon aTmp1; CPPUNIT_ASSERT_MESSAGE(sName, tools::importFromSvgD( - aTmp1, - OUString::createFromAscii(sSvg))); + aTmp1, OUString::createFromAscii(sSvg), false, 0)); const OUString aSvg= - tools::exportToSvgD(toTest.getClipPoly()); + tools::exportToSvgD(toTest.getClipPoly(), true, true, false); B2DPolyPolygon aTmp2; CPPUNIT_ASSERT_MESSAGE(sName, tools::importFromSvgD( - aTmp2, - aSvg)); + aTmp2, aSvg, false, 0)); CPPUNIT_ASSERT_MESSAGE( sName, @@ -142,8 +140,7 @@ public: B2DPolyPolygon aTmp1; tools::importFromSvgD( - aTmp1, - OUString::createFromAscii(unionSvg)); + aTmp1, OUString::createFromAscii(unionSvg), false, 0); aMixedClip.intersectPolyPolygon(aTmp1); aMixedClip.subtractRange(B2DRange(-20,-150,20,0)); diff --git a/basegfx/test/genericclipper.cxx b/basegfx/test/genericclipper.cxx index c1af17d369c5..8a428dd725e4 100644 --- a/basegfx/test/genericclipper.cxx +++ b/basegfx/test/genericclipper.cxx @@ -79,12 +79,12 @@ public: fprintf(stderr, "%s input LHS - svg:d=\"%s\"\n", pName, OUStringToOString( basegfx::tools::exportToSvgD( - aSelfIntersect), + aSelfIntersect, true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); fprintf(stderr, "%s input RHS - svg:d=\"%s\"\n", pName, OUStringToOString( basegfx::tools::exportToSvgD( - aRect), + aRect, true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); #endif @@ -94,14 +94,14 @@ public: #if OSL_DEBUG_LEVEL > 2 fprintf(stderr, "%s - svg:d=\"%s\"\n", pName, OUStringToOString( - basegfx::tools::exportToSvgD(aRes), + basegfx::tools::exportToSvgD(aRes, true, true, false), RTL_TEXTENCODING_UTF8).getStr() ); #endif OUString aValid=OUString::createFromAscii(pValidSvgD); CPPUNIT_ASSERT_MESSAGE(pName, - basegfx::tools::exportToSvgD(aRes) == aValid); + basegfx::tools::exportToSvgD(aRes, true, true, false) == aValid); } void validateOr() @@ -136,13 +136,13 @@ public: OUString aValid=OUString::createFromAscii(pValidSvgD); B2DPolyPolygon aInputPoly, aValidPoly; - tools::importFromSvgD(aInputPoly, aInput); - tools::importFromSvgD(aValidPoly, aValid); + tools::importFromSvgD(aInputPoly, aInput, false, NULL); + tools::importFromSvgD(aValidPoly, aValid, false, NULL); CPPUNIT_ASSERT_MESSAGE( pName, basegfx::tools::exportToSvgD( - tools::solveCrossovers(aInputPoly)) == aValid); + tools::solveCrossovers(aInputPoly), true, true, false) == aValid); } void checkCrossoverSolver() diff --git a/canvas/source/tools/surfaceproxy.cxx b/canvas/source/tools/surfaceproxy.cxx index c1f857a93f64..e2510b4e2b62 100644 --- a/canvas/source/tools/surfaceproxy.cxx +++ b/canvas/source/tools/surfaceproxy.cxx @@ -150,11 +150,11 @@ namespace canvas OSL_TRACE( "Original clip polygon: %s\n" "Triangulated polygon: %s\n", OUStringToOString( - basegfx::tools::exportToSvgD( rClipPoly ), + basegfx::tools::exportToSvgD( rClipPoly, true, true, false ), RTL_TEXTENCODING_ASCII_US).getStr(), OUStringToOString( basegfx::tools::exportToSvgD( - basegfx::B2DPolyPolygon(rTriangulatedPolygon) ), + basegfx::B2DPolyPolygon(rTriangulatedPolygon), true, true, false ), RTL_TEXTENCODING_ASCII_US).getStr() ); #endif diff --git a/filter/source/svg/svgreader.cxx b/filter/source/svg/svgreader.cxx index f1f9eedc249c..cd4a3931a0b6 100644 --- a/filter/source/svg/svgreader.cxx +++ b/filter/source/svg/svgreader.cxx @@ -1244,7 +1244,7 @@ struct ShapeWritingVisitor +OUString::number(y1)+"L"+OUString::number(x2)+"," +OUString::number(y2); basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD(aPoly, sLinePath); + basegfx::tools::importFromSvgD(aPoly, sLinePath, false, NULL); writePathShape(xAttrs, xUnoAttrs, @@ -1334,7 +1334,7 @@ struct ShapeWritingVisitor { OUString sPath = xElem->hasAttribute("d") ? xElem->getAttribute("d") : ""; basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD(aPoly, sPath); + basegfx::tools::importFromSvgD(aPoly, sPath, false, NULL); writePathShape(xAttrs, xUnoAttrs, @@ -1668,7 +1668,8 @@ struct ShapeWritingVisitor xAttrs->AddAttribute( "svg:d", basegfx::tools::exportToSvgD( aPolys[i], false, // no relative coords. causes rounding errors - false )); // no quad bezier detection. crashes older versions. + false, // no quad bezier detection. crashes older versions. + false )); mxDocumentHandler->startElement("draw:path", xUnoAttrs); mxDocumentHandler->endElement("draw:path"); } diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx index 6aa96927edd7..73137568c703 100644 --- a/include/basegfx/polygon/b2dpolygontools.hxx +++ b/include/basegfx/polygon/b2dpolygontools.hxx @@ -25,6 +25,8 @@ #include <basegfx/range/b2drectangle.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/polygon/b3dpolygon.hxx> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/drawing/FlagSequence.hpp> #include <vector> #include <basegfx/basegfxdllapi.h> @@ -451,6 +453,58 @@ namespace basegfx /// polygon path data. Take into account all stuff like closed state, zero-length edges and others. BASEGFX_DLLPUBLIC B2DVector getTangentLeavingPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + /// converters for com::sun::star::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolygon UnoPointSequenceToB2DPolygon( + const com::sun::star::drawing::PointSequence& rPointSequenceSource, + bool bCheckClosed = true); + BASEGFX_DLLPUBLIC void B2DPolygonToUnoPointSequence( + const B2DPolygon& rPolygon, + com::sun::star::drawing::PointSequence& rPointSequenceRetval); + + /* converters for com::sun::star::drawing::PointSequence and + com::sun::star::drawing::FlagSequence to B2DPolygon (curved polygons) + */ + B2DPolygon UnoPolygonBezierCoordsToB2DPolygon( + const com::sun::star::drawing::PointSequence& rPointSequenceSource, + const com::sun::star::drawing::FlagSequence& rFlagSequenceSource, + bool bCheckClosed = true); + void B2DPolygonToUnoPolygonBezierCoords( + const B2DPolygon& rPolyPolygon, + com::sun::star::drawing::PointSequence& rPointSequenceRetval, + com::sun::star::drawing::FlagSequence& rFlagSequenceRetval); + + /** Read poly-polygon from SVG. + + This function imports a poly-polygon from an SVG points + attribute (a plain list of coordinate pairs). + + @param o_rPoly + The output polygon. Note that svg:points can only define a + single polygon + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC bool importFromSvgPoints( B2DPolygon& o_rPoly, + const OUString& rSvgPointsAttribute ); + + /** Write poly-polygon to SVG. + + This function imports a non-bezier polygon to SVG points + (a plain list of coordinate pairs). + + @param rPoly + The polygon to export + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC OUString exportToSvgPoints( const B2DPolygon& rPoly ); + } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/polygon/b2dpolypolygontools.hxx b/include/basegfx/polygon/b2dpolypolygontools.hxx index 521d07595f8a..182053bfbd90 100644 --- a/include/basegfx/polygon/b2dpolypolygontools.hxx +++ b/include/basegfx/polygon/b2dpolypolygontools.hxx @@ -24,7 +24,10 @@ #include <basegfx/vector/b2dvector.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b3dpolypolygon.hxx> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> #include <vector> +#include <set> #include <basegfx/basegfxdllapi.h> @@ -100,6 +103,32 @@ namespace basegfx // with distance fDistance and rounded edges (start and end point). BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance); + /** Helper class to transport PointIndices to a PolyPolygon, + with an operator< for convenient sorting in a std::set usage + */ + class BASEGFX_DLLPUBLIC SAL_WARN_UNUSED PointIndex + { + private: + sal_uInt32 mnPolygonIndex; + sal_uInt32 mnPointIndex; + + public: + PointIndex(sal_uInt32 nPolygonIndex, sal_uInt32 nPointIndex) + : mnPolygonIndex(nPolygonIndex), + mnPointIndex(nPointIndex) + {} + + sal_uInt32 getPolygonIndex() const { return mnPolygonIndex; } + sal_uInt32 getPointIndex() const { return mnPointIndex; } + bool operator<(const PointIndex& rComp) const; + }; + + /** the PointIndexSet itself; it allows to define a 'selection'of + points in a PolyPolygon by giving the polygon and point index. + Adding points double makes no sense, hence the std::set + */ + typedef std::set< PointIndex > PointIndexSet; + /** Read poly-polygon from SVG. This function imports a poly-polygon from an SVG-D @@ -111,33 +140,29 @@ namespace basegfx @param rSvgDAttribute A valid SVG-D attribute string - @param rWrongPositionAfterZ - Indicates wheter the generator interprets wrongly - the position in the path after Z or z elements - https://bugs.freedesktop.org/show_bug.cgi?id=47406 - - @return true, if the string was successfully parsed - */ - BASEGFX_DLLPUBLIC bool importFromSvgD( B2DPolyPolygon& o_rPolyPoly, - const OUString& rSvgDAttribute, bool bWrongPositionAfterZ = false ); - - /** Read poly-polygon from SVG. - - This function imports a poly-polygon from an SVG points - attribute (a plain list of coordinate pairs). - - @param o_rPoly - The output polygon. Note that svg:points can only define a - single polygon - - @param rSvgPointsAttribute - A valid SVG points attribute string + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + + @param pHelpPointIndexSet + If given, all points created in the target PolyPolygon + which are only helper points are added here using their + point indices; this are currently points created from + import of the 'a' and 'A' svg:d statements which create + bezier curve info as representation and maybe points + which are no 'real' svg:d points, but helper points. It + is necessary to identify these e.g. when markers need to + be created in the svg import @return true, if the string was successfully parsed */ - BASEGFX_DLLPUBLIC bool importFromSvgPoints( B2DPolygon& o_rPoly, - const OUString& rSvgPointsAttribute ); - + BASEGFX_DLLPUBLIC bool importFromSvgD( + B2DPolyPolygon& o_rPolyPoly, + const OUString& rSvgDAttribute, + bool bHandleRelativeNextPointCompatible, + PointIndexSet* pHelpPointIndexSet); // grow for polyPolygon. Move all geometry in each point in the direction of the normal in that point // with the given amount. Value may be negative. @@ -210,12 +235,20 @@ namespace basegfx quadratic bezier segments. Note that the generated string causes versions prior to OOo2.0 to crash. + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + @return the generated SVG-D statement (the XML d attribute value alone, without any "<path ...>" or "d="...") */ - BASEGFX_DLLPUBLIC OUString exportToSvgD( const B2DPolyPolygon& rPolyPoly, - bool bUseRelativeCoordinates=true, - bool bDetectQuadraticBeziers=true ); + BASEGFX_DLLPUBLIC OUString exportToSvgD( + const B2DPolyPolygon& rPolyPoly, + bool bUseRelativeCoordinates, + bool bDetectQuadraticBeziers, + bool bHandleRelativeNextPointCompatible); // #i76891# Try to remove existing curve segments if they are simply edges BASEGFX_DLLPUBLIC B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate); @@ -259,6 +292,22 @@ namespace basegfx */ BASEGFX_DLLPUBLIC bool containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon& rCandidate); + /// converters for com::sun::star::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon( + const com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceSource, + bool bCheckClosed = true); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPointSequenceSequence( + const B2DPolyPolygon& rPolyPolygon, + com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceRetval); + + /// converters for com::sun::star::drawing::PolyPolygonBezierCoords (curved polygons) + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + const com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource, + bool bCheckClosed = true); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPolyPolygonBezierCoords( + const B2DPolyPolygon& rPolyPolygon, + com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval); + } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/polygon/b3dpolypolygontools.hxx b/include/basegfx/polygon/b3dpolypolygontools.hxx index 3b5011ddeeb3..24fb902e79cc 100644 --- a/include/basegfx/polygon/b3dpolypolygontools.hxx +++ b/include/basegfx/polygon/b3dpolypolygontools.hxx @@ -22,9 +22,10 @@ #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> -#include <vector> #include <basegfx/numeric/ftools.hxx> #include <basegfx/point/b3dpoint.hxx> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <vector> #include <basegfx/basegfxdllapi.h> ////////////////////////////////////////////////////////////////////////////// @@ -125,6 +126,14 @@ namespace basegfx // in bWithBorder flag. It is assumed that the orientations of the given polygon are correct. BASEGFX_DLLPUBLIC bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder = false); + /// converters for com::sun::star::drawing::PolyPolygonShape3D + BASEGFX_DLLPUBLIC B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon( + const com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource, + bool bCheckClosed = true); + BASEGFX_DLLPUBLIC void B3DPolyPolygonToUnoPolyPolygonShape3D( + const B3DPolyPolygon& rPolyPolygonSource, + com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval); + } // end of namespace tools } // end of namespace basegfx diff --git a/sd/source/core/CustomAnimationEffect.cxx b/sd/source/core/CustomAnimationEffect.cxx index 86cbdb68be34..0d32e356471a 100644 --- a/sd/source/core/CustomAnimationEffect.cxx +++ b/sd/source/core/CustomAnimationEffect.cxx @@ -1688,7 +1688,7 @@ SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath() void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj ) { ::basegfx::B2DPolyPolygon xPolyPoly; - if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath() ) ) + if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath(), true, 0 ) ) { SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() ); if( pObj ) @@ -1744,7 +1744,7 @@ void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj } } - setPath( ::basegfx::tools::exportToSvgD( xPolyPoly ) ); + setPath( ::basegfx::tools::exportToSvgD( xPolyPoly, true, true, true) ); } // ==================================================================== diff --git a/sdext/source/pdfimport/test/tests.cxx b/sdext/source/pdfimport/test/tests.cxx index 5ea11848dc3e..4dc70a015489 100644 --- a/sdext/source/pdfimport/test/tests.cxx +++ b/sdext/source/pdfimport/test/tests.cxx @@ -236,7 +236,7 @@ namespace const char* sExportString = "m53570 7650-35430 24100"; CPPUNIT_ASSERT_MESSAGE( "Stroke is m535.7 518.5-354.3-241", - basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 ); + basegfx::tools::exportToSvgD( aPath, true, true, false ).compareToAscii(sExportString) == 0 ); m_bGreenStrokeSeen = true; } @@ -259,7 +259,7 @@ namespace const char* sExportString = "m49890 5670.00000000001-35430 24090"; CPPUNIT_ASSERT_MESSAGE( "Stroke is m49890 5670.00000000001-35430 24090", - basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 ); + basegfx::tools::exportToSvgD( aPath, true, true, false ).compareToAscii(sExportString) == 0 ); m_bDashedLineSeen = true; } @@ -317,7 +317,7 @@ namespace const char* sExportString = "m12050 49610c-4310 0-7800-3490-7800-7800 0-4300 " "3490-7790 7800-7790 4300 0 7790 3490 7790 7790 0 4310-3490 7800-7790 7800z"; CPPUNIT_ASSERT_MESSAGE( "Stroke is a 4-bezier circle", - basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 ); + basegfx::tools::exportToSvgD( aPath, true, true, false ).compareToAscii(sExportString) == 0 ); m_bRedCircleSeen = true; } diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.cxx b/sdext/source/pdfimport/tree/drawtreevisiting.cxx index a4d166e8e4df..1b3cfadd43a9 100644 --- a/sdext/source/pdfimport/tree/drawtreevisiting.cxx +++ b/sdext/source/pdfimport/tree/drawtreevisiting.cxx @@ -335,7 +335,7 @@ void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >:: aBuf.append( sal_Unicode(' ') ); aBuf.append( convPx2mmPrec2(elem.h)*100.0 ); aProps[ "svg:viewBox" ] = aBuf.makeStringAndClear(); - aProps[ "svg:d" ] = basegfx::tools::exportToSvgD( elem.PolyPoly ); + aProps[ "svg:d" ] = basegfx::tools::exportToSvgD( elem.PolyPoly, true, true, false ); m_rEmitContext.rEmitter.beginTag( "draw:path", aProps ); m_rEmitContext.rEmitter.endTag( "draw:path" ); diff --git a/sdext/source/pdfimport/tree/writertreevisiting.cxx b/sdext/source/pdfimport/tree/writertreevisiting.cxx index 04238149efe7..6b4681e33ddc 100644 --- a/sdext/source/pdfimport/tree/writertreevisiting.cxx +++ b/sdext/source/pdfimport/tree/writertreevisiting.cxx @@ -275,7 +275,7 @@ void WriterXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* > aBuf.append( sal_Unicode(' ') ); aBuf.append( convPx2mmPrec2(elem.h)*100.0 ); aProps[ "svg:viewBox" ] = aBuf.makeStringAndClear(); - aProps[ "svg:d" ] = basegfx::tools::exportToSvgD( elem.PolyPoly ); + aProps[ "svg:d" ] = basegfx::tools::exportToSvgD( elem.PolyPoly, true, true, false ); m_rEmitContext.rEmitter.beginTag( "draw:path", aProps ); m_rEmitContext.rEmitter.endTag( "draw:path" ); diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx index 8f443059e3b1..d7877828e4fa 100644 --- a/slideshow/source/engine/animationfactory.cxx +++ b/slideshow/source/engine/animationfactory.cxx @@ -228,7 +228,7 @@ namespace slideshow ::basegfx::B2DPolyPolygon aPolyPoly; - ENSURE_OR_THROW( ::basegfx::tools::importFromSvgD( aPolyPoly, rSVGDPath ), + ENSURE_OR_THROW( ::basegfx::tools::importFromSvgD( aPolyPoly, rSVGDPath, false, 0 ), "PathAnimation::PathAnimation(): failed to parse SVG:d path" ); ENSURE_OR_THROW( aPolyPoly.count() == 1, "PathAnimation::PathAnimation(): motion path consists of multiple/zero polygon(s)" ); diff --git a/svgio/inc/svgio/svgreader/svgpathnode.hxx b/svgio/inc/svgio/svgreader/svgpathnode.hxx index a9e61d3361f4..1907baba8411 100644 --- a/svgio/inc/svgio/svgreader/svgpathnode.hxx +++ b/svgio/inc/svgio/svgreader/svgpathnode.hxx @@ -22,6 +22,7 @@ #include <svgio/svgreader/svgnode.hxx> #include <svgio/svgreader/svgstyleattributes.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -33,12 +34,13 @@ namespace svgio { private: /// use styles - SvgStyleAttributes maSvgStyleAttributes; + SvgStyleAttributes maSvgStyleAttributes; /// variable scan values, dependent of given XAttributeList - basegfx::B2DPolyPolygon* mpPolyPolygon; - basegfx::B2DHomMatrix* mpaTransform; - SvgNumber maPathLength; + basegfx::B2DPolyPolygon* mpPolyPolygon; + basegfx::B2DHomMatrix* mpaTransform; + SvgNumber maPathLength; + basegfx::tools::PointIndexSet maHelpPointIndices; public: SvgPathNode( diff --git a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx index be8ddd4e64e1..1624b37aebc8 100644 --- a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx +++ b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx @@ -23,6 +23,7 @@ #include <svgio/svgreader/svgpaint.hxx> #include <svgio/svgreader/svgnode.hxx> #include <vcl/vclenum.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> ////////////////////////////////////////////////////////////////////////////// // predefines @@ -250,7 +251,8 @@ namespace svgio const SvgMarkerNode& rMarker) const; void add_markers( const basegfx::B2DPolyPolygon& rPath, - drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::tools::PointIndexSet* pHelpPointIndices) const; public: /// local attribute scanner @@ -262,7 +264,8 @@ namespace svgio drawinglayer::primitive2d::Primitive2DSequence& rSource) const; void add_path( const basegfx::B2DPolyPolygon& rPath, - drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::tools::PointIndexSet* pHelpPointIndices) const; void add_postProcess( drawinglayer::primitive2d::Primitive2DSequence& rTarget, const drawinglayer::primitive2d::Primitive2DSequence& rSource, diff --git a/svgio/source/svgreader/svgcirclenode.cxx b/svgio/source/svgreader/svgcirclenode.cxx index c742a41f9989..f462a07e3284 100644 --- a/svgio/source/svgreader/svgcirclenode.cxx +++ b/svgio/source/svgreader/svgcirclenode.cxx @@ -135,7 +135,7 @@ namespace svgio drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, 0); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svgellipsenode.cxx b/svgio/source/svgreader/svgellipsenode.cxx index aa42d7adc757..283e9da9826b 100644 --- a/svgio/source/svgreader/svgellipsenode.cxx +++ b/svgio/source/svgreader/svgellipsenode.cxx @@ -150,7 +150,7 @@ namespace svgio drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, 0); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svglinenode.cxx b/svgio/source/svgreader/svglinenode.cxx index 74e9facbf973..aebefe7fdd9c 100644 --- a/svgio/source/svgreader/svglinenode.cxx +++ b/svgio/source/svgreader/svglinenode.cxx @@ -146,7 +146,7 @@ namespace svgio drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, 0); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svgpathnode.cxx b/svgio/source/svgreader/svgpathnode.cxx index 9e77f723a6df..e745711e786d 100644 --- a/svgio/source/svgreader/svgpathnode.cxx +++ b/svgio/source/svgreader/svgpathnode.cxx @@ -69,7 +69,7 @@ namespace svgio { basegfx::B2DPolyPolygon aPath; - if(basegfx::tools::importFromSvgD(aPath, aContent)) + if(basegfx::tools::importFromSvgD(aPath, aContent, false, &maHelpPointIndices)) { if(aPath.count()) { @@ -114,7 +114,7 @@ namespace svgio { drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(*getPath(), aNewTarget); + pStyle->add_path(*getPath(), aNewTarget, &maHelpPointIndices); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svgpolynode.cxx b/svgio/source/svgreader/svgpolynode.cxx index eef4808404dc..c475c79f7206 100644 --- a/svgio/source/svgreader/svgpolynode.cxx +++ b/svgio/source/svgreader/svgpolynode.cxx @@ -20,6 +20,7 @@ #include <svgio/svgreader/svgpolynode.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -111,7 +112,7 @@ namespace svgio { drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(*getPolygon()), aNewTarget); + pStyle->add_path(basegfx::B2DPolyPolygon(*getPolygon()), aNewTarget, 0); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svgrectnode.cxx b/svgio/source/svgreader/svgrectnode.cxx index 5d518a46c245..8348ed76ae14 100644 --- a/svgio/source/svgreader/svgrectnode.cxx +++ b/svgio/source/svgreader/svgrectnode.cxx @@ -207,7 +207,7 @@ namespace svgio drawinglayer::primitive2d::Primitive2DSequence aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, 0); if(aNewTarget.hasElements()) { diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx index 958debdfe21c..0e8be846a6fc 100644 --- a/svgio/source/svgreader/svgstyleattributes.cxx +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -829,7 +829,8 @@ namespace svgio void SvgStyleAttributes::add_markers( const basegfx::B2DPolyPolygon& rPath, - drawinglayer::primitive2d::Primitive2DSequence& rTarget) const + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::tools::PointIndexSet* pHelpPointIndices) const { // try to access linked markers const SvgMarkerNode* pStart = accessMarkerStartXLink(); @@ -888,6 +889,18 @@ namespace svgio pNeeded = pMid; } + if(pHelpPointIndices && !pHelpPointIndices->empty()) + { + const basegfx::tools::PointIndexSet::const_iterator aFound( + pHelpPointIndices->find(basegfx::tools::PointIndex(a, b))); + + if(aFound != pHelpPointIndices->end()) + { + // this point is a pure helper point; do not create a marker for it + continue; + } + } + if(!pNeeded) { // no marker needs to be created for this point @@ -999,7 +1012,8 @@ namespace svgio void SvgStyleAttributes::add_path( const basegfx::B2DPolyPolygon& rPath, - drawinglayer::primitive2d::Primitive2DSequence& rTarget) const + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::tools::PointIndexSet* pHelpPointIndices) const { if(!rPath.count()) { @@ -1057,7 +1071,7 @@ namespace svgio SVGTokenLine == mrOwner.getType()) // line { // try to add markers - add_markers(rPath, rTarget); + add_markers(rPath, rTarget, pHelpPointIndices); } } diff --git a/xmloff/inc/xexptran.hxx b/xmloff/inc/xexptran.hxx index 77944533de2b..2c8112adf360 100644 --- a/xmloff/inc/xexptran.hxx +++ b/xmloff/inc/xexptran.hxx @@ -93,79 +93,23 @@ public: class SdXMLImExViewBox { - OUString msString; - sal_Int32 mnX; - sal_Int32 mnY; - sal_Int32 mnW; - sal_Int32 mnH; + OUString msString; + double mfX; + double mfY; + double mfW; + double mfH; public: - SdXMLImExViewBox(sal_Int32 nX = 0L, sal_Int32 nY = 0L, sal_Int32 nW = 1000L, sal_Int32 nH = 1000L); + SdXMLImExViewBox(double fX = 0.0, double fY = 0.0, double fW = 1000.0, double fH = 1000.0); SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv); - sal_Int32 GetX() const { return mnX; } - sal_Int32 GetY() const { return mnY; } - sal_Int32 GetWidth() const { return mnW; } - sal_Int32 GetHeight() const { return mnH; } + double GetX() const { return mfX; } + double GetY() const { return mfY; } + double GetWidth() const { return mfW; } + double GetHeight() const { return mfH; } const OUString& GetExportString(); }; -class SdXMLImExPointsElement -{ - OUString msString; - com::sun::star::drawing::PointSequenceSequence maPoly; - -public: - SdXMLImExPointsElement(com::sun::star::drawing::PointSequence* pPoints, - const SdXMLImExViewBox& rViewBox, - const com::sun::star::awt::Point& rObjectPos, - const com::sun::star::awt::Size& rObjectSize, - // #96328# - const bool bClosed = true); - SdXMLImExPointsElement(const OUString& rNew, - const SdXMLImExViewBox& rViewBox, - const com::sun::star::awt::Point& rObjectPos, - const com::sun::star::awt::Size& rObjectSize, - const SvXMLUnitConverter& rConv); - - const OUString& GetExportString() const { return msString; } - const com::sun::star::drawing::PointSequenceSequence& GetPointSequenceSequence() const { return maPoly; } -}; - -class SdXMLImExSvgDElement -{ - OUString msString; - const SdXMLImExViewBox& mrViewBox; - bool mbIsClosed; - bool mbIsCurve; - bool mbRelative; - sal_Int32 mnLastX; - sal_Int32 mnLastY; - - com::sun::star::drawing::PolyPolygonBezierCoords maPoly; - -public: - SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox, const SvXMLExport& rExport); - SdXMLImExSvgDElement(const OUString& rNew, - const SdXMLImExViewBox& rViewBox, - const com::sun::star::awt::Point& rObjectPos, - const com::sun::star::awt::Size& rObjectSize, - const SvXMLImport& rImport); - - void AddPolygon( - com::sun::star::drawing::PointSequence* pPoints, - com::sun::star::drawing::FlagSequence* pFlags, - const com::sun::star::awt::Point& rObjectPos, - const com::sun::star::awt::Size& rObjectSize, - bool bClosed = false); - - const OUString& GetExportString() const { return msString; } - bool IsClosed() const { return mbIsClosed; } - bool IsCurve() const { return mbIsCurve; } - const com::sun::star::drawing::PointSequenceSequence& GetPointSequenceSequence() const { return maPoly.Coordinates; } - const com::sun::star::drawing::FlagSequenceSequence& GetFlagSequenceSequence() const { return maPoly.Flags; } -}; - -#endif // INCLUDED_XMLOFF_INC_XEXPTRAN_HXX +#endif // _XEXPTRANSFORM_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLImageMapContext.cxx b/xmloff/source/draw/XMLImageMapContext.cxx index efa3b48c18ab..4601b0065108 100644 --- a/xmloff/source/draw/XMLImageMapContext.cxx +++ b/xmloff/source/draw/XMLImageMapContext.cxx @@ -26,7 +26,6 @@ #include <com/sun/star/container/XIndexContainer.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/drawing/PointSequenceSequence.hpp> - #include <com/sun/star/document/XEventsSupplier.hpp> #include <com/sun/star/awt/Rectangle.hpp> #include <xmloff/xmltoken.hxx> @@ -40,7 +39,8 @@ #include <xmloff/XMLEventsImportContext.hxx> #include "XMLStringBufferImportContext.hxx" #include <tools/debug.hxx> - +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> using namespace ::com::sun::star; using namespace ::xmloff::token; @@ -492,34 +492,31 @@ void XMLImageMapPolygonContext::ProcessAttribute( bValid = bViewBoxOK && bPointsOK; } -void XMLImageMapPolygonContext::Prepare( - Reference<XPropertySet> & rPropertySet) +void XMLImageMapPolygonContext::Prepare(Reference<XPropertySet> & rPropertySet) { // process view box - SdXMLImExViewBox aViewBox(sViewBoxString, - GetImport().GetMM100UnitConverter()); + SdXMLImExViewBox aViewBox(sViewBoxString, GetImport().GetMM100UnitConverter()); // get polygon sequence - awt::Point aPoint(aViewBox.GetX(), aViewBox.GetY()); - awt::Size aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); - SdXMLImExPointsElement aPoints( sPointsString, aViewBox, aPoint, aSize, - GetImport().GetMM100UnitConverter() ); - PointSequenceSequence aPointSeqSeq = aPoints.GetPointSequenceSequence(); - - // only use first element of sequence-sequence - if (aPointSeqSeq.getLength() > 0) + basegfx::B2DPolygon aPolygon; + + if(basegfx::tools::importFromSvgPoints(aPolygon, sPointsString)) { - Any aAny; - aAny <<= aPointSeqSeq[0]; - rPropertySet->setPropertyValue(sPolygon, aAny); + if(aPolygon.count()) + { + com::sun::star::drawing::PointSequence aPointSequence; + uno::Any aAny; + + basegfx::tools::B2DPolygonToUnoPointSequence(aPolygon, aPointSequence); + aAny <<= aPointSequence; + rPropertySet->setPropertyValue(sPolygon, aAny); + } } // parent properties XMLImageMapObjectContext::Prepare(rPropertySet); } - - class XMLImageMapCircleContext : public XMLImageMapObjectContext { awt::Point aCenter; diff --git a/xmloff/source/draw/XMLImageMapExport.cxx b/xmloff/source/draw/XMLImageMapExport.cxx index c6e40115597a..2abba024f112 100644 --- a/xmloff/source/draw/XMLImageMapExport.cxx +++ b/xmloff/source/draw/XMLImageMapExport.cxx @@ -26,7 +26,6 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/container/XIndexContainer.hpp> - #include <com/sun/star/document/XEventsSupplier.hpp> #include <com/sun/star/awt/Rectangle.hpp> #include <com/sun/star/awt/Point.hpp> @@ -38,8 +37,8 @@ #include <xmloff/XMLEventExport.hxx> #include <xmloff/xmluconv.hxx> #include "xexptran.hxx" - - +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> using namespace ::com::sun::star; using namespace ::xmloff::token; @@ -314,8 +313,7 @@ void XMLImageMapExport::ExportCircle( aBuffer.makeStringAndClear() ); } -void XMLImageMapExport::ExportPolygon( - const Reference<XPropertySet> & rPropertySet) +void XMLImageMapExport::ExportPolygon(const Reference<XPropertySet> & rPropertySet) { // polygons get exported as bounding box, viewbox, and coordinate // pair sequence. The bounding box is always the entire image. @@ -325,52 +323,33 @@ void XMLImageMapExport::ExportPolygon( PointSequence aPoly; aAny >>= aPoly; - // get bounding box (assume top-left to be 0,0) - sal_Int32 nWidth = 0; - sal_Int32 nHeight = 0; - sal_Int32 nLength = aPoly.getLength(); - const struct awt::Point* pPointPtr = aPoly.getConstArray(); - for ( sal_Int32 i = 0; i < nLength; i++ ) - { - sal_Int32 nPolyX = pPointPtr->X; - sal_Int32 nPolyY = pPointPtr->Y; - - if ( nPolyX > nWidth ) - nWidth = nPolyX; - if ( nPolyY > nHeight ) - nHeight = nPolyY; - - pPointPtr++; - } - DBG_ASSERT(nWidth > 0, "impossible Polygon found"); - DBG_ASSERT(nHeight > 0, "impossible Polygon found"); + const basegfx::B2DPolygon aPolygon( + basegfx::tools::UnoPointSequenceToB2DPolygon( + aPoly)); + const basegfx::B2DRange aPolygonRange(aPolygon.getB2DRange()); // parameters svg:x, svg:y, svg:width, svg:height OUStringBuffer aBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); - mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, - aBuffer.makeStringAndClear() ); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, aBuffer.makeStringAndClear() ); mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); - mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, - aBuffer.makeStringAndClear() ); - mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, nWidth); - mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, - aBuffer.makeStringAndClear() ); - mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, nHeight); - mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, - aBuffer.makeStringAndClear() ); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getWidth())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getHeight())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, aBuffer.makeStringAndClear() ); // svg:viewbox - SdXMLImExViewBox aViewBox(0, 0, nWidth, nHeight); - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, - aViewBox.GetExportString()); + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolygonRange.getWidth(), aPolygonRange.getHeight()); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); // export point sequence - awt::Point aPoint(0, 0); - awt::Size aSize(nWidth, nHeight); - SdXMLImExPointsElement aPoints( &aPoly, aViewBox, aPoint, aSize ); - mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_POINTS, - aPoints.GetExportString()); + const OUString aPointString( + basegfx::tools::exportToSvgPoints( + aPolygon)); + + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx index 16f5d173b282..3a2a636027e1 100644 --- a/xmloff/source/draw/shapeexport.cxx +++ b/xmloff/source/draw/shapeexport.cxx @@ -20,6 +20,14 @@ #include <memory> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> #include <basegfx/tuple/b2dtuple.hxx> #include <basegfx/vector/b3dvector.hxx> @@ -2119,8 +2127,6 @@ void XMLShapeExport::ImpExportPolygonShape( const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); if(xPropSet.is()) { - sal_Bool bClosed(eShapeType == XmlShapeTypeDrawPolyPolygonShape - || eShapeType == XmlShapeTypeDrawClosedBezierShape); sal_Bool bBezier(eShapeType == XmlShapeTypeDrawClosedBezierShape || eShapeType == XmlShapeTypeDrawOpenBezierShape); @@ -2150,111 +2156,83 @@ void XMLShapeExport::ImpExportPolygonShape( { // get PolygonBezier uno::Any aAny( xPropSet->getPropertyValue("Geometry") ); - drawing::PolyPolygonBezierCoords* pSourcePolyPolygon = - (drawing::PolyPolygonBezierCoords*)aAny.getValue(); + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*(drawing::PolyPolygonBezierCoords*)aAny.getValue())); - if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) + if(aPolyPolygon.count()) { - sal_Int32 nOuterCnt(pSourcePolyPolygon->Coordinates.getLength()); - drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->Coordinates.getArray(); - drawing::FlagSequence* pOuterFlags = pSourcePolyPolygon->Flags.getArray(); + // complex polygon shape, write as svg:d + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible - if(pOuterSequence && pOuterFlags) - { - // prepare svx:d element export - SdXMLImExSvgDElement aSvgDElement(aViewBox, GetExport()); - - for(sal_Int32 a(0L); a < nOuterCnt; a++) - { - drawing::PointSequence* pSequence = pOuterSequence++; - drawing::FlagSequence* pFlags = pOuterFlags++; - - if(pSequence && pFlags) - { - aSvgDElement.AddPolygon(pSequence, pFlags, - aPoint, aSize, bClosed); - } - } - - // write point array - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString()); - } + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); // write object now - SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PATH, bCreateNewline, sal_True); + SvXMLElementExport aOBJ( + mrExport, + XML_NAMESPACE_DRAW, + XML_PATH, + bCreateNewline, + sal_True); - ImpExportDescription( xShape ); // #i68101# - ImpExportEvents( xShape ); - ImpExportGluePoints( xShape ); - ImpExportText( xShape ); } } else { // get non-bezier polygon uno::Any aAny( xPropSet->getPropertyValue("Geometry") ); - drawing::PointSequenceSequence* pSourcePolyPolygon = (drawing::PointSequenceSequence*)aAny.getValue(); + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::UnoPointSequenceSequenceToB2DPolyPolygon(*(drawing::PointSequenceSequence*)aAny.getValue())); - if(pSourcePolyPolygon && pSourcePolyPolygon->getLength()) + if(!aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count()) { - sal_Int32 nOuterCnt(pSourcePolyPolygon->getLength()); - - if(1L == nOuterCnt && !bBezier) - { - // simple polygon shape, can be written as svg:points sequence - drawing::PointSequence* pSequence = pSourcePolyPolygon->getArray(); - if(pSequence) - { - SdXMLImExPointsElement aPoints(pSequence, aViewBox, aPoint, aSize, - // #96328# - bClosed); - - // write point array - mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPoints.GetExportString()); - } - - // write object now - SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, - bClosed ? XML_POLYGON : XML_POLYLINE , bCreateNewline, sal_True); - - ImpExportDescription( xShape ); // #i68101# - ImpExportEvents( xShape ); - ImpExportGluePoints( xShape ); - ImpExportText( xShape ); - } - else - { - // polypolygon or bezier, needs to be written as a svg:path sequence - drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->getArray(); - if(pOuterSequence) - { - // prepare svx:d element export - SdXMLImExSvgDElement aSvgDElement(aViewBox, GetExport()); + // simple polygon shape, can be written as svg:points sequence + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0)); + const OUString aPointString(basegfx::tools::exportToSvgPoints(aPolygon)); - for(sal_Int32 a(0L); a < nOuterCnt; a++) - { - drawing::PointSequence* pSequence = pOuterSequence++; - if(pSequence) - { - aSvgDElement.AddPolygon(pSequence, 0L, aPoint, - aSize, bClosed); - } - } + // write point array + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); - // write point array - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString()); - } + // write object now + SvXMLElementExport aOBJ( + mrExport, + XML_NAMESPACE_DRAW, + aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE, + bCreateNewline, + sal_True); + } + else + { + // complex polygon shape, write as svg:d + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible - // write object now - SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PATH, bCreateNewline, sal_True); + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); - ImpExportDescription( xShape ); // #i68101# - ImpExportEvents( xShape ); - ImpExportGluePoints( xShape ); - ImpExportText( xShape ); - } + // write object now + SvXMLElementExport aOBJ( + mrExport, + XML_NAMESPACE_DRAW, + XML_PATH, + bCreateNewline, + sal_True); } } + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); } } @@ -2595,38 +2573,19 @@ void XMLShapeExport::ImpExportConnectorShape( if( xProps->getPropertyValue("PolyPolygonBezier") >>= aAny ) { // get PolygonBezier - drawing::PolyPolygonBezierCoords* pSourcePolyPolygon = - (drawing::PolyPolygonBezierCoords*)aAny.getValue(); + drawing::PolyPolygonBezierCoords* pSourcePolyPolygon = (drawing::PolyPolygonBezierCoords*)aAny.getValue(); if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) { - sal_Int32 nOuterCnt(pSourcePolyPolygon->Coordinates.getLength()); - drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->Coordinates.getArray(); - drawing::FlagSequence* pOuterFlags = pSourcePolyPolygon->Flags.getArray(); - - if(pOuterSequence && pOuterFlags) - { - // prepare svx:d element export - awt::Point aPoint( 0, 0 ); - awt::Size aSize( 1, 1 ); - SdXMLImExViewBox aViewBox( 0, 0, 1, 1 ); - SdXMLImExSvgDElement aSvgDElement(aViewBox, GetExport()); - - for(sal_Int32 a(0L); a < nOuterCnt; a++) - { - drawing::PointSequence* pSequence = pOuterSequence++; - drawing::FlagSequence* pFlags = pOuterFlags++; - - if(pSequence && pFlags) - { - aSvgDElement.AddPolygon(pSequence, pFlags, - aPoint, aSize, sal_False ); - } - } - - // write point array - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString()); - } + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + *pSourcePolyPolygon)); + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible } } @@ -3440,104 +3399,45 @@ void XMLShapeExport::ImpExport3DShape( case XmlShapeTypeDraw3DLatheObject: case XmlShapeTypeDraw3DExtrudeObject: { - // write special 3DLathe/3DExtrude attributes + // write special 3DLathe/3DExtrude attributes, get 3D PolyPolygon as drawing::PolyPolygonShape3D aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D"); drawing::PolyPolygonShape3D xPolyPolygon3D; aAny >>= xPolyPolygon3D; - // look for maximal values - double fXMin = 0; - double fXMax = 0; - double fYMin = 0; - double fYMax = 0; - sal_Bool bInit(sal_False); - sal_Int32 nOuterSequenceCount(xPolyPolygon3D.SequenceX.getLength()); - drawing::DoubleSequence* pInnerSequenceX = xPolyPolygon3D.SequenceX.getArray(); - drawing::DoubleSequence* pInnerSequenceY = xPolyPolygon3D.SequenceY.getArray(); - - sal_Int32 a; - for (a = 0; a < nOuterSequenceCount; a++) - { - sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength()); - double* pArrayX = pInnerSequenceX->getArray(); - double* pArrayY = pInnerSequenceY->getArray(); - - for(sal_Int32 b(0L); b < nInnerSequenceCount; b++) - { - double fX = *pArrayX++; - double fY = *pArrayY++; + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aPolyPolygon3D( + basegfx::tools::UnoPolyPolygonShape3DToB3DPolyPolygon( + xPolyPolygon3D)); - if(bInit) - { - if(fX > fXMax) - fXMax = fX; + // convert to 2D PolyPolygon using identity 3D transformation (just grep X and Y) + const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon( + aPolyPolygon3D, + aB3DHomMatrixFor2DConversion)); - if(fX < fXMin) - fXMin = fX; - - if(fY > fYMax) - fYMax = fY; - - if(fY < fYMin) - fYMin = fY; - } - else - { - fXMin = fXMax = fX; - fYMin = fYMax = fY; - bInit = sal_True; - } - } - - pInnerSequenceX++; - pInnerSequenceY++; - } + // get 2D range of it + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); // export ViewBox - awt::Point aMinPoint(FRound(fXMin), FRound(fYMin)); - awt::Size aMaxSize(FRound(fXMax) - aMinPoint.X, FRound(fYMax) - aMinPoint.Y); SdXMLImExViewBox aViewBox( - aMinPoint.X, aMinPoint.Y, aMaxSize.Width, aMaxSize.Height); - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, - aViewBox.GetExportString()); + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); - // prepare svx:d element export - SdXMLImExSvgDElement aSvgDElement(aViewBox, GetExport()); - pInnerSequenceX = xPolyPolygon3D.SequenceX.getArray(); - pInnerSequenceY = xPolyPolygon3D.SequenceY.getArray(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); - for (a = 0; a < nOuterSequenceCount; a++) - { - sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength()); - double* pArrayX = pInnerSequenceX->getArray(); - double* pArrayY = pInnerSequenceY->getArray(); - drawing::PointSequence aPoly(nInnerSequenceCount); - awt::Point* pInnerSequence = aPoly.getArray(); - - for(sal_Int32 b(0L); b < nInnerSequenceCount; b++) - { - double fX = *pArrayX++; - double fY = *pArrayY++; - - *pInnerSequence = awt::Point(FRound(fX), FRound(fY)); - pInnerSequence++; - } - - // calculate closed flag - awt::Point* pFirst = aPoly.getArray(); - awt::Point* pLast = pFirst + (nInnerSequenceCount - 1); - sal_Bool bClosed = (pFirst->X == pLast->X && pFirst->Y == pLast->Y); - - aSvgDElement.AddPolygon(&aPoly, 0L, aMinPoint, - aMaxSize, bClosed); - - // #80594# corrected error in PolyPolygon3D export for 3D XML - pInnerSequenceX++; - pInnerSequenceY++; - } + // prepare svg:d string + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible // write point array - mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString()); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); if(eShapeType == XmlShapeTypeDraw3DLatheObject) { diff --git a/xmloff/source/draw/xexptran.cxx b/xmloff/source/draw/xexptran.cxx index 5f131251f6ee..dbc5cdbe9c4d 100644 --- a/xmloff/source/draw/xexptran.cxx +++ b/xmloff/source/draw/xexptran.cxx @@ -245,6 +245,13 @@ double Imp_GetDoubleChar(const OUString& rStr, sal_Int32& rPos, const sal_Int32 return fRetval; } +void Imp_PutDoubleChar(OUString& rStr, double fValue) +{ + OUStringBuffer sStringBuffer; + ::sax::Converter::convertDouble(sStringBuffer, fValue); + rStr += OUString(sStringBuffer.makeStringAndClear()); +} + void Imp_PutDoubleChar(OUString& rStr, const SvXMLUnitConverter& rConv, double fValue, bool bConvertUnits = false) { @@ -1206,21 +1213,21 @@ void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans) } } -SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX, sal_Int32 nY, sal_Int32 nW, sal_Int32 nH) -: mnX( nX ), - mnY( nY ), - mnW( nW ), - mnH( nH ) +SdXMLImExViewBox::SdXMLImExViewBox(double fX, double fY, double fW, double fH) +: mfX( fX ), + mfY( fY ), + mfW( fW ), + mfH( fH ) { } // #100617# Asked vincent hardy: svg:viewBox values may be double precision. SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv) : msString(rNew), - mnX( 0L ), - mnY( 0L ), - mnW( 1000L ), - mnH( 1000L ) + mfX( 0.0 ), + mfY( 0.0 ), + mfW( 1000.0 ), + mfH( 1000.0 ) { if(!msString.isEmpty()) { @@ -1232,25 +1239,25 @@ SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverte Imp_SkipSpaces(aStr, nPos, nLen); // get mX, #100617# be prepared for doubles - mnX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnX)); + mfX = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfX); // skip spaces and commas Imp_SkipSpacesAndCommas(aStr, nPos, nLen); // get mY, #100617# be prepared for doubles - mnY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnY)); + mfY = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfY); // skip spaces and commas Imp_SkipSpacesAndCommas(aStr, nPos, nLen); // get mW, #100617# be prepared for doubles - mnW = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnW)); + mfW = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfW); // skip spaces and commas Imp_SkipSpacesAndCommas(aStr, nPos, nLen); // get mH, #100617# be prepared for doubles - mnH = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnH)); + mfH = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfH); } } @@ -1259,16 +1266,16 @@ const OUString& SdXMLImExViewBox::GetExportString() OUString aNewString; OUString aEmptySpace(" "); - Imp_PutNumberChar(aNewString, mnX); + Imp_PutDoubleChar(aNewString, mfX); aNewString += aEmptySpace; - Imp_PutNumberChar(aNewString, mnY); + Imp_PutDoubleChar(aNewString, mfY); aNewString += aEmptySpace; - Imp_PutNumberChar(aNewString, mnW); + Imp_PutDoubleChar(aNewString, mfW); aNewString += aEmptySpace; - Imp_PutNumberChar(aNewString, mnH); + Imp_PutDoubleChar(aNewString, mfH); // set new string msString = aNewString; @@ -1276,872 +1283,4 @@ const OUString& SdXMLImExViewBox::GetExportString() return msString; } -SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence* pPoints, - const SdXMLImExViewBox& rViewBox, - const awt::Point& rObjectPos, - const awt::Size& rObjectSize, - // #96328# - const bool bClosed) -: maPoly( 0L ) -{ - DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExPointsElement(!)"); - - // add polygon to string - sal_Int32 nCnt(pPoints->getLength()); - - // #104076# Convert to string only when at last one point included - if(nCnt > 0) - { - OUString aNewString; - awt::Point* pArray = pPoints->getArray(); - - // last point same? Ignore it. - // #96328# ...but only when polygon is CLOSED - if(bClosed && (pArray->X == (pArray + (nCnt - 1))->X) && (pArray->Y == (pArray + (nCnt - 1))->Y)) - nCnt--; - - // object size and ViewBox size different? - bool bScale(rObjectSize.Width != rViewBox.GetWidth() - || rObjectSize.Height != rViewBox.GetHeight()); - bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L); - - for(sal_Int32 a(0L); a < nCnt; a++) - { - // prepare coordinates - sal_Int32 nX( pArray->X - rObjectPos.X ); - sal_Int32 nY( pArray->Y - rObjectPos.Y ); - - if(bScale && rObjectSize.Width && rObjectSize.Height) - { - nX = (nX * rViewBox.GetWidth()) / rObjectSize.Width; - nY = (nY * rViewBox.GetHeight()) / rObjectSize.Height; - } - - if(bTranslate) - { - nX += rViewBox.GetX(); - nY += rViewBox.GetY(); - } - - // X and comma - Imp_PutNumberChar(aNewString, nX); - aNewString += ","; - - // Y and space (not for last) - Imp_PutNumberChar(aNewString, nY); - if(a + 1 != nCnt) - aNewString += " "; - - // next point - pArray++; - } - - // set new string - msString = aNewString; - } -} - -// #100617# svg:polyline or svg:polygon values may be double precision. -SdXMLImExPointsElement::SdXMLImExPointsElement(const OUString& rNew, - const SdXMLImExViewBox& rViewBox, - const awt::Point& rObjectPos, - const awt::Size& rObjectSize, - const SvXMLUnitConverter& rConv) -: msString( rNew ), - maPoly( 0L ) -{ - // convert string to polygon - const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength()); - const sal_Int32 nLen(aStr.getLength()); - sal_Int32 nPos(0); - sal_Int32 nNumPoints(0L); - - // skip starting spaces - Imp_SkipSpaces(aStr, nPos, nLen); - - // count points in first loop - while(nPos < nLen) - { - // skip number, #100617# be prepared for doubles - Imp_SkipDouble(aStr, nPos, nLen); - - // skip spaces and commas - Imp_SkipSpacesAndCommas(aStr, nPos, nLen); - - // skip number, #100617# be prepared for doubles - Imp_SkipDouble(aStr, nPos, nLen); - - // skip spaces and commas - Imp_SkipSpacesAndCommas(aStr, nPos, nLen); - - // one more point - nNumPoints++; - } - - // second loop - if(nNumPoints) - { - nPos = 0; - maPoly.realloc(1); - drawing::PointSequence* pOuterSequence = maPoly.getArray(); - pOuterSequence->realloc(nNumPoints); - awt::Point* pInnerSequence = pOuterSequence->getArray(); - - // object size and ViewBox size different? - bool bScale(rObjectSize.Width != rViewBox.GetWidth() - || rObjectSize.Height != rViewBox.GetHeight()); - bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L); - - // skip starting spaces - Imp_SkipSpaces(aStr, nPos, nLen); - - while(nPos < nLen) - { - // prepare new parameter pair - sal_Int32 nX(0L); - sal_Int32 nY(0L); - - // get mX, #100617# be prepared for doubles - nX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nX)); - - // skip spaces and commas - Imp_SkipSpacesAndCommas(aStr, nPos, nLen); - - // get mY, #100617# be prepared for doubles - nY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nY)); - - // skip spaces and commas - Imp_SkipSpacesAndCommas(aStr, nPos, nLen); - - // prepare parameters - if(bTranslate) - { - nX -= rViewBox.GetX(); - nY -= rViewBox.GetY(); - } - - if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight() ) - { - nX = (nX * rObjectSize.Width) / rViewBox.GetWidth(); - nY = (nY * rObjectSize.Height) / rViewBox.GetHeight(); - } - - nX += rObjectPos.X; - nY += rObjectPos.Y; - - // add new point - *pInnerSequence = awt::Point( nX, nY ); - pInnerSequence++; - } - } -} - -SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox, - const SvXMLExport& rExport) -: mrViewBox( rViewBox ), - mbIsClosed( false ), - mbIsCurve( false ), - // fdo#47406 - handle writing svg:d path slightly different for - // old ODF versions and ODF1.2 compat mode - since ~all the legacy - // ODF ecosystem interprets relative svg:d paths incorrectly, - // write out absolute paths in those cases. - mbRelative( rExport.getDefaultVersion() >= SvtSaveOptions::ODFVER_012 && - rExport.getDefaultVersion() != SvtSaveOptions::ODFVER_012_EXT_COMPAT ), - mnLastX( 0L ), - mnLastY( 0L ), - maPoly() -{ -} - -void Imp_GetPrevPos(awt::Point*& pPrevPos1, - drawing::PolygonFlags& aPrevFlag1, - const bool bClosed, awt::Point* pPoints, - drawing::PolygonFlags* pFlags, const sal_Int32 nPos, - const sal_Int32 nCnt, const sal_Int32 nAdd) -{ - if(bClosed) - { - pPrevPos1 = pPoints + ((nPos + nCnt - nAdd) % nCnt); - aPrevFlag1 = *(pFlags + ((nPos + nCnt - nAdd) % nCnt)); - } - else if(nPos > (nAdd - 1)) - { - pPrevPos1 = pPoints + (nPos - nAdd); - aPrevFlag1 = *(pFlags + (nPos - nAdd)); - } - else - pPrevPos1 = 0L; -} - -void Imp_PrepareCoorExport(sal_Int32& nX, sal_Int32& nY, - const awt::Point* pPointArray, const awt::Point& rObjectPos, - const awt::Size& rObjectSize, const SdXMLImExViewBox& mrViewBox, - const bool bScale, const bool bTranslate) -{ - nX = pPointArray->X - rObjectPos.X; - nY = pPointArray->Y - rObjectPos.Y; - - if(bScale && rObjectSize.Width && rObjectSize.Height ) - { - nX = (nX * mrViewBox.GetWidth()) / rObjectSize.Width; - nY = (nY * mrViewBox.GetHeight()) / rObjectSize.Height; - } - - if(bTranslate) - { - nX += mrViewBox.GetX(); - nY += mrViewBox.GetY(); - } -} - -//#define TEST_QUADRATIC_CURVES -#ifdef TEST_QUADRATIC_CURVES -// To be able to test quadratic curve code: The code concerning to -// bDoTestHere can be used (see below). Construct shapes which have their control -// points on equal coordinates. When these are written, they can be -// forced to create correct 'Q' and 'T' statements using this flag. -// These may then be tested for import/exporting. -static bool bDoTestHere(true); -#endif // TEST_QUADRATIC_CURVES - -void SdXMLImExSvgDElement::AddPolygon( - drawing::PointSequence* pPoints, - drawing::FlagSequence* pFlags, - const awt::Point& rObjectPos, - const awt::Size& rObjectSize, - bool bClosed) -{ - // Leaving the export stuff for the while, should eventually also - // consolidated with basegfx svg support - DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExSvgDElement(!)"); - - sal_Int32 nCnt(pPoints->getLength()); - - // #104076# Convert to string only when at last one point included - if(nCnt > 0) - { - // append polygon to string - OUString aNewString; - sal_Unicode aLastCommand = ' '; - awt::Point* pPointArray = pPoints->getArray(); - - // are the flags used at all? If not forget about them - if(pFlags) - { - sal_Int32 nFlagCnt(pFlags->getLength()); - - if(nFlagCnt) - { - bool bFlagsUsed(false); - drawing::PolygonFlags* pFlagArray = pFlags->getArray(); - - for(sal_Int32 a(0); !bFlagsUsed && a < nFlagCnt; a++) - if(drawing::PolygonFlags_NORMAL != *pFlagArray++) - bFlagsUsed = true; - - if(!bFlagsUsed) - pFlags = 0L; - } - else - { - pFlags = 0L; - } - } - - // object size and ViewBox size different? - bool bScale(rObjectSize.Width != mrViewBox.GetWidth() - || rObjectSize.Height != mrViewBox.GetHeight()); - bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L); - - // #87202# rework of point reduction: - // Test for Last point same -> closed, ignore last point. Take - // some more circumstances in account when looking at curve segments. - drawing::PolygonFlags* pFlagArray = (pFlags) ? pFlags->getArray() : 0L; - - // #i121090# only reduce double start/end points if polygon *is* closed - if(bClosed && (pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y)) - { - if(pFlags) - { - // point needs to be ignored if point before it is - // NO control point. Else the last point is needed - // for exporting the last segment of the curve. That means - // that the last and the first point will be saved double, - // but SVG does not support a better solution here. - if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2))) - { - nCnt--; - } - } - else - { - // no curve, ignore last point - nCnt--; - } - } - - // bezier poly, handle curves - bool bDidWriteStart(false); - sal_Int32 nStartX(0), nStartY(0); - - for(sal_Int32 a(0L); a < nCnt; a++) - { - if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray++) - { - bool bDidWriteAsCurve(false); - - if(bDidWriteStart) - { - if(pFlags) - { - // real curve point, get previous to see if it's a control point - awt::Point* pPrevPos1; - drawing::PolygonFlags aPrevFlag1; - - Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 1); - - if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1) - { - // get previous2 to see if it's a control point, too - awt::Point* pPrevPos2; - drawing::PolygonFlags aPrevFlag2; - - Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 2); - - if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2) - { - // get previous3 to see if it's a curve point and if, - // if it is fully symmetric or not - awt::Point* pPrevPos3; - drawing::PolygonFlags aPrevFlag3; - - Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 3); - - if(pPrevPos3) - { - // prepare coordinates - sal_Int32 nX, nY; - - Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - // #100617# test if this curve segment may be written as - // a quadratic bezier - // That's the case if both control points are in the same place - // when they are prolonged to the common quadratic control point - // Left: P = (3P1 - P0) / 2 - // Right: P = (3P2 - P3) / 2 - bool bIsQuadratic(false); - const bool bEnableSaveQuadratic(false); - - sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0)); - sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0)); - sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0)); - sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0)); - sal_Int32 nDist(0); - - if(nPX_L != nPX_R) - { - nDist += abs(nPX_L - nPX_R); - } - - if(nPY_L != nPY_R) - { - nDist += abs(nPY_L - nPY_R); - } - - if(nDist <= BORDER_INTEGERS_ARE_EQUAL) - { - if(bEnableSaveQuadratic) - { - bIsQuadratic = true; - } - } - -#ifdef TEST_QUADRATIC_CURVES - if(bDoTestHere) - { - bIsQuadratic = false; - - if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y) - bIsQuadratic = true; - } -#endif // TEST_QUADRATIC_CURVES - - if(bIsQuadratic) - { -#ifdef TEST_QUADRATIC_CURVES - if(bDoTestHere) - { - bool bPrevPointIsSymmetric(false); - - if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3) - { - // get previous4 to see if it's a control point - awt::Point* pPrevPos4; - drawing::PolygonFlags aPrevFlag4; - - Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 4); - - if(drawing::PolygonFlags_CONTROL == aPrevFlag4) - { - // okay, prevPos3 is symmetric (c2) and prevPos4 - // is existing control point, the 's' statement can be used - bPrevPointIsSymmetric = true; - } - } - - if(bPrevPointIsSymmetric) - { - // write a shorthand/smooth quadratic curveto entry (T) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('t')) - aNewString += "t"; - - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('t'); - } - else - { - if(aLastCommand != sal_Unicode('T')) - aNewString += "T"; - - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('T'); - } - } - else - { - // prepare coordinates - sal_Int32 nX1, nY1; - - Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - // write a quadratic curveto entry (Q) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('q')) - aNewString += "q"; - - Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('q'); - } - else - { - if(aLastCommand != sal_Unicode('Q')) - aNewString += "Q"; - - Imp_PutNumberCharWithSpace(aNewString, nX1); - Imp_PutNumberCharWithSpace(aNewString, nY1); - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('Q'); - } - } - } - else - { -#endif // TEST_QUADRATIC_CURVES - awt::Point aNewPoint(nPX_L, nPY_L); - bool bPrevPointIsSmooth(false); - - if(drawing::PolygonFlags_SMOOTH == aPrevFlag3) - { - // get previous4 to see if it's a control point - awt::Point* pPrevPos4; - drawing::PolygonFlags aPrevFlag4; - - Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 4); - - if(drawing::PolygonFlags_CONTROL == aPrevFlag4) - { - // okay, prevPos3 is smooth (c1) and prevPos4 - // is existing control point. Test if it's even symmetric - // and thus the 'T' statement may be used. - ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y); - ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y); - bool bSameLength(false); - bool bSameDirection(false); - - // get vector values - Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection); - - if(bSameLength && bSameDirection) - bPrevPointIsSmooth = true; - } - } - - if(bPrevPointIsSmooth) - { - // write a shorthand/smooth quadratic curveto entry (T) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('t')) - aNewString += "t"; - - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('t'); - } - else - { - if(aLastCommand != sal_Unicode('T')) - aNewString += "T"; - - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('T'); - } - } - else - { - // prepare coordinates - sal_Int32 nX1, nY1; - - Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - // write a quadratic curveto entry (Q) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('q')) - aNewString += "q"; - - Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('q'); - } - else - { - if(aLastCommand != sal_Unicode('Q')) - aNewString += "Q"; - - Imp_PutNumberCharWithSpace(aNewString, nX1); - Imp_PutNumberCharWithSpace(aNewString, nY1); - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('Q'); - } - } -#ifdef TEST_QUADRATIC_CURVES - } -#endif // TEST_QUADRATIC_CURVES - } - else - { - bool bPrevPointIsSymmetric(false); - - if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3) - { - // get previous4 to see if it's a control point - awt::Point* pPrevPos4; - drawing::PolygonFlags aPrevFlag4; - - Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), - pFlags->getArray(), a, nCnt, 4); - - if(drawing::PolygonFlags_CONTROL == aPrevFlag4) - { - // okay, prevPos3 is symmetric (c2) and prevPos4 - // is existing control point, the 's' statement can be used - bPrevPointIsSymmetric = true; - } - } - - // prepare coordinates - sal_Int32 nX2, nY2; - - Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - if(bPrevPointIsSymmetric) - { - // write a shorthand/smooth curveto entry (S) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('s')) - aNewString += "s"; - - Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY); - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('s'); - } - else - { - if(aLastCommand != sal_Unicode('S')) - aNewString += "S"; - - Imp_PutNumberCharWithSpace(aNewString, nX2); - Imp_PutNumberCharWithSpace(aNewString, nY2); - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('S'); - } - } - else - { - // prepare coordinates - sal_Int32 nX1, nY1; - - Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - // write a curveto entry (C) - if(mbRelative) - { - if(aLastCommand != sal_Unicode('c')) - aNewString += "c"; - - Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); - Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY); - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('c'); - } - else - { - if(aLastCommand != sal_Unicode('C')) - aNewString += "C"; - - Imp_PutNumberCharWithSpace(aNewString, nX1); - Imp_PutNumberCharWithSpace(aNewString, nY1); - Imp_PutNumberCharWithSpace(aNewString, nX2); - Imp_PutNumberCharWithSpace(aNewString, nY2); - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('C'); - } - } - } - - // remember that current point IS written - bDidWriteAsCurve = true; - - // remember new last position - mnLastX = nX; - mnLastY = nY; - } - } - } - } - } - - if(!bDidWriteAsCurve) - { - // current point not yet written, prepare coordinates - sal_Int32 nX, nY; - - Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize, - mrViewBox, bScale, bTranslate); - - if(bDidWriteStart) - { - // write as normal point - if(mnLastX == nX) - { - if(mbRelative) - { - if(aLastCommand != sal_Unicode('v')) - aNewString += "v"; - - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('v'); - } - else - { - if(aLastCommand != sal_Unicode('V')) - aNewString += "V"; - - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('V'); - } - } - else if(mnLastY == nY) - { - if(mbRelative) - { - if(aLastCommand != sal_Unicode('h')) - aNewString += "h"; - - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - - aLastCommand = sal_Unicode('h'); - } - else - { - if(aLastCommand != sal_Unicode('H')) - aNewString += "H"; - - Imp_PutNumberCharWithSpace(aNewString, nX); - - aLastCommand = sal_Unicode('H'); - } - } - else - { - if(mbRelative) - { - if(aLastCommand != sal_Unicode('l')) - aNewString += "l"; - - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('l'); - } - else - { - if(aLastCommand != sal_Unicode('L')) - aNewString += "L"; - - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('L'); - } - } - } - else - { - // write as start point - if(mbRelative) - { - aNewString += "m"; - - Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); - Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); - - aLastCommand = sal_Unicode('l'); - } - else - { - aNewString += "M"; - - Imp_PutNumberCharWithSpace(aNewString, nX); - Imp_PutNumberCharWithSpace(aNewString, nY); - - aLastCommand = sal_Unicode('L'); - } - - // remember start written - bDidWriteStart = true; - nStartX = nX; - nStartY = nY; - } - - // remember new last position - mnLastX = nX; - mnLastY = nY; - } - } - - // next point - pPointArray++; - } - - // close path if closed poly - if(bClosed) - { - if(mbRelative) - aNewString += "z"; - else - aNewString += "Z"; - - // update current point - we're back at the start - if( bDidWriteStart ) - { - mnLastX = nStartX; - mnLastY = nStartY; - } - } - - // append new string - msString += aNewString; - } -} - -SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew, - const SdXMLImExViewBox& rViewBox, - const awt::Point& rObjectPos, - const awt::Size& rObjectSize, - const SvXMLImport& rImport) -: msString( rNew ), - mrViewBox( rViewBox ), - mbIsClosed( false ), - mbIsCurve( false ), - mbRelative( true ), - mnLastX( 0L ), - mnLastY( 0L ), - maPoly() -{ - bool bWrongPositionAfterZ( false ); - sal_Int32 nUPD( 0 ); - sal_Int32 nBuildId( 0 ); - if ( rImport.getBuildIds( nUPD, nBuildId ) && - ( ( nUPD == 641 ) || ( nUPD == 645 ) || ( nUPD == 680 ) || ( nUPD == 300 ) || - ( nUPD == 310 ) || ( nUPD == 320 ) || ( nUPD == 330 ) || ( nUPD == 340 ) || - ( nUPD == 350 && nBuildId < 202 ) ) ) - { - bWrongPositionAfterZ = true; - } - - // convert string to polygon - basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD(aPoly,msString,bWrongPositionAfterZ); - - mbIsCurve = aPoly.areControlPointsUsed(); - mbIsClosed = aPoly.isClosed(); - - // object size and ViewBox size different? - basegfx::B2DHomMatrix aTransform; - const bool bScale(rObjectSize.Width != mrViewBox.GetWidth() - || rObjectSize.Height != mrViewBox.GetHeight()); - const bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L); - - if( bTranslate ) - aTransform.translate( - -mrViewBox.GetX(), - -mrViewBox.GetY()); - if( bScale ) - aTransform.scale( - (mrViewBox.GetWidth() ? rObjectSize.Width / mrViewBox.GetWidth() : 0), - (mrViewBox.GetHeight() ? rObjectSize.Height / mrViewBox.GetHeight() : 0)); - aTransform.translate( rObjectPos.X, rObjectPos.Y ); - aPoly.transform(aTransform); - - basegfx::unotools::b2DPolyPolygonToPolyPolygonBezier(aPoly,maPoly); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dobject.cxx b/xmloff/source/draw/ximp3dobject.cxx index ae53e0a8a628..6992a12c2314 100644 --- a/xmloff/source/draw/ximp3dobject.cxx +++ b/xmloff/source/draw/ximp3dobject.cxx @@ -31,6 +31,9 @@ #include <xmloff/xmltoken.hxx> #include <com/sun/star/drawing/PolyPolygonShape3D.hpp> #include <com/sun/star/drawing/DoubleSequence.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> using namespace ::com::sun::star; @@ -345,60 +348,37 @@ SdXML3DPolygonBasedShapeContext::~SdXML3DPolygonBasedShapeContext() void SdXML3DPolygonBasedShapeContext::StartElement(const uno::Reference< xml::sax::XAttributeList>& xAttrList) { uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) { // set parameters if(!maPoints.isEmpty() && !maViewBox.isEmpty()) { - SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); - awt::Point aMinPoint(aViewBox.GetX(), aViewBox.GetY()); - awt::Size aMaxSize(aViewBox.GetWidth(), aViewBox.GetHeight()); - SdXMLImExSvgDElement aPoints(maPoints, aViewBox, aMinPoint, aMaxSize, GetImport()); - - // convert to double sequences - drawing::PointSequenceSequence& xPoSeSe = - (drawing::PointSequenceSequence&)aPoints.GetPointSequenceSequence(); - sal_Int32 nOuterSequenceCount = xPoSeSe.getLength(); - drawing::PointSequence* pInnerSequence = xPoSeSe.getArray(); - - drawing::PolyPolygonShape3D xPolyPolygon3D; - xPolyPolygon3D.SequenceX.realloc(nOuterSequenceCount); - xPolyPolygon3D.SequenceY.realloc(nOuterSequenceCount); - xPolyPolygon3D.SequenceZ.realloc(nOuterSequenceCount); - drawing::DoubleSequence* pOuterSequenceX = xPolyPolygon3D.SequenceX.getArray(); - drawing::DoubleSequence* pOuterSequenceY = xPolyPolygon3D.SequenceY.getArray(); - drawing::DoubleSequence* pOuterSequenceZ = xPolyPolygon3D.SequenceZ.getArray(); - - for(sal_Int32 a(0L); a < nOuterSequenceCount; a++) - { - sal_Int32 nInnerSequenceCount(pInnerSequence->getLength()); - awt::Point* pArray = pInnerSequence->getArray(); - - pOuterSequenceX->realloc(nInnerSequenceCount); - pOuterSequenceY->realloc(nInnerSequenceCount); - pOuterSequenceZ->realloc(nInnerSequenceCount); - double* pInnerSequenceX = pOuterSequenceX->getArray(); - double* pInnerSequenceY = pOuterSequenceY->getArray(); - double* pInnerSequenceZ = pOuterSequenceZ->getArray(); - - for(sal_Int32 b(0L); b < nInnerSequenceCount; b++) - { - *pInnerSequenceX++ = pArray->X; - *pInnerSequenceY++ = pArray->Y; - *pInnerSequenceZ++ = 0.0; - pArray++; - } - pInnerSequence++; + // import 2d PolyPolygon from svg:d + basegfx::B2DPolyPolygon aPolyPolygon; - pOuterSequenceX++; - pOuterSequenceY++; - pOuterSequenceZ++; + if(basegfx::tools::importFromSvgD(aPolyPolygon, maPoints, true, 0)) + { + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aB3DPolyPolygon( + basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon( + aPolyPolygon)); + + // convert to UNO API class PolyPolygonShape3D + drawing::PolyPolygonShape3D xPolyPolygon3D; + basegfx::tools::B3DPolyPolygonToUnoPolyPolygonShape3D( + aB3DPolyPolygon, + xPolyPolygon3D); + + // set polygon data + uno::Any aAny; + aAny <<= xPolyPolygon3D; + xPropSet->setPropertyValue(OUString("D3DPolyPolygon3D"), aAny); + } + else + { + OSL_ENSURE(false, "Error on importing svg:d for 3D PolyPolygon (!)"); } - - // set poly - uno::Any aAny; - aAny <<= xPolyPolygon3D; - xPropSet->setPropertyValue("D3DPolyPolygon3D", aAny); } // call parent diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx index ed9def807223..fcfb945c6378 100644 --- a/xmloff/source/draw/ximpshap.cxx +++ b/xmloff/source/draw/ximpshap.cxx @@ -76,7 +76,11 @@ #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> #include <com/sun/star/container/XChild.hpp> #include <com/sun/star/text/XTextDocument.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/vector/b2dvector.hxx> using namespace ::com::sun::star; @@ -1280,20 +1284,45 @@ void SdXMLPolygonShapeContext::StartElement(const uno::Reference< xml::sax::XAtt // set polygon if(!maPoints.isEmpty() && !maViewBox.isEmpty()) { - SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); - awt::Size aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); - if (maSize.Width != 0 && maSize.Height !=0) + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) { - aSize = maSize; + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); } - awt::Point aPosition(aViewBox.GetX(), aViewBox.GetY()); - SdXMLImExPointsElement aPoints(maPoints, aViewBox, - aPosition, aSize, GetImport().GetMM100UnitConverter()); - uno::Any aAny; - aAny <<= aPoints.GetPointSequenceSequence(); - xPropSet->setPropertyValue( - OUString("Geometry"), aAny); + basegfx::B2DPolygon aPolygon; + + if(basegfx::tools::importFromSvgPoints(aPolygon, maPoints)) + { + if(aPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolygon.transform( + basegfx::tools::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + com::sun::star::drawing::PointSequenceSequence aPointSequenceSequence; + uno::Any aAny; + + basegfx::tools::B2DPolyPolygonToUnoPointSequenceSequence(basegfx::B2DPolyPolygon(aPolygon), aPointSequenceSequence); + aAny <<= aPointSequenceSequence; + xPropSet->setPropertyValue(OUString("Geometry"), aAny); + } + } } } @@ -1346,84 +1375,110 @@ void SdXMLPathShapeContext::StartElement(const uno::Reference< xml::sax::XAttrib // create polygon shape if(!maD.isEmpty()) { - // prepare some of the parameters - SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); - awt::Size aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); - awt::Point aPosition(aViewBox.GetX(), aViewBox.GetY()); - if (maSize.Width != 0 && maSize.Height !=0) - { - aSize = maSize; - } - SdXMLImExSvgDElement aPoints(maD, aViewBox, aPosition, aSize, GetImport()); + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); - const char* pService; - // now create shape - if(aPoints.IsCurve()) + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) { - if(aPoints.IsClosed()) - { - pService = "com.sun.star.drawing.ClosedBezierShape"; - } - else - { - pService = "com.sun.star.drawing.OpenBezierShape"; - } - } - else - { - if(aPoints.IsClosed()) - { - pService = "com.sun.star.drawing.PolyPolygonShape"; - } - else - { - pService = "com.sun.star.drawing.PolyLineShape"; - } + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); } - // Add, set Style and properties from base shape - AddShape(pService); + basegfx::B2DPolyPolygon aPolyPolygon; - // #89344# test for mxShape.is() and not for mxShapes.is() to support - // shape import helper classes WITHOUT XShapes (member mxShapes). This - // is used by the writer. - if( mxShape.is() ) + if(basegfx::tools::importFromSvgD(aPolyPolygon, maD, true, 0)) { - SetStyle(); - SetLayer(); - - // set local parameters on shape - uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); - if(xPropSet.is()) + if(aPolyPolygon.count()) { - uno::Any aAny; + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); - // set svg:d - if(!maD.isEmpty()) + if(!aSourceRange.equal(aTargetRange)) { - if(aPoints.IsCurve()) - { - drawing::PolyPolygonBezierCoords aSourcePolyPolygon( - aPoints.GetPointSequenceSequence(), - aPoints.GetFlagSequenceSequence()); + aPolyPolygon.transform( + basegfx::tools::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } - aAny <<= aSourcePolyPolygon; - xPropSet->setPropertyValue( - OUString("Geometry"), aAny); + // create shape + const char* pService; + + if(aPolyPolygon.areControlPointsUsed()) + { + if(aPolyPolygon.isClosed()) + { + pService = "com.sun.star.drawing.ClosedBezierShape"; } else { - aAny <<= aPoints.GetPointSequenceSequence(); - xPropSet->setPropertyValue( - OUString("Geometry"), aAny); + pService = "com.sun.star.drawing.OpenBezierShape"; + } + } + else + { + if(aPolyPolygon.isClosed()) + { + pService = "com.sun.star.drawing.PolyPolygonShape"; + } + else + { + pService = "com.sun.star.drawing.PolyLineShape"; } } - } - // set pos, size, shear and rotate - SetTransformation(); + // Add, set Style and properties from base shape + AddShape(pService); - SdXMLShapeContext::StartElement(xAttrList); + // #89344# test for mxShape.is() and not for mxShapes.is() to support + // shape import helper classes WITHOUT XShapes (member mxShapes). This + // is used by the writer. + if( mxShape.is() ) + { + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + uno::Any aAny; + + // set polygon data + if(aPolyPolygon.areControlPointsUsed()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::tools::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + else + { + drawing::PointSequenceSequence aSourcePolyPolygon; + + basegfx::tools::B2DPolyPolygonToUnoPointSequenceSequence( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + + xPropSet->setPropertyValue(OUString("Geometry"), aAny); + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::StartElement(xAttrList); + } + } } } } @@ -1771,30 +1826,32 @@ void SdXMLConnectorShapeContext::processAttribute( sal_uInt16 nPrefix, const OUS } if( IsXMLToken( rLocalName, XML_D ) ) { - SdXMLImExViewBox aViewBox( 0, 0, 1, 1 ); - awt::Point aPoint( 0, 0 ); - awt::Size aSize( 1, 1 ); - - SdXMLImExSvgDElement aPoints( rValue, aViewBox, aPoint, aSize, GetImport() ); + basegfx::B2DPolyPolygon aPolyPolygon; - if ( aPoints.IsCurve() ) + if(basegfx::tools::importFromSvgD(aPolyPolygon, rValue, true, 0)) { - drawing::PolyPolygonBezierCoords aSourcePolyPolygon( - aPoints.GetPointSequenceSequence(), - aPoints.GetFlagSequenceSequence()); - maPath <<= aSourcePolyPolygon; - } - else - { - const drawing::PointSequenceSequence& rOuterSeq = aPoints.GetPointSequenceSequence(); - drawing::FlagSequenceSequence aFlagSeqSeq( rOuterSeq.getLength() ); - for ( int a = 0; a < rOuterSeq.getLength(); a++ ) - aFlagSeqSeq[ a ] = drawing::FlagSequence( rOuterSeq[ a ].getLength() ); + if(aPolyPolygon.count()) + { + // set polygon data + if(aPolyPolygon.areControlPointsUsed()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; - drawing::PolyPolygonBezierCoords aSourcePolyPolygon( - aPoints.GetPointSequenceSequence(), - aFlagSeqSeq ); - maPath <<= aSourcePolyPolygon; + basegfx::tools::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + maPath <<= aSourcePolyPolygon; + } + else + { + drawing::PointSequenceSequence aSourcePolyPolygon; + + basegfx::tools::B2DPolyPolygonToUnoPointSequenceSequence( + aPolyPolygon, + aSourcePolyPolygon); + maPath <<= aSourcePolyPolygon; + } + } } } } @@ -3623,11 +3680,11 @@ void SdXMLCustomShapeContext::EndElement() if(bFlippedX) { - aNewPoroperty.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MirroredX")); + aNewPoroperty.Name = "MirroredX"; } else { - aNewPoroperty.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MirroredY")); + aNewPoroperty.Name = "MirroredY"; } aNewPoroperty.Handle = -1; diff --git a/xmloff/source/style/MarkerStyle.cxx b/xmloff/source/style/MarkerStyle.cxx index 125d411ab50c..b5f6fcdcdcd6 100644 --- a/xmloff/source/style/MarkerStyle.cxx +++ b/xmloff/source/style/MarkerStyle.cxx @@ -29,6 +29,9 @@ #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> using namespace ::com::sun::star; @@ -92,40 +95,37 @@ sal_Bool XMLMarkerStyleImport::importXML( if( bHasViewBox && bHasPathData ) { - SdXMLImExSvgDElement aPoints(strPathData, *pViewBox, awt::Point( 0, 0 ), - awt::Size( pViewBox->GetWidth(), pViewBox->GetHeight() ), rImport ); + basegfx::B2DPolyPolygon aPolyPolygon; - if(aPoints.IsCurve()) + if(basegfx::tools::importFromSvgD(aPolyPolygon, strPathData, true, 0)) { - drawing::PolyPolygonBezierCoords aSourcePolyPolygon( - aPoints.GetPointSequenceSequence(), - aPoints.GetFlagSequenceSequence()); - rValue <<= aSourcePolyPolygon; - } - else - { - drawing::PolyPolygonBezierCoords aSourcePolyPolygon; - aSourcePolyPolygon.Coordinates = aPoints.GetPointSequenceSequence(); - aSourcePolyPolygon.Flags.realloc(aSourcePolyPolygon.Coordinates.getLength()); - - // Zeiger auf innere sequences holen - const drawing::PointSequence* pInnerSequence = aSourcePolyPolygon.Coordinates.getConstArray(); - drawing::FlagSequence* pInnerSequenceFlags = aSourcePolyPolygon.Flags.getArray(); - - for(sal_Int32 a(0); a < aSourcePolyPolygon.Coordinates.getLength(); a++) + if(aPolyPolygon.count()) { - pInnerSequenceFlags->realloc(pInnerSequence->getLength()); - drawing::PolygonFlags* pPolyFlags = pInnerSequenceFlags->getArray(); + // ViewBox probably not used, but stay with former processing inside of + // SdXMLImExSvgDElement + const basegfx::B2DRange aSourceRange( + pViewBox->GetX(), pViewBox->GetY(), + pViewBox->GetX() + pViewBox->GetWidth(), pViewBox->GetY() + pViewBox->GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + pViewBox->GetWidth(), pViewBox->GetHeight()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::tools::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } - for(sal_Int32 b(0); b < pInnerSequence->getLength(); b++) - *pPolyFlags++ = drawing::PolygonFlags_NORMAL; + // always use PolyPolygonBezierCoords here + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; - // next run - pInnerSequence++; - pInnerSequenceFlags++; + basegfx::tools::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + rValue <<= aSourcePolyPolygon; } - - rValue <<= aSourcePolyPolygon; } if( !aDisplayName.isEmpty() ) @@ -134,7 +134,6 @@ sal_Bool XMLMarkerStyleImport::importXML( aDisplayName ); rStrName = aDisplayName; } - } if( pViewBox ) @@ -167,88 +166,44 @@ sal_Bool XMLMarkerStyleExport::exportXML( if(rValue >>= aBezier) { // Name - sal_Bool bEncoded = sal_False; + sal_Bool bEncoded(sal_False); OUString aStrName( rStrName ); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, - rExport.EncodeStyleName( aStrName, - &bEncoded ) ); - if( bEncoded ) - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, - aStrName ); - - // Viewbox (viewBox="0 0 1500 1000") - sal_Int32 nMinX(0x7fffffff); - sal_Int32 nMaxX(0x80000000); - sal_Int32 nMinY(0x7fffffff); - sal_Int32 nMaxY(0x80000000); - sal_Int32 nOuterCnt(aBezier.Coordinates.getLength()); - drawing::PointSequence* pOuterSequence = aBezier.Coordinates.getArray(); - sal_Int32 a, b; - sal_Bool bClosed(sal_False); - - for (a = 0; a < nOuterCnt; a++) - { - drawing::PointSequence* pSequence = pOuterSequence++; - const awt::Point *pPoints = pSequence->getConstArray(); - sal_Int32 nPointCount(pSequence->getLength()); - if(nPointCount) - { - const awt::Point aStart = pPoints[0]; - const awt::Point aEnd = pPoints[nPointCount - 1]; - - if(aStart.X == aEnd.X && aStart.Y == aEnd.Y) - { - bClosed = sal_True; - } - } + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, rExport.EncodeStyleName( aStrName, &bEncoded ) ); - for (b = 0; b < nPointCount; b++) - { - const awt::Point aPoint = pPoints[b]; - - if( aPoint.X < nMinX ) - nMinX = aPoint.X; - - if( aPoint.X > nMaxX ) - nMaxX = aPoint.X; - - if( aPoint.Y < nMinY ) - nMinY = aPoint.Y; - - if( aPoint.Y > nMaxY ) - nMaxY = aPoint.Y; - } + if( bEncoded ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, aStrName ); } - sal_Int32 nDifX(nMaxX - nMinX); - sal_Int32 nDifY(nMaxY - nMinY); + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + aBezier)); + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + + ///////////////// + // Viewbox (viewBox="0 0 1500 1000") - SdXMLImExViewBox aViewBox( 0, 0, nDifX, nDifY ); + SdXMLImExViewBox aViewBox( + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() ); // Pathdata - pOuterSequence = aBezier.Coordinates.getArray(); - drawing::FlagSequence* pOuterFlags = aBezier.Flags.getArray(); - SdXMLImExSvgDElement aSvgDElement(aViewBox, rExport); - - for (a = 0; a < nOuterCnt; a++) - { - drawing::PointSequence* pSequence = pOuterSequence++; - drawing::FlagSequence* pFlags = pOuterFlags++; - - aSvgDElement.AddPolygon(pSequence, pFlags, - awt::Point( 0, 0 ), - awt::Size( aViewBox.GetWidth(), aViewBox.GetHeight() ), - bClosed); - } + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible // write point array - rExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString()); + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); // Do Write - SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_MARKER, - sal_True, sal_False ); + SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_MARKER, sal_True, sal_False ); } } diff --git a/xmloff/source/text/XMLTextFrameContext.cxx b/xmloff/source/text/XMLTextFrameContext.cxx index 7a0ca85574a7..a8edd774cf1b 100644 --- a/xmloff/source/text/XMLTextFrameContext.cxx +++ b/xmloff/source/text/XMLTextFrameContext.cxx @@ -47,12 +47,14 @@ #include <xmloff/XMLEventsImportContext.hxx> #include "XMLImageMapContext.hxx" #include "XMLTextFrameContext.hxx" - #include "XMLTextListBlockContext.hxx" #include "XMLTextListItemContext.hxx" #include <xmloff/attrlist.hxx> #include <comphelper/stl_types.hxx> - +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <map> using namespace ::com::sun::star; @@ -283,31 +285,52 @@ XMLTextFrameContourContext_Impl::XMLTextFrameContourContext_Impl( } OUString sContourPolyPolygon("ContourPolyPolygon"); - Reference < XPropertySetInfo > xPropSetInfo = - rPropSet->getPropertySetInfo(); - if( xPropSetInfo->hasPropertyByName(sContourPolyPolygon ) && - nWidth > 0 && nHeight > 0 && bPixelWidth == bPixelHeight && - !(bPath ? sD : sPoints).isEmpty() ) + Reference < XPropertySetInfo > xPropSetInfo = rPropSet->getPropertySetInfo(); + + if(xPropSetInfo->hasPropertyByName(sContourPolyPolygon) && nWidth > 0 && nHeight > 0 && bPixelWidth == bPixelHeight && (bPath ? sD : sPoints).getLength()) { - awt::Point aPoint( 0, 0 ); - awt::Size aSize( nWidth, nHeight ); - SdXMLImExViewBox aViewBox( sViewBox, - GetImport().GetMM100UnitConverter()); + const SdXMLImExViewBox aViewBox( sViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DPolyPolygon aPolyPolygon; Any aAny; + if( bPath ) { - SdXMLImExSvgDElement aPoints( sD, aViewBox, aPoint, aSize, GetImport() ); - aAny <<= aPoints.GetPointSequenceSequence(); + basegfx::tools::importFromSvgD(aPolyPolygon, sD, true, 0); } else { - SdXMLImExPointsElement aPoints( sPoints, aViewBox, aPoint, aSize, - GetImport().GetMM100UnitConverter() ); - aAny <<= aPoints.GetPointSequenceSequence(); + basegfx::B2DPolygon aPolygon; + + if(basegfx::tools::importFromSvgPoints(aPolygon, sPoints)) + { + aPolyPolygon = basegfx::B2DPolyPolygon(aPolygon); + } } - OUString sIsPixelContour("IsPixelContour"); - xPropSet->setPropertyValue( sContourPolyPolygon, aAny ); + if(aPolyPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + nWidth, nHeight); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::tools::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + com::sun::star::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::tools::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPolygon, aPointSequenceSequence); + aAny <<= aPointSequenceSequence; + xPropSet->setPropertyValue( sContourPolyPolygon, aAny ); + } + + const OUString sIsPixelContour("IsPixelContour"); if( xPropSetInfo->hasPropertyByName( sIsPixelContour ) ) { @@ -315,7 +338,8 @@ XMLTextFrameContourContext_Impl::XMLTextFrameContourContext_Impl( xPropSet->setPropertyValue( sIsPixelContour, aAny ); } - OUString sIsAutomaticContour("IsAutomaticContour"); + const OUString sIsAutomaticContour("IsAutomaticContour"); + if( xPropSetInfo->hasPropertyByName( sIsAutomaticContour ) ) { aAny.setValue( &bAuto, ::getBooleanCppuType() ); diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx index 877d714edcb8..bc9820944274 100644 --- a/xmloff/source/text/txtparae.cxx +++ b/xmloff/source/text/txtparae.cxx @@ -21,11 +21,9 @@ #include <tools/debug.hxx> #include <rtl/ustrbuf.hxx> #include <sal/types.h> - #include <vector> #include <list> #include <boost/unordered_map.hpp> - #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/container/XEnumerationAccess.hpp> #include <com/sun/star/container/XEnumeration.hpp> @@ -59,15 +57,12 @@ #include <com/sun/star/document/XEmbeddedObjectSupplier.hpp> #include <com/sun/star/document/XEventsSupplier.hpp> #include <com/sun/star/document/XRedlinesSupplier.hpp> - #include <com/sun/star/text/XBookmarksSupplier.hpp> #include <com/sun/star/text/XFormField.hpp> - #include <com/sun/star/text/XTextSection.hpp> #include <com/sun/star/text/SectionFileLink.hpp> #include <com/sun/star/drawing/XShape.hpp> #include <com/sun/star/text/XTextShapesSupplier.hpp> - #include <com/sun/star/style/XAutoStylesSupplier.hpp> #include <com/sun/star/style/XAutoStyleFamily.hpp> #include <com/sun/star/text/XTextFieldsSupplier.hpp> @@ -104,8 +99,10 @@ #include <xmloff/formlayerexport.hxx> #include "XMLTextCharStyleNamesElementExport.hxx" #include <comphelper/stlunosequence.hxx> - #include <xmloff/odffields.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/XTransactedObject.hpp> #include <com/sun/star/document/XStorageBasedDocument.hpp> @@ -2964,38 +2961,29 @@ void XMLTextParagraphExport::_exportTextFrame( } void XMLTextParagraphExport::exportContour( - const Reference < XPropertySet > & rPropSet, - const Reference < XPropertySetInfo > & rPropSetInfo ) + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) { if( !rPropSetInfo->hasPropertyByName( sContourPolyPolygon ) ) + { return; + } PointSequenceSequence aSourcePolyPolygon; rPropSet->getPropertyValue( sContourPolyPolygon ) >>= aSourcePolyPolygon; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::tools::UnoPointSequenceSequenceToB2DPolyPolygon( + aSourcePolyPolygon)); + const sal_uInt32 nPolygonCount(aPolyPolygon.count()); - if( !aSourcePolyPolygon.getLength() ) - return; - - awt::Point aPoint( 0, 0 ); - awt::Size aSize( 0, 0 ); - sal_Int32 nPolygons = aSourcePolyPolygon.getLength(); - const PointSequence *pPolygons = aSourcePolyPolygon.getConstArray(); - while( nPolygons-- ) + if(!nPolygonCount) { - sal_Int32 nPoints = pPolygons->getLength(); - const awt::Point *pPoints = pPolygons->getConstArray(); - while( nPoints-- ) - { - if( aSize.Width < pPoints->X ) - aSize.Width = pPoints->X; - if( aSize.Height < pPoints->Y ) - aSize.Height = pPoints->Y; - pPoints++; - } - pPolygons++; + return; } - sal_Bool bPixel = sal_False; + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + bool bPixel(false); + if( rPropSetInfo->hasPropertyByName( sIsPixelContour ) ) { bPixel = *(sal_Bool *)rPropSet->getPropertyValue( sIsPixelContour ).getValue(); @@ -3003,77 +2991,59 @@ void XMLTextParagraphExport::exportContour( // svg: width OUStringBuffer aStringBuffer( 10 ); - if( bPixel ) + + if(bPixel) { - ::sax::Converter::convertMeasurePx(aStringBuffer, aSize.Width); + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); } else { - GetExport().GetMM100UnitConverter().convertMeasureToXML( - aStringBuffer, aSize.Width); + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); } - GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, - aStringBuffer.makeStringAndClear() ); + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStringBuffer.makeStringAndClear()); // svg: height - if( bPixel ) + if(bPixel) { - ::sax::Converter::convertMeasurePx(aStringBuffer, aSize.Height); + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); } else { - GetExport().GetMM100UnitConverter().convertMeasureToXML( - aStringBuffer, aSize.Height); + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); } - GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, - aStringBuffer.makeStringAndClear() ); - - // svg:viewbox - SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height); - GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, - aViewBox.GetExportString()); - sal_Int32 nOuterCnt( aSourcePolyPolygon.getLength() ); + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStringBuffer.makeStringAndClear()); + // svg:viewbox + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolyPolygonRange.getWidth(), aPolyPolygonRange.getHeight()); + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); enum XMLTokenEnum eElem = XML_TOKEN_INVALID; - if( 1L == nOuterCnt ) + + if(1 == nPolygonCount ) { // simple polygon shape, can be written as svg:points sequence - /*const*/ PointSequence* pSequence = - (PointSequence*)aSourcePolyPolygon.getConstArray(); - - SdXMLImExPointsElement aPoints( pSequence, aViewBox, aPoint, aSize ); + const OUString aPointString( + basegfx::tools::exportToSvgPoints( + aPolyPolygon.getB2DPolygon(0))); // write point array - GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_POINTS, - aPoints.GetExportString()); + GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); eElem = XML_CONTOUR_POLYGON; } else { // polypolygon, needs to be written as a svg:path sequence - /*const*/ PointSequence* pOuterSequence = - (PointSequence*)aSourcePolyPolygon.getConstArray(); - if(pOuterSequence) - { - // prepare svx:d element export - SdXMLImExSvgDElement aSvgDElement( aViewBox, GetExport() ); + const OUString aPolygonString( + basegfx::tools::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible - for(sal_Int32 a(0L); a < nOuterCnt; a++) - { - /*const*/ PointSequence* pSequence = pOuterSequence++; - if(pSequence) - { - aSvgDElement.AddPolygon(pSequence, 0L, aPoint, - aSize, sal_True ); - } - } - - // write point array - GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, - aSvgDElement.GetExportString()); - eElem = XML_CONTOUR_PATH; - } + // write point array + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, aPolygonString); + eElem = XML_CONTOUR_PATH; } if( rPropSetInfo->hasPropertyByName( sIsAutomaticContour ) ) |