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.zol...@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.zol...@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.zol...@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;
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits