From 886e29cff76d0358889aa676dbe90765950c990e Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Wed, 13 Jun 2012 18:04:51 +0200 Subject: rework handling the case of recursive ooxml shapes again Another attempt, whoever has written this apparently didn't consider the possibility of recursion at all, and this still feels a bit hackish. Writerfilter keeps just one oox::shape::ShapeContextHandler object during the entire time of parsing the document, because e.g. needs to be reachable even across VML block (see sw testcases for bnc#705956). This however presents a problem when VML contains which contains another VML, as this code previously just took whatever has been read and returned it to writerfilter, and it broke with recursion. So now try to mark recursion entry and returns the right shape. Related to 36c12c246d886b2d96d7a2d4d0c250db9d925c74 and the previous commits it reverted. Change-Id: I949a6b52ec7540aa59b047c7b6e908b10fb3bdc1 --- oox/inc/oox/vml/vmlshapecontainer.hxx | 23 +++++++++++++++++++---- oox/source/shape/ShapeContextHandler.cxx | 16 ++++++++++++---- oox/source/vml/vmlshapecontainer.cxx | 23 +++++++++++++++++++---- 3 files changed, 50 insertions(+), 12 deletions(-) (limited to 'oox') diff --git a/oox/inc/oox/vml/vmlshapecontainer.hxx b/oox/inc/oox/vml/vmlshapecontainer.hxx index 20671bbb05f3..f6be8e39dedd 100644 --- a/oox/inc/oox/vml/vmlshapecontainer.hxx +++ b/oox/inc/oox/vml/vmlshapecontainer.hxx @@ -32,6 +32,7 @@ #include #include "oox/helper/refmap.hxx" #include "oox/helper/refvector.hxx" +#include namespace com { namespace sun { namespace star { namespace drawing { class XShapes; } @@ -92,16 +93,29 @@ public: template< typename Functor > const ShapeBase* findShape( const Functor& rFunctor ) const; - /** Returns the first shape in the collection (Word only). */ - const ShapeBase* getFirstShape() const; + /** + (Word only) Returns the last shape in the collection, if it is after the last + mark from pushMark(), and removes it. + */ + boost::shared_ptr< ShapeBase > takeLastShape(); + /** + Adds a recursion mark to the stack. It is possible that a shape contains + which contains another shape, and writerfilter needs to know which shape is from the inner + ooxml context and which from the outer ooxml context, while it is necessary to keep + at least shape types across such blocks. Therefore this function marks beginning + of each shape xml block, and takeLastShape() returns only shapes from this block. + */ + void pushMark(); + /** + Removes a recursion mark. + */ + void popMark(); /** Creates and inserts all UNO shapes into the passed container. */ void convertAndInsert( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor = 0 ) const; - inline void clearShapes( ) { maShapes.clear( ); } - private: typedef RefVector< ShapeType > ShapeTypeVector; typedef RefVector< ShapeBase > ShapeVector; @@ -113,6 +127,7 @@ private: ShapeVector maShapes; ///< All shape definitions. ShapeTypeMap maTypesById; ///< All shape templates mapped by identifier. ShapeMap maShapesById; ///< All shape definitions mapped by identifier. + std::stack< size_t > markStack; ///< Recursion marks from pushMark()/popMark(). }; // ---------------------------------------------------------------------------- diff --git a/oox/source/shape/ShapeContextHandler.cxx b/oox/source/shape/ShapeContextHandler.cxx index 04e2330ca14d..418ca7ca585a 100644 --- a/oox/source/shape/ShapeContextHandler.cxx +++ b/oox/source/shape/ShapeContextHandler.cxx @@ -190,6 +190,11 @@ void SAL_CALL ShapeContextHandler::startFastElement createFastChildContext(Element, Attribs); } + // Entering VML block (startFastElement() is called for the outermost tag), + // handle possible recursion. + if ( getContextHandler() == getDrawingShapeContext() ) + mpDrawing->getShapes().pushMark(); + uno::Reference xContextHandler(getContextHandler()); if (xContextHandler.is()) @@ -201,6 +206,9 @@ void SAL_CALL ShapeContextHandler::startUnknownElement const uno::Reference< xml::sax::XFastAttributeList > & Attribs) throw (uno::RuntimeException, xml::sax::SAXException) { + if ( getContextHandler() == getDrawingShapeContext() ) + mpDrawing->getShapes().pushMark(); + uno::Reference xContextHandler(getContextHandler()); if (xContextHandler.is()) @@ -280,11 +288,11 @@ ShapeContextHandler::getShape() throw (uno::RuntimeException) if ( getContextHandler() == getDrawingShapeContext() ) { mpDrawing->finalizeFragmentImport(); - if( const ::oox::vml::ShapeBase* pShape = mpDrawing->getShapes().getFirstShape() ) - { + if( boost::shared_ptr< vml::ShapeBase > pShape = mpDrawing->getShapes().takeLastShape() ) xResult = pShape->convertAndInsert( xShapes ); - mpDrawing->getShapes( ).clearShapes( ); - } + // Only now remove the recursion mark, because getShape() is called in writerfilter + // after endFastElement(). + mpDrawing->getShapes().popMark(); } else if (mxDiagramShapeContext.is()) { diff --git a/oox/source/vml/vmlshapecontainer.cxx b/oox/source/vml/vmlshapecontainer.cxx index 0309839a9817..c30994c5cfc8 100644 --- a/oox/source/vml/vmlshapecontainer.cxx +++ b/oox/source/vml/vmlshapecontainer.cxx @@ -118,11 +118,26 @@ const ShapeBase* ShapeContainer::getShapeById( const OUString& rShapeId, bool bD return 0; } -const ShapeBase* ShapeContainer::getFirstShape() const +boost::shared_ptr< ShapeBase > ShapeContainer::takeLastShape() { - OSL_ENSURE( mrDrawing.getType() == VMLDRAWING_WORD, "ShapeContainer::getFirstShape - illegal call, Word filter only" ); - OSL_ENSURE( maShapes.size() == 1, "ShapeContainer::getFirstShape - single shape expected" ); - return maShapes.get( 0 ).get(); + OSL_ENSURE( mrDrawing.getType() == VMLDRAWING_WORD, "ShapeContainer::takeLastShape - illegal call, Word filter only" ); + assert( !markStack.empty()); + if( markStack.top() >= maShapes.size()) + return boost::shared_ptr< ShapeBase >(); + boost::shared_ptr< ShapeBase > ret = maShapes.back(); + maShapes.pop_back(); + return ret; +} + +void ShapeContainer::pushMark() +{ + markStack.push( maShapes.size()); +} + +void ShapeContainer::popMark() +{ + assert( !markStack.empty()); + markStack.pop(); } void ShapeContainer::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const -- cgit v1.2.3