oox: preserve scene3d/lightRig 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:rot lat="0" lon="0" rev="4800000"/>
    </a:lightRig>
  </a:scene3d>

This patch preserves the a:lightRig tag, its attributes and the child
element a:rot using the shape grab bag. It also adds a unit test for
this case.

Change-Id: I66b6de3c2b5ef89223b10da54006e28113b8ba5f
This commit is contained in:
Jacobo Aragunde Pérez 2014-05-06 16:40:27 +02:00
parent 273e73c896
commit 0df9ec782e
6 changed files with 201 additions and 15 deletions

View File

@ -51,13 +51,17 @@ struct Shape3DProperties
OptValue< sal_Int32 > mnLightRigDirection;
OptValue< sal_Int32 > mnLightRigType;
RotationProperties maCameraRotation;
RotationProperties maLightRigRotation;
/** Overwrites all members that are explicitly set in rSourceProps. */
void assignUsed( const Shape3DProperties& rSourceProps );
OUString getCameraPrstName( sal_Int32 nElement );
OUString getLightRigName( sal_Int32 nElement );
OUString getLightRigDirName( sal_Int32 nElement );
css::uno::Sequence< css::beans::PropertyValue > getCameraAttributes();
css::uno::Sequence< css::beans::PropertyValue > getLightRigAttributes();
};

View File

