[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - sw/source

Tamas Bunth tamas.bunth at collabora.co.uk
Fri Dec 15 10:54:19 UTC 2017


 sw/source/filter/ww8/wrtw8nds.cxx | 1181 +++++++++++++++++++-------------------
 sw/source/filter/ww8/wrtww8.cxx   |    7 
 sw/source/filter/ww8/wrtww8.hxx   |    4 
 3 files changed, 627 insertions(+), 565 deletions(-)

New commits:
commit 14af9cf82c492e623609df4bfebfb06692cb53e3
Author: Tamas Bunth <tamas.bunth at collabora.co.uk>
Date:   Fri Dec 1 14:58:17 2017 +0100

    tdf#41650 DOCX export: split para on section break
    
    Given two pages with entirely different style (resp. not plausible for a
    single section) and a paragraph which starts on the first page and has a
    follow on the second.
    
    Those page styles are represented in doc/docx structure with sections.
    Doc/Docx does not support having a paragraph in more than one sections.
    
    Workaround is to split the paragraph into more paragraphs and put the
    section break in between.
    
    Change-Id: I4014c45f97e18132470d0d0647bce84831b2460a
    Reviewed-on: https://gerrit.libreoffice.org/45666
    Reviewed-by: Tamás Bunth <btomi96 at gmail.com>
    Tested-by: Tamás Bunth <btomi96 at gmail.com>
    Reviewed-on: https://gerrit.libreoffice.org/46519
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 467355777f29..5515560b55f9 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2135,6 +2135,32 @@ void MSWordExportBase::GetSortedBookmarks( const SwTextNode& rNode, sal_Int32 nA
     }
 }
 
+bool MSWordExportBase::NeedSectionBreak( const SwNode& rNd ) const
+{
+    if ( m_bStyDef || m_bOutKF || m_bInWriteEscher || m_bOutPageDescs || m_pAktPageDesc == nullptr )
+        return false;
+
+    const SwPageDesc * pPageDesc = rNd.FindPageDesc()->GetFollow();
+
+    if (m_pAktPageDesc != pPageDesc)
+    {
+        if (!sw::util::IsPlausableSingleWordSection(m_pAktPageDesc->GetFirstMaster(), pPageDesc->GetMaster()))
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool MSWordExportBase::NeedTextNodeSplit( const SwTextNode& rNd, SwSoftPageBreakList& pList ) const
+{
+    rNd.fillSoftPageBreakList( pList );
+    pList.insert(0);
+    pList.insert( rNd.GetText().getLength() );
+    return pList.size() > 2 && NeedSectionBreak( rNd );
+}
+
 void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
 {
     SAL_INFO( "sw.ww8", "<OutWW8_SwTextNode>" );
@@ -2212,719 +2238,746 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
         }
     }
 
-    AttrOutput().StartParagraph( pTextNodeInfo );
+    SwSoftPageBreakList softBreakList;
+    // Let's decide if we need to split the paragraph because of a section break
+    bool bNeedParaSplit = NeedTextNodeSplit( rNode, softBreakList );
 
-    const SwSection* pTOXSect = nullptr;
-    if( m_bInWriteTOX )
+    auto aBreakIt = softBreakList.begin();
+    // iterate through portions on different pages
+    do
     {
-        // check for end of TOX
-        SwNodeIndex aIdx( rNode, 1 );
-        if( !aIdx.GetNode().IsTextNode() )
+        sal_Int32 nAktPos = *aBreakIt;
+        ++aBreakIt;
+
+        AttrOutput().StartParagraph( pTextNodeInfo );
+
+        const SwSection* pTOXSect = nullptr;
+        if( m_bInWriteTOX )
         {
-            const SwSectionNode* pTOXSectNd = rNode.FindSectionNode();
-            if ( pTOXSectNd )
+            // check for end of TOX
+            SwNodeIndex aIdx( rNode, 1 );
+            if( !aIdx.GetNode().IsTextNode() )
             {
-                pTOXSect = &pTOXSectNd->GetSection();
+                const SwSectionNode* pTOXSectNd = rNode.FindSectionNode();
+                if ( pTOXSectNd )
+                {
+                    pTOXSect = &pTOXSectNd->GetSection();
 
-                const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx );
-                if( pNxt && pNxt->FindSectionNode() == pTOXSectNd )
-                    pTOXSect = nullptr;
+                    const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx );
+                    if( pNxt && pNxt->FindSectionNode() == pTOXSectNd )
+                        pTOXSect = nullptr;
+                }
             }
         }
-    }
 
-    if ( aAttrIter.RequiresImplicitBookmark() )
-    {
-        OUString sBkmkName =  "_toc" + OUString::number( rNode.GetIndex() );
-        AppendWordBookmark( sBkmkName );
-    }
+        if ( aAttrIter.RequiresImplicitBookmark() )
+        {
+            OUString sBkmkName =  "_toc" + OUString::number( rNode.GetIndex() );
+            AppendWordBookmark( sBkmkName );
+        }
 
-    // Call this before write out fields and runs
-    AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
+        // Call this before write out fields and runs
+        AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
 
-    const OUString& aStr( rNode.GetText() );
+        const OUString& aStr( rNode.GetText() );
 
-    sal_Int32 nAktPos = 0;
-    sal_Int32 const nEnd = aStr.getLength();
-    bool bIncludeEndOfParaCRInRedlineProperties = false;
-    sal_Int32 nOpenAttrWithRange = 0;
-    OUString aStringForImage("\001");
+        sal_Int32 const nEnd = aStr.getLength();
+        bool bIncludeEndOfParaCRInRedlineProperties = false;
+        sal_Int32 nOpenAttrWithRange = 0;
+        OUString aStringForImage("\001");
 
-    ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner;
-    if ( pTextNodeInfo.get() != nullptr )
-    {
-        pTextNodeInfoInner = pTextNodeInfo->getFirstInner();
-    }
+        ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner;
+        if ( pTextNodeInfo.get() != nullptr )
+        {
+            pTextNodeInfoInner = pTextNodeInfo->getFirstInner();
+        }
 
-    do {
-        const SwRedlineData* pRedlineData = aAttrIter.GetRunLevelRedline( nAktPos );
-        FlyProcessingState nStateOfFlyFrame = FLY_PROCESSED;
-        bool bPostponeWritingText    = false ;
-        OUString aSavedSnippet ;
+        do {
+            const SwRedlineData* pRedlineData = aAttrIter.GetRunLevelRedline( nAktPos );
+            FlyProcessingState nStateOfFlyFrame = FLY_PROCESSED;
+            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, nAktPos, bSingleEmptyRun );
+            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, nAktPos, bSingleEmptyRun );
 
-        if( nNextAttr > nEnd )
-            nNextAttr = nEnd;
+            if( nNextAttr > nEnd )
+                nNextAttr = nEnd;
 
-        if( m_nTextTyp == TXT_FTN || m_nTextTyp == TXT_EDN )
-            AttrOutput().FootnoteEndnoteRefTag();
+            if( m_nTextTyp == TXT_FTN || m_nTextTyp == TXT_EDN )
+                AttrOutput().FootnoteEndnoteRefTag();
 
