diff options
author | Umesh Kadam <umesh.kadam@synerzip.com> | 2014-05-15 23:02:34 +0530 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2014-05-22 02:31:53 -0500 |
commit | 80fd9fb7209cfd5c0622ee99d59e42e6db32f021 (patch) | |
tree | 98e21c1b45b4ac9600112b158b392ad36b9c0deb /sw | |
parent | 4c05911b7ef25505acacbb81053a56cf428e9edc (diff) |
fdo#78333 : SdtContent and a Shape overlapping causes corruption
- Normally if there is a case where text/shape is overlapped with (another)
shape then LO used to write the text and the AlternateContent in the same run.
- This is supported in MSO and there is no visual difference.
- But in case if the SdtContent(with text) is overlapped with the Shape then LO
processes sdtContent as a text and ends up putting the alternateContent and the
text in a single run. Ultimately it includes the entire run in a SdtContent,
which is incorrect.
- The fix checks for the aforementioned scenario and puts them in a different run
and also restricts the sdtContent being written in an invalid AlternateContent.
Change-Id: I36f4cdb1b583523dd8f717ae094bdf09c7a61f62
Reviewed-on: https://gerrit.libreoffice.org/9374
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx | bin | 0 -> 29760 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 9 | ||||
-rw-r--r-- | sw/source/filter/ww8/attributeoutputbase.hxx | 9 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 69 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 6 | ||||
-rw-r--r-- | sw/source/filter/ww8/wrtw8nds.cxx | 78 | ||||
-rw-r--r-- | sw/source/filter/ww8/wrtww8.hxx | 13 |
7 files changed, 174 insertions, 10 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx b/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx Binary files differnew file mode 100644 index 000000000000..e1ec07489e66 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index 7a69e6769e5f..16d13a2e90a8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -2052,6 +2052,15 @@ DECLARE_OOXMLEXPORT_TEST(testFileOpenInputOutputError,"floatingtbl_with_formula. assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:pStyle", "val", "Normal"); } +DECLARE_OOXMLEXPORT_TEST(testSdtAndShapeOverlapping,"ShapeOverlappingWithSdt.docx") +{ + xmlDocPtr pXmlDoc = parseExport("word/document.xml"); + if (!pXmlDoc) + return; + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[1]/mc:AlternateContent"); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt[1]/w:sdtContent[1]/w:r[1]/w:t[1]"); +} + DECLARE_OOXMLEXPORT_TEST(testRelorientation, "relorientation.docx") { uno::Reference<drawing::XShape> xShape = getShape(1); diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx index 5a25c86a5fe4..d2df9c08be8c 100644 --- a/sw/source/filter/ww8/attributeoutputbase.hxx +++ b/sw/source/filter/ww8/attributeoutputbase.hxx @@ -309,6 +309,15 @@ public: /// Has different headers/footers for the title page. virtual void SectionTitlePage() = 0; + /// If the node has an anchor linked. + virtual void SetAnchorIsLinkedToNode( bool /*bAnchorLinkedToNode*/){}; + + /// Is processing of fly postponed ? + virtual bool IsFlyProcessingPostponed(){ return false; }; + + /// Reset the flag for FlyProcessing + virtual void ResetFlyProcessingFlag(){}; + /// Description of the page borders. virtual void SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmFmt* pFirstPageFmt ) = 0; diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 96602c3ff468..fb5933dd72f3 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -287,6 +287,20 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText m_bIsFirstParagraph = false; } +static void lcl_deleteAndResetTheLists( ::sax_fastparser::FastAttributeList* &pSdtPrTokenChildren, ::sax_fastparser::FastAttributeList* &pSdtPrDataBindingAttrs) +{ + if( pSdtPrTokenChildren ) + { + delete pSdtPrTokenChildren ; + pSdtPrTokenChildren = NULL; + } + if( pSdtPrDataBindingAttrs ) + { + delete pSdtPrDataBindingAttrs; + pSdtPrDataBindingAttrs = NULL; + } +} + void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) { // write the paragraph properties + the run, already in the correct order @@ -382,8 +396,16 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT } m_pSerializer->endElementNS( XML_w, XML_p ); + if( !m_bAnchorLinkedToNode ) + WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs ); + else + { + //These should be written out to the actual Node and not to the anchor. + //Clear them as they will be repopulated when the node is processed. + m_nParagraphSdtPrToken = 0; + lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs ); + } - WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs ); //sdtcontent is written so Set m_bParagraphHasDrawing to false m_rExport.SdrExporter().setParagraphHasDrawing( false ); m_bRunTextIsOn = false; @@ -701,6 +723,21 @@ void DocxAttributeOutput::EndParagraphProperties( const SfxItemSet* pParagraphMa m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); } +void DocxAttributeOutput::SetAnchorIsLinkedToNode( bool bAnchorLinkedToNode ) +{ + m_bAnchorLinkedToNode = bAnchorLinkedToNode ; +} + +void DocxAttributeOutput::ResetFlyProcessingFlag() +{ + m_bPostponedProcessingFly = false ; +} + +bool DocxAttributeOutput::IsFlyProcessingPostponed() +{ + return m_bPostponedProcessingFly; +} + void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bSingleEmptyRun*/ ) { // Don't start redline data here, possibly there is a hyperlink later, and @@ -858,7 +895,15 @@ void DocxAttributeOutput::EndRun() EndRedline( m_pRedlineData ); // enclose in a sdt block, if necessary - WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs ); + if ( !m_bAnchorLinkedToNode ) + WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs ); + else + { + //These should be written out to the actual Node and not to the anchor. + //Clear them as they will be repopulated when the node is processed. + m_nRunSdtPrToken = 0; + lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs ); + } m_pSerializer->mergeTopMarks(); WritePostponedMath(); @@ -4270,9 +4315,13 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po if ( pGrfNode ) { if( m_postponedGraphic == NULL ) + { + m_bPostponedProcessingFly = false ; FlyFrameGraphic( pGrfNode, rFrame.GetLayoutSize(), 0, 0, pSdrObj); + } else // we are writing out attributes, but w:drawing should not be inside w:rPr, { // so write it out later + m_bPostponedProcessingFly = true ; m_postponedGraphic->push_back( PostponedGraphic( pGrfNode, rFrame.GetLayoutSize(), 0, 0, pSdrObj)); } } @@ -4286,9 +4335,13 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po if ( IsDiagram( pSdrObj ) ) { if ( m_postponedDiagram == NULL ) + { + m_bPostponedProcessingFly = false ; m_rExport.SdrExporter().writeDiagram( pSdrObj, rFrame.GetFrmFmt(), m_anchorId++); + } else // we are writing out attributes, but w:drawing should not be inside w:rPr, { // so write it out later + m_bPostponedProcessingFly = true ; m_postponedDiagram->push_back( PostponedDiagram( pSdrObj, &(rFrame.GetFrmFmt()) )); } } @@ -4302,6 +4355,8 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po m_rExport.SdrExporter().writeDMLDrawing( pSdrObj, &rFrame.GetFrmFmt(), m_anchorId++); else m_rExport.SdrExporter().writeDMLAndVMLDrawing( pSdrObj, rFrame.GetFrmFmt(), rNdTopLeft, m_anchorId++); + + m_bPostponedProcessingFly = false ; } // IsAlternateContentChoiceOpen() : check is to ensure that only one object is getting added. Without this check, plus one obejct gets added // m_bParagraphFrameOpen : Check if the frame is open. @@ -4311,8 +4366,11 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po m_postponedCustomShape->push_back(PostponedDrawing(pSdrObj, &(rFrame.GetFrmFmt()), &rNdTopLeft)); } else + { // we are writing out attributes, but w:drawing should not be inside w:rPr, so write it out later + m_bPostponedProcessingFly = true ; m_postponedDMLDrawing->push_back(PostponedDrawing(pSdrObj, &(rFrame.GetFrmFmt()), &rNdTopLeft)); + } } } } @@ -4335,7 +4393,10 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po } if( !bDuplicate ) + { + m_bPostponedProcessingFly = true ; m_aFramesOfParagraph.push_back(sw::Frame(rFrame)); + } } break; case sw::Frame::eOle: @@ -4347,6 +4408,7 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po SwNodeIndex aIdx(*rFrmFmt.GetCntnt().GetCntntIdx(), 1); SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode(); WriteOLE2Obj( pSdrObj, rOLENd, rFrame.GetLayoutSize(), dynamic_cast<const SwFlyFrmFmt*>( &rFrmFmt )); + m_bPostponedProcessingFly = false ; } } break; @@ -4354,6 +4416,7 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Po { const SdrObject* pObject = rFrame.GetFrmFmt().FindRealSdrObject(); m_aPostponedFormControls.push_back(pObject); + m_bPostponedProcessingFly = true ; } break; default: @@ -7432,6 +7495,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri m_bOpenedSectPr( false ), m_bRunTextIsOn( false ), m_bWritingHeaderFooter( false ), + m_bAnchorLinkedToNode(false), m_sFieldBkm( ), m_nNextBookmarkId( 0 ), m_nNextAnnotationMarkId( 0 ), @@ -7440,6 +7504,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri m_bParagraphFrameOpen( false ), m_bIsFirstParagraph( true ), m_bAlternateContentChoiceOpen( false ), + m_bPostponedProcessingFly( false ), m_nColBreakStatus( COLBRK_NONE ), m_nTextFrameLevel( 0 ), m_closeHyperlinkInThisRun( false ), diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 2c0472d5cab6..ea609a67aad7 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -210,6 +210,10 @@ public: /// End of the tag that encloses the run. void EndRedline( const SwRedlineData * pRedlineData ); + virtual void SetAnchorIsLinkedToNode( bool bAnchorLinkedToNode = false ) SAL_OVERRIDE; + virtual bool IsFlyProcessingPostponed() SAL_OVERRIDE; + virtual void ResetFlyProcessingFlag() SAL_OVERRIDE; + virtual void FormatDrop( const SwTxtNode& rNode, const SwFmtDrop& rSwFmtDrop, sal_uInt16 nStyle, ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) SAL_OVERRIDE; /// Output style. @@ -726,6 +730,7 @@ private: /// Flag indicating that the header \ footer are being written bool m_bWritingHeaderFooter; + bool m_bAnchorLinkedToNode; /// Field data to remember in the text run std::vector< FieldInfos > m_Fields; @@ -767,6 +772,7 @@ private: bool m_bParagraphFrameOpen; bool m_bIsFirstParagraph; bool m_bAlternateContentChoiceOpen; + bool m_bPostponedProcessingFly; // Remember that a column break has to be opened at the // beginning of the next paragraph diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 16019979d2d2..e17625969a2e 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -540,7 +540,26 @@ bool SwWW8AttrIter::IsWatermarkFrame() return false; } -void SwWW8AttrIter::OutFlys(sal_Int32 nSwPos) +bool SwWW8AttrIter::IsAnchorLinkedToThisNode( sal_uLong nNodePos ) +{ + sw::FrameIter aTmpFlyIter = maFlyIter ; + + while ( aTmpFlyIter != maFlyFrms.end() ) + { + const SwPosition &rAnchor = maFlyIter->GetPosition(); + sal_uLong nAnchorPos = rAnchor.nNode.GetIndex(); + /* if current node position and the anchor position are the same + then the frame anchor is linked to this node + */ + if ( nAnchorPos == nNodePos ) + return true ; + + ++aTmpFlyIter; + } + return false ; +} + +sal_Int16 SwWW8AttrIter::OutFlys(sal_Int32 nSwPos) { /* #i2916# @@ -553,7 +572,7 @@ void SwWW8AttrIter::OutFlys(sal_Int32 nSwPos) const sal_Int32 nPos = rAnchor.nContent.GetIndex(); if ( nPos != nSwPos ) - break; + return FLY_NOT_PROCESSED ; //We havent processed the fly const SdrObject* pSdrObj = maFlyIter->GetFrmFmt().FindRealSdrObject(); @@ -585,6 +604,7 @@ void SwWW8AttrIter::OutFlys(sal_Int32 nSwPos) } ++maFlyIter; } + return ( m_rExport.AttrOutput().IsFlyProcessingPostponed() ? FLY_POSTPONED : FLY_PROCESSED ) ; } bool SwWW8AttrIter::IsTxtAttr( sal_Int32 nSwPos ) @@ -2017,6 +2037,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) sal_Int32 const nEnd = aStr.getLength(); bool bRedlineAtEnd = false; sal_Int32 nOpenAttrWithRange = 0; + OUString aStringForImage("\001"); ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner; if ( pTextNodeInfo.get() != NULL ) @@ -2024,18 +2045,33 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) do { const SwRedlineData* pRedlineData = aAttrIter.GetRunLevelRedline( nAktPos ); + sal_Int16 nStateOfFlyFrame = 0; + bool bPostponeWritingText = false ; + OUString aSavedSnippet ; sal_Int32 nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos ); // Is this the only run in this paragraph and it's empty? bool bSingleEmptyRun = nAktPos == 0 && nNextAttr == 0; AttrOutput().StartRun( pRedlineData, bSingleEmptyRun ); + if( nTxtTyp == TXT_FTN || nTxtTyp == TXT_EDN ) AttrOutput().FootnoteEndnoteRefTag(); if( nNextAttr > nEnd ) nNextAttr = nEnd; - aAttrIter.OutFlys( nAktPos ); + /* + 1) If there is a text node and an overlapping anchor, then write them in two different + runs and not as part of the same run. + 2) Ensure that it is a text node and not in a fly. + 3) If the anchor is associated with a text node with empty text then we ignore. + */ + if ( rNode.IsTxtNode() && aStr != aStringForImage && aStr != "" && + !rNode.GetFlyFmt() && aAttrIter.IsAnchorLinkedToThisNode(rNode.GetIndex())) + bPostponeWritingText = true ; + + nStateOfFlyFrame = aAttrIter.OutFlys( nAktPos ); + AttrOutput().SetAnchorIsLinkedToNode( bPostponeWritingText && (FLY_POSTPONED != nStateOfFlyFrame) ); // Append bookmarks in this range after flys, exclusive of final // position of this range AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos ); @@ -2152,7 +2188,17 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) if ( aSnippet[0] != 0x09 ) aSnippet = OUString( 0x09 ) + aSnippet; } - AttrOutput().RunText( aSnippet, eChrSet ); + + if ( bPostponeWritingText && ( FLY_POSTPONED != nStateOfFlyFrame ) ) + { + bPostponeWritingText = true ; + aSavedSnippet = aSnippet ; + } + else + { + bPostponeWritingText = false ; + AttrOutput().RunText( aSnippet, eChrSet ); + } } if ( aAttrIter.IsDropCap( nNextAttr ) ) @@ -2179,7 +2225,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) else { // insert final graphic anchors if any before CR - aAttrIter.OutFlys( nEnd ); + nStateOfFlyFrame = aAttrIter.OutFlys( nEnd ); // insert final bookmarks if any before CR and after flys AppendBookmarks( rNode, nEnd, 1 ); AppendAnnotationMarks( rNode, nEnd, 1 ); @@ -2228,7 +2274,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd ) { // insert final graphic anchors if any before CR - aAttrIter.OutFlys( nEnd ); + nStateOfFlyFrame = aAttrIter.OutFlys( nEnd ); // insert final bookmarks if any before CR and after flys AppendBookmarks( rNode, nEnd, 1 ); AppendAnnotationMarks( rNode, nEnd, 1 ); @@ -2256,7 +2302,25 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) AttrOutput().WritePostitFieldReference(); - AttrOutput().EndRun(); + if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame ) + { + AttrOutput().EndRun(); + //write the postponed text run + bPostponeWritingText = false ; + AttrOutput().StartRun( pRedlineData, bSingleEmptyRun ); + AttrOutput().SetAnchorIsLinkedToNode( false ); + AttrOutput().ResetFlyProcessingFlag(); + if (0 != nEnd) + { + AttrOutput().StartRunProperties(); + aAttrIter.OutAttr( nAktPos ); + AttrOutput().EndRunProperties( pRedlineData ); + } + AttrOutput().RunText( aSavedSnippet, eChrSet ); + AttrOutput().EndRun(); + } + else + AttrOutput().EndRun(); nAktPos = nNextAttr; UpdatePosition( &aAttrIter, nAktPos, nEnd ); diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index 9229fa5fcc71..36b260f21029 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -145,6 +145,16 @@ enum TxtTypes //enums for TextTypes TXT_EDN = 4, TXT_ATN = 5, TXT_TXTBOX = 6, TXT_HFTXTBOX= 7 }; +/** +enum to state the present state of the fly +*/ +enum FlyProcessingState +{ + FLY_PROCESSED, + FLY_POSTPONED, + FLY_NOT_PROCESSED +}; + struct WW8_SepInfo { const SwPageDesc* pPageDesc; @@ -1533,7 +1543,7 @@ public: int OutAttrWithRange(sal_Int32 nPos); const SwRedlineData* GetParagraphLevelRedline( ); const SwRedlineData* GetRunLevelRedline( sal_Int32 nPos ); - void OutFlys(sal_Int32 nSwPos); + sal_Int16 OutFlys(sal_Int32 nSwPos); sal_Int32 WhereNext() const { return nAktSwPos; } sal_uInt16 GetScript() const { return mnScript; } @@ -1545,6 +1555,7 @@ public: const SwFmtDrop& GetSwFmtDrop() const { return mrSwFmtDrop; } bool IsWatermarkFrame(); + bool IsAnchorLinkedToThisNode( sal_uLong nNodePos ); }; /// Class to collect and output the styles table. |