[Libreoffice-commits] core.git: 3 commits - filter/source oox/source sw/qa sw/source

Zolnai Tamás tamas.zolnai at collabora.com
Sun Feb 16 17:47:00 CET 2014


 filter/source/msfilter/escherex.cxx                       |    2 
 oox/source/export/drawingml.cxx                           |   55 ++----
 sw/qa/extras/ooxmlexport/data/nested-text-frames.odt      |binary
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx                  |   12 +
 sw/qa/extras/ooxmlimport/data/floating-tables-anchor.docx |binary
 sw/qa/extras/ooxmlimport/ooxmlimport.cxx                  |   15 +
 sw/source/core/unocore/unotext.cxx                        |   22 +-
 sw/source/filter/ww8/docxattributeoutput.cxx              |  112 +++++++-------
 sw/source/filter/ww8/docxattributeoutput.hxx              |    4 
 9 files changed, 130 insertions(+), 92 deletions(-)

New commits:
commit c7c761455fbdece36c4fb7cfb9bdd4495e80ddba
Author: Zolnai Tamás <tamas.zolnai at collabora.com>
Date:   Sun Feb 16 17:37:13 2014 +0100

    drawingML export: make WritePolyPolygon robuster
    
    Make sure a:cubicBezTo conatins three a:pt elements.
    
    escherex: It seems a cubic bezier curve last point has
    a POLY_NORMAL flag and not POLY_CONTROL.
    
    Change-Id: Id6dc2160c7ae171a720e4a1aa9161cef2b3b9413

diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
index 25a853a..a6423fc 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -1969,7 +1969,7 @@ PolyPolygon EscherPropertyContainer::GetPolyPolygon( const ::com::sun::star::uno
                                 {
                                     aPolygon.SetFlags( nPointIndex, POLY_CONTROL);
                                     aPolygon.SetFlags( nPointIndex+1, POLY_CONTROL);
-                                    aPolygon.SetFlags( nPointIndex+2, POLY_CONTROL);
+                                    aPolygon.SetFlags( nPointIndex+2, POLY_NORMAL);
                                     nPointIndex += 3;
                                     break;
                                 }
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index d03a0d8..c4e79a4 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -1793,7 +1793,6 @@ void DrawingML::WritePolyPolygon( const PolyPolygon& rPolyPolygon )
 
         const Polygon& rPoly = rPolyPolygon[ i ];
         Rectangle aRect( rPoly.GetBoundRect() );
-        sal_Bool bBezier = sal_False;
 
         mpFS->startElementNS( XML_a, XML_path,
                               XML_w, I64S( aRect.GetWidth() ),
@@ -1812,46 +1811,36 @@ void DrawingML::WritePolyPolygon( const PolyPolygon& rPolyPolygon )
             mpFS->endElementNS( XML_a, XML_moveTo );
         }
 
-        sal_Int32 nCounter = 0 ;
         for( sal_uInt16 j = 1; j < rPoly.GetSize(); j ++ )
         {
             enum PolyFlags flags = rPoly.GetFlags(j);
-            if( flags == POLY_CONTROL && !bBezier )
+            if( flags == POLY_CONTROL )
             {
-                mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
-                bBezier = sal_True;
-            }
-            else if( flags == POLY_NORMAL && !bBezier )
-            {
-                mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
-                ++nCounter ;
-            }
+                // a:cubicBezTo can only contain 3 a:pt elements, so we need to make sure of this
+                if( j+2 < rPoly.GetSize() && rPoly.GetFlags(j+1) == POLY_CONTROL && rPoly.GetFlags(j+2) != POLY_CONTROL )
+                {
 
-            mpFS->singleElementNS( XML_a, XML_pt,
-                                   XML_x, I64S( rPoly[j].X() - aRect.Left() ),
-                                   XML_y, I64S( rPoly[j].Y() - aRect.Top() ),
-                                   FSEND );
+                    mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
+                    for( sal_uInt8 k = 0; k <= 2; ++k )
+                    {
+                        mpFS->singleElementNS( XML_a, XML_pt,
+                                               XML_x, I64S( rPoly[j+k].X() - aRect.Left() ),
+                                               XML_y, I64S( rPoly[j+k].Y() - aRect.Top() ),
+                                               FSEND );
 
-            if( ( flags == POLY_NORMAL || flags == POLY_SYMMTR || j == rPoly.GetSize() - 1) && bBezier )
-            {
-                mpFS->endElementNS( XML_a, XML_cubicBezTo );
-                bBezier = sal_False;
+                    }
+                    mpFS->endElementNS( XML_a, XML_cubicBezTo );
+                    j += 2;
+                }
             }
-            else if( flags == POLY_NORMAL && !bBezier )
-                mpFS->endElementNS( XML_a, XML_lnTo );
-
-            /* ( j % 3 == 0 ) will fail to address the iterations
-               that have been dedicated to XML_lnTo in case if the
-               flag is POLY_NORMAL.
-               Similarly the sequence would go wrong if we do not
-               make the flag bBezier as false after ending the element.
-            */
-            else if( bBezier && ( ( j - nCounter ) % 3 ) == 0 )
+            else if( flags == POLY_NORMAL )
             {
-                // //a:cubicBezTo can only contain 3 //a:pt elements, so we
-                // need to break things up...
-                mpFS->endElementNS( XML_a, XML_cubicBezTo );
-                bBezier = sal_False;
+                mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
+                mpFS->singleElementNS( XML_a, XML_pt,
+                                       XML_x, I64S( rPoly[j].X() - aRect.Left() ),
+                                       XML_y, I64S( rPoly[j].Y() - aRect.Top() ),
+                                       FSEND );
+                mpFS->endElementNS( XML_a, XML_lnTo );
             }
         }
 
commit 6357031a3269ea191965469a8fe6867e7335e292
Author: Zolnai Tamás <tamas.zolnai at collabora.com>
Date:   Sun Feb 16 14:27:00 2014 +0100

    DOCX import: floating tables belong to the same paragraph
    
    When two floating tables were belong to the same paragraph,
    import makes one of them anchored to the other instead of
    anchorig both to the corresponding paragraph.
    
    Modifications:
    - Check the whole text range for anchored frames not
    just one point of it.
    - Save frame format's name because SwFrmFmt pointers can
    become invalid.
    
    Change-Id: Ide7c894065b619095a8e713ff0622bbea4f199b6

diff --git a/sw/qa/extras/ooxmlimport/data/floating-tables-anchor.docx b/sw/qa/extras/ooxmlimport/data/floating-tables-anchor.docx
new file mode 100644
index 0000000..70dc7cf
Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/floating-tables-anchor.docx differ
diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
index f1e7abd..fb2904a 100644
--- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
+++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
@@ -1856,6 +1856,21 @@ DECLARE_OOXMLIMPORT_TEST(testFdo69656, "Table_cell_auto_width_fdo69656.docx")
     uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables( ), uno::UNO_QUERY);
     CPPUNIT_ASSERT_EQUAL(sal_Int32(8154), getProperty<sal_Int32>(xTables->getByIndex(0), "Width"));
 }
