summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/source/msfilter/msdffimp.cxx334
-rw-r--r--svx/qa/unit/customshapes.cxx19
-rw-r--r--svx/qa/unit/data/tdf124029_Arc_position.docbin0 -> 19456 bytes
3 files changed, 192 insertions, 161 deletions
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx
index d3c5fada8df4..ed5dc9ea7d8f 100644
--- a/filter/source/msfilter/msdffimp.cxx
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -57,6 +57,8 @@
#include <unotools/ucbstreamhelper.hxx>
#include <filter/msfilter/escherex.hxx>
#include <basegfx/range/b2drange.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
#include <com/sun/star/container/XIdentifierContainer.hpp>
#include <com/sun/star/drawing/XGluePointsSupplier.hpp>
#include <com/sun/star/drawing/Position3D.hpp>
@@ -381,7 +383,6 @@ DffPropertyReader::~DffPropertyReader()
{
}
-
static SvStream& operator>>( SvStream& rIn, SvxMSDffConnectorRule& rRule )
{
sal_uInt32 nRuleId;
@@ -4512,10 +4513,10 @@ SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& r
}
}
- // mso_sptArc special treating:
- // sj: since we actually can't render the arc because of its weird SnapRect settings,
- // we will create a new CustomShape, that can be saved/loaded without problems.
- // We will change the shape type, so this code applies only if importing arcs from msoffice.
+ // mso_sptArc special treating
+ // tdf#124026: A new custom shape is generated from prototype 'msoArc'. Values, which are
+ // read here, are adapted and merged. The shape type is changed, so this code
+ // applies only if importing arcs from MS Office.
if ( aObjData.eShapeType == mso_sptArc )
{
const OUString sAdjustmentValues( "AdjustmentValues" );
@@ -4526,181 +4527,193 @@ SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& r
const OUString sPath( "Path" );
const OUString sTextFrames( "TextFrames" );
SdrCustomShapeGeometryItem aGeometryItem( static_cast<SdrObjCustomShape*>(pRet)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
- css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
- css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
-
- // before clearing the GeometryItem we have to store the current Coordinates
- const uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
- tools::Rectangle aPolyBoundRect;
- Point aStartPt( 0,0 );
- if ( pAny && ( *pAny >>= seqCoordinates ) && ( seqCoordinates.getLength() >= 4 ) )
- {
- sal_Int32 nPtNum, nNumElemVert = seqCoordinates.getLength();
- XPolygon aXP( static_cast<sal_uInt16>(nNumElemVert) );
- for ( nPtNum = 0; nPtNum < nNumElemVert; nPtNum++ )
- {
- Point aP;
- sal_Int32 nX = 0, nY = 0;
- seqCoordinates[ nPtNum ].First.Value >>= nX;
- seqCoordinates[ nPtNum ].Second.Value >>= nY;
- aP.setX(nX);
- aP.setY(nY);
- aXP[ static_cast<sal_uInt16>(nPtNum) ] = aP;
- }
- aPolyBoundRect = aXP.GetBoundRect();
-
- // arc first command is always wr -- clockwise arc
- // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
- aStartPt = aXP[2];
- }
- else
- aPolyBoundRect = tools::Rectangle( -21600, 0, 21600, 43200 ); // defaulting
-
- // clearing items, so MergeDefaultAttributes will set the corresponding defaults from EnhancedCustomShapeGeometry
- aGeometryItem.ClearPropertyValue( sHandles );
- aGeometryItem.ClearPropertyValue( sEquations );
- aGeometryItem.ClearPropertyValue( sViewBox );
- aGeometryItem.ClearPropertyValue( sPath );
+ PropertyValue aPropVal;
- sal_Int32 nEndAngle = 9000;
- sal_Int32 nStartAngle = 0;
- pAny = aGeometryItem.GetPropertyValueByName( sAdjustmentValues );
- if ( pAny && ( *pAny >>= seqAdjustmentValues ) && seqAdjustmentValues.getLength() > 1 )
+ // The default arc goes form -90deg to 0deg. Replace general defaults used
+ // when read from stream with this specific values.
+ double fStartAngle(-90.0);
+ double fEndAngle(0.0);
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
+ const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
+ pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
+ if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1)
{
- if ( seqAdjustmentValues[ 0 ].State == css::beans::PropertyState_DIRECT_VALUE )
+ if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE)
{
- double fNumber;
- seqAdjustmentValues[ 0 ].Value >>= fNumber;
- sal_Int32 nValue;
- bool bFail = o3tl::checked_multiply<sal_Int32>(fNumber, 100, nValue);
- if (bFail)
- SAL_WARN("filter.ms", "nEndAngle too large: " << fNumber);
- else
- nEndAngle = NormAngle36000(-nValue);
+ seqAdjustmentValues[0].Value <<= -90.0;
+ seqAdjustmentValues[0].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
}
- else
+ if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE)
{
- //normal situation:if endAngle != 90,there will be a direct_value,but for damaged curve,the endAngle need to recalculate.
- Point cent = aPolyBoundRect.Center();
- double fNumber;
- if ( aStartPt.Y() == cent.Y() )
- fNumber = ( aStartPt.X() >= cent.X() ) ? 0:180.0;
- else if ( aStartPt.X() == cent.X() )
- fNumber = ( aStartPt.Y() >= cent.Y() ) ? 90.0: 270.0;
- else
- {
- fNumber
- = basegfx::rad2deg(atan2(double(aStartPt.X() - cent.X()),
- double(aStartPt.Y() - cent.Y()))
- + F_PI); // 0..360.0
- }
- nEndAngle = NormAngle36000( - static_cast<sal_Int32>(fNumber) * 100 );
- seqAdjustmentValues[ 0 ].Value <<= fNumber;
- seqAdjustmentValues[ 0 ].State = css::beans::PropertyState_DIRECT_VALUE; // so this value will properly be stored
+ seqAdjustmentValues[1].Value <<= 0.0;
+ seqAdjustmentValues[1].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
}
-
- if ( seqAdjustmentValues[ 1 ].State == css::beans::PropertyState_DIRECT_VALUE )
- {
- double fNumber;
- seqAdjustmentValues[ 1 ].Value >>= fNumber;
- nStartAngle = NormAngle36000( - static_cast<sal_Int32>(fNumber) * 100 );
- }
- else
- {
- seqAdjustmentValues[ 1 ].Value <<= 0.0;
- seqAdjustmentValues[ 1 ].State = css::beans::PropertyState_DIRECT_VALUE;
- }
-
- PropertyValue aPropVal;
+ seqAdjustmentValues[0].Value >>= fStartAngle;
+ seqAdjustmentValues[1].Value >>= fEndAngle;
aPropVal.Name = sAdjustmentValues;
aPropVal.Value <<= seqAdjustmentValues;
- aGeometryItem.SetPropertyValue( aPropVal ); // storing the angle attribute
+ aGeometryItem.SetPropertyValue(aPropVal);
}
- if ( nStartAngle != nEndAngle )
- {
- XPolygon aXPoly( aPolyBoundRect.Center(), aPolyBoundRect.GetWidth() / 2, aPolyBoundRect.GetHeight() / 2,
- static_cast<sal_uInt16>(nStartAngle) / 10, static_cast<sal_uInt16>(nEndAngle) / 10, true );
- tools::Rectangle aPolyPieRect( aXPoly.GetBoundRect() );
- double fYScale = 0.0, fXScale = 0.0;
- double fYOfs, fXOfs;
+ // arc first command is always wr -- clockwise arc
+ // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
+ // The left/top vertex of the frame rectangle of the sector is the origin
+ // of the shape internal coordinate system in MS Office. The default arc
+ // has an ellipse frame rectange with LT(-21600,0) and
+ // RB(21600,43200) in this coordinate system.
+ basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0);
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
+ if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2))
+ {
+ sal_Int32 nL, nT, nR, nB;
+ seqCoordinates[0].First.Value >>= nL;
+ seqCoordinates[0].Second.Value >>= nT;
+ seqCoordinates[1].First.Value >>= nR;
+ seqCoordinates[1].Second.Value >>= nB;
+ aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB);
+ }
- Point aP( aObjData.aBoundRect.Center() );
- Size aS( aObjData.aBoundRect.GetSize() );
- aP.AdjustX( -(aS.Width() / 2) );
- aP.AdjustY( -(aS.Height() / 2) );
- tools::Rectangle aLogicRect( aP, aS );
+ // MS Office uses the pie frame rectangle as reference for outer position
+ // and size of the shape and for text in the shape. We can get this rectangle
+ // from imported viewBox or from the arc geometry.
+ basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0);
+ pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox);
+ css::awt::Rectangle aImportedViewBox;
+ if (pAny && (*pAny >>= aImportedViewBox))
+ {
+ aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X,
+ aImportedViewBox.Y,
+ aImportedViewBox.X + aImportedViewBox.Width,
+ aImportedViewBox.Y + aImportedViewBox.Height);
+ }
+ else
+ {
+ double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle)));
+ double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle)));
+ basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter());
+ basegfx::B2DPolygon aTempPie(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ aCenter,
+ aEllipseRect_MS.getWidth() * 0.5,
+ aEllipseRect_MS.getHeight() * 0.5,
+ fRadStartAngle,
+ fRadEndAngle));
+ aTempPie.append(aCenter);
+ aPieRect_MS = aTempPie.getB2DRange();
+ }
- fYOfs = fXOfs = 0.0;
+ // MS Office uses for mso_sptArc a frame rectangle (=resize handles)
+ // which encloses only the sector, LibreOffice uses for custom shapes as
+ // default a frame rectangle, which encloses the entire ellipse. That would
+ // result in wrong positions in Writer and Calc, see tdf#124026.
+ // We workaround this problem, by setting a suitable viewBox.
+ bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT);
+ css::awt::Rectangle aViewBox_LO; // in LO coordinate system
+ if (bIsImportPPT || aPieRect_MS.getWidth() == 0 || aPieRect_MS.getHeight() == 0)
+ { // clear item, so that default from EnhancedCustomShapeGeometry is used
+ aGeometryItem.ClearPropertyValue(sViewBox);
+ }
+ else
+ {
+ double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0);
+ double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0);
+ aViewBox_LO.X = static_cast<sal_Int32>(fX);
+ aViewBox_LO.Y = static_cast<sal_Int32>(fY);
+ aViewBox_LO.Width = static_cast<sal_Int32>(aPieRect_MS.getWidth() / 2.0);
+ aViewBox_LO.Height = static_cast<sal_Int32>(aPieRect_MS.getHeight() / 2.0);
+ aPropVal.Name = sViewBox;
+ aPropVal.Value <<= aViewBox_LO;
+ aGeometryItem.SetPropertyValue(aPropVal);
+ }
- if ( aPolyBoundRect.GetWidth() && aPolyPieRect.GetWidth() )
+ // aObjData.aBoundRect contains position and size of the sector in (outer)
+ // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips.
+ // For Impress the default viewBox is used, so adapt aObjData.aBoundRect.
+ tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on
+ if (bIsImportPPT)
+ {
+ double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs
+ double fLogicYOfs(0.0);
+ double fLogicPieWidth(aObjData.aBoundRect.getWidth());
+ double fLogicPieHeight(aObjData.aBoundRect.getHeight());
+ double fLogicEllipseWidth(0.0); // to be LogicWidth_LO
+ double fLogicEllipseHeight(0.0);
+ if (aPieRect_MS.getWidth())
{
- fXScale = static_cast<double>(aLogicRect.GetWidth()) / static_cast<double>(aPolyPieRect.GetWidth());
- if ( nSpFlags & ShapeFlag::FlipH )
- fXOfs = ( static_cast<double>(aPolyPieRect.Right()) - static_cast<double>(aPolyBoundRect.Right()) ) * fXScale;
+ // fXScale = ratio 'logic length' : 'shape internal length'
+ double fXScale = fLogicPieWidth / aPieRect_MS.getWidth();
+ if (nSpFlags & ShapeFlag::FlipH)
+ fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale;
else
- fXOfs = ( static_cast<double>(aPolyBoundRect.Left()) - static_cast<double>(aPolyPieRect.Left()) ) * fXScale;
+ fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale;
+ fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale;
}
- if ( aPolyBoundRect.GetHeight() && aPolyPieRect.GetHeight() )
+ if (aPieRect_MS.getHeight())
{
- fYScale = static_cast<double>(aLogicRect.GetHeight()) / static_cast<double>(aPolyPieRect.GetHeight());
- if ( nSpFlags & ShapeFlag::FlipV )
- fYOfs = ( static_cast<double>(aPolyPieRect.Bottom()) - static_cast<double>(aPolyBoundRect.Bottom()) ) * fYScale;
+ double fYScale = fLogicPieHeight / aPieRect_MS.getHeight();
+ if (nSpFlags & ShapeFlag::FlipV)
+ fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale;
else
- fYOfs = (static_cast<double>(aPolyBoundRect.Top()) - static_cast<double>(aPolyPieRect.Top()) ) * fYScale;
- }
-
- if ( aPolyPieRect.GetWidth() )
- fXScale = static_cast<double>(aPolyBoundRect.GetWidth()) / static_cast<double>(aPolyPieRect.GetWidth());
- if ( aPolyPieRect.GetHeight() )
- fYScale = static_cast<double>(aPolyBoundRect.GetHeight()) / static_cast<double>(aPolyPieRect.GetHeight());
-
- tools::Rectangle aOldBoundRect( aObjData.aBoundRect );
- aObjData.aBoundRect = tools::Rectangle( Point( aLogicRect.Left() + static_cast<sal_Int32>(fXOfs), aLogicRect.Top() + static_cast<sal_Int32>(fYOfs) ),
- Size( static_cast<sal_Int32>( aLogicRect.GetWidth() * fXScale ), static_cast<sal_Int32>( aLogicRect.GetHeight() * fYScale ) ) );
-
- // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
- double fTextFrameScaleX = 0.0;
- double fTextFrameScaleY = 0.0;
- if (aPolyBoundRect.GetWidth())
- fTextFrameScaleX = double(21600) / static_cast<double>(aPolyBoundRect.GetWidth());
- if (aPolyBoundRect.GetHeight())
- fTextFrameScaleY = double(21600) / static_cast<double>(aPolyBoundRect.GetHeight());
-
- sal_Int32 nLeft = static_cast<sal_Int32>(( aPolyPieRect.Left() - aPolyBoundRect.Left() ) * fTextFrameScaleX );
- sal_Int32 nTop = static_cast<sal_Int32>(( aPolyPieRect.Top() - aPolyBoundRect.Top() ) * fTextFrameScaleY );
- sal_Int32 nRight = static_cast<sal_Int32>(( aPolyPieRect.Right() - aPolyBoundRect.Left() ) * fTextFrameScaleX );
- sal_Int32 nBottom= static_cast<sal_Int32>(( aPolyPieRect.Bottom()- aPolyBoundRect.Top() ) * fTextFrameScaleY );
- css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
- EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.First, nLeft );
- EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.Second, nTop );
- EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.First, nRight );
- EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.Second,nBottom );
- PropertyValue aProp;
- aProp.Name = sTextFrames;
- aProp.Value <<= aTextFrame;
- aGeometryItem.SetPropertyValue( sPath, aProp );
-
- // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
- if ( mnFix16Angle )
- {
- sal_Int32 nAngle = mnFix16Angle;
- if ( nSpFlags & ShapeFlag::FlipH )
- nAngle = 36000 - nAngle;
- if ( nSpFlags & ShapeFlag::FlipV )
- nAngle = -nAngle;
- double a = nAngle * F_PI18000;
- double ss = sin( a );
- double cc = cos( a );
- Point aP1( aOldBoundRect.TopLeft() );
- Point aC1( aObjData.aBoundRect.Center() );
- Point aP2( aOldBoundRect.TopLeft() );
- Point aC2( aOldBoundRect.Center() );
- RotatePoint( aP1, aC1, ss, cc );
- RotatePoint( aP2, aC2, ss, cc );
- aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
+ fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale;
+ fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale;
}
+ aObjData.aBoundRect = tools::Rectangle(
+ Point(aOldBoundRect.Left() + static_cast<sal_Int32>(fLogicXOfs),
+ aOldBoundRect.Top() + static_cast<sal_Int32>(fLogicYOfs)),
+ Size(static_cast<sal_Int32>(fLogicEllipseWidth),
+ static_cast<sal_Int32>(fLogicEllipseHeight)));
+ }
+ // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox.
+
+ // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
+ double fTextFrameScaleX = 0.0;
+ double fTextFrameScaleY = 0.0;
+ if (aEllipseRect_MS.getWidth())
+ fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth();
+ if (aEllipseRect_MS.getHeight())
+ fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight();
+
+ sal_Int32 nLeft = static_cast<sal_Int32>((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
+ sal_Int32 nTop = static_cast<sal_Int32>((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
+ sal_Int32 nRight = static_cast<sal_Int32>((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
+ sal_Int32 nBottom= static_cast<sal_Int32>((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.First, nLeft );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.Second, nTop );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.First, nRight );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.Second,nBottom );
+ PropertyValue aProp;
+ aProp.Name = sTextFrames;
+ aProp.Value <<= aTextFrame;
+ aGeometryItem.SetPropertyValue( sPath, aProp );
+
+ // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
+ if ( mnFix16Angle )
+ {
+ sal_Int32 nAngle = mnFix16Angle;
+ if ( nSpFlags & ShapeFlag::FlipH )
+ nAngle = 36000 - nAngle;
+ if ( nSpFlags & ShapeFlag::FlipV )
+ nAngle = -nAngle;
+ double a = nAngle * F_PI18000;
+ double ss = sin( a );
+ double cc = cos( a );
+ Point aP1( aOldBoundRect.TopLeft() );
+ Point aC1( aObjData.aBoundRect.Center() );
+ Point aP2( aOldBoundRect.TopLeft() );
+ Point aC2( aOldBoundRect.Center() );
+ RotatePoint( aP1, aC1, ss, cc );
+ RotatePoint( aP2, aC2, ss, cc );
+ aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
}
+
+ // clearing items, so MergeDefaultAttributes will set the corresponding
+ // defaults from EnhancedCustomShapeGeometry
+ aGeometryItem.ClearPropertyValue( sHandles );
+ aGeometryItem.ClearPropertyValue( sEquations );
+ aGeometryItem.ClearPropertyValue( sPath );
+
static_cast<SdrObjCustomShape*>(pRet)->SetMergedItem( aGeometryItem );
static_cast<SdrObjCustomShape*>(pRet)->MergeDefaultAttributes();
@@ -4708,7 +4721,6 @@ SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& r
SdrCustomShapeGeometryItem aGeoName( static_cast<SdrObjCustomShape*>(pRet)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
const OUString sType( "Type" );
const OUString sName( "mso-spt100" );
- PropertyValue aPropVal;
aPropVal.Name = sType;
aPropVal.Value <<= sName;
aGeoName.SetPropertyValue( aPropVal );
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
index e2444b50f967..228ab7b3687b 100644
--- a/svx/qa/unit/customshapes.cxx
+++ b/svx/qa/unit/customshapes.cxx
@@ -276,6 +276,25 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124212_handle_position)
sal_Int32 nObservedX(aObservedPosition.X()); // tools::Point
CPPUNIT_ASSERT_EQUAL_MESSAGE("handle X coordinate", nDesiredX, nObservedX);
}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124029_arc_position)
+{
+ // tdf121029 MS binary custom shape mso_sptArc has wrong position
+ // MS uses the sector for position reference. Error was, that
+ // LibreOffice has used the underlaying ellipse.
+ const OUString sFileName("tdf124029_Arc_position.doc");
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName;
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument");
+ CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is());
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The visual wrong position is due to a wrong shape width.
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aFrameRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("shape width", static_cast<sal_uInt32>(1610),
+ static_cast<sal_uInt32>(aFrameRect.Width));
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/data/tdf124029_Arc_position.doc b/svx/qa/unit/data/tdf124029_Arc_position.doc
new file mode 100644
index 000000000000..d5396c375b75
--- /dev/null
+++ b/svx/qa/unit/data/tdf124029_Arc_position.doc
Binary files differ