From 4818c0ea0d90368ab4a18d3737261e1cca683f3f Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@suse.cz>
Date: Mon, 13 Aug 2012 17:36:50 +0200
Subject: [PATCH 1/1] fdo#53113 docx filter loses shape containing text

Upstream commits:
  aaddc56c4cc7695170f718dc689093e7849da9f2
  0e91441764a089e52fbc13dec835fd22c17b5444
  d195c45f01a8995cdbb3f2f704ad5c787c02d401
  3906777d1d3c08ec0dce85c7cb574bd159240208
  048d1f5568c3c34a0d1f42f36ff06218b1a5100f

Change-Id: I29988cae08635a8fa686dcfa8a09f9ba13f22e55
---
 oox/Library_oox.mk                           |    1 +
 oox/inc/oox/export/vmlexport.hxx             |   28 +++++++++-
 oox/source/export/vmlexport.cxx              |   72 +++++++++++++++++++++++---
 sw/source/filter/ww8/docxattributeoutput.cxx |   51 +++++++++++++++++-
 sw/source/filter/ww8/docxattributeoutput.hxx |    7 ++-
 sw/source/filter/ww8/docxexport.cxx          |    2 +-
 6 files changed, 150 insertions(+), 11 deletions(-)

diff --git a/oox/Library_oox.mk b/oox/Library_oox.mk
index 1906fc2..4767dbc 100644
--- a/oox/Library_oox.mk
+++ b/oox/Library_oox.mk
@@ -60,6 +60,7 @@ $(eval $(call gb_Library_add_linked_libs,oox,\
     comphelper \
     cppu \
     cppuhelper \
+    editeng \
     msfilter \
     sal \
     sax \
diff --git a/oox/inc/oox/export/vmlexport.hxx b/oox/inc/oox/export/vmlexport.hxx
index f748755..ad53fca 100644
--- a/oox/inc/oox/export/vmlexport.hxx
+++ b/oox/inc/oox/export/vmlexport.hxx
@@ -26,9 +26,14 @@
  *
  ************************************************************************/
 
+#ifndef _OOX_EXPORT_VMLEXPORT_HXX_
+#define _OOX_EXPORT_VMLEXPORT_HXX_
+
 #include <oox/dllapi.h>
+#include <oox/export/drawingml.hxx>
 #include <sax/fshelper.hxx>
 #include <filter/msfilter/escherex.hxx>
+#include <editeng/outlobj.hxx>
 
 namespace rtl {
     class OString;
@@ -39,11 +44,28 @@ namespace oox {
 
 namespace vml {
 
+/// Interface to be implemented by the parent exporter that knows how to handle shape text.
+class OOX_DLLPUBLIC VMLTextExport
+{
+public:
+    virtual void WriteOutliner(const OutlinerParaObject& rParaObj) = 0;
+    virtual oox::drawingml::DrawingML& GetDrawingML() = 0;
+protected:
+    VMLTextExport() {}
+    virtual ~VMLTextExport() {}
+};
+
 class OOX_DLLPUBLIC VMLExport : public EscherEx
 {
     /// Fast serializer to output the data
     ::sax_fastparser::FSHelperPtr m_pSerializer;
 
+    /// Parent exporter, used for text callback.
+    VMLTextExport* m_pTextExport;
+
+    /// The object we're exporting.
+    const SdrObject* m_pSdrObject;
+
     /// Fill the shape attributes as they come.
     ::sax_fastparser::FastAttributeList *m_pShapeAttrList;
 
@@ -60,7 +82,7 @@ class OOX_DLLPUBLIC VMLExport : public EscherEx
     bool *m_pShapeTypeWritten;
 
 public:
-                        VMLExport( ::sax_fastparser::FSHelperPtr pSerializer );
+                        VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport = 0 );
     virtual             ~VMLExport();
 
     ::sax_fastparser::FSHelperPtr
@@ -69,7 +91,7 @@ public:
     /// Export the sdr object as VML.
     ///
     /// Call this when you need to export the object as VML.
-    using EscherEx::AddSdrObject;
+    sal_uInt32 AddSdrObject( const SdrObject& rObj );
 
 protected:
     /// Add an attribute to the generated <v:shape/> element.
@@ -118,4 +140,6 @@ private:
 
 } // namespace oox
 
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 554d49f..006e452e 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -34,6 +34,8 @@
 #include <rtl/ustring.hxx>
 
 #include <tools/stream.hxx>
+#include <svx/svdotext.hxx>
+#include <vcl/cvtgrf.hxx>
 
 #include <cstdio>
 
@@ -64,9 +66,11 @@ public:
     virtual ~SvNullStream() {}
 };
 
-VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer )
+VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr pSerializer, VMLTextExport* pTextExport )
     : EscherEx( EscherExGlobalRef(new EscherExGlobal(0)), *( new SvNullStream ) ),
       m_pSerializer( pSerializer ),
+      m_pTextExport( pTextExport ),
+      m_pSdrObject( 0 ),
       m_pShapeAttrList( NULL ),
       m_nShapeType( ESCHER_ShpInst_Nil ),
       m_pShapeStyle( new OStringBuffer( 200 ) ),
@@ -491,9 +495,13 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                                     aPath.append( "e" );
                                     break;
                                 default:
-#if OSL_DEBUG_LEVEL > 0
-                                    fprintf( stderr, "TODO: unhandled segment '%x' in the path\n", nSeg );
-#endif
+                                    // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
+                                    for (int i = 0; i < nSeg; ++i)
+                                    {
+                                        sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
+                                        sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
+                                        aPath.append("l").append(nX).append(",").append(nY);
+                                    }
                                     break;
                             }
                         }