+
+DECLARE_OOXMLIMPORT_TEST(testFloatingTablesAnchor, "floating-tables-anchor.docx")
+{
+    // Problem was one of the two text frames was anchored to the other text frame
+    // Both frames should be anchored to the paragraph with the text "Anchor point"
+    uno::Reference<text::XTextContent> xTextContent(getShape(1), uno::UNO_QUERY);
+    uno::Reference<text::XTextRange> xRange(xTextContent->getAnchor(), uno::UNO_QUERY);
+    uno::Reference<text::XText> xText(xRange->getText(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString("Anchor point"), xText->getString());
+
+    xTextContent.set(getShape(2), uno::UNO_QUERY);
+    xRange.set(xTextContent->getAnchor(), uno::UNO_QUERY);
+    xText.set(xRange->getText(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString("Anchor point"), xText->getString());
+}
 #endif
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx
index 51a24c00..bfbbf01 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -21,6 +21,7 @@
 
 #include <memory>
 #include <iostream>
+#include <set>
 
 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
 #include <com/sun/star/text/ControlCharacter.hpp>
@@ -1662,14 +1663,15 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
     pEndPam.reset(0);
 
     // see if there are frames already anchored to this node
-    std::vector<SwFrmFmt*> aAnchoredFrames;
+    std::set<OUString> aAnchoredFrames;
     for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrmFmts()->size(); ++i)
     {
         SwFrmFmt* pFrmFmt = (*m_pImpl->m_pDoc->GetSpzFrmFmts())[i];
         const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
         if (FLY_AT_PARA == rAnchor.GetAnchorId() &&
-                aStartPam.GetNode()->GetIndex() == rAnchor.GetCntntAnchor()->nNode.GetIndex())
-            aAnchoredFrames.push_back(pFrmFmt);
+                aStartPam.Start()->nNode.GetIndex() <= rAnchor.GetCntntAnchor()->nNode.GetIndex() &&
+                aStartPam.End()->nNode.GetIndex() >= rAnchor.GetCntntAnchor()->nNode.GetIndex())
+            aAnchoredFrames.insert(pFrmFmt->GetName());
     }
 
     SwXTextFrame *const pNewFrame = new SwXTextFrame(m_pImpl->m_pDoc);
@@ -1709,12 +1711,16 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
                         aNewAnchor, *pNewFrame->GetFrmFmt() );
 
                     // also move frames anchored to us