@ -58,8 +58,9 @@ ContextHandlerRef Scene3DPropertiesContext::onCreateContext( sal_Int32 aElementT
case A_TOKEN( lightRig ):
mr3DProperties.mnLightRigDirection = rAttribs.getToken( XML_dir, XML_none );
mr3DProperties.mnLightRigType = rAttribs.getToken( XML_rig, XML_none );
// TODO: nested element XML_rot
break;
return new Scene3DRotationPropertiesContext( *this, mr3DProperties.maLightRigRotation );
case A_TOKEN( backdrop ):
case A_TOKEN( extLst ):
return 0; // TODO: later (backdrop is not supported by core anyway)

View File

@ -939,8 +939,14 @@ Reference< XShape > Shape::createAndInsert(
// add 3D effects if any
Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
if( aCamera3DEffects.getLength() > 0 )
putPropertyToGrabBag( "3DEffectProperties", Any( aCamera3DEffects ) );
Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
if( aCamera3DEffects.getLength() > 0 || aLightRig3DEffects.getLength() > 0 )
{
Sequence< PropertyValue > a3DEffectsGrabBag( 2 );
PUT_PROP( a3DEffectsGrabBag, 0, "Camera", Any( aCamera3DEffects ) );
PUT_PROP( a3DEffectsGrabBag, 1, "LightRig", Any( aLightRig3DEffects ) );
putPropertyToGrabBag( "3DEffectProperties", Any( a3DEffectsGrabBag ) );
}
}
// These can have a custom geometry, so position should be set here,

View File

@ -118,6 +118,59 @@ OUString Shape3DProperties::getCameraPrstName( sal_Int32 nElement )
return OUString();
}
OUString Shape3DProperties::getLightRigName( sal_Int32 nElement )
{
switch( nElement )
{
case XML_legacyFlat1: return OUString( "legacyFlat1" );
case XML_legacyFlat2: return OUString( "legacyFlat2" );
case XML_legacyFlat3: return OUString( "legacyFlat3" );
case XML_legacyFlat4: return OUString( "legacyFlat4" );
case XML_legacyNormal1: return OUString( "legacyNormal1" );
case XML_legacyNormal2: return OUString( "legacyNormal2" );
case XML_legacyNormal3: return OUString( "legacyNormal3" );
case XML_legacyNormal4: return OUString( "legacyNormal4" );
case XML_legacyHarsh1: return OUString( "legacyHarsh1" );
case XML_legacyHarsh2: return OUString( "legacyHarsh2" );
case XML_legacyHarsh3: return OUString( "legacyHarsh3" );
case XML_legacyHarsh4: return OUString( "legacyHarsh4" );
case XML_threePt: return OUString( "threePt" );
case XML_balanced: return OUString( "balanced" );
case XML_soft: return OUString( "soft" );
case XML_harsh: return OUString( "harsh" );
case XML_flood: return OUString( "flood" );
case XML_contrasting: return OUString( "contrasting" );
case XML_morning: return OUString( "morning" );
case XML_sunrise: return OUString( "sunrise" );
case XML_sunset: return OUString( "sunset" );
case XML_chilly: return OUString( "chilly" );
case XML_freezing: return OUString( "freezing" );
case XML_flat: return OUString( "flat" );
case XML_twoPt: return OUString( "twoPt" );
case XML_glow: return OUString( "glow" );
case XML_brightRoom: return OUString( "brightRoom" );
}
SAL_WARN( "oox.drawingml", "Shape3DProperties::getLightRigName - unexpected token" );
return OUString();
}
OUString Shape3DProperties::getLightRigDirName( sal_Int32 nElement )
{
switch( nElement )
{
case XML_tl: return OUString( "tl" );
case XML_t: return OUString( "t" );
case XML_tr: return OUString( "tr" );
case XML_l: return OUString( "l" );
case XML_r: return OUString( "r" );
case XML_bl: return OUString( "bl" );
case XML_b: return OUString( "b" );
case XML_br: return OUString( "br" );
}
SAL_WARN( "oox.drawingml", "Shape3DProperties::getLightRigDirName - unexpected token" );
return OUString();
}
css::uno::Sequence< css::beans::PropertyValue > Shape3DProperties::getCameraAttributes()
{
css::uno::Sequence<css::beans::PropertyValue> aSeq(6);
@ -162,6 +215,44 @@ css::uno::Sequence< css::beans::PropertyValue > Shape3DProperties::getCameraAttr
return aSeq;
}
css::uno::Sequence< css::beans::PropertyValue > Shape3DProperties::getLightRigAttributes()
{
css::uno::Sequence<css::beans::PropertyValue> aSeq(5);
sal_Int32 nSize = 0;
if( mnLightRigDirection.has() )
{
aSeq[nSize].Name = "dir";
aSeq[nSize].Value = css::uno::Any( getLightRigDirName( mnLightRigDirection.use() ) );
nSize++;
}
if( mnLightRigType.has() )
{
aSeq[nSize].Name = "rig";
aSeq[nSize].Value = css::uno::Any( getLightRigName( mnLightRigType.use() ) );
nSize++;
}
if( maLightRigRotation.mnLatitude.has() )
{
aSeq[nSize].Name = "rotLat";
aSeq[nSize].Value = css::uno::Any( maLightRigRotation.mnLatitude.use() );
nSize++;
}
if( maLightRigRotation.mnLongitude.has() )
{
aSeq[nSize].Name = "rotLon";
aSeq[nSize].Value = css::uno::Any( maLightRigRotation.mnLongitude.use() );
nSize++;
}
if( maLightRigRotation.mnRevolution.has() )
{
aSeq[nSize].Name = "rotRev";
aSeq[nSize].Value = css::uno::Any( maLightRigRotation.mnRevolution.use() );
nSize++;
}
aSeq.realloc( nSize );
return aSeq;
}
} // namespace drawingml

View File