-        /*
-            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.IsTextNode() && aStr != aStringForImage && !aStr.isEmpty() &&
-            !rNode.GetFlyFormat() && aAttrIter.IsAnchorLinkedToThisNode(rNode.GetIndex()))
-            bPostponeWritingText = true ;
-
-        nStateOfFlyFrame = aAttrIter.OutFlys( nAktPos );
-        AttrOutput().SetStateOfFlyFrame( nStateOfFlyFrame );
-        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 );
-        AppendAnnotationMarks( rNode, nAktPos, nNextAttr - nAktPos );
-
-        // At the moment smarttags are only written for paragraphs, at the
-        // beginning of the paragraph.
-        if (nAktPos == 0)
-            AppendSmartTags(rNode);
-
-        bool bTextAtr = aAttrIter.IsTextAttr( nAktPos );
-        nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nAktPos );
-
-        sal_Int32 nLen = nNextAttr - nAktPos;
-        if ( !bTextAtr && nLen )
-        {
-            sal_Unicode ch = aStr[nAktPos];
-            const sal_Int32 ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1 : 0 );
-
-            IDocumentMarkAccess* const pMarkAccess = m_pDoc->getIDocumentMarkAccess();
-            if ( ch == CH_TXT_ATR_FIELDSTART )
+            /*
+                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.IsTextNode() && aStr != aStringForImage && !aStr.isEmpty() &&
+                !rNode.GetFlyFormat() && aAttrIter.IsAnchorLinkedToThisNode(rNode.GetIndex()))
+                bPostponeWritingText = true ;
+
+            nStateOfFlyFrame = aAttrIter.OutFlys( nAktPos );
+            AttrOutput().SetStateOfFlyFrame( nStateOfFlyFrame );
+            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 );
+            AppendAnnotationMarks( rNode, nAktPos, nNextAttr - nAktPos );
+
+            // At the moment smarttags are only written for paragraphs, at the
+            // beginning of the paragraph.
+            if (nAktPos == 0)
+                AppendSmartTags(rNode);
+
+            bool bTextAtr = aAttrIter.IsTextAttr( nAktPos );
+            nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nAktPos );
+
+            sal_Int32 nLen = nNextAttr - nAktPos;
+            if ( !bTextAtr && nLen )
             {
-                SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
-                ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
-                OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
-
-                if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
-                    AppendBookmark( pFieldmark->GetName() );
-                ww::eField eFieldId = lcl_getFieldId( pFieldmark );
-                OUString sCode = lcl_getFieldCode( pFieldmark );
-                if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
+                sal_Unicode ch = aStr[nAktPos];
+                const sal_Int32 ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1 : 0 );
+
+                IDocumentMarkAccess* const pMarkAccess = m_pDoc->getIDocumentMarkAccess();
+                if ( ch == CH_TXT_ATR_FIELDSTART )
                 {
-                    IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
-                    if ( it != pFieldmark->GetParameters()->end() )
+                    SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
+                    ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
+                    OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
+
+                    if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
+                        AppendBookmark( pFieldmark->GetName() );
+                    ww::eField eFieldId = lcl_getFieldId( pFieldmark );
+                    OUString sCode = lcl_getFieldCode( pFieldmark );
+                    if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
                     {
-                        OUString sFieldId;
-                        it->second >>= sFieldId;
-                        eFieldId = (ww::eField)sFieldId.toInt32();
-                    }
+                        IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
+                        if ( it != pFieldmark->GetParameters()->end() )
+                        {
+                            OUString sFieldId;
+                            it->second >>= sFieldId;
+                            eFieldId = (ww::eField)sFieldId.toInt32();
+                        }
 
-                    it = pFieldmark->GetParameters()->find( ODF_CODE_PARAM );
-                    if ( it != pFieldmark->GetParameters()->end() )
-                    {
-                        it->second >>= sCode;
+                        it = pFieldmark->GetParameters()->find( ODF_CODE_PARAM );
+                        if ( it != pFieldmark->GetParameters()->end() )
+                        {
+                            it->second >>= sCode;
+                        }
                     }
-                }
 
-                OutputField( nullptr, eFieldId, sCode, WRITEFIELD_START | WRITEFIELD_CMD_START );
+                    OutputField( nullptr, eFieldId, sCode, WRITEFIELD_START | WRITEFIELD_CMD_START );
 
-                if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMTEXT )
-                    WriteFormData( *pFieldmark );
-                else if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_HYPERLINK )
-                    WriteHyperlinkData( *pFieldmark );
-                OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), WRITEFIELD_CMD_END );
+                    if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMTEXT )
+                        WriteFormData( *pFieldmark );
+                    else if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_HYPERLINK )
+                        WriteHyperlinkData( *pFieldmark );
+                    OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), WRITEFIELD_CMD_END );
 
-                if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
-                {
-                    // Check for the presence of a linked OLE object
-                    IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_OLE_PARAM );
-                    if ( it != pFieldmark->GetParameters()->end() )
+                    if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
                     {
-                        OUString sOleId;
-                        uno::Any aValue = it->second;
-                        aValue >>= sOleId;
-                        if ( !sOleId.isEmpty() )
-                            OutputLinkedOLE( sOleId );
+                        // Check for the presence of a linked OLE object
+                        IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_OLE_PARAM );
+                        if ( it != pFieldmark->GetParameters()->end() )
+                        {
+                            OUString sOleId;
+                            uno::Any aValue = it->second;
+                            aValue >>= sOleId;
+                            if ( !sOleId.isEmpty() )
+                                OutputLinkedOLE( sOleId );
+                        }
                     }
                 }
-            }
-            else if ( ch == CH_TXT_ATR_FIELDEND )
-            {
-                SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
-                ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
+                else if ( ch == CH_TXT_ATR_FIELDEND )
+                {
+                    SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
+                    ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
 
-                OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDEND??" );
+                    OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDEND??" );
 
-                ww::eField eFieldId = lcl_getFieldId( pFieldmark );
-                if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
-                {
-                    IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
-                    if ( it != pFieldmark->GetParameters()->end() )
+                    ww::eField eFieldId = lcl_getFieldId( pFieldmark );
+                    if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED )
                     {
-                        OUString sFieldId;
-                        it->second >>= sFieldId;
-                        eFieldId = (ww::eField)sFieldId.toInt32();
+                        IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM );
+                        if ( it != pFieldmark->GetParameters()->end() )
+                        {
+                            OUString sFieldId;
+                            it->second >>= sFieldId;
+                            eFieldId = (ww::eField)sFieldId.toInt32();
+                        }
                     }
+
+                    OutputField( nullptr, eFieldId, OUString(), WRITEFIELD_CLOSE );
+
+                    if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
+                        AppendBookmark( pFieldmark->GetName() );
                 }
+                else if ( ch == CH_TXT_ATR_FORMELEMENT )
+                {
+                    SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
+                    ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
+                    OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
+
+                    bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ||
+                        pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX );
+
+                    if ( isDropdownOrCheckbox )
+                        AppendBookmark( pFieldmark->GetName() );
+                    OutputField( nullptr, lcl_getFieldId( pFieldmark ),
+                            lcl_getFieldCode( pFieldmark ),
+                            WRITEFIELD_START | WRITEFIELD_CMD_START );
+                    if ( isDropdownOrCheckbox )
+                        WriteFormData( *pFieldmark );
+                    OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), WRITEFIELD_CLOSE );
+                    if ( isDropdownOrCheckbox )
+                        AppendBookmark( pFieldmark->GetName() );
+                }
+                nLen -= ofs;
 
-                OutputField( nullptr, eFieldId, OUString(), WRITEFIELD_CLOSE );
+                // if paragraph needs to be split, write only until split postition
+                if( bNeedParaSplit && nAktPos + ofs + nLen > *aBreakIt)
+                    nLen = *aBreakIt - nAktPos - ofs;
 
-                if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT )
-                    AppendBookmark( pFieldmark->GetName() );
-            }
-            else if ( ch == CH_TXT_ATR_FORMELEMENT )
-            {
-                SwPosition aPosition( rNode, SwIndex( const_cast< SwTextNode* >( &rNode ), nAktPos ) );
-                ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
-                OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
-
-                bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ||
-                    pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX );
-
-                if ( isDropdownOrCheckbox )
-                    AppendBookmark( pFieldmark->GetName() );
-                OutputField( nullptr, lcl_getFieldId( pFieldmark ),
-                        lcl_getFieldCode( pFieldmark ),
-                        WRITEFIELD_START | WRITEFIELD_CMD_START );
-                if ( isDropdownOrCheckbox )
-                    WriteFormData( *pFieldmark );
-                OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), WRITEFIELD_CLOSE );
-                if ( isDropdownOrCheckbox )
-                    AppendBookmark( pFieldmark->GetName() );
+                OUString aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + ofs, nLen ) );
+                if ( ( m_nTextTyp == TXT_EDN || m_nTextTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 )
+                {
+                    // Insert tab for aesthetic purposes #i24762#
+                    if ( aSnippet[0] != 0x09 )
+                        aSnippet = "\x09" + aSnippet;
+                }
+
+                if ( bPostponeWritingText && ( FLY_POSTPONED != nStateOfFlyFrame ) )
+                {
+                    bPostponeWritingText = true ;
+                    aSavedSnippet = aSnippet ;
+                }
+                else
+                {
+                    bPostponeWritingText = false ;
+                    AttrOutput().RunText( aSnippet, eChrSet );
+                }
             }
-            nLen -= ofs;
 
-            OUString aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + ofs, nLen ) );
-            if ( ( m_nTextTyp == TXT_EDN || m_nTextTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 )
+            if ( aAttrIter.IsDropCap( nNextAttr ) )
+                AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFormatDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner );
+
+            // Only output character attributes if this is not a postponed text run.
+            if (0 != nEnd && !(bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame))
             {
-                // Insert tab for aesthetic purposes #i24762#
-                if ( aSnippet[0] != 0x09 )
-                    aSnippet = "\x09" + aSnippet;
+                // Output the character attributes
+                // #i51277# do this before writing flys at end of paragraph
+                AttrOutput().StartRunProperties();
+                aAttrIter.OutAttr( nAktPos );
+                AttrOutput().EndRunProperties( pRedlineData );
             }
 
-            if ( bPostponeWritingText && ( FLY_POSTPONED != nStateOfFlyFrame ) )
+            // At the end of line, output the attributes until the CR.
+            // Exception: footnotes at the end of line
+            if ( nNextAttr == nEnd )
             {
-                bPostponeWritingText = true ;
-                aSavedSnippet = aSnippet ;
+                OSL_ENSURE( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" );
+                if ( !bTextAtr && nOpenAttrWithRange <= 0 )
+                {
+                    if ( aAttrIter.IncludeEndOfParaCRInRedlineProperties( nEnd ) )
+                        bIncludeEndOfParaCRInRedlineProperties = true;
+                    else
+                    {
+                        // insert final graphic anchors if any before CR
+                        nStateOfFlyFrame = aAttrIter.OutFlys( nEnd );
+                        // insert final bookmarks if any before CR and after flys
+                        AppendBookmarks( rNode, nEnd, 1 );
+                        AppendAnnotationMarks( rNode, nEnd, 1 );
+                        if ( pTOXSect )
+                        {
+                            m_aCurrentCharPropStarts.pop();
+                            AttrOutput().EndTOX( *pTOXSect ,false);
+                        }
+                        //For i120928,the position of the bullet's graphic is at end of doc
+                        if (bLastCR && (!bExported))
+                        {
+                            ExportGrfBullet(rNode);
+                            bExported = true;
+                        }
+
+                        WriteCR( pTextNodeInfoInner );
+                    }
+                }
             }
-            else
+
+            if (0 == nEnd)
             {
-                bPostponeWritingText = false ;
-                AttrOutput().RunText( aSnippet, eChrSet );
+                // Output the character attributes
+                // do it after WriteCR for an empty paragraph (otherwise
+                // WW8_WrFkp::Append throws SPRMs away...)
+                AttrOutput().StartRunProperties();
+                aAttrIter.OutAttr( nAktPos );
+                AttrOutput().EndRunProperties( pRedlineData );
             }
-        }
 
-        if ( aAttrIter.IsDropCap( nNextAttr ) )
-            AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFormatDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner );
+            // Exception: footnotes at the end of line
+            if ( nNextAttr == nEnd )
+            {
+                OSL_ENSURE(nOpenAttrWithRange >= 0,
+                    "odd to see this happening, expected >= 0");
+                bool bAttrWithRange = (nOpenAttrWithRange > 0);
+                if ( nAktPos != nEnd )
+                {
+                    nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nEnd );
+                    OSL_ENSURE(nOpenAttrWithRange == 0,
+                        "odd to see this happening, expected 0");
+                }
 
-        // Only output character attributes if this is not a postponed text run.
-        if (0 != nEnd && !(bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame))
-        {
-            // Output the character attributes
-            // #i51277# do this before writing flys at end of paragraph
-            AttrOutput().StartRunProperties();
-            aAttrIter.OutAttr( nAktPos );
-            AttrOutput().EndRunProperties( pRedlineData );
-        }
+                // !bIncludeEndOfParaCRInRedlineProperties implies we have just
+                // emitted a CR, in which case we want to pass force=true to
+                // OutputFKP to ensure that an FKP entry for direct character
+                // formatting is written even if empty, so that the next one will
+                // start after the CR.
+                AttrOutput().OutputFKP(!bIncludeEndOfParaCRInRedlineProperties);
 
-        // At the end of line, output the attributes until the CR.
-        // Exception: footnotes at the end of line
-        if ( nNextAttr == nEnd )
-        {
-            OSL_ENSURE( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" );
-            if ( !bTextAtr && nOpenAttrWithRange <= 0 )
-            {
-                if ( aAttrIter.IncludeEndOfParaCRInRedlineProperties( nEnd ) )
-                    bIncludeEndOfParaCRInRedlineProperties = true;
-                else
+                if (bTextAtr || bAttrWithRange || bIncludeEndOfParaCRInRedlineProperties)
                 {
                     // insert final graphic anchors if any before CR
                     nStateOfFlyFrame = aAttrIter.OutFlys( nEnd );
                     // insert final bookmarks if any before CR and after flys
                     AppendBookmarks( rNode, nEnd, 1 );
                     AppendAnnotationMarks( rNode, nEnd, 1 );
-                    if ( pTOXSect )
-                    {
-                        m_aCurrentCharPropStarts.pop();
-                        AttrOutput().EndTOX( *pTOXSect ,false);
-                    }
-                    //For i120928,the position of the bullet's graphic is at end of doc
+                    WriteCR( pTextNodeInfoInner );
+                    // #i120928 - position of the bullet's graphic is at end of doc
                     if (bLastCR && (!bExported))
                     {
                         ExportGrfBullet(rNode);
                         bExported = true;
                     }
 
-                    WriteCR( pTextNodeInfoInner );
-                }
-            }
-        }
-
-        if (0 == nEnd)
-        {
-            // Output the character attributes
-            // do it after WriteCR for an empty paragraph (otherwise
-            // WW8_WrFkp::Append throws SPRMs away...)
-            AttrOutput().StartRunProperties();
-            aAttrIter.OutAttr( nAktPos );
-            AttrOutput().EndRunProperties( pRedlineData );
-        }
+                    if ( pTOXSect )
+                    {
+                        m_aCurrentCharPropStarts.pop();
+                        AttrOutput().EndTOX( *pTOXSect );
+                    }
 
-        // Exception: footnotes at the end of line
-        if ( nNextAttr == nEnd )
-        {
-            OSL_ENSURE(nOpenAttrWithRange >= 0,
-                "odd to see this happening, expected >= 0");
-            bool bAttrWithRange = (nOpenAttrWithRange > 0);
-            if ( nAktPos != nEnd )
-            {
-                nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nEnd );
-                OSL_ENSURE(nOpenAttrWithRange == 0,
-                    "odd to see this happening, expected 0");
+                    if (bIncludeEndOfParaCRInRedlineProperties)
+                    {
+                        AttrOutput().Redline( aAttrIter.GetRunLevelRedline( nEnd ) );
+                        //If there was no redline property emitted, force adding
+                        //another entry for the CR so that in the case that this
+                        //has no redline, but the next para does, then this one is
+                        //not merged with the next
+                        AttrOutput().OutputFKP(true);
+                    }
+                }
             }
 
-            // !bIncludeEndOfParaCRInRedlineProperties implies we have just
-            // emitted a CR, in which case we want to pass force=true to
-            // OutputFKP to ensure that an FKP entry for direct character
-            // formatting is written even if empty, so that the next one will
-            // start after the CR.
-            AttrOutput().OutputFKP(!bIncludeEndOfParaCRInRedlineProperties);
+            AttrOutput().WritePostitFieldReference();
 
-            if (bTextAtr || bAttrWithRange || bIncludeEndOfParaCRInRedlineProperties)
+            if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame )
             {
-                // insert final graphic anchors if any before CR
-                nStateOfFlyFrame = aAttrIter.OutFlys( nEnd );
-                // insert final bookmarks if any before CR and after flys
-                AppendBookmarks( rNode, nEnd, 1 );
-                AppendAnnotationMarks( rNode, nEnd, 1 );
-                WriteCR( pTextNodeInfoInner );
-                // #i120928 - position of the bullet's graphic is at end of doc
-                if (bLastCR && (!bExported))
-                {
-                    ExportGrfBullet(rNode);
-                    bExported = true;
-                }
-
-                if ( pTOXSect )
+                AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
+                //write the postponed text run
+                AttrOutput().StartRun( pRedlineData, nAktPos, bSingleEmptyRun );
+                AttrOutput().SetAnchorIsLinkedToNode( false );
+                AttrOutput().ResetFlyProcessingFlag();
+                if (0 != nEnd)
                 {
-                    m_aCurrentCharPropStarts.pop();
-                    AttrOutput().EndTOX( *pTOXSect );
-                }
-
-                if (bIncludeEndOfParaCRInRedlineProperties)
-                {
-                    AttrOutput().Redline( aAttrIter.GetRunLevelRedline( nEnd ) );
-                    //If there was no redline property emitted, force adding
-                    //another entry for the CR so that in the case that this
-                    //has no redline, but the next para does, then this one is
-                    //not merged with the next
-                    AttrOutput().OutputFKP(true);
+                    AttrOutput().StartRunProperties();
+                    aAttrIter.OutAttr( nAktPos );
+                    AttrOutput().EndRunProperties( pRedlineData );
                 }
+                AttrOutput().RunText( aSavedSnippet, eChrSet );
+                AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
             }
-        }
+            else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
+            {
+                //write the postponed text run
+                AttrOutput().RunText( aSavedSnippet, eChrSet );
+                AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
+            }
+            else
+                AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
 
-        AttrOutput().WritePostitFieldReference();
+            nAktPos = nNextAttr;
+            UpdatePosition( &aAttrIter, nAktPos, nEnd );
+            eChrSet = aAttrIter.GetCharSet();
+        }
+        while ( nAktPos < nEnd );
 
-        if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame )
+        // if paragraph is split, put the section break between the parts
+        // else check if section break needed after the paragraph
+        if( !bNeedParaSplit || *aBreakIt != rNode.GetText().getLength() )
         {
-            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
-            //write the postponed text run
-            AttrOutput().StartRun( pRedlineData, nAktPos, bSingleEmptyRun );
-            AttrOutput().SetAnchorIsLinkedToNode( false );
-            AttrOutput().ResetFlyProcessingFlag();
-            if (0 != nEnd)
+            AttrOutput().SectionBreaks(rNode);
+            SwNodeIndex aNextIndex( rNode, 1 );
+            const SwNode& pNextNode = aNextIndex.GetNode();
+            if( pNextNode.IsTextNode() && bNeedParaSplit )
             {
-                AttrOutput().StartRunProperties();
-                aAttrIter.OutAttr( nAktPos );
-                AttrOutput().EndRunProperties( pRedlineData );
+                SectionBreaksAndFrames( *static_cast<SwTextNode*>(
+                            &aNextIndex.GetNode() ));
             }
-            AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
         }
-        else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
-        {
-            //write the postponed text run
-            AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
-        }
-        else
-            AttrOutput().EndRun(&rNode, nAktPos, nNextAttr == nEnd);
 
-        nAktPos = nNextAttr;
-        UpdatePosition( &aAttrIter, nAktPos, nEnd );
-        eChrSet = aAttrIter.GetCharSet();
-    }
-    while ( nAktPos < nEnd );
+        AttrOutput().StartParagraphProperties();
 
-    AttrOutput().SectionBreaks(rNode);
+        AttrOutput().ParagraphStyle( nStyle );
 
-    AttrOutput().StartParagraphProperties();
+        if ( m_pParentFrame && IsInTable() )    // Fly-Attrs
+            OutputFormat( m_pParentFrame->GetFrameFormat(), false, false, true );
 
-    AttrOutput().ParagraphStyle( nStyle );
-
-    if ( m_pParentFrame && IsInTable() )    // Fly-Attrs
-        OutputFormat( m_pParentFrame->GetFrameFormat(), false, false, true );
-
-    if ( pTextNodeInfo.get() != nullptr )
-    {
+        if ( pTextNodeInfo.get() != nullptr )
+        {
 #ifdef DBG_UTIL
-        SAL_INFO( "sw.ww8", pTextNodeInfo->toString());
+            SAL_INFO( "sw.ww8", pTextNodeInfo->toString());
 #endif
 
-        AttrOutput().TableInfoCell( pTextNodeInfoInner );
-        if (pTextNodeInfoInner->isFirstInTable())
-        {
-            const SwTable * pTable = pTextNodeInfoInner->getTable();
-
-            const SwTableFormat* pTabFormat = pTable->GetFrameFormat();
-            if (pTabFormat != nullptr)
+            AttrOutput().TableInfoCell( pTextNodeInfoInner );
+            if (pTextNodeInfoInner->isFirstInTable())
             {
-                if (pTabFormat->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE)
-                    AttrOutput().PageBreakBefore(true);
-            }
-        }
-    }
+                const SwTable * pTable = pTextNodeInfoInner->getTable();
 
-    if ( !bFlyInTable )
-    {
-        SfxItemSet* pTmpSet = nullptr;
-        const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode();
-
-        if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd )
-        {
-            const SfxPoolItem* pItem;
-            if( SfxItemState::SET == rNode.GetSwAttrSet().GetItemState(
-                    RES_UL_SPACE, true, &pItem ) &&
-                ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) &&
-                   static_cast<const SvxULSpaceItem*>(pItem)->GetUpper()) ||
-                  ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) &&
-                   static_cast<const SvxULSpaceItem*>(pItem)->GetLower()) ))
-            {
-                pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
-                SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(pItem) );
-                // #i25901#- consider compatibility option
-                if (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES))
-                {
-                    if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd ))
-                        aUL.SetUpper( 0 );
-                }
-                // #i25901# - consider compatibility option
-                if (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS))
+                const SwTableFormat* pTabFormat = pTable->GetFrameFormat();
+                if (pTabFormat != nullptr)
                 {
-                    if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd ))
-                        aUL.SetLower( 0 );
+                    if (pTabFormat->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE)
+                        AttrOutput().PageBreakBefore(true);
                 }
-                pTmpSet->Put( aUL );
             }
         }
 
-        bool bParaRTL = aAttrIter.IsParaRTL();
-
-        int nNumberLevel = -1;
-        if (rNode.IsNumbered())
-            nNumberLevel = rNode.GetActualListLevel();
-        if (nNumberLevel >= 0 && nNumberLevel < MAXLEVEL)
+        if ( !bFlyInTable )
         {
-            const SwNumRule* pRule = rNode.GetNumRule();
-            sal_uInt8 nLvl = static_cast< sal_uInt8 >(nNumberLevel);
-            const SwNumFormat* pFormat = pRule->GetNumFormat( nLvl );
-            if( !pFormat )
-                pFormat = &pRule->Get( nLvl );
+            SfxItemSet* pTmpSet = nullptr;
+            const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode();
 
-            if( !pTmpSet )
-                pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
-
-            SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE));
-            // #i86652#
-            if ( pFormat->GetPositionAndSpaceMode() ==
-                                    SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+            if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd )
             {
-                aLR.SetTextLeft( aLR.GetTextLeft() + pFormat->GetAbsLSpace() );
+                const SfxPoolItem* pItem;
+                if( SfxItemState::SET == rNode.GetSwAttrSet().GetItemState(
+                        RES_UL_SPACE, true, &pItem ) &&
+                    ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) &&
+                       static_cast<const SvxULSpaceItem*>(pItem)->GetUpper()) ||
+                      ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) &&
+                       static_cast<const SvxULSpaceItem*>(pItem)->GetLower()) ))
+                {
+                    pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
+                    SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(pItem) );
+                    // #i25901#- consider compatibility option
+                    if (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES))
+                    {
+                        if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd ))
+                            aUL.SetUpper( 0 );
+                    }
+                    // #i25901# - consider compatibility option
+                    if (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS))
+                    {
+                        if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd ))
+                            aUL.SetLower( 0 );
+                    }
+                    pTmpSet->Put( aUL );
+                }
             }
 
-            if( rNode.IsNumbered() && rNode.IsCountedInList() )
+            bool bParaRTL = aAttrIter.IsParaRTL();
+
+            int nNumberLevel = -1;
+            if (rNode.IsNumbered())
+                nNumberLevel = rNode.GetActualListLevel();
+            if (nNumberLevel >= 0 && nNumberLevel < MAXLEVEL)
             {
+                const SwNumRule* pRule = rNode.GetNumRule();
+                sal_uInt8 nLvl = static_cast< sal_uInt8 >(nNumberLevel);
+                const SwNumFormat* pFormat = pRule->GetNumFormat( nLvl );
+                if( !pFormat )
+                    pFormat = &pRule->Get( nLvl );
+
+                if( !pTmpSet )
+                    pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
+
+                SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE));
                 // #i86652#
                 if ( pFormat->GetPositionAndSpaceMode() ==
                                         SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
                 {
-                    if (bParaRTL)
-                        aLR.SetTextFirstLineOfstValue(pFormat->GetAbsLSpace() - pFormat->GetFirstLineOffset());
-                    else
-                        aLR.SetTextFirstLineOfst(GetWordFirstLineOffset(*pFormat));
+                    aLR.SetTextLeft( aLR.GetTextLeft() + pFormat->GetAbsLSpace() );
                 }
 
-                // correct fix for issue i94187
-                if (SfxItemState::SET !=
-                    pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
+                if( rNode.IsNumbered() && rNode.IsCountedInList() )
                 {
-                    // List style set via paragraph style - then put it into the itemset.
-                    // This is needed to get list level and list id exported for
-                    // the paragraph.
-                    pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
-
-                    // Put indent values into the itemset in case that the list
-                    // style is applied via paragraph style and the list level
-                    // indent values are not applicable.
+                    // #i86652#
                     if ( pFormat->GetPositionAndSpaceMode() ==
-                                            SvxNumberFormat::LABEL_ALIGNMENT &&
-                         !rNode.AreListLevelIndentsApplicable() )
+                                            SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+                    {
+                        if (bParaRTL)
+                            aLR.SetTextFirstLineOfstValue(pFormat->GetAbsLSpace() - pFormat->GetFirstLineOffset());
+                        else
+                            aLR.SetTextFirstLineOfst(GetWordFirstLineOffset(*pFormat));
+                    }
+
+                    // correct fix for issue i94187
+                    if (SfxItemState::SET !=
+                        pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
                     {
-                        pTmpSet->Put( aLR );
+                        // List style set via paragraph style - then put it into the itemset.
+                        // This is needed to get list level and list id exported for
+                        // the paragraph.
+                        pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
+
+                        // Put indent values into the itemset in case that the list
+                        // style is applied via paragraph style and the list level
+                        // indent values are not applicable.
+                        if ( pFormat->GetPositionAndSpaceMode() ==
+                                                SvxNumberFormat::LABEL_ALIGNMENT &&
+                             !rNode.AreListLevelIndentsApplicable() )
+                        {
+                            pTmpSet->Put( aLR );
+                        }
                     }
                 }
-            }
-            else
-                pTmpSet->ClearItem(RES_PARATR_NUMRULE);
+                else
+                    pTmpSet->ClearItem(RES_PARATR_NUMRULE);
 
-            // #i86652#
-            if ( pFormat->GetPositionAndSpaceMode() ==
-                                    SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
-            {
-                pTmpSet->Put(aLR);
+                // #i86652#
+                if ( pFormat->GetPositionAndSpaceMode() ==
+                                        SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+                {
+                    pTmpSet->Put(aLR);
 
-                //#i21847#
-                SvxTabStopItem aItem(
-                    ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP));
-                SvxTabStop aTabStop(pFormat->GetAbsLSpace());
-                aItem.Insert(aTabStop);
-                pTmpSet->Put(aItem);
+                    //#i21847#
+                    SvxTabStopItem aItem(
+                        ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP));
+                    SvxTabStop aTabStop(pFormat->GetAbsLSpace());
+                    aItem.Insert(aTabStop);
+                    pTmpSet->Put(aItem);
 
-                MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFormat->GetAbsLSpace());
+                    MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFormat->GetAbsLSpace());
+                }
             }
-        }
 
-        /*
-        If a given para is using the FRMDIR_ENVIRONMENT direction we
-        cannot export that, its its ltr then that's ok as thats word's
-        default. Otherwise we must add a RTL attribute to our export list
-        */
-        const SvxFrameDirectionItem* pItem = static_cast<const SvxFrameDirectionItem*>(
-            rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR));
-        if (
-            (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) &&
-            aAttrIter.IsParaRTL()
-           )
-        {
-            if ( !pTmpSet )
-                pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
-
-            pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR));
-        }
-        // move code for handling of numbered,
-        // but not counted paragraphs to this place. Otherwise, the paragraph
-        // isn't exported as numbered, but not counted, if no other attribute
-        // is found in <pTmpSet>
-        // #i44815# adjust numbering/indents for numbered paragraphs
-        //          without number (NO_NUMLEVEL)
-        // #i47013# need to check rNode.GetNumRule()!=NULL as well.
-        if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=nullptr )
-        {
-            // WW8 does not know numbered paragraphs without number
-            // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export
-            // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means
-            // no numbering. Here, we will adjust the indents to match
-            // visually.
-
-            if ( !pTmpSet )
-                pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
-
-            // create new LRSpace item, based on the current (if present)
-            const SfxPoolItem* pPoolItem = nullptr;
-            pTmpSet->GetItemState(RES_LR_SPACE, true, &pPoolItem);
-            SvxLRSpaceItem aLRSpace(
-                ( pPoolItem == nullptr )
-                    ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE)
-                    : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) );
-
-            // new left margin = old left + label space
-            const SwNumRule* pRule = rNode.GetNumRule();
-            int nLevel = rNode.GetActualListLevel();
-
-            if (nLevel < 0)
-                nLevel = 0;
-
-            if (nLevel >= MAXLEVEL)
-                nLevel = MAXLEVEL - 1;
-
-            const SwNumFormat& rNumFormat = pRule->Get( static_cast< sal_uInt16 >(nLevel) );
-
-            // #i86652#
-            if ( rNumFormat.GetPositionAndSpaceMode() ==
-                                    SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+            /*
+            If a given para is using the FRMDIR_ENVIRONMENT direction we
+            cannot export that, its its ltr then that's ok as thats word's
+            default. Otherwise we must add a RTL attribute to our export list
+            */
+            const SvxFrameDirectionItem* pItem = static_cast<const SvxFrameDirectionItem*>(
+                rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR));
+            if (
+                (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) &&
+                aAttrIter.IsParaRTL()
+               )
             {
-                aLRSpace.SetTextLeft( aLRSpace.GetLeft() + rNumFormat.GetAbsLSpace() );
+                if ( !pTmpSet )
+                    pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
+
+                pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR));
             }