-                    for (std::vector<SwFrmFmt*>::iterator i = aAnchoredFrames.begin(); i != aAnchoredFrames.end(); ++i)
+                    for (size_t i = 0; i < m_pImpl->m_pDoc->GetSpzFrmFmts()->size(); ++i)
                     {
-                        // copy the anchor to the next paragraph
-                        SwFmtAnchor aAnchor((*i)->GetAnchor());
-                        aAnchor.SetAnchor(aMovePam.Start());
-                        m_pImpl->m_pDoc->SetAttr(aAnchor, *(*i));
+                        SwFrmFmt* pFrmFmt = (*m_pImpl->m_pDoc->GetSpzFrmFmts())[i];
+                        if( aAnchoredFrames.find( pFrmFmt->GetName() ) != aAnchoredFrames.end() )
+                        {
+                            // copy the anchor to the next paragraph
+                            SwFmtAnchor aAnchor(pFrmFmt->GetAnchor());
+                            aAnchor.SetAnchor(aMovePam.Start());
+                            m_pImpl->m_pDoc->SetAttr(aAnchor, *pFrmFmt);
+                        }
                     }
                 }
             }
commit 05955dd2096c29853f831d5d16b86c7b7ca00b28
Author: Zolnai Tamás <tamas.zolnai at collabora.com>
Date:   Sun Feb 16 14:20:34 2014 +0100

    DOCX export: nested text frames
    
    In Word it is not allowed to anchor a shape to
    an onther shape.
    That's why this code write text boxes only on the first level,
    nested frames is also written out on the same level because
    writeDMLText/WriteVMLText will push nested frames
    into m_aFramesOfParagraph's back.
    
    Change-Id: Ie1956ac9ac0ed56ff9611ff9763eb454f02558b9

diff --git a/sw/qa/extras/ooxmlexport/data/nested-text-frames.odt b/sw/qa/extras/ooxmlexport/data/nested-text-frames.odt
new file mode 100644
index 0000000..4c38e1f
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/nested-text-frames.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index ab4e745..3710bc2 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -3236,6 +3236,18 @@ DECLARE_OOXMLEXPORT_TEST(testChartInFooter, "chart-in-footer.docx")
     }
 }
 
+DECLARE_OOXMLEXPORT_TEST(testNestedTextFrames, "nested-text-frames.odt")
+{
+    // First problem was LO crashed during export (crash test)
+
+    // Second problem was LO made file corruption, writing out nested text boxes, which can't be handled by Word.
+    // So test that all three exported text boxes are on the same level
+    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
+    if (!pXmlDoc)
+        return;
+    assertXPath(pXmlDoc,"/w:document/w:body/w:p/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:txbx/w:txbxContent/w:p/w:r/w:t", 3);
+}
+
 #endif
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 6e306e7..f376d52 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -277,60 +277,65 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
     m_pSerializer->mergeTopMarks();
 
     // Write the anchored frame if any
