sw/inc/IDocumentSettingAccess.hxx             |    5 +
 sw/qa/extras/layout/data/tdf150200.docx       |binary
 sw/qa/extras/layout/data/tdf150200.odt        |binary
 sw/qa/extras/layout/data/tdf150438.docx       |binary
 sw/qa/extras/layout/data/tdf150438.odt        |binary
 sw/qa/extras/layout/layout2.cxx               |   88 ++++++++++++++++++++++++++
 sw/source/core/doc/DocumentSettingManager.cxx |   10 ++
 sw/source/core/inc/DocumentSettingManager.hxx |    1 
 sw/source/core/text/txtdrop.cxx               |   14 ++++
 sw/source/filter/xml/xmlimp.cxx               |   12 +++
 sw/source/uibase/uno/SwXDocumentSettings.cxx  |   30 ++++++--
 writerfilter/source/filter/WriterFilter.cxx   |    1 
 12 files changed, 152 insertions(+), 9 deletions(-)

New commits:
commit a18a74d6762e56a20093ca51cfd12925697c2524
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Tue Aug 16 11:00:54 2022 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Wed Aug 17 18:07:24 2022 +0200

    tdf#150200 tdf#150438 sw, DOCX: fix drop cap dash, quotation etc.
    
    In drop cap layout, set smaller size for all glyphs positioned
    over the baseline, e.g. dashes (dash, en-dash, em-dash, figure dash),
    bullet, asterisks and quotation marks by extending the bounding box
    of the glyph to the baseline, like MSO does.
    
    Add "DropCapPunctuation", a new default compatibility option for this.
    Only old ODT files loads the old layout (which was partially broken:
    e.g. dashes were too long, often missing from the drop cap area or
    the drop cap was disabled). New ODT and imported DOCX documents
    use the new default layout for better typesetting and interoperability.
    
    Change-Id: I3aba0727fd15f6edb9245e31f523e12f407d189e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138356
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/inc/IDocumentSettingAccess.hxx 
b/sw/inc/IDocumentSettingAccess.hxx
index 548419576168..1f81ead70645 100644
--- a/sw/inc/IDocumentSettingAccess.hxx
+++ b/sw/inc/IDocumentSettingAccess.hxx
@@ -123,7 +123,10 @@ enum class DocumentSettingId
     // docx enable this flag. For details see ticket tdf#100680.
     WRAP_AS_CHAR_FLYS_LIKE_IN_OOXML,
     // Should we display follow by symbol for numbered paragraph if numbering 
