summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorRegényi Balázs <regenyi.balazs@nisz.hu>2020-12-01 12:16:12 +0100
committerLászló Németh <nemeth@numbertext.org>2020-12-10 12:03:39 +0100
commitaefb6aaf6475b71668bab7e11ce51b0fdc34f299 (patch)
tree38353099670125a3cb96189e0dc1fb155b73d2e1 /oox
parent172b81479451f0af2978dfa2eba1f9d105b946c9 (diff)
tdf#41466 DOCX import: fix VML v:shape/v:textbox
VML v:shape/v:textbox element was imported only as a text frame, losing (otherwise recognized) preset shape geometry, i.e. replacing a callout bubble (wedgeRectCallout) and other special shapes with a plain rectangle. Thanks to Attila Bakos for the initial help. Change-Id: I03a608822ed54a20ed07406a08c3539e72958f5b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105299 Tested-by: Jenkins Reviewed-by: László Németh <nemeth@numbertext.org> (cherry picked from commit bda05ba17362222b74727872579b65b3fa14e3d8) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107486
Diffstat (limited to 'oox')
-rw-r--r--oox/qa/unit/data/layout-flow-alt-alone.docxbin7669 -> 0 bytes
-rw-r--r--oox/qa/unit/vml.cxx19
-rw-r--r--oox/source/export/drawingml.cxx34
-rw-r--r--oox/source/export/vmlexport.cxx50
-rw-r--r--oox/source/vml/vmlshape.cxx32
-rw-r--r--oox/source/vml/vmlshapecontext.cxx20
6 files changed, 122 insertions, 33 deletions
diff --git a/oox/qa/unit/data/layout-flow-alt-alone.docx b/oox/qa/unit/data/layout-flow-alt-alone.docx
deleted file mode 100644
index 59c2db23d588..000000000000
--- a/oox/qa/unit/data/layout-flow-alt-alone.docx
+++ /dev/null
Binary files differ
diff --git a/oox/qa/unit/vml.cxx b/oox/qa/unit/vml.cxx
index d43d2d5645ae..ec64a08c3fcf 100644
--- a/oox/qa/unit/vml.cxx
+++ b/oox/qa/unit/vml.cxx
@@ -55,25 +55,6 @@ void OoxVmlTest::load(const OUString& rFileName)
mxComponent = loadFromDesktop(aURL);
}
-CPPUNIT_TEST_FIXTURE(OoxVmlTest, testLayoutFlowAltAlone)
-{
- // mso-layout-flow-alt:bottom-to-top without a matching layout-flow:vertical.
- load("layout-flow-alt-alone.docx");
-
- uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
- uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
- uno::UNO_QUERY);
- uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
- sal_Int16 nWritingMode = 0;
- xShape->getPropertyValue("WritingMode") >>= nWritingMode;
-
- // Without the accompanying fix in place, this test would have failed with:
- // - Expected: 5 [ BTLR ]
- // - Actual : 4 [ PAGE ]
- // i.e. in case layout-flow:vertical was missing, the text was not vertical.
- CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR, nWritingMode);
-}
-
CPPUNIT_TEST_FIXTURE(OoxVmlTest, testSpt202ShapeType)
{
// Load a document with a groupshape, 2nd child is a <v:shape>, its type has o:spt set to 202
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 3ed451710b55..918d212cac12 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -88,6 +88,7 @@
#include <com/sun/star/text/XTextContent.hpp>
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
#include <com/sun/star/style/CaseMap.hpp>
#include <com/sun/star/xml/dom/XNodeList.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
@@ -2942,6 +2943,39 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
}
}
}
+ else
+ {
+ if (mpTextExport)
+ {
+ uno::Reference<drawing::XShape> xShape(rXIface, uno::UNO_QUERY);
+ if (xShape)
+ {
+ auto xTextFrame = mpTextExport->GetUnoTextFrame(xShape);
+ if (xTextFrame)
+ {
+ uno::Reference<beans::XPropertySet> xPropSet(xTextFrame, uno::UNO_QUERY);
+ auto aAny = xPropSet->getPropertyValue("WritingMode");
+ sal_Int16 nWritingMode;
+ if (aAny >>= nWritingMode)
+ {
+ switch (nWritingMode)
+ {
+ case WritingMode2::TB_RL:
+ sWritingMode = "vert";
+ bVertical = true;
+ break;
+ case WritingMode2::BT_LR:
+ sWritingMode = "vert270";
+ bVertical = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
OUString sPresetWarp(PresetGeometryTypeNames::GetMsoName(sShapeType));
// ODF may have user defined TextPath, use "textPlain" as ersatz.
if (sPresetWarp.isEmpty())
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 430ade878bf2..5ef5ed096b2e 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -46,6 +46,8 @@
#include <com/sun/star/text/HoriOrientation.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
#include <cstdio>
@@ -1470,15 +1472,49 @@ void VMLExport::EndShape( sal_Int32 nShapeElement )
if (m_pTextExport && lcl_isTextBox(m_pSdrObject))
{
- uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY);
- comphelper::SequenceAsHashMap aCustomShapeProperties(xPropertySet->getPropertyValue("CustomShapeGeometry"));
- sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList();
- if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
+ uno::Reference<drawing::XShape> xShape {const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY};
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ bool bBottomToTop = false;
+ if (xPropertySetInfo->hasPropertyByName("CustomShapeGeometry"))
{
- sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
- if (nTextRotateAngle == -270)
- pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top");
+ // In this case a DrawingML DOCX was imported.
+ comphelper::SequenceAsHashMap aCustomShapeProperties(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+ if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
+ {
+ sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
+ if (nTextRotateAngle == -270)
+ bBottomToTop = true;
+ }
}
+ else
+ {
+ // In this case a pure VML DOCX was imported, so there is no CustomShapeGeometry.
+ auto pTextExport = m_pTextExport->GetDrawingML().GetTextExport();
+ // FIXME: somewhy pTextExport is always nullptr, we should find its reason
+ if (pTextExport)
+ {
+ auto xTextFrame = pTextExport->GetUnoTextFrame(xShape);
+ uno::Reference<beans::XPropertySet> xPropSet(xTextFrame, uno::UNO_QUERY);
+ auto aAny = xPropSet->getPropertyValue("WritingMode");
+ sal_Int16 nWritingMode;
+ if (aAny >>= nWritingMode)
+ {
+ switch (nWritingMode)
+ {
+ case text::WritingMode2::BT_LR:
+ bBottomToTop = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList();
+ if (bBottomToTop)
+ pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top");
sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList);
pTextboxAttrList = nullptr;
m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx
index 1e3e1f72e64d..7ee10203341e 100644
--- a/oox/source/vml/vmlshape.cxx
+++ b/oox/source/vml/vmlshape.cxx
@@ -69,6 +69,7 @@
#include <comphelper/processfactory.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/storagehelper.hxx>
+#include <comphelper/sequenceashashmap.hxx>
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::uno::Any;
@@ -259,6 +260,7 @@ ShapeModel::ShapeModel()
: mbIsSignatureLine(false)
, mbSignatureLineShowSignDate(true)
, mbSignatureLineCanAddComment(false)
+ , mbInGroup(false)
{
}
@@ -459,6 +461,8 @@ Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxS
PropertySet aControlShapeProp( xControlShape->getControl() );
aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) );
}
+
+ xShape = finalImplConvertAndInsert(xShape);
/* Notify the drawing that a new shape has been inserted. For
convenience, pass the rectangle that contains position and
size of the shape. */
@@ -887,6 +891,34 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes
return xShape;
}
+Reference<XShape> SimpleShape::finalImplConvertAndInsert(const css::uno::Reference<css::drawing::XShape>& rxShape) const
+{
+ // tdf#41466 This setting must be done here, because the position of textbox will be set as an
+ // effect of the PROP_TextBox property setting, and if we do this setting earlier (setting of
+ // properties of position and size) then the position of textbox will be set with wrong data.
+ // TODO: TextShape is set if we have rect shape in group; we should use the shape-with-textbox
+ // mechanism to handle this situation
+ if (getTextBox() && maService != "com.sun.star.text.TextFrame" && maService != "com.sun.star.drawing.TextShape"
+ && !maShapeModel.mbInGroup)
+ {
+ const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
+ const auto& nLeft = ConversionHelper::decodeMeasureToHmm(
+ rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true);
+ PropertySet aPropertySet(rxShape);
+ aPropertySet.setProperty(PROP_HoriOrientPosition, nLeft);
+ const auto& nTop = ConversionHelper::decodeMeasureToHmm(
+ rGraphicHelper, maTypeModel.maMarginTop, 0, true, true);
+ aPropertySet.setProperty(PROP_VertOrientPosition, nTop);
+ aPropertySet.setProperty(PROP_TextBox, true);
+
+ // And these properties must be set after textbox creation (set PROP_Textbox property).
+ // Note: if you set a new property then you have to handle it in the proper
+ // SwTextBoxHelper::syncProperty function.
+ if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
+ aPropertySet.setAnyProperty(PROP_TextWritingMode, uno::makeAny(text::WritingMode2::BT_LR));
+ }
+ return ShapeBase::finalImplConvertAndInsert(rxShape);
+}
Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
{
Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx
index f1ba9e32340c..e8f1b0b1910e 100644
--- a/oox/source/vml/vmlshapecontext.cxx
+++ b/oox/source/vml/vmlshapecontext.cxx
@@ -499,20 +499,26 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri
nShapeType = pShapeType->getTypeModel().moShapeType.get();
}
}
+ mrShapeModel.mbInGroup = (getParentElement() == VML_TOKEN(group));
- if (getParentElement() != VML_TOKEN( group ))
+ // FIXME: the shape with textbox should be used for the next cases
+ if (getCurrentElement() == VML_TOKEN(rect) || nShapeType == ESCHER_ShpInst_TextBox)
{
- // Custom shape in Writer with a textbox are transformed into a frame
- dynamic_cast<SimpleShape&>( mrShape ).setService(
- "com.sun.star.text.TextFrame");
+ if (mrShapeModel.mbInGroup)
+ // FIXME: without this a text will be added into the group-shape instead of its
+ // parent shape
+ dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.drawing.TextShape");
+ else
+ // FIXME: without this we does not handle some properties like shadow
+ dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.text.TextFrame");
}
- else if (getCurrentElement() == VML_TOKEN(rect) || nShapeType == ESCHER_ShpInst_TextBox)
- // Transform only rectangles into a TextShape inside a groupshape.
- dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.drawing.TextShape");
return new TextBoxContext( *this, mrShapeModel.createTextBox(mrShape.getTypeModel()), rAttribs,
mrShape.getDrawing().getFilter().getGraphicHelper());
}
case VMLX_TOKEN( ClientData ):
+ // tdf#41466 ActiveX control shapes with a textbox are transformed into a frame
+ // (see unit test testActiveXOptionButtonGroup)
+ dynamic_cast<SimpleShape&>(mrShape).setService("com.sun.star.text.TextFrame");
return new ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs );
case VMLPPT_TOKEN( textdata ):
// Force RectangleShape, this is ugly :(