summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2019-03-27 14:24:49 +0100
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2019-04-01 11:51:45 +0200
commit5c725eb7dee248c6d1792a9b9b9a9c813ca627e6 (patch)
tree9691ff1b3f97f3230e7442b5efba50200920e2df
parenttdf#42949 Fix IWYU warnings in include/sfx2/[sS]* (diff)
downloadcore-5c725eb7dee248c6d1792a9b9b9a9c813ca627e6.tar.gz
core-5c725eb7dee248c6d1792a9b9b9a9c813ca627e6.zip
tdf#124029 Force correct import pos&size of mso_sptArc shape
mso_sptArc uses the current pos&size of the sector as frame rectangle LO has used the underlaying ellipse. That has resulted in wrong shape position and text wrap problems in Writer. The patch sets the viewBox to the current pos&size of the sector and thus force the frame rectangle to the same values in LO as in MS Office. For details see bug report. Change-Id: I039c27f57966bad25e9f2123f50728e6a15f2f7e Reviewed-on: https://gerrit.libreoffice.org/69829 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-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