sw/inc/IDocumentSettingAccess.hxx             |    1 
 sw/qa/core/text/data/A011-charheight.rtf      |   27 ++++++++++++++++++++++++++
 sw/qa/core/text/itrform2.cxx                  |   18 +++++++++++++++++
 sw/source/core/doc/DocumentSettingManager.cxx |   11 ++++++++++
 sw/source/core/inc/DocumentSettingManager.hxx |    1 
 sw/source/core/layout/layact.cxx              |    6 +++++
 sw/source/core/text/itrform2.cxx              |   13 +++++++++---
 sw/source/filter/ww8/ww8par.cxx               |    1 
 sw/source/filter/xml/xmlimp.cxx               |   10 +++++++++
 sw/source/uibase/uno/SwXDocumentSettings.cxx  |   18 +++++++++++++++++
 writerfilter/source/filter/WriterFilter.cxx   |    1 
 11 files changed, 104 insertions(+), 3 deletions(-)

New commits:
commit 283c16f56500ee517c10cf86182954ef12340bde
Author:     Michael Stahl <[email protected]>
AuthorDate: Thu Apr 4 19:26:31 2024 +0200
Commit:     Michael Stahl <[email protected]>
CommitDate: Tue Apr 9 14:37:27 2024 +0200

    sw: layout: remove superfluous pages again in InternalAction()
    
    The bugdoc has a very large header containing hidden text changes height
    when toggling Formatting Marks.  When toggling on, it crashes, because
    UnHide() iterates the text frames in all headers, but after the first
    one empty pages at the end of the document are removed, so UAF.
    
    Remove the pages without content earlier; SwLayAction::InternalAction()
    already does it after the "normal" page loop, but the 2nd page loop
    following that may also move content off pages, so do it again.
    
    Change-Id: Iaae6a16842b3494f25cba8fc036d15049b71961f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165801
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 759d822dac5edc6104ce61b70c578425d9f2470d)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165728
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index a705ef251176..f4a578fe99eb 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -809,6 +809,12 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
             unlockPositionOfObjects( pPg );
             pPg = static_cast<SwPageFrame*>(pPg->GetNext());
         }
+        if (m_pRoot->IsSuperfluous()) // could be newly set now!
+        {
+            bool bOld = IsAgain();
+            m_pRoot->RemoveSuperfluous();
+            SetAgain(bOld);
+        }
         // reset flag for special interrupt content formatting.
         mbFormatContentOnInterrupt = false;
     }
commit acc47a4392777b4ad59633c31db71e96a4340cf5
Author:     Michael Stahl <[email protected]>
AuthorDate: Mon Apr 8 15:26:00 2024 +0200
Commit:     Michael Stahl <[email protected]>
CommitDate: Tue Apr 9 14:34:04 2024 +0200

    tdf#88214 sw: text formatting: adapt empty line at end of para to Word
    
    For an empty line at the end of an empty paragraph, Writer already uses
    any existing text attribute in the paragraph, see for example
    testEmptyTrailingSpans.
    
    For an empty line at the end of a non-empty paragraph, Writer text
    formatting uses only paragraph attributes, ignoring any text attributes,
    whereas the UI will display the attributes from the text attributes
    (such as font height) if you move the cursor there.
    
    Word uses text attributes also in this case, so adapt the inconsistent
    Writer behaviour: text formatting now uses text attributes too.
    
    Apparently this can be achieved by calling SeekAndChgBefore() instead of
    SeekAndChg().
    
    Add another compat flag "ApplyTextAttrToEmptyLineAtEndOfParagraph" to
    preserve the formatting of existing ODF documents.
    
    Adapt test document fdo74110.docx, it has a line break with "Angsana
    New" font.
    
    Change-Id: I0863d3077e419404194b47110e4ad2bdda3d11c4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165887
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <[email protected]>
    (cherry picked from commit 2b47fae7e3e23ee7c733708500cb0482ad7f8af1)

diff --git a/sw/inc/IDocumentSettingAccess.hxx 
b/sw/inc/IDocumentSettingAccess.hxx
index ad1d95c10b0d..ac319e3fb2a2 100644
--- a/sw/inc/IDocumentSettingAccess.hxx
+++ b/sw/inc/IDocumentSettingAccess.hxx
@@ -94,6 +94,7 @@ enum class DocumentSettingId
     HYPHENATE_URLS, ///< tdf#152952
     DO_NOT_BREAK_WRAPPED_TABLES,
     ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK,
+    APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH,
     // COMPATIBILITY FLAGS END
     BROWSE_MODE,
     HTML_MODE,