-            else
+            // move code for handling of numbered,
+            // but not counted paragraphs to this place. Otherwise, the paragraph
+            // isn't exported as numbered, but not counted, if no other attribute
+            // is found in <pTmpSet>
+            // #i44815# adjust numbering/indents for numbered paragraphs
+            //          without number (NO_NUMLEVEL)
+            // #i47013# need to check rNode.GetNumRule()!=NULL as well.
+            if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=nullptr )
             {
-                aLRSpace.SetTextLeft( aLRSpace.GetLeft() + rNumFormat.GetIndentAt() );
-            }
+                // WW8 does not know numbered paragraphs without number
+                // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export
+                // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means
+                // no numbering. Here, we will adjust the indents to match
+                // visually.
+
+                if ( !pTmpSet )
+                    pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
 
-            // new first line indent = 0
-            // (first line indent is ignored for NO_NUMLEVEL)
-            if (!bParaRTL)
-                aLRSpace.SetTextFirstLineOfst( 0 );
+                // create new LRSpace item, based on the current (if present)
+                const SfxPoolItem* pPoolItem = nullptr;
+                pTmpSet->GetItemState(RES_LR_SPACE, true, &pPoolItem);
+                SvxLRSpaceItem aLRSpace(
+                    ( pPoolItem == nullptr )
+                        ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE)
+                        : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) );
 
