From e3dfb54117f5325d8f38f58ef892c2808d601e54 Mon Sep 17 00:00:00 2001
From: Justin Luth <jluth@mail.com>
Date: Wed, 17 Jul 2024 14:48:57 -0400
Subject: tdf#125469 writerfilter: use "auto" for not-provided lineRule

This fixes the problem where a programmatically generated document
didn't specify a w:lineRule, and thus the w:line size
was treated as a FIXed spacing of 12pt instead of as single spacing.

------------------------------------------------------------
lineRule (Spacing Between Lines)
Specifies how the spacing between lines is calculated
as stored in the line attribute.

If this attribute is omitted, then it shall be assumed to be
of a value "auto" if a w:line attribute value is present.
------------------------------------------------------------
However, our implementation (wisely) defaulted to ::FIX
instead of ::PROP (which keeps precision in w:line sizes
since PROP is a integer percentage instead of a float
and thus loses precision when switching between FIX and PROP).

Note of course that if neither w:line nor w:lineRule is provided,
then we go with the LO default of mode=0, height=0 (aka AUTO).

This gets tricky because the lineRule can be inherited,
so just because it is missing in a pPr doesn't necessarily mean
we can just substitute "auto".

It is also tricky because w:spacing
deals with more than just line spacing.

Not surprisingly, no existing unit tests matched this case.
However, the unit tests were VERY helpful in pointing out
limitations as I attempted to code the fix.

make CppunitTest_sw_ooxmlexport21 \
    CPPUNIT_TEST_NAME=testTdf125469_singleSpacing

Change-Id: Id5e95f2983f4fb435810d5a1f3fd25ded5118ddc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170670
Tested-by: Jenkins
Reviewed-by: Justin Luth <jluth@mail.com>
---
 .../ooxmlexport/data/tdf125469_singleSpacing.docx  | Bin 0 -> 11682 bytes
 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx         |  36 +++++++++++++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 sw/qa/extras/ooxmlexport/data/tdf125469_singleSpacing.docx

(limited to 'sw/qa')

diff --git a/sw/qa/extras/ooxmlexport/data/tdf125469_singleSpacing.docx b/sw/qa/extras/ooxmlexport/data/tdf125469_singleSpacing.docx
new file mode 100644
index 000000000000..ff92e1b2d0c7
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf125469_singleSpacing.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
index 9ef569e47683..91fbf2e7e110 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
@@ -327,6 +327,42 @@ DECLARE_OOXMLEXPORT_TEST(testTdf158597, "tdf158597.docx")
     }
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf125469_singleSpacing, "tdf125469_singleSpacing.docx")
+{
+    // Given a document with 4 paragraphs of varying strange line spacing definitions,
+    // and a DocDefault of single line spacing (AUTO 240pt) (240pt is 0.423 cm)
+
+    // Paragraph 1 - DocDefaults specifies size 240 without a lineRule - default is AUTO(aka PROP)
+    // Visually, this should clearly say "Single spacing"
+    auto aSpacing = getProperty<style::LineSpacing>(getParagraph(1), u"ParaLineSpacing"_ustr);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(style::LineSpacingMode::PROP), aSpacing.Mode);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(100), aSpacing.Height);
+
+    // Paragraph 2 - paragraph style specifies atLeast 240, para overrides with only -240.
+    // The negative value (always) turns the (inherited) "atLeast" into an "exact".
+    // Visually, this is hardly readable (36pt font forced into 12pt space)
+    aSpacing = getProperty<style::LineSpacing>(getParagraph(2), u"ParaLineSpacing"_ustr);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(style::LineSpacingMode::FIX), aSpacing.Mode);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(423), aSpacing.Height);
+
+    // Paragraph 3 - paragraph style specifies exact 240, para overrides with exact -240.
+    // The negative value turns the non-inherited "exact" into an "atLeast".
+    // Visually, this should clearly say "Negative exact"
+    aSpacing = getProperty<style::LineSpacing>(getParagraph(3), u"ParaLineSpacing"_ustr);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(style::LineSpacingMode::MINIMUM), aSpacing.Mode);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(423), aSpacing.Height);
+
+    // Paragraph 4 - paragraph style specifies exact 240, para overrides with only -240.
+    // The negative value does nothing to the inherited "exact".
+    // Visually, this is hardly readable (36pt font forced into 12pt space)
+    aSpacing = getProperty<style::LineSpacing>(getParagraph(4), u"ParaLineSpacing"_ustr);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(style::LineSpacingMode::FIX), aSpacing.Mode);
+    // CPPUNIT_ASSERT_EQUAL(sal_Int16(423), aSpacing.Height);
+
+    // all of this ends up being squeezed onto a single page
+    // CPPUNIT_ASSERT_EQUAL(1, getPages());
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf43767_caseMapNumbering, "tdf43767_caseMapNumbering.odt")
 {
     // given a document with 2 numbered Lists [each entry restarts numbering for visual comparison]
-- 
cgit