diff --git a/sw/qa/core/text/data/A011-charheight.rtf 
b/sw/qa/core/text/data/A011-charheight.rtf
new file mode 100644
index 000000000000..4b56ecdd6a15
--- /dev/null
+++ b/sw/qa/core/text/data/A011-charheight.rtf
@@ -0,0 +1,27 @@
+{ 
tf1deflang1025nsinsicpg1252\uc1deff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang3079\deflangfe3079
       hemelang3079    hemelangfe0     hemelangcs0
+{onttbl{0bidi romancharset0prq2Times New Roman{\*alt Arial};}
+}
+{\*\defchp 0s22\lang3079\langfe1033\langfenp1033 }
+{\*\defpap \ql \li0 i0\sa200\sl276\slmult1
+\widctlpar\wrapdefaultspalphaspnumaautodjustright in0\lin0\itap0 }
+
oqfpromote
+{\stylesheet
+{\ql \li0 i0\sa200\sl276\slmult1\widctlpar\wrapdefaultspalphaspnum
aautodjustright in0\lin0\itap0  tlchcs1 f0fs22lang1025 \ltrchcs0
+0s23\lang3079\langfe1033+{\s15\ql \li0 i0\widctlpar  qc      x4536   qr      
x9072\wrapdefaultspalphaspnumaautodjustright in0\lin0\itap0  tlchcs1 
f0fs22lang1025 \ltrchcs0 0s23\lang3079\langfe1033+\sbasedon0 \snext15 
\slink16 \sunhideused header;}
+{\*+}
+\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1134\gutter0\ltrsect
+\deftab708\widowctrltnbjenddoc\hyphhotz425   rackmoves0      
rackformatting1\donotembedsysfont1 elyonvml0\donotembedlingdata0\grfdocevents0
alidatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
+\showxmlerrors1
oxlattoyenxpshrtn
oultrlspc\dntblnsbdb
ospaceforul
ormshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1
+\jexpandiewkind1iewscale100\pgbrdrhead\pgbrdrfoot\splytwnine
tnlytwnine\htmautsp
olnhtadjtbl\useltbalnlntblind\lytcalctblwd\lyttblrtgr\lnbrkrule
obrkwrptbl\snaptogridincellllowfieldendsel\wrppunct
+sianbrkrule
ewtblstyruls
ogrowautofit\usenormstyforlist
oindnmbrtselnbrelev
ocxsptable\indrlsweleven
oafcnsttblfelev\utinl\hwelev\spltpgpar
otcvasp
otbrkcnstfrctbl
otvatxbx\krnprsnet+{\*\wgrffmtfilter 2450}
ofeaturethrottle1\ilfomacatclnup0
+
+\ltrpar \pard\plain \ltrpar\s15\qc \li0 i0\widctlpar
+       qc      x4536   qr      x9072\wrapdefaultspalphaspnum
aautodjustright in0\lin0\itap0 tlchcs1 f0fs22lang1025 \ltrchcs0 0
s23\lang3079\langfe1033+s16 \line \line \line
+\par \line
+\par }
+}
diff --git a/sw/qa/core/text/itrform2.cxx b/sw/qa/core/text/itrform2.cxx
index c4fd1ac99dd8..b63ab6c996f3 100644
--- a/sw/qa/core/text/itrform2.cxx
+++ b/sw/qa/core/text/itrform2.cxx
@@ -88,6 +88,24 @@ CPPUNIT_TEST_FIXTURE(Test, 
testFloattableLegacyWrapEmptyParagraph)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs2.size());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testApplyTextAttrToEmptyLineAtEndOfParagraph)
+{
+    createSwDoc("A011-charheight.rtf");
+
+    calcLayout();
+
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+
+    SwContentFrame* pLastPara = pPage->FindLastBodyContent();
+    // wrong was 449 (11.5pt)
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(368), 
pLastPara->getFrameArea().Height());
+    SwContentFrame* pFirstPara = pPage->FindFirstBodyContent();
+    // wrong was 817 (11.5pt)
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(736), 
pFirstPara->getFrameArea().Height());
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testFlyMinimalWrap)
 {
     // Given a document with a first page that has a shape and a table in it 
(not floating table),
diff --git a/sw/source/core/doc/DocumentSettingManager.cxx 
b/sw/source/core/doc/DocumentSettingManager.cxx
index 4342fb419e80..1969c08fbd9b 100644
--- a/sw/source/core/doc/DocumentSettingManager.cxx
+++ b/sw/source/core/doc/DocumentSettingManager.cxx
@@ -247,6 +247,8 @@ bool sw::DocumentSettingManager::get(/*[in]*/ 
DocumentSettingId id) const
         case DocumentSettingId::AUTO_FIRST_LINE_INDENT_DISREGARD_LINE_SPACE:
             return mbAutoFirstLineIndentDisregardLineSpace;
         case DocumentSettingId::HYPHENATE_URLS: return mbHyphenateURLs;
+        case 
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
+            return mbApplyTextAttrToEmptyLineAtEndOfParagraph;
         case DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES:
             return mbDoNotBreakWrappedTables;
         case DocumentSettingId::ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK:
@@ -435,6 +437,10 @@ void sw::DocumentSettingManager::set(/*[in]*/ 
DocumentSettingId id, /*[in]*/ boo
             mbHyphenateURLs = value;
             break;
 
+        case 
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
+            mbApplyTextAttrToEmptyLineAtEndOfParagraph = value;
+            break;
+
         case DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES:
             mbDoNotBreakWrappedTables = value;
             break;
@@ -1066,6 +1072,11 @@ void 
sw::DocumentSettingManager::dumpAsXml(xmlTextWriterPtr pWriter) const
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
                                 
BAD_CAST(OString::number(mnImagePreferredDPI).getStr()));
 
+    (void)xmlTextWriterStartElement(pWriter, 
BAD_CAST("mbApplyTextAttrToEmptyLineAtEndOfParagraph"));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
+                                
BAD_CAST(OString::boolean(mbApplyTextAttrToEmptyLineAtEndOfParagraph).getStr()));
+    (void)xmlTextWriterEndElement(pWriter);
+
     (void)xmlTextWriterEndElement(pWriter);
 
     (void)xmlTextWriterEndElement(pWriter);
