diff options
-rw-r--r-- | oox/inc/oox/vml/vmlshapecontainer.hxx | 23 | ||||
-rw-r--r-- | oox/source/shape/ShapeContextHandler.cxx | 16 | ||||
-rw-r--r-- | oox/source/vml/vmlshapecontainer.cxx | 23 |
3 files changed, 50 insertions, 12 deletions
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 <com/sun/star/awt/Rectangle.hpp> #include "oox/helper/refmap.hxx" #include "oox/helper/refvector.hxx" +#include <stack> 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 <w:txbxContent> + 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<XFastContextHandler> 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<XFastContextHandler> 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 |