-            // put back the new item
-            pTmpSet->Put( aLRSpace );
+                // new left margin = old left + label space
+                const SwNumRule* pRule = rNode.GetNumRule();
+                int nLevel = rNode.GetActualListLevel();
 
-            // assure that numbering rule is in <pTmpSet>
-            if (SfxItemState::SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
-            {
-                pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
+                if (nLevel < 0)
+                    nLevel = 0;
+
+                if (nLevel >= MAXLEVEL)
+                    nLevel = MAXLEVEL - 1;
+
+                const SwNumFormat& rNumFormat = pRule->Get( static_cast< sal_uInt16 >(nLevel) );
+
+                // #i86652#
+                if ( rNumFormat.GetPositionAndSpaceMode() ==
+                                        SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+                {
+                    aLRSpace.SetTextLeft( aLRSpace.GetLeft() + rNumFormat.GetAbsLSpace() );
+                }
+                else
+                {
+                    aLRSpace.SetTextLeft( aLRSpace.GetLeft() + rNumFormat.GetIndentAt() );
+                }
+
+                // new first line indent = 0
+                // (first line indent is ignored for NO_NUMLEVEL)
+                if (!bParaRTL)
+                    aLRSpace.SetTextFirstLineOfst( 0 );
+
+                // put back the new item
+                pTmpSet->Put( aLRSpace );
+
+                // assure that numbering rule is in <pTmpSet>
+                if (SfxItemState::SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
+                {
+                    pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
+                }
             }
-        }
 
-        // #i75457#
-        // Export page break after attribute from paragraph style.
-        // If page break attribute at the text node exist, an existing page
-        // break after at the paragraph style hasn't got to be considered.
-        if ( !rNode.GetpSwAttrSet() ||
-             SfxItemState::SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) )
-        {
-            const SvxFormatBreakItem* pBreakAtParaStyle =
-                &(ItemGet<SvxFormatBreakItem>(rNode.GetSwAttrSet(), RES_BREAK));
-            if ( pBreakAtParaStyle &&
-                 pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER )
+            // #i75457#
+            // Export page break after attribute from paragraph style.
+            // If page break attribute at the text node exist, an existing page
+            // break after at the paragraph style hasn't got to be considered.
+            if ( !rNode.GetpSwAttrSet() ||
+                 SfxItemState::SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) )
             {
-                if ( !pTmpSet )
+                const SvxFormatBreakItem* pBreakAtParaStyle =
+                    &(ItemGet<SvxFormatBreakItem>(rNode.GetSwAttrSet(), RES_BREAK));
+                if ( pBreakAtParaStyle &&
+                     pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER )
                 {
-                    pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
+                    if ( !pTmpSet )
+                    {
+                        pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
+                    }
+                    pTmpSet->Put( *pBreakAtParaStyle );
+                }
+                else if( pTmpSet )
+                {   // Even a pagedesc item is set, the break item can be set 'NONE',
+                    // this has to be overruled.
+                    const SwFormatPageDesc& rPageDescAtParaStyle =
+                        ItemGet<SwFormatPageDesc>( rNode, RES_PAGEDESC );
+                    if( rPageDescAtParaStyle.KnowsPageDesc() )
+                        pTmpSet->ClearItem( RES_BREAK );
                 }
-                pTmpSet->Put( *pBreakAtParaStyle );
-            }
-            else if( pTmpSet )
-            {   // Even a pagedesc item is set, the break item can be set 'NONE',
-                // this has to be overruled.
-                const SwFormatPageDesc& rPageDescAtParaStyle =
-                    ItemGet<SwFormatPageDesc>( rNode, RES_PAGEDESC );
-                if( rPageDescAtParaStyle.KnowsPageDesc() )
-                    pTmpSet->ClearItem( RES_BREAK );
             }
-        }
-
-        // #i76520# Emulate non-splitting tables
-        if ( IsInTable() )
-        {
-            const SwTableNode* pTableNode = rNode.FindTableNode();
 
-            if ( pTableNode )
+            // #i76520# Emulate non-splitting tables
+            if ( IsInTable() )
             {
-                const SwTable& rTable = pTableNode->GetTable();
-                const SvxFormatKeepItem& rKeep = rTable.GetFrameFormat()->GetKeep();
-                const bool bKeep = rKeep.GetValue();
-                const bool bDontSplit = !(bKeep ||
-                                          rTable.GetFrameFormat()->GetLayoutSplit().GetValue());
+                const SwTableNode* pTableNode = rNode.FindTableNode();
 
-                if ( bKeep || bDontSplit )
+                if ( pTableNode )
                 {
-                    // bKeep: set keep at first paragraphs in all lines
-                    // bDontSplit : set keep at first paragraphs in all lines except from last line
-                    // but only for non-complex tables
-                    const SwTableBox* pBox = rNode.GetTableBox();
-                    const SwTableLine* pLine = pBox ? pBox->GetUpper() : nullptr;
+                    const SwTable& rTable = pTableNode->GetTable();
+                    const SvxFormatKeepItem& rKeep = rTable.GetFrameFormat()->GetKeep();
+                    const bool bKeep = rKeep.GetValue();
+                    const bool bDontSplit = !(bKeep ||
+                                              rTable.GetFrameFormat()->GetLayoutSplit().GetValue());
 
-                    if ( pLine && !pLine->GetUpper() )
+                    if ( bKeep || bDontSplit )
                     {
-                        // check if box is first in that line:
-                        if ( 0 == pLine->GetBoxPos( pBox ) && pBox->GetSttNd() )
+                        // bKeep: set keep at first paragraphs in all lines
+                        // bDontSplit : set keep at first paragraphs in all lines except from last line
+                        // but only for non-complex tables
+                        const SwTableBox* pBox = rNode.GetTableBox();
+                        const SwTableLine* pLine = pBox ? pBox->GetUpper() : nullptr;
+
+                        if ( pLine && !pLine->GetUpper() )
                         {
-                            // check if paragraph is first in that line:
-                            if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) )
+                            // check if box is first in that line:
+                            if ( 0 == pLine->GetBoxPos( pBox ) && pBox->GetSttNd() )
                             {
-                                bool bSetAtPara = false;
-                                if ( bKeep )
-                                    bSetAtPara = true;
-                                else if ( bDontSplit )
+                                // check if paragraph is first in that line:
+                                if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) )
                                 {
-                                    // check if pLine isn't last line in table
-                                    if ( rTable.GetTabLines().size() - rTable.GetTabLines().GetPos( pLine ) != 1 )
+                                    bool bSetAtPara = false;
+                                    if ( bKeep )
                                         bSetAtPara = true;
-                                }
-
-                                if ( bSetAtPara )
-                                {
-                                    if ( !pTmpSet )
-                                        pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
-
-                                    const SvxFormatKeepItem aKeepItem( true, RES_KEEP );
-                                    pTmpSet->Put( aKeepItem );
+                                    else if ( bDontSplit )
+                                    {
+                                        // check if pLine isn't last line in table
+                                        if ( rTable.GetTabLines().size() - rTable.GetTabLines().GetPos( pLine ) != 1 )
+                                            bSetAtPara = true;
+                                    }
+
+                                    if ( bSetAtPara )
+                                    {
+                                        if ( !pTmpSet )
+                                            pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
+
+                                        const SvxFormatKeepItem aKeepItem( true, RES_KEEP );
+                                        pTmpSet->Put( aKeepItem );
+                                    }
                                 }
                             }
                         }
                     }
                 }
             }
-        }
 
-        const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet();
-        if( pNewSet )
-        {                                               // Para-Attrs
-            m_pStyAttr = &rNode.GetAnyFormatColl().GetAttrSet();
+            const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet();
+            if( pNewSet )
+            {                                               // Para-Attrs
+                m_pStyAttr = &rNode.GetAnyFormatColl().GetAttrSet();
 
-            const SwModify* pOldMod = m_pOutFormatNode;
-            m_pOutFormatNode = &rNode;
+                const SwModify* pOldMod = m_pOutFormatNode;
+                m_pOutFormatNode = &rNode;
 
-            // Pap-Attrs, so script is not necessary
-            OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false);
+                // Pap-Attrs, so script is not necessary
+                OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false);
 
-            m_pStyAttr = nullptr;
-            m_pOutFormatNode = pOldMod;
+                m_pStyAttr = nullptr;
+                m_pOutFormatNode = pOldMod;
 
-            if( pNewSet != rNode.GetpSwAttrSet() )
-                delete pNewSet;
+                if( pNewSet != rNode.GetpSwAttrSet() )
+                    delete pNewSet;
+            }
         }
-    }
 
-    // The formatting of the paragraph marker has two sources:
-    // 1) If there are hints at the end of the paragraph, then use that.
-    // 2) Else use the RES_CHRATR_BEGIN..RES_TXTATR_END range of the paragraph
-    // properties.
-    //
-    // Exception: if there is a character style hint at the end of the
-    // paragraph only, then still go with 2), as RES_TXTATR_CHARFMT is always
-    // set as a hint.
-    SfxItemSet aParagraphMarkerProperties(m_pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_TXTATR_END);
-    bool bCharFormatOnly = true;
-    if(const SwpHints* pTextAttrs = rNode.GetpSwpHints())
-    {
-        for( size_t i = 0; i < pTextAttrs->Count(); ++i )
+        // The formatting of the paragraph marker has two sources:
+        // 1) If there are hints at the end of the paragraph, then use that.
+        // 2) Else use the RES_CHRATR_BEGIN..RES_TXTATR_END range of the paragraph
+        // properties.
+        //
+        // Exception: if there is a character style hint at the end of the
+        // paragraph only, then still go with 2), as RES_TXTATR_CHARFMT is always
+        // set as a hint.
+        SfxItemSet aParagraphMarkerProperties(m_pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_TXTATR_END);
+        bool bCharFormatOnly = true;
+        if(const SwpHints* pTextAttrs = rNode.GetpSwpHints())
         {
-            const SwTextAttr* pHt = pTextAttrs->Get(i);
-            const sal_Int32 startPos = pHt->GetStart();    // first Attr characters
-            const sal_Int32* endPos = pHt->End();    // end Attr characters
-            // Check if these attributes are for the last character in the paragraph
-            // - which means the paragraph marker. If a paragraph has 7 characters,
-            // then properties on character 8 are for the paragraph marker
-            if( (endPos) && (startPos == *endPos ) && (*endPos == rNode.GetText().getLength()) )
+            for( size_t i = 0; i < pTextAttrs->Count(); ++i )
             {
-                SAL_INFO( "sw.ww8", startPos << "startPos == endPos" << *endPos);
-                sal_uInt16 nWhich = pHt->GetAttr().Which();
-                SAL_INFO( "sw.ww8", "nWhich" << nWhich);
-                if (nWhich == RES_TXTATR_AUTOFMT || nWhich == RES_TXTATR_CHARFMT)
-                    aParagraphMarkerProperties.Put(pHt->GetAttr());
-                if (nWhich != RES_TXTATR_CHARFMT)
-                    bCharFormatOnly = false;
+                const SwTextAttr* pHt = pTextAttrs->Get(i);
+                const sal_Int32 startPos = pHt->GetStart();    // first Attr characters
+                const sal_Int32* endPos = pHt->End();    // end Attr characters
+                // Check if these attributes are for the last character in the paragraph
+                // - which means the paragraph marker. If a paragraph has 7 characters,
+                // then properties on character 8 are for the paragraph marker
+                if( (endPos) && (startPos == *endPos ) && (*endPos == rNode.GetText().getLength()) )
+                {
+                    SAL_INFO( "sw.ww8", startPos << "startPos == endPos" << *endPos);
+                    sal_uInt16 nWhich = pHt->GetAttr().Which();
+                    SAL_INFO( "sw.ww8", "nWhich" << nWhich);
+                    if (nWhich == RES_TXTATR_AUTOFMT || nWhich == RES_TXTATR_CHARFMT)
+                        aParagraphMarkerProperties.Put(pHt->GetAttr());
+                    if (nWhich != RES_TXTATR_CHARFMT)
+                        bCharFormatOnly = false;
+                }
             }
         }
-    }
-    if (rNode.GetpSwAttrSet() && bCharFormatOnly)
-    {
-        aParagraphMarkerProperties.Put(*rNode.GetpSwAttrSet());
-    }
-    const SwRedlineData* pRedlineParagraphMarkerDelete = AttrOutput().GetParagraphMarkerRedline( rNode, nsRedlineType_t::REDLINE_DELETE );
-    const SwRedlineData* pRedlineParagraphMarkerInsert = AttrOutput().GetParagraphMarkerRedline( rNode, nsRedlineType_t::REDLINE_INSERT );
-    const SwRedlineData* pParagraphRedlineData = aAttrIter.GetParagraphLevelRedline( );
-    AttrOutput().EndParagraphProperties(aParagraphMarkerProperties, pParagraphRedlineData, pRedlineParagraphMarkerDelete, pRedlineParagraphMarkerInsert);
+        if (rNode.GetpSwAttrSet() && bCharFormatOnly)
+        {
+            aParagraphMarkerProperties.Put(*rNode.GetpSwAttrSet());
+        }
+        const SwRedlineData* pRedlineParagraphMarkerDelete = AttrOutput().GetParagraphMarkerRedline( rNode, nsRedlineType_t::REDLINE_DELETE );
+        const SwRedlineData* pRedlineParagraphMarkerInsert = AttrOutput().GetParagraphMarkerRedline( rNode, nsRedlineType_t::REDLINE_INSERT );
+        const SwRedlineData* pParagraphRedlineData = aAttrIter.GetParagraphLevelRedline( );
+        AttrOutput().EndParagraphProperties(aParagraphMarkerProperties, pParagraphRedlineData, pRedlineParagraphMarkerDelete, pRedlineParagraphMarkerInsert);
 
-    AttrOutput().EndParagraph( pTextNodeInfoInner );
+        AttrOutput().EndParagraph( pTextNodeInfoInner );
+    }while(*aBreakIt != rNode.GetText().getLength() && bNeedParaSplit );
 
     SAL_INFO( "sw.ww8", "</OutWW8_SwTextNode>" );
 }
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 8e8c02496560..054d33ba09e7 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -2662,7 +2662,12 @@ void MSWordExportBase::WriteText()
         SwNode& rNd = m_pCurPam->GetNode();
 
         if ( rNd.IsTextNode() )
-            SectionBreaksAndFrames( *rNd.GetTextNode() );
+        {
+            SwSoftPageBreakList breakList;
+            // if paragraph need to be split than handle section break somewhere else.
+            if( !NeedTextNodeSplit( *rNd.GetTextNode(), breakList) )
+                SectionBreaksAndFrames( *rNd.GetTextNode() );
+        }
 
         // output the various types of nodes
         if ( rNd.IsContentNode() )
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index b5633010789a..4d4a1fa76747 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -868,6 +868,10 @@ protected:
     int CollectGrfsOfBullets();
     /// Write the numbering picture bullets.
     void BulletDefinitions();
+
+    bool NeedSectionBreak( const SwNode& rNd ) const;
+    bool NeedTextNodeSplit( const SwTextNode& rNd, std::set< sal_Int32 >& pList ) const;
+
     std::vector<const Graphic*> m_vecBulletPic; ///< Vector to record all the graphics of bullets
 
 public:


More information about the Libreoffice-commits mailing list