diff --git a/sw/source/core/inc/DocumentSettingManager.hxx 
b/sw/source/core/inc/DocumentSettingManager.hxx
index a84607de42ca..94c4fd4e28d6 100644
--- a/sw/source/core/inc/DocumentSettingManager.hxx
+++ b/sw/source/core/inc/DocumentSettingManager.hxx
@@ -177,6 +177,7 @@ class DocumentSettingManager final :
     bool mbHyphenateURLs = false;
     bool mbDoNotBreakWrappedTables = false;
     bool mbAllowTextAfterFloatingTableBreak = false;
+    bool mbApplyTextAttrToEmptyLineAtEndOfParagraph = true;
     // If this is on as_char flys wrapping will be handled the same like in 
Word
     bool mbNoNumberingShowFollowBy;
     bool mbDropCapPunctuation; // tdf#150200, tdf#150438
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 2ded20a97e8f..a0121e38ac9c 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -852,6 +852,7 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, 
SwLinePortion *pPor )
 
         // In empty lines the attributes are switched on via SeekStart
         const bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
+
         if ( pPor->IsQuoVadisPortion() )
             bChg = SeekStartAndChg( rInf, true );
         else
@@ -860,10 +861,16 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, 
SwLinePortion *pPor )
             {
                 if( !rInf.GetText().isEmpty() )
                 {
-                    if ( pPor->GetLen() || !rInf.GetIdx()
-                         || ( m_pCurr != pLast && !pLast->IsFlyPortion() )
-                         || !m_pCurr->IsRest() ) // instead of !rInf.GetRest()
+                    if ((rInf.GetIdx() != 
TextFrameIndex(rInf.GetText().getLength())
+                            || rInf.GetRest() // field continued - not empty
+                            || 
!GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
+                                
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH))
+                        && (pPor->GetLen() || !rInf.GetIdx()
+                            || (m_pCurr != pLast && !pLast->IsFlyPortion())
+                            || !m_pCurr->IsRest())) // instead of 
!rInf.GetRest()
+                    {
                         bChg = SeekAndChg( rInf );
+                    }
                     else
                         bChg = SeekAndChgBefore( rInf );
                 }
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index efac5960f8ee..723ff787d4ef 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -1942,6 +1942,7 @@ void SwWW8ImplReader::ImportDop()
     
m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE,
 true);
     
m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, 
true);
     // rely on default for HYPHENATE_URLS=false
+    // rely on default for 
APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
 
     IDocumentSettingAccess& rIDSA = m_rDoc.getIDocumentSettingAccess();
     if (m_xWDop->fDontBreakWrappedTables)
diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx
index 49f51c0f5ac7..a60b766ea87d 100644
--- a/sw/source/filter/xml/xmlimp.cxx
+++ b/sw/source/filter/xml/xmlimp.cxx
@@ -1301,6 +1301,7 @@ void SwXMLImport::SetConfigurationSettings(const Sequence 
< PropertyValue > & aC
     bool bCollapseEmptyCellPara = false;
     bool bAutoFirstLineIndentDisregardLineSpace = false;
     bool bHyphenateURLs = false;
+    bool bApplyTextAttrToEmptyLineAtEndOfParagraph = false;
     bool bDoNotBreakWrappedTables = false;
     bool bAllowTextAfterFloatingTableBreak = false;
     bool bDropCapPunctuation = false;
@@ -1401,6 +1402,10 @@ void SwXMLImport::SetConfigurationSettings(const 
Sequence < PropertyValue > & aC
                 {
                     bHyphenateURLs = true;
                 }
+                else if (rValue.Name == 
"ApplyTextAttrToEmptyLineAtEndOfParagraph")
+                {
+                    bApplyTextAttrToEmptyLineAtEndOfParagraph = true;
+                }
                 else if (rValue.Name == "DoNotBreakWrappedTables")
                 {
                     rValue.Value >>= bDoNotBreakWrappedTables;
@@ -1578,6 +1583,11 @@ void SwXMLImport::SetConfigurationSettings(const 
Sequence < PropertyValue > & aC
         xProps->setPropertyValue("HyphenateURLs", Any(true));
     }
 
+    if (!bApplyTextAttrToEmptyLineAtEndOfParagraph)
+    {
+        xProps->setPropertyValue("ApplyTextAttrToEmptyLineAtEndOfParagraph", 
Any(false));
+    }
+
     if (bDoNotBreakWrappedTables)
     {
         xProps->setPropertyValue("DoNotBreakWrappedTables", Any(true));
diff --git a/sw/source/uibase/uno/SwXDocumentSettings.cxx 
b/sw/source/uibase/uno/SwXDocumentSettings.cxx
index bbf96ab967b5..ba7ed59dd64b 100644
--- a/sw/source/uibase/uno/SwXDocumentSettings.cxx
+++ b/sw/source/uibase/uno/SwXDocumentSettings.cxx
@@ -157,6 +157,7 @@ enum SwDocumentSettingsPropertyHandles
     HANDLE_ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK,
     HANDLE_NO_NUMBERING_SHOW_FOLLOWBY,
     HANDLE_DROP_CAP_PUNCTUATION,
+    HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH,
 };
 
 }
@@ -260,6 +261,7 @@ static rtl::Reference<MasterPropertySetInfo> 
lcl_createSettingsInfo()
         { OUString("AllowTextAfterFloatingTableBreak"), 
HANDLE_ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK, cppu::UnoType<bool>::get(), 0 },
         { OUString("NoNumberingShowFollowBy"), 
HANDLE_NO_NUMBERING_SHOW_FOLLOWBY, cppu::UnoType<bool>::get(), 0 },
         { OUString("DropCapPunctuation"), HANDLE_DROP_CAP_PUNCTUATION, 
cppu::UnoType<bool>::get(), 0 },
+        { OUString("ApplyTextAttrToEmptyLineAtEndOfParagraph"), 
HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, 
cppu::UnoType<bool>::get(), 0 },
 
 /*
  * As OS said, we don't have a view when we need to set this, so I have to
@@ -1070,6 +1072,16 @@ void SwXDocumentSettings::_setSingleValue( const 
comphelper::PropertyInfo & rInf
             }
         }
         break;
+        case HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
+        {
+            bool bTmp;
+            if (rValue >>= bTmp)
+            {
+                mpDoc->getIDocumentSettingAccess().set(
+                    
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, bTmp);
+            }
+        }
+        break;
         case HANDLE_DO_NOT_BREAK_WRAPPED_TABLES:
         {
             bool bTmp;
@@ -1634,6 +1646,12 @@ void SwXDocumentSettings::_getSingleValue( const 
comphelper::PropertyInfo & rInf
                 DocumentSettingId::HYPHENATE_URLS);
         }
         break;
+        case HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
+        {
+            rValue <<= mpDoc->getIDocumentSettingAccess().get(
+                
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH);
+        }
+        break;
         case HANDLE_DO_NOT_BREAK_WRAPPED_TABLES:
         {
             rValue <<= mpDoc->getIDocumentSettingAccess().get(
diff --git a/writerfilter/source/filter/WriterFilter.cxx 
b/writerfilter/source/filter/WriterFilter.cxx
index 88b710c449ff..b40cdbd696ff 100644
--- a/writerfilter/source/filter/WriterFilter.cxx
+++ b/writerfilter/source/filter/WriterFilter.cxx
@@ -330,6 +330,7 @@ void WriterFilter::setTargetDocument(const 
uno::Reference<lang::XComponent>& xDo
     xSettings->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
     xSettings->setPropertyValue("DropCapPunctuation", uno::Any(true));
     // rely on default for HyphenateURLs=false
+    // rely on default for 
APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
 }
 
 void WriterFilter::setSourceDocument(const uno::Reference<lang::XComponent>& 
xDoc)

Reply via email to