Kaydet (Commit) 1b7773cb authored tarafından Jacobo Aragunde Pérez's avatar Jacobo Aragunde Pérez

oox: preserve scene3d/camera effects on shapes.

Shapes can contain 3D effects like in the following example:

  <a:scene3d>
    <a:camera prst="isometricLeftDown" zoom="150000"/>
    <a:lightRig rig="threePt" dir="t"/>
  </a:scene3d>

This patch preserves the a:camera tag and its attributes using the
shape grab bag. It also adds a unit test for this case.

Change-Id: Ic6a78031d2e1fb84a2bacd97b5cc9c55d9dbaa95
üst 8d2a5c16
...@@ -46,6 +46,10 @@ struct Shape3DProperties ...@@ -46,6 +46,10 @@ struct Shape3DProperties
/** Overwrites all members that are explicitly set in rSourceProps. */ /** Overwrites all members that are explicitly set in rSourceProps. */
void assignUsed( const Shape3DProperties& rSourceProps ); void assignUsed( const Shape3DProperties& rSourceProps );
OUString getCameraPrstName( sal_Int32 nElement );
css::uno::Sequence< css::beans::PropertyValue > getCameraAttributes();
}; };
......
...@@ -174,6 +174,7 @@ public: ...@@ -174,6 +174,7 @@ public:
void WriteFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPropSet ); void WriteFill( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPropSet );
void WriteShapeStyle( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet ); void WriteShapeStyle( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
void WriteShapeEffects( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet ); void WriteShapeEffects( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
void WriteShape3DEffects( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rXPropSet );
static void ResetCounters(); static void ResetCounters();
......
...@@ -46,9 +46,12 @@ ContextHandlerRef Scene3DPropertiesContext::onCreateContext( sal_Int32 aElementT ...@@ -46,9 +46,12 @@ ContextHandlerRef Scene3DPropertiesContext::onCreateContext( sal_Int32 aElementT
switch( aElementToken ) switch( aElementToken )
{ {
case A_TOKEN( camera ): case A_TOKEN( camera ):
mr3DProperties.mfFieldOfVision = rAttribs.getInteger( XML_fov, 0 ) / 60000.0; // 60000ths of degree if( rAttribs.hasAttribute( XML_fov ) )
mr3DProperties.mfZoom = rAttribs.getInteger( XML_zoom, 100000 ) / 100000.0; mr3DProperties.mfFieldOfVision = rAttribs.getInteger( XML_fov, 0 ) / 60000.0; // 60000ths of degree
mr3DProperties.mnPreset = rAttribs.getToken( XML_prst, XML_none ); if( rAttribs.hasAttribute( XML_zoom ) )
mr3DProperties.mfZoom = rAttribs.getInteger( XML_zoom, 100000 ) / 100000.0;
if( rAttribs.hasAttribute( XML_prst ) )
mr3DProperties.mnPreset = rAttribs.getToken( XML_prst, XML_none );
// TODO: nested element XML_rot // TODO: nested element XML_rot
break; break;
case A_TOKEN( lightRig ): case A_TOKEN( lightRig ):
......
...@@ -924,6 +924,11 @@ Reference< XShape > Shape::createAndInsert( ...@@ -924,6 +924,11 @@ Reference< XShape > Shape::createAndInsert(
putPropertyToGrabBag( "EffectProperties", Any( aEffectsGrabBag ) ); putPropertyToGrabBag( "EffectProperties", Any( aEffectsGrabBag ) );
} }
// add 3D effects if any
Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
if( aCamera3DEffects.getLength() > 0 )
putPropertyToGrabBag( "3DEffectProperties", Any( aCamera3DEffects ) );
} }
// These can have a custom geometry, so position should be set here, // These can have a custom geometry, so position should be set here,
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <com/sun/star/graphic/XGraphicTransformer.hpp> #include <com/sun/star/graphic/XGraphicTransformer.hpp>
#include "oox/helper/propertymap.hxx" #include "oox/helper/propertymap.hxx"
#include "oox/helper/propertyset.hxx" #include "oox/helper/propertyset.hxx"
#include "oox/token/tokens.hxx"
using namespace ::com::sun::star; using namespace ::com::sun::star;
using namespace ::com::sun::star::drawing; using namespace ::com::sun::star::drawing;
...@@ -46,6 +47,102 @@ namespace oox { ...@@ -46,6 +47,102 @@ namespace oox {
namespace drawingml { namespace drawingml {
OUString Shape3DProperties::getCameraPrstName( sal_Int32 nElement )
{
switch( nElement )
{
case XML_legacyObliqueTopLeft: return OUString( "legacyObliqueTopLeft" );
case XML_legacyObliqueTop: return OUString( "legacyObliqueTop" );
case XML_legacyObliqueTopRight: return OUString( "legacyObliqueTopRight" );
case XML_legacyObliqueLeft: return OUString( "legacyObliqueLeft" );
case XML_legacyObliqueFront: return OUString( "legacyObliqueFront" );
case XML_legacyObliqueRight: return OUString( "legacyObliqueRight" );
case XML_legacyObliqueBottomLeft: return OUString( "legacyObliqueBottomLeft" );
case XML_legacyObliqueBottom: return OUString( "legacyObliqueBottom" );
case XML_legacyObliqueBottomRight: return OUString( "legacyObliqueBottomRight" );
case XML_legacyPerspectiveTopLeft: return OUString( "legacyPerspectiveTopLeft" );
case XML_legacyPerspectiveTop: return OUString( "legacyPerspectiveTop" );
case XML_legacyPerspectiveTopRight: return OUString( "legacyPerspectiveTopRight" );
case XML_legacyPerspectiveLeft: return OUString( "legacyPerspectiveLeft" );
case XML_legacyPerspectiveFront: return OUString( "legacyPerspectiveFront" );
case XML_legacyPerspectiveRight: return OUString( "legacyPerspectiveRight" );
case XML_legacyPerspectiveBottomLeft: return OUString( "legacyPerspectiveBottomLeft" );
case XML_legacyPerspectiveBottom: return OUString( "legacyPerspectiveBottom" );
case XML_legacyPerspectiveBottomRight: return OUString( "legacyPerspectiveBottomRight" );
case XML_orthographicFront: return OUString( "orthographicFront" );
case XML_isometricTopUp: return OUString( "isometricTopUp" );
case XML_isometricTopDown: return OUString( "isometricTopDown" );
case XML_isometricBottomUp: return OUString( "isometricBottomUp" );
case XML_isometricBottomDown: return OUString( "isometricBottomDown" );
case XML_isometricLeftUp: return OUString( "isometricLeftUp" );
case XML_isometricLeftDown: return OUString( "isometricLeftDown" );
case XML_isometricRightUp: return OUString( "isometricRightUp" );
case XML_isometricRightDown: return OUString( "isometricRightDown" );
case XML_isometricOffAxis1Left: return OUString( "isometricOffAxis1Left" );
case XML_isometricOffAxis1Right: return OUString( "isometricOffAxis1Right" );
case XML_isometricOffAxis1Top: return OUString( "isometricOffAxis1Top" );
case XML_isometricOffAxis2Left: return OUString( "isometricOffAxis2Left" );
case XML_isometricOffAxis2Right: return OUString( "isometricOffAxis2Right" );
case XML_isometricOffAxis2Top: return OUString( "isometricOffAxis2Top" );
case XML_isometricOffAxis3Left: return OUString( "isometricOffAxis3Left" );
case XML_isometricOffAxis3Right: return OUString( "isometricOffAxis3Right" );
case XML_isometricOffAxis3Bottom: return OUString( "isometricOffAxis3Bottom" );
case XML_isometricOffAxis4Left: return OUString( "isometricOffAxis4Left" );
case XML_isometricOffAxis4Right: return OUString( "isometricOffAxis4Right" );
case XML_isometricOffAxis4Bottom: return OUString( "isometricOffAxis4Bottom" );
case XML_obliqueTopLeft: return OUString( "obliqueTopLeft" );
case XML_obliqueTop: return OUString( "obliqueTop" );
case XML_obliqueTopRight: return OUString( "obliqueTopRight" );
case XML_obliqueLeft: return OUString( "obliqueLeft" );
case XML_obliqueRight: return OUString( "obliqueRight" );
case XML_obliqueBottomLeft: return OUString( "obliqueBottomLeft" );
case XML_obliqueBottom: return OUString( "obliqueBottom" );
case XML_obliqueBottomRight: return OUString( "obliqueBottomRight" );
case XML_perspectiveFront: return OUString( "perspectiveFront" );
case XML_perspectiveLeft: return OUString( "perspectiveLeft" );
case XML_perspectiveRight: return OUString( "perspectiveRight" );
case XML_perspectiveAbove: return OUString( "perspectiveAbove" );
case XML_perspectiveBelow: return OUString( "perspectiveBelow" );
case XML_perspectiveAboveLeftFacing: return OUString( "perspectiveAboveLeftFacing" );
case XML_perspectiveAboveRightFacing: return OUString( "perspectiveAboveRightFacing" );
case XML_perspectiveContrastingLeftFacing: return OUString( "perspectiveContrastingLeftFacing" );
case XML_perspectiveContrastingRightFacing: return OUString( "perspectiveContrastingRightFacing" );
case XML_perspectiveHeroicLeftFacing: return OUString( "perspectiveHeroicLeftFacing" );
case XML_perspectiveHeroicRightFacing: return OUString( "perspectiveHeroicRightFacing" );
case XML_perspectiveHeroicExtremeLeftFacing: return OUString( "perspectiveHeroicExtremeLeftFacing" );
case XML_perspectiveHeroicExtremeRightFacing: return OUString( "perspectiveHeroicExtremeRightFacing" );
case XML_perspectiveRelaxed: return OUString( "perspectiveRelaxed" );
case XML_perspectiveRelaxedModerately: return OUString( "perspectiveRelaxedModerately" );
}
SAL_WARN( "oox.drawingml", "Shape3DProperties::getCameraPrstName - unexpected prst type" );
return OUString();
}
css::uno::Sequence< css::beans::PropertyValue > Shape3DProperties::getCameraAttributes()
{
css::uno::Sequence<css::beans::PropertyValue> aSeq(3);
sal_Int32 nSize = 0;
if( mfFieldOfVision.has() )
{
aSeq[nSize].Name = "fov";
aSeq[nSize].Value = css::uno::Any( mfFieldOfVision.use() );
nSize++;
}
if( mfZoom.has() )
{
aSeq[nSize].Name = "zoom";
aSeq[nSize].Value = css::uno::Any( mfZoom.use() );
nSize++;
}
if( mnPreset.has() )
{
aSeq[nSize].Name = "prst";
aSeq[nSize].Value = css::uno::Any( getCameraPrstName( mnPreset.use() ) );
nSize++;
}
aSeq.realloc( nSize );
return aSeq;
}
......
...@@ -94,7 +94,7 @@ ContextHandlerRef ShapePropertiesContext::onCreateContext( sal_Int32 aElementTok ...@@ -94,7 +94,7 @@ ContextHandlerRef ShapePropertiesContext::onCreateContext( sal_Int32 aElementTok
case A_TOKEN( effectDag ): // CT_EffectContainer case A_TOKEN( effectDag ): // CT_EffectContainer
return new EffectPropertiesContext( *this, mrShape.getEffectProperties() ); return new EffectPropertiesContext( *this, mrShape.getEffectProperties() );
// todo // todo not supported by core, only for preservation via grab bags
case A_TOKEN( scene3d ): // CT_Scene3D case A_TOKEN( scene3d ): // CT_Scene3D
return new Scene3DPropertiesContext( *this, mrShape.get3DProperties() ); return new Scene3DPropertiesContext( *this, mrShape.get3DProperties() );
break; break;
......
...@@ -2270,6 +2270,59 @@ void DrawingML::WriteShapeEffects( Reference< XPropertySet > rXPropSet ) ...@@ -2270,6 +2270,59 @@ void DrawingML::WriteShapeEffects( Reference< XPropertySet > rXPropSet )
} }
} }
void DrawingML::WriteShape3DEffects( Reference< XPropertySet > xPropSet )
{
// check existence of the grab bag
if( !GetProperty( xPropSet, "InteropGrabBag" ) )
return;
// extract the relevant properties from the grab bag
Sequence< PropertyValue > aGrabBag, aEffectProps;
mAny >>= aGrabBag;
for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
if( aGrabBag[i].Name == "3DEffectProperties" )
{
aGrabBag[i].Value >>= aEffectProps;
break;
}
if( aEffectProps.getLength() == 0 )
return;
sax_fastparser::FastAttributeList *aCameraAttrList = mpFS->createAttrList();
for( sal_Int32 i=0; i < aEffectProps.getLength(); ++i )
{
if( aEffectProps[i].Name == "prst" )
{
OUString sVal;
aEffectProps[i].Value >>= sVal;
aCameraAttrList->add( XML_prst, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
}
else if( aEffectProps[i].Name == "fov" )
{
float fVal = 0;
aEffectProps[i].Value >>= fVal;
aCameraAttrList->add( XML_fov, OString::number( fVal * 60000 ).getStr() );
}
else if( aEffectProps[i].Name == "zoom" )
{
float fVal = 1;
aEffectProps[i].Value >>= fVal;
aCameraAttrList->add( XML_zoom, OString::number( fVal * 100000 ).getStr() );
}
}
mpFS->startElementNS( XML_a, XML_scene3d, FSEND );
sax_fastparser::XFastAttributeListRef xAttrList( aCameraAttrList );
mpFS->startElementNS( XML_a, XML_camera, xAttrList );
mpFS->endElementNS( XML_a, XML_camera );
// a:lightRig with Word default values - Word won't open the document if this is not present
mpFS->singleElementNS( XML_a, XML_lightRig, XML_rig, "threePt", XML_dir, "t", FSEND );
mpFS->endElementNS( XML_a, XML_scene3d );
}
} }
} }
......
...@@ -374,6 +374,7 @@ ShapeExport& ShapeExport::WriteCustomShape( Reference< XShape > xShape ) ...@@ -374,6 +374,7 @@ ShapeExport& ShapeExport::WriteCustomShape( Reference< XShape > xShape )
WriteFill( rXPropSet ); WriteFill( rXPropSet );
WriteOutline( rXPropSet ); WriteOutline( rXPropSet );
WriteShapeEffects( rXPropSet ); WriteShapeEffects( rXPropSet );
WriteShape3DEffects( rXPropSet );
} }
pFS->endElementNS( mnXmlNamespace, XML_spPr ); pFS->endElementNS( mnXmlNamespace, XML_spPr );
......
...@@ -1145,6 +1145,26 @@ DECLARE_OOXMLEXPORT_TEST(testShapeEffectPreservation, "shape-effect-preservation ...@@ -1145,6 +1145,26 @@ DECLARE_OOXMLEXPORT_TEST(testShapeEffectPreservation, "shape-effect-preservation
0 ); // should not be present 0 ); // should not be present
} }
DECLARE_OOXMLEXPORT_TEST(testShape3DEffectPreservation, "shape-3d-effect-preservation.docx")
{
xmlDocPtr pXmlDoc = parseExport("word/document.xml");
if (!pXmlDoc)
return;
// first shape
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:scene3d/a:camera",
"prst", "perspectiveRelaxedModerately");
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:scene3d/a:camera",
"zoom", "150000");
// second shape
assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:r/mc:AlternateContent/mc:Choice/w:drawing/"
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:scene3d/a:camera",
"prst", "isometricLeftDown");
}
DECLARE_OOXMLEXPORT_TEST(fdo77719, "fdo77719.docx") DECLARE_OOXMLEXPORT_TEST(fdo77719, "fdo77719.docx")
{ {
xmlDocPtr pXmlDoc = parseExport("word/document.xml"); xmlDocPtr pXmlDoc = parseExport("word/document.xml");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment