[Libreoffice-commits] core.git: sw/qa sw/source
Umesh Kadam
umesh.kadam at synerzip.com
Thu May 22 00:32:18 PDT 2014
sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx |binary
sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 9 +
sw/source/filter/ww8/attributeoutputbase.hxx | 9 +
sw/source/filter/ww8/docxattributeoutput.cxx | 69 +++++++++++
sw/source/filter/ww8/docxattributeoutput.hxx | 6 +
sw/source/filter/ww8/wrtw8nds.cxx | 78 +++++++++++--
sw/source/filter/ww8/wrtww8.hxx | 13 ++
7 files changed, 174 insertions(+), 10 deletions(-)
New commits:
commit 80fd9fb7209cfd5c0622ee99d59e42e6db32f021
Author: Umesh Kadam <umesh.kadam at synerzip.com>
Date: Thu May 15 23:02:34 2014 +0530
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 at collabora.co.uk>
Tested-by: Miklos Vajna <vmiklos at collabora.co.uk>
diff --git a/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx b/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx
new file mode 100644
index 0000000..e1ec074
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ShapeOverlappingWithSdt.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 7a69e67..16d13a2 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 5a25c86..d2df9c0 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 96602c3..fb5933d 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 2c0472d..ea609a6 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 1601997..e176259 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 9229fa5..36b260f 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.
More information about the Libreoffice-commits
mailing list