exists, but "None"?
-    NO_NUMBERING_SHOW_FOLLOWBY
+    NO_NUMBERING_SHOW_FOLLOWBY,
+    // drop cap punctuation: smaller dashes, bullet, asterisks, quotation 
marks etc.
+    // by extending the rounding box of the glyph to the baseline
+    DROP_CAP_PUNCTUATION
 };
 
 /** Provides access to settings of a document
diff --git a/sw/qa/extras/layout/data/tdf150200.docx 
b/sw/qa/extras/layout/data/tdf150200.docx
new file mode 100644
index 000000000000..8f3a57d764b9
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf150200.docx differ
diff --git a/sw/qa/extras/layout/data/tdf150200.odt 
b/sw/qa/extras/layout/data/tdf150200.odt
new file mode 100644
index 000000000000..224d5c4c4b3e
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf150200.odt differ
diff --git a/sw/qa/extras/layout/data/tdf150438.docx 
b/sw/qa/extras/layout/data/tdf150438.docx
new file mode 100644
index 000000000000..87aa1c5f6de2
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf150438.docx differ
diff --git a/sw/qa/extras/layout/data/tdf150438.odt 
b/sw/qa/extras/layout/data/tdf150438.odt
new file mode 100644
index 000000000000..5634ab91adb4
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf150438.odt differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 09e113fc4ed0..eafb21646cdf 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -2009,6 +2009,94 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf118672)
                 "setetur");
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf150200)
+{
+    createSwDoc(DATA_DIRECTORY, "tdf150200.odt");
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    // dash
+    OUString sFirstLine = 
parseDump("/root/page/body/txt[1]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"-(dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(93), sFirstLine.getLength());
+    // en-dash
+    sFirstLine = parseDump("/root/page/body/txt[2]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"–(en-dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(88), sFirstLine.getLength());
+    // em-dash
+    sFirstLine = parseDump("/root/page/body/txt[3]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"—(em-dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(77), sFirstLine.getLength());
+    // figure dash
+    sFirstLine = parseDump("/root/page/body/txt[4]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"‒(figure dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(87), sFirstLine.getLength());
+}
+
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf150200_DOCX)
+{
+    createSwDoc(DATA_DIRECTORY, "tdf150200.docx");
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    // dash
+    OUString sFirstLine = 
parseDump("/root/page/body/txt[1]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"-(dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(93), sFirstLine.getLength());
+    // en-dash
+    sFirstLine = parseDump("/root/page/body/txt[2]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"–(en-dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(88), sFirstLine.getLength());
+    // em-dash
+    sFirstLine = parseDump("/root/page/body/txt[3]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"—(em-dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(77), sFirstLine.getLength());
+    // figure dash
+    sFirstLine = parseDump("/root/page/body/txt[4]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"‒(figure dash)"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(87), sFirstLine.getLength());
+}
+
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf150438)
+{
+    createSwDoc(DATA_DIRECTORY, "tdf150438.odt");
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    // left double quotation mark
+    OUString sFirstLine = 
parseDump("/root/page/body/txt[1]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"“Lorem ipsum"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(92), sFirstLine.getLength());
+    // right double quotation mark
+    sFirstLine = parseDump("/root/page/body/txt[2]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"”Nunc viverra imperdiet 
enim."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(97), sFirstLine.getLength());
+    // left single quotation mark
+    sFirstLine = parseDump("/root/page/body/txt[3]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"‘Aenean nec lorem."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(85), sFirstLine.getLength());
+    // right single quotation mark or apostrophe
+    sFirstLine = parseDump("/root/page/body/txt[4]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"’Aenean nec lorem."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(85), sFirstLine.getLength());
+}
+
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf150438_DOCX)
+{
+    createSwDoc(DATA_DIRECTORY, "tdf150438.docx");
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    // left double quotation mark
+    OUString sFirstLine = 
parseDump("/root/page/body/txt[1]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"“Lorem ipsum"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(92), sFirstLine.getLength());
+    // right double quotation mark
+    sFirstLine = parseDump("/root/page/body/txt[2]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"”Nunc viverra imperdiet 
enim."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(97), sFirstLine.getLength());
+    // left single quotation mark
+    sFirstLine = parseDump("/root/page/body/txt[3]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"‘Aenean nec lorem."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(85), sFirstLine.getLength());
+    // right single quotation mark or apostrophe
+    sFirstLine = parseDump("/root/page/body/txt[4]/LineBreak[1]/@Line");
+    CPPUNIT_ASSERT_EQUAL(true, sFirstLine.startsWith(u"’Aenean nec lorem."));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(85), sFirstLine.getLength());
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf117923)
 {
     createSwDoc(DATA_DIRECTORY, "tdf117923.doc");
diff --git a/sw/source/core/doc/DocumentSettingManager.cxx 
b/sw/source/core/doc/DocumentSettingManager.cxx
index 5f2a57099938..cb2ea3288d35 100644
--- a/sw/source/core/doc/DocumentSettingManager.cxx
+++ b/sw/source/core/doc/DocumentSettingManager.cxx
@@ -107,7 +107,9 @@ sw::DocumentSettingManager::DocumentSettingManager(SwDoc 
&rDoc)
     mnImagePreferredDPI(0),
     mbAutoFirstLineIndentDisregardLineSpace(true),
     mbWrapAsCharFlysLikeInOOXML(false),
-    mbNoNumberingShowFollowBy(false)
+    mbNoNumberingShowFollowBy(false),
+    mbDropCapPunctuation(true)
+
     // COMPATIBILITY FLAGS END
 {
     // COMPATIBILITY FLAGS START
@@ -247,6 +249,7 @@ bool sw::DocumentSettingManager::get(/*[in]*/ 
DocumentSettingId id) const
             return mbAutoFirstLineIndentDisregardLineSpace;
         case DocumentSettingId::WRAP_AS_CHAR_FLYS_LIKE_IN_OOXML: return 
mbWrapAsCharFlysLikeInOOXML;
         case DocumentSettingId::NO_NUMBERING_SHOW_FOLLOWBY: return 
mbNoNumberingShowFollowBy;
+        case DocumentSettingId::DROP_CAP_PUNCTUATION: return 
mbDropCapPunctuation;
         default:
             OSL_FAIL("Invalid setting id");
     }