@ -2277,15 +2277,23 @@ void DrawingML::WriteShape3DEffects( Reference< XPropertySet > xPropSet )
return;
// extract the relevant properties from the grab bag
Sequence< PropertyValue > aGrabBag, aEffectProps;
Sequence< PropertyValue > aGrabBag, aEffectProps, aLightRigProps;
mAny >>= aGrabBag;
for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
if( aGrabBag[i].Name == "3DEffectProperties" )
{
aGrabBag[i].Value >>= aEffectProps;
Sequence< PropertyValue > a3DEffectProps;
aGrabBag[i].Value >>= a3DEffectProps;
for( sal_Int32 j=0; j < a3DEffectProps.getLength(); ++j )
{
if( a3DEffectProps[j].Name == "Camera" )
a3DEffectProps[j].Value >>= aEffectProps;
else if( a3DEffectProps[j].Name == "LightRig" )
a3DEffectProps[j].Value >>= aLightRigProps;
}
break;
}
if( aEffectProps.getLength() == 0 )
if( aEffectProps.getLength() == 0 && aLightRigProps.getLength() == 0 )
return;
bool bCameraRotationPresent = false;
@ -2328,19 +2336,70 @@ void DrawingML::WriteShape3DEffects( Reference< XPropertySet > xPropSet )
}
}
bool bLightRigRotationPresent = false;
sax_fastparser::FastAttributeList *aLightRigAttrList = mpFS->createAttrList();
sax_fastparser::FastAttributeList *aLightRigRotationAttrList = mpFS->createAttrList();
for( sal_Int32 i=0; i < aLightRigProps.getLength(); ++i )
{
if( aLightRigProps[i].Name == "rig" || aLightRigProps[i].Name == "dir" )
{
OUString sVal;
sal_Int32 nToken = XML_none;
aLightRigProps[i].Value >>= sVal;
if( aLightRigProps[i].Name == "rig" )
nToken = XML_rig;
else if( aLightRigProps[i].Name == "dir" )
nToken = XML_dir;
aLightRigAttrList->add( nToken, OUStringToOString( sVal, RTL_TEXTENCODING_UTF8 ).getStr() );
}
else if( aLightRigProps[i].Name == "rotLat" ||
aLightRigProps[i].Name == "rotLon" ||
aLightRigProps[i].Name == "rotRev" )
{
sal_Int32 nVal = 0, nToken = XML_none;
aLightRigProps[i].Value >>= nVal;
if( aLightRigProps[i].Name == "rotLat" )
nToken = XML_lat;
else if( aLightRigProps[i].Name == "rotLon" )
nToken = XML_lon;
else if( aLightRigProps[i].Name == "rotRev" )
nToken = XML_rev;
aLightRigRotationAttrList->add( nToken, OString::number( nVal ).getStr() );
bLightRigRotationPresent = true;
}
}
mpFS->startElementNS( XML_a, XML_scene3d, FSEND );
sax_fastparser::XFastAttributeListRef xAttrList( aCameraAttrList );
mpFS->startElementNS( XML_a, XML_camera, xAttrList );
if( bCameraRotationPresent )
if( aEffectProps.getLength() > 0 )
{
sax_fastparser::XFastAttributeListRef xRotAttrList( aCameraRotationAttrList );
mpFS->singleElementNS( XML_a, XML_rot, xRotAttrList );
sax_fastparser::XFastAttributeListRef xAttrList( aCameraAttrList );
mpFS->startElementNS( XML_a, XML_camera, xAttrList );
if( bCameraRotationPresent )
{
sax_fastparser::XFastAttributeListRef xRotAttrList( aCameraRotationAttrList );
mpFS->singleElementNS( XML_a, XML_rot, xRotAttrList );
}
mpFS->endElementNS( XML_a, XML_camera );
}
mpFS->endElementNS( XML_a, XML_camera );
else
// a:camera with Word default values - Word won't open the document if this is not present
mpFS->singleElementNS( XML_a, XML_camera, XML_prst, "orthographicFront", FSEND );
// 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 );
if( aEffectProps.getLength() > 0 )
{
sax_fastparser::XFastAttributeListRef xAttrList( aLightRigAttrList );
mpFS->startElementNS( XML_a, XML_lightRig, xAttrList );
if( bLightRigRotationPresent )
{
sax_fastparser::XFastAttributeListRef xRotAttrList( aLightRigRotationAttrList );
mpFS->singleElementNS( XML_a, XML_rot, xRotAttrList );
}
mpFS->endElementNS( XML_a, XML_lightRig );
}
else
// 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 );
}

View File

@ -1168,6 +1168,22 @@ DECLARE_OOXMLEXPORT_TEST(testShape3DEffectPreservation, "shape-3d-effect-preserv
"wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:scene3d/a:camera/a:rot",
"rev", "12900001");
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:lightRig",
"rig", "threePt");
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:lightRig",
"dir", "t");
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:lightRig/a:rot",
"lat", "0");
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:lightRig/a:rot",
"lon", "0");
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:lightRig/a:rot",
"rev", "4800000");
// 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",
@ -1175,6 +1191,15 @@ DECLARE_OOXMLEXPORT_TEST(testShape3DEffectPreservation, "shape-3d-effect-preserv
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/a:rot",
0);
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:lightRig",
"rig", "threePt");
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:lightRig",
"dir", "t");
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:lightRig/a:rot",
0);
}
DECLARE_OOXMLEXPORT_TEST(fdo77719, "fdo77719.docx")