summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorMark Hung <marklh9@gmail.com>2016-06-12 20:03:01 +0800
committerMark Hung <marklh9@gmail.com>2016-08-11 12:37:22 +0000
commit2b4f9d0b2b0006fc7bebb9e696a32eabd1aeb993 (patch)
treefb523219ec177c003caef31ffb5e71df922daa2f /oox
parentc878bfc8c90372217bfa41818825f4e047b794d8 (diff)
Convert handles of built-in shapes in Impress when exporting to PPTX.
For those shapes exported as OOXML preset shapes, their AdjustmentValues property was exported as the list of adjustment values ( avLst ) in the exported PPTX file. This works for shapes imported from PPTX, whose AdjustmentValues is exactly the same as avLst of the original PPTX file. For built-in shapes in Impress, avLst and AdjustmentValues would not be the same because the path and the equation created by LibreOffice and OOXML are not the same. This patch convert position of handles to adjustment values according to the shape type case by case. It also adds default values if the built-in shape in Impress has fewer handles then the exported preset shape because Powerpoint seems to be very strict about the number of values in avLst, and deemed the file as corrupted if any of defined adjustment values is missing. Round-rectangular-callouts, rectangular-callout, and round-callouts are added to the blacklist so that they are exported as preset shapes. Change-Id: Icd1284790607e927b6a9a614ac463a96cadedd81 Reviewed-on: https://gerrit.libreoffice.org/26479 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Mark Hung <marklh9@gmail.com>
Diffstat (limited to 'oox')
-rw-r--r--oox/source/export/drawingml.cxx27
-rw-r--r--oox/source/export/shapes.cxx211
2 files changed, 237 insertions, 1 deletions
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 );