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)