@@ -513,6 +521,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
             case ESCHER_Prop_fillType: // 384
             case ESCHER_Prop_fillColor: // 385
             case ESCHER_Prop_fillBackColor: // 387
+            case ESCHER_Prop_fillBlip: // 390
             case ESCHER_Prop_fNoFillHitTest: // 447
                 {
                     sal_uInt32 nValue;
@@ -525,7 +534,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                         {
                             case ESCHER_FillSolid:       pFillType = "solid"; break;
                             // TODO case ESCHER_FillPattern:     pFillType = ""; break;
-                            // TODO case ESCHER_FillTexture:     pFillType = ""; break;
+                            case ESCHER_FillTexture:     pFillType = "tile"; break;
                             // TODO case ESCHER_FillPicture:     pFillType = ""; break;
                             // TODO case ESCHER_FillShade:       pFillType = ""; break;
                             // TODO case ESCHER_FillShadeCenter: pFillType = ""; break;
@@ -549,6 +558,19 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                     if ( rProps.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
                         impl_AddColor( pAttrList, XML_color2, nValue );
 
+                    EscherPropSortStruct aStruct;
+                    if ( rProps.GetOpt( ESCHER_Prop_fillBlip, aStruct ) && m_pTextExport)
+                    {
+                        SvMemoryStream aStream;
+                        int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
+                        aStream.Write(aStruct.pBuf + nHeaderSize, aStruct.nPropSize - nHeaderSize);
+                        aStream.Seek(0);
+                        Graphic aGraphic;
+                        GraphicConverter::Import(aStream, aGraphic, CVT_PNG);
+                        OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
+                        pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
+                    }
+
                     if ( rProps.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
                         impl_AddBool( pAttrList, XML_detectmouseclick, nValue );
 
@@ -557,6 +579,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                 bAlreadyWritten[ ESCHER_Prop_fillType ] = true;
                 bAlreadyWritten[ ESCHER_Prop_fillColor ] = true;
                 bAlreadyWritten[ ESCHER_Prop_fillBackColor ] = true;
+                bAlreadyWritten[ ESCHER_Prop_fillBlip ] = true;
                 bAlreadyWritten[ ESCHER_Prop_fNoFillHitTest ] = true;
                 break;
 
@@ -667,7 +690,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
             default:
 #if OSL_DEBUG_LEVEL > 0
                 fprintf( stderr, "TODO VMLExport::Commit(), unimplemented id: %d, value: %" SAL_PRIuUINT32 ", data: [%" SAL_PRIuUINT32 ", %p]\n",
-                        it->nPropId, it->nPropValue, it->nPropSize, it->pBuf );
+                        nId, it->nPropValue, it->nPropSize, it->pBuf );
                 if ( it->nPropSize )
                 {
                     const sal_uInt8 *pIt = it->pBuf;
@@ -825,6 +848,37 @@ sal_Int32 VMLExport::StartShape()
         m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) );
     }
 
+    // now check if we have some text and we have a text exporter registered
+    const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
+    if (pTxtObj && m_pTextExport)
+    {
+        const OutlinerParaObject* pParaObj = 0;
+        bool bOwnParaObj = false;
+
+        /*
+        #i13885#
+        When the object is actively being edited, that text is not set into
+        the objects normal text object, but lives in a seperate object.
+        */
+        if (pTxtObj->IsTextEditActive())
+        {
+            pParaObj = pTxtObj->GetEditOutlinerParaObject();
+            bOwnParaObj = true;
+        }
+        else
+        {
+            pParaObj = pTxtObj->GetOutlinerParaObject();
+        }
+
+        if( pParaObj )
+        {
+            // this is reached only in case some text is attached to the shape
+            m_pTextExport->WriteOutliner(*pParaObj);
+            if( bOwnParaObj )
+                delete pParaObj;
+        }
+    }
+
     return nShapeElement;
 }
 