@@ -433,6 +436,10 @@ void sw::DocumentSettingManager::set(/*[in]*/ 
DocumentSettingId id, /*[in]*/ boo
             mbNoNumberingShowFollowBy = value;
             break;
 
+        case DocumentSettingId::DROP_CAP_PUNCTUATION:
+            mbDropCapPunctuation = value;
+            break;
+
         // COMPATIBILITY FLAGS END
 
         case DocumentSettingId::BROWSE_MODE: //can be used temporary 
(load/save) when no SwViewShell is available
@@ -704,6 +711,7 @@ void 
sw::DocumentSettingManager::ReplaceCompatibilityOptions(const DocumentSetti
     mbHeaderSpacingBelowLastPara = rSource.mbHeaderSpacingBelowLastPara;
     mbFrameAutowidthWithMorePara = rSource.mbFrameAutowidthWithMorePara;
     mbFootnoteInColumnToPageEnd = rSource.mbFootnoteInColumnToPageEnd;
+    mbDropCapPunctuation = rSource.mbDropCapPunctuation;
 }
 
 sal_uInt32 sw::DocumentSettingManager::Getn32DummyCompatibilityOptions1() const
diff --git a/sw/source/core/inc/DocumentSettingManager.hxx 
b/sw/source/core/inc/DocumentSettingManager.hxx
index f37696df1a3e..0cde949ecf94 100644
--- a/sw/source/core/inc/DocumentSettingManager.hxx
+++ b/sw/source/core/inc/DocumentSettingManager.hxx
@@ -177,6 +177,7 @@ class DocumentSettingManager final :
     // If this is on as_char flys wrapping will be handled the same like in 
Word
     bool mbWrapAsCharFlysLikeInOOXML;
     bool mbNoNumberingShowFollowBy;
+    bool mbDropCapPunctuation; // tdf#150200, tdf#150438
 
 public:
 
diff --git a/sw/source/core/text/txtdrop.cxx b/sw/source/core/text/txtdrop.cxx
index 9f6d94a8c28e..f139cb4e4435 100644
--- a/sw/source/core/text/txtdrop.cxx
+++ b/sw/source/core/text/txtdrop.cxx
@@ -36,6 +36,7 @@
 #include <editeng/fhgtitem.hxx>
 #include <calbck.hxx>
 #include <doc.hxx>
+#include <IDocumentSettingAccess.hxx>
 
 using namespace ::com::sun::star::i18n;
 using namespace ::com::sun::star;
@@ -797,6 +798,11 @@ void SwDropCapCache::CalcFontSize( SwDropPortion* pDrop, 
SwTextFormatInfo &rInf
         else
             pWin = Application::GetDefaultDevice();
 
+        // adjust punctuation?
+        bool bKeepBaseline = 
rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess()
+            .get(DocumentSettingId::DROP_CAP_PUNCTUATION) &&
+            !rInf.GetDropFormat()->GetWholeWord(); // && 
rInf.GetDropFormat()->GetChars() == 1;
+
         while( bGrow )
         {
             // reset pCurrPart to first part
@@ -855,6 +861,14 @@ void SwDropCapCache::CalcFontSize( SwDropPortion* pDrop, 
SwTextFormatInfo &rInf
                     }
                 }
 
+                // extend rectangle to the baseline to avoid of giant dashes,
+                // quotation marks, bullet, asterisks etc.
+                if ( bKeepBaseline && aRect.Top() < 0 )
+                {
+                    aRect.SetBottom(0);
+                    aRect.SetTop(aRect.Top() - nAscent/60);
+                }
+
                 // Now we (hopefully) have a bounding rectangle for the
                 // glyphs of the current portion and the ascent of the current
                 // font
diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx
index a0b201cda9cc..971059732e14 100644
--- a/sw/source/filter/xml/xmlimp.cxx
+++ b/sw/source/filter/xml/xmlimp.cxx
@@ -1300,6 +1300,7 @@ void SwXMLImport::SetConfigurationSettings(const Sequence 
< PropertyValue > & aC
     bool bEmptyDbFieldHidesPara = false;
     bool bCollapseEmptyCellPara = false;
     bool bAutoFirstLineIndentDisregardLineSpace = false;
+    bool bDropCapPunctuation = false;
 
     const PropertyValue* currentDatabaseDataSource = nullptr;
     const PropertyValue* currentDatabaseCommand = nullptr;
@@ -1393,6 +1394,8 @@ void SwXMLImport::SetConfigurationSettings(const Sequence 
< PropertyValue > & aC
                     bCollapseEmptyCellPara = true;
                 else if (rValue.Name == 
"AutoFirstLineIndentDisregardLineSpace")
                     bAutoFirstLineIndentDisregardLineSpace = true;
+                else if ( rValue.Name == "DropCapPunctuation" )
+                    bDropCapPunctuation = true;
             }
             catch( Exception& )
             {
@@ -1555,6 +1558,15 @@ void SwXMLImport::SetConfigurationSettings(const 
Sequence < PropertyValue > & aC
     if (!bAutoFirstLineIndentDisregardLineSpace)
         xProps->setPropertyValue("AutoFirstLineIndentDisregardLineSpace", 
Any(false));
 
+    // LO 7.4 and previous versions had different drop cap punctuation: very 
long dashes.
+    // In order to keep backwards compatibility, DropCapPunctuation option is 
written to .odt
+    // files, and the default for new documents is 'true'. Files without this 
option
+    // are considered to be old files, so set the compatibility option too.
+    if ( !bDropCapPunctuation )
+    {
+        xProps->setPropertyValue( "DropCapPunctuation", Any( false ) );
+    }
+
     SwDoc *pDoc = getDoc();
     SfxPrinter *pPrinter = pDoc->getIDocumentDeviceAccess().getPrinter( false 
);
     if( pPrinter )
diff --git a/sw/source/uibase/uno/SwXDocumentSettings.cxx 
b/sw/source/uibase/uno/SwXDocumentSettings.cxx
index b58b20ea6cd1..e29a25a49c0c 100644
--- a/sw/source/uibase/uno/SwXDocumentSettings.cxx
+++ b/sw/source/uibase/uno/SwXDocumentSettings.cxx
@@ -153,7 +153,8 @@ enum SwDocumentSettingsPropertyHandles
     HANDLE_IMAGE_PREFERRED_DPI,
     HANDLE_AUTO_FIRST_LINE_INDENT_DISREGARD_LINE_SPACE,
     HANDLE_WORD_LIKE_WRAP_FOR_AS_CHAR_FLYS,
-    HANDLE_NO_NUMBERING_SHOW_FOLLOWBY
+    HANDLE_NO_NUMBERING_SHOW_FOLLOWBY,
+    HANDLE_DROP_CAP_PUNCTUATION
 };
 
 }
@@ -254,6 +255,7 @@ static rtl::Reference<MasterPropertySetInfo> 
lcl_createSettingsInfo()
         { OUString("AutoFirstLineIndentDisregardLineSpace"), 
HANDLE_AUTO_FIRST_LINE_INDENT_DISREGARD_LINE_SPACE, cppu::UnoType<bool>::get(), 
0 },
         { OUString("WordLikeWrapForAsCharFlys"), 
HANDLE_WORD_LIKE_WRAP_FOR_AS_CHAR_FLYS, 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 },
 
 /*
  * As OS said, we don't have a view when we need to set this, so I have to
@@ -1057,18 +1059,26 @@ void SwXDocumentSettings::_setSingleValue( const 
comphelper::PropertyInfo & rInf
         break;
         case HANDLE_WORD_LIKE_WRAP_FOR_AS_CHAR_FLYS:
         {
-            bool bValue = false;
-            if (rValue >>= bValue)
+            bool bTmp;
+            if (rValue >>= bTmp)
                 mpDoc->getIDocumentSettingAccess().set(
-                    DocumentSettingId::WRAP_AS_CHAR_FLYS_LIKE_IN_OOXML, 
bValue);
+                    DocumentSettingId::WRAP_AS_CHAR_FLYS_LIKE_IN_OOXML, bTmp);
         }
         break;
         case HANDLE_NO_NUMBERING_SHOW_FOLLOWBY:
         {
-            bool bValue = false;
-            if (rValue >>= bValue)
+            bool bTmp;
+            if (rValue >>= bTmp)
+                mpDoc->getIDocumentSettingAccess().set(
+                    DocumentSettingId::NO_NUMBERING_SHOW_FOLLOWBY, bTmp);
+        }
+        break;
+        case HANDLE_DROP_CAP_PUNCTUATION:
+        {
+            bool bTmp;
+            if (rValue >>= bTmp)
                 mpDoc->getIDocumentSettingAccess().set(
-                    DocumentSettingId::NO_NUMBERING_SHOW_FOLLOWBY, bValue);
+                    DocumentSettingId::DROP_CAP_PUNCTUATION, bTmp);
         }
         break;
         default:
@@ -1606,6 +1616,12 @@ void SwXDocumentSettings::_getSingleValue( const 
comphelper::PropertyInfo & rInf
                 DocumentSettingId::NO_NUMBERING_SHOW_FOLLOWBY);
         }
         break;
+        case HANDLE_DROP_CAP_PUNCTUATION:
+        {
+            rValue <<= mpDoc->getIDocumentSettingAccess().get(
+                DocumentSettingId::DROP_CAP_PUNCTUATION);
+        }
+        break;
         default:
             throw UnknownPropertyException(OUString::number(rInfo.mnHandle));
     }
diff --git a/writerfilter/source/filter/WriterFilter.cxx 
b/writerfilter/source/filter/WriterFilter.cxx
index f65df20f0f1f..26ec2701f28b 100644
--- a/writerfilter/source/filter/WriterFilter.cxx
+++ b/writerfilter/source/filter/WriterFilter.cxx
@@ -332,6 +332,7 @@ void WriterFilter::setTargetDocument(const 
uno::Reference<lang::XComponent>& xDo
     xSettings->setPropertyValue("DoNotCaptureDrawObjsOnPage", uno::Any(true));
     xSettings->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
     xSettings->setPropertyValue("WordLikeWrapForAsCharFlys", uno::Any(true));
+    xSettings->setPropertyValue("DropCapPunctuation", uno::Any(true));
 }
 
 void WriterFilter::setSourceDocument(const uno::Reference<lang::XComponent>& 
xDoc)

Reply via email to