From a9c5c0d814a266096483572b84c72875ef8efd77 Mon Sep 17 00:00:00 2001 From: "Daniel Arato (NISZ)" Date: Tue, 29 Sep 2020 16:37:41 +0200 Subject: tdf#133037 OOXML shape import: camera rotation along Z MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of implementing proper OOXML 3D rotation (which would be an entirely new feature if I understand correctly), I merely interpret attribute "rev" of the rotation element a:camera/a:rot as a directive to rotate the entire shape the usual 2D way. That is already implemented and works well. This isn't the same thing Word does, but it might be good enough for now. This is kind of a mock solution, but it will be very easy to revert if it turns out to cause problems. Note: the export worked well previously, too (moreover, reloading the first LO export fixed the import). Change-Id: I2a99c119880bbed1c5b6430c4638cfbd10b7ac06 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103627 Tested-by: László Németh Reviewed-by: László Németh --- oox/qa/unit/data/camera-rotation-revolution.docx | Bin 0 -> 23748 bytes oox/qa/unit/drawingml.cxx | 25 ++++++++++++++++++ oox/source/drawingml/shape.cxx | 7 +++-- oox/source/export/drawingml.cxx | 32 +++++++++++++++++++++-- 4 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 oox/qa/unit/data/camera-rotation-revolution.docx (limited to 'oox') diff --git a/oox/qa/unit/data/camera-rotation-revolution.docx b/oox/qa/unit/data/camera-rotation-revolution.docx new file mode 100644 index 000000000000..74054aa82b3f Binary files /dev/null and b/oox/qa/unit/data/camera-rotation-revolution.docx differ diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx index 7fcee1756a6f..6a0415b257f2 100644 --- a/oox/qa/unit/drawingml.cxx +++ b/oox/qa/unit/drawingml.cxx @@ -265,6 +265,31 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testShapeTextAdjustLeft) CPPUNIT_ASSERT_EQUAL(drawing::TextHorizontalAdjust_BLOCK, eAdjust); } +CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testCameraRotationRevolution) +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "camera-rotation-revolution.docx"; + load(aURL); + + uno::Reference xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference xShape0(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference xShape1(xDrawPage->getByIndex(1), uno::UNO_QUERY); + uno::Reference xShapeProps0(xShape0, uno::UNO_QUERY); + uno::Reference xShapeProps1(xShape1, uno::UNO_QUERY); + sal_Int32 nRotateAngle0; + sal_Int32 nRotateAngle1; + xShapeProps0->getPropertyValue("RotateAngle") >>= nRotateAngle0; + xShapeProps1->getPropertyValue("RotateAngle") >>= nRotateAngle1; + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 8000 + // - Actual : 0 + // so the camera rotation would not have been factored into how the shape is displayed + CPPUNIT_ASSERT_EQUAL(static_cast(8000), nRotateAngle0); + CPPUNIT_ASSERT_EQUAL(static_cast(27000), nRotateAngle1); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index c9ade16f7a1d..95b608eadcc6 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -1461,11 +1461,14 @@ Reference< XShape > const & Shape::createAndInsert( else if( getTextBody() ) getTextBody()->getTextProperties().pushVertSimulation(); + // tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate + const sal_Int32 nCameraRotation = get3DProperties().maCameraRotation.mnRevolution.get(0); + PropertySet aPropertySet(mxShape); - if ( !bUseRotationTransform && mnRotation != 0 ) + if ( !bUseRotationTransform && (mnRotation != 0 || nCameraRotation != 0) ) { // use the same logic for rotation from VML exporter (SimpleShape::implConvertAndInsert at vmlshape.cxx) - aPropertySet.setAnyProperty( PROP_RotateAngle, makeAny( sal_Int32( NormAngle36000( mnRotation / -600 ) ) ) ); + aPropertySet.setAnyProperty( PROP_RotateAngle, makeAny( sal_Int32( NormAngle36000( (mnRotation - nCameraRotation) / -600 ) ) ) ); aPropertySet.setAnyProperty( PROP_HoriOrientPosition, makeAny( maPosition.X ) ); aPropertySet.setAnyProperty( PROP_VertOrientPosition, makeAny( maPosition.Y ) ); } diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 4a9ac9f69014..c19b030ad642 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -1708,7 +1708,8 @@ void DrawingML::WriteShapeTransformation( const Reference< XShape >& rXShape, sa { SAL_INFO("oox.shape", "write shape transformation"); - sal_Int32 nRotation=0; + sal_Int32 nRotation = 0; + sal_Int32 nCameraRotation = 0; awt::Point aPos = rXShape->getPosition(); awt::Size aSize = rXShape->getSize(); @@ -1745,6 +1746,33 @@ void DrawingML::WriteShapeTransformation( const Reference< XShape >& rXShape, sa uno::Reference xPropertySetInfo = xPropertySet->getPropertySetInfo(); if (xPropertySetInfo->hasPropertyByName("RotateAngle")) xPropertySet->getPropertyValue("RotateAngle") >>= nRotation; + // tdf#133037: restore original rotate angle before output + if (xPropertySetInfo->hasPropertyByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG)) + { + uno::Sequence aGrabBagProps; + xPropertySet->getPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG) >>= aGrabBagProps; + auto p3DEffectProps = std::find_if(std::cbegin(aGrabBagProps), std::cend(aGrabBagProps), + [](const PropertyValue& rProp) { return rProp.Name == "3DEffectProperties"; }); + if (p3DEffectProps != std::cend(aGrabBagProps)) + { + uno::Sequence a3DEffectProps; + p3DEffectProps->Value >>= a3DEffectProps; + auto pCameraProps = std::find_if(std::cbegin(a3DEffectProps), std::cend(a3DEffectProps), + [](const PropertyValue& rProp) { return rProp.Name == "Camera"; }); + if (pCameraProps != std::cend(a3DEffectProps)) + { + uno::Sequence aCameraProps; + pCameraProps->Value >>= aCameraProps; + auto pZRotationProp = std::find_if(std::cbegin(aCameraProps), std::cend(aCameraProps), + [](const PropertyValue& rProp) { return rProp.Name == "rotRev"; }); + if (pZRotationProp != std::cend(aCameraProps)) + { + pZRotationProp->Value >>= nCameraRotation; + nCameraRotation = NormAngle36000(nCameraRotation / -600); + } + } + } + } } // OOXML flips shapes before rotating them. @@ -1752,7 +1780,7 @@ void DrawingML::WriteShapeTransformation( const Reference< XShape >& rXShape, sa nRotation = nRotation * -1 + 36000; WriteTransformation(tools::Rectangle(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)), nXmlNamespace, - bFlipHWrite, bFlipVWrite, ExportRotateClockwisify(nRotation), IsGroupShape( rXShape )); + bFlipHWrite, bFlipVWrite, ExportRotateClockwisify(nRotation + nCameraRotation), IsGroupShape( rXShape )); } void DrawingML::WriteRunProperties( const Reference< XPropertySet >& rRun, bool bIsField, sal_Int32 nElement, -- cgit