-    // Make a copy and clear the original early, as this method is called
-    // recursively for in-frame paragraphs
-    std::vector<sw::Frame> aParentFrames = m_aParentFrames;
-    m_aParentFrames.clear();
-    for (size_t i = 0; i < aParentFrames.size(); ++i)
+    // Word can't handle nested text boxes, so write them on the same level.
+    ++m_nTextFrameLevel;
+    if( m_nTextFrameLevel == 1 )
     {
-        sw::Frame* pParentFrame = &aParentFrames[i];
-        m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+        for (size_t nIndex = 0; nIndex < m_aFramesOfParagraph.size(); ++nIndex)
+        {
+            sw::Frame aFrame = m_aFramesOfParagraph[nIndex];
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
 
-        m_pSerializer->startElementNS(XML_mc, XML_AlternateContent, FSEND);
-        m_pSerializer->startElementNS(XML_mc, XML_Choice,
-                XML_Requires, "wps",
-                FSEND);
-        /** FDO#71834 :
-           We should probably be renaming the function
-           switchHeaderFooter to something like SaveRetrieveTableReference.
-           Save the table reference attributes before calling WriteDMLTextFrame,
-           otherwise the StartParagraph function will use the previous existing
-           table reference attributes since the variable is being shared.
-        */
-        switchHeaderFooter(true,1);
-        /** Save the table info's before writing the shape
-            as there might be a new table that might get
-            spawned from within the VML & DML block and alter
-            the contents.
-        */
-        ww8::WW8TableInfo::Pointer_t pOldTableInfo = m_rExport.mpTableInfo;
-        //Reset the table infos after saving.
-        m_rExport.mpTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo());
-
-        m_rExport.SdrExporter().writeDMLTextFrame(pParentFrame, m_anchorId++);
-        m_pSerializer->endElementNS(XML_mc, XML_Choice);
-
-        // Reset table infos, otherwise the depth of the cells will be incorrect,
-        // in case the text frame had table(s) and we try to export the
-        // same table second time.
-        m_rExport.mpTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo());
-        //reset the tableReference.
-        switchHeaderFooter(false,0);
-
-        m_pSerializer->startElementNS(XML_mc, XML_Fallback, FSEND);
-        m_rExport.SdrExporter().writeVMLTextFrame(pParentFrame);
-        /* FDO#71834 :Restore the data here after having written the Shape
-           for further processing.
-        */
-        switchHeaderFooter(false,-1);
-        m_rExport.mpTableInfo = pOldTableInfo;
+            m_pSerializer->startElementNS(XML_mc, XML_AlternateContent, FSEND);
+            m_pSerializer->startElementNS(XML_mc, XML_Choice,
+                    XML_Requires, "wps",
+                    FSEND);
+            /** FDO#71834 :
+               We should probably be renaming the function
+               switchHeaderFooter to something like SaveRetrieveTableReference.
+               Save the table reference attributes before calling WriteDMLTextFrame,
+               otherwise the StartParagraph function will use the previous existing
+               table reference attributes since the variable is being shared.
+            */
+            switchHeaderFooter(true,1);
+            /** Save the table info's before writing the shape
+                as there might be a new table that might get
+                spawned from within the VML & DML block and alter
+                the contents.
+            */
+            ww8::WW8TableInfo::Pointer_t pOldTableInfo = m_rExport.mpTableInfo;
+            //Reset the table infos after saving.
+            m_rExport.mpTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo());
+
+            m_rExport.SdrExporter().writeDMLTextFrame(&aFrame, m_anchorId++);
+            m_pSerializer->endElementNS(XML_mc, XML_Choice);
+
+            // Reset table infos, otherwise the depth of the cells will be incorrect,
+            // in case the text frame had table(s) and we try to export the
+            // same table second time.
+            m_rExport.mpTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo());
+            //reset the tableReference.
+            switchHeaderFooter(false,0);
+
+            m_pSerializer->startElementNS(XML_mc, XML_Fallback, FSEND);
+            m_rExport.SdrExporter().writeVMLTextFrame(&aFrame);
+            /* FDO#71834 :Restore the data here after having written the Shape
+               for further processing.
+            */
+            switchHeaderFooter(false,-1);
+            m_rExport.mpTableInfo = pOldTableInfo;
+
+            m_pSerializer->endElementNS(XML_mc, XML_Fallback);
+            m_pSerializer->endElementNS(XML_mc, XML_AlternateContent);
 
-        m_pSerializer->endElementNS(XML_mc, XML_Fallback);
-        m_pSerializer->endElementNS(XML_mc, XML_AlternateContent);
+            m_pSerializer->endElementNS( XML_w, XML_r );
+        }
 
-        m_pSerializer->endElementNS( XML_w, XML_r );
+        m_aFramesOfParagraph.clear();
     }
 
+    --m_nTextFrameLevel;
+
     m_pSerializer->endElementNS( XML_w, XML_p );
 
     // Check for end of cell, rows, tables here
@@ -3381,7 +3386,15 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po
         case sw::Frame::eTxtBox:
             {
                 // The frame output is postponed to the end of the anchor paragraph
-                m_aParentFrames.push_back(sw::Frame(rFrame));
+                bool bDuplicate = false;
+                for( unsigned nIndex = 0; nIndex < m_aFramesOfParagraph.size(); ++nIndex )
+                {
+                    if( rFrame.GetFrmFmt().GetName() == m_aFramesOfParagraph[nIndex].GetFrmFmt().GetName() )
+                        bDuplicate = true;
+                }
+
+                if( !bDuplicate )
+                    m_aFramesOfParagraph.push_back(sw::Frame(rFrame));
             }
             break;
         case sw::Frame::eOle:
@@ -6320,6 +6333,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri
       m_pTableWrt( NULL ),
       m_bParagraphOpened( false ),
       m_nColBreakStatus( COLBRK_NONE ),
+      m_nTextFrameLevel( 0 ),
       m_closeHyperlinkInThisRun( false ),
       m_closeHyperlinkInPreviousRun( false ),
       m_startedHyperlink( false ),
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 8d167c0..e25606d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -744,7 +744,9 @@ private:
     // beginning of the next paragraph
     DocxColBreakStatus m_nColBreakStatus;
 
-    std::vector<sw::Frame> m_aParentFrames;
+    std::vector<sw::Frame> m_aFramesOfParagraph;
+    sal_Int32 m_nTextFrameLevel;
+
     // close of hyperlink needed
     bool m_closeHyperlinkInThisRun;
     bool m_closeHyperlinkInPreviousRun;


More information about the Libreoffice-commits mailing list