summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oox/inc/oox/vml/vmlshapecontainer.hxx23
-rw-r--r--oox/source/shape/ShapeContextHandler.cxx16
-rw-r--r--oox/source/vml/vmlshapecontainer.cxx23
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