include/oox/vml/vmlshape.hxx | 3 include/oox/vml/vmlshapecontext.hxx | 9 oox/source/vml/vmlshape.cxx | 8 oox/source/vml/vmlshapecontext.cxx | 13 sw/Library_sw_writerfilter.mk | 1 sw/qa/extras/ooxmlexport/data/tdf164065.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport21.cxx | 15 + sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx | 199 +++++++++++++-- sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx | 12 sw/source/writerfilter/ooxml/ShadowContext.cxx | 96 +++++++ sw/source/writerfilter/ooxml/ShadowContext.hxx | 156 +++++++++++ 11 files changed, 491 insertions(+), 21 deletions(-)
New commits: commit 5fb8e29926a5c0dd1ae027f05d48826399cc31a1 Author: Oliver Specht <oliver.spe...@cib.de> AuthorDate: Mon Oct 14 14:50:06 2024 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Dec 10 17:18:10 2024 +0100 tdf#164065 load vml textbox in a group shape Store (vml) textbox elements to determine whether to load shape text or Writer frame. Replay elements in second step and process depending on the outcome. - result flag not yet available while processing - The text shape in docx bugdoc of tdf#152878 can now be loaded as Writer frame but with wrong size/position. - should also be applied to drawing ml shapes currently always loaded as Writer frame Change-Id: I0778057f9985f5523d91a9d757e00f2968aba350 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174902 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Tested-by: Gabor Kelemen <gabor.kelemen.ext...@allotropia.de> diff --git a/include/oox/vml/vmlshape.hxx b/include/oox/vml/vmlshape.hxx index 64259c554caf..6348b539f689 100644 --- a/include/oox/vml/vmlshape.hxx +++ b/include/oox/vml/vmlshape.hxx @@ -145,6 +145,8 @@ public: OUString getGraphicPath() const; const Drawing& getDrawing() const { return mrDrawing; } + void setTextBox(bool bSet) {mbTextBox = bSet;} + bool isTextBox() const {return mbTextBox;} protected: /** Returns the coordinate system of this shape. */ @@ -159,6 +161,7 @@ protected: protected: Drawing& mrDrawing; ///< The VML drawing page that contains this shape. ShapeTypeModel maTypeModel; ///< The model structure containing shape type data. + bool mbTextBox; //will be set if the shape contains a text box }; diff --git a/include/oox/vml/vmlshapecontext.hxx b/include/oox/vml/vmlshapecontext.hxx index 8252e0e6ebe6..6f7a2eff7d5b 100644 --- a/include/oox/vml/vmlshapecontext.hxx +++ b/include/oox/vml/vmlshapecontext.hxx @@ -24,6 +24,7 @@ #include <oox/core/contexthandler2.hxx> #include <rtl/ustring.hxx> #include <sal/types.h> +//#include <oox/dllapi.h> #include <optional> @@ -79,7 +80,7 @@ private: }; -class ShapeContextBase : public ::oox::core::ContextHandler2 +class SAL_DLLPUBLIC_RTTI ShapeContextBase : public ::oox::core::ContextHandler2 { public: static ::oox::core::ContextHandlerRef @@ -94,7 +95,7 @@ protected: }; -class ShapeTypeContext : public ShapeContextBase +class SAL_DLLPUBLIC_RTTI ShapeTypeContext : public ShapeContextBase { public: explicit ShapeTypeContext( @@ -118,7 +119,7 @@ private: }; -class ShapeContext : public ShapeTypeContext +class SAL_DLLPUBLIC_RTTI ShapeContext : public ShapeTypeContext { public: explicit ShapeContext(::oox::core::ContextHandler2Helper const& rParent, @@ -127,6 +128,8 @@ public: virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override; + void OOX_DLLPUBLIC setWriterShape(); + private: /** Processes the 'points' attribute. */ void setPoints( std::u16string_view rPoints ); diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index 1f5a8f27c59e..7908dd7527c4 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -150,6 +150,7 @@ void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource ) ShapeType::ShapeType( Drawing& rDrawing ) : mrDrawing( rDrawing ) + , mbTextBox(false) { } @@ -859,6 +860,13 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, Any(sal_Int32(getTextBox()->borderDistanceBottom))); xShape->setSize(aSize); } + + if (mbTextBox) + { + // similar to drawingml::Shape::createAndInsert(...) + PropertySet(xShape).setAnyProperty(PROP_TextBox, Any(true)); + } + } } diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index daedc527f465..85c70347e0e8 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -548,7 +548,14 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri 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(u"com.sun.star.drawing.TextShape"_ustr); + { + if (mrShape.isTextBox()) + dynamic_cast<SimpleShape&>(mrShape).setService( + u"com.sun.star.drawing.CustomShape"_ustr); + else + dynamic_cast<SimpleShape&>(mrShape).setService( + u"com.sun.star.drawing.TextShape"_ustr); + } else // FIXME: without this we does not handle some properties like shadow dynamic_cast<SimpleShape&>(mrShape).setService(u"com.sun.star.text.TextFrame"_ustr); @@ -591,6 +598,10 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri // handle remaining stuff in base class return ShapeTypeContext::onCreateContext( nElement, rAttribs ); } +void ShapeContext::setWriterShape() +{ + mrShape.setTextBox(true); +} void ShapeContext::setPoints(std::u16string_view rPoints) { diff --git a/sw/Library_sw_writerfilter.mk b/sw/Library_sw_writerfilter.mk index a51650ce9bf2..224b73de5cc7 100644 --- a/sw/Library_sw_writerfilter.mk +++ b/sw/Library_sw_writerfilter.mk @@ -134,6 +134,7 @@ $(eval $(call gb_Library_add_exception_objects,sw_writerfilter,\ sw/source/writerfilter/ooxml/OOXMLParserState \ sw/source/writerfilter/ooxml/OOXMLPropertySet \ sw/source/writerfilter/ooxml/OOXMLStreamImpl \ + sw/source/writerfilter/ooxml/ShadowContext \ )) $(eval $(call gb_Library_add_generated_exception_objects,sw_writerfilter,\ diff --git a/sw/qa/extras/ooxmlexport/data/tdf164065.docx b/sw/qa/extras/ooxmlexport/data/tdf164065.docx new file mode 100644 index 000000000000..b66a6cdb2da4 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf164065.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx index 207568ee8b76..0447f0b78f12 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx @@ -17,6 +17,7 @@ #include <com/sun/star/text/XDocumentIndex.hpp> #include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/table/XCellRange.hpp> #include <com/sun/star/style/LineSpacing.hpp> #include <com/sun/star/style/LineSpacingMode.hpp> #include <com/sun/star/packages/zip/ZipFileAccess.hpp> @@ -1189,6 +1190,20 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf146269) } } +CPPUNIT_TEST_FIXTURE(Test, testTdf164065) +{ + loadAndSave("tdf164065.docx"); + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + + uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), + uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount()); + uno::Reference<table::XCellRange> xTable(xTables->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XText> xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"a"_ustr, xCell->getString()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx index 046d8c6aacb0..ab01166040fe 100644 --- a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx +++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx @@ -25,6 +25,7 @@ #include <oox/mathml/imexport.hxx> #include <oox/token/namespaces.hxx> #include <oox/shape/ShapeFilterBase.hxx> +#include <oox/vml/vmlshapecontext.hxx> #include <sal/log.hxx> #include <comphelper/embeddedobjectcontainer.hxx> #include <comphelper/propertyvalue.hxx> @@ -42,6 +43,7 @@ #include "OOXMLPropertySet.hxx" #include <dmapper/GraphicHelpers.hxx> #include <unodraw.hxx> +#include "ShadowContext.hxx" const sal_Unicode uCR = 0xd; const sal_Unicode uFtnEdnRef = 0x2; @@ -1973,7 +1975,26 @@ OOXMLFastContextHandlerWrapper::OOXMLFastContextHandlerWrapper rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler) : OOXMLFastContextHandler(pParent), mxWrappedContext(xContext), - mxShapeHandler(xShapeHandler) + mxShapeHandler(xShapeHandler), + mbIsWriterFrameDetected(false), + mbIsReplayTextBox(false) +{ + setId(pParent->getId()); + setToken(pParent->getToken()); + setPropertySet(pParent->getPropertySet()); +} + +OOXMLFastContextHandlerWrapper::OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent, + rtl::Reference<ShadowContext> const & xShadowContext, + uno::Reference<XFastContextHandler> const& xParentContext, + rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler) + : OOXMLFastContextHandler(pParent), + mxWrappedContext(xShadowContext), + mxShapeHandler(xShapeHandler), + mxShadowContext(xShadowContext), + mxReplayParentContext(xParentContext), + mbIsWriterFrameDetected(false), + mbIsReplayTextBox(false) { setId(pParent->getId()); setToken(pParent->getToken()); @@ -2001,6 +2022,114 @@ void SAL_CALL OOXMLFastContextHandlerWrapper::endUnknownElement mxWrappedContext->endUnknownElement(Namespace, Name); } +void SAL_CALL OOXMLFastContextHandlerWrapper::endFastElement(::sal_Int32 Element) +{ + OOXMLFastContextHandler::endFastElement(Element); + if (mxShadowContext.is()) + { + mxWrappedContext = mxReplayParentContext; + mbIsReplayTextBox = true; + mbIsWriterFrameDetected = mxShadowContext->isWriterFrame(); + sal_uInt16 nLevel = mxShadowContext->getElementLevel(); + if (!nLevel) + { + std::deque<CallData>& callDataDeque = mxShadowContext->getCallData(); + std::deque<uno::Reference<xml::sax::XFastContextHandler>> aLocalHandlers; + for (auto callDataIt = callDataDeque.begin(); callDataIt != callDataDeque.end(); ++callDataIt) + { + switch (callDataIt->getType()) + { + case Init: + { + sal_Int32 nElement = callDataIt->getElement(); + css::uno::Reference<css::xml::sax::XFastAttributeList> rAttribs + = callDataIt->getAttributes(); + if (mbIsWriterFrameDetected) + { + oox::vml::ShapeContext* pShapeContext = dynamic_cast<oox::vml::ShapeContext*>(mxWrappedContext.get()); + if (pShapeContext) + pShapeContext->setWriterShape(); + } + uno::Reference< xml::sax::XFastContextHandler > newWrapper = lcl_createFastChildContext(nElement, rAttribs); + static_cast<OOXMLFastContextHandlerWrapper*>(newWrapper.get())->mbIsWriterFrameDetected = mbIsWriterFrameDetected; + aLocalHandlers.push_back(newWrapper); + } + break; + case ElementAttr: + { + sal_Int32 nElement = callDataIt->getElement(); + css::uno::Reference<css::xml::sax::XFastAttributeList> rAttrs + = callDataIt->getAttributes(); + auto xHandler = aLocalHandlers.back(); + if (xHandler) + xHandler->startFastElement(nElement, rAttrs); + } + break; + case Char: + { + const ::rtl::OUString& chars = callDataIt->getChars(); + auto xHandler = aLocalHandlers.back(); + if (xHandler) + xHandler->characters(chars); + } + break; + case EndElementAttr: + { + sal_Int32 nElement = callDataIt->getElement(); + auto xHandler = aLocalHandlers.back(); + if (xHandler) + xHandler->endFastElement(nElement); + aLocalHandlers.pop_back(); + } + break; + case Unknown: + { + const ::rtl::OUString& rNameSpace = callDataIt->getUnknownNameSpace(); + const ::rtl::OUString& rElement = callDataIt->getUnknownElement(); + css::uno::Reference<css::xml::sax::XFastAttributeList> rAttrs + = callDataIt->getAttributes(); + auto xHandler = aLocalHandlers.back(); + if (xHandler) + xHandler->startUnknownElement(rNameSpace, rElement, rAttrs); + } + break; + case EndUnknown: + { + const ::rtl::OUString& rNameSpace = callDataIt->getUnknownNameSpace(); + const ::rtl::OUString& rElement = callDataIt->getUnknownElement(); + auto xHandler = aLocalHandlers.back(); + if (xHandler) + xHandler->endUnknownElement(rNameSpace, rElement); + aLocalHandlers.pop_back(); + } + break; + case ElementContext: + { + sal_Int32 nElement = callDataIt->getElement(); + css::uno::Reference<css::xml::sax::XFastAttributeList> rAttrs + = callDataIt->getAttributes(); + uno::Reference< xml::sax::XFastContextHandler > newContext = aLocalHandlers.back()->createFastChildContext(nElement, rAttrs); + if (nElement == Token_t(NMSP_vml | XML_textbox)) + static_cast<OOXMLFastContextHandlerWrapper*>(newContext.get())->mbIsWriterFrameDetected = mbIsWriterFrameDetected; + aLocalHandlers.push_back(newContext); + } + break; + case UnknownContext: + { + const ::rtl::OUString& rNameSpace = callDataIt->getUnknownNameSpace(); + const ::rtl::OUString& rElement = callDataIt->getUnknownElement(); + css::uno::Reference<css::xml::sax::XFastAttributeList> rAttrs + = callDataIt->getAttributes(); + uno::Reference< xml::sax::XFastContextHandler > newContext = aLocalHandlers.back()->createUnknownChildContext(rNameSpace, rElement, rAttrs); + aLocalHandlers.push_back(newContext); + } + break; + } + } + } + } +} + uno::Reference< xml::sax::XFastContextHandler > SAL_CALL OOXMLFastContextHandlerWrapper::createUnknownChildContext (const OUString & Namespace, @@ -2051,12 +2180,17 @@ void OOXMLFastContextHandlerWrapper::lcl_startFastElement { if (mxWrappedContext.is()) mxWrappedContext->startFastElement(Element, Attribs); - - if (mxShapeHandler->isDMLGroupShape() - && (Element == Token_t(NMSP_wps | XML_txbx) - || Element == Token_t(NMSP_wps | XML_linkedTxbx))) - { - mpStream->startTextBoxContent(); + if (!mxShadowContext.is()) + { + bool bInTokens = mMyTokens.find(Element) != mMyTokens.end(); + if ((mxShapeHandler->isDMLGroupShape() + && (Element == Token_t(NMSP_wps | XML_txbx) + || Element == Token_t(NMSP_wps | XML_linkedTxbx))) + //TODO: why check for bInTokens + || (!bInTokens && mbIsWriterFrameDetected && Element == Token_t(NMSP_vml | XML_textbox))) + { + mpStream->startTextBoxContent(); + } } } @@ -2066,11 +2200,16 @@ void OOXMLFastContextHandlerWrapper::lcl_endFastElement if (mxWrappedContext.is()) mxWrappedContext->endFastElement(Element); - if (mxShapeHandler->isDMLGroupShape() - && (Element == Token_t(NMSP_wps | XML_txbx) - || Element == Token_t(NMSP_wps | XML_linkedTxbx))) + if (!mxShadowContext.is()) { - mpStream->endTextBoxContent(); + bool bInTokens = mMyTokens.find(Element) != mMyTokens.end(); + if ((mxShapeHandler->isDMLGroupShape() + && (Element == Token_t(NMSP_wps | XML_txbx) + || Element == Token_t(NMSP_wps | XML_linkedTxbx))) + || (!bInTokens && mbIsWriterFrameDetected && Element == Token_t(NMSP_vml | XML_textbox))) + { + mpStream->endTextBoxContent(); + } } } @@ -2080,6 +2219,10 @@ OOXMLFastContextHandlerWrapper::lcl_createFastChildContext const uno::Reference< xml::sax::XFastAttributeList > & Attribs) { uno::Reference< xml::sax::XFastContextHandler > xResult; + if (mxShadowContext.is() && !mbIsReplayTextBox) + { + return mxShadowContext->createFastChildContext(Element, Attribs); + } bool bInNamespaces = mMyNamespaces.find(oox::getNamespace(Element)) != mMyNamespaces.end(); bool bInTokens = mMyTokens.find( Element ) != mMyTokens.end( ); @@ -2100,11 +2243,34 @@ OOXMLFastContextHandlerWrapper::lcl_createFastChildContext } else if (mxWrappedContext.is() && !bSkipImages) { - rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper = - new OOXMLFastContextHandlerWrapper - (this, mxWrappedContext->createFastChildContext(Element, Attribs), - mxShapeHandler); - pWrapper->mMyNamespaces = mMyNamespaces; + rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper; + if (Element == (NMSP_vml | XML_textbox) && !mbIsReplayTextBox) + { + //TODO: change handling of drawingml, currently Writer frame only + rtl::Reference<ShadowContext> xShadowContext + = new ShadowContext(Element, Attribs); + pWrapper = new OOXMLFastContextHandlerWrapper(this, xShadowContext, mxWrappedContext, mxShapeHandler); + pWrapper->mMyNamespaces = mMyNamespaces; + //don't send shape here + bInTokens = false; + } + else + { + pWrapper = + new OOXMLFastContextHandlerWrapper + (this, mxWrappedContext->createFastChildContext(Element, Attribs), + mxShapeHandler); + if (mbIsWriterFrameDetected) + { + pWrapper->addNamespace(NMSP_doc); + pWrapper->addNamespace(NMSP_vmlWord); + pWrapper->addNamespace(NMSP_vmlOffice); + } + else + { + pWrapper->mMyNamespaces = mMyNamespaces; + } + } pWrapper->mMyTokens = mMyTokens; pWrapper->setPropertySet(getPropertySet()); xResult.set(pWrapper); @@ -2243,7 +2409,6 @@ Token_t OOXMLFastContextHandlerWrapper::getToken() const return nResult; } - /* class OOXMLFastContextHandlerLinear */ diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx index 03a4d40e5c2f..49abfde529ce 100644 --- a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx +++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx @@ -27,6 +27,7 @@ #include <rtl/ref.hxx> #include "OOXMLParserState.hxx" #include "OOXMLPropertySet.hxx" +#include "ShadowContext.hxx" namespace writerfilter::ooxml { @@ -494,9 +495,14 @@ public: OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent, css::uno::Reference<css::xml::sax::XFastContextHandler> const & xContext, rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler); + OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent, + rtl::Reference<ShadowContext> const & xContext, + css::uno::Reference<css::xml::sax::XFastContextHandler> const & xParentContext, + rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler); virtual ~OOXMLFastContextHandlerWrapper() override; // css::xml::sax::XFastContextHandler: + virtual void SAL_CALL endFastElement( ::sal_Int32 Element ) override; virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override; virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override; @@ -532,12 +538,18 @@ protected: virtual void setToken(Token_t nToken) override; virtual Token_t getToken() const override; + bool isWriterFrameDetected() const { return mbIsWriterFrameDetected;} + private: css::uno::Reference<css::xml::sax::XFastContextHandler> mxWrappedContext; rtl::Reference<OOXMLFastContextHandlerShape> mxShapeHandler; std::set<Id> mMyNamespaces; std::set<Token_t> mMyTokens; OOXMLPropertySet::Pointer_t mpPropertySet; + rtl::Reference<ShadowContext> const mxShadowContext; + css::uno::Reference<css::xml::sax::XFastContextHandler> mxReplayParentContext; + bool mbIsWriterFrameDetected; + bool mbIsReplayTextBox; OOXMLFastContextHandler * getFastContextHandler() const; }; diff --git a/sw/source/writerfilter/ooxml/ShadowContext.cxx b/sw/source/writerfilter/ooxml/ShadowContext.cxx new file mode 100644 index 000000000000..d850092c9adc --- /dev/null +++ b/sw/source/writerfilter/ooxml/ShadowContext.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "ShadowContext.hxx" +#include <ooxml/resourceids.hxx> +#include <oox/token/namespaces.hxx> + +namespace writerfilter::ooxml +{ +using namespace ::com::sun::star; +using namespace oox; +using namespace ::com::sun::star::xml::sax; + +ShadowContext::ShadowContext(::sal_Int32 nElement, + const uno::Reference<XFastAttributeList>& rAttribs) + : m_nElementLevel(0) + , m_bImportAsWriterFrame(false) +{ + CallData callData(m_nElementLevel, nElement, rAttribs, CallDataType::Init); + m_aCallDataDeque.push_back(callData); +} +ShadowContext::~ShadowContext() {} + +void ShadowContext::startFastElement( + ::sal_Int32 nElement, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& rAttribs) +{ + ++m_nElementLevel; + CallData callData(m_nElementLevel, nElement, rAttribs, CallDataType::ElementAttr); + m_aCallDataDeque.push_back(callData); + if (nElement == (oox::NMSP_doc | oox::XML_tbl)) + { + m_bImportAsWriterFrame = true; + } +} + +void ShadowContext::startUnknownElement( + const ::rtl::OUString& rNamespace, const ::rtl::OUString& rElement, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& rAttribs) +{ + ++m_nElementLevel; + CallData callData(m_nElementLevel, rNamespace, rElement, rAttribs, CallDataType::Unknown); + m_aCallDataDeque.push_back(callData); +} +void ShadowContext::endFastElement(::sal_Int32 nElement) +{ + --m_nElementLevel; + CallData callData(m_nElementLevel, nElement); + m_aCallDataDeque.push_back(callData); +} +void ShadowContext::endUnknownElement(const ::rtl::OUString& rNamespace, + const ::rtl::OUString& rElement) +{ + --m_nElementLevel; + CallData callData(m_nElementLevel, rNamespace, rElement); + m_aCallDataDeque.push_back(callData); +} +::css::uno::Reference<::css::xml::sax::XFastContextHandler> ShadowContext::createFastChildContext( + ::sal_Int32 nElement, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& rAttribs) +{ + CallData callData(m_nElementLevel, nElement, rAttribs, CallDataType::ElementContext); + m_aCallDataDeque.push_back(callData); + return this; +} +::css::uno::Reference<::css::xml::sax::XFastContextHandler> +ShadowContext::createUnknownChildContext( + const ::rtl::OUString& rNamespace, const ::rtl::OUString& rElement, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& rAttribs) +{ + CallData callData(m_nElementLevel, rNamespace, rElement, rAttribs, + CallDataType::UnknownContext); + m_aCallDataDeque.push_back(callData); + return this; +} +void ShadowContext::characters(const ::rtl::OUString& aChars) +{ + CallData callData(m_nElementLevel, aChars); + m_aCallDataDeque.push_back(callData); +} +} //namespace diff --git a/sw/source/writerfilter/ooxml/ShadowContext.hxx b/sw/source/writerfilter/ooxml/ShadowContext.hxx new file mode 100644 index 000000000000..d7e389d10abd --- /dev/null +++ b/sw/source/writerfilter/ooxml/ShadowContext.hxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/xml/sax/XFastContextHandler.hpp> +#include <sax/fastattribs.hxx> +#include <oox/helper/attributelist.hxx> +#include <oox/core/contexthandler.hxx> +#include <queue> + +namespace writerfilter::ooxml +{ +enum CallDataType +{ + Init, + ElementAttr, + Char, + EndElementAttr, + Unknown, + EndUnknown, + ElementContext, + UnknownContext +}; + +class CallData +{ + sal_uInt32 m_nLevel; + CallDataType m_eType; + sal_Int32 m_nElement; + css::uno::Reference<css::xml::sax::XFastAttributeList> m_aAttributes; + + //char + ::rtl::OUString m_aChars; + + //unknwon + ::rtl::OUString m_sNameSpace; + ::rtl::OUString m_sElement; + +public: + //Start unknown element or context + CallData(sal_uInt32 nLevel, const ::rtl::OUString& rNameSpace, const ::rtl::OUString& rElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& rAttributes, + CallDataType eType) + : m_nLevel(nLevel) + , m_eType(eType) + , m_aAttributes(new sax_fastparser::FastAttributeList(rAttributes)) + , m_sNameSpace(rNameSpace) + , m_sElement(rElement) + { + } + + //end unknown element + CallData(sal_uInt32 nLevel, const ::rtl::OUString& rNameSpace, const ::rtl::OUString& rElement) + : m_nLevel(nLevel) + , m_eType(CallDataType::EndUnknown) + , m_sNameSpace(rNameSpace) + , m_sElement(rElement) + { + } + + // start fast element + CallData(sal_uInt32 nLevel, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& rAttributes, + CallDataType eType) + : m_nLevel(nLevel) + , m_eType(eType) + , m_nElement(nElement) + , m_aAttributes(new sax_fastparser::FastAttributeList(rAttributes)) + { + } + + // end fast element + CallData(sal_uInt32 nLevel, sal_Int32 nElement) + : m_nLevel(nLevel) + , m_eType(CallDataType::EndElementAttr) + , m_nElement(nElement) + { + } + + //chars + CallData(sal_uInt32 nLevel, const ::rtl::OUString& rChars) + : m_nLevel(nLevel) + , m_eType(CallDataType::Char) + , m_aChars(rChars) + { + } + + CallData(CallData const&) = default; + + sal_uInt32 getLevel() const { return m_nLevel; } + CallDataType getType() const { return m_eType; } + sal_Int32 getElement() const { return m_nElement; } + const ::rtl::OUString& getChars() { return m_aChars; } + css::uno::Reference<css::xml::sax::XFastAttributeList> getAttributes() const + { + return m_aAttributes; + } + const ::rtl::OUString& getUnknownNameSpace() const { return m_sNameSpace; } + const ::rtl::OUString& getUnknownElement() const { return m_sElement; } +}; +class ShadowContext : public ::oox::core::ContextHandler_BASE +{ +public: + explicit ShadowContext(::sal_Int32 Element, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& rAttribs); + virtual ~ShadowContext() override; + + //XFastContextHandler + virtual void SAL_CALL startFastElement( + ::sal_Int32 Element, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& Attribs) override; + virtual void SAL_CALL startUnknownElement( + const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& Attribs) override; + virtual void SAL_CALL endFastElement(::sal_Int32 Element) override; + virtual void SAL_CALL endUnknownElement(const ::rtl::OUString& Namespace, + const ::rtl::OUString& Name) override; + virtual ::css::uno::Reference<::css::xml::sax::XFastContextHandler> + SAL_CALL createFastChildContext( + ::sal_Int32 Element, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& Attribs) override; + virtual ::css::uno::Reference<::css::xml::sax::XFastContextHandler> + SAL_CALL createUnknownChildContext( + const ::rtl::OUString& Namespace, const ::rtl::OUString& Name, + const ::css::uno::Reference<::css::xml::sax::XFastAttributeList>& Attribs) override; + virtual void SAL_CALL characters(const ::rtl::OUString& aChars) override; + + sal_uInt16 getElementLevel() const { return m_nElementLevel; } + bool isWriterFrame() const { return m_bImportAsWriterFrame; } + + std::deque<CallData>& getCallData() { return m_aCallDataDeque; } + +private: + std::deque<CallData> m_aCallDataDeque; + sal_uInt16 m_nElementLevel; + bool m_bImportAsWriterFrame; +}; +}