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 /basegfx | |
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
Diffstat (limited to 'basegfx')
-rw-r--r-- | basegfx/Library_basegfx.mk | 1 | ||||
-rw-r--r-- | basegfx/source/inc/stringconversiontools.hxx | 96 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygontools.cxx | 343 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolypolygontools.cxx | 114 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dsvgpolypolygon.cxx | 474 | ||||
-rw-r--r-- | basegfx/source/polygon/b3dpolypolygontools.cxx | 153 | ||||
-rw-r--r-- | basegfx/source/tools/stringconversiontools.cxx | 169 | ||||
-rw-r--r-- | basegfx/test/basegfx2d.cxx | 40 | ||||
-rw-r--r-- | basegfx/test/boxclipper.cxx | 21 | ||||
-rw-r--r-- | basegfx/test/clipstate.cxx | 13 | ||||
-rw-r--r-- | basegfx/test/genericclipper.cxx | 14 |
11 files changed, 1095 insertions, 343 deletions
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() |