@@ -837,4 +891,10 @@ void VMLExport::EndShape( sal_Int32 nShapeElement )
     }
 }
 
+sal_uInt32 VMLExport::AddSdrObject( const SdrObject& rObj )
+{
+    m_pSdrObject = &rObj;
+    return EscherEx::AddSdrObject(rObj);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 100a1e1..12bb58d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -44,7 +44,6 @@
 #include <oox/token/tokens.hxx>
 #include <oox/export/drawingml.hxx>
 #include <oox/export/utils.hxx>
-#include <oox/export/vmlexport.hxx>
 #include <oox/mathml/export.hxx>
 
 #include <i18npool/mslangid.hxx>
@@ -93,6 +92,7 @@
 #include <editeng/blnkitem.hxx>
 #include <editeng/charhiddenitem.hxx>
 #include <editeng/opaqitem.hxx>
+#include <editeng/editobj.hxx>
 #include <svx/svdmodel.hxx>
 #include <svx/svdobj.hxx>
 #include <sfx2/sfxbasemodel.hxx>
@@ -2408,6 +2408,55 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po
     m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
 }
 
+void DocxAttributeOutput::WriteOutliner(const OutlinerParaObject& rParaObj)
+{
+    const EditTextObject& rEditObj = rParaObj.GetTextObject();
+    MSWord_SdrAttrIter aAttrIter( m_rExport, rEditObj, TXT_HFTXTBOX );
+
+    sal_uInt16 nPara = rEditObj.GetParagraphCount();
+
+    m_pSerializer->startElementNS( XML_w, XML_textbox, FSEND );
+    m_pSerializer->startElementNS( XML_w, XML_txbxContent, FSEND );
+    for (sal_uInt16 n = 0; n < nPara; ++n)
+    {
+        if( n )
+            aAttrIter.NextPara( n );
+
+        String aStr( rEditObj.GetText( n ));
+        xub_StrLen nAktPos = 0;
+        xub_StrLen nEnd = aStr.Len();
+
+        m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
+        do {
+            xub_StrLen nNextAttr = aAttrIter.WhereNext();
+            if( nNextAttr > nEnd )
+                nNextAttr = nEnd;
+
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+            bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
+            if( !bTxtAtr )
+            {
+                String aOut( aStr.Copy( nAktPos, nNextAttr - nAktPos ) );
+                RunText(aOut);
+            }
+
+            m_pSerializer->endElementNS( XML_w, XML_r );
+
+            nAktPos = nNextAttr;
+            aAttrIter.NextPos();
+        }
+        while( nAktPos < nEnd );
+        m_pSerializer->endElementNS( XML_w, XML_p );
+    }
+    m_pSerializer->endElementNS( XML_w, XML_txbxContent );
+    m_pSerializer->endElementNS( XML_w, XML_textbox );
+}
+
+oox::drawingml::DrawingML& DocxAttributeOutput::GetDrawingML()
+{
+    return m_rDrawingML;
+}
+
 void DocxAttributeOutput::StartStyle( const String& rName, bool bPapFmt,
         sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 /*nWwId*/, sal_uInt16 nId, bool bAutoUpdate )
 {
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 4d1b5a6..7256d90 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -42,6 +42,7 @@
 
 #include <vector>
 #include <boost/scoped_ptr.hpp>
+#include <oox/export/vmlexport.hxx>
 
 class SwGrfNode;
 class SdrObject;
@@ -68,7 +69,7 @@ enum DocxColBreakStatus
 };
 
 /// The class that has handlers for various resource types when exporting as DOCX.
-class DocxAttributeOutput : public AttributeOutputBase
+class DocxAttributeOutput : public AttributeOutputBase, public oox::vml::VMLTextExport
 {
 public:
     /// Export the state of RTL/CJK.
@@ -631,6 +632,10 @@ public:
 
     bool HasPostitFields() const;
     void WritePostitFields();
+
+    /// VMLTextExport
+    virtual void WriteOutliner(const OutlinerParaObject& rParaObj);
+    virtual oox::drawingml::DrawingML& GetDrawingML();
 };
 
 #endif // _DOCXATTRIBUTEOUTPUT_HXX_
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 98049c6..6759a68 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -826,7 +826,7 @@ DocxExport::DocxExport( DocxExportFilter *pFilter, SwDoc *pDocument, SwPaM *pCur
     m_pAttrOutput = new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML );
 
     // the related VMLExport
-    m_pVMLExport = new VMLExport( m_pDocumentFS );
+    m_pVMLExport = new VMLExport( m_pDocumentFS, m_pAttrOutput );
 }
 
 DocxExport::~DocxExport()
-- 
1.7.10.4

