summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/oox/export/drawingml.hxx1
-rw-r--r--oox/source/export/drawingml.cxx27
-rw-r--r--oox/source/export/shapes.cxx211
-rwxr-xr-xsd/qa/unit/data/odp/preset-shapes-export.odpbin0 -> 21208 bytes
-rw-r--r--sd/qa/unit/export-tests-ooxml2.cxx81
5 files changed, 319 insertions, 1 deletions
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 10b5e953df63..a880cd23d6c3 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -201,6 +201,7 @@ public:
void WriteRun( const css::uno::Reference< css::text::XTextRange >& rRun );
void WriteRunProperties( const css::uno::Reference< css::beans::XPropertySet >& rRun, bool bIsField, sal_Int32 nElement = XML_rPr ,bool bCheckDirect = true);
+ void WritePresetShape( const char* pShape , std::vector< std::pair<sal_Int32,sal_Int32>> & rAvList );
void WritePresetShape( const char* pShape );
void WritePresetShape( const char* pShape, MSO_SPT eShapeType, bool bPredefinedHandlesUsed, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, const css::beans::PropertyValue& rProp );
void WriteCustomGeometry( const css::uno::Reference<css::drawing::XShape>& rXShape );
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 5f66ab5c2874..b93962ec2e63 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -2189,6 +2189,33 @@ void DrawingML::WriteText( const Reference< XInterface >& rXIface, const OUStrin
}
+void DrawingML::WritePresetShape( const char* pShape , std::vector< std::pair<sal_Int32,sal_Int32>> & rAvList )
+{
+ mpFS->startElementNS( XML_a, XML_prstGeom,
+ XML_prst, pShape,
+ FSEND );
+ if ( !rAvList.empty() )
+ {
+
+ mpFS->startElementNS( XML_a, XML_avLst, FSEND );
+ for(auto iter = rAvList.begin() ; iter != rAvList.end() ; ++iter)
+ {
+ OString sName = OString("adj") + ( ( iter->first > 0 ) ? OString::number(iter->first) : OString("") );
+ OString sFmla = OString("val ") + OString::number( iter->second );
+
+ mpFS->singleElementNS( XML_a, XML_gd,
+ XML_name, sName.getStr(),
+ XML_fmla, sFmla.getStr(),
+ FSEND );
+ }
+ mpFS->endElementNS( XML_a, XML_avLst );
+ }
+ else
+ mpFS->singleElementNS( XML_a, XML_avLst, FSEND );
+
+ mpFS->endElementNS( XML_a, XML_prstGeom );
+}
+
void DrawingML::WritePresetShape( const char* pShape )
{
mpFS->startElementNS( XML_a, XML_prstGeom,
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index 8d63d2cdfb06..d61635991cd6 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -52,6 +52,8 @@
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/embed/XEmbedPersist.hpp>
@@ -550,6 +552,9 @@ static bool lcl_IsOnBlacklist(OUString& rShapeType)
OUStringLiteral("col-60da8460"),
OUStringLiteral("col-502ad400"),
OUStringLiteral("quad-bevel"),
+ OUStringLiteral("round-rectangular-callout"),
+ OUStringLiteral("rectangular-callout"),
+ OUStringLiteral("round-callout"),
OUStringLiteral("cloud-callout"),
OUStringLiteral("line-callout-1"),
OUStringLiteral("line-callout-2"),
@@ -607,6 +612,83 @@ static bool lcl_IsOnWhitelist(OUString& rShapeType)
return std::find(vWhitelist.begin(), vWhitelist.end(), rShapeType) != vWhitelist.end();
}
+bool lcl_GetHandlePosition( sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
+{
+ bool bAdj = false;
+ if ( rParam.Value.getValueTypeClass() == TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ if ( rParam.Value >>= fValue )
+ nValue = (sal_Int32)fValue;
+ }
+ else
+ rParam.Value >>= nValue;
+
+ if ( rParam.Type == EnhancedCustomShapeParameterType::ADJUSTMENT)
+ {
+ bAdj = true;
+ sal_Int32 nIdx = nValue;
+ if ( nIdx < rSeq.getLength() )
+ {
+ if ( rSeq[ nIdx ] .Value.getValueTypeClass() == TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ rSeq[ nIdx ].Value >>= fValue;
+ nValue = fValue;
+
+ }
+ else
+ {
+ rSeq[ nIdx ].Value >>= nValue;
+ }
+ }
+ }
+ return bAdj;
+}
+
+void lcl_AnalyzeHandles( const uno::Sequence<beans::PropertyValues> & rHandles,
+ std::vector< std::pair< sal_Int32, sal_Int32> > &rHandlePositionList,
+ Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
+{
+ sal_uInt16 k, j;
+ sal_uInt16 nHandles = rHandles.getLength();
+ for ( k = 0; k < nHandles ; k++ )
+ {
+ const OUString sSwitched( "Switched" );
+ const OUString sPosition( "Position" );
+ sal_Int32 nXPosition = 0;
+ sal_Int32 nYPosition = 0;
+ bool bSwitched = false;
+ bool bPosition = false;
+ EnhancedCustomShapeParameterPair aPosition;
+ EnhancedCustomShapeParameterPair aPolar;
+ const Sequence< PropertyValue >& rPropSeq = rHandles[ k ];
+ for ( j = 0; j < rPropSeq.getLength(); j++ )
+ {
+ const PropertyValue& rPropVal = rPropSeq[ j ];
+ if ( rPropVal.Name.equals( sPosition ) )
+ {
+ if ( rPropVal.Value >>= aPosition )
+ bPosition = true;
+ }
+ else if ( rPropVal.Name.equals( sSwitched ) )
+ {
+ rPropVal.Value >>= bSwitched ;
+ }
+ }
+ if ( bPosition )
+ {
+ lcl_GetHandlePosition( nXPosition, aPosition.First , rSeq );
+ lcl_GetHandlePosition( nYPosition, aPosition.Second, rSeq );
+ rHandlePositionList.push_back( std::pair<sal_Int32, sal_Int32> ( nXPosition, nYPosition ) );
+ }
+ }
+}
+
+void lcl_AppendAdjustmentValue( std::vector< std::pair< sal_Int32, sal_Int32> > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue )
+{
+ rAvList.push_back( std::pair<sal_Int32, sal_Int32> ( nAdjIdx , nValue ) );
+}
ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
{
@@ -615,6 +697,7 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
bool bPredefinedHandlesUsed = true;
bool bHasHandles = false;
+
OUString sShapeType;
sal_uInt32 nMirrorFlags = 0;
MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType );
@@ -624,6 +707,8 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
SAL_INFO("oox.shape", "custom shape type: " << sShapeType << " ==> " << sPresetShape);
Sequence< PropertyValue > aGeometrySeq;
sal_Int32 nAdjustmentValuesIndex = -1;
+ awt::Rectangle aViewBox;
+ uno::Sequence<beans::PropertyValues> aHandles;
bool bFlipH = false;
bool bFlipV = false;
@@ -646,7 +731,6 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
nAdjustmentValuesIndex = i;
else if ( rProp.Name == "Handles" )
{
- uno::Sequence<beans::PropertyValues> aHandles;
rProp.Value >>= aHandles;
if ( aHandles.getLength() )
bHasHandles = true;
@@ -658,6 +742,8 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
{
rProp.Value >>= m_presetWarp;
}
+ else if ( rProp.Name == "ViewBox" )
+ rProp.Value >>= aViewBox;
}
}
}
@@ -716,6 +802,7 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
// but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a blacklist
// we use a whitelist for shapes where mapping to MSO preset shape is not optimal
bool bCustGeom = true;
+ bool bOnBlacklist = false;
if( sShapeType == "ooxml-non-primitive" )
bCustGeom = true;
else if( sShapeType.startsWith("ooxml") )
@@ -723,7 +810,10 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
else if( lcl_IsOnWhitelist(sShapeType) )
bCustGeom = true;
else if( lcl_IsOnBlacklist(sShapeType) )
+ {
bCustGeom = false;
+ bOnBlacklist = true;
+ }
else if( bHasHandles )
bCustGeom = true;
@@ -746,6 +836,125 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
WriteCustomGeometry( xShape );
}
+ else if (bOnBlacklist && bHasHandles && nAdjustmentValuesIndex !=-1 && !sShapeType.startsWith("mso-spt"))
+ {
+ WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
+ Sequence< EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq;
+ std::vector< std::pair< sal_Int32, sal_Int32> > aHandlePositionList;
+ std::vector< std::pair< sal_Int32, sal_Int32> > aAvList;
+ aGeometrySeq[ nAdjustmentValuesIndex ].Value >>= aAdjustmentSeq ;
+
+ lcl_AnalyzeHandles( aHandles, aHandlePositionList, aAdjustmentSeq );
+
+ sal_Int32 nXPosition = 0;
+ sal_Int32 nYPosition = 0;
+ if ( !aHandlePositionList.empty() )
+ {
+ nXPosition = aHandlePositionList[0].first ;
+ nYPosition = aHandlePositionList[0].second ;
+ }
+ switch( eShapeType )
+ {
+ case mso_sptBorderCallout1:
+ {
+ sal_Int32 adj3 = double(nYPosition)/aViewBox.Height *100000;
+ sal_Int32 adj4 = double(nXPosition)/aViewBox.Width *100000;
+ lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
+ lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
+ lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
+ lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
+ break;
+ }
+ case mso_sptBorderCallout2:
+ {
+ sal_Int32 adj5 = double(nYPosition)/aViewBox.Height *100000;
+ sal_Int32 adj6 = double(nXPosition)/aViewBox.Width *100000;
+ sal_Int32 adj3 = 18750;
+ sal_Int32 adj4 = -16667;
+ lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
+ lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
+ if ( aHandlePositionList.size() > 1 )
+ {
+ nXPosition = aHandlePositionList[1].first ;
+ nYPosition = aHandlePositionList[1].second ;
+ adj3 = double(nYPosition)/aViewBox.Height *100000;
+ adj4 = double(nXPosition)/aViewBox.Width *100000;
+ }
+ lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
+ lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
+ lcl_AppendAdjustmentValue( aAvList, 5, adj5 );
+ lcl_AppendAdjustmentValue( aAvList, 6, adj6 );
+ break;
+ }
+ case mso_sptWedgeRectCallout:
+ case mso_sptWedgeRRectCallout:
+ case mso_sptWedgeEllipseCallout:
+ case mso_sptCloudCallout:
+ {
+ sal_Int32 adj1 = (double(nXPosition)/aViewBox.Width -0.5) *100000;
+ sal_Int32 adj2 = (double(nYPosition)/aViewBox.Height -0.5) *100000;
+ lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
+ lcl_AppendAdjustmentValue( aAvList, 2, adj2 );
+ if ( eShapeType == mso_sptWedgeRRectCallout)
+ {
+ lcl_AppendAdjustmentValue( aAvList, 3, 16667);
+ }
+
+ break;
+ }
+ case mso_sptFoldedCorner:
+ {
+ sal_Int32 adj = double( aViewBox.Width - nXPosition) / std::min( aViewBox.Width,aViewBox.Height ) * 100000;
+ lcl_AppendAdjustmentValue( aAvList, 0, adj );
+ break;
+ }
+ case mso_sptNoSmoking:
+ {
+ sal_Int32 adj = double( nXPosition )/7200 *50000 ;
+ lcl_AppendAdjustmentValue( aAvList, 0, adj );
+ break;
+ }
+ case mso_sptDonut:
+ case mso_sptSun:
+ case mso_sptMoon:
+ case mso_sptHorizontalScroll:
+ case mso_sptBevel:
+ case mso_sptBracketPair:
+ {
+ sal_Int32 adj = double( nXPosition )/aViewBox.Width*100000 ;
+ lcl_AppendAdjustmentValue( aAvList, 0, adj );
+ break;
+ }
+ case mso_sptCan:
+ case mso_sptCube:
+ case mso_sptBracePair:
+ case mso_sptVerticalScroll:
+ {
+ sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 ;
+ lcl_AppendAdjustmentValue( aAvList, 0, adj );
+ break;
+ }
+ case mso_sptSmileyFace:
+ {
+ sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 - 76458.0;
+ lcl_AppendAdjustmentValue( aAvList, 0, adj );
+ break;
+ }
+ // case mso_sptNil:
+ // case mso_sptBentConnector3:
+ // case mso_sptBorderCallout3:
+ default:
+ {
+ if (!strcmp( sPresetShape, "frame" ))
+ {
+ sal_Int32 adj1 = double( nYPosition )/aViewBox.Height *100000 ;
+ lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
+ }
+ break;
+ }
+ }
+ WritePresetShape( sPresetShape , aAvList );
+ }
else // preset geometry
{
WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
diff --git a/sd/qa/unit/data/odp/preset-shapes-export.odp b/sd/qa/unit/data/odp/preset-shapes-export.odp
new file mode 100755
index 000000000000..30668535be70
--- /dev/null
+++ b/sd/qa/unit/data/odp/preset-shapes-export.odp
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index 78050171a8fd..fdf5d0453460 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -90,6 +90,7 @@ public:
void testMathObjectPPT2010();
void testTdf80224();
void testExportTransitionsPPTX();
+ void testPresetShapesExport();
void testTdf92527();
void testDatetimeFieldNumberFormat();
void testDatetimeFieldNumberFormatPPTX();
@@ -113,6 +114,7 @@ public:
CPPUNIT_TEST(testMathObjectPPT2010);
CPPUNIT_TEST(testTdf80224);
CPPUNIT_TEST(testExportTransitionsPPTX);
+ CPPUNIT_TEST(testPresetShapesExport);
CPPUNIT_TEST(testTdf92527);
CPPUNIT_TEST(testDatetimeFieldNumberFormat);
CPPUNIT_TEST(testDatetimeFieldNumberFormatPPTX);
@@ -438,6 +440,85 @@ void SdOOXMLExportTest2::testExportTransitionsPPTX()
xDocShRef->DoClose();
}
+void SdOOXMLExportTest2::testPresetShapesExport()
+{
+ ::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/odp/preset-shapes-export.odp"), ODP);
+ const sal_Char *sShapeTypeAndValues[] =
+ {
+ "wedgeEllipseCallout",
+ "adj1","val 45310",
+ "adj2","val 97194",
+ "wedgeRoundRectCallout",
+ "adj1","val 46694",
+ "adj2","val 129726",
+ "adj3","val 16667",
+ "wedgeRectCallout",
+ "adj1","val 40037",
+ "adj2","val 111694",
+ "smileyFace",
+ "adj","val -9282",
+ "can",
+ "adj","val 50000",
+ "frame",
+ "adj1","val 10490",
+ "donut",
+ "adj","val 9601",
+ "noSmoking",
+ "adj","val 16118",
+ "bevel",
+ "adj","val 42587",
+ "foldedCorner",
+ "adj","val 10750",
+ "verticalScroll",
+ "adj","val 25000",
+ "horizontalScroll",
+ "adj","val 25000",
+ "cube",
+ "adj","val 85129",
+ "bracketPair",
+ "adj","val 50000",
+ "sun",
+ "adj","val 12500",
+ "bracePair",
+ "adj","val 25000",
+ "cloudCallout",
+ "adj1","val 77611",
+ "adj2","val -47819",
+ "borderCallout1",
+ "adj1","val 18750",
+ "adj2","val -8333",
+ "adj3","val 170013",
+ "adj4","val 143972",
+ "borderCallout2",
+ "adj1","val 18750",
+ "adj2","val -8333",
+ "adj3","val 113768",
+ "adj4","val -81930",
+ "adj5","val -22375",
+ "adj6","val -134550",
+ };
+
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload( xDocShRef, PPTX, &tempFile );
+
+ xmlDocPtr pXmlDocCT = parseExport(tempFile, "ppt/slides/slide1.xml");
+ const OString sPattern( "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:prstGeom[@prst='_T_']/a:avLst/a:gd[_N_]" );
+ const OString sT( "_T_" );
+ const OString sN( "_N_" );
+ const OString sPropertyName("name");
+ const OString sPropertyFmla("fmla");
+
+ size_t i = 0;
+ while(i < SAL_N_ELEMENTS( sShapeTypeAndValues )) {
+ OString sType = OString( sShapeTypeAndValues[ i++ ] );
+ for ( size_t j = 1 ; i < SAL_N_ELEMENTS( sShapeTypeAndValues ) && OString(sShapeTypeAndValues[i]).startsWith("adj") ; ++j ) {
+ OString sXPath= sPattern.replaceFirst( sT, sType).replaceFirst( sN, OString::number(j) );
+ assertXPath(pXmlDocCT, sXPath, sPropertyName , OUString::createFromAscii(sShapeTypeAndValues[ i++ ]) );
+ assertXPath(pXmlDocCT, sXPath, sPropertyFmla , OUString::createFromAscii(sShapeTypeAndValues[ i++ ]) );
+ }
+ }
+}
+
void SdOOXMLExportTest2::testTdf92527()
{
// We draw a diamond in an empty document. A newly created diamond shape does not have