diff options
-rw-r--r-- | include/oox/export/drawingml.hxx | 1 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 27 | ||||
-rw-r--r-- | oox/source/export/shapes.cxx | 211 | ||||
-rwxr-xr-x | sd/qa/unit/data/odp/preset-shapes-export.odp | bin | 0 -> 21208 bytes | |||
-rw-r--r-- | sd/qa/unit/export-tests-ooxml2.cxx | 81 |
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 Binary files differnew file mode 100755 index 000000000000..30668535be70 --- /dev/null +++ b/sd/qa/unit/data/odp/preset-shapes-export.odp 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 |